Понимание формы сигнала LSTM Tensorflow

У меня есть набор данных X, который состоит из N = 4000 образцов, каждый образец состоит из d = 2 признаков (непрерывных значений), охватывающих назад t = 10 раз шаги. У меня также есть соответствующие "метки" каждого образца, которые также являются непрерывными значениями, на этапе 11.

В настоящий момент мой набор данных имеет форму X: [4000,20], Y: [4000].

Я хочу обучить LSTM с помощью TensorFlow, чтобы предсказать значение Y (регрессия), учитывая 10 предыдущих входов d-функций, но мне сложно выполнять это в TensorFlow.

Основная проблема, с которой я сейчас сталкиваюсь, заключается в понимании того, как TensorFlow ожидает, что ввод будет отформатирован. Я видел различные примеры, такие как this, но эти примеры относятся к одной большой строке непрерывных временных рядов. Мои данные - разные образцы, каждый из которых независимый временной ряд.

Ответ 1

Документация tf.nn.dynamic_rnn гласит:

inputs: Входы RNN. Если time_major == False (по умолчанию), это должен быть Тензор формы: [batch_size, max_time, ...] или вложенный кортеж таких элементов.

В вашем случае это означает, что вход должен иметь форму [batch_size, 10, 2]. Вместо того, чтобы тренироваться во всех 4000 последовательностях, вы должны использовать только batch_size многие из них на каждой итерации обучения. Что-то вроде следующего должно работать (добавлено изменение для ясности):

batch_size = 32
# batch_size sequences of length 10 with 2 values for each timestep
input = get_batch(X, batch_size).reshape([batch_size, 10, 2])
# Create LSTM cell with state size 256. Could also use GRUCell, ...
# Note: state_is_tuple=False is deprecated;
# the option might be completely removed in the future
cell = tf.nn.rnn_cell.LSTMCell(256, state_is_tuple=True)
outputs, state = tf.nn.dynamic_rnn(cell,
                                   input,
                                   sequence_length=[10]*batch_size,
                                   dtype=tf.float32)

Из документации, outputs будет иметь форму [batch_size, 10, 256], то есть один 256-вывод для каждого временного времени. state будет кортежем форм [batch_size, 256]. Вы можете предсказать свое окончательное значение, по одному для каждой последовательности, из этого:

predictions = tf.contrib.layers.fully_connected(state.h,
                                                num_outputs=1,
                                                activation_fn=None)
loss = get_loss(get_batch(Y).reshape([batch_size, 1]), predictions)

Число 256 в формах outputs и state определяется cell.output_size соответственно. cell.state_size. При создании LSTMCell, как указано выше, они одинаковы. Также см. документацию LSTMCell.

Ответ 2

(Этот ответ "устраняет" проблему, когда прямой np.reshape() не организует конечный массив так, как мы этого хотим. Если мы хотим напрямую изменить форму в 3D, np.reshape сделает это, но следите за окончательной организацией вход).

В моей личной попытке окончательно решить эту проблему подачи входной формы для RNN и больше не путать, я дам свое "личное" объяснение этого.

В моем случае (и я думаю, что многие другие могут иметь эту схему организации в своих матрицах возможностей), большинство блогов за пределами "не помогают". Давайте попробуем, как преобразовать 2D-матрицу объектов в 3D-матрицу для RNN.

Допустим, у нас есть этот тип организации в нашей матрице объектов: у нас есть 5 наблюдений (т.е. строк - для соглашения, я думаю, что это самый логичный термин для использования), и в каждой строке у нас есть 2 функции для КАЖДОГО временного шага (и у нас есть 2 временные шаги), вот так:

(df, чтобы лучше понять мои слова)

In [1]: import numpy as np                                                           

In [2]: arr = np.random.randint(0,10,20).reshape((5,4))                              

In [3]: arr                                                                          
Out[3]: 
array([[3, 7, 4, 4],
       [7, 0, 6, 0],
       [2, 0, 2, 4],
       [3, 9, 3, 4],
       [1, 2, 3, 0]])

In [4]: import pandas as pd                                                          

In [5]: df = pd.DataFrame(arr, columns=['f1_t1', 'f2_t1', 'f1_t2', 'f2_t2'])         

In [6]: df                                                                           
Out[6]: 
   f1_t1  f2_t1  f1_t2  f2_t2
0      3      7      4      4
1      7      0      6      0
2      2      0      2      4
3      3      9      3      4
4      1      2      3      0

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

На самом деле, в том 3D-входе, который нам нужно сделать, у нас еще есть 5 наблюдений. Дело в том, что нам нужно расположить их по-разному: RNN возьмет первую строку (или указанный пакет - но мы будем здесь все упрощать) первого массива (т.е. timestep1) и первую строку второго сложенного массива (т.е. timestep2). Затем второй ряд... до последнего (пятый в нашем примере). Таким образом, в каждом ряду каждого временного шага нам, разумеется, нужно разделить две функции на разные массивы, каждый из которых соответствует его временному шагу. Давайте посмотрим на это с помощью цифр.

Я сделаю два массива для облегчения понимания. Помните, что из-за нашей организационной схемы в df вы, возможно, заметили, что нам нужно взять первые два столбца (т.е. функции 1 и 2 для временного шага 1) в качестве ПЕРВОГО Массива стека и последних двух столбцов, то есть 3-й и 4-й, как наш ВТОРОЙ массив из стека, так что все, наконец, имеет смысл.

In [7]: arrStack1 = arr[:,0:2]                                                       

In [8]: arrStack1                                                                    
Out[8]: 
array([[3, 7],
       [7, 0],
       [2, 0],
       [3, 9],
       [1, 2]])

In [9]: arrStack2 = arr[:,2:4]                                                       

In [10]: arrStack2                                                                   
Out[10]: 
array([[4, 4],
       [6, 0],
       [2, 4],
       [3, 4],
       [3, 0]])

Наконец, единственное, что нам нужно сделать, это сложить оба массива ("один за другим"), как если бы они были частью одной и той же конечной структуры:

In [11]: arrfinal3D = np.stack([arrStack1, arrStack2])                               

In [12]: arrfinal3D                                                                  
Out[12]: 
array([[[3, 7],
        [7, 0],
        [2, 0],
        [3, 9],
        [1, 2]],

       [[4, 4],
        [6, 0],
        [2, 4],
        [3, 4],
        [3, 0]]])

In [13]: arrfinal3D.shape                                                            
Out[13]: (2, 5, 2)

Вот и все: у нас есть наша матрица признаков, готовая для подачи в ячейку RNN, с учетом нашей организации матрицы 2D-объектов.

(Для одного лайнера относительно всего этого вы можете использовать:

In [14]: arrfinal3D_1 = np.stack([arr[:,0:2], arr[:,2:4]])                           

In [15]: arrfinal3D_1                                                                
Out[15]: 
array([[[3, 7],
        [7, 0],
        [2, 0],
        [3, 9],
        [1, 2]],

       [[4, 4],
        [6, 0],
        [2, 4],
        [3, 4],
        [3, 0]]])

Надеюсь это поможет!