【问题标题】:Moving averaging of Loss during Training in KerasKeras 训练期间损失的移动平均
【发布时间】:2022-10-19 05:03:25
【问题描述】:

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

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

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

我还尝试编写自定义损失函数,但这也无济于事。

【问题讨论】:

  • 我认为如果不编辑 Keras 源代码或制作自定义训练循环,您基本上可以完成 keras 所做的所有损失管理,就无法做到这一点。

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


【解决方案1】:

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

【讨论】:

    【解决方案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,则不要在回调中包含此代码,因为在这些版本中已经提供了当前损失,而不是平均损失。

    【讨论】:

      【解决方案3】:

      (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()
      

      [ 输出 ]: ...

      【讨论】:

      • 当我使用 Keras 时,您是否可以为 Keras 提供代码 sn-p 而不是 TensorFlow API?
      • 那就是过滤器和层,您在 Tensorflow 中的意思是 Keras 库或 Keras 实用程序,您在其中安装了 Tensorflow,除非您出于特定目的直接下载。 <tensorflow.org/install>
      猜你喜欢
      • 1970-01-01
      • 2019-04-02
      • 2020-06-23
      • 2021-06-14
      • 2016-02-23
      • 1970-01-01
      • 2016-08-26
      • 2017-08-24
      • 1970-01-01
      相关资源
      最近更新 更多