动手学深度学习 PyTorch版 李沐视频课笔记
一、RNN从零开始实现
1. 读取数据集
Code:
%matplotlib inline
import math
import torch
from torch import nn
from torch.nn import functional as F
from d2l import torch as d2l
batch_size, num_steps = 32, 35
train_iter, vocab = d2l.load_data_time_machine(batch_size, num_steps)
2. 独热编码
Code:
F.one_hot(torch.tensor([0, 2]), len(vocab))
Result:
3. 每次采样的小批量数据形状是二维张量:(批量大小,时间步数)
one_hot函数将这样一个小批量数据转换成三维张量,张量的最后⼀个维度等于词表大小(len(vocab))。我们经常转换输入的维度,以便获得形状为(时间步数,批量大小,词表大小)的输出
Code:
X = torch.arange(10).reshape((2, 5))
F.one_hot(X.T, 28).shape
Result:
4. 初始化循环神经网络的参数
Code:
def get_params(vocab_size, num_hiddens, device):
num_inputs = num_outputs = vocab_size
def normal(shape):
return torch.randn(size=shape, device=device) * 0.01
# 隐藏层参数
W_xh = normal((num_inputs, num_hiddens))
W_hh = normal((num_hiddens, num_hiddens))
b_h = torch.zeros(num_hiddens, device=device)
# 输出层参数
W_hq = normal((num_hiddens, num_outputs))
b_q = torch.zeros(num_outputs, device=device)
# 附加梯度
params = [W_xh, W_hh, b_h, W_hq, b_q]
for param in params:
param.requires_grad_(True)
return params
5. init_rnn_state函数
初始化时返回隐藏状态
Code:
def init_rnn_state(batch_size, num_hiddens, device):
return (torch.zeros((batch_size, num_hiddens), device=device), )
6. rnn函数
rnn函数定义了如何在一个时间步内计算隐状态和输出。循环神经网络模型通过inputs最外层的维度实现循环,以便逐时间步更新小批量数据的隐状态H。此外,这里使用tanh函数作为激活函数。
Code:
def rnn(inputs, state, params):
# inputs的形状:(时间步数量,批量⼤⼩,词表⼤⼩)
W_xh, W_hh, b_h, W_hq, b_q = params
H, = state
outputs = []
# X的形状:(批量⼤⼩,词表⼤⼩)
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
outputs.append(Y)
return torch.cat(outputs, dim=0), (H,)
7. 创建一个类来包装这些函数,并存储从零开始实现的循环神经网络模型的参数
Code:
class RNNModelScratch: #@save
"""从零开始实现的循环神经⽹络模型"""
def __init__(self, vocab_size, num_hiddens, device,
get_params, init_state, forward_fn):
self.vocab_size, self.