Цель этой статьи - предоставить обзор применения моделей LSTM и уникальных проблем, которые они представляют. Я объясню некоторые из наиболее важных (и запутанных) параметров, как подготовить данные для модели LSTM, а также разницу между моделями LSTM с сохранением состояния и без него. Это обсуждение будет вращаться вокруг применения моделей LSTM с Keras. Однако в этой статье не будет подробно рассказываться о том, как работают модели LSTM в целом. Таким образом, чтобы полностью понять это, вы уже должны быть знакомы с LSTM. В общем, сообщение Christopher Olah - фантастическая отправная точка.

Основная причина использования моделей LSTM / RNN заключается в том, что они работают с последовательностями векторов; последовательности на входе, выходе или обоих. Таким образом, перед применением модели LSTM необходимо знать, как выглядят ваши данные и чего вы пытаетесь достичь. Вот несколько примеров потенциальных схем RNN:

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

После определения структуры основной проблемы вам необходимо изменить форму данных так, чтобы они соответствовали форме ввода, которую ожидает модель LSTM Keras, а именно:

[образцы, время_шаги, особенности].

  • samples: количество ваших обучающих примеров.
  • time_steps: количество предыдущих шагов, которые вы хотите учесть при прогнозировании текущего шага. Например, мы можем использовать временной шаг = 3 с 2019–03–24, 2019–03–25 и 2019–03–26, чтобы предсказать ответ временного шага 2019–03–27 (см. Рисунок 2). Кроме того, параметр определяет количество внутренних / скрытых циклов в модели LSTM, т.е. количество зеленых прямоугольников (рисунок 1) равно параметру time_steps. Таким образом, как часто обновляется внутреннее состояние / состояние ячейки. Единственным исключением являются случаи один ко многим и многие ко многим с большим количеством скрытых циклов, чем входов и выходов (для таких случаев вы можете использовать RepeatVectors. Этот метод часто используется для моделей LSTM кодировщика-декодера. См. Brownlee для получения дополнительной информации).
  • features: количество функций в каждом входе.

Как изменить форму данных?

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

В качестве аргумента мы используем 100 образцов, каждый из которых содержит три функции и одну метку. Таким образом, при разделении набора данных на объекты и метки у нас есть набор классов объектов X с формой [100,3] и набор данных меток y с формой [100,]

Думайте о функциях f1, f2 и f3 как о информации о погоде, такой как давление, влажность и температура. Столбец метки содержит информацию, например, идет ли дождь или нет. Кроме того, строки упорядочены по возрастанию времени. Чтобы предсказать, будет ли дождь на следующем временном шаге (2019–03–28), было бы полезно рассмотреть предыдущие временные интервалы. Таким образом, в этом контексте входные данные представляют собой последовательность временных шагов, в то время как выходные данные могут быть либо одиночным значением («многие к одному»), либо последовательностью («многие ко многим»). Имейте в виду, что теперь мы должны изменить форму набора классов функций, чтобы он соответствовал форме архитектуры LSTM (опять же, ее [образцы, время_шаги, особенности]). Очевидно, что количество выборок - 100, а количество функций - 3, но как насчет параметра time_steps?

  1. Какое значение выбрать для значения временного шага? 5? 10? 100? К сожалению, общего ответа нет, и, как обычно в машинном обучении, это зависит от набора данных. Так что просто попробуйте разные комбинации и выясните, что лучше всего подходит для вашего контекста.
  2. Ради аргумента, давайте выберем timestep = 3. Как мы можем изменить набор данных так, чтобы он имел форму [100,3,3]? В настоящее время у нас есть 100 * 3 = 300 значений, поэтому мы не можем изменить набор данных до 100 * 3 * 3 = 900 значений. Но добиться этого можно, сдвинув данные, как это сделал Браунли в своей статье. Поступая таким образом, мы можем учитывать особенности / метки x предыдущих временных шагов для прогнозирования метки для текущего временного шага. Я хотел бы привести несколько примеров и добавить несколько идей:

a) Изменение функций: (в основном описано Браунли) мы используем функции предыдущих временных шагов time_step (например, 3), а также функции текущего временного шага для прогнозирования текущий ярлык. Это выглядит как:

б) Смещение меток: мы используем метки предыдущих временных шагов time_step (например, 5), чтобы предсказать текущую метку. Это выглядит как:

c) Сдвиг функций и меток: мы используем функции и метки предыдущего time_step (например, 3) временных шагов, чтобы предсказать текущую метку. Важно! Выбирая этот метод сдвига, мы не можем учитывать особенности текущего временного шага, потому что Форма ввода должна быть одинаковой на каждом временном шаге. К сожалению, мы не можем предоставить метку для текущего временного шага, потому что это то, что мы хотим спрогнозировать, и поэтому, хотя мы предоставляем x функций и 1 метку для каждого из предыдущих временных шагов, мы просто предоставляем x функций, а не метку для текущего временного шага. , что приводит к разному количеству информации по временным шагам. Тем не менее, вы можете использовать этот метод переключения, который выглядит так:

Я просто хочу упомянуть, что если мы выберем time_step = 1, это будет случай «один к одному», как на внешней левой диаграмме на рисунке 1. В этом случае модель LSTM почти похожа на нейронная сеть с прямой связью. Единственная разница - это математика в скрытом слое. В модели LSTM у нас все еще есть шлюз Забытия, Шлюз обновления и Выходной шлюз. Поскольку time_step = 1, у нас нет повторяющейся структуры, и поэтому внутреннее состояние и несколько выходов пропадают.

Что происходит в слоях LSTM Кераса?

Теперь давайте подробнее рассмотрим, что происходит в слое Keras LSTM для решения проблемы «многие к одному» или «многие ко многим». Вспомните информацию, которую Кристофер Олах предоставил в своем блоге: «Ключ к LSTM - это состояние ячейки […]. Он проходит прямо по всей цепочке.» Таким образом, для каждого цепочка / последовательность у нас одна ячейка / внутреннее состояние. В Keras есть важное различие между stateful (stateful = True) и stateless (stateful = False, default) Слои LSTM. На уровне LSTM без сохранения состояния пакет имеет x (размер пакета) внутренних состояний, по одному для каждой последовательности. Предположим, у нас есть 30 выборок, и мы выбираем размер пакета 10. Для каждой последовательности / строки в пакете у нас есть одно внутреннее состояние, ведущее к 10 внутренним состояниям в первом пакете, 10 внутренним состояниям во втором пакете и 10 внутренним состояниям в третья партия. (См. Рисунок 3). Критически важно, что внутреннее состояние и все выходы одной строки / последовательности удаляются при обработке последовательности, то есть при обработке одного пакета.

На уровне LSTM с отслеживанием состояния мы не сбрасываем внутреннее состояние и выходные данные после каждого пакета. Скорее мы удаляем их после каждой эпохи, что буквально означает, что мы используем и обновляем одно внутреннее состояние для одной последовательности в нескольких пакетах. Предположим, у нас есть 30 образцов. Каждый образец содержит информацию о последних 10 временных шагах, каждый из которых имеет две особенности. Таким образом, в одной последовательности / строке всего 20 признаков. Как мы можем использовать одну последовательность для нескольких партий? Путем определения batch_input_shape (batch_size, time_steps, features) на уровне LSTM, например:

model.add(LSTM(50, batch_input_shape=(1,10,2), stateful = True)´

Выбирая (1,10,2) в качестве параметра, мы обрабатываем каждую последовательность (1) более 10 пакетами, каждая из которых содержит 2 функции. Таким образом, каждый пакет содержит один временной шаг последовательности (10 * 2 = 20). Чтобы быть более точным, первый пакет содержит первый временной шаг (t-9) первой последовательности, второй пакет содержит второй временной шаг (t-8) первой последовательности и т. Д., Что приводит к использованию 10 пакетов для обработать первую последовательность. В то время как LSTM без сохранения состояния сбрасывает внутреннее состояние между пакетами, мы передаем внутреннее состояние и выходные данные из одного пакета в следующий пакет. Почему? Потому что мы хотим хранить информацию в нескольких пакетах (помните: цель модели LSTM - связать предыдущую информацию с текущей задачей). См. Филипп Ереми для получения дополнительной информации. Когда нам следует использовать LSTM с отслеживанием состояния?

1. Вычислительные ограничения. Например, когда дело доходит до анализа видео, мы часто имеем дело с кадрами порядка 1000x1000x3 элементов. Кроме того, последовательность может легко хранить информацию последних 1000 кадров, что приводит к общему количеству 1000x1000x1000x3 = 3 000 000 000 функций на последовательность! Из-за нагрузки на память, создаваемой такой последовательностью, мы хотели бы разбить последовательность на несколько частей.

2. Машинное обучение в Интернете. Когда дело доходит до анализа данных в реальном времени в связи с инкрементальным обучением, мы не хотим сбрасывать свое внутреннее состояние. Скорее, мы хотели бы сохранять и постоянно обновлять его при каждом сборе новых входных данных.

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

Давайте посмотрим на одну итерацию для первой последовательности / строки слоя LSTM с time_step = 5.

После 5-го шага мы либо сбросим внутреннее состояние и все выходы (если stateful = False), либо сохраним внутреннее состояние и все выходы (если stateful = True ), и мы продолжим со следующей последовательностью.

Кроме того, нам нужно определить, как должен выглядеть результат. Оператор return_sequence может использоваться либо для возврата списка, содержащего один вывод для каждого ввода (return_sequence = True, «многие ко многим»), либо для возврата только последнего вывода (return_sequence = False , «многие к одному»). В первом случае форма вывода будет (batch_size, time_steps, unit), тогда как мы игнорируем time_steps во втором случае, что приводит к следующей форме вывода: (batch_size, unit)

А как насчет размера партии?

Нет никакой разницы между выбором размера пакета в модели LSTM и в нейронной сети любого другого типа. С вычислительной точки зрения, более эффективно обновлять веса в нейронной сети после мини-партии примеров, чем после каждого примера. Для объяснения и других преимуществ см. Глубокое обучение Гудфеллоу, Бенжио и Курвиль.

Заключение

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