gpt4 book ai didi

julia - NLopt SLSQP 放弃了好的解决方案,取而代之的是旧的、更差的解决方案

转载 作者:行者123 更新时间:2023-12-01 03:35:39 25 4
gpt4 key购买 nike

我正在解决金融的标准优化问题 - 投资组合优化。在绝大多数情况下,NLopt 正在返回一个合理的解决方案。然而,在极少数情况下,SLSQP 算法似乎迭代到正确的解决方案,然后无缘无故地选择从迭代过程的大约三分之一返回一个非常明显次优的解决方案。有趣的是,通过很小的量改变初始参数向量可以解决这个问题。

我已经设法隔离了我正在谈论的行为的一个相对简单的工作示例。抱歉数字有点乱。这是我能做的最好的。以下代码可以剪切并粘贴到 Julia REPL 中,并且每次都会运行并打印目标函数和参数的值 NLopt调用目标函数。我两次调用优化例程。如果您回滚下面代码打印的输出,您会注意到在第一次调用时,优化例程迭代到目标函数值为 0.0022 的良好解决方案。但随后无缘无故地回到了一个更早的解决方案,其中目标函数是 0.0007 ,并返回它。第二次调用优化函数时,我使用了稍微不同的参数起始向量。同样,优化例程迭代到相同的好解,但这次它返回目标函数值为 0.0022 的好解。 .

那么,问题是:有谁知道为什么在第一种情况下,SLSQP 在迭代过程的大约三分之一中放弃了好的解决方案而支持更差的解决方案?如果是这样,有什么办法可以解决这个问题吗?

#-------------------------------------------
#Load NLopt package
using NLopt
#Define objective function for the portfolio optimisation problem (maximise expected return subject to variance constraint)
function obj_func!(param::Vector{Float64}, grad::Vector{Float64}, meanVec::Vector{Float64}, covMat::Matrix{Float64})
if length(grad) > 0
tempGrad = meanVec - covMat * param
for j = 1:length(grad)
grad[j] = tempGrad[j]
end
println("Gradient vector = " * string(grad))
end
println("Parameter vector = " * string(param))
fOut = dot(param, meanVec) - (1/2)*dot(param, covMat*param)
println("Objective function value = " * string(fOut))
return(fOut)
end
#Define standard equality constraint for the portfolio optimisation problem
function eq_con!(param::Vector{Float64}, grad::Vector{Float64})
if length(grad) > 0
for j = 1:length(grad)
grad[j] = 1.0
end
end
return(sum(param) - 1.0)
end
#Function to call the optimisation process with appropriate input parameters
function do_opt(meanVec::Vector{Float64}, covMat::Matrix{Float64}, paramInit::Vector{Float64})
opt1 = Opt(:LD_SLSQP, length(meanVec))
lower_bounds!(opt1, [0.0, 0.0, 0.05, 0.0, 0.0, 0.0])
upper_bounds!(opt1, [1.0, 1.0, 1.0, 1.0, 1.0, 1.0])
equality_constraint!(opt1, eq_con!)
ftol_rel!(opt1, 0.000001)
fObj = ((param, grad) -> obj_func!(param, grad, meanVec, covMat))
max_objective!(opt1, fObj)
(fObjOpt, paramOpt, flag) = optimize(opt1, paramInit)
println("Returned parameter vector = " * string(paramOpt))
println("Return objective function = " * string(fObjOpt))
end
#-------------------------------------------
#Inputs to optimisation
meanVec = [0.00238374894628471,0.0006879970888824095,0.00015027322404371585,0.0008440624572209092,-0.004949409024535505,-0.0011493778903180567]
covMat = [8.448145928621056e-5 1.9555283947528615e-5 0.0 1.7716366331331983e-5 1.5054664977783003e-5 2.1496436765051825e-6;
1.9555283947528615e-5 0.00017068536691928327 0.0 1.4272576023325365e-5 4.2993023110905543e-5 1.047156519965148e-5;
0.0 0.0 0.0 0.0 0.0 0.0;
1.7716366331331983e-5 1.4272576023325365e-5 0.0 6.577888700124854e-5 3.957059294420261e-6 7.365234067319808e-6
1.5054664977783003e-5 4.2993023110905543e-5 0.0 3.957059294420261e-6 0.0001288060347757139 6.457128839875466e-6
2.1496436765051825e-6 1.047156519965148e-5 0.0 7.365234067319808e-6 6.457128839875466e-6 0.00010385067478418426]
paramInit = [0.0,0.9496114216578236,0.050388578342176464,0.0,0.0,0.0]

#Call the optimisation function
do_opt(meanVec, covMat, paramInit)

#Re-define initial parameters to very similar numbers
paramInit = [0.0,0.95,0.05,0.0,0.0,0.0]

#Call the optimisation function again
do_opt(meanVec, covMat, paramInit)

注意:我知道我的协方差矩阵是正半定的,而不是正定的。这不是问题的根源。我已经通过将零行的对角线元素更改为一个很小但明显非零的值来确认这一点。该问题仍然存在于上述示例中,以及我可以随机生成的其他示例中。

最佳答案

SLSQP 是一个 受限 优化算法。每一轮它都必须检查是否具有最佳目标值并满足约束条件。当满足约束条件时,最终输出是最佳值。

通过更改 eq_con! 打印出约束的值到:

function eq_con!(param::Vector{Float64}, grad::Vector{Float64})
if length(grad) > 0
for j = 1:length(grad)
grad[j] = 1.0
end
end
@show sum(param)-1.0
return(sum(param) - 1.0)
end

显示第一次运行中的最后一个有效评估点:
Objective function value = 0.0007628202546187453
sum(param) - 1.0 = 0.0

而在第二次运行中,所有评估点都满足约束。这解释了行为并表明它是合理的。

附录:

导致参数不稳定的根本问题是等式约束的确切性质。引自 NLopt 引用 ( http://ab-initio.mit.edu/wiki/index.php/NLopt_Reference#Nonlinear_constraints):

For equality constraints, a small positive tolerance is strongly advised in order to allow NLopt to converge even if the equality constraint is slightly nonzero.



确实,切换 equality_constraint!调用 do_opt
    equality_constraint!(opt1, eq_con!,0.00000001)

给出两个初始参数的 0.0022 解。

关于julia - NLopt SLSQP 放弃了好的解决方案,取而代之的是旧的、更差的解决方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35213506/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com