【问题标题】:How to replace loss function during training tensorflow.keras如何在训练 tensorflow.keras 期间替换损失函数
【发布时间】:2020-07-14 17:42:37
【问题描述】:

我想在训练期间替换与我的神经网络相关的损失函数,这是网络:

model = tensorflow.keras.models.Sequential()
        model.add(tensorflow.keras.layers.Conv2D(32, kernel_size=(3, 3), activation="relu", input_shape=input_shape))
        model.add(tensorflow.keras.layers.Conv2D(64, (3, 3), activation="relu"))
        model.add(tensorflow.keras.layers.MaxPooling2D(pool_size=(2, 2)))
        model.add(tensorflow.keras.layers.Dropout(0.25))
        model.add(tensorflow.keras.layers.Flatten())
        model.add(tensorflow.keras.layers.Dense(128, activation="relu"))
        model.add(tensorflow.keras.layers.Dropout(0.5))
        model.add(tensorflow.keras.layers.Dense(output_classes, activation="softmax"))
        model.compile(loss=tensorflow.keras.losses.categorical_crossentropy, optimizer=tensorflow.keras.optimizers.Adam(0.001), metrics=['accuracy'])
        history = model.fit(x_train, y_train, batch_size=128, epochs=5, validation_data=(x_test, y_test))

所以现在我想用另一个更改tensorflow.keras.losses.categorical_crossentropy,所以我做了这个:

model.compile(loss=tensorflow.keras.losses.mse, optimizer=tensorflow.keras.optimizers.Adam(0.001), metrics=['accuracy'])
    history = model.fit(x_improve, y_improve, epochs=1, validation_data=(x_test, y_test)) #FIXME bug during training

但我有这个错误:

ValueError: No gradients provided for any variable: ['conv2d/kernel:0', 'conv2d/bias:0', 'conv2d_1/kernel:0', 'conv2d_1/bias:0', 'dense/kernel:0', 'dense/bias:0', 'dense_1/kernel:0', 'dense_1/bias:0'].

为什么?我该如何解决?还有其他方法可以改变损失函数吗?

谢谢

【问题讨论】:

    标签: python tensorflow keras loss-function


    【解决方案1】:

    我目前正在使用 Tensorflow 和 Keras 开发 google colab,但每次我重新编译这样的模型时,我都无法重新编译保持权重的模型:

    with strategy.scope():
      model = hd_unet_model(INPUT_SIZE)
      model.compile(optimizer=Adam(lr=0.01), 
                    loss=tf.keras.losses.MeanSquaredError() ,
                    metrics=[tf.keras.metrics.MeanSquaredError()]) 
    

    权重被重置。 所以我找到了另一个解决方案,你需要做的就是:

    1. 获取具有所需权重的模型(加载或其他)
    2. 这样获取模型的权重:
    weights = model.get_weights()
    
    1. 重新编译模型(改变损失函数)
    2. 再次设置重新编译模型的权重,如下所示:
    model.set_weights(weights)
    
    1. 启动培训

    我测试了这个方法,它似乎有效。

    所以要改变训练中的损失,你可以:

    1. 用第一个损失编译。
    2. 第一次损失的火车。
    3. 保存权重。
    4. 用第二个损失重新编译。
    5. 加载砝码。
    6. 第二次损失训练。

    【讨论】:

    • 这是一个非常直接的解决方案! :)
    【解决方案2】:

    所以,我会给出一个直截了当的答案:如果你想玩这种游戏,请切换到 pytorch。由于在 pytorch 中定义了训练和评估函数,因此只需一个 if 语句即可从损失函数切换到另一个损失函数。

    另外,我在你的代码中看到你想从 cross_entropy 切换到 mean_square_error,前者适合分类,后者适合回归,所以这不是你可以做的,在下面的代码中我从 mean 切换平方误差到均方对数误差,都是适合回归的损失。

    尽管其他答案为您的问题提供了解决方案(请参阅change-loss-function-dynamically-during-training),但尚不清楚您是否可以信任结果。有些人发现,即使使用自定义函数,有时 Keras 也会在第一次损失时继续训练。

    解决方案:

    我的解决方案基于 train_on_batch,它允许我们在 for 循环中训练模型,因此只要我们希望使用新的损失函数重新编译模型时就停止训练它。请注意,重新编译模型不会重置权重(请参阅:Does recompiling a model re-initialize the weights?)。

    数据集可以在这里找到Boston housing dataset

    # Regression Example With Boston Dataset: Standardized and Larger
    from pandas import read_csv
    from keras.models import Sequential
    from keras.layers import Dense
    from sklearn.model_selection import train_test_split
    from keras.losses import mean_squared_error, mean_squared_logarithmic_error
    from matplotlib import pyplot
    import matplotlib.pyplot as plt
    
    # load dataset
    dataframe = read_csv("housing.csv", delim_whitespace=True, header=None)
    dataset = dataframe.values
    
    # split into input (X) and output (Y) variables
    X = dataset[:,0:13]
    y = dataset[:,13]
    
    trainX, testX, trainy, testy = train_test_split(X, y, test_size=0.33, random_state=42)
    
    # create model
    model = Sequential()
    model.add(Dense(13, input_dim=13, kernel_initializer='normal', activation='relu'))
    model.add(Dense(6, kernel_initializer='normal', activation='relu'))
    model.add(Dense(1, kernel_initializer='normal'))
    
    batch_size = 25
    
    # have to define manually a dict to store all epochs scores 
    history = {}
    history['history'] = {}
    history['history']['loss'] = []
    history['history']['mean_squared_error'] = []
    history['history']['mean_squared_logarithmic_error'] = []
    history['history']['val_loss'] = []
    history['history']['val_mean_squared_error'] = []
    history['history']['val_mean_squared_logarithmic_error'] = []
    
    # first compiling with mse
    model.compile(loss='mean_squared_error', optimizer='adam', metrics=[mean_squared_error, mean_squared_logarithmic_error])
    
    # define number of iterations in training and test
    train_iter = round(trainX.shape[0]/batch_size)
    test_iter = round(testX.shape[0]/batch_size)
    
    for epoch in range(2):
        
        # train iterations 
        loss, mse, msle = 0, 0, 0
        for i in range(train_iter):
            
            start = i*batch_size
            end = i*batch_size + batch_size
            batchX = trainX[start:end,]
            batchy = trainy[start:end,]
            
            loss_, mse_, msle_ = model.train_on_batch(batchX,batchy)
                    
            loss += loss_
            mse += mse_
            msle += msle_
        
        history['history']['loss'].append(loss/train_iter)
        history['history']['mean_squared_error'].append(mse/train_iter)
        history['history']['mean_squared_logarithmic_error'].append(msle/train_iter)
        
        # test iterations 
        val_loss, val_mse, val_msle = 0, 0, 0
        for i in range(test_iter):
            
            start = i*batch_size
            end = i*batch_size + batch_size
            batchX = testX[start:end,]
            batchy = testy[start:end,]
            
            val_loss_, val_mse_, val_msle_ = model.test_on_batch(batchX,batchy)
            
            val_loss += val_loss_
            val_mse += val_mse_
            val_msle += msle_
            
        history['history']['val_loss'].append(val_loss/test_iter)
        history['history']['val_mean_squared_error'].append(val_mse/test_iter)
        history['history']['val_mean_squared_logarithmic_error'].append(val_msle/test_iter)
        
    # recompiling the model with new loss
    model.compile(loss='mean_squared_logarithmic_error', optimizer='adam', metrics=[mean_squared_error, mean_squared_logarithmic_error])
    
    for epoch in range(2):
        
        # train iterations 
        loss, mse, msle = 0, 0, 0
        for i in range(train_iter):
            
            start = i*batch_size
            end = i*batch_size + batch_size
            batchX = trainX[start:end,]
            batchy = trainy[start:end,]
        
            loss_, mse_, msle_ = model.train_on_batch(batchX,batchy)
            
            loss += loss_
            mse += mse_
            msle += msle_
            
        history['history']['loss'].append(loss/train_iter)
        history['history']['mean_squared_error'].append(mse/train_iter)
        history['history']['mean_squared_logarithmic_error'].append(msle/train_iter)
         
        # test iterations 
        val_loss, val_mse, val_msle = 0, 0, 0
        for i in range(test_iter):
            
            start = i*batch_size
            end = i*batch_size + batch_size
            batchX = testX[start:end,]
            batchy = testy[start:end,]
            
            val_loss_, val_mse_, val_msle_ = model.test_on_batch(batchX,batchy)
            
            val_loss += val_loss_
            val_mse += val_mse_
            val_msle += msle_
            
        history['history']['val_loss'].append(val_loss/test_iter)
        history['history']['val_mean_squared_error'].append(val_mse/test_iter)
        history['history']['val_mean_squared_logarithmic_error'].append(val_msle/test_iter)
        
    # Some plots to check what is going on   
    # loss function 
    pyplot.subplot(311)
    pyplot.title('Loss')
    pyplot.plot(history['history']['loss'], label='train')
    pyplot.plot(history['history']['val_loss'], label='test')
    pyplot.legend()
    
    # Only mean squared error 
    pyplot.subplot(312)
    pyplot.title('Mean Squared Error')
    pyplot.plot(history['history']['mean_squared_error'], label='train')
    pyplot.plot(history['history']['val_mean_squared_error'], label='test')
    pyplot.legend()
    
    # Only mean squared logarithmic error 
    pyplot.subplot(313)
    pyplot.title('Mean Squared Logarithmic Error')
    pyplot.plot(history['history']['mean_squared_logarithmic_error'], label='train')
    pyplot.plot(history['history']['val_mean_squared_logarithmic_error'], label='test')
    pyplot.legend()
    plt.tight_layout()
    pyplot.show()
    

    结果图确认损失函数在第二个 epoch 之后发生了变化:

    损失函数的下降是由于模型从正常均方误差转换为对数误差,后者的值要低得多。打印分数也证明使用的损失确实发生了变化:

    print(history['history']['loss'])
    [599.5209197998047, 570.4041115897043, 3.8622902120862688, 2.1578191178185597]
    print(history['history']['mean_squared_error'])
    [599.5209197998047, 570.4041115897043, 510.29034205845426, 425.32058388846264]
    print(history['history']['mean_squared_logarithmic_error'])
    [8.624503476279122, 6.346359729766846, 3.8622902120862688, 2.1578191178185597]
    

    在前两个 epoch 中,loss 的值等于 mean_square_error 的值,在第三和第四个 epoch 中,值变得等于 mean_square_logarithmic_error 的值,这是设置的新损失。因此,似乎使用 train_on_batch 可以更改损失函数,但是我想再次强调,这基本上是在 pytoch 上应该做的以达到相同的结果,不同之处在于 pytorch 的行为(在这种情况下和我的意见)更可靠。

    【讨论】:

      猜你喜欢
      • 2017-08-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-23
      • 2021-12-28
      • 2021-12-27
      • 2021-02-24
      • 2021-12-11
      相关资源
      最近更新 更多