游戏AI的创造思路-技术基础-深度学习(3)

继续填坑,本篇介绍深度学习中的长短期记忆网络~~~~

目录

3.3. 长短期记忆网络(LSTM)

3.3.1. 什么是长短期记忆网络

3.3.2. 形成过程与运行原理

3.3.2.1. 细胞状态与门结构

3.3.2.2. 遗忘门

3.3.2.3. 输入门

3.3.2.4. 细胞状态更新

3.3.2.5. 输出门

3.3.2.6. 以上各步骤的示例代码

3.3.3. 优缺点

3.3.4. 存在的问题及解决方法

3.3.5. 示例代码


3.3. 长短期记忆网络(LSTM)

3.3.1. 什么是长短期记忆网络

长短期记忆网络(LSTM,Long Short-Term Memory)算法是一种特殊的循环神经网络(RNN),它旨在解决传统RNN在处理长序列数据时遇到的梯度消失和梯度爆炸问题,从而更有效地学习序列中的长期依赖关系。

  • 为了最小化训练误差,通常使用梯度下降法,如应用时序性倒传递算法,来依据错误修改每次的权重。此外,LSTM有多种变体,其中一个重要的版本是门控循环单元(GRU)。
  • LSTM适合于处理和预测时间序列中间隔和延迟非常长的重要事件。其表现通常比时间递归神经网络及隐马尔科夫模型(HMM)更好。例如,在不分段连续手写识别上,LSTM模型曾赢得过ICDAR手写识别比赛冠军。此外,LSTM还广泛应用于自主语音识别,并在2013年使用TIMIT自然演讲数据库达成了17.7%的错误率纪录。
  • LSTM的成功在很大程度上促进了深度学习和人工智能领域的发展。尽管近年来出现了新的模型结构,如基于注意力机制的Transformer,但LSTM仍然是许多序列建模任务的可靠选择。随着时间的推移,LSTM被广泛应用于自然语言处理、语音识别、文本生成、视频分析等多个领域

3.3.2. 形成过程与运行原理

LSTM通过引入“”结构和“细胞状态”来更好地捕捉序列中的长期依赖关系。(通过借鉴脑神经学的知识来组建序列中的长期依赖关系)

3.3.2.1. 细胞状态与门结构

LSTM的核心是细胞状态,它像一条传送带,在整个链上运行,只有一些小的线性操作作用其上,信息在上面流传保持不变会很容易。LSTM通过精心设计的门结构来去除或增加信息到细胞状态,这些门结构包括遗忘门、输入门和输出门。

3.3.2.2. 遗忘门

决定从细胞状态中丢弃什么信息。它查看当前的输入和前一个时间步的隐藏状态,并为细胞状态中的每个数字输出一个在0到1之间的数字,1表示“完全保留”,0表示“完全舍弃”。

遗忘门决定了从上一个时间步的细胞状态中丢弃哪些信息。其计算公式为:

[ I_t = \sigma(X_tW_{xi} + H_{t-1}W_{hi} + b_i) ]

其中,( I_t )表示输入门在时刻( t )的值,( X_t )是时刻 ( t ) 的输入,( H_{t-1} )是前一个时刻的隐藏状态,( W_{xi} )( W_{hi} ) 是对应的权重矩阵,而( b_i )( b_i )是偏置项。函数( \sigma )表示sigmoid激活函数。

3.3.2.3. 输入门

决定什么新信息将被存储在细胞状态中。这包括两部分,一部分是输入门决定我们将更新哪些部分,另一部分是tanh层创建一个新的候选值向量,这个向量可能会被添加到细胞状态中。

[ F_t = \sigma(X_tW_{xf} + H_{t-1}W_{hf} + b_f) ]

类似地,( F_t )表示遗忘门在时刻( t )的值,其他符号的含义与输入门公式中的相同,只是权重和偏置项是针对遗忘门的。

3.3.2.4. 细胞状态更新

首先,旧细胞状态与遗忘门相乘,丢弃掉需要丢弃的信息。然后,将输入门的输出与tanh层的输出相乘,得出新的候选细胞状态。最后,将这两个值相加,形成新的细胞状态。

  • 旧细胞状态与遗忘门相乘

[ \tilde{C}t = C{t-1} \odot F_t ]

这里,( \tilde{C}t )表示经过遗忘门处理后的旧细胞状态,( C{t-1} )是前一个时刻的细胞状态,( F_t ) 是遗忘门在时刻( t )的输出,而( \odot )表示逐元素相乘(Hadamard乘积)。这一步的目的是丢弃掉不需要的信息。

  • 计算新的候选细胞状态

[ \hat{C}t = \tanh(X_tW{xc} + H_{t-1}W_{hc} + b_c) ]

其中,( \hat{C}t )是新的候选细胞状态,( X_t )是时刻 ( t )的输入,( H{t-1} ) 是前一个时刻的隐藏状态,( W_{xc} )( W_{hc} ) 是对应的权重矩阵,( b_c )是偏置项。函数 ( \tanh )是双曲正切激活函数,它将输入值压缩到 ( -1 ) 到 ( 1 ) 的范围内。

  • 将候选细胞状态与输入门相乘

[ i_t \odot \hat{C}_t ]

这里,( i_t )是输入门在时刻( t )的输出,( \odot )表示逐元素相乘。这一步的目的是根据输入门的选择来决定哪些新的信息被加入到细胞状态中。

  • 更新细胞状态

[ C_t = \tilde{C}_t + i_t \odot \hat{C}_t ]

最终,新的细胞状态( C_t )是经过遗忘门处理后的旧细胞状态 ( \tilde{C}_t )与经过输入门处理后的新候选细胞状态 ( i_t \odot \hat{C}_t ) 之和。这一步完成了细胞状态的更新,使得LSTM能够记住长期依赖关系。

3.3.2.5. 输出门

基于细胞状态来决定输出什么。首先,运行一个sigmoid层来确定细胞状态的哪个部分将输出,然后将细胞状态通过tanh进行处理(得到一个在-1到1之间的值),并将其与sigmoid门的输出相乘,最终得到输出。

[ O_t = \sigma(X_tW_{xo} + H_{t-1}W_{ho} + b_o) ]

在这里,( O_t )是输出门在时刻( t )的值,其他参数和符号的意义与前面公式中的一致,但针对输出门。

3.3.2.6. 以上各步骤的示例代码

Python代码示例

import numpy as np  
  
def sigmoid(x):  
    return 1 / (1 + np.exp(-x))  
  
def tanh(x):  
    return np.tanh(x)  
  
# LSTM Cell 参数初始化  
input_size = 10  
hidden_size = 20  
  
Wf = np.random.randn(hidden_size, hidden_size + input_size) # 遗忘门权重  
Wi = np.random.randn(hidden_size, hidden_size + input_size) # 输入门权重  
Wc = np.random.randn(hidden_size, hidden_size + input_size) # 候选细胞状态权重  
Wo = np.random.randn(hidden_size, hidden_size + input_size) # 输出门权重  
  
# LSTM Cell 前向传播  
def lstm_cell_forward(xt, ht_prev, ct_prev, Wf, Wi, Wc, Wo):  
    # 拼接前一个隐藏状态和当前输入  
    concat = np.concatenate((ht_prev, xt), axis=0)  
      
    # 计算遗忘门  
    ft = sigmoid(np.dot(Wf, concat))  
      
    # 计算输入门  
    it = sigmoid(np.dot(Wi, concat))  
      
    # 计算候选细胞状态  
    cct = tanh(np.dot(Wc, concat))  
      
    # 细胞状态更新  
    ct = ft * ct_prev + it * cct  
      
    # 计算输出门  
    ot = sigmoid(np.dot(Wo, concat))  
      
    # 计算隐藏状态  
    ht = ot * tanh(ct)  
      
    return ht, ct  
  
# 示例使用  
xt = np.random.randn(input_size) # 当前输入  
ht_prev = np.zeros(hidden_size) # 前一个隐藏状态  
ct_prev = np.zeros(hidden_size) # 前一个细胞状态  
  
ht, ct = lstm_cell_forward(xt, ht_prev, ct_prev, Wf, Wi, Wc, Wo)

C++代码示例

#include <Eigen/Dense>  
#include <cmath>  
  
using namespace Eigen;  
  
// 激活函数  
double sigmoid(double x) {  
    return 1.0 / (1.0 + std::exp(-x));  
}  
  
double tanh(double x) {  
    return std::tanh(x);  
}  
  
// LSTM单元前向传播  
void LSTMCellForward(const VectorXd& xt, const VectorXd& ht_prev, const VectorXd& ct_prev,   
                     const MatrixXd& Wf, const MatrixXd& Wi, const MatrixXd& Wc, const MatrixXd& Wo,  
                     VectorXd& ht, VectorXd& ct) {  
    int input_size = xt.size();  
    int hidden_size = ht_prev.size();  
    VectorXd concat(input_size + hidden_size);  
    concat << ht_prev, xt;  
      
    // 计算遗忘门  
    VectorXd ft = concat.unaryExpr([](double elem) { return sigmoid(elem); }) * Wf.transpose();  
      
    // 计算输入门  
    VectorXd it = concat.unaryExpr([](double elem) { return sigmoid(elem); }) * Wi.transpose();  
      
    // 计算候选细胞状态  
    VectorXd cct = concat.unaryExpr([](double elem) { return tanh(elem); }) * Wc.transpose();  
      
    // 细胞状态更新  
    ct = ft.array() * ct_prev.array() + it.array() * cct.array();  
      
    // 计算输出门  
    VectorXd ot = concat.unaryExpr([](double elem) { return sigmoid(elem); }) * Wo.transpose();  
      
    // 计算隐藏状态  
    ht = ot.array() * ct.array().unaryExpr([](double elem) { return tanh(elem); });  
}  
  
int main() {  
    int input_size = 10;  
    int hidden_size = 20;  
      
    MatrixXd Wf = MatrixXd::Random(hidden_size, hidden_size + input_size); // 遗忘门权重  
    MatrixXd Wi = MatrixXd::Random(hidden_size, hidden_size + input_size); // 输入门权重  
    MatrixXd Wc = MatrixXd::Random(hidden_size, hidden_size + input_size); // 候选细胞状态权重  
    MatrixXd Wo = MatrixXd::Random(hidden_size, hidden_size + input_size); // 输出门权重  
      
    VectorXd xt = VectorXd::Random(input_size); // 当前输入  
    VectorXd ht_prev = VectorXd::Zero(hidden_size); // 前一个隐藏状态  
    VectorXd ct_prev = VectorXd::Zero(hidden_size); // 前一个细胞状态  
    VectorXd ht(hidden_size), ct(hidden_size);  
      
    LSTMCellForward(xt, ht_prev, ct_prev, Wf, Wi, Wc, Wo, ht, ct);  
      
    // Do something with ht and ct...  
      
    return 0;  
}

这些代码是简化示例,实际应用中LSTM的实现会更加复杂,包括多个时间步的迭代、批处理支持、梯度计算和权重更新等。

在生产环境中,建议使用成熟的深度学习框架如TensorFlow或PyTorch来实现LSTM哦。

3.3.3. 优缺点

优点

  1. 能够有效地解决传统RNN中的梯度消失和梯度爆炸问题。
  2. 能够更好地捕捉序列中的长期依赖关系。
  3. 在处理长序列数据时具有优势。

缺点

  1. LSTM模型相对复杂,计算成本较高。
  2. 对于输入序列长度较长时,可能会出现过拟合现象,导致泛化能力下降。

3.3.4. 存在的问题及解决方法

过拟合问题:可以通过正则化、dropout等技术来减轻过拟合现象。

无法有效捕捉时间上下文关系:可以引入双向LSTM(Bidirectional LSTM)结构来提高对于时间上下文之间关系的建模能力。

对输入数据序列顺序敏感:在实际应用中,可以通过数据增强、序列颠倒等方法来减轻模型对输入数据序列顺序的敏感性。

3.3.5. 示例代码

Python代码

由于篇幅限制,这里提供一个简化的Python示例,使用PyTorch库实现LSTM:

import torch  
import torch.nn as nn  
  
# 定义一个简单的LSTM模型  
class SimpleLSTM(nn.Module):  
    def __init__(self, input_size, hidden_size, output_size):  
        super(SimpleLSTM, self).__init__()  
        self.hidden_size = hidden_size  
        self.lstm = nn.LSTM(input_size, hidden_size, batch_first=True)  
        self.fc = nn.Linear(hidden_size, output_size)  
      
    def forward(self, x, hidden):  
        lstm_out, hidden = self.lstm(x, hidden)  
        output = self.fc(lstm_out[:, -1, :])  # 取最后一个时间步的输出进行分类  
        return output, hidden  
      
    def init_hidden(self, batch_size):  
        return (torch.zeros(1, batch_size, self.hidden_size),  
                torch.zeros(1, batch_size, self.hidden_size))  
  
# 模型参数  
input_size = 10  
hidden_size = 20  
output_size = 2  
batch_size = 1  
sequence_length = 5  
  
# 创建模型实例  
model = SimpleLSTM(input_size, hidden_size, output_size)  
  
# 创建虚拟输入数据和初始隐藏状态  
x = torch.randn(batch_size, sequence_length, input_size)  
hidden = model.init_hidden(batch_size)  
  
# 前向传播  
output, hidden = model(x, hidden)  
print(output)

C++代码

在C++中使用LSTM,我们通常会借助PyTorch的C++ API,也称为LibTorch。以下是一个简单的示例:

#include <torch/script.h> // 包含TorchScript的头文件  
#include <iostream>  
  
int main() {  
    // 加载一个预先训练好的LSTM模型(这里假设你已经有一个用PyTorch训练的模型并导出了TorchScript)  
    torch::jit::script::Module module;  
    try {  
        module = torch::jit::load("lstm_model.pt"); // 加载模型  
    } catch (const c10::Error& e) {  
        std::cerr << "模型加载错误\n";  
        return -1;  
    }  
  
    // 创建一个输入张量,假设输入大小为[1, 5, 10](batch_size, sequence_length, input_size)  
    torch::Tensor input = torch::randn({1, 5, 10});  
      
    // 执行模型前向传播  
    std::vector<torch::jit::IValue> inputs;  
    inputs.push_back(input);  
    torch::Tensor output = module.forward(inputs).toTensor();  
      
    std::cout << output << std::endl;  
    return 0;  
}

请注意,C++ 示例中的模型需要是预先训练好并导出为TorchScript的模型。TorchScript是PyTorch的一个子集,允许模型在没有Python运行时的环境中执行。

在C++中直接使用LSTM而不依赖预先训练的模型会更复杂,因为你需要手动实现LSTM的所有细节。这通常不是推荐的做法,除非你有特定的性能要求或需要深度定制LSTM的行为。

在大多数情况下,使用PyTorch等高级库会更加方便和高效。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/753452.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

一个分析电路图的好助手

GPT。 最进分析电路图的时候发现GPT支持读取图片功能&#xff1a; 还别说&#xff0c;分析的很有道理。 此外&#xff0c;它还可以分析芯片的引脚功能&#xff0c;辅助电路分析&#xff1a; AB胶&#xff1a;粘的非常牢固&#xff0c;需要A和B两种胶混合使用。

有兄弟对这类区域比较感兴趣,也引起我的好奇,我提取出来给大家看看

要说这类地区&#xff0c;亚洲泰国排第二估计没人敢说第一吧&#xff0c;所以我就提取泰国的数据给大家看看&#xff01; 如图&#xff1a;这些特殊服务地区主要集中在曼谷和芭提雅地区&#xff0c;芭提雅最多&#xff01;看来管理还是不错的&#xff0c;限制在一定范围&#x…

php composer 报错

引用文章&#xff1a; Composer设置国内镜像_composer 国内源-CSDN博客 php composer.phar require --prefer-dist yiidoc/yii2-redactor "*" A connection timeout was encountered. If you intend to run Composer without connecting to the internet, run the …

汉江师范学院2024年成人高等继续教育招生简章

汉江师范学院&#xff0c;这所承载着深厚文化底蕴和学术积淀的高等学府&#xff0c;即将在2024年迎来新一季的成人高等继续教育招生。这不仅是一次知识的盛宴&#xff0c;更是对每一位怀揣梦想、追求进步的成年人的诚挚邀请。 汉江师范学院&#xff0c;以其严谨的教学态度、卓…

老师如何发布学校分班情况?

随着新学期的临近&#xff0c;许多老师可能都会回想起过去那些忙碌的日子&#xff0c;他们不得不面对一堆学生名单&#xff0c;手动进行班级分配&#xff0c;然后逐一通知家长和学生&#xff0c;这种工作不仅繁琐而且容易出错&#xff0c;让人倍感压力。 然而&#xff0c;今天我…

真正的IDEA在线版有多好用

前言 在上一篇文章使用过TitanIDE的VS Code在线版以后&#xff0c;尝到了不少甜头&#xff0c;紧接着又去使用了他的在线版IntelliJ IDEA&#xff0c;同样非常惊艳&#xff0c;不需要任何时间去适应这款云原生开发工具,事不宜迟&#xff0c;马上开整 这才是真正的VS Code在线版…

9种慢慢被淘汰的编程语言...【送源码】

技术不断进步&#xff0c;我们使用的编程语言也不例外。 随着人工智能的兴起以及对编程语言使用的影响&#xff0c;我们更加关注哪些语言将在未来继续流行&#xff0c;哪些会被淘汰。 Python、Java 和 JavaScript 等多功能编程语言正在主导市场&#xff0c;而其他一些语言则逐…

第 1 章SwiftUI 简介

在 2019 年的 WWDC 上,Apple 宣布推出一款名为 SwiftUI 的全新框架,令开发者们大吃一惊。该框架不仅改变了开发 iOS 应用的方式,还代表了自 Swift 首次亮相以来 Apple 开发者生态系统最重大的转变。SwiftUI 适用于所有 Apple 平台,包括 iPadOS、macOS、tvOS 和 watchOS,这…

REST API 中的 HTTP 请求参数

当我们在谈论现代 Web 开发时&#xff0c;REST API (Representational State Transfer Application Programming Interface) 扮演着至关重要的角色。它允许不同的系统以一种简洁且高效的方式进行通信。HTTP 请求参数是控制此通信流程中数据如何被发送和接收的重要组成部分。 H…

加密教程:pdf怎么加密?7个pdf加密技巧任你选(图文详解)

pdf作为一种便携式文档&#xff0c;是展示内容的首选格式&#xff0c;目前也已广泛应用于交换和分享重要等温&#xff0c;例如内部报告、人力资源文件&#xff0c;以及商业提案等包含敏感信息的文档。然而&#xff0c;在如今的数字化时代&#xff0c;随着越来越多的企业将其文档…

mfc140.dll怎么安装?mfc140.dll丢失安装详细解决方法

当电脑出现找不到mfc140.dll丢失问题&#xff0c;我们需要怎么办&#xff1f;怎么解决mfc140.dll丢失问题&#xff1f;mfc140.dll到底是什么&#xff1f;下面我给大家详细介绍与分析&#xff0c;最重要的是mfc140.dll的解决方法&#xff01; 一、文件丢失原因分析 在分析mfc14…

golang 获取系统的主机 CPU 内存 磁盘等信息

golang 获取系统的主机 CPU 内存 磁盘等信息 要求 需要go1.18或更高版本 官方地址&#xff1a;https://github.com/shirou/gopsutil 使用 #下载包 go get github.com/shirou/gopsutil/v3/cpu go get github.com/shirou/gopsutil/v3/disk go get github.com/shirou/gopsuti…

PIP安装Python扩展包超时解决办法-国内镜像

问题描述 使用pip安装Python扩展包经常超时&#xff0c;无法安装 解决方法 使用清华大学镜像&#xff1a; https://pypi.tuna.tsinghua.edu.cn/simple/ 使用方法&#xff1a;以openpyxl为例 原来&#xff1a;pip install openpyxl 现在&#xff1a;pip install -i https…

Git与GitLab的企业实战--尚硅谷git课程

Git与GitLab的企业实战 第1章 Git概述 Git是一个免费的、开源的分布式版本控制系统&#xff0c;可以快速高效地处理从小型到大型的各种项目。 Git易于学习&#xff0c;占地面积小&#xff0c;性能极快。 它具有廉价的本地库&#xff0c;方便的暂存区域和多个工作流分支等特性…

IEEE JSTSP综述:从信号处理领域分析视触觉传感器的研究

触觉传感器是机器人系统的重要组成部分&#xff0c;虽然与视觉相比触觉具有较小的感知面积&#xff0c;但却可以提供机器人与物体交互过程中更加真实的物理信息。 视觉触觉传感是一种分辨率高、成本低的触觉感知技术&#xff0c;被广泛应用于分类、抓取、操作等领域中。近期&a…

什么是指令微调(LLM)

经过大规模数据预训练后的语言模型已经具备较强的模型能力&#xff0c;能够编码丰富的世界知识&#xff0c;但是由于预训练任务形式所限&#xff0c;这些模型更擅长于文本补全&#xff0c;并不适合直接解决具体的任务。 指令微调是相对“预训练”来讲的&#xff0c;预训练的时…

UG_NX11.0之Windows11中安装出错及解决方法

UG_NX11.0之Windows11中安装出错及解决方法 文章目录 UG_NX11.0之Windows11中安装出错及解决方法1. 安装出错2. 解决方法1. 设置以兼容性模式运行2. 配置环境变量 3. 再次安装问题解决4. 安装后可删除配置的环境变量(可选) 1. 安装出错 以管理员身份运行Launch.exe,如下 点击D…

浅谈逻辑控制器之while控制器

浅谈逻辑控制器之while控制器 “While控制器”是一种高级控制结构&#xff0c;它允许用户基于特定条件来循环执行其下的子采样器或控制器&#xff0c;直至该条件不再满足。本文旨在详细介绍While控制器的功能、配置方法、使用场景以及实践示例&#xff0c;帮助测试工程师高效利…

浅谈红队攻防之道-DLL注入上线cs

等我熬过这一段狼狈&#xff0c;一个人尝尽孤独的滋味&#xff0c;我会笑着与这个世界和解 0x1 DLL注入概念 DLL注入(DLL Injection)是一种计算机编程技术&#xff0c;它可以强行使另一个进程加载一个动态链接库(DLL)以在其地址空间内运行指定代码。常见用途是改变原先程序的…

C++Primer Plus 第十四章代码重用:14.4.4 数组模板示例和非类型参数2

14.4.4 数组模板示例和非类型参数 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 例如&#xff1a;第一章 Python 机器学习入门之pandas的使用 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右…