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

提取caret中nnet的finalModel参数:无法复现模型结果

问题:用caret训练nnet模型后,无法用nnet包单独复现结果?

嘿,我最近在折腾caret和nnet的时候遇到个头疼的问题:当我把caret训练出来的nnet模型参数原封不动地拿到nnet::nnet里调用时,两次的预测结果居然不一样!我明明觉得参数都对齐了啊😤。虽然知道可以直接用caret的模型做预测,但就是想搞明白怎么用nnet单独复现出来,不然总觉得没搞透。

先给大家看一下我用的示例代码:

library(nnet)
library(caret)
len <- 100
set.seed(4321)
X <- data.frame(x1 = rnorm(len, 40, 25), x2 = rnorm(len, 70, 4), x3 = rnorm(len, 1.6, 0.3))
y <- 20000 + X$x1 * 3 - X$x1*X$x2 * 4 - (X$x3**4) * 7 + rnorm(len, 0, 4)
XY <- cbind(X, y)
# 预处理
preProcPrms <- preProcess(XY, method = c("center", "scale"))
XY_pre <- predict(preProcPrms, XY)
# 用caret训练nnet
controlList <- trainControl(method = "cv", number = 5)
tuneMatrix <- expand.grid(size = c(1, 2), decay = c(0, 0.1))
caret_net <- train(
  x = XY_pre[ , colnames(XY_pre) != "y"], 
  y = XY_pre[ , colnames(XY_pre) == "y"], 
  method = "nnet", 
  linout = TRUE, 
  TRACE = FALSE, 
  maxit = 100, 
  tuneGrid = tuneMatrix, 
  trControl = controlList
)
# 尝试用nnet复现
nnet_net <- nnet(
  x = XY_pre[ , colnames(XY_pre) != "y"], 
  y = XY_pre[ , colnames(XY_pre) == "y"], 
  linout = caret_net$finalModel$param$linout, 
  TRACE = caret_net$finalModel$param$TRACE, 
  size = caret_net$bestTune$size, 
  decay = caret_net$bestTune$decay, 
  entropy = caret_net$finalModel$entropy, 
  maxit = 100
)
# 对比结果
print(caret_net$finalModel)
print(nnet_net)
y_caret <- predict(caret_net$finalModel, XY_pre[ , colnames(XY_pre) != "y"])
y_nnet <- predict(nnet_net, XY_pre[ , colnames(XY_pre) != "y"])
plot(y_caret, y_nnet, main = "Hard to spot, but y_caret <> y_nnet - which prm have I forgotten?")
hist(y_caret - y_nnet)

问题出在哪?

其实你漏了两个关键细节:

  • 随机种子:caret的train函数在交叉验证过程中会自动设置一系列随机种子(存放在caret_net$control$seeds里),最终训练最优模型时用的是列表里最后一个种子。而你直接调用nnet时,用的是全局的种子,和caret内部的种子不一致,导致神经网络的初始权重不一样,结果自然有差异。
  • rang参数:caret在调用nnet时,默认会把权重的初始范围rang设为0.1,但nnet包的默认值是0.5!这个参数直接影响权重初始化,也是结果差异的重要原因。

怎么修正才能复现结果?

只需要同步这两个点就行,修正后的nnet调用代码如下:

# 同步caret训练最终模型时使用的随机种子
set.seed(caret_net$control$seeds[[length(caret_net$control$seeds)]])
# 调用nnet时加上rang参数,确保和caret默认一致
nnet_net <- nnet(
  x = XY_pre[, colnames(XY_pre) != "y"], 
  y = XY_pre[, colnames(XY_pre) == "y"], 
  linout = caret_net$finalModel$param$linout, 
  TRACE = caret_net$finalModel$param$TRACE, 
  size = caret_net$bestTune$size, 
  decay = caret_net$bestTune$decay, 
  entropy = caret_net$finalModel$entropy, 
  maxit = 100,
  rang = 0.1  # 这个是caret调用nnet的默认值,必须加上!
)

运行这段代码后,再对比y_caret和y_nnet,你会发现两者几乎完全一致(可能存在极小的浮点精度差异,但可以忽略)。

内容的提问来源于stack exchange,提问作者r.user.05apr

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:21:17