Yukarıdaki cevaplar neden çok iyi sorusuna yanıt verdi . Sadece kullanımını daha iyi anlamak için bir örnek eklemek istiyorum pack_padded_sequence
.
Bir örnek alalım
Not: pack_padded_sequence
toplu işlemde sıralı diziler gerektirir (sıra uzunluklarının azalan sırasına göre). Aşağıdaki örnekte, daha az dağınıklık için sekans grubu zaten sıralanmıştır. Tam uygulama için bu temel bağlantıyı ziyaret edin .
İlk olarak, aşağıdaki gibi farklı dizi uzunluklarına sahip 2 diziden oluşan bir grup oluşturuyoruz. Toplamda 7 elementimiz var.
- Her dizinin gömme boyutu 2'dir.
- İlk sıranın uzunluğu: 5
- İkinci sıranın uzunluğu: 2
import torch
seq_batch = [torch.tensor([[1, 1],
[2, 2],
[3, 3],
[4, 4],
[5, 5]]),
torch.tensor([[10, 10],
[20, 20]])]
seq_lens = [5, 2]
Bu ped seq_batch
5 eşit uzunlukta (toplu olarak maksimum uzunluk) sahip dizilerin toplu alır. Şimdi, yeni partide toplam 10 eleman var.
padded_seq_batch = torch.nn.utils.rnn.pad_sequence(seq_batch, batch_first=True)
"""
>>>padded_seq_batch
tensor([[[ 1, 1],
[ 2, 2],
[ 3, 3],
[ 4, 4],
[ 5, 5]],
[[10, 10],
[20, 20],
[ 0, 0],
[ 0, 0],
[ 0, 0]]])
"""
Ardından padded_seq_batch
,. İki tensörden oluşan bir demet döndürür:
- Birincisi, dizi grubundaki tüm öğeleri içeren verilerdir.
- İkincisi,
batch_sizes
adımlarla öğelerin birbirleriyle nasıl ilişkili olduğunu söyleyecektir.
packed_seq_batch = torch.nn.utils.rnn.pack_padded_sequence(padded_seq_batch, lengths=seq_lens, batch_first=True)
"""
>>> packed_seq_batch
PackedSequence(
data=tensor([[ 1, 1],
[10, 10],
[ 2, 2],
[20, 20],
[ 3, 3],
[ 4, 4],
[ 5, 5]]),
batch_sizes=tensor([2, 2, 1, 1, 1]))
"""
Şimdi packed_seq_batch
tuple'ı Pytorch'taki RNN, LSTM gibi tekrarlayan modüllere geçiriyoruz. Bu sadece 5 + 2=7
recurrrent modülünde hesaplamalar gerektirir .
lstm = nn.LSTM(input_size=2, hidden_size=3, batch_first=True)
output, (hn, cn) = lstm(packed_seq_batch.float())
"""
>>> output # PackedSequence
PackedSequence(data=tensor(
[[-3.6256e-02, 1.5403e-01, 1.6556e-02],
[-6.3486e-05, 4.0227e-03, 1.2513e-01],
[-5.3134e-02, 1.6058e-01, 2.0192e-01],
[-4.3123e-05, 2.3017e-05, 1.4112e-01],
[-5.9372e-02, 1.0934e-01, 4.1991e-01],
[-6.0768e-02, 7.0689e-02, 5.9374e-01],
[-6.0125e-02, 4.6476e-02, 7.1243e-01]], grad_fn=<CatBackward>), batch_sizes=tensor([2, 2, 1, 1, 1]))
>>>hn
tensor([[[-6.0125e-02, 4.6476e-02, 7.1243e-01],
[-4.3123e-05, 2.3017e-05, 1.4112e-01]]], grad_fn=<StackBackward>),
>>>cn
tensor([[[-1.8826e-01, 5.8109e-02, 1.2209e+00],
[-2.2475e-04, 2.3041e-05, 1.4254e-01]]], grad_fn=<StackBackward>)))
"""
output
Yastıklı çıktı kümesine geri dönmemiz gerekiyor :
padded_output, output_lens = torch.nn.utils.rnn.pad_packed_sequence(output, batch_first=True, total_length=5)
"""
>>> padded_output
tensor([[[-3.6256e-02, 1.5403e-01, 1.6556e-02],
[-5.3134e-02, 1.6058e-01, 2.0192e-01],
[-5.9372e-02, 1.0934e-01, 4.1991e-01],
[-6.0768e-02, 7.0689e-02, 5.9374e-01],
[-6.0125e-02, 4.6476e-02, 7.1243e-01]],
[[-6.3486e-05, 4.0227e-03, 1.2513e-01],
[-4.3123e-05, 2.3017e-05, 1.4112e-01],
[ 0.0000e+00, 0.0000e+00, 0.0000e+00],
[ 0.0000e+00, 0.0000e+00, 0.0000e+00],
[ 0.0000e+00, 0.0000e+00, 0.0000e+00]]],
grad_fn=<TransposeBackward0>)
>>> output_lens
tensor([5, 2])
"""
Bu çabayı standart yöntemle karşılaştırın
Standart şekilde, sadece geçmesi gerekiyor padded_seq_batch
için lstm
modül. Ancak, 10 hesaplama gerektirir. Hesaplama açısından verimsiz olan dolgu öğelerinde daha fazla sayıda hesaplama içerir .
Yanlış temsillere yol açmadığını , ancak doğru temsilleri çıkarmak için çok daha fazla mantığa ihtiyaç duyduğunu unutmayın.
- Yalnızca ileri yönlü LSTM (veya herhangi bir tekrarlayan modül) için, son adımın gizli vektörünü bir dizinin temsili olarak çıkarmak istersek, T (th) adımından gizli vektörleri almamız gerekir; burada T girişin uzunluğudur. Son temsili almak yanlış olacaktır. Toplu işteki farklı girişler için T'nin farklı olacağını unutmayın.
- İki yönlü LSTM (veya herhangi bir tekrarlayan modül) için, biri girişin başında dolgu ile ve diğeri girişin sonunda dolgu ile çalışan iki RNN modülünü sürdürmek zorunda kalacağı için daha da zahmetlidir ve son olarak yukarıda açıklandığı gibi gizli vektörlerin çıkarılması ve birleştirilmesi.
Farkı görelim:
output, (hn, cn) = lstm(padded_seq_batch.float())
"""
>>> output
tensor([[[-3.6256e-02, 1.5403e-01, 1.6556e-02],
[-5.3134e-02, 1.6058e-01, 2.0192e-01],
[-5.9372e-02, 1.0934e-01, 4.1991e-01],
[-6.0768e-02, 7.0689e-02, 5.9374e-01],
[-6.0125e-02, 4.6476e-02, 7.1243e-01]],
[[-6.3486e-05, 4.0227e-03, 1.2513e-01],
[-4.3123e-05, 2.3017e-05, 1.4112e-01],
[-4.1217e-02, 1.0726e-01, -1.2697e-01],
[-7.7770e-02, 1.5477e-01, -2.2911e-01],
[-9.9957e-02, 1.7440e-01, -2.7972e-01]]],
grad_fn= < TransposeBackward0 >)
>>> hn
tensor([[[-0.0601, 0.0465, 0.7124],
[-0.1000, 0.1744, -0.2797]]], grad_fn= < StackBackward >),
>>> cn
tensor([[[-0.1883, 0.0581, 1.2209],
[-0.2531, 0.3600, -0.4141]]], grad_fn= < StackBackward >))
"""
Yukarıdaki sonuçlar hn
, cn
iki yönden farklı olduğunu , iki yoldan ise output
dolgu öğeleri için farklı değerlere yol açtığını göstermektedir.