You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 10:25:32