Правильный способ подачи данных временных рядов в LSTM с отслеживанием состояния?

Предположим, у меня есть последовательность целых чисел:

0,1,2, ..

и хотите предсказать следующее целое число по последним 3 целым числам, например:

[0,1,2]->5, [3,4,5]->6, так далее

Предположим, я настроил свою модель так:

batch_size=1
time_steps=3
model = Sequential()
model.add(LSTM(4, batch_input_shape=(batch_size, time_steps, 1), stateful=True))
model.add(Dense(1))

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

Первый вопрос: правильно ли я понимаю?

Обратите внимание, я нарисовал предыдущие состояния C_{t-1}, h_{t-1} ввод изображения, как это показано при указании stateful=True. В этой простой задаче "прогнозирование следующего целого числа" производительность должна улучшиться за счет предоставления этой дополнительной информации (если предыдущее состояние является результатом трех предыдущих целых чисел).

Это подводит меня к моему основному вопросу: кажется, стандартной практикой (например, см. Этот пост в блоге и утилиту предварительной обработки keras TimeseriesGenerator) является подача в модель ступенчатого набора входных данных во время обучения.

Например:

batch0: [[0, 1, 2]]
batch1: [[1, 2, 3]]
batch2: [[2, 3, 4]]
etc

Это меня смутило, потому что кажется, что для этого требуется вывод 1-й ячейки Lstm (соответствует 1-му временному шагу). Смотрите этот рисунок:

Из документов tensorflow:

Stateful: Boolean (по умолчанию False). Если True, последнее состояние для каждой выборки с индексом i в пакете будет использоваться в качестве начального состояния для выборки с индексом i в следующем пакете.

кажется, что это "внутреннее" состояние недоступно, и все, что доступно, - это конечное состояние. Смотрите этот рисунок:

Итак, если я правильно понимаю (а это явно не так), не следует ли нам подавать неперекрывающиеся окна образцов в модель при использовании stateful=True? Например:

batch0: [[0, 1, 2]]
batch1: [[3, 4, 5]]
batch2: [[6, 7, 8]]
etc

1 ответ

Решение

Ответ: зависит от решаемой проблемы. В вашем случае одноэтапного прогнозирования - да, можно, но не обязательно. Но независимо от того, сделаете вы это или нет, это существенно повлияет на обучение.


Пакетный или образец механизма ("см. AI" = см. Раздел "дополнительная информация")

Все модели рассматривают образцы как независимые примеры; Пакет из 32 образцов похож на подачу по 1 образцу за раз, 32 раза (с отличиями - см. AI). С точки зрения модели, данные разделяются на пакетное измерение,batch_shape[0], и размеры элементов, batch_shape[1:]- двое "не разговаривают". Единственная связь между ними - через градиент (см. AI).


Партии с перекрытием и без перекрытия

Возможно, лучший способ понять это - основанный на информации. Я начну с двоичной классификации таймсерий, а затем свяжу ее с предсказанием: предположим, у вас есть 10-минутные записи ЭЭГ, 240000 временных шагов каждая. Задача: захват или невыход?

  • Поскольку 240k - это слишком много для RNN, мы используем CNN для уменьшения размерности.
  • У нас есть возможность использовать "скользящие окна" - т.е. кормить подсегмент за раз; давайте использовать 54k

Возьмите 10 образцов, сформируйте (240000, 1). Как кормить?

  1. (10, 54000, 1), включены все образцы, нарезка как sample[0:54000]; sample[54000:108000]...
  2. (10, 54000, 1), включены все образцы, нарезка как sample[0:54000]; sample[1:54001]...

Что из двух вышеперечисленных вы выберете? Если (2), ваша нейронная сеть никогда не перепутает припадок с неприпадом для этих 10 образцов. Но он также ничего не знает о любом другом образце. То есть, он будет сильно переобучен, потому что информация, которую он видит за итерацию, почти не отличается (1/54000 = 0,0019%) - так что вы в основном скармливаете ему одну и ту же партию несколько раз подряд. Теперь предположим (3):

  1. (10, 54000, 1), включены все образцы, нарезка как sample[0:54000]; sample[24000:81000]...

Намного разумнее; теперь наши окна перекрываются на 50%, а не на 99,998%.


Прогноз: плохое перекрытие?

Если вы делаете одноэтапный прогноз, теперь информационный ландшафт изменится:

  • Скорее всего, длина вашей последовательности составляет faaar от 240000, поэтому перекрытия любого рода не страдают от эффекта "одна и та же партия несколько раз".
  • Прогнозирование принципиально отличается от классификации тем, что метки (следующий временной шаг) различаются для каждой подвыборки, которую вы кормите; классификация использует один для всей последовательности

Это резко меняет вашу функцию потерь и то, что является "хорошей практикой" для ее минимизации:

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

Что я должен делать?

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

  1. Сдвинута одна выборка: модель учится лучше предсказывать на один шаг вперед для каждого начального шага - это означает: (1) устойчивость LSTM к начальному состоянию ячейки; (2) LSTM хорошо предсказывает любой шаг вперед с учетом X шагов позади
  2. Многие образцы, сдвинутые в более поздней партии: модель с меньшей вероятностью `` запомнит '' набор поездов и переобучится

Ваша цель: уравновесить два; Основное преимущество 1 над 2:

  • 2 может нанести ущерб модели, заставив ее забыть увиденные образцы
  • 1 позволяет модели извлекать более качественные характеристики, исследуя образец по нескольким начальным и конечным точкам (меткам) и соответствующим образом усредняя градиент.

Должен ли я когда-нибудь использовать (2) в предсказании?

  • Если длина вашей последовательности очень велика и вы можете позволить себе "скользящее окно" с ~50% ее длины, возможно, но это зависит от природы данных: сигналов (ЭЭГ)? Да. Акции, погода? Сомневаюсь.
  • Прогнозирование "многие-ко-многим"; чаще можно увидеть (2), в больших для более длинных последовательностей.

LSTM с отслеживанием состояния: на самом деле может быть совершенно бесполезным для вашей проблемы.

Stateful используется, когда LSTM не может обработать всю последовательность сразу, поэтому она "разбивается" - или когда требуются разные градиенты из обратного распространения. В первом случае идея такова - LSTM учитывает первую последовательность при оценке второй:

  • t0=seq[0:50]; t1=seq[50:100] имеет смысл; t0 логически приводит к t1
  • seq[0:50] --> seq[1:51] не имеет смысла; t1 не происходит причинно из t0

Другими словами: не перекрывайте состояние в отдельных пакетах. Одна и та же партия в порядке, опять же, независимость - отсутствие "состояния" между образцами.

Когда использовать с отслеживанием состояния: когда LSTM выигрывает от рассмотрения предыдущего пакета при оценке следующего. Это может включать одношаговые прогнозы, но только если вы не можете кормить всю последовательность сразу:

  • Желательно: 100 временных шагов. Может: 50. Итак, мы настроилиt0, t1 как в первом пункте выше.
  • Проблема: не просто реализовать программно. Вам нужно будет найти способ подавать в LSTM, не применяя градиенты - например, замораживание веса или настройкуlr = 0.

Когда и как LSTM "передает состояния" в состоянии с отслеживанием состояния?

  • Когда: только от партии к партии; образцы полностью независимы
  • Как: в Керасе только от партии образца к партии образца:stateful=True требует указатьbatch_shape вместо того input_shape - потому что Керас строит batch_size отдельные состояния LSTM при компиляции

Как указано выше, вы не можете этого сделать:

# sampleNM = sample N at timestep(s) M
batch1 = [sample10, sample20, sample30, sample40]
batch2 = [sample21, sample41, sample11, sample31]

Из этого следует 21 причинно следует 10- и сорвут обучение. Вместо этого сделайте:

batch1 = [sample10, sample20, sample30, sample40]
batch2 = [sample11, sample21, sample31, sample41]

Партия против образца: дополнительная информация

"Пакет" - это набор образцов - 1 или больше (всегда предполагайте последнее для этого ответа). Три подхода для перебора данных: пакетный градиентный спуск (сразу весь набор данных), стохастический GD (по одной выборке за раз) и Minibatch GD (промежуточный). (Однако на практике мы также называем последний SGD и различаем только BGD - предположим, что это так для этого ответа.) Различия:

  • SGD на самом деле никогда не оптимизирует функцию потерь поезда - только ее "приближения"; каждый пакет является подмножеством всего набора данных, и вычисленные градиенты имеют отношение только к минимизации потерь этого пакета. Чем больше размер партии, тем лучше ее функция потерь похожа на функцию потерь поезда.
  • Вышеупомянутое может распространяться на подгонку партии к образцу: выборка является приближением партии или более плохой аппроксимацией набора данных.
  • Подгонка сначала 16 образцов, а затем еще 16 - это не то же самое, что подгонка сразу 32 - поскольку веса обновляются между ними, поэтому результаты модели для второй половины будут изменяться.
  • Основная причина выбора SGD вместо BGD на самом деле не в вычислительных ограничениях, а в том, что в большинстве случаев он лучше. Объясняется просто: намного проще переоснастить BGD, и SGD сходится к лучшим решениям на тестовых данных, исследуя более разнообразное пространство потерь.

БОНУСНЫЕ ДИАГРАММЫ:


Другие вопросы по тегам