nloptr:lbfgs() 在做优化时需要显式提供梯度函数吗?
nloptr: does lbfgs() need to explicitly provide a gradient function when doing optimization?
在nloptr
包中,像lbfgs()
这样的函数似乎需要一个梯度函数。但是如果我不提供渐变功能,它们也可以。
我的问题是:nloptr
是自动计算梯度函数,还是像lbfgs()
这样的函数不需要梯度函数?
如果objective函数很复杂,nloptr
可以自动计算梯度函数吗,还是必须用户自己提供?
library(nloptr)
## example for auglag()
x0 <- c(1, 1)
fn <- function(x) {
(x[1] - 2) ^ 2 + (x[2] - 1) ^ 2
}
hin <- function(x) {
-0.25 * x[1] ^ 2 - x[2] ^ 2 + 1 # hin >= 0
}
heq <- function(x) {
x[1] - 2 * x[2] + 1 # heq == 0
}
## it works even gr = NULL
auglag(x0, fn, gr = NULL, hin = hin, heq = heq, localsolver = "LBFGS")
gr <- function(x) nl.grad(x, fn)
## it also works, when provide the gradient function.
auglag(x0, fn, gr = gr, hin = hin, heq = heq, localsolver = "LBFGS")
从?lbfgs
,我们了解到如果没有提供这个函数确实会自动计算梯度:
gr: gradient of function fn; will be calculated numerically if not
specified.
深入研究 lbfgs
的源代码,我们发现它是通过 nl.grad
函数实现的:
if (is.null(gr)) {
gr <- function(x) nl.grad(x, fn)
}
从nl.grad
(或?nl.grad
)的源代码可以看出,该函数执行central differences来数值计算梯度。这种估计梯度的方法仅评估 2k 个附近点处的 k 个变量的函数,这对简单函数和复杂函数都适用。
在nloptr
包中,像lbfgs()
这样的函数似乎需要一个梯度函数。但是如果我不提供渐变功能,它们也可以。
我的问题是:nloptr
是自动计算梯度函数,还是像lbfgs()
这样的函数不需要梯度函数?
如果objective函数很复杂,nloptr
可以自动计算梯度函数吗,还是必须用户自己提供?
library(nloptr)
## example for auglag()
x0 <- c(1, 1)
fn <- function(x) {
(x[1] - 2) ^ 2 + (x[2] - 1) ^ 2
}
hin <- function(x) {
-0.25 * x[1] ^ 2 - x[2] ^ 2 + 1 # hin >= 0
}
heq <- function(x) {
x[1] - 2 * x[2] + 1 # heq == 0
}
## it works even gr = NULL
auglag(x0, fn, gr = NULL, hin = hin, heq = heq, localsolver = "LBFGS")
gr <- function(x) nl.grad(x, fn)
## it also works, when provide the gradient function.
auglag(x0, fn, gr = gr, hin = hin, heq = heq, localsolver = "LBFGS")
从?lbfgs
,我们了解到如果没有提供这个函数确实会自动计算梯度:
gr: gradient of function fn; will be calculated numerically if not specified.
深入研究 lbfgs
的源代码,我们发现它是通过 nl.grad
函数实现的:
if (is.null(gr)) { gr <- function(x) nl.grad(x, fn) }
从nl.grad
(或?nl.grad
)的源代码可以看出,该函数执行central differences来数值计算梯度。这种估计梯度的方法仅评估 2k 个附近点处的 k 个变量的函数,这对简单函数和复杂函数都适用。