PyTorchのこの release は、リカレントニューラルネットワークの可変長入力にPackedSequence
を提供するようです。ただし、正しく使用するのは少し難しいことがわかりました。
pad_packed_sequence
を使用してpack_padded_sequence
によって供給されたRNNレイヤーの出力を回復すると、T x B x N
テンソルoutputs
が得られました。ここで、T
は最大時間ですステップ、B
はバッチサイズ、N
は非表示サイズです。バッチ内の短いシーケンスの場合、後続の出力はすべてゼロになることがわかりました。
ここに私の質問があります。
outputs[-1]
は間違った結果を返します。すべてのシーケンスの個々の最後の出力を取得するには、シーケンスの長さでインデックスを作成する必要があります。それを行う簡単な方法はありますか?N x O
を追加し、バッチ出力T x B x O
をTB x O
に再形成し、真のターゲットとのクロスエントロピー損失を計算しますTB
(通常、言語モデルの整数)。この場合、バッチ出力のこれらのゼロは重要ですか?質問1-最終タイムステップ
これは、最後のタイムステップの出力を取得するために使用するコードです。もっと簡単な解決策があるかどうかはわかりません。もしそうなら、私はそれを知りたいです。この ディスカッション に従い、last_timestep
メソッドの相対コードスニペットを取得しました。これは私の楽しみです。
class BaselineRNN(nn.Module):
def __init__(self, **kwargs):
...
def last_timestep(self, unpacked, lengths):
# Index of the last output for each sequence.
idx = (lengths - 1).view(-1, 1).expand(unpacked.size(0),
unpacked.size(2)).unsqueeze(1)
return unpacked.gather(1, idx).squeeze()
def forward(self, x, lengths):
embs = self.embedding(x)
# pack the batch
packed = pack_padded_sequence(embs, list(lengths.data),
batch_first=True)
out_packed, (h, c) = self.rnn(packed)
out_unpacked, _ = pad_packed_sequence(out_packed, batch_first=True)
# get the outputs from the last *non-masked* timestep for each sentence
last_outputs = self.last_timestep(out_unpacked, lengths)
# project to the classes using a linear layer
logits = self.linear(last_outputs)
return logits
質問2-マスクされたクロスエントロピー損失
はい、デフォルトではゼロが埋め込まれたタイムステップ(ターゲット)が重要です。ただし、それらをマスクするのは非常に簡単です。使用するPyTorchのバージョンに応じて、2つのオプションがあります。
PyTorch 0.2.0 :pytorchは、ignore_index
引数を使用して、 CrossEntropyLoss で直接マスキングをサポートします。たとえば、言語モデリングまたはseq2seqで、ゼロパディングを追加する場合、次のようにゼロパディングワード(ターゲット)をマスクします。
loss_function = nn.CrossEntropyLoss(ignore_index = 0)
PyTorch 0.1.12 以前:PyTorchの古いバージョンでは、マスキングはサポートされていなかったため、独自の回避策を実装する必要がありました。私が使用した解決策は、 jihunchoi による masked_cross_entropy.py でした。この ディスカッション にも興味があるかもしれません。
数日前、私は このメソッド を見つけました。これは、インデックス付けを使用して、ワンライナーで同じタスクを実行します。
最初にデータセットバッチ(_[batch size, sequence length, features]
_)があるので、私にとっては:
_unpacked_out = unpacked_out[np.arange(unpacked_out.shape[0]), lengths - 1, :]
_
ここで、_unpacked_out
_は_torch.nn.utils.rnn.pad_packed_sequence
_の出力です。
クリストスバジオティスが上記で使用しているlast_timestep()
メソッドに似ている ここで説明 メソッドと比較しました(また here を推奨)。私の場合、結果は同じです。