LSTM предсказывает одно и то же значение.

Вопрос или проблема

Я реализую в PyTorch модель LSTM для предсказания, увеличится или уменьшится закрывающая стоимость акции через 5 и 10 минут. Конкретно, я использую 24 года данных с интервалом в 5 минут с 19 признаками, разделенных на блоки по одной неделе на прогноз (используя 7 различных акций). Проблема, с которой я столкнулся, заключается в том, что, как ни старайся, модель LSTM, похоже, предсказывает значения вокруг одного определенного значения, чтобы всегда минимизировать потерю, что не снижается слишком сильно.

Я предварительно подготавливаю входные данные и цели в torch.tensors с размерностью [batch_size, sequence_len, features] (в моем случае это [32, 2016, 19]), нормализую их между 0 и 1 и подаю в мою модель LSTM, которая структурирована следующим образом:

class MultiInputOutputLSTM(nn.Module):
  def __init__(self, input_size, hidden_size, num_layers, output_size, dropout, lr, batch_size):
    super(MultiInputOutputLSTM, self).__init__()
    self.input_size = input_size
    self.hidden_size = hidden_size
    self.num_layers = num_layers
    self.dropout = dropout
    self.batch_size = batch_size
    self.loss_list = []
    self.accuracy = 0
    self.predictions_list = [0]

    self.lstm = nn.LSTM(input_size = self.input_size, hidden_size = self.hidden_size, num_layers = self.num_layers, dropout = self.dropout,  batch_first=True)
    self.fc = nn.Linear(hidden_size, output_size, bias=True)
    self.sigmoid = nn.Sigmoid()
    self.criterion = nn.BCEWithLogitsLoss()
    self.optimizer = torch.optim.RMSprop(self.parameters(), lr = lr, alpha=0.9, weight_decay=1e-4,  momentum=0.5)
    self.scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(self.optimizer, 'min')

  def forward(self, x):

    h0 = torch.zeros(self.num_layers, self.batch_size, self.hidden_size)
    c0 = torch.zeros(self.num_layers, self.batch_size, self.hidden_size)
    lstm_out, _ = self.lstm(x, (h0, c0))
    output = self.fc(lstm_out[:, -1, :])

    return output

  def train_step(self ,x, y):
        self.train()
        predictions_1 = torch.round(self.forward(x))
        predictions = self.forward(x)
        if (predictions_1.detach().cpu().numpy()[0] == y.detach().cpu().numpy()[0]).all():
          self.accuracy += 1
        self.predictions_list.append(predictions.detach().cpu().numpy()[0][0])
        penalty = torch.mean((predictions-0.5)**2)
        loss = self.criterion(predictions, y) + penalty
        self.scheduler.step(loss)
        self.optimizer.zero_grad()
        self.loss_list.append(loss.item())
        mean_loss = sum(self.loss_list)/len(self.loss_list)
        loss.backward()
        torch.nn.utils.clip_grad_norm_(self.parameters(), max_norm=6)
        self.optimizer.step()
        return loss.item(), mean_loss, self.accuracy, predictions.detach().cpu().numpy()[0], y.detach().cpu().numpy()[0]

Цели равны 1, если цена растет, 0 в противном случае.
Гиперпараметры такие:

input_size = 19
hidden_size = 3
num_layers = 5
output_size = 2
lr = 0.001
num_epochs = 5
batch_size = 32
dropout = 0.3

Сначала я создаю dataframe из CSV файла: затем я делю его на цели и входные данные, и с последними вычисляю различные торговые сигналы.
Затем я преобразую данные в подходящий вид для модели LSTM, разделяя их на недельные блоки.

Модель должна предсказывать значения, близкие к единице, если цена растет, и близкие к нулю, если цена остается неизменной/снижается: однако, она создает одно предсказание и затем постепенно снижается к отметке 0.5, оставаясь на месте до конца процесса обучения. Разделение на обучающую и тестовую выборки составляет 85-15%.

Вот список того, что я пробовал: уменьшение или увеличение скорости обучения (от 0.00001 до 0.1), размера выхода (с большим и меньшим количеством прогнозов), batch_size (от 1 до 256), num_layers (от 1 до 5), input_size (с 1, 2, 3… 19 признаками), dropout (от 0 до 0.7) и num_epochs (от 1 до 100).

Я пробовал Adam оптимизатор, затем SDG, затем RMSProp оптимизатор, изменяя alpha, momentum и weight_decay.
Я пробовал менять входные данные, чтобы лучше соответствовать целям (заменяя каждый элемент на 0 и 1: 1, если элемент больше предыдущего, 0 в противном случае) или использовать приросты между элементами.

Также пробовал BCELoss (с слоем активации sigmoid в self.forward()), L1Loss, MSELoss, CrossEntropyLoss, и даже регулировал потери, добавляя штраф penalty = torch.mean((y-predictions)**(-2)), но это ничего не изменило, значения все равно колеблются вокруг 0.5. Средняя потеря снижается с 1.174 до 1.040.
Сейчас я пытаюсь сильно штрафовать значения вокруг 0.5 с помощью penalty = torch.mean((predictions-0.5)**(-2)), но предсказания идут в одном направлении и остаются около 0 или 1, не обучаясь.

Что я могу сделать, чтобы решить эти проблемы? (кто-то предложил, что это может быть исчезающий градиент, но я действительно не знаю, как решить эту проблему)

Ответ или решение

Проблема, с которой вы столкнулись при реализации модели LSTM в PyTorch для предсказания изменения стоимости акций, типична для задач временных рядов и классификации. Вы описали, что ваша модель, независимо от попыток изменить гиперпараметры или стратегию обучения, кажется, стремится к предсказаниям, близким к постоянному значению, главным образом к 0.5, вместо того чтобы правильно разбирать входные данные и делать значимые прогнозы. Рассмотрим, почему это может происходить, и обсудим возможные решения.

Теория

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

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

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

  3. Архитектура и гиперпараметры. Открытые архитектуры могут плохо справляться с задачей, особенно если емкость модели (например, количество нейронов в скрытых слоях) не соотносится с размерностью и сложностью данных. Кроме того, выбор функции активации, функции потерь и оптимизатора может существенно влиять на производительность.

Пример

На практике, эффективное решение проблемы требует применения комплексного подхода:

  1. Анализ и предобработка данных:

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

    • Попробуйте увеличить или уменьшить hidden_size. Это может помочь модели лучше улавливать сложные зависимости.
    • Увеличьте количество эпох обучения, чтобы дать возможность модели проявить свои способности.
    • Измените количество слоев LSTM. Иногда менее глубокая модель может лучше справляться с задачей.
  3. Выбор функций потерь и оптимизации:

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

Применение

На основании приведенной теории и примеров, разработайте план действий:

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

  2. Испытайте настройки параметров модели. Рассмотрите возможность увеличения hidden_size для LSTM, хотя важно помнить, что слишком большие размеры могут привести к переобучению.

  3. Проверяйте архитектуру и оптимизатор:

    • Проверьте, чтобы dropout не был слишком высоким; это может приводить к "забыванию" всей полной зависимости данных.
    • Пробуйте различные стратегии регуляризации, такие как L2-регуляризация в оптимизаторе Adam или AdamW.
  4. Если структура входных данных использует признаки, недопонимание связи которых с выводом может вредить модели, проведите переработку: может быть полезно сократить количество используемых признаков для сокрытия информации.

  5. Рассмотрите возможность использования более сложной архитектуры, такой как двойные LSTM с разными фильтрами или внедрение дополнительных слоев регуляризации.

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

Оцените материал
Добавить комментарий

Капча загружается...