首页 文章

R优化:每次迭代都将值从函数传递到梯度

提问于
浏览
1

我有一个函数,我正在使用R中的 optimx 函数进行优化(我也打开使用 optim ,因为我试图这样做) . 我有一个渐变,我传递给 optimx (希望)与不使用渐变相比更快收敛 . 函数和梯度都使用从每个新参数集计算的许多相同量 . 特别是这些量中的一个在计算上非常昂贵,并且它试图找到一种计算该量的方法,然后将其传递给函数和梯度 .

所以这就是我在做的事情 . 到目前为止,这是有效的,但效率低下:

optfunc<-function(paramvec){
    quant1<-costlyfunction(paramvec) 
    #costlyfunction is a separate function that takes a while to run

    loglikelihood<-sum(quant1)**2 
    #not really squared, but the log likelihood uses quant1 in its calculation

    return(loglikelihood)
}

optgr<-function(paramvec){
    quant1<-costlyfunction(paramvec)
    mygrad<-sum(quant1) #again not the real formula, just for illustration
    return(mygrad)
}

optimx(par=paramvec,fn=optfunc,gr=optgr,method="BFGS")

我试图找到一种方法,每次迭代 optimx 只计算一次 quant1 . 似乎第一步是将 fngr 组合成一个函数 . 我认为this question的答案可能对我有所帮助,因此我将优化记录为:

optfngr<-function(){
    quant1<-costlyfunction(paramvec)
    optfunc<-function(paramvec){
        loglikelihood<-sum(quant1)**2
        return(loglikelihood)
    }
    optgr<-function(paramvec){
        mygrad<-sum(quant1)
        return(mygrad)
    }
    return(list(fn = optfunc, gr = optgr))
}

do.call(optimx, c(list(par=paramvec,method="BFGS",optfngr() )))

在这里,我收到错误:“optimx.check中的错误(par,optcfg $ ufn,optcfg $ ugr,optcfg $ uhess,lower,:无法在初始参数下评估函数 . ”当然,我的代码在这里有明显的问题所以,我正在考虑回答以下任何或所有问题可能会有所启发:

  • 我通过 paramvec 作为 optfuncoptgr 的唯一参数,以便 optimx 知道 paramvec 是需要迭代的 . 但是,我不知道如何将 quant1 传递给 optfuncoptgr . 如果我尝试传递 quant1 ,那么 optimx 会无法正确识别参数向量吗?

  • 我将 optfuncoptgr 包装成一个函数,因此数量 quant1 将与两个函数存在于同一个函数空间中 . 也许我可以避免这种情况,如果我能找到一种方法从 optfunc 返回 quant1 ,然后将其传递给 optgr . 这可能吗?我没有'm thinking it',因为 optimx 的文档很清楚该函数需要返回一个标量 .

  • 我知道我可以使用 optimx 的点参数作为额外的参数参数,但我知道这些是针对固定参数的,而不是随每次迭代而改变的参数 . 除非还有办法操纵这个?

提前致谢!

1 回答

  • 1

    你的方法接近你想要的,但不是很正确 . 您想在 optfn(paramvec)optgr(paramvec) 内调用 costlyfunction(paramvec) ,但仅在 paramvec 已更改时调用 . 然后,您希望将其值保存在封闭框架中,以及用于执行此操作的 paramvec 的值 . 就是这样的:

    optfngr<-function(){
        quant1 <- NULL
        prevparam <- NULL
    
        updatecostly <- function(paramvec) {
          if (!identical(paramvec, prevparam)) {
            quant1 <<- costlyfunction(paramvec)
            prevparam <<- paramvec
          }
        }
        optfunc<-function(paramvec){
            updatecostly(paramvec)
            loglikelihood<-sum(quant1)**2
            return(loglikelihood)
        }
        optgr<-function(paramvec){
            updatecostly(paramvec)
            mygrad<-sum(quant1)
            return(mygrad)
        }
        return(list(fn = optfunc, gr = optgr))
    }
    
    do.call(optimx, c(list(par=paramvec,method="BFGS"),optfngr() ))
    

    我使用 <<- 来对封闭框架进行赋值,并修复了 do.call 第二个参数 .

    执行此操作称为"memoization"(或某些语言环境中的"memoisation";请参阅http://en.wikipedia.org/wiki/Memoization),并且有一个名为 memoise 的程序包可以执行此操作 . 它跟踪了之前调用 costlyfunction 的大量(或全部?),因此如果 paramvec 只占用少量值,那将特别好 . 但我认为它赢了't be so good in your situation because you' ll可能只会对 costlyfunction 进行少量重复调用,然后再也不会使用相同的 paramvec .

相关问题