【问题标题】:Get loss values for each training instance - Keras获取每个训练实例的损失值 - Keras
【发布时间】:2018-01-05 17:05:16
【问题描述】:

我想获得损失值作为每个实例的模型训练。

history = model.fit(..)

例如上面的代码返回每个时期的损失值,而不是小批量或实例。

最好的方法是什么?有什么建议吗?

【问题讨论】:

    标签: python python-3.x keras


    【解决方案1】:

    在这个官方 keras 文档页面 https://keras.io/callbacks/#callback 的末尾,正是您要寻找的内容。

    这是创建自定义回调的代码

    class LossHistory(keras.callbacks.Callback):
        def on_train_begin(self, logs={}):
            self.losses = []
    
        def on_batch_end(self, batch, logs={}):
            self.losses.append(logs.get('loss'))
    
    model = Sequential()
    model.add(Dense(10, input_dim=784, kernel_initializer='uniform'))
    model.add(Activation('softmax'))
    model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
    
    history = LossHistory()
    model.fit(x_train, y_train, batch_size=128, epochs=20, verbose=0, callbacks=[history])
    
    print(history.losses)
    # outputs
    '''
    [0.66047596406559383, 0.3547245744908703, ..., 0.25953155204159617, 0.25901699725311789]
    '''
    

    【讨论】:

      【解决方案2】:

      如果您想获取每个批次的损失值,您可能需要在生成器中使用 call model.train_on_batch。在不了解您的数据集的情况下很难提供完整的示例,但您必须将数据集分成多个批次并逐个提供它们

      def make_batches(...):
          ...
      
      batches = make_batches(...)
      batch_losses = [model.train_on_batch(x, y) for x, y in batches]
      

      单个实例会稍微复杂一些。当然,您可以在 1 大小的批次上进行训练,尽管它很可能会破坏您的优化器(通过最大化梯度方差)并显着降低性能。此外,由于损失函数是在 Python 的域之外评估的,因此没有直接的方法来劫持计算而不修补 C/C++ 和 CUDA 源。即使这样,后端本身也会批量评估损失(受益于高度向量化的矩阵运算),因此您将通过强制它评估每个实例的损失来严重降低性能。简而言之,破解后端只会(可能)帮助您减少 GPU 内存传输(与从 Python 接口对 1 大小的批次进行训练相比)。如果您真的想获得每个实例的分数,我建议您进行批量训练并评估实例(这样您将避免高方差问题并减少昂贵的梯度计算,因为梯度仅在训练期间进行估计):

      def make_batches(batchsize, x, y):
          ...
      
      
      batchsize = n
      batches = make_batches(n, ...)
      batch_instances = [make_batches(1, x, y) for x, y in batches]
      losses = [
          (model.train_on_batch(x, y), [model.test_on_batch(*inst) for inst in instances]) 
          for batch, instances in zip(batches, batch_instances)
      ]
      

      【讨论】:

      • 我想要在每个实例上训练模型后的损失值。因此,如果我是正确的,您是在建议我一次喂 1 个实例作为批次?我想知道是否有更有效的方法来获取损失信息。
      【解决方案3】:

      一种解决方案是计算列车期望值与列车输入预测值之间的损失函数。在 loss = mean_squared_error 和三维输出(即图像宽 x 高 x 通道)的情况下:

      model.fit(train_in,train_out,...)
      
      pred = model.predict(train_in)
      loss = np.add.reduce(np.square(test_out-pred),axis=(1,2,3)) # this computes the total squared error for each sample
      loss = loss / ( pred.shape[1]*pred.shape[2]*pred.shape[3]) # this computes the mean over the sample entry 
      
      np.savetxt("loss.txt",loss) # This line saves the data to file
      

      【讨论】:

        【解决方案4】:

        结合herehere 的资源后,我想出了以下代码。也许它会帮助你。这个想法是,您可以覆盖 keras 中的 Callbacks 类,然后使用 on_batch_end 方法检查 keras 将自动提供给该方法的 logs 的损失值。

        这是一个内置特定功能的神经网络的工作代码。也许你可以从这里开始 -

        import numpy as np
        import pandas as pd
        import seaborn as sns
        import os
        import matplotlib.pyplot as plt
        import time
        from sklearn.preprocessing import StandardScaler
        from sklearn.model_selection import train_test_split
        
        import keras
        from keras.models import Sequential
        from keras.layers import Dense
        from keras.callbacks import Callback
        
        # fix random seed for reproducibility
        seed = 155
        np.random.seed(seed)
        
        # load pima indians dataset
        
        # download directly from website
        dataset = pd.read_csv("https://archive.ics.uci.edu/ml/machine-learning-databases/pima-indians-diabetes/pima-indians-diabetes.data", 
                              header=None).values
        X_train, X_test, Y_train, Y_test = train_test_split(dataset[:,0:8], dataset[:,8], test_size=0.25, random_state=87)
        class NBatchLogger(Callback):
            def __init__(self,display=100):
                '''
                display: Number of batches to wait before outputting loss
                '''
                self.seen = 0
                self.display = display
        
            def on_batch_end(self,batch,logs={}):
                self.seen += logs.get('size', 0)
                if self.seen % self.display == 0:
                    print('\n{0}/{1} - Batch Loss: {2}'.format(self.seen,self.params['samples'],
                                                        logs.get('loss')))
        
        
        out_batch = NBatchLogger(display=1000)
        np.random.seed(seed)
        my_first_nn = Sequential() # create model
        my_first_nn.add(Dense(5, input_dim=8, activation='relu')) # hidden layer
        my_first_nn.add(Dense(1, activation='sigmoid')) # output layer
        my_first_nn.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
        
        my_first_nn_fitted = my_first_nn.fit(X_train, Y_train, epochs=1000, verbose=0, batch_size=128,
                                             callbacks=[out_batch], initial_epoch=0)
        

        如果你想要这样的东西,请告诉我。

        【讨论】:

        • Callback 接口似乎没有每个实例丢失的操作。 on_batch_end 仅在每个 mini batch 结束时的回波损耗。我想要做的是在每个训练实例之后变得更深并获得损失。有什么建议吗?
        • 感谢@SRC。这行得通!我只需要将批量大小设置为 1。
        • @e.hurrington 你不应该这样做。批量大小会严重影响训练性能(即使您不考虑训练时间),i.p.您的模型可能无法在 1 大小的批次上收敛。
        • @SRC 谢谢。我不介意训练时间。但我需要它收敛。我会看看一些替代方案。有的话请分享。再次感谢。
        • @e.hurrington 我在我的编辑中给了你一个替代方案。
        猜你喜欢
        • 2019-04-02
        • 2017-08-10
        • 1970-01-01
        • 2021-06-14
        • 2019-02-04
        • 2016-09-14
        • 1970-01-01
        • 2022-10-19
        • 2023-04-03
        相关资源
        最近更新 更多