Keras 训练期间损失的移动平均

问题描述 投票:0回答:3

我正在使用 Keras 和 TensorFlow 来实现深度神经网络。当我plot损失和迭代次数时,每个时期之后损失都会出现显着的跳跃。实际上,每个小批量的损失应该彼此不同,但 Keras 计算小批量损失的移动平均值,这就是为什么我们获得平滑曲线而不是任意曲线的原因。移动平均线的数组在每个时期后都会重置,因此我们可以观察到损失的跳跃。

我想删除移动平均线的功能,而是希望拥有原始损失值,该值会因每个小批量而异。目前,我尝试减少损失函数,但它仅适用于小批量中的示例。以下代码对小批量内所有训练示例的损失求和。

tf.keras.losses.BinaryCrossentropy(reduction = 'sum')

我还尝试编写自定义损失函数,但这也没有帮助。

python tensorflow keras deep-learning neural-network
3个回答
0
投票

Keras 实际上显示的是移动平均值,而不是“原始”损失值。为了获取原始损失值,应该实现如下所示的回调:

class LossHistory(keras.callbacks.Callback):
    def on_train_begin(self, logs={}):
        #initialize a list at the begining of training
        self.losses = []

    def on_batch_end(self, batch, logs={}):
        self.losses.append(logs.get('loss'))

mycallback = LossHistory()

然后调用它

model.fit

model.fit(X, Y, epochs=epochs, batch_size=batch, shuffle=True, verbose = 0, callbacks=[mycallback])
print(mycallback.losses)

我使用以下配置进行了测试

Keras 2.3.1
Tensorflow 2.1.0
Python 3.7.9

0
投票

了解 Keras 中的噪声损失曲线 (TensorFlow 2.13)

TLDR: 这是一个平滑工件,归因于 Keras 对所有损失和指标使用运行方式的方式。

这个答案与Keras损失值大幅跃升

中的答案相同

为什么损失曲线会跳跃?

我花了相当长的时间才理解为什么训练期间会出现时期之间的跳跃,并且我注意到许多其他人在各个论坛上讨论类似的问题。我在自己的训练管道中搜索错误并尝试了解内部结构。最后,这只是一个糟糕的文档和平滑工件的情况。

这些跳跃的原因有点微妙。 Keras 是一种流行的人工智能框架,将其指标和损失计算为一个时期内的运行平均值。这可能会让你的损失曲线在训练开始时看起来非常嘈杂。然而,随着时间的推移,它会变得平滑。但问题是:在下一个纪元中,损失实际上远低于前一个纪元的平均水平。这会在你的训练图中创建类似楼梯的曲线。

如果您想可视化原始批次损失,可以使用自定义回调。我通常只是继承 Keras TensorBoard 回调并添加我需要的东西,但你可以像这里一样创建自己的自定义独立回调Keras 损失值显着跳跃

import tensorflow as tf

class CustomKerasTensorBoard(tf.keras.callbacks.TensorBoard):
    def on_epoch_begin(self, epoch, logs=None):
        self.previous_loss_sum = 0
        super().on_epoch_begin(epoch, logs)

    def on_train_batch_end(self, batch, logs=None):
        current_loss_sum = (batch + 1) * logs["loss"]
        current_loss = current_loss_sum - self.previous_loss_sum
        self.previous_loss_sum = current_loss_sum
        logs["loss_raw"] = current_loss
        super().on_train_batch_end(batch, logs)

并将其添加到您的 model.fit/model.evaluate/model.predict 调用中。

这是一个图形表示,可以帮助您更好地理解这个概念:

上图显示了分类准确率。 中间的图显示了损失。 下图显示了原始批次损失,我没有对其进行平滑处理。 📉 因此,当您看到损失曲线中那些看似不稳定的跳跃时,请记住这是平滑过程的一部分,并且您的训练可能进展顺利。保持冷静并进行! 💪


-1
投票

我想删除移动平均线的功能,而是希望拥有每个小批量都不同的原始损失值。

这可以通过使用回调函数来实现,但我再次查看了这个问题,您还尝试将实际损失值优化回计算中。

当然,您可以在回调函数中应用,也可以直接执行,因为这个示例告诉您基本的自定义优化器是如何工作的。

[样本]:

import os
from os.path import exists

import tensorflow as tf

import matplotlib.pyplot as plt
from skimage.transform import resize

import numpy as np

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""
Variables
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""
learning_rate = 0.001
global_step = 0
tf.compat.v1.disable_eager_execution()

BATCH_SIZE = 1
IMG_SIZE = (32, 32)

history = [ ] 
history_Y = [ ]
list_file = [ ]
list_label = [ ]

for file in os.listdir("F:\\datasets\\downloads\\dark\\train") :
    image = plt.imread( "F:\\datasets\\downloads\\dark\\train\\" + file )
    image = resize(image, (32, 32))
    image = np.reshape( image, (1, 32, 32, 3) )
    list_file.append( image )
    list_label.append(1)

optimizer = tf.compat.v1.train.ProximalAdagradOptimizer(
    learning_rate,
    initial_accumulator_value=0.1,
    l1_regularization_strength=0.2,
    l2_regularization_strength=0.1,
    use_locking=False,
    name='ProximalAdagrad'
)

var1 = tf.Variable(255.0)
var2 = tf.Variable(10.0)
X_var = tf.compat.v1.get_variable('X', dtype = tf.float32, initializer = tf.random.normal((1, 32, 32, 3)))
y_var = tf.compat.v1.get_variable('Y', dtype = tf.float32, initializer = tf.random.normal((1, 32, 32, 3)))
Z = tf.nn.l2_loss((var1 - X_var) ** 2 + (var2 - y_var) ** 2, name="loss")

cosine_loss = tf.keras.losses.CosineSimilarity(axis=1)
loss = tf.reduce_mean(input_tensor=tf.square(Z))
training_op = optimizer.minimize(cosine_loss(X_var, y_var))

previous_train_loss = 0
with tf.compat.v1.Session() as sess:
    sess.run(tf.compat.v1.global_variables_initializer())

    image = list_file[0]
    X = image
    Y = image

    for i in range(1000):
        global_step = global_step + 1
        train_loss, temp = sess.run([loss, training_op], feed_dict={X_var:X, y_var:Y})
        
        history.append( train_loss )
        
        if global_step % 2 == 0 :
            var2 = var2 - 0.001
        if global_step % 4 == 0 and train_loss <=  previous_train_loss :
            var1 = var1 - var2 + 0.5
        print( 'steps: ' + str(i) )
        print( 'train_loss: ' + str(train_loss) )
        
        previous_train_loss = train_loss
        
sess.close()

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""
: Graph
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""
history = history[:-1]

plt.plot(np.asarray(history))
plt.xlabel('Epoch')
plt.ylabel('loss')
plt.legend(loc='lower right')
plt.show()
© www.soinside.com 2019 - 2024. All rights reserved.