Понимание линейного слоя в маркировке последовательности с помощью ptorch lstm - PullRequest
0 голосов
/ 07 июля 2019

Я пытаюсь получить контроль над LSTM и pytorch. Даны последовательности различной длины. Каждый элемент данных в последовательности состоит из 8 объектов, и каждый элемент данных принадлежит одному из 6 классов (0-5). Я хочу узнать, как использовать LSTM для прогнозирования меток этих точек данных.

Пока я предпринял пару попыток решить эту проблему, но боюсь, что мне не хватает некоторых базовых знаний, когда речь заходит об этой теме.

Я начал с дополнения последовательностей -1 и меток до max_amount.

У меня есть загрузчики данных (train, test, val), которые заботятся о доставке пакетов формы [batch_size, max_seq_length, num_features]. Модель довольно проста и состоит из lstm и линейного слоя.

LSTM:

...
  self.lstm = nn.LSTM(
            input_size=self.sequence_dimension, # 8 features
            hidden_size=self.hidden_dim,
            num_layers=self.n_layers,
            batch_first=True,
        )
        self.linear_fc = nn.Linear(self.hidden_dim, self.output_size)
...

init:

    def init_hidden(self):
        # the weights are of the form (nb_layers, batch_size, nb_lstm_units)
        hidden_a = torch.randn(self.n_layers, self.batch_size, self.hidden_dim)
        hidden_b = torch.randn(self.n_layers, self.batch_size, self.hidden_dim)

        hidden_a = Variable(hidden_a)
        hidden_b = Variable(hidden_b)

        return (hidden_a, hidden_b)

вперед:

     def forward(self, X):
        # shape of X: [batch_size, max_seq_len, feature_size]
       self.hidden = self.init_hidden()

        # get unpadded sequence lenghts (padding: -1)
        lenghts = []
        for batch in X:
            for i, elem in enumerate(batch):
                if elem[0] == -1:
                    lenghts.append(i-1)
                    break

        # pack the padded sequences, length contains unpadded lenghts (eg., [43,46,67,121]
        x_packed = torch.nn.utils.rnn.pack_padded_sequence(X, lenghts, batch_first=True, enforce_sorted=False)

        lstm_out, self.hidden = self.lstm(x_packed.float(), self.hidden)

        # unpack
        x_unpacked, seq_len = torch.nn.utils.rnn.pad_packed_sequence(lstm_out, batch_first=True)

        #squash the batches from [batch_size, max_seq_len_of_this_batch, hidden_dim]
        #to [batch_size*max_seq_len_of_this_batch, hidden dim]
        batches_squashed = x_unpacked.contiguous().view(-1, x_unpacked.shape[2])

        #feed it to linear
        y_pred = self.linear_fc(batches_squashed)

        #unsquash batches to [batch_size, max_seq_len_of_this_batch, hidden_dim]
        y_pred = y_pred.contiguous().view((batch_size, max(lenghts),self.output_size))
        return y_pred, max(lenghts)

Я очень не уверен, правильно ли я это делаю, особенно с линейным слоем. Он получает тензор формы [batchsize * max_seq_len, hidden_layers], это правильно? Там еще есть дополненные значения ...

В моем цикле поезда я просто инициирую скрытое состояние для каждой эпохи, а затем зацикливаю (ввод, метки) из загрузчика данных:

    loss_funtion = nn.CrossEntropyLoss(ignore_index=-1)
    optimizer = torch.optim.SGD(net.parameters(), lr=lr, momentum=0.9)
   for inputs, labels in train_loader:
        counter+=1
        net.zero_grad()
        if train_on_gpu:
            inputs = inputs.to(device)
            labels = labels.to(device)

        output, _ = net(inputs)

        #remove excessive padding for labels
        labels = decreasing_padding(labels, max_padding_for_this_batch)

        #transposing the output to fit the crossEntropy definiton
        loss = loss_funtion(output.transpose(1, 2),labels.long())
        loss.backward()
        optimizer.step()

LSTM часто просто выводит одну метку для всей последовательности (есть последовательности, для которых это правильно). Потеря и точность в обучении и проверочный набор указывают на то, что он не обучается. Хотя потери немного уменьшаются, они сильно колеблются

Я подозреваю, что линейный слой реализован неправильно.

  • Должен ли я проходить каждое скрытое состояние (без заполнения?) Один за другим через слой и складывать его выходы?

Я был бы чрезвычайно признателен, если бы кто-то мог указать на мои ошибки и заблуждения, я потратил довольно много времени на это до сих пор.

...