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

并行化调参时mlr自定义度量无法找到外部函数的问题求助

解决mlr并行调优中自定义度量函数找不到的问题

我来帮你搞定这个并行调优时的函数找不到问题,以及后续用extra.args传递函数时的参数错误。

问题根源分析

  1. 并行时函数找不到:开启并行会话后,子进程(不管是socket还是multicore模式)不会自动共享主进程全局环境的所有对象,所以inverse_fun虽然在主进程全局环境中,但子进程没办法找到它。
  2. extra.args使用错误:你之前创建makeMeasure时直接调用了transf_measure_fun(extra.args = list(...)),这会导致函数被立即执行,而此时缺少pred等必要参数,所以才会报错"argument 'pred' is missing"。正确做法是把函数对象传给fun参数,而不是函数调用后的结果。

正确的解决方案

步骤1:修正自定义度量的定义

重新定义度量函数和度量对象,确保fun参数传递的是函数本身,并且正确使用extra.args:

# 保持inverse_fun的定义不变
inverse_fun = function(x){x^2}
inverse_fun = Vectorize(inverse_fun)
inverse_fun = cmpfun(inverse_fun, options=list(suppressUndefined=T))

tuning_criterion = 'rmse'
original_measure = getMeasure(tuning_criterion) # 用getMeasure替代eval(parse)更安全、更规范

# 修正度量函数:从extra.args中获取逆函数
transf_measure_fun = function(task, model, pred, feats, extra.args){
  # 从extra.args中取出逆函数
  inv_fun = extra.args$inv_fun
  # 转换预测值和真实值
  pred$data$truth = inv_fun(pred$data$truth)
  pred$data$response = inv_fun(pred$data$response)
  # 调用原始度量的函数
  return(original_measure$fun(task, model, pred, feats, extra.args))
}

# 创建度量对象:这里fun传函数对象,不要调用它!
transf_measure = makeMeasure(
  id = 'ii',
  name = 'ccc',
  properties = original_measure$properties,
  minimize = original_measure$minimize,
  best = original_measure$best,
  worst = original_measure$worst,
  fun = transf_measure_fun, # 传函数本身,不是调用结果
  extra.args = list(inv_fun = inverse_fun) # 在这里设置默认的extra.args,也可以在tuneParams时传递
)

# 保持聚合度量的定义不变
transf_measure = setAggregation(transf_measure, original_measure$aggr)
aggregated_measure = list(transf_measure, setAggregation(transf_measure, test.sd), setAggregation(transf_measure, train.mean), setAggregation(transf_measure, train.sd))

步骤2:并行调优时确保参数正确传递

开启并行会话后,tuneParams会自动把度量的extra.args传递给子进程,这样子进程就能获取到inv_fun了。

完整的并行调优代码:

# 初始化并行会话
current_os = Sys.info()[['sysname']]
if (current_os == "Windows"){
  set.seed(1, "L'Ecuyer-CMRG")
  parallelStart(mode = "socket", cpus = detectCores(), show.info = F)
  parallel::clusterSetRNGStream(iseed = 1)
} else if (current_os == "Linux"){
  set.seed(1, "L'Ecuyer-CMRG")
  parallelStart(mode = "multicore", cpus = detectCores(), show.info = F)
} else {
  cat('\n\n#### OS not recognized, check parallelization init\n\n')
}

# 执行调优:此时transf_measure已经携带了extra.args,子进程能获取到inv_fun
res = tuneParams(lrn.lm, task = bh.task, resampling = rdesc, par.set = discrete_ps, control = ctrl, measures = transf_measure)

# 关闭并行会话
parallelStop()

备选方案:用parallelExport导出函数

如果你不想修改度量的extra.args,也可以在开启并行后,用parallelExport把inverse_fun导出到所有子进程:

# 开启并行后添加这一行
parallelExport("inverse_fun")

这种方式也能让子进程找到inverse_fun,但用extra.args的方式更符合mlr度量的设计规范,耦合性更低。

验证修复

你可以先在非并行模式下验证自定义度量的正确性,再开启并行测试:

# 验证非并行模式
res = tuneParams(lrn.lm, task = bh.task, resampling = rdesc, par.set = discrete_ps, control = ctrl, measures = transf_measure)

# 验证并行模式(按上面的代码执行)

这样应该就能解决你遇到的两个问题了。

内容的提问来源于stack exchange,提问作者Alessandro Bitetto

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:15:28