我正在尝试更新每个时期的权重,但是我正在分批处理数据。问题是,要归一化损失,我需要在训练循环之外(要跟踪和归一化)将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()位置的不同以及如何在批处理数据集中更新每个时代的权重。
答案 0 :(得分:1)
tape变量主要用于观看可训练的张量变量(记录变量的前一个值和变化的值),以便我们可以根据损失函数计算训练时期的梯度。它是python上下文管理器构造的实现,用于记录变量的状态。 here是python上下文管理器的绝佳资源。因此,如果在循环内,它将记录该前向传递的变量(权重),以便我们可以一次性计算所有这些变量的梯度(而不是像没有tensorflow这样的库的朴素实现中的基于堆栈的梯度传递) 。如果它不在循环中,它将记录所有时期的状态,并且根据Tensorflow源代码,如果使用的是TF2.0(与TF1.x不同,模型开发人员必须负责冲洗),它也会冲洗。在您的示例中,您没有设置任何writer,但是如果设置了任何writer,它也会这样做。因此,对于上面的代码,它将继续记录(内部使用Graph.add_to_collection方法)所有权重,随着时期的增加,您应该会看到速度变慢。减速速度将与网络规模(可训练变量)和当前时期数成正比。
因此将其放入循环内是正确的。同样,应该在for循环内而不是在外部(与indent处于相同的缩进级别)应用渐变,否则,您仅在训练循环的最后(最后一个时期之后)应用渐变。我看到您对当前的梯度检索放置可能不太满意(尽管您在代码段中省略了它,但现在将其应用到您的代码中)。
我刚刚发现的关于渐变色带的另一个不错的resource。