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

Я пытаюсь реализовать 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?

4 ответа

Решение

Как вы упоминаете в своем вопросе, самый простой способ добиться этого - создать две операции оптимизатора, используя отдельные вызовы для 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)

Ответ @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

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

tf.Variable(my_weights, trainable=False)

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

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, которая остановит возврат градиентов.

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

Другие вопросы по тегам