Keras 损失值显着跳跃

Keras loss value significant jump

我正在使用 Tensorflow 在 Keras 中开发一个简单的神经网络。从 epoch L-1 的最后一个 mini-batch 到 epoch L 的第一个 mini-batch,损失值有显着的跳跃。

我知道损失应该随着迭代次数的增加而减少,但是在每个时期之后损失的显着跳跃看起来很奇怪。这是代码片段

tf.keras.initializers.he_uniform(seed=None)
initializer = tf.keras.initializers.he_uniform()

def my_loss(y_true, y_pred): 
   epsilon=1e-30 #epsilon is added to avoid inf/nan
   y_pred = K.cast(y_pred, K.floatx())
   y_true = K.cast(y_true, K.floatx())
   loss = y_true* K.log(y_pred+epsilon)  + (1-y_true)*K.log(1-y_pred+epsilon)
   loss = K.mean(loss, axis= -1) 
   loss = K.mean(loss)
   loss = -1*loss
   return loss

inputs = tf.keras.Input(shape=(140,))
x = tf.keras.layers.Dense(1000,kernel_initializer=initializer)(inputs)
x = tf.keras.layers.BatchNormalization()(x)
x = tf.keras.layers.Dense(1000,kernel_initializer=initializer)(x)
x = tf.keras.layers.ReLU()(x)
x = tf.keras.layers.Dense(1000,kernel_initializer=initializer)(x)
x = tf.keras.layers.ReLU()(x)
x = tf.keras.layers.Dense(100, kernel_initializer=initializer)(x)
outputs = tf.keras.activations.sigmoid(x)

model = tf.keras.Model(inputs=inputs, outputs=outputs)


opt = tf.keras.optimizers.Adam()
recall1 = tf.keras.metrics.Recall(top_k = 8)
c_entropy = tf.keras.losses.BinaryCrossentropy()

model.compile(loss=c_entropy, optimizer= opt , metrics = [recall1,my_loss], run_eagerly=True)

model.fit(X_train_test, Y_train_test, epochs=epochs, batch_size=batch, shuffle=True, verbose = 1)

当我在网上搜索时,我发现了这个 article,这表明 Keras 计算了小批量的移动平均值。另外,我在某处发现用于计算移动平均值的数组在每个纪元后重置,这就是为什么我们在一个纪元内获得非常平滑的曲线但在纪元之后跳跃。

为了避免移动平均线,我实现了自己的损失函数,它应该输出小批量的损失值而不是批量的移动平均线。由于每个小批量彼此不同;因此相应的损失也必须彼此不同。由于这个原因,我期望通过损失函数的实现在每个小批量上有一个任意的损失值。相反,我获得了与 Keras 的损失函数完全相同的值。

我不清楚:

  1. Keras 是否在计算小批量的移动平均值,其数组在每个导致跳跃的纪元后重置。如果不是,那么是什么导致了损失值的跳跃行为。
  2. 我对每个小批量的损失实施是否正确?如果没有,那我如何在训练过程中获得mini-batch的损失值。

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

出于某种原因,它不适用于以下配置

Keras 2.4.3
Tensorflow 2.2.0
Python 3.8.5

回答第二个问题,损失函数my_loss的实现是正确的,得到的值和built-in函数生成的值非常接近。

tf.keras.losses.BinaryCrossentropy()