2017-04-01 1 views
9

BFGS 알고리즘을 사용하여 Julia에서 함수를 최소화하기 위해 Optim.jl 라이브러리를 사용하고 있습니다. 오늘 나는 question에 대해 같은 라이브러리를 요청했지만 혼란을 피하기 위해 2로 나누기로 결정했습니다.Optim.jl : 역방향 역변환

다음 계산을 위해 최적화 후 부정 역 Hessian의 추정값을 얻고 싶습니다. Optim을 라이브러리의 GitHub의 웹 사이트에서

, 나는 다음과 같은 작업 예제를 발견

using Optim 
rosenbrock(x) = (1.0 - x[1])^2 + 100.0 * (x[2] - x[1]^2)^2 
result  = optimize(rosenbrock, zeros(2), BFGS()) 
내가 결과에서 최적화 후 부정적인 역 독일인를 얻을 수있는 방법

? Hessian, Inverse Hessian 또는 Negative inverse Hessian을 식별하는 필드가 있습니까? 의견에 대한

편집

감사합니다. 함수가 inverse Hessian을 반환하도록 "optimize.jl"을 편집하는 것이 더 효율적이라고 생각합니까? 작업 예를 들어 아래를 참조하십시오 - 편집은 라인 (226)에 도입되었습니다 단지

if state.method_string == "BFGS" 
     return MultivariateOptimizationResults(state.method_string, 
               initial_x, 
               f_increased ? state.x_previous : state.x, 
               f_increased ? state.f_x_previous : state.f_x, 
               iteration, 
               iteration == options.iterations, 
               x_converged, 
               options.x_tol, 
               f_converged, 
               options.f_tol, 
               g_converged, 
               options.g_tol, 
               f_increased, 
               tr, 
               state.f_calls, 
               state.g_calls, 
               state.h_calls), state.invH 
    else 
     return MultivariateOptimizationResults(state.method_string, 
               initial_x, 
               f_increased ? state.x_previous : state.x, 
               f_increased ? state.f_x_previous : state.f_x, 
               iteration, 
               iteration == options.iterations, 
               x_converged, 
               options.x_tol, 
               f_converged, 
               options.f_tol, 
               g_converged, 
               options.g_tol, 
               f_increased, 
               tr, 
               state.f_calls, 
               state.g_calls, 
               state.h_calls) 
    end 

또는를 :

return MultivariateOptimizationResults(state.method_string, 
             initial_x, 
             f_increased ? state.x_previous : state.x, 
             f_increased ? state.f_x_previous : state.f_x, 
             iteration, 
             iteration == options.iterations, 
             x_converged, 
             options.x_tol, 
             f_converged, 
             options.f_tol, 
             g_converged, 
             options.g_tol, 
             f_increased, 
             tr, 
             state.f_calls, 
             state.g_calls, 
             state.h_calls), state 

는 최적화 후 "상태"에 대한 전체 액세스 권한을 가지려면.

편집이 변화가 Optim.jl 라이브러리의 새 버전에 도입되기 때문에 2

,이 논의를 계속할 필요가 없습니다. 현재로서는 확장형after_while! 트릭이 작동합니다. 개인적으로 나는 후자를 선호하기 때문에 @Dan Getz에게 정답을주는 토론을 마무리 할 것입니다.

+0

'optimize.jl'에 대한 제안 된 변경 사항은 작동하지만'optimize.jl'에 대한 BFGS에만 해당되며 모든 옵티 마이저의 최종 최적화 상태에 자연스럽게 접근 할 필요가 없습니다. –

+0

마지막 편집은 어떨까요? 의미 : 최적화 후 "상태"에 대한 액세스 권한 부여. – merch

+2

이것은 확실히 Optim에 추가하려는 것입니다. 아무도 패키지의 파일을 편집해야합니다! – pkofod

답변

5

내부 최적 기능 after_while!에 연결하고 현재 아무것도 수행하지 않고 있으며 마지막 상태에서 정보를 가져 오는 데 사용하는 최적의 방법이 적합하지 않습니다.

julia> using Optim 

julia> rosenbrock(x) = (1.0 - x[1])^2 + 100.0 * (x[2] - x[1]^2)^2 
rosenbrock (generic function with 1 method) 

julia> Optim.after_while!{T}(d, state::Optim.BFGSState{T}, method::BFGS, options) 
    = global invH = state.invH 

julia> result  = optimize(rosenbrock, zeros(2), BFGS()) 
Results of Optimization Algorithm 
* Algorithm: BFGS 
* Starting Point: [0.0,0.0] 
* Minimizer: [0.9999999926033423,0.9999999852005353] 
* Minimum: 5.471433e-17 
* Iterations: 16 
* Convergence: true 
    * |x - x'| < 1.0e-32: false 
    * |f(x) - f(x')|/|f(x)| < 1.0e-32: false 
    * |g(x)| < 1.0e-08: true 
    * f(x) > f(x'): false 
    * Reached Maximum Number of Iterations: false 
* Objective Function Calls: 69 
* Gradient Calls: 69 

julia> invH 
2×2 Array{Float64,2}: 
0.498092 0.996422 
0.996422 1.9983 

이 전역 변수를 사용하고/실행 optimize를 컴파일하기 전에 after_while! 정의에 따라 대한 매력 (하지만 어쩌면 v0.6이 이미 해결)입니다 :

줄리아 코드에서이처럼 보인다 .

@DSM이 그의 답변에서 지적한 바와 같이, 최적화 프로그램의 마지막 상태에 액세스하려는 것은 당연합니다. 추적이 대답이 아닐 수도 있습니다.

5

나는 한 가지 방법을 알고 있지만, 확실하지 않은 역 헤세 인을 추정하는 것과는 대조적으로 가치가 있는지 여부를 알고 있습니다. Optim.Options(store_trace=true, extended_trace=true)을 전달하면 마지막 ~ invH가 포함 된 최적화 경로 레코드를 얻을 수 있습니다.

첫 번째 extended_trace=true 켜면 보이는 것입니다 : 예를 들어,

result = optimize(rosenbrock, zeros(2), BFGS(), 
        Optim.Options(store_trace=true, extended_trace=true)); 

후 우리는 내가이 방법에 대해 좋아하지 않아 적어도 두 가지 생각이 있습니다

julia> result.trace[end] 
    16  5.471433e-17  2.333740e-09 
* Current step size: 1.0091356566200325 
* g(x): [2.33374e-9,-1.22984e-9] 
* ~inv(H): [0.498092 0.996422; 0.996422 1.9983] 
* x: [1.0,1.0] 


julia> result.trace[end].metadata["~inv(H)"] 
2×2 Array{Float64,2}: 
0.498092 0.996422 
0.996422 1.9983 

를 얻을 수 있습니다 show_trace=true을 강제합니다 - 계산 결과를 표시하지 않았 음을 알 수 있습니다! 버그 같아. 이것은 show_every을 큰 값으로 설정하거나 stdout을 완전히 리디렉션하지 않아도되므로 제거 할 수는 있지만 완화 할 수 있습니다.

두 번째는 전체 경로를 저장하지 않고 마지막 상태에 액세스 할 수 있어야하지만 실제로 문제인지 여부는 문제의 크기에 따라 다릅니다.

+1

'extended_trace'는'show_trace'가 참이 아니고 참이어야합니다. 지금 당신의'show_ever' 해킹은 작동 할 것이지만, 이것은 변경 될 것입니다. 최적화가 더 큰 반복 프로세스의 일부인 경우 재사용 할 수 있도록 전체 "MethodState"를 반환 할 계획입니다 (선택적으로). 이렇게하면 invH 등과 같은 것들에 액세스 할 수 있습니다. – pkofod

+0

@pkofod 감사합니다. 비슷한 수정을 제안하는 게시물을 편집했습니다 (의미 : 기본 출력 외에 ** 상태 ** 반환). 이 경우 메트로폴리스 알고리즘에 필요하기 때문에 역 헤센의 추정치를 얻는 것이 중요합니다. – merch

+1

내 의견을 편집 할 수 없지만 현재 확장 된 추적을 표시하지 않고 현재 수행 할 수 있다고 말하지 않고 현재 동작을 이해할 수 없으므로 해결할 것이라고 분명히 밝히고 싶습니다. – pkofod

1

Optim.jl에서 이것을 수행하는 가장 덜 위험한 방법은 다음을 수행하는 것입니다. 우리가 그런

julia> x0 = prob.initial_x 
2-element Array{Float64,1}: 
2.0 
2.0 

julia> obj = OnceDifferentiable(prob.f, prob.g!, x0) 
NLSolversBase.OnceDifferentiable{Float64,Array{Float64,1},Array{Float64,1},Val{false}}(OptimTestProblems.MultivariateProblems.UnconstrainedProblems.himmelblau, OptimTestProblems.MultivariateProblems.UnconstrainedProblems.himmelblau_gradient!, NLSolversBase.fg!, 0.0, [NaN, NaN], [NaN, NaN], [NaN, NaN], [0], [0]) 

julia> m = BFGS() 
Optim.BFGS{LineSearches.InitialStatic{Float64},LineSearches.HagerZhang{Float64},Optim.##67#69}(LineSearches.InitialStatic{Float64} 
    alpha: Float64 1.0 
    scaled: Bool false 
, LineSearches.HagerZhang{Float64} 
    delta: Float64 0.1 
    sigma: Float64 0.9 
    alphamax: Float64 Inf 
    rho: Float64 5.0 
    epsilon: Float64 1.0e-6 
    gamma: Float64 0.66 
    linesearchmax: Int64 50 
    psi3: Float64 0.1 
    display: Int64 0 
, Optim.#67, Optim.Flat()) 

julia> options = Optim.Options() 
Optim.Options{Float64,Void}(1.0e-32, 1.0e-32, 1.0e-8, 0, 0, 0, false, 0, 1000, false, false, false, 1, nothing, NaN) 

julia> bfgsstate = Optim.initial_state(m, options, obj, x0) 
Optim.BFGSState{Array{Float64,1},Array{Float64,2},Float64,Array{Float64,1}}([2.0, 2.0], [6.91751e-310, 6.9175e-310], [-42.0, -18.0], NaN, [6.9175e-310, 0.0], [6.91751e-310, 0.0], [6.91751e-310, 0.0], [1.0 0.0; 0.0 1.0], [6.91751e-310, 0.0], NaN, [6.9175e-310, 6.91751e-310], 1.0, false, LineSearches.LineSearchResults{Float64}(Float64[], Float64[], Float64[], 0)) 

julia> res = optimize(obj, x0, m, options, bfgsstate) 
Results of Optimization Algorithm 
* Algorithm: BFGS 
* Starting Point: [2.0,2.0] 
* Minimizer: [2.9999999999998894,2.000000000000162] 
* Minimum: 5.406316e-25 
* Iterations: 7 
* Convergence: true 
    * |x - x'| ≤ 1.0e-32: false 
    |x - x'| = 5.81e-09 
    * |f(x) - f(x')| ≤ 1.0e-32 |f(x)|: false 
    |f(x) - f(x')| = 2.93e+09 |f(x)| 
    * |g(x)| ≤ 1.0e-08: true 
    |g(x)| = 4.95e-12 
    * Stopped by an increasing objective: false 
    * Reached Maximum Number of Iterations: false 
* Objective Calls: 42 
* Gradient Calls: 42 

:

첫째, 부하 Optim을하고 OptimTestProblems는

julia> using Optim, OptimTestProblems 

julia> prob = OptimTestProblems.UnconstrainedProblems.examples["Himmelblau"] 
OptimTestProblems.MultivariateProblems.OptimizationProblem{Void,Void,Float64,String,Void}("Himmelblau", OptimTestProblems.MultivariateProblems.UnconstrainedProblems.himmelblau, OptimTestProblems.MultivariateProblems.UnconstrainedProblems.himmelblau_gradient!, nothing, OptimTestProblems.MultivariateProblems.UnconstrainedProblems.himmelblau_hessian!, nothing, [2.0, 2.0], [3.0, 2.0], 0.0, true, true, nothing) 

그런 다음 모든 부분 optimize 요구 사항을 지정하고 올바른 순서로 입력 (떨어져 일할 수있는 예제를 위해) optimize에서 돌연변이 된 상태에서 역 헤센을 액세스 할 수 있습니다.

julia> bfgsstate.invH 
2×2 Array{Float64,2}: 
    0.0160654 -0.00945561 
-0.00945561 0.034967 

그리고 실제 헤센의 역수를 계산하여 얻은 역 헤세 지언과 비교하십시오.

julia> H=similar(bfgsstate.invH) 
2×2 Array{Float64,2}: 
6.91751e-310 6.91751e-310 
6.91751e-310 6.91751e-310 

julia> prob.h!(H, Optim.minimizer(res)) 
34.00000000000832 

julia> H 
2×2 Array{Float64,2}: 
74.0 20.0 
20.0 34.0 

julia> inv(H) 
2×2 Array{Float64,2}: 
    0.0160681 -0.0094518 
-0.0094518 0.0349716 

이것은 BFGS 실행의 마지막 단계에서 얻은 것과 유사합니다.