PyTorch LSTMCell – Формы входного, скрытого состояния, состояния ячейки и выхода

PyTorch LSTMCell - вход, скрытое состояние, состояние ячейки и выход

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

В этой статье мы используем следующую терминологию:

batch = количество многомерных временных рядов в одной партии данных

input_features = количество одномерных временных рядов в одном многомерном временном ряде

time_steps = количество временных шагов в каждом многомерном временном ряде

Партия многомерных временных рядов, которая подается на вход LSTMCell, должна быть тензором формы (time_steps, batch, input_features)

Следующая картинка поможет понять эту форму для входных данных:

Входные данные в LSTMCell подаются специфическим образом. В основном, весь многомерный временной ряд не подается на вход в виде временного ряда. Вектор x_t, который является вектором в определенный момент времени в МВР, подается на вход LSTMCell. Для обработки вектора на одном временном шаге LSTMCell требуется один скрытый вектор состояния и один вектор состояния ячейки. Они представлены соответственно как h_0 и c_0, . Выходом LSTMCell являются скрытое состояние и состояние ячейки, которые будут использоваться при обработке вектора на следующем временном шаге x_t+1. Эти скрытые и состояния ячейки обозначаются как h_1 и c_1 соответственно. LSTMCell вызывается в цикле, передавая h_1 и c_1 в качестве h_0 и c_0 для последующих временных шагов. Этот концепт проиллюстрирован в следующем фрагменте кода.

При инициализации объекта LSTMCell аргументы input_features и hidden_size должны быть указаны.

Здесь,

input_features = количество одномерных временных рядов в одном многомерном временном ряде (тот же самый размер, что и input_features, указанный выше)

hidden_size = количество размерностей вектора скрытого состояния. Такой же размер должен использоваться и для размерности вектора состояния ячейки.

Начальные значения скрытого состояния и состояния ячейки в LSTMCell должны быть созданы с формой (batch, hidden_size). Здесь batch должен совпадать с batch во входном многомерном временном ряде. Это означает, что для каждого МВР во входной партии данных есть соответствующее скрытое состояние и состояние ячейки.

Начальное скрытое состояние и начальное состояние ячейки временного ряда должны быть поданы на вход для прямого прохождения через LSTMCell.

Прямое прохождение специфического вектора временного шага входного МВР, начального скрытого состояния и начального состояния ячейки через объект LSTMCell должно быть в формате:

LSTMCell(x_t, (h_0, c_0))

Следующая картинка поможет понять эту форму для скрытого состояния и состояния ячейки:

Приведен ниже пример кода. Пояснение к коду следует после него.

import torchimport torch.nn as nn lstm_0 = nn.LSTMCell(10, 20) # (input_features, hidden_size)inp = torch.randn(7, 3, 10) # (time_steps, batch, input_features) -> входной временной рядhx = torch.randn(3, 20) # (batch, hidden_size) -> начальное значение скрытого состоянияcx = torch.randn(3, 20) # (batch, hidden_size) -> начальное значение состояния ячейкиfor i in range(inp.size()[0]):     hx, cx = lstm_0(inp[i], (hx, cx)) # прямое прохождение входа через LSTMCell     output.append(hx)output = torch.stack(output, dim=0)

Вызов nn.LSTMCell() вызовет магический метод __init__() и создаст объект LSTMCell. В приведенном выше коде этот объект ссылается как lstm_0.

В общем случае RNN (LSTM является типом RNN) каждый time_step временного ряда должен быть передан в RNN один за другим в последовательном порядке для обработки RNN.

Для обработки многомерных временных рядов пакетом с использованием LSTMCell каждый time_step во всех MTS в пакете должен быть последовательно передан через LSTMCell.

Это достигается с помощью цикла for. Цикл перебирает каждый time_step MTS (первое измерение inp.size() – это количество time_step) и последовательно передает вектор time_step в каждом MTS в пакете параллельно в LSTMCell. Одним вызовом LSTMCell обрабатывается только вектор time_step в MTS.

Результат вызова lstm_0(inp[i], (hx, cx)) внутри цикла for – это создание следующего скрытого состояния и состояния ячейки для каждого time_step. Выходное скрытое состояние (hx) и состояние ячейки (cx) рекурсивно вычисляются на основе предыдущего hx и cx.

Выход: (h_1, c_1)

Этот вывод вычисляется для каждого временного ряда на всем пакете. Форма вывода – (batch, hidden_size).

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

Эти вычисленные hx, созданные для каждого time_step в каждом MTS во входном пакете, добавляются в выходной тензор, который в свою очередь стекается вдоль оси 0. Следовательно, форма вывода – (time_steps, batch, hidden_size).

Для приведенного выше примера кода, следующий вывод:

tensor([[[ 0.0087,  0.0365, -0.1233, -0.2641,  0.2908, -0.5075,  0.2587,           0.1057, -0.2079, -0.2327,  0.1390,  0.1023, -0.1186,  0.3302,           0.1139,  0.1591, -0.0264, -0.0499,  0.0153,  0.3881],         [ 0.3585, -0.4133, -0.0259,  0.2490, -0.0936, -0.2756, -0.1941,          -0.0967,  0.1501, -0.0334, -0.1904, -0.3945, -0.1036, -0.2091,           0.0545,  0.1937, -0.2338,  0.0382,  0.2344,  0.1169],         [-0.2532,  0.0745, -0.0329,  0.0971, -0.1057, -0.0383,  0.1328,           0.1263, -0.1422,  0.0351,  0.3957, -0.4115, -0.2951, -0.5560,           0.1941,  0.0100,  0.3028, -0.1803,  0.0028,  0.3210]],        [[ 0.1105, -0.1295, -0.0636, -0.2510,  0.1923, -0.2457,  0.2401,           0.1379, -0.1373, -0.2451,  0.0387,  0.1004, -0.0580,  0.3430,          -0.0149,  0.1827, -0.0229, -0.2061,  0.1718,  0.3146],         [ 0.2741, -0.2413, -0.1310,  0.1206,  0.0379, -0.1738, -0.0568,           0.0417,  0.0756,  0.1020,  0.0262, -0.3280, -0.0352, -0.1713,           0.1065,  0.0458, -0.3404, -0.0795,  0.0586,  0.0026],         [-0.0112,  0.0883, -0.1755, -0.0438,  0.0193,  0.0151,  0.1010,           0.1614, -0.0524,  0.0970,  0.2092, -0.3518, -0.0715, -0.3941,           0.1422,  0.1164,  0.2946, -0.1919,  0.1493,  0.1203]]],       grad_fn=<StackBackward0>)

Для каждого временного шага входных данных (time_steps входных данных = 2) создается массив (создается 2 массива). Каждый из этих массивов содержит массивы для каждого временного ряда многомерных временных рядов в пакете (batch_size = 3). Для каждого временного шага во временном ряду получаем вектор скрытого состояния размерности hidden_size (здесь hidden_size = 20). Таким образом, для каждого временного шага значение временного ряда представлено вектором. Этот вектор в момент времени отображается в 20-мерный вектор скрытого состояния.

Следующая картинка дает представление об этой форме для пакета многомерных временных рядов на выходе:

Если вывести переменную hx в коде выше для одного временного шага (для одной итерации в цикле), получим следующий вывод:

tensor([[ 0.1034, -0.0192, -0.0581, -0.0772, -0.1578, -0.1450,  0.0377, -0.0013,         -0.2641, -0.1821,  0.0431, -0.2262,  0.3025,  0.0952,  0.4113, -0.2968,         -0.4377,  0.0794,  0.3683, -0.0021],        [ 0.0309,  0.3957,  0.2143,  0.1020,  0.0640, -0.0628,  0.4390,  0.1818,          0.0373,  0.2497, -0.1768, -0.2038, -0.1249, -0.2995,  0.0786, -0.0522,         -0.0080, -0.3095, -0.0815,  0.2874],        [-0.2458,  0.1622,  0.2564, -0.3136,  0.0631,  0.0643,  0.4036,  0.3293,         -0.1806, -0.0251, -0.4505, -0.1437, -0.1718, -0.0479, -0.1116, -0.1065,         -0.3289,  0.1137,  0.1160,  0.1227]], grad_fn=<MulBackward0>)

Он имеет один массив, соответствующий одному временному шагу. Внутри этого временного шага находятся 3 массива, соответствующие 3 временным рядам в пакете. Каждый из этих массивов, соответствующих одному временному ряду, имеет 20-мерный вектор скрытого состояния. Таким образом, на выходе в одном временном шаге получается (batch, hidden_size).

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

Аргументы инициализации nn.LSTMCell следующие:

input_size

hidden_size

bias

device

dtype

Он не имеет аргумента num_layers. Поскольку это одна ячейка, она не может иметь несколько слоев LSTM.