GRU
RNN存在的問題:梯度較容易出現衰減或爆炸(BPTT)
⻔控循環神經⽹絡:捕捉時間序列中時間步距離較⼤的依賴關係
RNN:
GRU:
• 重置⻔有助於捕捉時間序列⾥短期的依賴關係;
• 更新⻔有助於捕捉時間序列⾥⻓期的依賴關係。
⻔控循環單元將計算候選隱藏狀態來輔助稍後的隱藏狀態計算。如圖所示,我們將當前時間步重置⻔的輸出與上⼀時間步隱藏狀態做按元素乘法(符號爲)。如果重置⻔中元素值接近0,那麼意味着重置置對應隱藏狀態元素爲0,即丟棄上⼀時間步的隱藏狀態。如果元素值接近1,那麼表示保留上⼀時間步的隱藏狀態。然後,將按元素乘法的結果與當前時間步的輸⼊連結,再通過含激活函數tanh的全連接層計算出候選隱藏狀態,其所有元素的值域爲[-1,1]
最後:時間步t的隱藏狀態的計算使用當前時間步的更新門對上一步時間步的隱藏狀態和當前時間步的隱藏候選狀態組合
載入數據集
- 重置⻔有助於捕捉時間序列⾥短期的依賴關係;
- 更新⻔有助於捕捉時間序列⾥⻓期的依賴關係。
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)是一種應對梯度爆炸的方法。假設我們把所有模型參數的梯度拼接成一個向量 ,並設裁剪的閾值是。裁剪後的梯度
的範數不超過。
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 **:
遺忘門:控制上一時間步的記憶細胞
輸入門:控制當前時間步的輸入
輸出門:控制從記憶細胞到隱藏狀態
記憶細胞:⼀種特殊的隱藏狀態的信息的流動
初始化參數
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)
深度循環神經網絡
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:
雙向循環神經網絡
<Empty \space Math \space Block>
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
- 分開始開始開始開始開始開始開始開始開始開始開始開始開始開始開始開始開始開始開始開始開始開始開始開始開始開
- 不分開始開始開始開始開始開始開始開始開始開始開始開始開始開始開始開始開始開始開始開始開始開始開始開始開始開