Что значит развернуть RNN динамически?

Что значит "развернуть RNN динамически". Я видел это специально упомянутое в исходном коде Tensorflow, но я ищу концептуальное объяснение, которое распространяется на RNN в целом.

В методе tenorflow rnn он документирован:

Если предоставляется вектор sequence_length, динамический расчет выполнено. Этот метод расчета не вычисляет шаги RNN мимо максимальной длины последовательности мини-бара (таким образом, сохранение вычислительное время),

Но в методе dynamic_rnn он упоминает:

Параметр sequence_length является необязательным и используется для состояния копирования и вывода нулевого выхода, когда прошло через элемент пакетного элемента длина последовательности. Так что это больше для правильности, чем производительность, в отличие от rnn().

Значит ли это, что rnn более эффективен для последовательностей переменной длины? Какова концептуальная разница между dynamic_rnn и rnn?

Ответы

Ответ 1

Из документации я понимаю, что они говорят, что параметр sequence_length в методе rnn влияет на производительность, потому что когда он установлен, он будет выполнять динамическое вычисление, и он остановится раньше.

Например, если самая большая входная последовательность rnn имеет длину 50, если другие последовательности короче, то лучше будет установить sequence_length для каждой последовательности, так что вычисление для каждой последовательности остановится, когда последовательность заканчивается и не будет вычислять нулевые пробелы до достижения 50 временных меток. Однако, если sequence_length не предоставляется, он будет рассматривать каждую последовательность с одинаковой длиной, поэтому она будет обрабатывать нули, используемые для заполнения в качестве обычных элементов в последовательности.

Это не означает, что dynamic_rnn менее эффективен, в документации говорится, что параметр sequence_length не повлияет на производительность, потому что вычисление уже является динамическим.

Также в соответствии с этот пост о RNN в Tensorflow:

Внутренне, tf.nn.rnn создает развернутый график для фиксированной длины RNN. Это означает, что если вы вызываете tf.nn.rnn с входами, имеющими 200 временных шагов, вы создаете статический график с 200 шагами RNN. Во-первых, создание графика происходит медленно. Во-вторых, вы не можете передать более длинные последовательности ( > 200), чем вы первоначально указали.

tf.nn.dynamic_rnn решает это. Он использует цикл tf.While для динамического построения графика при его выполнении. Это означает, что создание графика происходит быстрее, и вы можете комбинировать партии переменного размера. Как насчет производительности? Вы можете думать, что статический rnn быстрее, чем его динамический аналог, потому что он предварительно создает граф. По моему опыту это не так.

Короче говоря, просто используйте tf.nn.dynamic_rnn. Нет никакой пользы для tf.nn.rnn, и я бы не удивился, если бы он был устаревшим в будущем.

dynamic_rnn еще быстрее (или равно), поэтому он предлагает использовать dynamic_rnn в любом случае.

Ответ 2

Ячейка LSTM (или GRU) является базой обоих.

Представьте себе RNN как сложную глубокую сеть с

  • распределение весов (= матрицы весов и смещений одинаковы во всех слоях)
  • вход "со стороны" в каждый слой Выходы
  • интерпретируются на более высоких уровнях (например, декодере), по одному в каждом слое

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

Теперь классический способ построения этого состоит в том, чтобы группировать пары ввода-вывода в фиксированные максимальные длины (то есть model_with_buckets()). DynRNN ломается с этим ограничением и приспосабливается к фактическим длинам последовательности.

Так что никакого реального компромисса здесь нет. Кроме того, что вам придется переписать старый код для адаптации.