Мультитензорный вход, без изменения потерь эпохи (LSTM + Линейная сеть) - PullRequest
0 голосов
/ 16 февраля 2020

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

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

Для каждой обучающей выборки у меня есть N тензоров (изначально 2D), которые соответствуют различным частотам выборки. Строки каждого тензора соответствуют временному индексу, а столбцы являются признаками. Для каждой обучающей выборки есть одна метка (0 или 1). Я использовал пользовательский набор данных PyTorch, чтобы сложить эти тензоры для пакета следующим образом (отрывок):

 def __getitem__(self, index):
        # self.tensors is a tuple of 2D data tensors (different shapes)
        # corresponding to different sampling frequencies
        features = [tensor[index] for tensor in self.tensors]

        if self.labels is None:
            return features
        else:
            return (features, self.labels[index])

Набор данных (например, train_ds ) можно индексировать следующим образом:

train_ds[sample_index][0][frequency_index][...row/col...]  # For data
train_ds[sample_index][1] # For label

При использовании с DataLoader возвращаемые функции из getitem для партии образцов (например, x ) будет сложен как тензор, который проиндексирован следующим образом:

x[frequency_index][sample_index][...row/col...]  # For data 

Обратите внимание на эффективный обмен индексов выше при использовании с DataLoader. Для каждой обучающей выборки данные от каждого из тензоров для этой выборки проталкиваются через две сети LSTM с различной длиной (соответствующей количеству временных шагов с учетом разных частот выборки). Выходные данные сетей LSTM затем передаются в линейную сеть с активацией ReLU, второй линейной сетью и, наконец, сигмовидным выходом.

Определение модели:

def __init__(...)

        # LSTMs for each of the different sampling frequencies for a fixed 
        #period (e.g., each tensor has different number of time steps
        self.layers = nn.ModuleList([nn.LSTM(window_size,1) for window_size in freq_window_sizes])

        # Linear layer that combines LSTM outputs
        self.fc1 = nn.Linear(lstm_output_count,hidden_dim)
        self.fc2 = nn.Linear(hidden_dim)
        self.fc3 = nn.Sigmoid()

код выглядит следующим образом:

def forward(self, x):
        y_pred = list()

        sample_count = len(x[0])
        freq_count = len(x)   

        for i in range(sample_count):
            lstm_outputs = list()

            # Different LSTMs for different frequencies of data
            for j in range(freq_count):             
                tensor_data = x[j][i]
                tensor_data = tensor_data.t()
                tensor_data.unsqueeze_(0)

                lstm_out, _ = self.layers[j](tensor_data)
                lstm_outputs += lstm_out                

            lstm_outputs = torch.cat(lstm_outputs, 0)

            # Push lstm outputs through linear network
            y = F.relu(self.fc1(lstm_outputs.t()))
            y = self.fc2(y)
            y = self.fc3(y)

            y_pred.append(y)

        return torch.tensor(y_pred,requires_grad=True)

Код обучения выглядит следующим образом:

def train(model, train_loader, epochs, criterion, optimizer, device):
    for epoch in range(1, epochs + 1):
        model.train() 
        total_loss = 0
        for x, y in train_loader:

            # The train_loader will feed us a batch of data
            # stacked for the batch_size (number of samples)
            # and provided seperately as daily and quarterly
            # data. e.g., x[frequency_index][sample_index][2D index for feature/timestep]
            for tensor in x:
                tensor.requires_grad_(True)

            x = [tensor.to(device) for tensor in x]

            y = y.type(torch.float32)  # Labels were integers
            y = y.to(device)

            optimizer.zero_grad()

            # get predictions from model
            y_pred = model(x)

            # perform backprop
            loss = criterion(y_pred, y)
            loss.backward()
            optimizer.step()

            total_loss += loss.data.item()

        print("Epoch: {}, Loss: {}".format(epoch, total_loss / len(train_loader)))

Он вызывается следующим образом:

torch.manual_seed(42)

train_dl = torch.utils.data.DataLoader(train_ds, batch_size=5,shuffle=False)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
feature_count = train_ds.get_feature_count()
window_sizes = [189, 3]
model = Model(feature_count,window_sizes).to(device)

optimizer = optim.Adam(model.parameters(),lr=0.001)

loss_fn = torch.nn.BCELoss()

train(model, train_dl, 10, loss_fn, optimizer, device)

Вывод выглядит следующим образом:

Epoch: 1, Loss: 0.25956406459516407
Epoch: 2, Loss: 0.25956406459516407
Epoch: 3, Loss: 0.25956406459516407
Epoch: 4, Loss: 0.25956406459516407
Epoch: 5, Loss: 0.25956406459516407
Epoch: 6, Loss: 0.25956406459516407
Epoch: 7, Loss: 0.25956406459516407
Epoch: 8, Loss: 0.25956406459516407
Epoch: 9, Loss: 0.25956406459516407
Epoch: 10, Loss: 0.25956406459516407

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

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

...