在R的Keras与TensorFlow中自定义损失函数:MSE复现结果不一致问题
问题:Keras自定义MSE指标与内置MSE损失的数值差异
我正在为R语言的Keras和TensorFlow创建自定义损失函数,为验证代码合理性,尝试复现MSE(均方误差)并与Keras内置功能对比,编写了如下可复现代码:
library(keras) library(tensorflow) epochs <- 3 dataset <- dataset_boston_housing() c(c(train_data, train_targets), c(test_data, test_targets)) %<-% dataset X_mean <- apply(train_data, 2, mean) X_std <- apply(train_data, 2, sd) train_data <- scale(train_data, center = X_mean, scale = X_std) test_data <- scale(test_data, center = X_mean, scale = X_std) set_random_seed(1234) model <- keras_model_sequential() %>% layer_dense(units = 64, activation = "relu", kernel_initializer = initializer_he_uniform(),input_shape = dim(train_data)[[2]]) %>% layer_dense(units = 64, activation = "relu", kernel_initializer = initializer_he_uniform()) %>% layer_dense(units = 1) my_mse <- function(y_true, y_pred){ K <- backend() loss <- K$mean(K$square(y_true-y_pred)) loss } metric_mse <- custom_metric("my_mse", function(y_true, y_pred) { my_mse(y_true, y_pred) }) model <- model %>% compile( loss = "mse", optimizer = optimizer_adam(lr=0.001), metrics = metric_mse) history <- model %>% fit( train_data, train_targets, epochs = epochs, batch_size = 2^4, validation_split=0.2 )
训练时每个epoch的内置MSE损失与自定义my_mse指标结果始终略有差异,例如:
1s 33ms/step - loss: 490.4459 - my_mse: 484.7218 - val_loss: 441.9290 - val_my_mse: 446.8440
补充:若将metric_mse()设为损失函数、mse设为指标,两者结果完全一致!这是为何?
解答
差异核心:损失与指标的平均计算逻辑不同
- 内置MSE损失采用批次加权平均:每个批次的MSE会根据该批次的样本数加权,最终整个epoch的损失是所有批次MSE的加权平均值(样本数多的批次权重更高)。
- 当前自定义指标采用批次算术平均:每个批次的MSE被平等对待,直接取所有批次MSE的算术平均值,不考虑每个批次的样本数差异。
当训练数据总数无法被batch_size整除时,最后一个批次的样本数会少于设定值,两种平均方式的计算结果就会出现差异。
交换后结果一致的原因
当把自定义MSE设为损失函数时,Keras会自动让内置MSE指标沿用损失的加权平均逻辑进行计算,两者的计算方式完全统一,因此结果完全对齐。
修正自定义指标的方法
要让自定义指标和内置MSE损失结果一致,需要让指标也使用加权平均逻辑,修改自定义指标的定义,基于总误差和总样本数计算:
metric_mse <- custom_metric("my_mse", function(y_true, y_pred) { K <- backend() squared_error <- K$square(y_true - y_pred) # 计算当前批次的总误差和样本数 total_squared_error <- K$sum(squared_error) batch_size <- K$cast(K$shape(y_true)[[1]], K$floatx()) # 返回用于累加的总误差和样本数,Keras会自动计算加权平均 list( value = total_squared_error / batch_size, count = batch_size ) }, aggregation = "mean")
修改后,自定义指标会和内置MSE损失采用相同的加权平均方式,数值就会完全对齐。
内容的提问来源于stack exchange,提问作者Myoujin
相关产品推荐
相关产品推荐

