"freeze" 张量流中的一些 variables/scopes:stop_gradient vs 传递变量以最小化

"freeze" some variables/scopes in tensorflow: stop_gradient vs passing variables to minimize

我正在尝试实现 Adversarial NN,这需要在交替训练小批量期间 'freeze' 图的一部分或另一部分。 IE。有两个子网:G和D。

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

其中 G 的损失函数取决于 D[G(Z)], D[X].

首先我需要在固定所有 G 参数的情况下训练 D 中的参数,然后在固定 D 中的参数的情况下训练 G 中的参数。第一种情况下的损失函数在第二种情况下将是负损失函数,并且更新必须应用于第一个或第二个子网的参数。

我看到tensorflow有tf.stop_gradient功能。为了训练 D(下游)子网,我可以使用此函数来阻止梯度流向

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

tf.stop_gradient 注释非常简洁,没有内联示例(并且示例 seq2seq.py 太长且不那么容易阅读),但看起来必须在图表中调用它创建。 是否意味着如果我想block/unblock梯度流交替批次,我需要重新创建并重新初始化图形模型?

而且似乎无法通过tf.stop_gradient来阻止流经G(上游)网络的梯度,对吗?

作为替代方案,我看到可以将变量列表作为 opt_op = opt.minimize(cost, <list of variables>) 传递给优化器调用,如果可以获取每个子网范围内的所有变量,这将是一个简单的解决方案。 tf.scope可以得到<list of variables>吗?

您可能要考虑的另一个选项是您可以在变量上设置 trainable=False。这意味着它不会被训练修改。

tf.Variable(my_weights, trainable=False)

正如您在问题中提到的那样,实现此目的的最简单方法是使用对 opt.minimize(cost, ...) 的单独调用来创建两个优化器操作。默认情况下,优化器将使用 tf.trainable_variables(). If you want to filter the variables to a particular scope, you can use the optional scope argument to 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)

我不知道我的方法是否有缺点,但我用这个结构自己解决了这个问题:

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 张量的索引让我可以随机训练网络的不同部分。

@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