【问题标题】:Keras loss value significant jumpKeras 损失值大幅跃升
【发布时间】:2022-10-19 04:47:05
【问题描述】:

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

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

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 计算了小批量的移动平均值。另外,我在某处发现用于计算移动平均线的数组在每个时期后都会重置,这就是为什么我们在一个时期内获得一条非常平滑的曲线,但在该时期之后有一个跳跃。

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

我不清楚:

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

【问题讨论】:

    标签: python tensorflow keras deep-learning neural-network


    【解决方案1】:

    Keras 实际上显示的是移动平均线,而不是“原始”损失值。移动平均数组在每个 epoch 之后都会重置,这就是为什么我们可以在每个 epoch 之后看到巨大的跳跃。为了获取原始损失值,应该实现如下所示的回调:

    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 的实现是正确的,得到的值与内置函数生成的值非常接近。

    tf.keras.losses.BinaryCrossentropy()
    

    【讨论】:

      【解决方案2】:

      在 TensorFlow 2.2 及更高版本中,提供给 on_train_batch_end 的损失现在是直到当前批次的所有批次的平均值。其他指标也是如此,并适用于内置损失/指标以及任何自定义损失/指标。

      幸运的是,当前批次的损失可以从平均损失计算如下:

      from tensorflow.keras.callbacks import Callback
      
      class CustomCallback(Callback):
          ''' This callback converts the average loss (default behavior in TF>=2.2)
              into the loss for only the current batch.
          '''
          def on_epoch_begin(self, epoch, logs={}):
              self.previous_loss_sum = 0
      
          def on_train_batch_end(self, batch, logs={}):
              # calculate loss of current batch:
              current_loss_sum =  (batch + 1) * logs['loss']
              current_loss = current_loss_sum - self.previous_loss_sum
              self.previous_loss_sum = current_loss_sum
      
              # use current_loss:
              # ...
      

      可以将此代码添加到任何需要当前批次损失而不是平均损失的自定义回调中,包括 Doc Jazzy's answer 中提供的 LossHistory 回调。

      此外,如果您使用的是 Tensorflow 1 或 TensorFlow 2 版本 <= 2.1,则不要在回调中包含此代码,因为在这些版本中已经提供了当前损失,而不是平均损失。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-07-19
        • 2020-11-08
        • 1970-01-01
        • 2019-10-06
        • 1970-01-01
        • 1970-01-01
        • 2018-07-08
        • 2019-04-02
        相关资源
        最近更新 更多