Эта запись в блоге является продолжением моей предыдущей публикации о том, как использовать LSTM для прогнозирования цены акции на основе ее исторических данных. Мы видели, как скомпилировать модель Keras LSTM. Здесь мы увидим некоторые способы, с помощью которых мы можем найти правильную архитектуру и гиперпараметры.

Вот некоторые из наших вариантов:

  1. Ручная настройка или ручной поиск - это наиболее болезненный метод поиска правильной конфигурации, при котором вы пробуете определенные значения для каждого параметра одно за другим. Но при наличии некоторого опыта, тщательного анализа первоначальных результатов и интуиции это может оказаться действительно полезным.
  2. Поиск по сетке. Это действительно единственный способ предоставить вам лучший набор параметров из всех введенных в него опций. Вы передаете диапазон значений для каждого параметра, который хотите оптимизировать, затем тренируетесь и обнаруживаете потерю проверки для каждой комбинации. Как вы понимаете, это наиболее трудоемкий и зачастую неосуществимый метод.
  3. Случайный поиск - это подмножество поиска по сетке, которое случайным образом выбирает подмножество всех возможных комбинаций.
  4. Байесовская оптимизация / другие вероятностные оптимизации. Этот метод (байесовская оптимизация) действительно сложен математически, и, честно говоря, я не исследовал математику в нем. Я просто дам обзор того, что он на самом деле делает, даже если вы не знаете, как он работает внутри, вы все равно можете применить его в программе, как мы увидим позже. Байесовская оптимизация использует так называемый гауссовский процесс, чтобы угадать или смоделировать целевую функцию (функцию, которую мы хотим минимизировать, найдя правильный набор гиперпараметров). В этом методе устанавливается ограничение на то, сколько раз мы хотим оценивать нашу целевую функцию, поскольку предполагается, что это очень дорого. Сначала выбирается случайный набор точек в диапазоне параметров для наблюдения за значениями функции. Затем, используя эти результаты, используется гауссовский процесс, чтобы угадать целевую функцию. Опубликуйте, какая функция сбора данных используется, чтобы решить, из какой точки выполнять выборку следующей. И этот процесс повторяется предельное количество раз, указанное выше. Вы можете ссылаться на это и это для получения более глубоких знаний. Существуют и другие методы, такие как TPE, который реализован с использованием Hyperopt (код ниже). Вы можете проверить эту бумагу, чтобы понять TPE.

Реализация поиска по сетке

Если вы используете модели SK-Learn, вы можете использовать их GridSearchCV напрямую. Это довольно просто использовать. Вы можете перейти по ссылке на их документацию выше. Преимущество состоит в том, что у него есть возможность запускать задания параллельно. Если вы используете модель Keras, вам придется использовать оболочки для модели Keras, как описано здесь.

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

Другая реализация интеллектуального поиска

Доступно несколько пакетов с открытым исходным кодом для минимизации целевых функций с помощью других более умных алгоритмов поиска. Я буду показывать примеры для HyperOpt и Talos. Ниже показано, как реализовать настройку гиперпараметров с помощью Hyperopt, который использует алгоритм TPE для минимизации функции.

В приведенном выше фрагменте кода переменная search_space содержит параметры и их значения, которые вы хотите найти. Функция «fmin» в конце - это фактическая функция, которая выполняет минимизацию. Сама программа довольно проста, и я добавил к ней комментарии, поэтому разобраться в ней не составит труда. Но я хотел бы глубже изучить формирование словаря пространства поиска, потому что это немного неудобно. Рассмотрим это под микроскопом:

В основном словаре содержатся все ключи для параметров, которые мы хотим оптимизировать. В основном мы будем иметь дело с двумя функциями (или стохастическими выражениями, как они это называют), а именно с выбором и равномерным. «hp.choice» принимает список значений для попытки. Затем эта функция возвращает один из вариантов, который должен быть списком или кортежем. Строка (первый параметр), которую мы передаем в hp.choice и hp.uniform, используется Hyperopt в основном для внутренних целей. «hp.uniform» возвращает значение, равное между 2-м и 3-м переданными параметрами (низким и высоким). Сложнее всего, когда у вас есть такой параметр, как «lstm_layers», который определяет количество слоев LSTM в сети. Для таких параметров у нас есть два новых набора параметров для тестирования: первый, когда количество уровней LSTM в сети равно одному, второй, когда используются два уровня LSTM. В этом случае вы можете видеть, что я использовал hp.choice, чтобы сообщить системе, что я выбрал для этого параметра (lstm_layers), и значение для этого параметра задается ключом «Layers». Когда Hyperopt тестирует модель с двумя уровнями LSTM, он будет рассматривать 2 других параметра для тестирования, а именно - количество узлов на 2-м уровне LSTM (lstm2_nodes) и исключить их, которые будут использоваться для 2-го уровня LSTM (lstm2_dropouts). Я оставил первый слой lstm пустым, но вы также можете включить другие параметры для тестирования.

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

Использование Talos аналогично предыдущему инструменту; вам нужно создать функцию, которая строит модель, обучает ее, оценивает ее на данных проверки. Единственное отличие состоит в том, что функция модели возвращает объект и модель истории Keras вместо словаря. Также следует отметить, что мы передаем X и Y здесь, в функции сканирования, но они никогда не используются, поскольку мы хотим построить данные на основе выбранных «batch_size» и «time_steps» в текущей итерации. Но для более простых задач было бы проще.

Вы также можете использовать Hyperas (Hyperopt + Keras), который является оболочкой для Hyperopt. Главное преимущество заключается в том, что вам не нужно изучать какой-либо новый синтаксис / функции Hyperopt. Все, что вам нужно сделать, это определить словарь пространства поиска, как раньше, и построить свою модель, как показано ниже. Все, что вам нужно сделать, это поместить значения, которые вы хотите проверить для параметра, в двойные фигурные скобки (например, {{[1, 2, 3]}}).

Но Hyperas в этом случае не сработал, так как я вызывал функцию «data» из функции «model», и синтаксис использования двойных фигурных скобок вызвал некоторые проблемы. Я не стал вдаваться в подробности, так как у меня уже были другие инструменты. Тем не менее, я думаю, что об этом стоит упомянуть здесь, так как это намного проще.

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

Например, когда я работал над набором данных по акциям, я сначала написал свою собственную реализацию поиска по сетке и запустил ее в облаке. Затем я попробовал эти вышеупомянутые инструменты для интеллектуальной настройки, но, к сожалению, облачная виртуальная машина в тот день была довольно медленной (медленнее, чем мой ноутбук!), И у меня заканчивалось терпение. К счастью, к тому времени, когда я прочитал об этих инструментах, реализовал и начал использовать их в облаке, мой поиск по сетке был завершен. Я выполнил поиск по сетке по этим значениям:

search_params = {
    "batch_size": [20, 30, 40],
    "time_steps": [30, 60, 90],
    "lr": [0.01, 0.001, 0.0001],
    "epochs": [30, 50, 70]
}

Этот поиск всего по 4 параметрам (81 комбинация) длился 24 часа! У меня нет результата, чтобы поделиться здесь, потому что я забыл реализовать регистрацию в волнении (ошибка 1). Используя результаты поиска по сетке, я получил неутешительный прогноз:

Но я не оптимизировал другие вещи, такие как количество слоев и т. Д. (Я начал с нейронной сети, имеющей 2 слоя LSTM и 1 плотный слой - ошибка 2. Всегда начинайте с более простой модели, тестируйте воду, а затем строить свой путь вверх). Так или иначе, я решил продолжить оптимизацию вручную. Я взял лучший результат из поиска по сетке и попробовал другие параметры. Как бы я ни старался, я не мог сильно исправить потерю. Я знал, что это переоснащение, поэтому попытался увеличить отсев, но безуспешно. Затем меня осенило, что, возможно, я слишком стараюсь и одного слоя LSTM достаточно (да, я знаю, что глуп - ошибка 3, недооценивающая мощь нейронных сетей). Но как узнать, переоснащена ли модель? На самом деле это довольно просто. В моем случае ошибка обучения и ошибка проверки выглядели так:

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

Поэтому я удалил второй слой LSTM и добавил слой выпадения со значением выше, чем то, что я использовал (0,5 из 0,2). И вуаля!

Значительное улучшение, правда? Я почти уверен, что приложив больше усилий, мы сможем сделать его еще лучше.

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

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