【问题标题】:TensorFlow: How to write multistep decayTensorFlow:如何编写多步衰减
【发布时间】:2016-09-01 15:31:40
【问题描述】:

Caffe 中存在多步衰减。它计算为base_lr * gamma ^ (floor(step)),其中step 在您的每个衰减步骤后递增。例如,[100, 200] 衰减步骤和 global step=101 我想得到base_lr * gamma ^ 1,对于global step=201 和更多我想得到base_lr * gamma ^ 2 等等。

我尝试根据指数衰减源来实现它,但我无能为力。这是指数衰减的代码(https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/training/learning_rate_decay.py#L27):

def exponential_decay(learning_rate, global_step, decay_steps, decay_rate,
staircase=False, name=None):
  with ops.name_scope(name, "ExponentialDecay",
                      [learning_rate, global_step,
                       decay_steps, decay_rate]) as name:
    learning_rate = ops.convert_to_tensor(learning_rate, name="learning_rate")
    dtype = learning_rate.dtype
    global_step = math_ops.cast(global_step, dtype)
    decay_steps = math_ops.cast(decay_steps, dtype)
    decay_rate = math_ops.cast(decay_rate, dtype)
    p = global_step / decay_steps
    if staircase:
      p = math_ops.floor(p)
return math_ops.mul(learning_rate, math_ops.pow(decay_rate, p), name=name)

我必须将decay_steps 作为某种数组传递——python 数组或张量。我还必须(?)通过current_decay_step(上面公式中的step)。

第一个选项:在没有张量的纯python中非常简单:

decay_steps.append(global_step)
p = sorted(decay_steps).index(global_step) # may be there must be `+1` or `-1`. I hope that main idea is clear

我不能这样做,因为 TF 中没有排序。不知道实现它需要多少时间。

第二个选项:类似于下面的代码。由于许多原因,它不起作用。首先,我不知道如何将参数传递给tf.cond 中的函数。其次,即使我会通过args它也可能不起作用:Can cond support TF ops with side effects?

def new_decay_step(decay_steps):
        decay_steps = decay_steps[1:]
        current_decay_step.assign(current_decay_step + 1)
        return tf.no_op()

tf.cond(tf.greater(tf.shape(decay_steps)[0], 0),
                             tf.cond(tf.greater(global_step, decay_steps[0]), new_decay_step, tf.no_op()),
tf.no_op())

p = current_decay_step

第三个选项:它不起作用,因为我无法使用tensor[another_tensor] 获取元素。

    # if len(decay_steps) > (current_step + 1):
    #    if global_step > decay_steps[current_step + 1]:
    #        current_step += 1


    current_decay_step = tf.cond(tf.greater(tf.shape(current_decay_step)[0], tf.add(current_decay_step,1)),
                                 tf.cond(tf.greater(global_step, decay_steps[tf.add(current_decay_step + 1]), tf.add(current_decay_step,1), tf.add(current_decay_step,0)),
                                 tf.add(current_decay_step, 0)

我能做什么?

UPD:我几乎可以用第二种选择。

我可以做

   def nothing: return tf.no_op()
   tf.cond(tf.greater(global_step, decay_steps[0]),
                    functools.partial(new_decay_step, decay_steps),
                    nothing)

但由于某种原因,内部 tf.cond 不起作用

对于此代码,我收到错误 fn1 must be callable

   def nothing: return tf.no_op()
   tf.cond(tf.greater(tf.shape(decay_steps)[0], 0),
            tf.cond(tf.greater(global_step, decay_steps[0]),
                    functools.partial(new_decay_step, decay_steps),
                    nothing),
            nothing)

UPD2: 内部 tf.cond 将不起作用,因为它们返回张量并且 args 必须是函数。

我没有检查它,但它似乎可以工作(至少它不会因错误而崩溃):

 tf.cond(tf.logical_and(tf.greater(tf.shape(decay_steps)[0], 0),  tf.greater(global_step, decay_steps[0])),
                    functools.partial(new_decay_step, decay_steps),
                    nothing)

UPD3:我意识到 UPD2 中的代码将不起作用,因为我无法更改函数内的列表。

我也不知道tf.logical_and 的哪些部分真正被执行了。

我做了以下代码:

class ohmy:
    def __init__(self, decay_steps):
        self.decay_steps = decay_steps

    def multistep_decay(self, learning_rate, global_step, current_decay_step, decay_steps, decay_rate,
                    staircase=False, name=None):

        learning_rate = tf.convert_to_tensor(learning_rate, name="learning_rate")
        dtype = learning_rate.dtype
        global_step = tf.cast(global_step, dtype)

        decay_rate = tf.cast(decay_rate, dtype)

        def new_step():
            self.decay_steps = self.decay_steps[1:]
            current_decay_step.assign(current_decay_step + 1)
            return current_decay_step

        def curr_step():
            return current_decay_step

        current_decay_step = tf.cond(tf.logical_and(tf.greater(tf.shape(self.decay_steps)[0], 0),  tf.greater(global_step, self.decay_steps[0])),
                new_step,
                curr_step)

        a = tf.Print(global_step, [global_step], "global")
        b = tf.Print(self.decay_steps, [self.decay_steps], "decay_steps")
        c = tf.Print(current_decay_step, [current_decay_step], "step")

        with tf.control_dependencies([a, b, c, current_decay_step]):
            p = current_decay_step

            if staircase:
                p = tf.floor(p)

            return tf.mul(learning_rate, tf.pow(decay_rate, p), name=name)


decay_steps = [3,4,5,6,7]
decay_steps = tf.convert_to_tensor(decay_steps, dtype=tf.float32)
current_decay_step = tf.Variable(0.0, trainable=False)
global_step = tf.Variable(0, trainable=False)
decay_rate = 0.5

c=ohmy(decay_steps)
lr = ohmy.multistep_decay(c, 0.010, global_step, current_decay_step, decay_steps, decay_rate)
#lr = tf.train.exponential_decay(0.001, global_step=global_step, decay_steps=2, decay_rate=0.5, staircase=True)
tf.scalar_summary('learning_rate', lr)

opt = tf.train.AdamOptimizer(lr)
#...train loop and so on

它根本不起作用。这是输出:

I tensorflow/core/kernels/logging_ops.cc:79] step[0]
I tensorflow/core/kernels/logging_ops.cc:79] global[0]
E tensorflow/core/client/tensor_c_api.cc:485] The tensor returned for MergeSummary/MergeSummary:0 was not valid.
Traceback (most recent call last):
  File "flownet_new.py", line 528, in <module>
    summary_str = sess.run(summary_op)
  File "/usr/local/lib/python2.7/dist-packages/tensorflow/python/client/session.py", line 382, in run
    run_metadata_ptr)
  File "/usr/local/lib/python2.7/dist-packages/tensorflow/python/client/session.py", line 655, in _run
    feed_dict_string, options, run_metadata)
  File "/usr/local/lib/python2.7/dist-packages/tensorflow/python/client/session.py", line 723, in _do_run
    target_list, options, run_metadata)
  File "/usr/local/lib/python2.7/dist-packages/tensorflow/python/client/session.py", line 743, in _do_call
    raise type(e)(node_def, op, message)
tensorflow.python.framework.errors.InvalidArgumentError: The tensor returned for MergeSummary/MergeSummary:0 was not valid.

如您所见,没有衰减步骤的输出。我什至无法调试它!

现在我绝对不知道如何用一个功能来制作它。 顺便说一句,要么我做错了什么,要么tf.contrib.slim 不适用于学习率衰减。

目前最简单的解决方案是按照cleros 所说的那样在火车循环中制作您想要的东西。

【问题讨论】:

  • 查看 Stackoverflow 问题 #33919948:您可以简单地将学习率设为变量,然后您可以使用 assign_op 将其分配给您想要的任何值(例如在无张量代码中计算)跨度>
  • 谢谢。是的,如果我要手动构建训练循环,我可以这样做。但我不确定我是否可以使用tf.contrib.slim.learning.train(请参阅github.com/tensorflow/models/blob/master/inception/inception/…)。
  • 抱歉,网址不正确。文档在这里:github.com/tensorflow/tensorflow/tree/master/tensorflow/contrib/…
  • 我不熟悉tf.contrib.slim。但看起来您在 global_step 中定义了优化器(例如 AdaGrad):def train_step(sess, train_op, global_step, train_step_kwargs)。由于您可以将任何优化器的学习率初始化为 TF 变量,因此您可以像这样初始化它,然后将其传递给该函数(该函数又由 train 调用,该函数在 train_step_kwargs=_USE_DEFAULT 中接受这些参数)。

标签: python tensorflow


【解决方案1】:

我在 tensorflow 中寻找这个功能,我发现它可以使用 tf.train.piecewise_constant 轻松实现。这是 tensorflow 的 api_docs 中的一个示例:(https://www.tensorflow.org/api_docs/python/tf/train/piecewise_constant)

示例:对前 100000 步使用 1.0,对第 100001 到 110000 步使用 0.5,对任何其他步使用 0.1。

global_step = tf.Variable(0, trainable=False)
boundaries = [100000, 110000]
values = [1.0, 0.5, 0.1]
learning_rate = tf.train.piecewise_constant(global_step, boundaries, values)

稍后,每当我们执行优化步骤时,我们都会增加 global_step。

【讨论】:

    【解决方案2】:

    使用tf.train.exponential_decay(),这正是您要找的。衰减的学习率计算如下:

    decayed_learning_rate = learning_rate *
                        decay_rate ^ (global_step / decay_steps)
    

    请注意,decay_steps 参数是一个整数(不是数组也不是张量),用于保存学习率变化的迭代周期。在您的示例中decay_steps=100

    【讨论】:

    • 抱歉,我尝试实现的网络作者使用不等间隔进行衰减。出于这个原因,我讲述了张量或数组。例如,使用此功能,您不能在 100、200、300 之后衰减,并在不改变学习率的情况下继续到 1000。我几乎可以肯定我可以更改其他超参数和网络结构并获得良好的训练,但首先我想检查他们的方式。
    【解决方案3】:

    你可以试试caseswitchmerge

    比如假设base_lr0.1,而gamma0.1,可以使用

    import tensorflow as tf
    from tensorflow.python.ops import control_flow_ops
    
    global_step = global_step = tf.placeholder(dtype=tf.int64)
    
    learning_rate = tf.case(
        [(tf.less(global_step, 100), lambda: tf.constant(0.1)),
         (tf.less(global_step, 200), lambda: tf.constant(0.01))],
        default=lambda: tf.constant(0.001))
    
    with tf.Session() as sess:
        print(sess.run(learning_rate, {global_step: 0}))   # 0.1
        print(sess.run(learning_rate, {global_step: 1}))   # 0.1
        print(sess.run(learning_rate, {global_step: 99}))  # 0.1
        print(sess.run(learning_rate, {global_step: 100})) # 0.01
        print(sess.run(learning_rate, {global_step: 101})) # 0.01
        print(sess.run(learning_rate, {global_step: 199})) # 0.01
        print(sess.run(learning_rate, {global_step: 200})) # 0.001
        print(sess.run(learning_rate, {global_step: 201})) # 0.001
    

    import tensorflow as tf
    from tensorflow.python.ops import control_flow_ops
    
    global_step = global_step = tf.placeholder(dtype=tf.int64)
    
    learning_rate = control_flow_ops.merge(
        [control_flow_ops.switch(tf.constant(0.1), 
                                 tf.less(global_step, 100))[1],
         control_flow_ops.switch(tf.constant(0.01), 
                                 tf.logical_and(tf.greater_equal(global_step, 100),
                                                tf.less(global_step, 200)))[1],
         control_flow_ops.switch(tf.constant(0.001), 
                                 tf.greater_equal(global_step, 200))[1]])[0]
    
    with tf.Session() as sess:
        print(sess.run(learning_rate, {global_step: 0}))   # 0.1
        print(sess.run(learning_rate, {global_step: 1}))   # 0.1
        print(sess.run(learning_rate, {global_step: 99}))  # 0.1
        print(sess.run(learning_rate, {global_step: 100})) # 0.01
        print(sess.run(learning_rate, {global_step: 101})) # 0.01
        print(sess.run(learning_rate, {global_step: 199})) # 0.01
        print(sess.run(learning_rate, {global_step: 200})) # 0.001
        print(sess.run(learning_rate, {global_step: 201})) # 0.001
    

    代码用tensorflow 0.12.1测试。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-01-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多