tf.GradientTape()的位置对模型训练时间的影响

时间:2019-08-26 12:53:55

标签: python tensorflow gradient training-data eager-execution

我正在尝试更新每个时期的权重,但是我正在分批处理数据。问题是,要归一化损失,我需要在训练循环之外(要跟踪和归一化)将TensorFlow变量记录下来。但是,当我这样做时,培训时间非常长。

我认为,它会将所有批次的变量累积到图中,并最终计算出梯度。

我已经开始在for循环外和for循环内跟踪变量,而后者比第一个要快。我对为什么会这样感到困惑,因为无论我做什么,我模型的可训练变量和损失都保持不变。

# Very Slow

loss_value = 0
batches = 0

with tf.GradientTape() as tape:
    for inputs, min_seq in zip(dataset, minutes_sequence):
        temp_loss_value = my_loss_function(inputs, min_seq)
        batches +=1
        loss_value = loss_value + temp_loss_value

# The following line takes huge time.
grads = tape.gradient(loss_value, model.trainable_variables)

# Very Fast

loss_value = 0
batches = 0

for inputs, min_seq in zip(dataset, minutes_sequence):
    with tf.GradientTape() as tape:
        temp_loss_value = my_loss_function(inputs, min_seq)
        batches +=1
        loss_value = loss_value + temp_loss_value

# If I do the following line, the graph will break because this are out of tape's scope.
    loss_value = loss_value / batches

# the following line takes huge time
grads = tape.gradient(loss_value, model.trainable_variables)

当我在for循环中声明tf.GradientTape()时,它非常快,但是在外面时,它却很慢。

P.S。 -这是一种自定义损失,并且该架构仅包含一个大小为10的隐藏层。

我想知道tf.GradientTape()位置的不同以及如何在批处理数据集中更新每个时代的权重。

1 个答案:

答案 0 :(得分:1)

tape变量主要用于观看可训练的张量变量(记录变量的前一个值和变化的值),以便我们可以根据损失函数计算训练时期的梯度。它是python上下文管理器构造的实现,用于记录变量的状态。 here是python上下文管理器的绝佳资源。因此,如果在循环内,它将记录该前向传递的变量(权重),以便我们可以一次性计算所有这些变量的梯度(而不是像没有tensorflow这样的库的朴素实现中的基于堆栈的梯度传递) 。如果它不在循环中,它将记录所有时期的状态,并且根据Tensorflow源代码,如果使用的是TF2.0(与TF1.x不同,模型开发人员必须负责冲洗),它也会冲洗。在您的示例中,您没有设置任何writer,但是如果设置了任何writer,它也会这样做。因此,对于上面的代码,它将继续记录(内部使用Graph.add_to_collection方法)所有权重,随着时期的增加,您应该会看到速度变慢。减速速度将与网络规模(可训练变量)和当前时期数成正比。

因此将其放入循环内是正确的。同样,应该在for循环内而不是在外部(与indent处于相同的缩进级别)应用渐变,否则,您仅在训练循环的最后(最后一个时期之后)应用渐变。我看到您对当前的梯度检索放置可能不太满意(尽管您在代码段中省略了它,但现在将其应用到您的代码中)。

我刚刚发现的关于渐变色带的另一个不错的resource