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

时间:2018-06-17 14:17:25

标签: r optimization mathematical-optimization

我有一个函数,我正在使用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")

我试图找到一种方法,在quant1的每次迭代中只计算一次optimx。似乎第一步是将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,:无法在初始参数下评估函数。”当然,有明显的问题我的代码在这里。所以,我正在考虑回答以下任何或所有问题可能会有所启发:

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

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

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

  4. 提前致谢!

1 个答案:

答案 0 :(得分:2)

你的方法接近你想要的,但不是很正确。您想从costlyfunction(paramvec)optfn(paramvec)内拨打optgr(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仅占用少量值,则会特别好。但我认为在你的情况下它不会那么好,因为你可能只会对costlyfunction进行少量重复调用,然后再也不会使用相同的paramvec