R语言梯度最小化优化:复用计算结果避免重复运算
问题:避免
optim迭代中重复计算共享中间结果(delta) 我想用optim这类R包做基于梯度的最小化,目标函数f和梯度函数g逻辑都比较复杂。如下面的简化示例,f里计算的delta也是g需要的,而且同一迭代中二者的delta完全相同。但delta是百万参数不动点问题的计算结果,非常耗时,想优化实现避免每次迭代重复计算,请问有什么解决思路或相关参考包?我还没写错误代码,只是不清楚实现方式,曾考虑过用全局变量每次迭代更新。
示例代码:
f <- function(par,dt,..){ delta <- complexfunction(par,dt) obj_value <- complexfunction2(par,dt,delta) return(obj_value) } g <- function(par,dt){ delta <- complexfunction(par,dt) # 同一迭代中与f里的delta完全相同,能否复用? gradient <- complexfunction4(par, delta) return(gradient) }
解决思路
方法一:用闭包(Closure)缓存中间结果
闭包可以在内部维护缓存状态,存储最近计算的参数par和对应的delta,每次调用目标函数或梯度函数时,先检查当前参数是否与缓存一致,一致则直接复用delta,不一致才重新计算。这种方式避免了全局变量的副作用,同时保证缓存只在当前优化流程中有效。
示例代码:
# 创建闭包封装目标函数、梯度函数及缓存 create_opt_functions <- function(dt) { cached_par <- NULL cached_delta <- NULL # 目标函数 fn <- function(par) { if (!identical(par, cached_par)) { cached_delta <<- complexfunction(par, dt) cached_par <<- par } return(complexfunction2(par, dt, cached_delta)) } # 梯度函数 gr <- function(par) { if (!identical(par, cached_par)) { cached_delta <<- complexfunction(par, dt) cached_par <<- par } return(complexfunction4(par, cached_delta)) } return(list(fn = fn, gr = gr)) } # 使用示例 opt_funs <- create_opt_functions(dt = your_data) optim(par = initial_parameters, fn = opt_funs$fn, gr = opt_funs$gr, method = "BFGS")
注意:如果参数是浮点数,可考虑用
all.equal(par, cached_par, tolerance = 1e-8)替代identical,避免因浮点精度问题导致不必要的重复计算。
方法二:用单函数同时返回目标值和梯度
部分优化包支持传入一个同时返回目标值和梯度的函数,这样可以一次性计算delta并生成两个结果,从根源上避免重复计算。比如optimx、nloptr都支持这种模式。
以optimx为例的示例代码:
library(optimx) # 同时计算目标值和梯度的函数 fg_combined <- function(par, dt) { delta <- complexfunction(par, dt) obj_val <- complexfunction2(par, dt, delta) grad_val <- complexfunction4(par, delta) return(list(value = obj_val, gradient = grad_val)) } # 调用优化函数,指定使用梯度 optimx( par = initial_parameters, fn = fg_combined, gr = NULL, method = "BFGS", control = list(usegrad = TRUE), dt = your_data )
方法三:全局变量缓存(不推荐)
如果一定要用全局变量,需注意避免跨调用的缓存污染,仅在单次优化流程中使用。这种方式容易引发意外副作用,不推荐在复杂场景或并行计算中使用。
示例代码:
# 全局缓存变量(用.开头避免冲突) .cached_par <<- NULL .cached_delta <<- NULL f <- function(par, dt) { if (!identical(par, .cached_par)) { .cached_delta <<- complexfunction(par, dt) .cached_par <<- par } return(complexfunction2(par, dt, .cached_delta)) } g <- function(par, dt) { if (!identical(par, .cached_par)) { .cached_delta <<- complexfunction(par, dt) .cached_par <<- par } return(complexfunction4(par, .cached_delta)) }
内容的提问来源于stack exchange,提问作者Jakob D.
相关产品推荐
相关产品推荐

