【问题标题】:Why does tf.assign() slow the execution time?为什么 tf.assign() 会减慢执行时间?
【发布时间】:2016-10-24 07:55:20
【问题描述】:

今天我在 Tensorflow 中为我的 LSTM 添加了学习率衰减。

我变了

train_op = tf.train.RMSPropOptimizer(lr_rate).minimize(loss)

lr = tf.Variable(0.0,trainable=False)

并运行每个火车步骤

sess.run(tf.assign(lr, lr_rate*0.9**epoch))

但是,此更改将执行时间从约 7 分钟增加到约 20 分钟以上。

我的问题是: 为什么此更改会增加执行时间?

一个明显的解决方法是每 1000 次迭代才进行一次分配。但是,我想了解这背后的原因。

  • sess.run() 是否需要额外的时间?
  • tf.asign() 是否需要额外的时间?
  • 我可以用另一种更有效的方式实现这个 tf.assign() 吗?

【问题讨论】:

    标签: tensorflow


    【解决方案1】:

    计算时间增加 3 似乎有点奇怪,但您可以尝试以下一些方法:

    • 在图表中创建一个操作来更新您的学习率。在您的代码中,您在每个步骤中创建一个新操作,该操作将添加到图表中,因此可能需要额外的时间。一般来说,最好在tf.Session() 之前创建所有必要的操作
    update_lr = tf.assign(lr, lr_rate*0.9**epoch)
    
    • 每次迭代仅使用 1 个sess.run(),结合训练操作和update_lr
    sess.run([train_op, update_lr], ...)
    
    • 实现衰减学习率的更有效方法是使用tf.train.exponential_decay()。如果你想每个 epoch 衰减 0.9,你可以这样做:
    training_size = 60000  # size of an epoch
    global_step = tf.Variable(0, trainable=False)
    starter_learning_rate = 0.1
    learning_rate = tf.train.exponential_decay(starter_learning_rate, global_step,
                                               training_size, 0.9, staircase=True)
    # Passing global_step to minimize() will increment it at each step.
    
    train_op = tf.train.RMSPropOptimizer(lr_rate).minimize(loss, global_step=global_step)
    

    【讨论】:

    • 感谢 Olivier,我将实现指数衰减()。到本周末,我将报告改进情况
    【解决方案2】:

    您遇到的问题与sess.runtf.assign 无关。这在许多模型中是一个非常流行的问题,并且您的模型很慢,因为您的图形过于臃肿。我将在一个与您的代码无关的非常简单的示例中解释所有这些意味着什么。看看这 2 个 sn-ps:

    片段 1

    a = tf.Variable(1, name='a')
    b = tf.Variable(2, name='b')
    with tf.Session() as sess:
        sess.run(tf.global_variables_initializer())
        for _ in range(3):
            print sess.run(tf.add(a, b)),
    

    片段 2

    a = tf.Variable(1, name='a')
    b = tf.Variable(2, name='b')
    res = tf.add(a, b)
    with tf.Session() as sess:
        sess.run(tf.global_variables_initializer())
        for _ in range(3):
            print sess.run(res),
    

    它们都返回相同的值,并且看起来它们都执行相同的操作。问题是它们创建了不同的图表,如果您在循环后 print len(tf.get_default_graph().get_operations()),您会看到 Snippet 1 的节点比 Snippet 2 多。将范围增加到几千个,差异会很大。

    对于臃肿的图表,您也有同样的问题。因为在循环的每次迭代中,您都会在图中创建tf.assign(lr, lr_rate*0.9**epoch) 3 个节点。将您的图表定义与图表运行分开移动,您将看到改进。

    【讨论】:

    • 很好的解释,膨胀图,当您在每个全局步骤后更新学习率时,这可能是一个严重的问题。
    【解决方案3】:

    虽然我不确定为什么这会大大减慢进程(在https://github.com/tensorflow/tensorflow/issues/1439 中似乎不断创建新的图形节点会导致这种情况),但我认为最好使用 feed_dict 来执行此操作:

    learn_rate = tf.placeholder(tf.float32, shape=[])
    optiizer = tf.train.AdamOptimizer(learn_rate)
    ...
    learnrate = 1e-5
    ...
    sess.run(minimizer, feed_dict={learn_rate: learnrate})
    

    我使用这种方法,但没有发现性能问题。此外,您可以传递任意数字,因此您甚至可以根据训练/验证数据的错误增加/减少学习率。

    【讨论】:

      猜你喜欢
      • 2023-03-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-15
      • 1970-01-01
      • 1970-01-01
      • 2018-11-30
      • 2017-01-16
      相关资源
      最近更新 更多