MLR3MBO中待优化目标函数能否包含非优化输入?
问题
在MLR3MBO中定义待优化的目标函数时,是否允许该函数包含无需优化的输入?
详细场景
数据来自人类参与计算机任务的过程,包含一系列y值(参与者按下的按钮)与对应的x值(屏幕显示内容)。我构建了一个人类认知模型(决策模型),用于描述给定参数p时,y如何由x生成。我需要优化参数p,即找到适配每个参与者的最优参数,每个参与者的x、y、p均不同。
我尝试通过以下方式定义待优化函数的输入列表:
xs=list(x1=x1,x2=x2... ,p1=p1,p2=p2) domain=paradox::ps(p1=p_dbl(lower = -10, upper = 10),....)
即未将x1、x2等变量纳入domain定义,但运行以下代码时,程序无法识别x1、x2:
codomain=ps(y=p_dbl(tags='minimize')) objective= ObjectiveRFun$new( fun=myModel, domain=domain, codomain=codomain) instance = OptimInstanceSingleCrit$new( objective=objective, search_space=domain, terminator=trm('evals',n_evals =60)) # maybe change this? # Gaussian Process, EI, DIRECT surrogate = srlrn(lrn("regr.km", covtype = "matern3_2", optim.method = "gen", nugget.stability = 10^-8, control = list(trace = FALSE))) acq_function = acqf("ei") acq_optimizer = acqo(opt("nloptr", algorithm = "NLOPT_GN_DIRECT_L"), terminator = trm("stagnation", threshold = 1e-8)) optimizer = opt("mbo", loop_function = bayesopt_ego, surrogate = surrogate, acq_function = acq_function, acq_optimizer = acq_optimizer) set.seed(2906) start.time=Sys.time() optimizer$optimize(instance)
最初选择MLR3MBO的原因是该函数在每次优化循环中计算耗时较长(包含多步骤for循环)。
解决方案
MLR3MBO允许目标函数包含无需优化的输入,但不能直接将非优化参数放进输入列表——ObjectiveRFun只会把domain里定义的参数传给目标函数。正确做法是通过闭包或参数绑定的方式,将x、y这类固定数据注入目标函数。
方法1:用闭包封装目标函数
把固定的x、y数据封装到外层函数中,返回仅接受优化参数p的目标函数,让目标函数能直接访问外部的固定数据:
# 封装固定参数,生成目标函数 create_objective_fun <- function(x_data, y_true) { function(p) { # 调用你的认知模型,用p和固定的x_data生成预测 predictions <- myModel(p, x_data) # 计算需要最小化的损失(示例为MSE) loss <- mean((predictions - y_true)^2) return(list(y = loss)) } } # 针对当前参与者的x、y数据创建专属目标函数 my_objective_fun <- create_objective_fun(x1, x2, y) # 仅定义需要优化的参数p的domain domain <- paradox::ps( p1 = p_dbl(lower = -10, upper = 10), p2 = p_dbl(lower = -5, upper = 5) # 添加其他需要优化的参数 ) # 初始化目标和实例 codomain <- ps(y = p_dbl(tags = 'minimize')) objective <- ObjectiveRFun$new( fun = my_objective_fun, domain = domain, codomain = codomain ) instance <- OptimInstanceSingleCrit$new( objective = objective, search_space = domain, terminator = trm('evals', n_evals = 60) ) # 后续优化代码保持不变 surrogate <- srlrn(lrn("regr.km", covtype = "matern3_2", optim.method = "gen", nugget.stability = 10^-8, control = list(trace = FALSE))) acq_function <- acqf("ei") acq_optimizer <- acqo(opt("nloptr", algorithm = "NLOPT_GN_DIRECT_L"), terminator = trm("stagnation", threshold = 1e-8)) optimizer <- opt("mbo", loop_function = bayesopt_ego, surrogate = surrogate, acq_function = acq_function, acq_optimizer = acq_optimizer) set.seed(2906) start.time <- Sys.time() result <- optimizer$optimize(instance)
方法2:用参数绑定简化函数
如果不想用闭包,可借助purrr::partial或mlr3misc::partial把固定参数绑定到目标函数上,生成仅接受p的新函数:
library(purrr) # 改造myModel,让第一个参数为优化参数p,后续为固定的x、y myModel <- function(p, x_data, y_true) { predictions <- # 你的模型计算逻辑,用p和x_data生成预测 loss <- mean((predictions - y_true)^2) return(list(y = loss)) } # 绑定固定参数x、y,生成只接受p的函数 bound_fun <- partial(myModel, x_data = x1, y_true = y) # 后续domain、objective定义与方法1一致 domain <- paradox::ps(p1 = p_dbl(lower = -10, upper = 10), ...) codomain <- ps(y = p_dbl(tags = 'minimize')) objective <- ObjectiveRFun$new(fun = bound_fun, domain = domain, codomain = codomain)
关键说明
- MLR3MBO的优化逻辑只会遍历
domain内定义的参数,因此目标函数必须仅接受这些优化参数作为输入,非优化参数需通过外部环境传递。 - 闭包是最常用的方式,能清晰隔离不同参与者的数据,你可以为每个参与者单独创建闭包函数,再分别执行优化。
内容的提问来源于stack exchange,提问作者JacquieS
相关产品推荐
相关产品推荐

