Подтвердить что ты не робот

"заморозить" некоторые переменные/области действия в тензорном потоке: stop_gradient vs пропускает переменные для минимизации

Я пытаюсь реализовать Adversarial NN, который требует "заморозить" одну или другую часть графика во время чередующихся миниатюр тренировок. То есть есть две подсерии: G и D.

G( Z ) ->  Xz
D( X ) ->  Y

где функция потерь G зависит от D[G(Z)], D[X].

Сначала мне нужно настроить параметры в D со всеми фиксированными параметрами G, а затем параметры в G с параметрами в D фиксированными. Функция потерь в первом случае будет отрицательной функцией потерь во втором случае, и обновление должно будет применяться к параметрам первой или второй подсети.

Я видел, что у тензорного потока есть функция tf.stop_gradient. Для обучения D (нисходящей) подсети я могу использовать эту функцию для блокировки потока градиента до

 Z -> [ G ] -> tf.stop_gradient(Xz) -> [ D ] -> Y

tf.stop_gradient очень кратко аннотируется без примера в строке (и пример seq2seq.py слишком длинный и не так прост для чтения), но выглядит так, как будто он должен вызываться во время создания графика. Означает ли это, что если я хочу блокировать/разблокировать поток градиента в чередующихся партиях, мне нужно заново создать и повторно инициализировать модель графа?

Также кажется, что нельзя заблокировать градиент, проходящий через сеть G (вверх по течению) с помощью tf.stop_gradient, справа?

В качестве альтернативы я увидел, что можно перечислить список переменных для вызова оптимизатора как opt_op = opt.minimize(cost, <list of variables>), что было бы простым решением, если бы можно было получить все переменные в области каждой подсети. Можно ли получить <list of variables> для tf.scope?

4b9b3361

Ответ 1

Самый простой способ добиться этого, как вы упомянули в своем вопросе, - создать две операции оптимизатора, используя отдельные вызовы opt.minimize(cost, ...). По умолчанию оптимизатор будет использовать все переменные в tf.trainable_variables(). Если вы хотите отфильтровать переменные в определенной области, вы можете использовать необязательный аргумент scope для tf.get_collection() следующим образом:

optimizer = tf.train.AdagradOptimzer(0.01)

first_train_vars = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES,
                                     "scope/prefix/for/first/vars")
first_train_op = optimizer.minimize(cost, var_list=first_train_vars)

second_train_vars = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES,
                                      "scope/prefix/for/second/vars")                     
second_train_op = optimizer.minimize(cost, var_list=second_train_vars)

Ответ 2

@mrry ответ абсолютно прав и, возможно, более общий, чем то, что я собираюсь предложить. Но я думаю, что более простой способ сделать это - просто передать ссылку на python непосредственно на var_list:

W = tf.Variable(...)
C = tf.Variable(...)
Y_est = tf.matmul(W,C)
loss = tf.reduce_sum((data-Y_est)**2)
optimizer = tf.train.AdamOptimizer(0.001)

# You can pass the python object directly
train_W = optimizer.minimize(loss, var_list=[W])
train_C = optimizer.minimize(loss, var_list=[C])

У меня есть отдельный пример: https://gist.github.com/ahwillia/8cedc710352eb919b684d8848bc2df3a

Ответ 3

Другой вариант, который вы, возможно, захотите рассмотреть, - установить переменную trainable = False. Это означает, что он не будет изменен путем обучения.

tf.Variable(my_weights, trainable=False)

Ответ 4

Я не знаю, имеет ли мой подход разные стороны, но я решил эту проблему для себя с помощью этой конструкции:

do_gradient = <Tensor that evaluates to 0 or 1>
no_gradient = 1 - do_gradient
wrapped_op = do_gradient * original + no_gradient * tf.stop_gradient(original)

Итак, если do_gradient = 1, значения и градиенты будут проходить через только тонкие, но если do_gradient = 0, то значения будут проходить только через stop_gradient op, что остановит возврат градиентов.

В моем сценарии привязка do_gradient до индекса тензора random_shuffle позволяет произвольно обучать разные части моей сети.