2016-11-25 10 views
0

私は、自動微分(autodiff=true)のOptim.jlを使って次の与えられた関数(quad_function)を最適化Julia:整数のために `Optim.jl`と` autodiff`を使ってコスト関数を最適化する

私の目的関数は、Realを整数に丸めて階段状です。

私はautodiffオプションを使用しているので、私のRealの値はdual numbersForwardDiff.Duals)です。しかし残念ながら、ForwardDiff.Dualタイプのために実装されたround機能はありません。したがって、私は実際の部分を抽出するroundtoint64関数を書いています。このアプローチは、最適化中に問題を引き起こします。

using Plots 
plotlyjs() 

function roundtoint64(x) 
    if typeof(x) <: ForwardDiff.Dual 
    roundtoint64(x.value) 
    else 
    Int64(round(x)) 
    end 
end 

function quad_function(xs::Vector) 
    roundtoint64(xs[1])^2 + roundtoint64(xs[2])^2 
end 

x, y = linspace(-5, 5, 100), linspace(-5, 5, 100) 
z = Surface((x,y)->quad_function([x,y]), x, y) 
surface(x,y,z, linealpha = 0.3) 

これは次のように私のquad_functionがどのように見えるかです:問題はoptimize機能がすぐに収束すると進まないこと、である quad_function plot

using Optim 

res = Optim.optimize(
    quad_function, 
    [5.0,5.0], 
    Newton(), 
    OptimizationOptions(
    autodiff = true, 
    # show_trace = true 
)) 

結果:

Results of Optimization Algorithm 
* Algorithm: Newton's Method 
* Starting Point: [5.0,5.0] 
* Minimizer: [5.0,5.0] 
* Minimum: 5.000000e+01 
* Iterations: 0 
* Convergence: true 
    * |x - x'| < 1.0e-32: false 
    * |f(x) - f(x')|/|f(x)| < 1.0e-32: false 
    * |g(x)| < 1.0e-08: true 
    * Reached Maximum Number of Iterations: false 
* Objective Function Calls: 1 
* Gradient Calls: 1 


optimal_values = Optim.minimizer(res) # [5.0, 5.0] 
optimum   = Optim.minimum(res) # 50.0 

私はまた、丸め、物事を避けるために、整数[5,5]のベクターでoptimize機能を初期化しようとしたが、それは初期のステップサイズを見つけるのも問題が発生します。

ERROR: InexactError() 
in alphainit(::Int64, ::Array{Int64,1}, ::Array{Int64,1}, ::Int64) at /home/sebastian/.julia/v0.5/Optim/src/linesearch/hz_linesearch.jl:63 
in optimize(::Optim.TwiceDifferentiableFunction, ::Array{Int64,1}, ::Optim.Newton, ::Optim.OptimizationOptions{Void}) at /home/sebastian/.julia/v0.5/Optim/src/newton.jl:69 
in optimize(::Function, ::Array{Int64,1}, ::Optim.Newton, ::Optim.OptimizationOptions{Void}) at /home/sebastian/.julia/v0.5/Optim/src/optimize.jl:169 

質問:optimizeに電子メールのみを送信する方法はありますか整数空間をxplore?

更新: 私はInt64への変換アプローチの問題は、私はもはやForwardDiff.Dual秒を持っていないので、任意の誘導体/勾配を計算することができないということだと思います。どのようにより良いround関数は、ネストされたデュアルをラウンドし、二重を返すように見えるかもしれませんか?

+1

グラジエントがゼロであるためアルゴリズムが停止します。あなたの問題は、円滑な関数を期待するソルバーにはあまり適していません。あなたの関数には、MIQP(混合整数二次計画法)ソルバのようなものを試してみてください。 –

+0

ありがとうございます@ErwinKalvelagen私はそれをチェックします。しかし、ソルバーがそれに適していない限り、私がやろうとしているこの種のマッピングを実現する方法が一般的にあると思いますか?なぜなら、私のpersperctiveでは滑らかな関数から離れていないからです。 – swiesend

+1

これは滑らかではなく、ローカルnlpソルバが停止することになるゼログラデーションを持つこれらの領域をすべて持っています。これは本当に本質的に離散的な問題の間違った技術です。 –

答えて

0

Erwin Kalvelagen私の質問のコメントに指摘されています。このアルゴリズムには、この種の問題の解決策はありません。

このように私は私のコスト関数は、少なくともいくつかの勾配を持つように少し変更されたが、スムーズにまだされていない。

function quad_function_with_gradient(xs::Vector) 
    round(xs[1])*xs[1] + round(xs)[2]*xs[2] 
end 

次のようになりた:

quad_function_with_gradient

しかし、私二重数の丸めの問題を修正しなければならなかった。したがって、私はいつも実部とパーシャルを丸めround機能を、書いた:

using Optim 

roundpartials{T<:ForwardDiff.Partials}(partials::T) = (round(v) for v in partials.values) 

Base.round{T<:ForwardDiff.Dual}(dual::T) = ForwardDiff.Dual(
    round(dual.value), 
    roundpartials(dual.partials)...) 

これは私にソリューションを提供しますが、わずかdiffernt問題に:

res = Optim.optimize(
    quad_function, 
    [5.0,5.0], 
    Newton(), 
    OptimizationOptions(
    autodiff = true 
)) 

Results of Optimization Algorithm 
* Algorithm: Newton's Method 
* Starting Point: [5.0,5.0] 
* Minimizer: [0.0,0.0] 
* Minimum: 0.000000e+00 
* Iterations: 1 
* Convergence: true 
    * |x - x'| < 1.0e-32: false 
    * |f(x) - f(x')|/|f(x)| < 1.0e-32: false 
    * |g(x)| < 1.0e-08: true 
    * Reached Maximum Number of Iterations: false 
* Objective Function Calls: 5 
* Gradient Calls: 5 

それは君たちに次第ですこれが実行可能な解決策であるかどうかを判断してください。

2

Erwin Kalvelagenが元の質問に私を打ち負かすので、私はあなたのアップデートに、よりデュアル・ナンバー・セントリックの回答で対応します。

実際にはa round function implemented for ForwardDiff.Dualというオリジナルの投稿に記載されている動作があります。これは部分的な派生成分を切り捨て、実際の成分にはroundしか適用しません。 roundの導関数はほぼどこでもゼロであり、ステップが発生するところでは(すなわち、0.5の間隔で)定義されていないため、これはほとんど正しい定義です。

この定義は、NaNを伝搬することによって、または派生物が定義されていない点でエラーを起こすことによって「より正確」にすることができますが、実際のADの観点からはその戦略にはあまり効果がありません。 roundメソッドは、不連続の場合に「側を選択する」ので、微分をとるときに手を振って「片側を選択」することは意味があります。 roundの場合は、不連続のいずれかの側の導関数がゼロであるため、これは簡単です。

現在定義されているメソッドを上書きすることによって任意の定義を使用することができますが、指摘したように、中間部分偏導関数roundは間違った全体的な派生をもたらす可能性があります。これは基本的には、もはや同じ目的関数を区別しないという事実によるものです。

関連する問題