2017-09-24 38 views
6

Ten release z PyTorch wydaje PackedSequence dla zmiennej długości wejścia dla rekurencyjnej sieci neuronowej. Jednak okazało się, że jest to trochę trudne w użyciu.Jak poprawnie zaimplementować sieć LSTM do wprowadzania wsadowego w PyTorch?

Korzystanie pad_packed_sequence odzyskać moc warstwą RNN które były karmione przez pack_padded_sequence, mamy T x B x N tensor outputs gdzie T jest max kroków czasowych, B jest wielkość partii i N jest ukryty rozmiar. Zauważyłem, że dla krótkich sekwencji w partii kolejne wyniki będą zerami.

Oto moje pytania.

  1. W przypadku pojedynczego zadania wyjściowego gdzie jeden musiałby ostatnie wyjście wszystkich sekwencji, prosty outputs[-1] daje zły wynik, ponieważ to tensor zawiera wiele zer dla krótkich sekwencji. Będzie trzeba skonstruować indeksy według długości sekwencji, aby pobrać ostatnie dane wyjściowe dla wszystkich sekwencji. Czy istnieje prostszy sposób na zrobienie tego?
  2. dla zadania wielokrotnego wyjścia (np seq2seq), zazwyczaj jeden doda liniowej warstwy N x O i przekształcenia Wyjścia wsadowych T x B x O do TB x O i obliczyć przekrój straty entropii i rzeczywistych celów (zazwyczaj TB liczby całkowite w modelu Language). W tej sytuacji, czy te zera w wyjściach wsadowych mają znaczenie?

Odpowiedz

3

Pytanie 1 - Ostatni krok czasowy

Jest to kod, który mogę używać, aby uzyskać wyjście ostatniego kroku to. Nie wiem, czy istnieje prostsze rozwiązanie. Jeśli tak, chciałbym to wiedzieć. Podążyłem za tym discussion i chwyciłem względny fragment kodu dla mojej metody last_timestep. To jest mój postęp.

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 

Pytanie 2 - Zamaskowany Krzyż Entropia Utrata

Tak, domyślnie zerowe wyściełane timesteps (cele) sprawa. Jednak bardzo łatwo je zamaskować. Masz dwie opcje, w zależności od wersji PyTorch, której używasz.

  1. PyTorch 0.2.0: Teraz pytorch podpory maskujące bezpośrednio w CrossEntropyLoss, z ignore_index argument. Na przykład, w modelowaniu języka lub seq2seq, gdzie dodaję wypełniania zerami, i maskować zerowe słowa wyściełane (tarcza) po prostu jak to:

    loss_function = nn.CrossEntropyLoss (ignore_index = 0)

  2. PyTorch 0.1.12 i starsze: W starszych wersjach PyTorch maskowanie nie było obsługiwane, więc trzeba było wdrożyć własne obejście. Roztwór, którego użyłem, był masked_cross_entropy.py, przez jihunchoi. Możesz być także zainteresowany tym discussion.

+0

Staram swoje rozwiązanie i mam błąd: Plik "/root/PycharmProjects/skip-thoughts.torch/pytorch/tmpRNN.py", linia 13, w last_timestep powrotnej unpacked.gather (1, idx) .squeeze() Plik "/ usr/local/lib/python3.5/dist-packages/torch/autograd/variable.py ", linia 684, w zbiorach return Gather.apply (self, dim, index) RuntimeError: save_for_backward może tylko zapisać tensory wejściowe lub wyjściowe, ale argument 0 nie spełniają ten warunek – chenfei