9.4. 循环神经网络¶ 在 SageMaker Studio Lab 中打开 Notebook
在 第 9.3 节中,我们介绍了用于语言建模的马尔可夫模型和\(n\)元语法,其中时间步\(t\)的词元\(x_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})\)进行建模,不如使用隐变量模型,
其中\(h_{t-1}\)是一个*隐藏状态*,它存储了到时间步\(t-1\)为止的序列信息。通常,任何时间步\(t\)的隐藏状态都可以根据当前输入\(x_{t}\)和前一个隐藏状态\(h_{t-1}\)计算得出
对于 (9.4.2) 中一个足够强大的函数 \(f\),隐变量模型并非一个近似。毕竟,\(h_t\) 可以简单地存储它到目前为止所观察到的所有数据。然而,这可能会使计算和存储都变得代价高昂。
回想一下,我们在 第 5 节 中讨论了带有隐藏单元的隐藏层。值得注意的是,隐藏层和隐藏状态指的是两个截然不同的概念。如前所述,隐藏层是在从输入到输出的路径上隐藏起来的层。隐藏状态严格来说是我们给定步骤中任何操作的*输入*,它们只能通过查看先前时间步的数据来计算。
循环神经网络(RNNs)是具有隐藏状态的神经网络。在介绍RNN模型之前,我们首先回顾一下在 第 5.1 节 中介绍的多层感知机模型。
import torch
from d2l import torch as d2l
from mxnet import np, npx
from d2l import mxnet as d2l
npx.set_np()
import jax
from jax import numpy as jnp
from d2l import jax as d2l
No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)
import tensorflow as tf
from d2l import tensorflow as d2l
9.4.3. 基于RNN的字符级语言模型¶
回想一下,在第 9.3 节中进行语言建模时,我们的目标是根据当前和过去的词元预测下一个词元;因此我们将原始序列向后移动一个词元作为目标(标签)。Bengio 等人(2003)首次提出使用神经网络进行语言建模。接下来,我们演示如何使用RNN构建语言模型。设小批量大小为1,文本序列为“machine”。为了简化后续章节的训练,我们将文本分词为字符而不是单词,并考虑一个*字符级语言模型*。图 9.4.2演示了如何通过RNN进行字符级语言建模,以根据当前和之前的字符预测下一个字符。
图 9.4.2 基于RNN的字符级语言模型。输入和目标序列分别是“machin”和“achine”。¶
在训练过程中,我们对每个时间步的输出层输出运行softmax操作,然后使用交叉熵损失来计算模型输出与目标之间的误差。由于隐藏层中隐藏状态的循环计算,图 9.4.2中时间步3的输出\(\mathbf{O}_3\)由文本序列“m”、“a”和“c”决定。由于训练数据中序列的下一个字符是“h”,因此时间步3的损失将取决于基于特征序列“m”、“a”、“c”生成的下一个字符的概率分布以及该时间步的目标“h”。
在实践中,每个词元都由一个\(d\)维向量表示,我们使用批量大小\(n>1\)。因此,时间步\(t\)的输入\(\mathbf X_t\)将是一个\(n\times d\)矩阵,这与我们在第 9.4.2 节中讨论的完全相同。
在接下来的章节中,我们将为字符级语言模型实现RNNs。
9.4.4. 小结¶
使用循环计算来处理隐藏状态的神经网络称为循环神经网络(RNN)。RNN的隐藏状态可以捕获截至当前时间步的序列历史信息。通过循环计算,RNN模型参数的数量不会随着时间步数的增加而增长。至于应用方面,RNN可以用来创建字符级语言模型。