为什么tf.assign()会减慢执行时间?

时间:2016-06-22 11:38:15

标签: tensorflow

今天我在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()吗?

3 个答案:

答案 0 :(得分:9)

您遇到的问题与sess.runtf.assign无关。在许多模型中,这是一个非常受欢迎的问题,由于图形膨胀,您的模型很慢。我将在一个与您的代码无关的非常简单的示例中解释所有这些意味着什么。看看这两个片段:

Snippet 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)),

Snippet 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个节点。将图表定义与图表运行分开移动,您将看到改进。

答案 1 :(得分:2)

计算时间增加3似乎有点奇怪,但有些事情可以尝试:

  • 在图表中创建操作以更新您的学习率。在您的代码中,您在每个步骤创建一个新操作,该操作将添加到图形中,因此可能需要额外的时间。通常,最佳做法是在tf.Session()
  • 之前创建所有必要的操作
update_lr = tf.assign(lr, lr_rate*0.9**epoch)
  • 每次迭代仅使用1 sess.run(),结合训练op和update_lr
sess.run([train_op, update_lr], ...)
  • 实施衰减学习率的更有效方法是使用tf.train.exponential_decay()。如果你想在每个时期衰减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)

答案 2 :(得分:1)

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

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

我使用这种方法,我认为没有性能问题。此外,您可以传递任意数字,因此您甚至可以根据列车/验证数据的错误来提高/降低学习率。