目次
lstmとは
詳細について:Understanding LSTM Networks
http://colah.github.io/posts/2015-08-Understanding-LSTMs/
構造図
公式
forget gate、忘れられているものを決定します。
input gate、状態Cellの更新を決定します。
Ct状態の更新、forget gateとinput gateに関連する
output gateは、時間tの出力を決定します。
その中で、ht−1は最後の時間ノードt-1の出力です。出力の次元は設定できます。例えば:pytorchの場合
rnn = nn.LSTM(10, 20, 2) #(input_size,hidden_size,num_layers)
hidden_sizeの次元は、実際には設定されているh hhの次元であり、時間ノードtが出力を取得するたびに、通常、最後の時間ノードの出力が使用されます。もちろん、各時間ノードの隠れ層の機能を使用し、判断できます。attentionはこのようなものです。
lstmのpytorchの使用
単方向のlstmの使用
rnn = nn.LSTM(input_size=10, hidden_size=20, num_layers=2)#(input_size,hidden_size,num_layers)
input = torch.randn(5, 3, 10)#(seq_len, batch, input_size)
h0 = torch.randn(2, 3, 20) #(num_layers,batch,output_size)
c0 = torch.randn(2, 3, 20) #(num_layers,batch,output_size)
output, (hn, cn) = rnn(input, (h0, c0))
output.shape #(seq_len, batch, output_size)
hn.shape #(num_layers, batch, output_size)
hn.shape #(num_layers, batch, output_size)
torch.Size([5, 3, 20])
torch.Size([2, 3, 20])
cn.shape #(num_layers, batch, output_size)
torch.Size([2, 3, 20])
解析については以下の図と説明をご覧ください。
- output:各stepは、seq_lenの各ステップに相当し、output_size次元の機能出力があるため、outputの次元は5,3,20(seq_len, batch, output_size)です。
- lstmにnum_layers=2が設定されているため、hcは最後の時間ノードtの隠れ層の特徴です。そのため、lstmの各層の最後の時間ノードはoutput_size次元の特徴出力を持ち、その出力次元は2, 3, 20(num_layers, batch, output_size)です。
- cnはhcと同じです
双方向のlstmの使用
rnn = nn.LSTM(input_size=10, hidden_size=20, num_layers=2,bidirectional=True)#(input_size,hidden_size,num_layers)
input = torch.randn(5, 3, 10)#(seq_len, batch, input_size)
h0 = torch.randn(4, 3, 20) #(num_layers,batch,output_size)
c0 = torch.randn(4, 3, 20) #(num_layers,batch,output_size)
output, (hn, cn) = rnn(input, (h0, c0))
output.shape #(seq_len, batch, output_size*2)
torch.Size([5, 3, 40])
hn.shape #(num_layers*2, batch, output_size)
torch.Size([4, 3, 20])
cn.shape #(num_layers*2, batch, output_size)
torch.Size([4, 3, 20])
実際、lstmのレイヤーは逆方向に追加され、出力時に連結されるため、次元は*2になり、bilstmは以下の図に示されます。
pytorch可変長lstmの使用
RNNが可変長入力を処理する必要がある理由
仮に感情分析の例があり、各文を感情レベルで分類します。主なフローは、以下の図に表示します。
考え方は簡単ですが、batch個のトレーニングデータを一緒に計算すると、複数のトレーニング例の長さが異なる場合、パディングします。つまり、短い文を最も長い文にパディングし、文の長さが同じになります。
以下の図のようです。
しかし、問題があります。例えば、上記の図では、「Yes」という文には1つの単語しかありませんが、5のパッド記号はパディングであるため、LSTMはその表現で多くの役に立たない文字を渡すため、取得される文には誤差があり、以下の図のようです。
正しいやり方は以下に説明します。
これにより、可変長入力を処理するためにpytorchのRNNが必要になります。上記の実例では、取得したい表現は、LSTMが「Yes」という単語を渡した後の表現のみであり、複数の役に立たない「Pad」を介して取得された表現ではありません。
pytorchでRNNによって可変長paddingを処理する方法
主にtorch.nn.utils.rnn.pack_padded_sequence()関数とtorch.nn.utils.rnn.pad_packed_sequence()関数を使用して、これら2つの関数の使い方をご覧ください。
ここのpackは、圧縮としてよりよく理解されています。満たされた可変長シーケンスを圧縮します。(満たす時には冗長性があるため、圧縮する)
入力形状は(T×B×* )にすることができます。 Tは最長のシーケンスの長さであり、Bはbatch size、*は任意の次元を表します(0にすることができます)。batch_first=Trueの場合、対応するinput sizeは(B×T×*)です。
Variableに格納されているシーケンスは、シーケンスの長さに従ってソートする必要があります。最初が最も長く、最後が最も短くなります(並べ替えが必要であることを注意してください)。つまり、input[:,0]は最長のシーケンスを表し、input[:, B-1]は最短のシーケンスを格納します。
パラメータの説明:
- input (Variable) – 可変長シーケンス 満たされたbatch
- lengths (list[int]) – 変数の各シーケンスの長さ。(各シーケンスの長さを知ることで、各シーケンスが停止するために処理される時点を知ることができます)
- batch_first (bool, optional) – Trueの場合、inputの形状はBT*sizeです。
返す値:
PackedSequenceオブジェクト。 PackedSequenceは次のように表されます。
具体的なコードは以下のとおりです。
embed_input_x_packed = pack_padded_sequence(embed_input_x, sentence_lens, batch_first=True)
encoder_outputs_packed, (h_last, c_last) = self.lstm(embed_input_x_packed)
このとき、返されるh_lastとc_lastは、どちらも変数型のパディング文字を除いた後のhidden stateとcell stateです。代表の意味は次のとおりです(各文の表現、lstmは実際の長さの文にのみ影響し、無駄なパディング文字では影響しません。次の図は赤いチェックマークで表されます)。
ただし、返されたoutputはPackedSequence型であるため、次のコードを使用できます。
encoder_outputs, _ = pad_packed_sequence(encoder_outputs_packed, batch_first=True)
encoderoutputsを変数型に変換し、取得された_は各文の長さを表します。
まとめ
そのため、RNNが類似の可変長センテンスシーケンスを処理している場合、torch.nn.utils.rnn.pack_padded_sequence()とtorch.nn.utils.rnn.pad_packed_sequence()を使用して、パディングの影響を回避できます。
コメントを残す