【问题标题】:"freeze" some variables/scopes in tensorflow: stop_gradient vs passing variables to minimize在张量流中“冻结”一些变量/范围:stop_gradient 与传递变量以最小化
【发布时间】:2016-05-19 19:24:30
【问题描述】:

我正在尝试实现Adversarial NN,这需要在交替训练小批量期间“冻结”图表的一个或另一部分。 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 太长且不易阅读),但看起来必须在图形创建期间调用它。 是否意味着如果我想分批阻塞/解除阻塞梯度流,我需要重新创建和重新初始化图模型?

另外,似乎无法通过tf.stop_gradient 阻止流经G(上游)网络的梯度,对吧?

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

【问题讨论】:

    标签: python tensorflow


    【解决方案1】:

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

    tf.Variable(my_weights, trainable=False)
    

    【讨论】:

    • 如果我根本不希望它可训练,这很好。但是,我希望它在每个 n_th_ 时期都可以训练。
    【解决方案2】:

    正如您在问题中提到的那样,实现此目的的最简单方法是使用对 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)
    

    【讨论】:

    • 我正在使用这个配方进行训练,当我检查 tensorboard 中的图表时,我看到我的图表翻了一番,例如我得到gradientsgradients_1。是预期的结果吗?
    【解决方案3】:

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

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

    【讨论】:

    • 这种方法解决的问题与所要求的不同。如果停止梯度,则不会训练此操作之前的任何变量。这在某些情况下很有用。除非这是您想要的,否则您最好使用其他答案之一,因为它们没有其他副作用。
    【解决方案4】:

    @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

    【讨论】:

    • 谢谢!如果您在某些单独的数据结构中维护自己的变量列表,这是一个更直接的解决方案解决方案(因此您不必通过名称反向搜索它们(每个 mrry 解决方案)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-12-06
    • 1970-01-01
    • 2016-06-25
    • 1970-01-01
    • 1970-01-01
    • 2014-06-09
    • 2018-11-17
    相关资源
    最近更新 更多