Spec-Zone.ru › TensorFlow 2.3

tf.while_loop

Просмотреть исходный код на GitHub

Повторять body до тех пор, пока условие cond истинно. (устаревшие аргументы)

tf.while_loop(
    cond, body, loop_vars, shape_invariants=None, parallel_iterations=10,
    back_prop=True, swap_memory=False, maximum_iterations=None, name=None
)
Предупреждение: НЕКОТОРЫЕ ЗНАЧЕНИЯ АРГУМЕНТОВ УСТАРЕЛИ: (back_prop=False). Они будут удалены в будущей версии. Инструкции по обновлению: устарел back_prop=False. Рассмотрите использование tf.stop_gradient вместо него. Вместо: results = tf.while_loop(c, b, vars, back_prop=False) Используйте: results = tf.nest.map_structure(tf.stop_gradient, tf.while_loop(c, b, vars))

cond — это вызываемый объект, возвращающий скалярный булевый тензор. body — это вызываемый объект, возвращающий (возможно, вложенную) кортеж, namedtuple или список тензоров с той же арностью (длиной и структурой) и типами, что и loop_vars. loop_vars — это (возможно, вложенная) кортеж, namedtuple или список тензоров, который передаётся как аргумент в cond и body. cond и body оба принимают столько аргументов, сколько loop_vars.

Помимо обычных тензоров или IndexedSlices, тело может принимать и возвращать объекты TensorArray. Потоки объектов TensorArray будут должным образом передаваться между циклами и при вычислении градиентов.

Обратите внимание, что while_loop вызывает cond и body *точно один раз* (внутри вызова while_loop, и не вызывается вообще во время Session.run()). while_loop связывает фрагменты графа, созданные во время вызовов cond и body, с дополнительными узлами графа, чтобы создать поток графа, который повторяет body до тех пор, пока cond не вернёт false.

Для корректности, tf.while_loop() строго проверяет инварианты формы для переменных цикла. Инвариант формы — это (возможно, частичная) форма, которая не меняется в течение итераций цикла. Будет выведено сообщение об ошибке, если форма переменной цикла после итерации окажется более общей или несовместимой с её инвариантом формы. Например, форма [11, None] более общая, чем форма [11, 17], а [11, 21] несовместима с [11, 17]. По умолчанию (если аргумент shape_invariants не указан), предполагается, что начальная форма каждого тензора в loop_vars одинакова на каждой итерации. Аргумент shape_invariants позволяет вызывающему объекту указать менее специфичный инвариант формы для каждой переменной цикла, что необходимо, если форма меняется между итерациями. Функцию tf.Tensor.set_shape также можно использовать в функции body для указания определённой формы выходной переменной цикла. Инварианты формы для SparseTensor и IndexedSlices обрабатываются следующим образом:

a) Если переменная цикла — SparseTensor, инвариант формы должен быть TensorShape([r]), где r — ранг плотного тензора, представленного разреженным тензором. Это означает, что формы трёх тензоров SparseTensor равны ([None], [None, r], [r]). ПРИМЕЧАНИЕ: Здесь инвариант формы — это форма свойства SparseTensor.dense_shape. Он должен иметь форму вектора.

b) Если переменная цикла — IndexedSlices, инвариант формы должен быть инвариантом формы тензора значений IndexedSlices. Это означает, что формы трёх тензоров IndexedSlices равны (форма, [форма[0]], [форма.ndims]).

while_loop реализует нестрогую семантику, позволяющую запускать несколько итераций параллельно. Максимальное число параллельных итераций можно контролировать с помощью parallel_iterations, что даёт пользователям некоторый контроль над потреблением памяти и порядком выполнения. Для корректных программ while_loop должен возвращать тот же результат для любого parallel_iterations > 0.

Для обучения TensorFlow хранит тензоры, которые генерируются в прямом выводе и необходимы для обратного распространения. Эти тензоры являются основным источником потребления памяти и часто вызывают ошибки OOM при обучении на графических процессорах. Когда флаг swap_memory равен true, мы переключаем эти тензоры с графического процессора на центральный процессор. Это, например, позволяет обучать модели RNN с очень длинными последовательностями и большими пакетами.

Args
cond Вызываемый объект, представляющий условие завершения цикла.
body Вызываемый объект, представляющий тело цикла.
loop_vars (Возможно, вложенная) кортеж, namedtuple или список numpy массивов, Tensor, и TensorArray объектов.
shape_invariants Инварианты формы для переменных цикла.
parallel_iterations Количество итераций, разрешённых для выполнения параллельно. Должно быть положительным целым числом.
back_prop (необязательно) Устарел. False отключает поддержку обратного распространения. Вместо этого предпочтительнее использовать tf.stop_gradient.
swap_memory Включить ли обмен памятью между GPU и CPU для этого цикла.
maximum_iterations Необязательное максимальное количество итераций цикла while для выполнения. Если указано, результат cond перемножается с дополнительным условием, гарантирующим, что количество выполненных итераций не превышает maximum_iterations.
name Необязательный префикс имени для возвращаемых тензоров.
Returns
Выходные тензоры для переменных цикла после цикла. Результат имеет ту же структуру, что и loop_vars.
Raises
TypeError если cond или body не вызываемый объект.
ValueError если loop_vars пусто.

Пример:

i = tf.constant(0)
c = lambda i: tf.less(i, 10)
b = lambda i: (tf.add(i, 1), )
r = tf.while_loop(c, b, [i])

Пример с вложенностью и namedtuple:

import collections
Pair = collections.namedtuple('Pair', 'j, k')
ijk_0 = (tf.constant(0), Pair(tf.constant(1), tf.constant(2)))
c = lambda i, p: i < 10
b = lambda i, p: (i + 1, Pair((p.j + p.k), (p.j - p.k)))
ijk_final = tf.while_loop(c, b, ijk_0)

Пример использования shape_invariants:

i0 = tf.constant(0)
m0 = tf.ones([2, 2])
c = lambda i, m: i < 10
b = lambda i, m: [i+1, tf.concat([m, m], axis=0)]
tf.while_loop(
    c, b, loop_vars=[i0, m0],
    shape_invariants=[i0.get_shape(), tf.TensorShape([None, 2])])

Пример, демонстрирующий нестрогую семантику: В следующем примере конечное значение счётчика i не зависит от x. Таким образом, while_loop может увеличивать счётчик параллельно с обновлениями x. Однако, поскольку значение счётчика цикла на одной итерации зависит от значения на предыдущей итерации, сам счётчик цикла не может увеличиваться параллельно. Следовательно, если нам нужно только конечное значение счётчика (которое мы выводим на строке print(sess.run(i))), то x никогда не будет увеличиваться, а счётчик будет обновляться на одном потоке. И наоборот, если нам нужно значение результата (которое мы выводим на строке print(sess.run(out).shape)), то счётчик может быть увеличен на собственном потоке, в то время как x может быть увеличен параллельно в отдельном потоке. В крайнем случае, можно представить, что поток, увеличивающий счётчик, выполнится до завершения, прежде чем x будет увеличен хотя бы один раз. Единственное, что никогда не произойдёт, это то, что поток, обновляющий x, не сможет обогнать поток счётчика, поскольку поток, увеличивающий x, зависит от значения счётчика.

import tensorflow as tf

n = 10000
x = tf.constant(list(range(n)))
c = lambda i, x: i < n
b = lambda i, x: (tf.compat.v1.Print(i + 1, [i]), tf.compat.v1.Print(x + 1,
[i], "x:"))
i, out = tf.while_loop(c, b, (0, x))
with tf.compat.v1.Session() as sess:
    print(sess.run(i))  # prints [0] ... [9999]

    # The following line may increment the counter and x in parallel.
    # The counter thread may get ahead of the other thread, but not the
    # other way around. So you may see things like
    # [9996] x:[9987]
    # meaning that the counter thread is on iteration 9996,
    # while the other thread is on iteration 9987
    print(sess.run(out).shape)

© 2020 The TensorFlow Authors. All rights reserved.
Licensed under the Creative Commons Attribution License 3.0.
Code samples licensed under the Apache 2.0 License.
https://www.tensorflow.org/versions/r2.3/api_docs/python/tf/while_loop

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API