как построить многомерный автоэнкодер с pytorch - PullRequest
1 голос
/ 03 июня 2019

Я следовал этому замечательному ответу для автоматического кодера последовательности,

Автокодер LSTM всегда возвращает среднее значение входной последовательности .

но я столкнулся с некоторой проблемой при попытке изменить код:

  1. вопрос первый: Ваше объяснение настолько профессионально, но проблема немного отличается от моей, я приложил некоторый код, который я изменил из вашего примера. Мои входные функции являются двухмерными, и мои выходные данные совпадают с входными данными. например:
input_x = torch.Tensor([[0.0,0.0], [0.1,0.1], [0.2,0.2], [0.3,0.3], [0.4,0.4]])
output_y = torch.Tensor([[0.0,0.0], [0.1,0.1], [0.2,0.2], [0.3,0.3], [0.4,0.4]])
the input_x and output_y are same, 5-timesteps, 2-dimensional feature.

        import torch
        import torch.nn as nn
        import torch.optim as optim

        class LSTM(nn.Module):
            def __init__(self, input_dim, latent_dim, num_layers):
                super(LSTM, self).__init__()
               self.input_dim = input_dim
                self.latent_dim = latent_dim
                self.num_layers = num_layers
                self.encoder = nn.LSTM(self.input_dim, self.latent_dim, self.num_layers)

                # I changed here, to 40 dimesion, I think there is some problem 
                # self.decoder = nn.LSTM(self.latent_dim, self.input_dim, self.num_layers)
                self.decoder = nn.LSTM(40, self.input_dim, self.num_layers)

            def forward(self, input):
                # Encode
                _, (last_hidden, _) = self.encoder(input)
                # It is way more general that way
                encoded = last_hidden.repeat(input.shape)
                # Decode
                y, _ = self.decoder(encoded)
               return torch.squeeze(y)

        model = LSTM(input_dim=2, latent_dim=20, num_layers=1)
        loss_function = nn.MSELoss()
        optimizer = optim.Adam(model.parameters())
        y = torch.Tensor([[0.0,0.0], [0.1,0.1], [0.2,0.2], [0.3,0.3], [0.4,0.4]])
        x = y.view(len(y), -1, 2)   # I changed here 

        while True:
            y_pred = model(x)
            optimizer.zero_grad()
            loss = loss_function(y_pred, y)
            loss.backward()
            optimizer.step()
            print(y_pred)

Приведенный выше код может очень хорошо выучить, вы можете помочь просмотреть код и дать некоторые инструкции.

Когда я вводю 2 примера в качестве входных данных для модели, модель не может работать:

например, измените код:

y = torch.Tensor([[0.0,0.0], [0.1,0.1], [0.2,0.2], [0.3,0.3], [0.4,0.4]])

до:

y = torch.Tensor([[[0.0,0.0],[0.5,0.5]], [[0.1,0.1], [0.6,0.6]], [[0.2,0.2],[0.7,0.7]], [[0.3,0.3],[0.8,0.8]], [[0.4,0.4],[0.9,0.9]]])

Когда я вычисляю функцию потерь, она жалуется на некоторые ошибки? может кто-нибудь помочь взглянуть

  1. вопрос второй: мои тренировочные образцы разной длины: например:
x1 = [[0.0,0.0], [0.1,0.1], [0.2,0.2], [0.3,0.3], [0.4,0.4]]   #with 5 timesteps
x2 = [[0.5,0.5], [0.6,0.6], [0.7,0.7]] #with only 3 timesteps

Как я могу одновременно ввести эти два обучающих образца в модель для пакетного обучения.

1 Ответ

0 голосов
/ 05 июня 2019

Рекуррентный N-мерный автоэнкодер

Прежде всего, LSTM работают на 1D выборках, у вас 2D, как обычно используется для слов, закодированных одним вектором.

Не беспокойтесь, можно сгладить этот 2D образец до 1D, например, для вашего случая:

import torch

var = torch.randn(10, 32, 100, 100)
var.reshape((10, 32, -1))  # shape: [10, 32, 100 * 100]

Пожалуйста, обратите внимание, что это на самом деле не является общим, что, если бы у вас был 3D ввод? Приведенные ниже фрагменты обобщают это понятие для любого измерения ваших образцов, при условии, что предыдущими измерениями являются batch_size и seq_len:

import torch

input_size = 2

var = torch.randn(10, 32, 100, 100, 35)
var.reshape(var.shape[:-input_size] + (-1,)) # shape: [10, 32, 100 * 100 * 35]

Наконец, вы можете использовать его внутри нейронной сети следующим образом. Посмотрите на forward особенности метода и аргументы конструктора:

import torch


class LSTM(nn.Module):
    # input_dim has to be size after flattening
    # For 20x20 single input it would be 400
    def __init__(
        self,
        input_dimensionality: int,
        input_dim: int,
        latent_dim: int,
        num_layers: int,
    ):
        super(LSTM, self).__init__()
        self.input_dimensionality: int = input_dimensionality
        self.input_dim: int = input_dim  # It is 1d, remember
        self.latent_dim: int = latent_dim
        self.num_layers: int = num_layers
        self.encoder = torch.nn.LSTM(self.input_dim, self.latent_dim, self.num_layers)
        # You can have any latent dim you want, just output has to be exact same size as input
        # In this case, only encoder and decoder, it has to be input_dim though
        self.decoder = torch.nn.LSTM(self.latent_dim, self.input_dim, self.num_layers)

    def forward(self, input):
        # Save original size first:
        original_shape = input.shape
        # Flatten 2d (or 3d or however many you specified in constructor)
        input = input.reshape(input.shape[: -self.input_dimensionality] + (-1,))

        # Rest goes as in my previous answer
        _, (last_hidden, _) = self.encoder(input)
        encoded = last_hidden.repeat(input.shape)
        y, _ = self.decoder(encoded)

        # You have to reshape output to what the original was
        reshaped_y = y.reshape(original_shape)
        return torch.squeeze(reshaped_y)

Помните, что в этом случае вы должны reshape свои выходные данные. Это должно работать для любых размеров.

Дозирование

Когда дело касается пакетирования и разной длины последовательностей, это немного сложнее.

Вы должны заполнить каждую последовательность партиями, прежде чем проталкивать ее по сети. Обычно значения, которые вы дополняете нулями, вы можете настроить в LSTM.

Вы можете проверить эту ссылку для примера. Вам придется использовать такие функции, как torch.nn.pack_padded_sequence и другие, чтобы заставить его работать, вы можете проверить этот ответ .

О, начиная с PyTorch 1.1, вам не нужно сортировать последовательности по длине, чтобы упаковать их. Но когда дело доходит до этой темы, возьмите несколько уроков, которые должны прояснить ситуацию.

Наконец: Пожалуйста, разделите ваши вопросы. Если вы выполняете автоматическое кодирование на одном примере, переходите к пакетной обработке и, если у вас там есть проблемы, пожалуйста, опубликуйте новый вопрос в StackOverflow, спасибо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...