Я пытаюсь реализовать двоичный классификатор, где каждая выборка включает данные временных рядов с разными частотами выборки в течение фиксированного периода времени. Я не сгенерировал полный набор данных, но хотел, чтобы среда работала, чтобы убедиться, что я понимаю, что она может быть реализована.
Проблема в том, что мой минимальный рабочий пример не демонстрирует никакого числового (даже шумового) движения во время тренировок и мне интересно, где я ошибся. Я думаю, что разные тензоры данных могут усложнять, или я что-то упустил.
Для каждой обучающей выборки у меня есть 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. Потеря меняется, но она не переходит от одной эпохи к другой. Интуитивно понятно, что результаты, которые я получаю из прогнозов, слишком похожи, чтобы быть точными, и, похоже, не меняются от одной эпохи к другой.
Я не уверен, что я делаю здесь неправильно - любые советы или советы приветствуются.