[英]Using `Optim` package for a non-linear object function is too slow
我想提高優化 function 的性能。
我使用Optim
package 來優化非線性 function 和 BFGS 算法。
我放了一個 object function (非線性由於link_approx
,它會生成三次樣條)
並將其梯度向量轉化為optimize
。
然而,結果證明它比 R 編程補碼慢 4 倍。
我將容差(收斂標准)設置為與 R 相同。
(如果需要我可以附上代碼)
Z::Matrix{Float64}; X::Matrix{Float64}; Y::Matrix{Float64}; B::Matrix{Float64}; G::Matrix{Float64}
using Splines2
using LinearAlgebra
using Optim
function link_approx(x_v::Array)
local est; local der
est = bs(x_v, knots = knots, order = 4)[:, 3:end-3] * fit[:theta]
der = bs(x_v, knots = knots, order = 3)[:, 3:end-3] * coef
return Dict{Symbol, Array{Float64}}(:est => est, :der => der)
end
@time for j in 1:r
# for update G
function grad!(storage, gamma)
local linkfit
linkfit = link_approx(Y*gamma)
output = (transpose(Y) * ((X*B[:,j] + linkfit[:est] - Z[:,j]) .* linkfit[:der])./n - U0[:,j] - U2[:,j] - U3[:,j]
+ rho*(pennum * gamma - C0[:,j] - C2[:,j] - C3[:,j]))
for i in 1:size(Y)[2]
storage[i] = output[i]
end
end
function obj(gamma)
return norm(Z[:,j] - X*B[:,j] - link_approx(Y*gamma)[:est], 2)^2/(2*n) - transpose(U0[:,j] + U2[:,j] + U3[:,j])*(gamma)
+ rho*(norm(gamma - C0[:,j], 2)^2 + norm(gamma - C2[:,j], 2)^2*lowrank_G + norm(gamma - C3[:,j], 2)^2*sparse_G)/2
end
temp = optimize(obj, grad!, G[:,j], BFGS(), Optim.Options(iterations = Int(5e1)))
G[:,j] = Optim.minimizer(temp)
end
2.419329 seconds (32.44 M allocations: 824.036 MiB, 3.52% gc time, 3.57% compilation time)
(梯度由B樣條曲線的導數公式計算)
我認為它的梯度向量或重復編譯存在問題。
我不知道如何在高維情況下對梯度的存儲進行評估。
由於它的維度超過 100,所以我使用了 for 循環。
這是我的代碼的一個工作示例。
using Splines2
using LinearAlgebra
using Optim
using Distributions
## basic settings (its codes are irrelevant to questions)
n=200
p=100
q=100
r=10
X = randn(n, p)
Y = randn(n, q)
B = ones(p, r) ./ p
G = ones(q, r) ./ q
Z = (X * B + Y * G)
Z_c = Z .- mean(Z, dims = 1)
Z = Z_c ./ mapslices(std, Z_c, dims = 1)
theta = convert(Array{Float64}, LinRange(-3.8, 4, 5))
knots = convert(Array{Float64}, LinRange(-7.2, 7.5, 9))
coef = (3*diff(vcat(0, theta, 0)) ./ (knots[4:end] - knots[1:end-3]))[2:end-1]
function link_approx(x_v::Array)
local est; local der
est = bs(x_v, knots = knots, order = 4)[:, 3:end-3] * theta
der = bs(x_v, knots = knots, order = 3)[:, 3:end-3] * coef
return Dict{Symbol, Array{Float64}}(:est => est, :der => der)
end
## Why it takes so long time?
@time for j in 1:r
# for update G
function grad!(storage, gamma)
local linkfit
linkfit = link_approx(Y*gamma)
output = transpose(Y) * ((X*B[:,j] + linkfit[:est] - Z[:,j]) .* linkfit[:der])./n
for i in 1:size(Y)[2]
storage[i] = output[i]
end
end
function obj(gamma)
return norm(Z[:,j] - X* B[:,j] - link_approx(Y*gamma)[:est], 2)^2/(2*n)
end
temp = optimize(obj, grad!, G[:,j], BFGS(), Optim.Options(iterations = Int(5e1)))
G[:,j] = Optim.minimizer(temp)
end
這些代碼在我的筆記本電腦上花費了大約 5 秒(設置第 9 代。英特爾 CPU i7-9750H,16GB 內存)。
我想grad!
在我的代碼中有問題。
我應該使用一個 for 循環來填充它的存儲空間,以避免我的知識錯誤。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.