Как эффективно обновить переменную среза Keras? - PullRequest
3 голосов
/ 06 февраля 2020

Предположим, у нас есть x = K.zeros((4, 6)), и мы будем sh, чтобы добавить 1 к строке 0: x[0] += 1. Переменная создается с помощью Layer add_weight() w / training=False, поэтому она не обновляется с помощью backprop. Какой самый эффективный быстрый способ сделать это?

Релевантно Git


Контекст : я реализую периодическую нормализацию партии с переменными moving_mean и moving_variance отличается для каждого временного шага в RNN - каждый, таким образом, имеет форму (units, timesteps). Цель состоит в том, чтобы обновить один timesteps срез за шаг с помощью K.moving_average_update(). Один из подходов заключается в следующем:

import keras.backend as K
units, timesteps = 4, 6
x = K.zeros((units, timesteps), dtype='float32', name='x')

x_new = x[:units, 0].assign(K.ones((units,), dtype='float32'))  # dummy example
K.set_value(x, K.get_value(x_new))
print(K.get_value(x))
[[1. 0. 0. 0. 0. 0.]
 [1. 0. 0. 0. 0. 0.]
 [1. 0. 0. 0. 0. 0.]
 [1. 0. 0. 0. 0. 0.]]

Выглядит хорошо - за исключением того, что новая копия из x была создана. На практике у нас может быть timesteps > 100 (например, 120), поэтому мы создаем массив в 120 раз больше, чем нужно, в 120 раз (1 / шаг), что делает его операцией O(timesteps**2) - в отличие от обычного среза, O(timesteps). При проверке Backend Keras все его методы update_ включают копирование исходного массива.

Есть ли что-нибудь более эффективное в Keras? Если нет, то в TensorFlow?


Примечание : мне известно об альтернативе «добавить в список *, затем назначить с помощью массива на последнем шаге», которая равна намного эффективнее, но мы можем добиться большего успеха - по крайней мере, с точки зрения «традиционных» массивов (* или заполнение нулевого массива). Правда, есть и фактор GPU, который лучше работает в пакетных назначениях, чем итеративный, но я не могу сравнительно эффективно сравнить его с тем, что я описал.

1 Ответ

0 голосов
/ 19 февраля 2020

Выяснилось прямое обновление среза:

x_slice = x[4:5]
x_slice.assign(math_ops.sub(x_slice, some_tensor))

x_slice, кажется, хорошо ссылается на исходный тензорный массив; по какой-то причине assign_sub терпит неудачу в этом; см. уточняющий комментарий .

...