我如何在 Julia 中独立于 Optim.jl 使用 Linesearches.jl 模块?
How can I use the Linesearches.jl module in Julia independent of Optim.jl?
我有一个 L-BFGS 的实现,想从 LineSearches.jl 调用线搜索来比较。但是,文档非常稀疏,仅关注 Linesearches.jl 在 Optim.jl 上下文中的使用。我找不到任何有关如何独立使用 Linesearches.jl 的示例。
我创建了一个示例,说明如何将 LineSearches
算法与 custom-made optimizer in the latest
documentation 一起使用。
请注意,该示例当前需要 LineSearches master
,但应该很快会在 v6.0.0
中可用。
这是完整的示例,以防链接中断:(编辑:更新了简化过程的新示例代码。)
在没有 Optim/NLsolve
的情况下使用 LineSearches
假设我们已经编写了梯度下降优化算法,但想要
尝试不同的线搜索算法。
算法实现如下
function gdoptimize(f, g!, fg!, x0::AbstractArray{T}, linesearch,
maxiter::Int = 10000,
g_rtol::T = sqrt(eps(T)), g_atol::T = eps(T)) where T <: Number
x = copy(x0)
gvec = similar(x)
g!(gvec, x)
fx = f(x)
gnorm = norm(gvec)
gtol = max(g_rtol*gnorm, g_atol)
# Univariate line search functions
ϕ(α) = f(x .+ α.*s)
function dϕ(α)
g!(gvec, x .+ α.*s)
return vecdot(gvec, s)
end
function ϕdϕ(α)
phi = fg!(gvec, x .+ α.*s)
dphi = vecdot(gvec, s)
return (phi, dphi)
end
s = similar(gvec) # Step direction
iter = 0
while iter < maxiter && gnorm > gtol
iter += 1
s .= -gvec
dϕ_0 = dot(s, gvec)
α, fx = linesearch(ϕ, dϕ, ϕdϕ, 1.0, fx, dϕ_0)
@. x = x + α*s
g!(gvec, x)
gnorm = norm(gvec)
end
return (fx, x, iter)
end
请注意,有许多优化和线搜索算法允许
用户同时评估 objective 和梯度,因为
计算效率的原因。
我们已将此功能包含在算法中作为输入函数 fg!
,
即使梯度下降算法没有明确使用它,许多 LineSearches 算法也会使用它。
梯度下降gdoptimize
方法选择下降方向并调用
线搜索算法 linesearch
其中 returns 步长 α
和
objective 值 fx = f(x + α*s)
.
函数 ϕ 和 dϕ 表示单变量 objective
及其导数,用于线搜索算法。
要在优化器中使用 fg!
函数调用,一些行搜索
需要一个函数 ϕdϕ 其中 returns 单变量 objective 和
同时导数
优化罗森布罗克
这里有一个例子来展示我们如何结合 gdoptimize
和 LineSearches
最小化由
定义的 Rosenbrock 函数
f(x) = (1.0 - x[1])^2 + 100.0 * (x[2] - x[1]^2)^2
function g!(gvec, x)
gvec[1] = -2.0 * (1.0 - x[1]) - 400.0 * (x[2] - x[1]^2) * x[1]
gvec[2] = 200.0 * (x[2] - x[1]^2)
gvec
end
function fg!(gvec, x)
g!(gvec, x)
f(x)
end
我们现在可以使用 gdoptimize
和 BackTracking
来优化 Rosenbrock 函数
从给定的初始条件 x0
.
x0 = [-1., 1.0]
using LineSearches
ls = BackTracking(order=3)
fx_bt3, x_bt3, iter_bt3 = gdoptimize(f, g!, fg!, x0, ls)
有趣的是,StrongWolfe
线搜索在一次迭代中收敛,而
所有其他算法都需要数千次迭代。
由于初始条件的特殊选择,这只是运气
ls = StrongWolfe()
fx_sw, x_sw, iter_sw = gdoptimize(f, g!, fg!, x0, ls)
我有一个 L-BFGS 的实现,想从 LineSearches.jl 调用线搜索来比较。但是,文档非常稀疏,仅关注 Linesearches.jl 在 Optim.jl 上下文中的使用。我找不到任何有关如何独立使用 Linesearches.jl 的示例。
我创建了一个示例,说明如何将 LineSearches
算法与 custom-made optimizer in the latest
documentation 一起使用。
请注意,该示例当前需要 LineSearches master
,但应该很快会在 v6.0.0
中可用。
这是完整的示例,以防链接中断:(编辑:更新了简化过程的新示例代码。)
在没有 Optim/NLsolve
的情况下使用 LineSearches假设我们已经编写了梯度下降优化算法,但想要 尝试不同的线搜索算法。 算法实现如下
function gdoptimize(f, g!, fg!, x0::AbstractArray{T}, linesearch,
maxiter::Int = 10000,
g_rtol::T = sqrt(eps(T)), g_atol::T = eps(T)) where T <: Number
x = copy(x0)
gvec = similar(x)
g!(gvec, x)
fx = f(x)
gnorm = norm(gvec)
gtol = max(g_rtol*gnorm, g_atol)
# Univariate line search functions
ϕ(α) = f(x .+ α.*s)
function dϕ(α)
g!(gvec, x .+ α.*s)
return vecdot(gvec, s)
end
function ϕdϕ(α)
phi = fg!(gvec, x .+ α.*s)
dphi = vecdot(gvec, s)
return (phi, dphi)
end
s = similar(gvec) # Step direction
iter = 0
while iter < maxiter && gnorm > gtol
iter += 1
s .= -gvec
dϕ_0 = dot(s, gvec)
α, fx = linesearch(ϕ, dϕ, ϕdϕ, 1.0, fx, dϕ_0)
@. x = x + α*s
g!(gvec, x)
gnorm = norm(gvec)
end
return (fx, x, iter)
end
请注意,有许多优化和线搜索算法允许
用户同时评估 objective 和梯度,因为
计算效率的原因。
我们已将此功能包含在算法中作为输入函数 fg!
,
即使梯度下降算法没有明确使用它,许多 LineSearches 算法也会使用它。
梯度下降gdoptimize
方法选择下降方向并调用
线搜索算法 linesearch
其中 returns 步长 α
和
objective 值 fx = f(x + α*s)
.
函数 ϕ 和 dϕ 表示单变量 objective
及其导数,用于线搜索算法。
要在优化器中使用 fg!
函数调用,一些行搜索
需要一个函数 ϕdϕ 其中 returns 单变量 objective 和
同时导数
优化罗森布罗克
这里有一个例子来展示我们如何结合 gdoptimize
和 LineSearches
最小化由
f(x) = (1.0 - x[1])^2 + 100.0 * (x[2] - x[1]^2)^2
function g!(gvec, x)
gvec[1] = -2.0 * (1.0 - x[1]) - 400.0 * (x[2] - x[1]^2) * x[1]
gvec[2] = 200.0 * (x[2] - x[1]^2)
gvec
end
function fg!(gvec, x)
g!(gvec, x)
f(x)
end
我们现在可以使用 gdoptimize
和 BackTracking
来优化 Rosenbrock 函数
从给定的初始条件 x0
.
x0 = [-1., 1.0]
using LineSearches
ls = BackTracking(order=3)
fx_bt3, x_bt3, iter_bt3 = gdoptimize(f, g!, fg!, x0, ls)
有趣的是,StrongWolfe
线搜索在一次迭代中收敛,而
所有其他算法都需要数千次迭代。
由于初始条件的特殊选择,这只是运气
ls = StrongWolfe()
fx_sw, x_sw, iter_sw = gdoptimize(f, g!, fg!, x0, ls)