OutputProjectionWrapper против полностью подключенного слоя поверх RNN

#tensorflow #machine-learning #deep-learning #recurrent-neural-network

#tensorflow #машинное обучение #глубокое обучение #рекуррентная нейронная сеть

Вопрос:

Я читаю 14-ю главу практического машинного обучения с помощью Scikit-Learn и TensorFlow. В нем говорится:

Хотя использование OutputProjectionWrapper является самым простым решением для уменьшения размерности выходных последовательностей RNN всего до одного значения за шаг по времени (для каждого экземпляра), это не самое эффективное. Существует более сложное, но более эффективное решение: вы можете изменить форму выходных данных RNN, а затем применить один полностью подключенный слой с соответствующим размером выходных данных. […] Это может обеспечить значительное повышение скорости, поскольку на каждом временном шаге используется только один полностью подключенный слой вместо одного.

Для меня это не имеет смысла. В случае OutputProjectionWrapper нам нужно выполнить 2 операции за временной шаг:

  1. Вычислите новое скрытое состояние на основе предыдущего скрытого состояния и входных данных.
  2. Вычисляйте выходные данные, применяя плотный слой к вычисляемому скрытому состоянию.

Конечно, когда мы используем обычный BasicRNNCell плотный слой поверх, нам нужно выполнять только одну операцию на каждом временном шаге (первом), но затем нам нужно передавать каждый выходной тензор через наш плотный слой. Итак, нам нужно выполнить одинаковое количество операций в обоих случаях.

Кроме того, я не могу понять следующую часть:

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

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

Я буду очень благодарен, если кто-нибудь сможет объяснить разницу между этими подходами.

UPD Вот псевдокод для вопроса. Я что-то упускаю?

 # 2 time steps, x1 and x2 - inputs, h1 and h2 - hidden states, y1 and y2 - outputs.

# OutputProjectionWrapper
h1 = calc_hidden(x1, 0)
y1 = dense(h1)
h2 = calc_hidden(x2, h1)
y2 = dense(h2)

# BasicRNNCell   dense layer on top of all time steps
h1 = calc_hidden(x1, 0)
y1 = h1
h2 = calc_hidden(x2, h1)
y2 = h2

y1 = dense(y1)
y2 = dense(y2)
  

UPD 2 Я создал два небольших фрагмента кода (один с OutputProjectionWrapper , а другой с BasicRNNCell и tf.layers.dense сверху) — оба создали 14 переменных одинаковой формы. Таким образом, между этими подходами определенно нет различий в памяти.

Ответ №1:

Я предполагаю, что применение 1 слоя к тензору формы (x, n) происходит быстрее, чем применение того же слоя к тензору формы (x) n раз из-за оптимизации умножения матрицы.

Ответ №2:

На этой веб-странице есть подробное объяснение самого вашего вопроса.

https://www.oreilly.com/library/view/neural-networks-and/9781492037354/ch04.html

Вот выдержка из вышеупомянутой страницы. Надеюсь, это поможет.

Хотя использование OutputProjectionWrapper является самым простым решением для уменьшения размерности выходных последовательностей RNN всего до одного значения за шаг по времени (для каждого экземпляра), это не самое эффективное. Существует более сложное, но более эффективное решение: вы можете изменить выходные данные RNN с [batch_size, n_steps, n_neurons] на [batch_size * n_steps, n_neurons], затем применить один полностью подключенный слой с соответствующим размером выходных данных (в нашем случае всего 1), что приведет к выходному тензору формы [batch_size * n_steps, n_outputs ], а затем измените этот тензор на [batch_size, n_steps, n_outputs]. Эти операции представлены на рисунке 4-10.

Комментарии:

1. Я полагаю, что это именно тот пост, для которого OP попросил разъяснений. Повторение того же объяснения, похоже, не оказывает никакой помощи.