2016-11-25 4 views
0
나는 자동 차별화 ( autodiff=true)와 Optim.jl를 사용하여 다음 주어진 함수 ( quad_function를) 최적화 (최소화) 좋아

에 대한 autodiff`와 비용 함수를 최적화 할 수 있습니다.줄리아 :`Optim.jl`와`정수

내 목적 함수 은 정수로Real 값을 반올림하므로 단계적입니다. 나는 autodiff 옵션을 사용할 때

, 내 Real 값은 dual numbers (ForwardDiff.Dual들)을 얻는다. 그러나 불행하게도 ForwardDiff.Dual 유형에 대해 구현 된 round 함수가 없습니다. 따라서 나는 실제 부품을 추출하는 roundtoint64 함수를 작성했습니다. 이 접근법은 최적화하는 동안 문제를 일으 킵니다. quad_function plot

문제optimize 기능을 즉시 수렴 및 진행되지 않습니다 :

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 보이는 방법이다.

using Optim 

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

결과 : 나는 또한 반올림 것을 피하기 위해 정수 [5,5]의 벡터와 optimize 기능을 초기화하려고했으나 그에서 초기 단계의 크기를 찾아도 문제가 발생

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 

:

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

그래디언트가 0이므로 알고리즘이 중지됩니다. 당신의 문제는 매끄러운 기능을 기대하는 솔버에게는 적합하지 않습니다. 함수에 MIQP (mixed integer quadratic programming) 솔버와 같은 것을 사용해보십시오. –

+0

@ErwinKalvelagen 감사합니다. 그러나 솔버가 적합하지 않다면 일반적으로이 매핑을 수행하는 방법이 있다고 생각합니까? 왜냐하면 그것은 내 persperctive에서 부드러운 함수로부터 멀지 않은 것이기 때문에 ... – swiesend

+1

그것은 전혀 부드럽 지 않다. 그리고 지역 nlp 솔버가 멈추기로 결정할 0 그라디언트가있는이 모든 영역을 가지고있다. 이것은 근본적으로 분리 된 문제에 대한 잘못된 기술입니다. –

답변

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

하지만를 I 여전히 이중 숫자 반올림 문제를 해결해야했습니다.최대 너희들에게

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 

그건 :

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 문제 : 그러므로 나는 항상 실수 부와 파셜 반올림 round 기능을 썼다 이것이 실현 가능한 해결책인지 결정하십시오.

2

Erwin Kalvelagen이 나에게 원래 질문에 대한 답을 던지기 때문에 더 많은 이중 숫자 중심 답변으로 응답하겠습니다.

실제로 원래 게시물에서 언급 한 동작이있는 a round function implemented for ForwardDiff.Dual이 있습니다. 이는 파생 된 부분 파생물을 자르고 실제 구성 요소에만 round을 적용합니다. round의 파생물이 거의 모든 곳에서 0이고 단계가 발생할 때 (즉, 0.5의 간격으로) 정의되지 않았기 때문에 이는 대부분 올바른 정의입니다.

이 정의는 미분양이 정의되지 않은 지점에서 NaN을 전파하거나 오류를 발생시킴으로써 "더 정확한"것으로 나타낼 수 있지만 실용적인 광고의 관점에서 그 전략에 많은 이점이 없습니다. round 메서드는 불연속의 경우 "측면을 선택"하므로 파생물을 가져올 때 "측면을 선택"하는 것이 당연합니다. round의 경우에는 불연속의 양쪽에서 파생 값이 0이기 때문에 이것은 쉽습니다.

현재 정의 된 방법을 덮어 쓰면 원하는 정의를 사용할 수 있지만 중간 부분 파생 상품 round은 잘못된 전체적인 파생어를 산출 할 수 있습니다. 이것은 근본적으로 당신이 더 이상 같은 목적 함수를 구별하지 않기 때문입니다.