24/10/14 算法笔记 循环神经网络RNN

RNN:

        一种专门用于处理序列数据的神经网络,它能够捕捉时间序列中的动态特征。RNN的核心特点是其循环连接,这允许网络在不同时间步之间传递信息,从而实现对序列数据的记忆和处理能力。

应用的场景:

自然语言处理(NLP)语音识别,时间序列预测(天气预报,股票),机器人控制(预测动作),图像处理

在前向传播过程中,RNN利用前一时间步的隐藏状态和当前时间步的输入来计算当前时间步的隐藏状态和输出,这种循环连接允许RNN在处理序列数据时考虑时间依赖性,从而在多种应用中表现出色。

然而,RNN在训练过程中可能会遇到梯度消失和梯度爆炸的问题,尤其是在处理长序列时。为了解决这些问题,研究者们开发了LSTM(长短期记忆网络)和GRU(门控循环单元)等变体,它们通过引入门控机制来控制信息的流动,从而有效地解决了梯度问题,并提高了RNN在长序列数据上的性能。

隐状态:

它代表了网络在处理序列数据时的内部记忆或信息状态。隐状态是网络在每个时间步的内部表示,它携带了序列中之前信息的累积效应,并用于预测当前时间步的输出。

  1. 信息的累积: 隐状态捕捉了序列中之前所有时间步的信息。在处理序列数据时,如文本、语音或时间序列数据,隐状态帮助网络记住重要的上下文信息。

  2. 序列依赖性: 由于隐状态的存在,RNN能够处理输入数据之间的序列依赖性。这意味着网络的输出不仅依赖于当前的输入,还依赖于之前的输入。

困惑度:困惑度(Perplexity)是一个衡量语言模型性能的指标,尤其在自然语言处理(NLP)领域中。它主要用于评估语言模型对文本序列的预测能力。困惑度越低,表示模型对数据的预测越准确。

困惑度可以被解释为模型在预测下一个词时的平均分支数。例如,如果困惑度为 100,这意味着对于每个词,模型平均需要从 100 个可能的词中选择下一个词。因此,困惑度越低,表示模型的预测越准确。困惑度常用于比较不同的语言模型或评估模型在不同数据集上的性能。它也用于监控模型训练过程中的性能变化,帮助确定何时停止训练以避免过拟合。

循环神经网络的实现

初始化返回隐状态的函数

def __init_rnn_state(batch_size,num_hiddens,device):return(torch.zeros((batch_size,num_hiddens),device = device),)

在一个时间步内计算隐状态和输出

RNN的前向传播

def rnn(inputs,state,params):W_xh,W_hh,b_h,W_hq,b_q = paramsH, = state #这里的逗号 , 是必需的,它告诉 Python 解释器 H 是一个单独的元素,而不是一个元组。如果没有逗号,H = state 将会尝试将整个 state 赋值给变量 Houtputs = []for X in inputs:H = torch.tanh(torch.mm(X,W_xh)+torch.mm(H,W_hh)+b_h)Y = torch.mm(H, W_hq) + b_q   #torch.mm矩阵乘法outputs.append(Y)return torch.cat(outputs, dim=0), (H,)

包装

class RNNModelScratch: #@save"""从零开始实现的循环神经网络模型"""def __init__(self, vocab_size, num_hiddens, device,get_params, init_state, forward_fn):self.vocab_size, self.num_hiddens = vocab_size, num_hiddensself.params = get_params(vocab_size, num_hiddens, device)self.init_state, self.forward_fn = init_state, forward_fndef __call__(self, X, state):X = F.one_hot(X.T, self.vocab_size).type(torch.float32)return self.forward_fn(X, state, self.params)def begin_state(self, batch_size, device):return self.init_state(batch_size, self.num_hiddens, device)

检查输出是否具有正确的形状

num_hiddens = 512
net = RNNModelScratch(len(vocab), num_hiddens, d2l.try_gpu(), get_params,init_rnn_state, rnn)
state = net.begin_state(X.shape[0], d2l.try_gpu())
Y, new_state = net(X.to(d2l.try_gpu()), state)
Y.shape, len(new_state), new_state[0].shape

 预测

其中的prefix是一个用户提供的包含多个字符的字符串。 在循环遍历prefix中的开始字符时, 我们不断地将隐状态传递到下一个时间步,但是不生成任何输出。 这被称为预热(warm-up)期, 因为在此期间模型会自我更新(例如,更新隐状态), 但不会进行预测。 预热期结束后,隐状态的值通常比刚开始的初始值更适合预测, 从而预测字符并输出它们。
def predict_ch8(prefix, num_preds, net, vocab, device):  #@save"""在prefix后面生成新字符"""state = net.begin_state(batch_size=1, device=device)outputs = [vocab[prefix[0]]]get_input = lambda: torch.tensor([outputs[-1]], device=device).reshape((1, 1))for y in prefix[1:]:  # 预热期_, state = net(get_input(), state)outputs.append(vocab[y])for _ in range(num_preds):  # 预测num_preds步y, state = net(get_input(), state)outputs.append(int(y.argmax(dim=1).reshape(1)))return ''.join([vocab.idx_to_token[i] for i in outputs])

梯度裁剪

def grad_clipping(net, theta):  #@save"""裁剪梯度"""if isinstance(net, nn.Module):params = [p for p in net.parameters() if p.requires_grad]else:params = net.paramsnorm = torch.sqrt(sum(torch.sum((p.grad ** 2)) for p in params))if norm > theta:for param in params:param.grad[:] *= theta / norm

训练

def train_epoch_ch8(net, train_iter, loss, updater, device, use_random_iter):"""训练网络一个迭代周期(定义见第8章)"""state, timer = None, d2l.Timer()metric = d2l.Accumulator(2)  # 训练损失之和,词元数量for X, Y in train_iter:if state is None or use_random_iter:# 在第一次迭代或使用随机抽样时初始化statestate = net.begin_state(batch_size=X.shape[0], device=device)else:if isinstance(net, nn.Module) and not isinstance(state, tuple):# state对于nn.GRU是个张量state.detach_()else:# state对于nn.LSTM或对于我们从零开始实现的模型是个张量for s in state:s.detach_()y = Y.T.reshape(-1)X, y = X.to(device), y.to(device)y_hat, state = net(X, state)l = loss(y_hat, y.long()).mean()if isinstance(updater, torch.optim.Optimizer):updater.zero_grad()l.backward()grad_clipping(net, 1)updater.step()else:l.backward()grad_clipping(net, 1)# 因为已经调用了mean函数updater(batch_size=1)metric.add(l * y.numel(), y.numel())return math.exp(metric[0] / metric[1]), metric[1] / timer.stop()

用高级API实现

def train_ch8(net, train_iter, vocab, lr, num_epochs, device,use_random_iter=False):"""训练模型(定义见第8章)"""loss = nn.CrossEntropyLoss()animator = d2l.Animator(xlabel='epoch', ylabel='perplexity',legend=['train'], xlim=[10, num_epochs])# 初始化if isinstance(net, nn.Module):updater = torch.optim.SGD(net.parameters(), lr)else:updater = lambda batch_size: d2l.sgd(net.params, lr, batch_size)predict = lambda prefix: predict_ch8(prefix, 50, net, vocab, device)# 训练和预测for epoch in range(num_epochs):ppl, speed = train_epoch_ch8(net, train_iter, loss, updater, device, use_random_iter)if (epoch + 1) % 10 == 0:print(predict('time traveller'))animator.add(epoch + 1, [ppl])print(f'困惑度 {ppl:.1f}, {speed:.1f} 词元/秒 {str(device)}')print(predict('time traveller'))print(predict('traveller'))
num_epochs, lr = 500, 1
train_ch8(net, train_iter, vocab, lr, num_epochs, d2l.try_gpu())

检查一下使用随机抽样方法的结果

net = RNNModelScratch(len(vocab), num_hiddens, d2l.try_gpu(), get_params,init_rnn_state, rnn)
train_ch8(net, train_iter, vocab, lr, num_epochs, d2l.try_gpu(),use_random_iter=True)

循环神经网络的简洁实现

定义模型

num_hiddens = 256
rnn_layer = nn.RNN(len(vocab), num_hiddens)

使用张量来初始化隐状态

state = torch.zeros((1, batch_size, num_hiddens))

通过一个隐状态和一个输入,我们就可以用更新后的隐状态计算输出。

X = torch.rand(size=(num_steps, batch_size, len(vocab)))
Y, state_new = rnn_layer(X, state)
Y.shape, state_new.shape

为一个完整的循环神经网络模型定义一个RNNModel

class RNNModel(nn.Module):"""循环神经网络模型"""def __init__(self, rnn_layer, vocab_size, **kwargs):super(RNNModel, self).__init__(**kwargs)self.rnn = rnn_layerself.vocab_size = vocab_sizeself.num_hiddens = self.rnn.hidden_size# 如果RNN是双向的(之后将介绍),num_directions应该是2,否则应该是1if not self.rnn.bidirectional:self.num_directions = 1self.linear = nn.Linear(self.num_hiddens, self.vocab_size)else:self.num_directions = 2self.linear = nn.Linear(self.num_hiddens * 2, self.vocab_size)def forward(self, inputs, state):X = F.one_hot(inputs.T.long(), self.vocab_size)X = X.to(torch.float32)Y, state = self.rnn(X, state)# 全连接层首先将Y的形状改为(时间步数*批量大小,隐藏单元数)# 它的输出形状是(时间步数*批量大小,词表大小)。output = self.linear(Y.reshape((-1, Y.shape[-1])))return output, statedef begin_state(self, device, batch_size=1):if not isinstance(self.rnn, nn.LSTM):# nn.GRU以张量作为隐状态return  torch.zeros((self.num_directions * self.rnn.num_layers,batch_size, self.num_hiddens),device=device)else:# nn.LSTM以元组作为隐状态return (torch.zeros((self.num_directions * self.rnn.num_layers,batch_size, self.num_hiddens), device=device),torch.zeros((self.num_directions * self.rnn.num_layers,batch_size, self.num_hiddens), device=device))

训练与预测

device = d2l.try_gpu()
net = RNNModel(rnn_layer, vocab_size=len(vocab))
net = net.to(device)
d2l.predict_ch8('time traveller', 10, net, vocab, device)

由于深度学习框架的高级API对代码进行了更多的优化, 该模型在较短的时间内达到了较低的困惑度。

  • 相比从零开始实现的循环神经网络,使用高级API实现可以加速训练。

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

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

相关文章

关于Python AI 编程助手Fitten Code的应用体验以及Python 修改删除 sys.path 路径以实现两个项目代码的合并

一、关于Python AI 编程助手Fitten Code的应用体验 AI现在无孔不入,现在都开始进入到编程中了,有一个能适用多种编译器环境的AI编程插件 Fitten Code。其适配了 Viusal Studio,VS Code(本文使用),JetBrains 系列(本文使用)以及Vim…

如何使用C#实现Padim算法的训练和推理

目录 说明 项目背景 算法实现 预处理模块——图像预处理 主要模块——训练:Resnet层信息提取 主要模块——信息处理,计算Anomaly Map 主要模块——评估 主要模块——评估:门限值的确定 主要模块——推理 写在最后 项目下载链接 说…

进入 Searing-66 火焰星球:第一周游戏指南

Alpha 第四季已开启,穿越火焰星球 Searing-66,带你开启火热征程。准备好勇闯炙热的沙漠,那里有无情的高温和无情的挑战在等待着你。从高风险的烹饪对决到炙热的冒险,Searing-66 将把你的耐力推向极限。带上充足的水,天…

Java线程的状态以及转换条件,与操作系统线程状态的区别?

先看图增加点记忆。 Java线程状态: 线程状态转换图: 背景知识 JAVA的线程模型与操作系统线程的对应关系是1:1的,线程的调度权是由操作系统控制的。 为什么java的线程状态与操作系统不一致? JVM线程状态:RUNNAB…

【含开题报告+文档+PPT+源码】基于SSM的景行天下旅游网站的设计与实现

开题报告 随着互联网的快速发展,旅游业也逐渐进入了数字化时代。作为一个旅游目的地,云浮市意识到了互联网在促进旅游业发展方面的巨大潜力。为了更好地推广云浮的旅游资源,提高旅游服务质量,云浮市决定开发一个专门的旅游网站。…

【红日安全】vulnstack (一)

🏘️个人主页: 点燃银河尽头的篝火(●’◡’●) 如果文章有帮到你的话记得点赞👍收藏💗支持一下哦 【红日安全】vulnstack (一) 靶场搭建靶场渗透明确目标信息收集phpadmin后台getshell 靶场搭建 靶场下载…

IP报文格式、IPv6概述

IPv4报文格式 IPv4报文首部长度至少为20字节(没有可选字段和填充的情况下),下面来逐一介绍首部各个字段的含义 Version版本:表示采用哪一种具体的IP协议,对于IPv4来说该字段就填充4以表示,如果是IPv6就填充6IHL首部长度&#xff…

网络资源模板--Android Studio 实现简易计算器App

目录 一、项目演示 二、项目测试环境 三、项目详情 四、完整的项目源码 一、项目演示 网络资源模板--基于Android studio 实现的简易计算器 二、项目测试环境 三、项目详情 动态绑定按钮: 使用循环遍历 buttons 数组,根据动态生成的按钮 ID (btn_0, …

SQL进阶技巧:如何删除第N次连续出现NULL值所存在的行?

目录 0 场景描述 1 数据准备 2 问题分析 问题拓展:如何删除第2次、第3次、第N次连续出现NULL值所在的行? 3 小结 0 场景描述 有下面的场景: 我们希望删除某id中连续存在NULL值的所有行,但是保留第一次出现不为NULL值的以下所有存在NULL值的行。具体如下图所示: 如…

iframe的使用详解

目录 一、基本概念和语法 二、优点 1.内容整合与复用: 2.独立的浏览环境: 3.跨域数据展示: 三、缺点 1.可访问性问题: 2.性能问题: 3.安全风险: 四、替代方案 1.使用JavaScript框架进行组件化开…

Unity开发Hololens项目

Unity打包Hololens设备 目录Visual Studio2019 / Visual Studio2022 远端部署设置Visual Studio2019 / Visual Studio2022 USB部署设置Hololens设备如何查找自身IPHololens设备门户Unity工程内的打包设置 目录 记录下自己做MR相关:Unity和HoloLens设备的历程。 Vi…

大规模多传感器滑坡检测数据集,利用landsat,哨兵2,planet,无人机图像等多种传感器采集数据共2w余副图像,mask准确标注滑坡位置

大规模多传感器滑坡检测数据集,利用landsat,哨兵2,planet,无人机图像等多种传感器采集数据共2w余副图像,mask准确标注滑坡位置 大规模多传感器滑坡检测数据集介绍 数据集概述 名称:大规模多传感器滑坡检测…

Python | Leetcode Python题解之第491题非递减子序列

题目: 题解: class Solution:def findSubsequences(self, nums: List[int]) -> List[List[int]]:def dfs(i, tmp):if i len(nums):if len(tmp) > 2:res.append(tmp[:]) # 拷贝,tmp[:]而非tmpreturn# 选 nums[i]if not tmp or nu…

2d 数字人实时语音聊天对话使用案例;支持asr、llm、tts实时语音交互

参考: https://github.com/lyz1810/live2dSpeek 下载live2dSpeek项目 ## 下载live2dSpeek git clone https://github.com/lyz1810/live2dSpeek cd live2dSpeek-main ## 运行live2dSpeek npm install -g http-server http-server .更改新的index.html页面 index.html

【SQL Server】数据库在新建查询后闪退——解决方案:以管理员的身份运行

我的SQLServer2022之前都是可以用的,隔了好久没有使用,今天要用到去写一些SQL 语句 结果在点击新建查询后闪退了, 经过查询后,解决方案: 以管理员的身份运行后点击新建查询,发现正常了 总结:以…

记一次库版本升级引起程序自动停止

记一次库版本升级引起程序自动停止 最近我们的应用升级了jedis 版本,版本从 2.10.2 升级 到3.8.0。发现我们的任务应用启动后立马自动关闭了。 这就奇怪了,为什么升级个版本,会导致程序启动后自动关闭呢。带着这个疑问我们看下代码。 表现如下&#x…

C语言_指针_进阶

引言:在前面的c语言_指针初阶上,我们了解了简单的指针类型以及使用,下面我们将进入更深层次的指针学习,对指针的理解会有一个极大的提升。从此以后,指针将不再是难点,而是学习底层语言的一把利器。 本章重点…

vr体验馆计时收银软件试用版下载 佳易王VR游戏厅计时计费管理系统使用操作教程

一、前言 【软件试用版资源文件下载可以点击文章最后卡片了解】 vr体验馆计时收银软件试用版下载 佳易王VR游戏厅计时计费管理系统使用操作教程 VR体验馆计时计费软件是专门为VR体验馆设计的管理工具,旨在提高服务效率和客户的满意度。软件能够记录客户使用设备的…

vue组件调用生命周期

《vue基础学习-组件》提到组件传递数据方式: 1. props/$emit 父传子:子组件通过 props 显式声明 自定义 属性,接收父组件的传值。子传父:子组件通过 $emit() 显式声明 自定义 事件,父组件调用自定义事件接收子组件返…

Docker-compose提示specified IP address..configured subnets问题以及Docker容器相关操作记录保存

一、Docker-compose提示user specified IP address is supported only when connecting to networks with user configured subnets 在网上下载的一些docker-compose.yml在执行的时碰到过多次如下报错: ERROR: for 5307e2acb....user specified IP address is supp…