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

news2024/11/24 19:49:59

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

目录

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.coloradmin.cn/o/1873870.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vscode 生成项目目录结构 directory-tree 实用教程

1. 安装插件 directory-tree 有中文介绍&#xff0c;极其友好&#xff01; 2. 用 vscode 打开目标项目 3. 快捷键 Ctrl Shift p&#xff0c;输入 Directory Tree 后回车 会在 README.md 文件的底部生成项目目录&#xff08;若项目中没有 README.md 文件&#xff0c;则会自动创…

数据结构速成--图

由于是速成专题&#xff0c;因此内容不会十分全面&#xff0c;只会涵盖考试重点&#xff0c;各学校课程要求不同 &#xff0c;大家可以按照考纲复习&#xff0c;不全面的内容&#xff0c;可以看一下小编主页数据结构初阶的内容&#xff0c;找到对应专题详细学习一下。 目录 …

CO-DETR利用coco数据集训练和推理过程

CO-DETR利用coco数据集训练和推理过程&#xff0c;参考链接 Co-DETR训练自己的数据集 文章目录 前言训练过程推理过程总结 前言 环境&#xff1a;PyTorch 1.11.0 Python 3.8(ubuntu20.04) Cuda 11.3 先是在github上下载CO-DETR模型 !git clone https://github.com/Sense-X/Co…

JAVA设计模式-大集合数据拆分

背景 我们在做软件开发时&#xff0c;经常会遇到把大集合的数据&#xff0c;拆分成子集合处理。例如批量数据插入数据库时&#xff0c;一次大约插入5000条数据比较合理&#xff0c;但是有时候待插入的数据远远大于5000条。这时候就需要进行数据拆分。数据拆分基本逻辑并不复杂&…

复分析——第9章——椭圆函数导论(E.M. Stein R. Shakarchi)

第 9 章 椭圆函数导论 (An Introduction to Elliptic Functions) The form that Jacobi had given to the theory of elliptic functions was far from perfection; its flaws are obvious. At the base we find three fundamental functions sn, cn and dn. These functio…

一款轻量级的WPF UI库---Adonis UI

Adonis UI适用于 WPF 应用程序的轻型 UI 工具包,提供经典但增强的 Windows 视觉对象 组件内容 几乎所有 WPF 控件的模板的默认样式为方便起见,可根据需要使用两种配色方案(浅色和深色),也可用于自定义样式支持在运行时更改配色方案支持其他自定义配色方案提供水印等功能的…

华为BGP路由实验基础1------用物理口建立对等体

1.用物理口做BGP建立对等体建立BGP连接 实验拓扑&#xff1a; 实验步骤&#xff1a; 1.完成基本配置 sys [Huawei]sys AR1 [AR1]undo in e [AR1]int g0/0/0 [AR1-GigabitEthernet0/0/0]ip add 1.1.1.1 24 [AR1-GigabitEthernet0/0/0]q [AR1] sys [Huawei]sys AR2 [AR2]undo i…

2024年危化品安全员生产单位(生产管理人员)考试精选题库

31.《危险化学品安全管理条例》所称重大危险源,是指生产、储存、使用或者搬运危险化学品,且危险化学品的数量等于或者超过&#xff08;&#xff09;的单元(包括场所和设施)。 A.标准 B.一定量 C.临界量 答案&#xff1a;C 32.《危险化学品生产企业安全生产许可证实施办法》…

Sui创始团队在竞速环节中的快问快答

在Sui Basecamp活动期间&#xff0c;Sui区块链的最初贡献者在Oracle红牛赛车模拟器上展示了他们的技术能力&#xff0c;在驾驶圈时回答了有关Sui的问题。 Evan Cheng&#xff08;又名Revvin’ Evan&#xff09;在解释Mysticeti创下区块链最终性记录的同时保持着他的驾驶线路。…

C++——string类用法指南

一、前言 在C语言中&#xff0c;字符串是以\0结尾的一些字符的集合&#xff0c;为了操作方便&#xff0c;C标准库中提供了一些str系列的库函数&#xff0c;但是这些库函数与字符串是分离的&#xff0c;不太符合OOP的思想&#xff0c;而且底层空间需要用户自己管理&#xff0c;稍…

Linux—系统安全及应用

目录 一、账号安全控制 1、系统账号清理 1.1、将用户账号设置为无法登录 1.2、锁定长期不使用的账号 1.3、删除无用的账号 1.4、锁定账号文件passwd、shadow 2、密码安全控制 2.1、设置密码有效期 2.1.1、适用于新建用户 2.1.2、适用于已有用户 2.2、强制用户下次登录…

Python学习笔记26:进阶篇(十五)常见标准库使用之性能测试cProfile模块学习使用

前言 本文是根据python官方教程中标准库模块的介绍&#xff0c;自己查询资料并整理&#xff0c;编写代码示例做出的学习笔记。 根据模块知识&#xff0c;一次讲解单个或者多个模块的内容。 教程链接&#xff1a;https://docs.python.org/zh-cn/3/tutorial/index.html 本文主要…

Qt—贪吃蛇项目(由0到1实现贪吃蛇项目)

用Qt实现一个贪吃蛇项目 一、项目介绍二、游戏大厅界面实现2.1完成游戏大厅的背景图。2.2创建一个按钮&#xff0c;给它设置样式&#xff0c;并且可以跳转到别的页面 三、难度选择界面实现四、 游戏界面实现五、在文件中写入历史战绩5.1 从文件里提取分数5.2 把贪吃蛇的长度存入…

华为OceanStor磁盘阵列存储恢复出厂设置命令 LUN不处于在线状态,不能执行此操作解决方案

环境 OceanStor S2600T V2老版本 客户现场有一台Oceanstor 2600 V2的存储&#xff0c;因和另一台磁盘扩展框做了跨设备LUN需要进行配置清除&#xff0c;配置结束后需要重新划分存储空间并对接服务器&#xff0c;保证业务能够正常上线&#xff01;在清除配置回退的过程中&#…

Firefox 编译指南2024 Windows10篇- 编译Firefox(三)

1.引言 在成功获取了Firefox源码之后&#xff0c;下一步就是将这些源码编译成一个可执行的浏览器。编译是开发流程中的关键环节&#xff0c;通过编译&#xff0c;我们可以将源代码转换为可执行的程序&#xff0c;测试其功能&#xff0c;并进行必要的优化和调试。 对于像Firef…

Milvus【部署 01】向量数据库Milvus在Linux环境下的在线+离线安装

向量数据库Milvus在Linux环境下的在线离线安装 1.千问简介2.在线安装2.离线安装 1.千问简介 Milvus 是一款专为处理高维向量数据设计的开源云原生数据库&#xff0c;旨在满足海量向量数据的实时召回需求。它由 Zilliz 公司开发并维护&#xff0c;基于Apache许可证2.0版本发布。…

选择适合你的8款原型设计工具

随着互联网的飞速发展&#xff0c;设计行业逐渐成为近年来的热门职业。设计师们需要的掌握的技能也越来越多&#xff0c;例如海报设计、名片设计、产品设计、网页设计等。产品原型设计就是产品设计中非常重要的一个阶段&#xff0c;主要目的是帮助用户更容易了解产品设计的思路…

YouTube广告投放指南:如何投放 YouTube视频广告

在海外广告投放中&#xff0c;YOutube是重要的渠道之一。这篇文章Maskfog将为你介绍Youtube广告类型以及广告投放流程&#xff0c;继续看下去&#xff01; YouTube 视频广告的类型 1.信息流视频广告 信息流视频广告显示在 YouTube 主页、搜索结果页面上&#xff0c;并作为 Yo…

【pytorch10】统计属性

常见统计属性 norm&#xff08;范数&#xff09;mean,sumprodmax&#xff0c;min&#xff0c;argmin&#xff0c;argmaxkthvalue&#xff0c;topk kthvalue求第几个的位置和第几个的值 topk求top几的这样的一个数值 norm范数 这里的norm表达的是范数的意思&#xff0c;norma…

wait/notify 的原理

目录 一、wait/notify 的原理 二、虚假唤醒&#xff08;错误唤醒&#xff09; 三、使用 wait/notify 的正确姿势 一、wait/notify 的原理 1. owner 线程发现有条件不满足&#xff0c;调用 wait() 进入 Monitor 的 WaitSet 等待&#xff0c;切换为 Waiting 状态 2. 问题&…