动手学深度学习8.4. 循环神经网络-笔记练习(PyTorch)

news2024/9/21 14:45:52

本节课程地址:54 循环神经网络 RNN【动手学深度学习v2】_哔哩哔哩_bilibili

本节教材地址:8.4. 循环神经网络 — 动手学深度学习 2.0.0 documentation (d2l.ai)

本节开源代码:...>d2l-zh>pytorch>chapter_multilayer-perceptrons>rnn.ipynb


循环神经网络

在 8.3节 中, 我们介绍了 n 元语法模型, 其中单词 x_t 在时间步 t 的条件概率仅取决于前面 n-1 个单词。 对于时间步 t-(n-1) 之前的单词, 如果我们想将其可能产生的影响合并到 x_t 上, 需要增加 n ,然而模型参数的数量也会随之呈指数增长, 因为词表 \mathcal{V} 需要存储 |\mathcal{V}|^n 个数字, 因此与其将 P(x_t \mid x_{t-1}, \ldots, x_{t-n+1}) 模型化, 不如使用隐变量模型:

P(x_t \mid x_{t-1}, \ldots, x_1) \approx P(x_t \mid h_{t-1}), (8.4.1)

其中 h_{t-1} 是隐状态(hidden state), 也称为隐藏变量(hidden variable), 它存储了到时间步 t-1 的序列信息。 通常,我们可以基于当前输入 x_t 和先前隐状态 h_{t-1} 来计算时间步 t 处的任何时间的隐状态:

h_t = f(x_{t}, h_{t-1}). (8.4.2)

对于 (8.4.2)中的函数 f ,隐变量模型不是近似值。 毕竟 h_t 是可以仅仅存储到目前为止观察到的所有数据, 然而这样的操作可能会使计算和存储的代价都变得昂贵。

回想一下,我们在 4节 中 讨论过的具有隐藏单元的隐藏层。 值得注意的是,隐藏层和隐状态指的是两个截然不同的概念。 如上所述,隐藏层是在从输入到输出的路径上(以观测角度来理解)的隐藏的层, 而隐状态则是在给定步骤所做的任何事情(以技术角度来定义)的输入, 并且这些状态只能通过先前时间步的数据来计算。

循环神经网络(recurrent neural networks,RNNs) 是具有隐状态的神经网络。 在介绍循环神经网络模型之前, 我们首先回顾 4.1节 中介绍的多层感知机模型。

无隐状态的神经网络

让我们来看一看只有单隐藏层的多层感知机。 设隐藏层的激活函数为 \phi , 给定一个小批量样本 \mathbf{X} \in \mathbb{R}^{n \times d} , 其中批量大小为 n ,输入维度为 d , 则隐藏层的输出 \mathbf{H} \in \mathbb{R}^{n \times h} 通过下式计算:

\mathbf{H} = \phi(\mathbf{X} \mathbf{W}_{xh} + \mathbf{b}_h). (8.4.3)

在 (8.4.3)中, 我们拥有的隐藏层权重参数为 \mathbf{W}_{xh} \in \mathbb{R}^{d \times h}, 偏置参数为 \mathbf{b}_h \in \mathbb{R}^{1 \times h} , 以及隐藏单元的数目为 h 。 因此求和时可以应用广播机制(见 2.1.3节)。 接下来,将隐藏变量 H 用作输出层的输入。 输出层由下式给出:

\mathbf{O} = \mathbf{H} \mathbf{W}_{hq} + \mathbf{b}_q,(8.4.4)

其中, \mathbf{O} \in \mathbb{R}^{n \times q} 是输出变量, \mathbf{W}_{hq} \in \mathbb{R}^{h \times q} 是权重参数, \mathbf{b}_q \in \mathbb{R}^{1 \times q} 是输出层的偏置参数。 如果是分类问题,我们可以用 \text{softmax}(\mathbf{O}) 来计算输出类别的概率分布。

这完全类似于之前在 8.1节 中解决的回归问题, 因此我们省略了细节。 无须多言,只要可以随机选择“特征-标签”对, 并且通过自动微分和随机梯度下降能够学习网络参数就可以了。

有隐状态的循环神经网络

有了隐状态后,情况就完全不同了。 假设我们在时间步 t 有小批量输入 \mathbf{X}_t \in \mathbb{R}^{n \times d}。 换言之,对于 n 个序列样本的小批量, \mathbf{X}_t 的每一行对应于来自该序列的时间步 t 处的一个样本。 接下来,用 \mathbf{H}_t \in \mathbb{R}^{n \times h} 表示时间步 t 的隐藏变量。 与多层感知机不同的是, 我们在这里保存了前一个时间步的隐藏变量 \mathbf{H}_{t-1} , 并引入了一个新的权重参数 \mathbf{W}_{hh} \in \mathbb{R}^{h \times h}, 来描述如何在当前时间步中使用前一个时间步的隐藏变量。 具体地说,当前时间步隐藏变量由当前时间步的输入 与前一个时间步的隐藏变量一起计算得出:

\mathbf{H}_t = \phi(\mathbf{X}_t \mathbf{W}_{xh} + \mathbf{H}_{t-1} \mathbf{W}_{hh} + \mathbf{b}_h). (8.4.5)

与 (8.4.3) 相比, (8.4.5) 多添加了一项 \mathbf{H}_{t-1} \mathbf{W}_{hh} , 从而实例化了 (8.4.2) 。 从相邻时间步的隐藏变量 \mathbf{H}_{t} 和 \mathbf{H}_{t-1} 之间的关系可知, 这些变量捕获并保留了序列直到其当前时间步的历史信息, 就如当前时间步下神经网络的状态或记忆, 因此这样的隐藏变量被称为隐状态(hidden state)。 由于在当前时间步中, 隐状态使用的定义与前一个时间步中使用的定义相同, 因此 (8.4.5) 的计算是循环的(recurrent)。 于是基于循环计算的隐状态神经网络被命名为 循环神经网络(recurrent neural network)。 在循环神经网络中执行 (8.4.5) 计算的层 称为循环层(recurrent layer)。

有许多不同的方法可以构建循环神经网络, 由 (8.4.5) 定义的隐状态的循环神经网络是非常常见的一种。 对于时间步 t ,输出层的输出类似于多层感知机中的计算:

\mathbf{O}_t = \mathbf{H}_t \mathbf{W}_{hq} + \mathbf{b}_q. (8.4.6)

循环神经网络的参数包括隐藏层的权重 \mathbf{W}_{xh} \in \mathbb{R}^{d \times h}, \mathbf{W}_{hh} \in \mathbb{R}^{h \times h} 和偏置 \mathbf{b}_h \in \mathbb{R}^{1 \times h} , 以及输出层的权重 \mathbf{W}_{hq} \in \mathbb{R}^{h \times q} 和偏置 \mathbf{b}_q \in \mathbb{R}^{1 \times q} 。 值得一提的是,即使在不同的时间步,循环神经网络也总是使用这些模型参数。 因此,循环神经网络的参数开销不会随着时间步的增加而增加。

图8.4.1 展示了循环神经网络在三个相邻时间步的计算逻辑。 在任意时间步 t ,隐状态的计算可以被视为:

  1. 拼接当前时间步 t 的输入 \mathbf{X}_t 和前一时间步 t-1 的隐状态 \mathbf{H}_{t-1} ;
  2. 将拼接的结果送入带有激活函数 \phi 的全连接层。 全连接层的输出是当前时间步 t 的隐状态 \mathbf{H}_{t} 。

在本例中,模型参数是 \mathbf{W}_{xh}  \mathbf{W}_{hh} 的拼接, 以及 \mathbf{b}_h 的偏置,所有这些参数都来自 (8.4.5)。 当前时间步 t 的隐状态 \mathbf{H}_{t} 将参与计算下一时间步 t+1 的隐状态 \mathbf{H}_{t+1} 。 而且 \mathbf{H}_{t} 还将送入全连接输出层, 用于计算当前时间步 t 的输出 \mathbf{O}_t 。

我们刚才提到,隐状态中 \mathbf{X}_t \mathbf{W}_{xh} + \mathbf{H}_{t-1} \mathbf{W}_{hh} 的计算, 相当于 \mathbf{X}_t 和 \mathbf{H}_{t-1} 的拼接 与 \mathbf{W}_{xh} 和 \mathbf{W}_{hh} 的拼接的矩阵乘法。 虽然这个性质可以通过数学证明, 但在下面我们使用一个简单的代码来说明一下。 首先,我们定义矩阵X、W_xh、H和W_hh, 它们的形状分别为(3,1)、(1,4)、(3,4)和(4,4)。 分别将X乘以W_xh,将H乘以W_hh, 然后将这两个乘法相加,我们得到一个形状为(3,4)的矩阵。

import torch
from d2l import torch as d2l
X, W_xh = torch.normal(0, 1, (3, 1)), torch.normal(0, 1, (1, 4))
H, W_hh = torch.normal(0, 1, (3, 4)), torch.normal(0, 1, (4, 4))
torch.matmul(X, W_xh) + torch.matmul(H, W_hh)

输出结果:
tensor([[ 1.1244, 0.3294, 0.2590, 1.7822],
[ 0.9678, -2.0727, 1.8833, -0.9362],
[-2.6480, 5.5913, 3.1343, 2.0930]])

现在,我们沿列(轴1)拼接矩阵X和H, 沿行(轴0)拼接矩阵W_xh和W_hh。 这两个拼接分别产生形状(3, 5)和形状(5, 4)的矩阵。 再将这两个拼接的矩阵相乘, 我们得到与上面相同形状(3, 4)的输出矩阵。

torch.matmul(torch.cat((X, H), 1), torch.cat((W_xh, W_hh), 0))

输出结果:
tensor([[ 1.1244, 0.3294, 0.2590, 1.7822],
[ 0.9678, -2.0727, 1.8833, -0.9362],
[-2.6480, 5.5913, 3.1343, 2.0930]])


RNN补充:

\mathbf{H}_t = \phi(\mathbf{X}_t \mathbf{W}_{xh} + \mathbf{H}_{t-1} \mathbf{W}_{hh} + \mathbf{b}_h)

RNN多的一项 \mathbf{H}_{t-1} \mathbf{W}_{hh} 可以建立不同时刻的关联性,赋予网络记忆的能力。

从上图的RNN展开图中可以看出,RNN是多个沿着时序反复迭代的网络组成的大的网络结构,但由于每个时间点的网络和计算都是相同的,因此可以看作是循环计算。


基于循环神经网络的字符级语言模型

回想一下 8.3节 中的语言模型, 我们的目标是根据过去的和当前的词元预测下一个词元, 因此我们将原始序列移位一个词元作为标签。 Bengio等人首先提出使用神经网络进行语言建模 f="https://zh.d2l.ai/chapter_references/zreferences.html#id8">Bengioet al., 2003。 接下来,我们看一下如何使用循环神经网络来构建语言模型。 设小批量大小为1,批量中的文本序列为“machine”。 为了简化后续部分的训练,我们考虑使用 字符级语言模型(character-level language model), 将文本词元化为字符而不是单词。 图8.4.2 演示了 如何通过基于字符级语言建模的循环神经网络, 使用当前的和先前的字符预测下一个字符。

在训练过程中,我们对每个时间步的输出层的输出进行softmax操作, 然后利用交叉熵损失计算模型输出和标签之间的误差。 由于隐藏层中隐状态的循环计算, 图8.4.2中的第3个时间步的输出 O3 由文本序列“m”“a”和“c”确定。 由于训练数据中这个文本序列的下一个字符是“h”, 因此第3个时间步的损失将取决于下一个字符的概率分布, 而下一个字符是基于特征序列“m”“a”“c”和这个时间步的标签“h”生成的。

在实践中,我们使用的批量大小为 n>1 , 每个词元都由一个 d 维向量表示。 因此,在时间步 t 输入 \mathbf X_t 将是一个 n\times d 矩阵, 这与我们在 8.4.2节 中的讨论相同。

困惑度(Perplexity)

最后,让我们讨论如何度量语言模型的质量, 这将在后续部分中用于评估基于循环神经网络的模型。 一个好的语言模型能够用高度准确的词元来预测我们接下来会看到什么。 考虑一下由不同的语言模型给出的对“It is raining ...”(“...下雨了”)的续写:

  1. "It is raining outside"(外面下雨了);
  2. "It is raining banana tree"(香蕉树下雨了);
  3. "It is raining piouw;kcj pwepoiut"(piouw;kcj pwepoiut下雨了)。

就质量而言,例1显然是最合乎情理、在逻辑上最连贯的。 虽然这个模型可能没有很准确地反映出后续词的语义, 比如,“It is raining in San Francisco”(旧金山下雨了) 和“It is raining in winter”(冬天下雨了) 可能才是更完美的合理扩展, 但该模型已经能够捕捉到跟在后面的是哪类单词。 例2则要糟糕得多,因为其产生了一个无意义的续写。 尽管如此,至少该模型已经学会了如何拼写单词, 以及单词之间的某种程度的相关性。 最后,例3表明了训练不足的模型是无法正确地拟合数据的。

我们可以通过计算序列的似然概率来度量模型的质量。 然而这是一个难以理解、难以比较的数字。 毕竟,较短的序列比较长的序列更有可能出现, 因此评估模型产生托尔斯泰的巨著《战争与和平》的可能性 不可避免地会比产生圣埃克苏佩里的中篇小说《小王子》可能性要小得多。 而缺少的可能性值相当于平均数。

在这里,信息论可以派上用场了。 我们在引入softmax回归 ( 3.4.7节 )时定义了熵、惊异和交叉熵, 并在信息论的在线附录 中讨论了更多的信息论知识。 如果想要压缩文本,我们可以根据当前词元集预测的下一个词元。 一个更好的语言模型应该能让我们更准确地预测下一个词元。 因此,它应该允许我们在压缩序列时花费更少的比特。 所以我们可以通过一个序列中所有的 n 个词元的交叉熵损失的平均值来衡量:

\frac{1}{n} \sum_{t=1}^n -\log P(x_t \mid x_{t-1}, \ldots, x_1), (8.4.7)

其中 P 由语言模型给出, x_t 是在时间步 t 从该序列中观察到的实际词元。 这使得不同长度的文档的性能具有了可比性。 由于历史原因,自然语言处理的科学家更喜欢使用一个叫做困惑度(perplexity)的量。 简而言之,它是 (8.4.7) 的指数:

\exp\left(-\frac{1}{n} \sum_{t=1}^n \log P(x_t \mid x_{t-1}, \ldots, x_1)\right).

困惑度的最好的理解是“下一个词元的实际选择数的调和平均数”。 我们看看一些案例。

  • 在最好的情况下,模型总是完美地估计标签词元的概率为1。 在这种情况下,模型的困惑度为1。
  • 在最坏的情况下,模型总是预测标签词元的概率为0。 在这种情况下,困惑度是正无穷大。
  • 在基线上,该模型的预测是词表的所有可用词元上的均匀分布。 在这种情况下,困惑度等于词表中唯一词元的数量。 事实上,如果我们在没有任何压缩的情况下存储序列, 这将是我们能做的最好的编码方式。 因此,这种方式提供了一个重要的上限, 而任何实际模型都必须超越这个上限。

在接下来的小节中,我们将基于循环神经网络实现字符级语言模型, 并使用困惑度来评估这样的模型。


补充:

 


小结

  • 对隐状态使用循环计算的神经网络称为循环神经网络(RNN)。
  • 循环神经网络的隐状态可以捕获直到当前时间步序列的历史信息。
  • 循环神经网络模型的参数数量不会随着时间步的增加而增加。
  • 我们可以使用循环神经网络创建字符级语言模型。
  • 我们可以使用困惑度来评价语言模型的质量。

练习

1. 如果我们使用循环神经网络来预测文本序列中的下一个字符,那么任意输出所需的维度是多少?
解:
任意输出的维度=需要预测的文本序列总长度n,因为RNN的目的是预测下一个字符,所以需要为每个可能的字符提供一个概率值,因此,任意输出所需的维度为n。

2. 为什么循环神经网络可以基于文本序列中所有先前的词元,在某个时间步表示当前词元的条件概率?
解:
原因如下:

  • 隐状态 h_t 在每个时间步t都会接收前一时间隐状态 h_{t-1} 和当前输入 x_t 的信息,并更新,再循环传递下去,使得先前所有的词元信息得以循环保留。
  • RNN在处理序列的每个时间步时,都使用相同的权重矩阵,这意味着无论序列中的哪个位置,网络都会以相同的方式处理输入数据,但通过隐状态的更新,网络可以保持对不同时间步的敏感性。
  • 在训练过程中,通过反向传播算法,RNN能够计算损失函数关于每个时间步输入的梯度,这使得网络可以学习如何根据先前词元调整当前词元的预测。

3. 如果基于一个长序列进行反向传播,梯度会发生什么状况?
解:
可能出现梯度爆炸或梯度消失的问题,可以通过梯度裁剪、调整学习率、调整网络结构等方法解决。

4. 与本节中描述的语言模型相关的问题有哪些?
解:
本节中描述的根据一个单词的前几个字符预测下一个字符的语言模型,可以用于预测并纠正单词的拼写错误或者语法错误。 但如果给定的序列过长,也会有梯度消失或爆炸的问题;而且对于具有相同开头字符的单词的预测能力可能有限,比如probability和probably,如果输入是probab,则输出的困惑度可能较大。

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

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

相关文章

电池的电-热-寿命模型是什么?

一、背景 电池的电-热-寿命模型在工程领域具有重要意义,它是一种描述电池性能、温度与使用寿命之间相互关系的复杂模型。具体工程意义体现在以下几个方面: 性能预测: 通过电-热-寿命模型,工程师可以预测在不同负载条件下电池的…

FreeRTOS基础入门——FreeRTOS优先级翻转(十五)

个人名片: 🎓作者简介:嵌入式领域优质创作者🌐个人主页:妄北y 📞个人QQ:2061314755 💌个人邮箱:[mailto:2061314755qq.com] 📱个人微信:Vir2025WB…

【重磅升级】积木报表 v1.8.1 版本发布,支持填报功能

项目介绍 一款免费的数据可视化报表工具,含报表和大屏设计,像搭建积木一样在线设计报表!功能涵盖,数据报表、打印设计、图表报表、大屏设计等! Web 版报表设计器,类似于excel操作风格,通过拖拽完…

[数据结构] 开散列法 闭散列法 模拟实现哈希结构

标题:[数据结构] 开散列法 && 闭散列法 模拟实现哈希结构 个人主页:水墨不写bug 目录 一、闭散列法 核心逻辑的解决 i、为什么要设置位置状态?(伪删除法的使用) ii、哈希函数的设计 接口的实现 1、插入&a…

SD三分钟入门!秋叶大佬24年8月最新的Stable Diffusion整合包V4.9.7来了~

1 什么是 Stable Diffusion? Stable Diffusion(简称SD)是一种生成式人工智能技术,于2022年推出。它主要用于根据文本描述生成精细图像,同时也可应用于其他任务,如图像修补、扩展,以及在文本提…

圣诞节:白酒与西式料理的异国风情

随着冬日的脚步渐近,圣诞的钟声即将敲响。在这个充满异国情调和温馨氛围的节日里,一场中西合璧的美食盛宴悄然上演。豪迈白酒(HOMANLISM)与西式料理的碰撞,不仅为圣诞餐桌增添了几分不同的韵味,更让人们在这…

标准库_string的代码实现

前言 string不属于stl,string比stl出现的早的多,所以string属于标准库,不属于stl 大家可以在cplusplus网站看string的内容 string的六个构造函数 构造函数 在写构造函数的时候不管传的字符串里面有没有字符,都必须至少要new c…

zerojs前端面试题系列--vue3篇(4)

1. Vue3中的可选链运算符(?.)和空值合并运算符(??)是什么?它们有什么作用? 可选链运算符(?.)和空值合并运算符(??)是Vue 3.x中新增的两种运算符。 可选…

点餐小程序实战教程04变量定义和初始化

目录 1 什么是变量2 如何创建变量3 具体该选择什么类型4 变量的初始化5 await/async6 调试我们的程序7 运行我们的代码总结 日常碰到的最多的一句话是,我看到代码就发憷,我一点基础也没有。那低代码开发需要掌握什么样的基础,怎么才算是掌握了…

图像分割像素三分类效果

pets_fg 数据集 训练集: avg_score: 0.8818 - dice: 0.9138 - iou: 0.8520 - loss: 0.1116 - mae: 0.6862 训练集掩码效果 avg_score: 0.8415 - dice: 0.8798 - iou: 0.8065 - loss: 0.1601 - mae: 0.6882 验证集效果展示

提前锁定!2024云栖大会大数据AI参会攻略来啦

2024年9月19日~9月21日,一年一度的云栖大会又要与大家见面了。一文尽览大数据AI精彩预告,赶紧收藏吧! 9月20日上午 10:45~11:25 阿里云智能集团副总裁、计算平台事业部负责人汪军华带来大数据AI平台年度发布。揭晓全新的 OpenLake 方案如何为…

力扣题解2181

大家好,欢迎来到无限大的频道,有些日子没更新了(其实是因为懒) 言归正传,开始分享今日的题解。 题目描述: 合并零之间的节点 给一个链表的头节点 head ,该链表包含由 0 分隔开的一连串整数。…

七种方法加密图纸!2024企业要如何对CAD图纸进行加密?

随着企业信息化的发展,CAD图纸作为企业的核心数据之一,其安全性变得尤为重要。如何有效加密CAD图纸,以防止数据泄露,是众多企业关注的重点问题。本文将介绍2024年企业加密CAD图纸的七种有效方法,帮助企业提升图纸安全性…

记一次高版本view-design的组件迁移到自身项目的低版本

背景 npm i -S view-design当前老项目使用view-design这个组件库,但是当我们去官网查看该组件库最新版本,竟然发现没有博主想用的image/ImagePreivew这两个基础组件 说实话,有点离谱了哈!! 自己造轮子? …

软考基础知识之网络工程

目录 前言 网络工程 网络规划 1、网络需求分析 2、可行性研究 3、对现有网络的分析与描述 网络设计 1、网络逻辑结构设计 2、网络物理结构设计 3、 分层设计 网络实施 1、工程实施计划 2、网络设备到货验收 3、设备安装 4、系统测试 5、系统试运行 6、用户培训…

利用熵权法进行数值评分计算——算法过程

1、概述 在软件系统中,研发人员常常遇上需要对系统内的某种行为/模型进行评分的情况。例如根据系统的各种漏洞情况对系统安全性进行评分、根据业务员最近操作系统的情况对业务员工作状态进行打分等等。显然研发人员了解一种或者几种标准评分算法是非常有利于开展研…

mp4转文字怎么快速转换?5个软件教你快速进行视频提取文字

mp4转文字怎么快速转换?5个软件教你快速进行视频提取文字 将MP4视频转换为文字是一项常见的需求,尤其是在需要将视频中的对话、演讲或字幕转为文本时。通过使用AI转录软件,你可以快速将视频中的音频内容提取并转换为文字。以下介绍5款可以帮…

一个数组向左移动i位(学会分析问题,找出规律,不要小看任何一个小程序;小程序都是实现大的功能的基础--体现问题分解的思想)

学会分析问题,找出规律; 不要小看任何一个小程序,小程序都是实现大的功能的基础--体现问题分解的思想) 思想火花--好算法是反复努力和重新修正的结果 解法1:先将数组中的前i个元素存放在一个临时数组中,再将余下的n一i个元素左…

黑马点评15——分布式缓存-Redis分片集群

文章目录 搭建分片集群散列插槽集群伸缩故障转移RedisTemplate访问分片集群 搭建分片集群 参考我前面的文章:单机部署Redis集群 散列插槽 集群伸缩 添加新的节点后要重新分配插槽, 故障转移 这是自动的故障转移,但有时候需要手动的故障转移——比如更…

Hfinger:一款针对恶意软件HTTP请求的指纹识别工具

关于Hfinger Hfinger是一款功能强大的HTTP请求指纹识别工具,该工具使用纯Python开发,基于Tshark实现其功能,可以帮助广大研究人员对恶意软件的 HTTP 请求进行指纹识别。 该工具的主要目标是提供恶意软件请求的唯一表示(指纹&…