Вопрос-Ответ

Understanding Keras LSTMs

Понимание Keras LSTMs

Я пытаюсь согласовать свое понимание LSTMs с тем, что указано здесь в этом посте Кристофера Олаха, реализованном в Keras. Я слежу за блогом, написанным Джейсоном Браунли для руководства Keras. Что меня больше всего смущает, так это,


  1. Преобразование рядов данных в [samples, time steps, features] и,

  2. LSTMs с отслеживанием состояния

Давайте сосредоточимся на двух вышеупомянутых вопросах со ссылкой на вставленный ниже код:

# reshape into X=t and Y=t+1
look_back = 3
trainX, trainY = create_dataset(train, look_back)
testX, testY = create_dataset(test, look_back)

# reshape input to be [samples, time steps, features]
trainX = numpy.reshape(trainX, (trainX.shape[0], look_back, 1))
testX = numpy.reshape(testX, (testX.shape[0], look_back, 1))
########################
# The IMPORTANT BIT
##########################
# create and fit the LSTM network
batch_size = 1
model = Sequential()
model.add(LSTM(4, batch_input_shape=(batch_size, look_back, 1), stateful=True))
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')
for i in range(100):
model.fit(trainX, trainY, nb_epoch=1, batch_size=batch_size, verbose=2, shuffle=False)
model.reset_states()

Примечание: create_dataset принимает последовательность длины N и возвращает N-look_back массив, каждый элемент которого представляет собой последовательность длины look_back.

Что такое временные шаги и возможности?

Как можно видеть, trainX представляет собой трехмерный массив, в котором Time_steps и Feature являются двумя последними измерениями соответственно (3 и 1 в этом конкретном коде). Что касается изображения ниже, означает ли это, что мы рассматриваем many to one случай, когда количество розовых прямоугольников равно 3? Или это буквально означает, что длина цепочки равна 3 (т. Е. Рассматриваются только 3 зеленых квадрата). введите описание изображения здесь

Становится ли аргумент features актуальным, когда мы рассматриваем многомерные ряды? например, моделирование двух финансовых запасов одновременно?

LSTMs с отслеживанием состояния

Означает ли LSTMs с сохранением состояния, что мы сохраняем значения ячеек памяти между запусками пакетов? Если это так, batch_size является единицей, и память сбрасывается между тренировочными запусками, так какой смысл говорить, что она была с сохранением состояния. Я предполагаю, что это связано с тем фактом, что обучающие данные не перемешиваются, но я не уверен, как.

Есть идеи? Ссылка на изображение: http://karpathy.github.io/2015/05/21/rnn-effectiveness /

Правка 1:

Немного смущен комментарием @ van о равенстве красного и зеленого полей. Итак, просто для подтверждения, соответствуют ли следующие вызовы API развернутым диаграммам? Особо отмечая вторую диаграмму (batch_size была выбрана произвольно.): введите описание изображения здесь
введите описание изображения здесь

Edit 2:

For people who have done Udacity's deep learning course and still confused about the time_step argument, look at the following discussion: https://discussions.udacity.com/t/rnn-lstm-use-implementation/163169

Update:

It turns out model.add(TimeDistributed(Dense(vocab_len))) was what I was looking for. Here is an example: https://github.com/sachinruk/ShakespeareBot

Update2:

Я обобщил большую часть своего понимания LSTMs здесь: https://www.youtube.com/watch ?v = ywinX5wgdEU

Переведено автоматически
Ответ 1

В дополнение к принятому ответу этот ответ показывает поведение keras и способы достижения каждого изображения.

Общее поведение Keras

Стандартная внутренняя обработка keras всегда много ко многим, как показано на следующем рисунке (где я использовал features=2, давление и температуру, просто в качестве примера):

ManyToMany

На этом изображении я увеличил количество шагов до 5, чтобы избежать путаницы с другими измерениями.

Для этого примера:


  • У нас есть N масляных баков

  • Мы потратили 5 часов на ежечасное измерение (временные шаги)

  • Мы измерили две особенности:

    • Давление P

    • Температура T


Затем наш входной массив должен иметь форму (N,5,2):

        [     Step1      Step2      Step3      Step4      Step5
Tank A: [[Pa1,Ta1], [Pa2,Ta2], [Pa3,Ta3], [Pa4,Ta4], [Pa5,Ta5]],
Tank B: [[Pb1,Tb1], [Pb2,Tb2], [Pb3,Tb3], [Pb4,Tb4], [Pb5,Tb5]],
....
Tank N: [[Pn1,Tn1], [Pn2,Tn2], [Pn3,Tn3], [Pn4,Tn4], [Pn5,Tn5]],
]

Входные данные для раздвижных окон

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

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

        [     Step1    Step2    Step3    Step4    Step5
Window A: [[P1,T1], [P2,T2], [P3,T3], [P4,T4], [P5,T5]],
Window B: [[P2,T2], [P3,T3], [P4,T4], [P5,T5], [P6,T6]],
Window C: [[P3,T3], [P4,T4], [P5,T5], [P6,T6], [P7,T7]],
....
]

Обратите внимание, что в этом случае у вас изначально есть только одна последовательность, но вы разделяете ее на множество последовательностей для создания окон.

Концепция "что такое последовательность" абстрактна. Важными частями являются:


  • у вас могут быть пакеты со многими отдельными последовательностями

  • что делает последовательности последовательностями, так это то, что они развиваются поэтапно (обычно с временными шагами)

Решение каждого случая с помощью "отдельных слоев"

Достижение стандарта "многие ко многим":

StandardManyToMany

Вы можете достичь многого с помощью простого уровня LSTM, используя return_sequences=True:

outputs = LSTM(units, return_sequences=True)(inputs)

#output_shape -> (batch_size, steps, units)

Соотношение многих к одному:

Используя точно такой же уровень, keras выполнит точно такую же внутреннюю предварительную обработку, но когда вы используете return_sequences=False (или просто игнорируете этот аргумент), keras автоматически отменит шаги, предшествующие последнему:

ManyToOne

outputs = LSTM(units)(inputs)

#output_shape -> (batch_size, units) --> steps were discarded, only the last was returned

Соотношение одного ко многим

Теперь это поддерживается не только слоями keras LSTM. Вам придется создать свою собственную стратегию для умножения шагов. Есть два хороших подхода:


  • Создайте постоянный многоступенчатый ввод, повторяя тензор

  • Используйте stateful=True для повторного получения выходных данных одного шага и использования их в качестве входных данных следующего шага (потребности output_features == input_features)

Один ко многим с повторяющимся вектором

Чтобы соответствовать стандартному поведению keras, нам нужны входные данные поэтапно, поэтому мы просто повторяем входные данные для нужной нам длины:

OneToManyRepeat

outputs = RepeatVector(steps)(inputs) #where inputs is (batch,features)
outputs = LSTM(units,return_sequences=True)(outputs)

#output_shape -> (batch_size, steps, units)

Понимание состояния = True

Теперь предлагается одно из возможных применений stateful=True (помимо того, что позволяет избежать загрузки данных, которые не могут сразу поместиться в память вашего компьютера)

Функция управления состоянием позволяет нам вводить "части" последовательностей поэтапно. Разница в том, что:


  • В stateful=False вторая партия содержит совершенно новые последовательности, независимые от первой партии

  • В stateful=True вторая партия продолжает первую партию, расширяя те же последовательности.

Это похоже на разделение последовательностей и в Windows, с этими двумя основными отличиями:


  • эти окна не накладываются друг на друга!!

  • stateful=True вы увидите, что эти окна соединены в единую длинную последовательность

В stateful=True каждый новый пакет будет интерпретироваться как продолжение предыдущего пакета (до тех пор, пока вы не вызовете model.reset_states()).


  • Последовательность 1 в пакете 2 продолжит последовательность 1 в пакете 1.

  • Последовательность 2 в пакете 2 продолжит последовательность 2 в пакете 1.

  • Последовательность n в пакете 2 продолжит последовательность n в пакете 1.

Пример входных данных, пакет 1 содержит шаги 1 и 2, пакет 2 содержит шаги с 3 по 5:

                   BATCH 1                           BATCH 2
[ Step1 Step2 | [ Step3 Step4 Step5
Tank A: [[Pa1,Ta1], [Pa2,Ta2], | [Pa3,Ta3], [Pa4,Ta4], [Pa5,Ta5]],
Tank B: [[Pb1,Tb1], [Pb2,Tb2], | [Pb3,Tb3], [Pb4,Tb4], [Pb5,Tb5]],
.... |
Tank N: [[Pn1,Tn1], [Pn2,Tn2], | [Pn3,Tn3], [Pn4,Tn4], [Pn5,Tn5]],
] ]

Обратите внимание на выравнивание ячеек в пакетах 1 и 2! Вот почему нам нужно shuffle=False (если, конечно, мы не используем только одну последовательность).

У вас может быть любое количество пакетов до бесконечности. (Для переменной длины в каждом пакете используйте input_shape=(None,features).

Один ко многим с отслеживанием состояния = True

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

Пожалуйста, обратите внимание, что поведение на рисунке не "вызвано" stateful=True. Мы принудительно применим это поведение в ручном цикле ниже. В этом примере stateful=True - это то, что "позволяет" нам останавливать последовательность, манипулировать тем, что мы хотим, и продолжать с того места, где мы остановились.

OneToManyStateful

Честно говоря, подход repeat, вероятно, является лучшим выбором для этого случая. Но поскольку мы изучаем stateful=True, это хороший пример. Лучший способ использовать это - следующий пример "многие ко многим".

Уровень:

outputs = LSTM(units=features, 
stateful=True,
return_sequences=True, #just to keep a nice output shape even with length 1
input_shape=(None,features))(inputs)
#units = features because we want to use the outputs as inputs
#None because we want variable length

#output_shape -> (batch_size, steps, units)

Теперь нам понадобится ручной цикл для предсказаний:

input_data = someDataWithShape((batch, 1, features))

#important, we're starting new sequences, not continuing old ones:
model.reset_states()

output_sequence = []
last_step = input_data
for i in steps_to_predict:

new_step = model.predict(last_step)
output_sequence.append(new_step)
last_step = new_step

#end of the sequences
model.reset_states()

Многие ко многим с отслеживанием состояния = True

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

Мы используем тот же метод, что и в приведенном выше разделе "один ко многим", с той разницей, что:


  • мы будем использовать саму последовательность в качестве целевых данных, на шаг впереди

  • мы знаем часть последовательности (поэтому мы отбрасываем эту часть результатов).

ManyToManyStateful

Уровень (такой же, как указано выше):

outputs = LSTM(units=features, 
stateful=True,
return_sequences=True,
input_shape=(None,features))(inputs)
#units = features because we want to use the outputs as inputs
#None because we want variable length

#output_shape -> (batch_size, steps, units)

Обучение:

Мы собираемся обучить нашу модель предсказывать следующий шаг последовательностей:

totalSequences = someSequencesShaped((batch, steps, features))
#batch size is usually 1 in these cases (often you have only one Tank in the example)

X = totalSequences[:,:-1] #the entire known sequence, except the last step
Y = totalSequences[:,1:] #one step ahead of X

#loop for resetting states at the start/end of the sequences:
for epoch in range(epochs):
model.reset_states()
model.train_on_batch(X,Y)

Прогнозирование:

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

model.reset_states() #starting a new sequence
predicted = model.predict(totalSequences)
firstNewStep = predicted[:,-1:] #the last step of the predictions is the first future step

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

output_sequence = [firstNewStep]
last_step = firstNewStep
for i in steps_to_predict:

new_step = model.predict(last_step)
output_sequence.append(new_step)
last_step = new_step

#end of the sequences
model.reset_states()

Этот подход был использован в этих ответах и файле:

Создание сложных конфигураций

Во всех приведенных выше примерах я показал поведение "одного слоя".

Вы, конечно, можете накладывать много слоев друг на друга, необязательно все по одному шаблону, и создавать свои собственные модели.

Одним из интересных примеров, который появлялся, является "автоэнкодер", который имеет кодировщик "многие к одному", за которым следует декодер "один ко многим":

Кодировщик:

inputs = Input((steps,features))

#a few many to many layers:
outputs = LSTM(hidden1,return_sequences=True)(inputs)
outputs = LSTM(hidden2,return_sequences=True)(outputs)

#many to one layer:
outputs = LSTM(hidden3)(outputs)

encoder = Model(inputs,outputs)

Декодер:

Использование метода "repeat";

inputs = Input((hidden3,))

#repeat to make one to many:
outputs = RepeatVector(steps)(inputs)

#a few many to many layers:
outputs = LSTM(hidden4,return_sequences=True)(outputs)

#last layer
outputs = LSTM(features,return_sequences=True)(outputs)

decoder = Model(inputs,outputs)

Автоэнкодер:

inputs = Input((steps,features))
outputs = encoder(inputs)
outputs = decoder(outputs)

autoencoder = Model(inputs,outputs)

Тренируйтесь с fit(X,X)

Дополнительные пояснения

Если вам нужны подробности о том, как вычисляются шаги в LSTMs, или подробности о stateful=True приведенных выше случаях, вы можете прочитать больше в этом ответе: Сомнения относительно "понимания Keras LSTMs"

Ответ 2

Прежде всего, вы выбираете отличные учебные пособия (1,2) для начала.

Что означает временной шаг: Time-steps==3 в X.форма (Описывающая форму данных) означает, что есть три розовых прямоугольника. Поскольку в Keras каждый шаг требует ввода, следовательно, количество зеленых полей обычно должно равняться количеству красных полей. Если только вы не взломаете структуру.

многие ко многим или многие к одному: В keras при инициализации есть return_sequences параметр LSTM or GRU или SimpleRNN. Когда return_sequences равно False (по умолчанию), то это много к одному, как показано на рисунке. Его возвращаемая форма - это (batch_size, hidden_unit_length), которые представляют последнее состояние. Когда return_sequences это True, то это многие ко многим. Его возвращаемая форма - это (batch_size, time_step, hidden_unit_length)

Становится ли релевантным аргумент features: аргумент Feature означает "Насколько велик ваш красный прямоугольник" или каков размер ввода на каждом шаге. Если вы хотите делать прогнозы на основе, скажем, 8 видов рыночной информации, то вы можете сгенерировать свои данные с помощью feature==8.

С отслеживанием состояния: вы можете посмотреть исходный код. При инициализации состояния, если stateful==True, то в качестве начального состояния будет использоваться состояние из последнего обучения, в противном случае оно сгенерирует новое состояние. Я еще не включил stateful. Однако я не согласен с тем, что batch_size может быть только 1, когда stateful==True.

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

Ответ 3

Когда у вас есть return_sequences в вашем последнем слое RNN, вы не можете использовать простой плотный слой, вместо этого используйте TimeDistributed .

Вот пример фрагмента кода, который может помочь другим.

words = keras.layers.Input(batch_shape=(None, self.maxSequenceLength), name = "input")

# Build a matrix of size vocabularySize x EmbeddingDimension
# where each row corresponds to a "word embedding" vector.
# This layer will convert replace each word-id with a word-vector of size Embedding Dimension.
embeddings = keras.layers.embeddings.Embedding(self.vocabularySize, self.EmbeddingDimension,
name = "embeddings")(words)
# Pass the word-vectors to the LSTM layer.
# We are setting the hidden-state size to 512.
# The output will be batchSize x maxSequenceLength x hiddenStateSize
hiddenStates = keras.layers.GRU(512, return_sequences = True,
input_shape=(self.maxSequenceLength,
self.EmbeddingDimension),
name = "rnn")(embeddings)
hiddenStates2 = keras.layers.GRU(128, return_sequences = True,
input_shape=(self.maxSequenceLength, self.EmbeddingDimension),
name = "rnn2")(hiddenStates)

denseOutput = TimeDistributed(keras.layers.Dense(self.vocabularySize),
name = "linear")(hiddenStates2)
predictions = TimeDistributed(keras.layers.Activation("softmax"),
name = "softmax")(denseOutput)

# Build the computational graph by specifying the input, and output of the network.
model = keras.models.Model(input = words, output = predictions)
# model.compile(loss='kullback_leibler_divergence', \
model.compile(loss='sparse_categorical_crossentropy', \
optimizer = keras.optimizers.Adam(lr=0.009, \
beta_1=0.9,\
beta_2=0.999, \
epsilon=None, \
decay=0.01, \
amsgrad=False))
Ответ 4

Обратитесь к этому блогу за более подробной информацией об анимированных RNN, LSTM и GRU.

Рисунок ниже дает вам лучшее представление о LSTM. Это ячейка LSTM. Этот рисунок

Как вы можете видеть, X имеет 3 features (зеленые кружочки), поэтому вход в эту ячейку является вектором размерности 3, а скрытое состояние имеет 2 units (красные кружочки), поэтому выход этой ячейки (а также состояния ячейки) является вектором размерности 2.

Пример одного слоя LSTM с 3 временными шагами (3 ячейки LSTM) показан на рисунке ниже:

Это изображение

** Модель может иметь несколько уровней LSTM.

Теперь я снова использую пример Даниэля Меллера для лучшего понимания: у нас есть 10 масляных резервуаров. Для каждого из них мы измеряем 2 характеристики: температуру, давление каждые час по 5 раз. теперь параметры:


  • batch_size = количество выборок, используемых за один прямой / обратный проход (по умолчанию = 32) --> например, если у вас 1000 выборок и вы устанавливаете batch_size равным 100, то модели потребуется 10 итераций, чтобы передать все выборки один раз по сети (1 эпоха). Чем больше размер пакета, тем больше места в памяти вам понадобится. Поскольку количество выборок в этом примере невелико, мы считаем batch_size равным all of samples = 10

  • временные интервалы = 5

  • возможности = 2

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

  • input_shape = (batch_size, временные интервалы, функции) = (10,5,2)

  • output_shape:

    • (batch_size, временные интервалы, единицы измерения), если return_sequences=True

    • (batch_size, единицы измерения), если return_sequences=False



python keras