欢迎光临
我们一直在努力

深度学习29门控循环单元DRU、长短期记忆网路LSTM、深层循环神经网络

1. 门控循环单元GRU

① 相当于全连接层把X和H并在一起。

② 点圈是按元素乘法的意思。

③ 是可以学的,它可以根据前面的信息,看到这种情况知道哪些东西pass到下面的情况,哪些东西不pass到下面的情况。

④ 更新新隐藏状态的时候,要用到多少过去隐藏状态的信息。

⑤ 若Z全0,R全1,则会回到RNN状态。

个人看法: R_t 和 Z_t 都是根据过去的状态 H_{t-1} 和当前输入 X_t 计算得到的 【0,1】 之间的量。 R_t 首先与 H_{t-1} 进行元素积,由于 R_t 内部都是 【0,1】 的变量,因此是对过去的状态 H_{t-1} 进行一次选择,R_t 在某个位置的值越趋近于0,则表示这个位置的过去信息越倾向于被丢弃,反之保留。随后与 X_t 一起构成候选隐藏变量 \\tilde{H}_t。同样由于 R_t 的值在 【0,1】 中,它只会削弱过去的状态,而不会增强,因此被称为遗忘门(或重置门,重置过去的状态)。 Z_t 被称为更新门,因为它控制了隐藏状态的更新。假如Z_t全为1,则 H_t 将完全保留上一个时间的状态 H_{t-1};反之,则全盘采用当前时刻的候选隐藏变量 \\tilde{H}_t。 或许各位会有疑问,感觉 R_t 已经对过去有所选择,为何还要加上 Z_t 多此一举。个人认为,Z_t 实际上是对当前进行选择,根据老师的例子,如果一个序列中已经有很多的“猫”,那么再输入猫,实际上对于网络的正收益不大,可以抛弃,而 R_t 只能选择过去,不能抛弃当前,而 Z_t 可以。 总而言之,GRU通过两个门控网络,根据过去状态和当前输入,一方面对过去状态进行选择,一方面对当前状态也进行选择。

这段代码做的事一句话就能说清:**让计算机"读"完一本英文小说(《时间机器》),然后模仿它的文风自己写字**。用的是一种叫 GRU(门控循环单元)的神经网络。下面我从"它在干嘛"讲到"每段代码为什么这么写",尽量用比喻讲。

## 一、整体在干什么?

**任务:字符级语言模型(Character-level Language Model)**

– 把小说拆成一个一个**字符**(不是单词!),模型的任务是:看到前面的字符,**猜下一个字符是什么**。
– 比如看到 `time travel`,下一个字符大概率是 `l`;看到 `the `,下一个大概率是 `t`。
– 猜得准了,就能一个字一个字地"续写"出整段文字。训练完后打印的 `time traveller…` 就是模型自己编的"仿《时间机器》体"文字。

**为什么用 GRU 而不是普通 RNN?**

普通 RNN 就像一个金鱼记忆的读者:读到第 100 个字符时,早就忘了第 1 个字符说了啥(梯度消失)。GRU 给它发了两个"门",让它学会**选择性记忆**:

门作用比喻
更新门 Z (update) 决定旧记忆保留多少、新内容写入多少 记事本翻页:是继续用旧笔记,还是翻新页重写
重置门 R (reset) 决定写新笔记时要参考多少旧笔记 写新想法前,要不要翻看旧笔记找灵感

## 二、逐段代码讲解

### 1. 数据准备

```python
batch_size, num_steps = 32, 35
train_iter, vocab = d2l.load_data_time_machine(batch_size, num_steps)
```

– 整本小说被切成很多条"长度为 35 的字符序列"(`num_steps=35`),每 32 条打成一个小包(`batch_size=32`)喂给模型。
– 为什么是 35?太短看不出上下文,太长训练起来梯度不好传,35 是个"够用"的经验值。
– `vocab` 是字符字典:比如 `{'a': 0, 'b': 1, …}`,把字符变成数字才能进神经网络。

### 2. 初始化参数 `get_params` —— 给模型发"装备"

```python
def normal(shape):
    return torch.randn(size=shape, device=device) * 0.01
```

– 权重随机初始化(正态分布),**乘以 0.01** 让数值很小。
– **为什么小?** 初始权重太大,sigmoid/tanh 会饱和(输出全是 0 或 1),梯度传不动,模型学不会。小随机数 = 让模型从一个"接近白纸"的状态慢慢学。

```python
def three():
    return (normal((num_inputs, num_hiddens)),   # 输入→隐藏
            normal((num_hiddens, num_hiddens)),  # 上一时刻隐藏态→隐藏
            torch.zeros(num_hiddens, device=device))  # 偏置
```

– 每个门都需要三样东西:**怎么处理当前输入(X 的权重)**、**怎么处理旧记忆(H 的权重)**、**偏置**。三个门结构一样,所以抽成 `three()` 复用。
– `torch.zeros` 初始化偏置 —— **偏置从 0 开始**是惯例,因为偏置的作用是调节"门的开合倾向",0 表示一开始不偏不倚。

```python
W_xz, W_hz, b_z = three()  # 更新门的参数
W_xr, W_hr, b_r = three()  # 重置门的参数
W_xh, W_hh, b_h = three()  # 候选隐藏状态的参数
W_hq = normal((num_hiddens, num_hiddens→vocab))  # 记忆→输出
```

– 命名规律:`W_xz` = 输入 x 到门 z 的权重,`W_hz` = 隐藏态 h 到门 z 的权重。下标就是"从哪到哪"。
– `requires_grad_(True)`:告诉 PyTorch"这些数是要被训练的,请帮我记梯度"。

### 3. 初始化隐藏状态

```python
def init_gru_state(batch_size, num_hiddens, device):
    return (torch.zeros((batch_size, num_hiddens), device=device),)
```

– 隐藏状态 H 就是模型的"笔记本"。小说读第一句之前,笔记当然是**空白**的,所以全是 0。
– 注意包了一层元组 `(H,)`——这是为了接口统一(LSTM 有两个状态,RNN/GRU 只有一个,包成元组代码就能通用)。

### 4. 核心:GRU 前向计算(重头戏)

想象一个**边读小说边做笔记的人**,每个字符进来,他做三件事:

```python
Z = torch.sigmoid((X @ W_xz) + (H @ W_hz) + b_z)   # ① 更新门
R = torch.sigmoid((X @ W_xr) + (H @ W_hr) + b_r)   # ② 重置门
```

**① 更新门 Z**:把"当前看到的字 X"和"旧笔记 H"放一起打分,sigmoid 把分数压到 0~1 之间。
**为什么用 sigmoid?** 因为 sigmoid 输出是 0~1 的连续值,天然就是"阀门开度":0=全关,1=全开。这是它在这里的物理意义。

```python
H_tilda = torch.tanh((X @ W_xh) + ((R * H) @ W_hh) + b_h)  # ③ 候选隐藏状态
```

**② 重置门 R 的用武之地在这里**:`R * H` 是**逐元素相乘**——如果 R 接近 0,就相当于"写新笔记时基本不看旧笔记,从当前这个字重新开始";R 接近 1 则充分参考旧笔记。
比如小说刚开始新的一章,旧笔记是上一章的内容,R 就该关小,别让上一章的情节污染新开头。

```python
H = Z * H + (1 – Z) * H_tilda     # ④ 混合新旧记忆
```

**这是 GRU 的灵魂**。Z 和 `1-Z` 此消彼长,加起来恰好等于 1:

– Z=1 → `H = 旧笔记`,新内容完全忽略 → **长期记忆得以保存**(这就是它比 RNN 记得久的原因!)
– Z=0 → `H = 新笔记`,旧记忆全部丢弃

比喻:旧笔记 H 和新草稿 H_tilda 像两杯水,Z 决定按什么比例**调一杯新的混合饮料**。Z 对每个记忆维度(256 个数字里的每一个)独立控制,所以模型可以"只记住主角名字,忘掉不重要的天气描写"。

```python
Y = H @ W_hq + b_q
outputs.append(Y)
```

– 最后把"笔记"翻译成"对下一个字符的预测"(对 vocab 里每个字符打分)。
– 循环 35 次(`for X in inputs`),把每一步的预测拼起来返回。**这就是"循环"二字的含义:同一个公式反复用,笔记本 H 一路传递下去。**

### 5. 训练与结果解读

```python
model = d2l.RNNModelScratch(len(vocab), num_hiddens, device, get_params,
                            init_gru_state, gru)
d2l.train_ch8(model, train_iter, vocab, lr, num_epochs, device)
```

– `RNNModelScratch` 把前面手写的零件(参数、初始化、前向函数)打包成一个标准模型。
– `train_ch8` 是 d2l 的训练循环:循环地"喂 batch → 预测 → 算损失 → 反向传播 → 更新参数",还内置了**梯度裁剪**(防止循环网络梯度爆炸)。

看懂输出:

```
perplexity 1.1, 29478.1 tokens/sec on cuda:0
time travelleryou can show black is white by argument said filby
```

– **perplexity(困惑度)**:模型猜下一个字时的"犹豫程度"。1.1 ≈ 几乎每次只在 1~2 个候选里纠结,基本背下了原文风格(1 是完美)。想象模型面前摆着一排字符按钮,困惑度就是"它平均在几个按钮之间摇摆"。
– **29478 tokens/sec**:每秒处理 3 万个字符,衡量速度。
– 生成的文字以 `time traveller` 开头是因为 d2l 默认用这个前缀续写。

**那个 `b'\\r\\n\\r\\n\\r\\n'` 不是模型的输出**,是 Windows 环境下回车换行符(`\\r\\n`)以字节形式被打印出来了,属于环境小杂音,可以无视。

### 6. 简洁实现:两行换掉上面全部手写代码

```python
gru_layer = nn.GRU(num_inputs, num_hiddens)
model = d2l.RNNModel(gru_layer, len(vocab))
```

– `nn.GRU` 是 PyTorch 官方**内置的 GRU**,数学上和手写版完全一样,只是全部用优化的底层代码(cuDNN)实现。
– `RModel` 包装器负责搭上输出层、处理 hidden state 的形状,让训练接口和手写版一致。

对比结果:

手写版简洁版
困惑度 1.1 1.0
速度 ~3 万 tokens/sec ~31 万 tokens/sec

**快 10 倍的原因**:手写版在 Python 里 for 循环 35 步,每步都是独立的矩阵乘法,解释器开销巨大;`nn.GRU` 把整个循环用 CUDA 融合成一次调用,类似"一个人搬 35 块砖来回跑 vs 开叉车一次运完"。

**实际工作中用简洁版,学习时手写一遍**——这正是 d2l 把两者都放在一起的用意。

## 三、怎么用?怎么改着玩?

**环境**:`pip install torch d2l`(无需 GPU 也能跑,只是慢;你有 `cuda:0` 说明装了 CUDA 版 PyTorch)。

**值得动手试的实验**:

1. **换前缀生成文字**:
   ```python
   d2l.predict_ch8('the time machine', 50, model, vocab, device)
   ```
2. **看模型的成长**:把 `num_epochs` 改成 5 再跑,你会看到生成的文字是乱码(如 `xkqzhhz`)——这就是"还没学会"的样子;500 轮后能写出通顺句子,对比非常震撼。
3. **调 num_hiddens**:改成 8,记忆本只有 8 格,模型会记不住长距离的信息,困惑度明显升高——直观感受"隐藏单元数 = 记忆容量"。
4. **调学习率**:`lr=1` 看起来大得吓人(一般模型用 0.001),但因为训练时做了梯度裁剪 + 输出是 softmax,这个量级对 RNN 是安全的。

## 四、给初学者的一句话总结

这套代码的学习路线是:**数据 → 参数 → 前向循环 → 训练 → 生成**。核心洞察只有一个——GRU 的 `H = Z * H + (1-Z) * H_tilda`,它让网络自己学会"哪些记忆值得永久保存,哪些可以随手丢掉",这一招解决了 RNN 记不住远处的根本问题。手写一遍是为了懂原理,以后写项目直接用 `nn.GRU`。

2. 门控循环单元GRU

import torch
from torch import nn
from d2l import torch as d2l

# 设置每个batch的大小和时间步数
batch_size, num_steps = 32, 35
# 加载时间机器数据集并获取词汇表
train_iter, vocab = d2l.load_data_time_machine(batch_size, num_steps)

# 初始化模型参数
def get_params(vocab_size, num_hiddens, device):
# 设置输入和输出的维度为词汇表大小
num_inputs = num_outputs = vocab_size

# 定义一个函数,用于生成服从正态分布的随机张量,并乘以0.01进行缩放
def normal(shape):
return torch.randn(size=shape, device=device) * 0.01

# 定义一个函数,生成三组权重和偏置张量,用于不同的门控机制
def three():
return (normal(
(num_inputs, num_hiddens)), normal((num_hiddens, num_hiddens)),
torch.zeros(num_hiddens, device=device))

# 初始化GRU中的权重和偏置
# 权重和偏置用于控制更新门
W_xz, W_hz, b_z = three() # GRU多了这两行
# 权重和偏置用于控制重置门
W_xr, W_hr, b_r = three() # GRU多了这两行
# 权重和偏置用于计算候选隐藏状态
W_xh, W_hh, b_h = three()
# 隐藏状态到输出的权重
W_hq = normal((num_hiddens, num_outputs))
# 输出的偏置
b_q = torch.zeros(num_outputs, device=device)
# 参数列表中各参数顺序
params = [W_xz, W_hz, b_z, W_xr, W_hr, b_r, W_xh, W_hh, b_h, W_hq, b_q]
# 遍历参数列表中所有参数
for param in params:
# 设置参数的`requires_grad`属性为True,以便进行梯度计算
param.requires_grad_(True)
# 返回参数列表中所有参数
return params

# 定义隐藏状态的初始化函数
def init_gru_state(batch_size, num_hiddens, device):
# 返回隐藏状态初始化为全零的元组
return (torch.zeros((batch_size, num_hiddens), device=device),)

# 定义门控循环单元模型
def gru(inputs, state, params):
# 参数 params 解包为多个变量,分别表示模型中的权重和偏置
W_xz, W_hz, b_z, W_xr, W_hr, b_r, W_xh, W_hh, b_h, W_hq, b_q = params
# 传入的隐藏状态 state 解包为单个变量 H。
H, = state
# 创建一个空列表,用于存储每个时间步的输出
outputs = []
# 遍历输入序列中的每个时间步
for X in inputs:
# 更新门控机制 Z
Z = torch.sigmoid((X @ W_xz) + (H @ W_hz) + b_z)
# 重置门控机制 R
R = torch.sigmoid((X @ W_xr) + (H @ W_hr) + b_r)
# 计算候选隐藏状态 H_tilda
H_tilda = torch.tanh((X @ W_xh) + ((R * H) @ W_hh) + b_h)
# 更新隐藏状态 H
H = Z * H + (1 – Z) * H_tilda
# 计算输出 Y
Y = H @ W_hq + b_q
# 将输出添加到列表中
outputs.append(Y)
# 将所有输出拼接在一起,并返回拼接后的结果和最终的隐藏状态
return torch.cat(outputs, dim=0), (H,)

# 训练
vocab_size, num_hiddens, device = len(vocab), 256, d2l.try_gpu()
# 设置训练的总轮数和学习率
num_epochs, lr = 500, 1
# 创建 GRU 模型实例
model = d2l.RNNModelScratch(len(vocab), num_hiddens, device, get_params,
init_gru_state, gru)
# 调用 D2L 库中的训练函数,传入模型实例、训练数据迭代器、词汇表、学习率和训练的总轮数
d2l.train_ch8(model, train_iter, vocab, lr, num_epochs, device)

perplexity 1.1, 29478.1 tokens/sec on cuda:0
time travelleryou can show black is white by argument said filby
travelleryou can show black is white by argument said filby

# 简洁实现
# 设置输入特征的维度为词汇表大小
num_inputs = vocab_size
# 创建一个 GRU 层,指定输入特征的维度和隐藏单元的数量
gru_layer = nn.GRU(num_inputs, num_hiddens)
# 创建一个 RNNModel 实例,传入 GRU 层和词汇表的大小
model = d2l.RNNModel(gru_layer, len(vocab))
# 将模型移动到指定的设备上(可能是 GPU)
model = model.to(device)
# 调用 D2L 库中的 train_ch8 函数进行训练,传入模型实例、训练数据迭代器、词汇表、学习率和训练的总轮数
d2l.train_ch8(model, train_iter, vocab, lr, num_epochs, device)

perplexity 1.0, 316122.5 tokens/sec on cuda:0
time traveller with a slight accession ofcheerfulness really thi
travelleryou can show black is white by argument said filby

1. 长短期记忆网络LSTM

门公式比喻打分范围
遗忘门 F sigmoid(X@W_xf + H@W_hf + b_f) 翻相册时决定:旧照片删不删。F≈1 留着,F≈0 删掉 0~1
输入门 I sigmoid(X@W_xi + H@W_hi + b_i) 刚拍了一张新照片,决定:要不要存进相册 0~1
输出门 O sigmoid(X@W_xo + H@W_ho + b_o) 相册内容很多,决定:现在往屏幕上显示多少 0~1

2. 长短期记忆网络LSTM

import torch
from torch import nn
from d2l import torch as d2l

# 设置批量大小为32,时间步数为35
batch_size, num_steps = 32, 35
# 使用d2l库中的load_data_time_machine函数加载时间机器数据集,
# 并设置批量大小为32,时间步数为35,将加载的数据集赋值给train_iter和vocab变量
train_iter, vocab = d2l.load_data_time_machine(batch_size, num_steps)

def get_lstm_params(vocab_size, num_hiddens, device):
# 将词汇表大小赋值给num_inputs和num_outputs
num_inputs = num_outputs = vocab_size

# 定义一个辅助函数normal,用于生成具有特定形状的正态分布随机数,并将其初始化为较小的值
def normal(shape):
return torch.randn(size=shape, device=device) * 0.01

# 定义一个辅助函数three,用于生成三个参数:输入到隐藏状态的权重矩阵、隐藏状态到隐藏状态的权重矩阵和隐藏状态的偏置项
def three():
return (normal(
(num_inputs, num_hiddens)), normal((num_hiddens, num_hiddens)),
torch.zeros(num_hiddens, device=device))

# 调用three函数获取输入到隐藏状态的权重矩阵W_xi、隐藏状态到隐藏状态的权重矩阵W_hi和隐藏状态的偏置项b_i
W_xi, W_hi, b_i = three()
# 调用three函数获取输入到隐藏状态的权重矩阵W_xf、隐藏状态到隐藏状态的权重矩阵W_hf和隐藏状态的偏置项b_f
W_xf, W_hf, b_f = three()
# 调用three函数获取输入到隐藏状态的权重矩阵W_xo、隐藏状态到隐藏状态的权重矩阵W_ho和隐藏状态的偏置项b_o
W_xo, W_ho, b_o = three()
# 调用three函数获取输入到隐藏状态的权重矩阵W_xc、隐藏状态到隐藏状态的权重矩阵W_hc和隐藏状态的偏置项b_c
W_xc, W_hc, b_c = three()
# 生成隐藏状态到输出的权重矩阵W_hq
W_hq = normal((num_hiddens, num_outputs))
# 生成输出的偏置项b_q
b_q = torch.zeros(num_outputs, device=device)
# 将所有参数组合成列表params
params = [W_xi, W_hi, b_i, W_xf, W_hf, b_f, W_xo, W_ho, b_o, W_xc, W_hc, b_c, W_hq, b_q]

# 变量所有参数
for param in params:
# 将所有参数的requires_grad属性设置为True,表示需要计算梯度
param.requires_grad_(True)

# 返回所有参数
return params

# 初始化函数
def init_lstm_state(batch_size, num_hiddens, device):
# 返回一个元组,包含两个张量:一个全零张量表示初始的隐藏状态,和一个全零张量表示初始的记忆细胞状态。
return (torch.zeros((batch_size, num_hiddens), device=device),
torch.zeros((batch_size, num_hiddens),device=device))

# 实际模型
def lstm(inputs, state, params):
# 解包参数列表params,分别赋值给对应的变量
[W_xi, W_hi, b_i, W_xf, W_hf, b_f, W_xo, W_ho, b_o, W_xc, W_hc, b_c, W_hq, b_q] = params
# 解包状态元组state,分别赋值给隐藏状态H和记忆细胞状态C
(H, C) = state
# 创建一个空列表用于存储每个时间步的输出
outputs = []
# 对于输入序列中的每个时间步
for X in inputs:
# 输入门的计算:使用输入、隐藏状态和偏置项,通过线性变换和sigmoid函数计算输入门
I = torch.sigmoid((X @ W_xi) + (H @ W_hi) + b_i)
# 遗忘门的计算:使用输入、隐藏状态和偏置项,通过线性变换和sigmoid函数计算遗忘门
F = torch.sigmoid((X @ W_xf) + (H @ W_hf) + b_f)
# 输出门的计算:使用输入、隐藏状态和偏置项,通过线性变换和sigmoid函数计算输出门
O = torch.sigmoid((X @ W_xo) + (H @ W_ho) + b_o)
# 新的记忆细胞候选值的计算:使用输入、隐藏状态和偏置项,通过线性变换和tanh函数计算新的记忆细胞候选值
C_tilda = torch.tanh((X @ W_xc) + (H @ W_hc) + b_c)
# 更新记忆细胞状态:将旧的记忆细胞状态与遗忘门和输入门的乘积相加,再与新的记忆细胞候选值的乘积相加,得到新的记忆细胞状态
C = F * C + I * C_tilda
# 更新隐藏状态:将输出门和经过tanh函数处理的记忆细胞状态的乘积作为新的隐藏状态
H = O * torch.tanh(C)
# 输出的计算:使用新的隐藏状态和偏置项,通过线性变换得到输出
Y = (H @ W_hq) + b_q
# 将当前时间步的输出添加到列表中
outputs.append(Y)
# 将所有时间步的输出在维度0上拼接起来,作为最终的输出结果;
# 返回最终的输出结果和更新后的隐藏状态和记忆细胞状态的元组
return torch.cat(outputs, dim=0), (H, C)

# 训练
# 获取词汇表大小,并设置隐藏单元数量为256,设备为GPU(如果可用)
vocab_size, num_hiddens, device = len(vocab), 256, d2l.try_gpu()
# 设置训练的轮数为500,学习率为1
num_epochs, lr = 500, 1
# 使用d2l库中的RNNModelScratch类创建一个基于LSTM的模型对象,
# 并传入词汇表大小、隐藏单元数量、设备、参数初始化函数、初始状态函数和LSTM模型函数
model = d2l.RNNModelScratch(len(vocab), num_hiddens, device, get_lstm_params, init_lstm_state, lstm)
# 使用d2l库中的train_ch8函数进行模型的训练,传入模型对象、训练数据迭代器、词汇表、学习率、训练轮数和设备
d2l.train_ch8(model, train_iter, vocab, lr, num_epochs, device)

perplexity 1.1, 26271.0 tokens/sec on cuda:0
time travellerit s against reason said filby wo onles of the fil
traveller cursedwe can ghee was aloxmat eachanerurely but y

# 简洁实现
# 输入特征数量等于词汇表大小
num_inputs = vocab_size
# 使用nn.LSTM创建一个LSTM层,输入特征数量为num_inputs,隐藏单元数量为num_hiddens
lstm_layer = nn.LSTM(num_inputs, num_hiddens)
# 使用d2l库中的RNNModel类创建一个基于LSTM的模型对象,传入LSTM层和词汇表大小
model = d2l.RNNModel(lstm_layer, len(vocab))
# 将模型移动到指定的设备上
mode = model.to(device)
# 使用d2l库中的train_ch8函数进行模型的训练,传入模型对象、训练数据迭代器、词汇表、学习率、训练轮数和设备
d2l.train_ch8(model, train_iter, vocab, lr, num_epochs, device)

perplexity 1.0, 359354.8 tokens/sec on cuda:0
time travelleryou can show black is white by argument said filby
traveller with a slight accession ofcheerfulness really thi

1. 深层循环神经网络

2. 深层循环神经网络

import torch
from torch import nn
from d2l import torch as d2l

# 定义每个小批量的样本数量和时间步数
batch_size, num_steps = 32, 35
# 使用d2l库中的load_data_time_machine函数加载时间机器数据集
# 将数据集划分为以batch_size为批量大小,num_steps为时间步数的小批量数据
# train_iter是用于训练的迭代器,vocab是数据集的词汇表
train_iter, vocab = d2l.load_data_time_machine(batch_size, num_steps)

# 通过 num_layers 的值来设定隐藏层数
# 将vocab的长度作为vocab_size,即词汇表的大小
# 设置隐藏状态的维度为256,即num_hiddens
# 设置隐藏层数为2,即num_layers
# 这些值是手动设置的超参数,用于定义模型的隐藏状态的维度和隐藏层数
vocab_size, num_hiddens, num_layers = len(vocab), 256, 2
# 将输入的维度设置为词汇表的大小,用于将词汇表中的词转换为嵌入向量
num_inputs = vocab_size
# 尝试使用 GPU 运行,如果没有可用的 GPU,则使用 CPU 运行
device = d2l.try_gpu()
# 创建 LSTM 层
# num_inputs 表示输入的特征维度,即词汇表的大小
# num_hiddens 表示隐藏状态的维度,即 LSTM 单元中的隐藏单元数量
# num_layers 表示 LSTM 的隐藏层数
lstm_layer = nn.LSTM(num_inputs, num_hiddens, num_layers)
# 创建 RNNModel 模型,用于将 LSTM 层与输出层结合起来
# lstm_layer 是 LSTM 层的实例
# len(vocab) 表示输出层的输出维度,即词汇表的大小
model = d2l.RNNModel(lstm_layer, len(vocab))
# 将模型移动到设备上进行计算,即将模型放到 GPU 或 CPU 上运行
model = model.to(device)

# 训练
# 设置训练的总轮数为500,学习率为2
num_epochs, lr = 500, 2
# 使用d2l库中的train_ch8函数进行模型训练
# model为待训练的模型
# train_iter为训练数据的迭代器
# vocab为词汇表
# lr为学习率
# num_epochs为总的训练轮数
# device为模型的运行设备,可以是GPU或CPU
d2l.train_ch8(model, train_iter, vocab, lr, num_epochs, device)

perplexity 1.0, 213727.4 tokens/sec on cuda:0
time travelleryou can show black is white by argument said filby
travelleryou can show black is white by argument said filby

赞(0)
未经允许不得转载:171主机测评 » 深度学习29门控循环单元DRU、长短期记忆网路LSTM、深层循环神经网络
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址