pytorch-高级rnn

GRU

RNN存在的问题:梯度较容易出现衰减或爆炸(BPTT)
⻔控循环神经⽹络:捕捉时间序列中时间步距离较⼤的依赖关系
RNN:

Image Name

Ht=ϕ(XtWxh+Ht1Whh+bh) H_{t} = ϕ(X_{t}W_{xh} + H_{t-1}W_{hh} + b_{h})
GRU:

Image Name

Rt=σ(XtWxr+Ht1Whr+br)Zt=σ(XtWxz+Ht1Whz+bz)H~t=tanh(XtWxh+(RtHt1)Whh+bh)Ht=ZtHt1+(1Zt)H~t R_{t} = σ(X_tW_{xr} + H_{t−1}W_{hr} + b_r)\\ Z_{t} = σ(X_tW_{xz} + H_{t−1}W_{hz} + b_z)\\ \widetilde{H}_t = tanh(X_tW_{xh} + (R_t ⊙H_{t−1})W_{hh} + b_h)\\ H_t = Z_t⊙H_{t−1} + (1−Z_t)⊙\widetilde{H}_t
• 重置⻔有助于捕捉时间序列⾥短期的依赖关系;
• 更新⻔有助于捕捉时间序列⾥⻓期的依赖关系。
⻔控循环单元将计算候选隐藏状态来辅助稍后的隐藏状态计算。如图所示,我们将当前时间步重置⻔的输出与上⼀时间步隐藏状态做按元素乘法(符号为\odot)。如果重置⻔中元素值接近0,那么意味着重置置对应隐藏状态元素为0,即丢弃上⼀时间步的隐藏状态。如果元素值接近1,那么表示保留上⼀时间步的隐藏状态。然后,将按元素乘法的结果与当前时间步的输⼊连结,再通过含激活函数tanh的全连接层计算出候选隐藏状态,其所有元素的值域为[-1,1]
最后:时间步t的隐藏状态HtH_t的计算使用当前时间步的更新门ZtZ_t对上一步时间步的隐藏状态Ht1H_{t-1}和当前时间步的隐藏候选状态组合

载入数据集

  • 重置⻔有助于捕捉时间序列⾥短期的依赖关系;
  • 更新⻔有助于捕捉时间序列⾥⻓期的依赖关系。
import os
os.listdir('/home/kesci/input')
['jaychou_lyrics4703', 'd2l_jay9460']
import numpy as np
import torch
from torch import nn, optim
import torch.nn.functional as F
import sys
sys.path.append("../input/")
import d2l_jay9460 as d2l
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

(corpus_indices, char_to_idx, idx_to_char, vocab_size) = d2l.load_data_jay_lyrics()

初始化参数

num_inputs, num_hiddens, num_outputs = vocab_size, 256, vocab_size# 1027 256 256
print('will use', device)

def get_params():  
    def _one(shape):
        ts = torch.tensor(np.random.normal(0, 0.01, size=shape), device=device, dtype=torch.float32) #正态分布
        return torch.nn.Parameter(ts, requires_grad=True)
    def _three():
        return (_one((num_inputs, num_hiddens)),
                _one((num_hiddens, num_hiddens)),
                torch.nn.Parameter(torch.zeros(num_hiddens, device=device, dtype=torch.float32), requires_grad=True))
    # 隐藏层系数256*256,输入层系数1027*256,偏置1*256
    W_xz, W_hz, b_z = _three()  # 更新门参数
    W_xr, W_hr, b_r = _three()  # 重置门参数
    W_xh, W_hh, b_h = _three()  # 候选隐藏状态参数
    
    # 输出层参数
    W_hq = _one((num_hiddens, num_outputs))# 256*1027
    b_q = torch.nn.Parameter(torch.zeros(num_outputs, device=device, dtype=torch.float32), requires_grad=True)
    return nn.ParameterList([W_xz, W_hz, b_z, W_xr, W_hr, b_r, W_xh, W_hh, b_h, W_hq, b_q])

def init_gru_state(batch_size, num_hiddens, device):   #隐藏状态初始化 batch_size*num_hiddens
    return (torch.zeros((batch_size, num_hiddens), device=device), )
will use cpu

GRU模型

def gru(inputs, state, params):
    W_xz, W_hz, b_z, W_xr, W_hr, b_r, W_xh, W_hh, b_h, W_hq, b_q = params
    H, = state
    outputs = []
    for X in inputs:
        Z = torch.sigmoid(torch.matmul(X, W_xz) + torch.matmul(H, W_hz) + b_z)
        R = torch.sigmoid(torch.matmul(X, W_xr) + torch.matmul(H, W_hr) + b_r)
        H_tilda = torch.tanh(torch.matmul(X, W_xh) + R * torch.matmul(H, W_hh) + b_h)
        H = Z * H + (1 - Z) * H_tilda
        Y = torch.matmul(H, W_hq) + b_q# 对隐藏状态进行预测
        outputs.append(Y)
    return outputs, (H,)

训练模型

循环神经网络中较容易出现梯度衰减或梯度爆炸,这会导致网络几乎无法训练。裁剪梯度(clip gradient)是一种应对梯度爆炸的方法。假设我们把所有模型参数的梯度拼接成一个向量 g\boldsymbol{g},并设裁剪的阈值是θ\theta。裁剪后的梯度

min(θg,1)g \min\left(\frac{\theta}{\|\boldsymbol{g}\|}, 1\right)\boldsymbol{g}

L2L_2范数不超过θ\theta

num_epochs, num_steps, batch_size, lr, clipping_theta = 160, 35, 32, 1e2, 1e-2
# 训练160次,每个单元使用35个字符,每批32个,步长lr,裁剪梯度
pred_period, pred_len, prefixes = 40, 50, ['分开', '不分开']# 每40次预测一次
d2l.train_and_predict_rnn(gru, get_params, init_gru_state, num_hiddens,
                          vocab_size, device, corpus_indices, idx_to_char,
                          char_to_idx, False, num_epochs, num_steps, lr,
                          clipping_theta, batch_size, pred_period, pred_len,
                          prefixes)
                          # 拿周杰伦的歌词做训练,每次去32个样本每个样本35个字符,进行训练
                          # 最后预测50个字的歌词
# def train_and_predict_rnn(rnn, get_params, init_rnn_state, num_hiddens,
#                           vocab_size, device, corpus_indices, idx_to_char,
#                           char_to_idx, is_random_iter, num_epochs, num_steps,
#                           lr, clipping_theta, batch_size, pred_period,
#                           pred_len, prefixes):
#     if is_random_iter:
#         data_iter_fn = data_iter_random
#     else:
#         data_iter_fn = data_iter_consecutive
#     params = get_params()
#     loss = nn.CrossEntropyLoss()

#     for epoch in range(num_epochs):
#         if not is_random_iter:  # 如使用相邻采样,在epoch开始时初始化隐藏状态
#             state = init_rnn_state(batch_size, num_hiddens, device)
#         l_sum, n, start = 0.0, 0, time.time()
#         data_iter = data_iter_fn(corpus_indices, batch_size, num_steps, device)
#         for X, Y in data_iter:
#             if is_random_iter:  # 如使用随机采样,在每个小批量更新前初始化隐藏状态
#                 state = init_rnn_state(batch_size, num_hiddens, device)
#             else: 
#             # 否则需要使用detach函数从计算图分离隐藏状态, 这是为了
#             # 使模型参数的梯度计算只依赖一次迭代读取的小批量序列(防止梯度计算开销太大)
#                 for s in state:
#                     s.detach_()
            
#             inputs = to_onehot(X, vocab_size)
#             # outputs有num_steps个形状为(batch_size, vocab_size)的矩阵
#             (outputs, state) = rnn(inputs, state, params)
#             # 拼接之后形状为(num_steps * batch_size, vocab_size)
#             outputs = torch.cat(outputs, dim=0)
#             # Y的形状是(batch_size, num_steps),转置后再变成长度为
#             # batch * num_steps 的向量,这样跟输出的行一一对应
#             y = torch.transpose(Y, 0, 1).contiguous().view(-1)
#             # 使用交叉熵损失计算平均分类误差
#             l = loss(outputs, y.long())
            
#             # 梯度清0
#             if params[0].grad is not None:
#                 for param in params:
#                     param.grad.data.zero_()
#             l.backward()
#             grad_clipping(params, clipping_theta, device)  # 裁剪梯度
#             sgd(params, lr, 1)  # 因为误差已经取过均值,梯度不用再做平均
#             l_sum += l.item() * y.shape[0]
#             n += y.shape[0]

#         if (epoch + 1) % pred_period == 0:
#             print('epoch %d, perplexity %f, time %.2f sec' % (
#                 epoch + 1, math.exp(l_sum / n), time.time() - start))
#             for prefix in prefixes:
#                 print(' -', predict_rnn(prefix, pred_len, rnn, params, init_rnn_state,
#                     num_hiddens, vocab_size, device, idx_to_char, char_to_idx))
epoch 40, perplexity 151.886344, time 1.50 sec
 - 分开 我想你 我不 你不 我不 你不 我不 你不 我不 你不 我不 你不 我不 你不 我不 你不 我不 
 - 不分开 我想你 我不 你不 我不 你不 我不 你不 我不 你不 我不 你不 我不 你不 我不 你不 我不 
epoch 80, perplexity 32.911311, time 1.54 sec
 - 分开 我想要你的微笑 一定好人 你在一直热 快哼哈兮 快使用双截棍 哼哼哈兮 快使用双截棍 哼哼哈兮 快
 - 不分开 我想要你的微笑 一定好人 你在一直热 快哼哈兮 快使用双截棍 哼哼哈兮 快使用双截棍 哼哼哈兮 快
epoch 120, perplexity 5.060078, time 1.42 sec
 - 分开 我想就这样牵着你的手不放开 爱可不可以简单单 没有你回了里堡 学只林起的牛肉 干什么 干什么 我想
 - 不分开  没有你在我有多难熬多多恼  没有你烦 我有多烦恼  没有你在我有多难熬多多恼  没有你烦 我有多
epoch 160, perplexity 1.513418, time 1.59 sec
 - 分开 我想带这样牵着你的手不放开 爱可不可以简简单单没有伤害 你 靠着我的肩膀 你 在我胸口睡著 像这样
 - 不分开  没有你烦我有多烦恼多 拜托的假你在娇听暴看  我叫道这里很美但家乡的你更美走过我想要你 陪我去吃

简洁实现

num_hiddens=256
num_epochs, num_steps, batch_size, lr, clipping_theta = 160, 35, 32, 1e2, 1e-2
pred_period, pred_len, prefixes = 40, 50, ['分开', '不分开']

lr = 1e-2 # 注意调整学习率
gru_layer = nn.GRU(input_size=vocab_size, hidden_size=num_hiddens)# 输入层隐藏层
#参数说明: - input_size – 期望的输入$x$的特征值的维度 - hidden_size – 隐状态的维度
#- num_layers – RNN的层数。 - bias – 如果为False,那么RNN层将不会使用bias,默认为True。
#- batch_first – 如果为True的话,那么输入和输出的tensor的形状是(batch, seq, feature)。
# - dropout – 如果非零的话,将会在RNN的输出上加个dropout,最后一层除外。
#- bidirectional – 如果为True,将会变成一个双向RNN,默认为False
model = d2l.RNNModel(gru_layer, vocab_size).to(device)
d2l.train_and_predict_rnn_pytorch(model, num_hiddens, vocab_size, device,
                                corpus_indices, idx_to_char, char_to_idx,
                                num_epochs, num_steps, lr, clipping_theta,
                                batch_size, pred_period, pred_len, prefixes)
epoch 40, perplexity 1.021082, time 1.00 sec
 - 分开始移动 回到当初爱你的时空 停格内容不忠 所有回忆对着我进攻 我的伤口被你拆封 誓言太沉重泪被纵容 
 - 不分开暴风圈来不及逃 我不能再想 我不能再想 我不 我不 我不能 爱情走的太快就像龙卷风 不能承受我已无处
epoch 80, perplexity 1.015856, time 1.12 sec
 - 分开的黑色幽默 走过了很多地方 我来到伊斯坦堡 就像是童话故事  有教堂有城堡 每天忙碌地的寻找 到底什
 - 不分开始移动 回到当初爱你的时空 停格内容不忠 所有回忆对着我进攻 我的伤口被你拆封 誓言太沉重泪被纵容 
epoch 120, perplexity 1.010134, time 1.02 sec
 - 分开的黑色幽默 想通 却又再考倒我 说散 你想很久了吧? 我不想拆穿你 当作 是你开的玩笑 想通 却又再
 - 不分开始打我疯狂的可爱女人 坏坏的让我疯狂的可爱女人 漂亮的让我面红的可爱女人 温柔的让我心疼的可爱女人 
epoch 160, perplexity 1.008007, time 1.06 sec
 - 分开的黑色幽默 想通 却又再考倒我 说散 你想很久了吧? 我不想拆穿你 当作 是你开的玩笑 想通 却又再
 - 不分开始 我不想拆穿你 当作 是你开的玩笑 想通 却又再考倒我 说散 你想很久了吧? 败给你的黑色幽默 说

LSTM

** 长短期记忆long short-term memory **:
遗忘门:控制上一时间步的记忆细胞
输入门:控制当前时间步的输入
输出门:控制从记忆细胞到隐藏状态
记忆细胞:⼀种特殊的隐藏状态的信息的流动

Image Name

It=σ(XtWxi+Ht1Whi+bi)Ft=σ(XtWxf+Ht1Whf+bf)Ot=σ(XtWxo+Ht1Who+bo)C~t=tanh(XtWxc+Ht1Whc+bc)Ct=FtCt1+ItC~tHt=Ottanh(Ct) I_t = σ(X_tW_{xi} + H_{t−1}W_{hi} + b_i) \\ F_t = σ(X_tW_{xf} + H_{t−1}W_{hf} + b_f)\\ O_t = σ(X_tW_{xo} + H_{t−1}W_{ho} + b_o)\\ \widetilde{C}_t = tanh(X_tW_{xc} + H_{t−1}W_{hc} + b_c)\\ C_t = F_t ⊙C_{t−1} + I_t ⊙\widetilde{C}_t\\ H_t = O_t⊙tanh(C_t)

初始化参数

num_inputs, num_hiddens, num_outputs = vocab_size, 256, vocab_size
print('will use', device)

def get_params():
    def _one(shape):
        ts = torch.tensor(np.random.normal(0, 0.01, size=shape), device=device, dtype=torch.float32)
        return torch.nn.Parameter(ts, requires_grad=True)
    def _three():
        return (_one((num_inputs, num_hiddens)),
                _one((num_hiddens, num_hiddens)),
                torch.nn.Parameter(torch.zeros(num_hiddens, device=device, dtype=torch.float32), requires_grad=True))
      # 隐藏层系数256*256,输入层系数1027*256,偏置1*256
    W_xi, W_hi, b_i = _three()  # 输入门参数
    W_xf, W_hf, b_f = _three()  # 遗忘门参数
    W_xo, W_ho, b_o = _three()  # 输出门参数
    W_xc, W_hc, b_c = _three()  # 候选记忆细胞参数
    
    # 输出层参数
    W_hq = _one((num_hiddens, num_outputs))
    b_q = torch.nn.Parameter(torch.zeros(num_outputs, device=device, dtype=torch.float32), requires_grad=True)
    return nn.ParameterList([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])

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))
will use cpu

LSTM模型

def lstm(inputs, state, 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
    (H, C) = state
    outputs = []
    # 公式的书写
    for X in inputs:
        I = torch.sigmoid(torch.matmul(X, W_xi) + torch.matmul(H, W_hi) + b_i)
        F = torch.sigmoid(torch.matmul(X, W_xf) + torch.matmul(H, W_hf) + b_f)
        O = torch.sigmoid(torch.matmul(X, W_xo) + torch.matmul(H, W_ho) + b_o)
        C_tilda = torch.tanh(torch.matmul(X, W_xc) + torch.matmul(H, W_hc) + b_c)
        C = F * C + I * C_tilda
        H = O * C.tanh()
        Y = torch.matmul(H, W_hq) + b_q
        outputs.append(Y)
    return outputs, (H, C)

训练模型

num_epochs, num_steps, batch_size, lr, clipping_theta = 160, 35, 32, 1e2, 1e-2
pred_period, pred_len, prefixes = 40, 50, ['分开', '不分开']
#forward(* input)定义了每次执行的 计算步骤。 在所有的子类中都需要重写这个函数。
d2l.train_and_predict_rnn(lstm, get_params, init_lstm_state, num_hiddens,
                          vocab_size, device, corpus_indices, idx_to_char,
                          char_to_idx, False, num_epochs, num_steps, lr,
                          clipping_theta, batch_size, pred_period, pred_len,
                          prefixes)
epoch 40, perplexity 211.894212, time 1.76 sec
 - 分开 我不不的我 我不不你 我不不 我不你 我不你 我不你 我不你 我不你 我不你 我不你 我不你 我不
 - 不分开 我不不的我 我不不你 我不不 我不你 我不你 我不你 我不你 我不你 我不你 我不你 我不你 我不
epoch 80, perplexity 67.757828, time 1.79 sec
 - 分开 我想你你的你 我想想你 你不不 我不要 我不不 我不要 我不不 我不要 我不不 我不要 我不不 我
 - 不分开 我想你你的你 我想要你 我不要 我不要 我不不 我不要 我不不 我不要 我不不 我不要 我不不 我
epoch 120, perplexity 15.901755, time 1.82 sec
 - 分开 我想想你 你我我多难你 你有去对医药箱说 别怪我 别怪我 说你怎么 我想就这样 我有的我面奏 一知
 - 不分开 我有你这生你 我想想这样 我不要这想活 不知不觉 我该了这节活 后知后觉 我该好好节活 我该好好生
epoch 160, perplexity 4.070628, time 1.75 sec
 - 分开 我想带你里里著 想想样这样打我妈妈 难道一一色色幽默 我不到你和坦堡 想这我的话里就听想 我说和你
 - 不分开 我已这这生我 不要歌 我想要我想我 我不抖没担堡 每知歌 一直我 我想就这样牵着你的手不放开 爱可

简洁实现

num_hiddens=256
num_epochs, num_steps, batch_size, lr, clipping_theta = 160, 35, 32, 1e2, 1e-2
pred_period, pred_len, prefixes = 40, 50, ['分开', '不分开']

lr = 1e-2 # 注意调整学习率
lstm_layer = nn.LSTM(input_size=vocab_size, hidden_size=num_hiddens)
model = d2l.RNNModel(lstm_layer, vocab_size)
#    (output, state) = model(X, state) # output: 形状为(num_steps * batch_size, vocab_size)
d2l.train_and_predict_rnn_pytorch(model, num_hiddens, vocab_size, device,
                                corpus_indices, idx_to_char, char_to_idx,
                                num_epochs, num_steps, lr, clipping_theta,
                                batch_size, pred_period, pred_len, prefixes)

深度循环神经网络

Image Name

Ht(1)=ϕ(XtWxh(1)+Ht1(1)Whh(1)+bh(1))Ht()=ϕ(Ht(1)Wxh()+Ht1()Whh()+bh())Ot=Ht(L)Whq+bq \boldsymbol{H}_t^{(1)} = \phi(\boldsymbol{X}_t \boldsymbol{W}_{xh}^{(1)} + \boldsymbol{H}_{t-1}^{(1)} \boldsymbol{W}_{hh}^{(1)} + \boldsymbol{b}_h^{(1)})\\ \boldsymbol{H}_t^{(\ell)} = \phi(\boldsymbol{H}_t^{(\ell-1)} \boldsymbol{W}_{xh}^{(\ell)} + \boldsymbol{H}_{t-1}^{(\ell)} \boldsymbol{W}_{hh}^{(\ell)} + \boldsymbol{b}_h^{(\ell)})\\ \boldsymbol{O}_t = \boldsymbol{H}_t^{(L)} \boldsymbol{W}_{hq} + \boldsymbol{b}_q

pytorch简洁实现深度循环网络

# py

num_hiddens=256
num_epochs, num_steps, batch_size, lr, clipping_theta = 160, 35, 32, 1e2, 1e-2
pred_period, pred_len, prefixes = 40, 50, ['分开', '不分开']

lr = 1e-2 # 注意调整学习率

gru_layer = nn.LSTM(input_size=vocab_size, hidden_size=num_hiddens,num_layers=2)
model = d2l.RNNModel(gru_layer, vocab_size).to(device)
d2l.train_and_predict_rnn_pytorch(model, num_hiddens, vocab_size, device,
                                corpus_indices, idx_to_char, char_to_idx,
                                num_epochs, num_steps, lr, clipping_theta,
                                batch_size, pred_period, pred_len, prefixes)
epoch 40, perplexity 18.048462, time 2.02 sec
 - 分开  想不你 我不要你 想不你 我不要你 想不你 我不要你 想不你 我不要你 想不你 我不要你 想不你
 - 不分开 我不开 我想你 我不想你 我不要你 我不我 我不想你 我不要你 我不我 我不想你 我不要你 我不我
epoch 80, perplexity 1.531773, time 1.98 sec
 - 分开么想想你 我不能再想你想有多难熬  穿过云层 我试著努力向你奔跑 爱才到到  爱散 你对来是泪不舍 
 - 不分开 温柔的让我心疼的可爱女人 坏坏的让我疯狂的可爱女人 坏坏的让我疯狂的可爱女人 坏坏的让我疯狂的可爱
epoch 120, perplexity 1.047978, time 1.95 sec
 - 分开烦我想 我的想我 都想要太多 我想你看棒球 想这样没担忧 唱着歌 一直走 我想就这样牵着你的手不放开
 - 不分开 温暖  为什么我爸爸 那么凶 如果真的我有一双翅膀 二双翅膀 随时出发 偷偷出发 我一定带我妈走 
epoch 160, perplexity 1.019455, time 1.81 sec
 - 分开看棒球 想这样没担忧 唱着歌 一直走 我想就这样牵着你的手不放开 爱可不可以简简单单没有伤害 你 靠
 - 不分开 你爱我 你叫我怎么跟 像 不要再这样打我妈妈 我说的话 你甘会听 不要再这样打我妈妈 难道你手不会
gru_layer = nn.LSTM(input_size=vocab_size, hidden_size=num_hiddens,num_layers=6)
model = d2l.RNNModel(gru_layer, vocab_size).to(device)
d2l.train_and_predict_rnn_pytorch(model, num_hiddens, vocab_size, device,
                                corpus_indices, idx_to_char, char_to_idx,
                                num_epochs, num_steps, lr, clipping_theta,
                                batch_size, pred_period, pred_len, prefixes)
epoch 40, perplexity 277.531330, time 16.53 sec
 - 分开                                                  
 - 不分开                                                  



---------------------------------------------------------------------------

KeyboardInterrupt                         Traceback (most recent call last)

<ipython-input-17-bdddefc4f118> in <module>
      4                                 corpus_indices, idx_to_char, char_to_idx,
      5                                 num_epochs, num_steps, lr, clipping_theta,
----> 6                                 batch_size, pred_period, pred_len, prefixes)


~/input/d2l_jay9460/utils.py in train_and_predict_rnn_pytorch(model, num_hiddens, vocab_size, device, corpus_indices, idx_to_char, char_to_idx, num_epochs, num_steps, lr, clipping_theta, batch_size, pred_period, pred_len, prefixes)
    542 
    543             optimizer.zero_grad()
--> 544             l.backward()
    545             # 梯度裁剪
    546             grad_clipping(model.parameters(), clipping_theta, device)


/opt/conda/lib/python3.7/site-packages/torch/tensor.py in backward(self, gradient, retain_graph, create_graph)
    148                 products. Defaults to ``False``.
    149         """
--> 150         torch.autograd.backward(self, gradient, retain_graph, create_graph)
    151 
    152     def register_hook(self, hook):


/opt/conda/lib/python3.7/site-packages/torch/autograd/__init__.py in backward(tensors, grad_tensors, retain_graph, create_graph, grad_variables)
     97     Variable._execution_engine.run_backward(
     98         tensors, grad_tensors, retain_graph, create_graph,
---> 99         allow_unreachable=True)  # allow_unreachable flag
    100 
    101 


KeyboardInterrupt: 

双向循环神经网络

Image Name

Ht=ϕ(XtWxh(f)+Ht1Whh(f)+bh(f))Ht=ϕ(XtWxh(b)+Ht+1Whh(b)+bh(b)) \begin{aligned} \overrightarrow{\boldsymbol{H}}_t &= \phi(\boldsymbol{X}_t \boldsymbol{W}_{xh}^{(f)} + \overrightarrow{\boldsymbol{H}}_{t-1} \boldsymbol{W}_{hh}^{(f)} + \boldsymbol{b}_h^{(f)})\\ \overleftarrow{\boldsymbol{H}}_t &= \phi(\boldsymbol{X}_t \boldsymbol{W}_{xh}^{(b)} + \overleftarrow{\boldsymbol{H}}_{t+1} \boldsymbol{W}_{hh}^{(b)} + \boldsymbol{b}_h^{(b)}) \end{aligned}
Ht=(Ht,Ht) \boldsymbol{H}_t=(\overrightarrow{\boldsymbol{H}}_{t}, \overleftarrow{\boldsymbol{H}}_t)
<Empty \space Math \space Block>
Ot=HtWhq+bq \boldsymbol{O}_t = \boldsymbol{H}_t \boldsymbol{W}_{hq} + \boldsymbol{b}_q

num_hiddens=128
num_epochs, num_steps, batch_size, lr, clipping_theta = 160, 35, 32, 1e-2, 1e-2
pred_period, pred_len, prefixes = 40, 50, ['分开', '不分开']

lr = 1e-2 # 注意调整学习率

gru_layer = nn.GRU(input_size=vocab_size, hidden_size=num_hiddens,bidirectional=True)
model = d2l.RNNModel(gru_layer, vocab_size).to(device)
d2l.train_and_predict_rnn_pytorch(model, num_hiddens, vocab_size, device,
                                corpus_indices, idx_to_char, char_to_idx,
                                num_epochs, num_steps, lr, clipping_theta,
                                batch_size, pred_period, pred_len, prefixes)
epoch 40, perplexity 1.001741, time 0.91 sec
 - 分开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开
 - 不分开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开
epoch 80, perplexity 1.000520, time 0.91 sec
 - 分开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开
 - 不分开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开
epoch 120, perplexity 1.000255, time 0.99 sec
 - 分开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开
 - 不分开球我球我球我球我球我球我球我球我球我球我球我球我球我球我球我球我球我球我球我球我球我球我球我球我球我
epoch 160, perplexity 1.000151, time 0.92 sec
 - 分开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开
 - 不分开球我球我球我球我球我球我球我球我球我球我球我球我球我球我球我球我球我球我球我球我球我球我球我球我球我
# 双向循环神经网络 (many-to-one)
class BiRNN(nn.Module):
    def __init__(self, input_size, hidden_size, num_layers, num_classes):
        super(BiRNN, self).__init__()
        self.hidden_size = hidden_size
        self.num_layers = num_layers
        self.lstm = nn.LSTM(input_size,# x的特征维度
                            hidden_size,# 隐藏层单元数
                            num_layers,# 层数
                            batch_first=True,# 第一个维度设为 batch, 即:(batch_size, seq_length, input_size)
                            bidirectional=True) # 是否用双向
        self.fc = nn.Linear(hidden_size * 2, num_classes)  # 2 for bidirection

    def forward(self, x):
        # x维度为(batch_size, time_step, input_size)
        # 隐层初始化
        # h0维度为(num_layers*direction_num, batch_size, hidden_size)
        # c0维度为(num_layers*direction_num, batch_size, hidden_size)
        h0 = torch.zeros(self.num_layers * 2, x.size(0), self.hidden_size).to(device)  # 2 for bidirection
        c0 = torch.zeros(self.num_layers * 2, x.size(0), self.hidden_size).to(device)

        # LSTM前向传播,此时out维度为(batch_size, seq_length, hidden_size*2)
        # hn,cn表示最后一个状态?维度与h0和c0一样
        out, (hn, cn) = self.lstm(x, (h0, c0))

        # 我们只需要最后一步的输出,即(batch_size, -1, output_size)
        out = self.fc(out[:, -1, :])
        return out
num_hiddens=256
num_epochs, num_steps, batch_size, lr, clipping_theta = 160, 35, 32, 1e2, 1e-2
pred_period, pred_len, prefixes = 40, 50, ['分开', '不分开']

lr = 1e-2 # 注意调整学习率
                        #   num_layers,# 层数
                        #     batch_first=True,# 第一个维度设为 batch, 即:(batch_size, seq_length, input_size)
                        #     bidirectional=True) # 是否用双向
lstm_layer = nn.LSTM(input_size=vocab_size, hidden_size=num_hiddens,num_layers=1,bidirectional=True)
model = d2l.RNNModel(lstm_layer, vocab_size)
#    (output, state) = model(X, state) # output: 形状为(num_steps * batch_size, vocab_size)
d2l.train_and_predict_rnn_pytorch(model, num_hiddens, vocab_size, device,
                                corpus_indices, idx_to_char, char_to_idx,
                                num_epochs, num_steps, lr, clipping_theta,
                                batch_size, pred_period, pred_len, prefixes)
epoch 40, perplexity 1.000759, time 1.51 sec
 - 分开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开
 - 不分开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开
epoch 80, perplexity 1.000204, time 1.53 sec
 - 分开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开
 - 不分开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开
epoch 120, perplexity 1.000097, time 1.64 sec
 - 分开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开
 - 不分开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开
epoch 160, perplexity 1.000053, time 1.55 sec
 - 分开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开
 - 不分开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开始开

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章