Mushen 版の「手を使って学ぶディープラーニング」の学習ノートです。学習プロセスを記録しています。詳細な内容については書籍を購入してください。
B ステーションのビデオ リンク
オープンソース チュートリアル リンク
長短期記憶ネットワーク (LSTM)
長い間、隠れ変数モデルには長期的な情報の保存と短期的な入力の欠落という問題がありました。この問題に対する初期のアプローチの 1 つは、長期短期記憶ネットワークでした。
LSTM ネットワークの設計は、コンピューターの論理ゲートからインスピレーションを受けています。
ゲートされたメモリ要素:
ゲートを忘れる: 値を 0 に向けて減少させる
入力ゲート: 入力データを無視するかどうかを決定する
出力ゲート: 隠し状態を使用するかどうかを決定する
シグモイドによる 3 によるシグモイドs i g mo i d活性化関数の全結合層処理:
候補メモリ ユニットは、上記の 3 つのゲートに似ていますが、活性化関数として Tanh 関数を使用し、関数の値の範囲は (-1, 1) です。
メモリユニット:入力ゲートI t I_t私たC ~ t \tilde{C}_tから使用する量を制御しますC~た新しいデータ、忘れゲートF i F_iF私は過去の記憶C t − 1 C_{t-1} をいくつ保持するかを制御しますCt − 1コンテンツ。
忘却ゲートが常に 1 で、入力ゲートが常に 0 の場合、過去のメモリ セルC t − 1 C_{t-1}Ct − 1時間の経過とともに保存され、現在のタイム ステップに渡されます。この設計は、勾配消失の問題を軽減し、シーケンス内の長距離依存関係をより適切に捕捉するために導入されました。
最後に隠れ状態H t H_tを定義します。Hたの計算では、出力ゲートが機能します。LSTM ネットワークでは、これは単にメモリ要素の正接のゲート バージョンです。これにより、H t H_tが保証されます。Hたの値は常に (-1, 1) の範囲内にあります。
出力ゲートが 1 に近い限り、すべてのメモリ情報を予測部分に効果的に渡すことができますが、出力ゲートが 0 に近い場合は、隠れ状態を更新せずにすべての情報をメモリ セル内に保持するだけです。
一部の文献では、メモリ セルを特別な種類の隠れ状態と考えており、隠れ状態と同じ形状を持ち、追加情報を記録するように設計されています。
要約する
長期短期記憶ネットワークは、重要な状態制御を備えた典型的な潜在変数自己回帰モデルです。ただし、シーケンスの長距離依存性により、LSTM ネットワークやその他のシーケンス モデル (ゲート付きリカレント ユニットなど) のトレーニングのコストは非常に高くなります。Transformer はその先進的な代替モデルです。
LSTM は、勾配の爆発と勾配の消失を軽減できます。
非表示状態のみが出力層 (Y) に渡され、メモリは完全に内部情報です。
実践的な学習
長短期記憶ネットワーク - LSTM
import torch
from torch import nn
from d2l import torch as d2l
batch_size, num_steps = 32, 35
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 = vocab_size
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))
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 = normal((num_hiddens, num_outputs))
b_q = torch.zeros(num_outputs, device=device)
# 附加梯度
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:
param.requires_grad_(True)
return params
# H 和 C 的初始化
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):
[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((X @ W_xi) + (H @ W_hi) + b_i) # 输入门
F = torch.sigmoid((X @ W_xf) + (H @ W_hf) + b_f) # 遗忘门
O = torch.sigmoid((X @ W_xo) + (H @ W_ho) + b_o) # 输出门
C_tilda = torch.tanh((X @ W_xc) + (H @ W_hc) + b_c) # 候选记忆单元
C = F * C + I * C_tilda # 记忆元
H = O * torch.tanh(C) # 隐状态
Y = (H @ W_hq) + b_q # 输出
outputs.append(Y)
return torch.cat(outputs, dim=0), (H, C)
vocab_size, num_hiddens, device = len(vocab), 256, d2l.try_gpu()
num_epochs, lr = 500, 1
model = d2l.RNNModelScratch(len(vocab), num_hiddens, device, get_lstm_params,
init_lstm_state, lstm)
d2l.train_ch8(model, train_iter, vocab, lr, num_epochs, device)
簡潔な実装
num_inputs = vocab_size
lstm_layer = nn.LSTM(num_inputs, num_hiddens)
model = d2l.RNNModel(lstm_layer, len(vocab))
model = model.to(device)
d2l.train_ch8(model, train_iter, vocab, lr, num_epochs, device)