在“tensorflow”中“冻结”一些变量/范围:stop_gradient vs传递变量以最小化

时间:2016-02-09 17:26:37

标签: python tensorflow

我正在尝试实施Adversarial NN,这需要在交替培训小批量时“冻结”图表的一个或另一个部分。即有两个子网:G和D.

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

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

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

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

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

tf.stop_gradient非常简洁地注释,没有内联示例(示例seq2seq.py太长而且不容易阅读),但看起来它必须在图创建期间调用。 是否意味着如果我想在交替批次中阻止/取消阻止渐变流,我需要重新创建并重新初始化图模型吗?

似乎无法通过tf.stop_gradient阻止流经G(上游)网络的渐变,对吗?

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

4 个答案:

答案 0 :(得分:63)

正如您在问题中提到的,实现此目的的最简单方法是使用对opt.minimize(cost, ...)的单独调用创建两个优化器操作。默认情况下,优化程序将使用tf.trainable_variables()中的所有变量。如果要将变量过滤到特定范围,可以使用tf.get_collection()的可选scope参数,如下所示:

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)

答案 1 :(得分:21)

@prry的回答是完全正确的,也许比我要建议的更为笼统。但我认为一种更简单的方法就是将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

答案 2 :(得分:16)

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

tf.Variable(my_weights, trainable=False)

答案 3 :(得分:1)

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

netstandard16

因此,如果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,则值将仅流过stop_gradient op,这将停止渐变回流。

对于我的场景,将do_gradient挂钩到random_shuffle张量的索引让我随机训练我的网络的不同部分。