從新發現梯度降低法--backtracking line search

一直覺得梯度降低很簡單的,結果最近發現我寫的一個梯度降低特別慢,後來終於找到緣由:step size的選擇很關鍵,有一種叫backtracking line search的梯度降低法就很是高效,該算法描述見下圖:python

 

下面用一個簡單的例子來展現,給一個無約束優化問題:算法

minimize y = (x-3)*(x-3)app

下面是python代碼,比較兩種方法優化

# -*- coding: cp936 -*-
#optimization test, y = (x-3)^2
from matplotlib.pyplot import figure, hold, plot, show, xlabel, ylabel, legend
def f(x):
        "The function we want to minimize"
        return (x-3)**2
def f_grad(x):
        "gradient of function f"
        return 2*(x-3)
x = 0
y = f(x)
err = 1.0
maxIter = 300
curve = [y]
it = 0
step = 0.1
#下面展現的是我以前用的方法,看上去貌似還挺合理的,可是很慢
while err > 1e-4 and it < maxIter:
    it += 1
    gradient = f_grad(x)
    new_x = x - gradient * step
    new_y = f(new_x)
    new_err = abs(new_y - y)
    if new_y > y: #若是出現divergence的跡象,就減少step size
        step *= 0.8
    err, x, y = new_err, new_x, new_y
    print 'err:', err, ', y:', y
    curve.append(y)

print 'iterations: ', it
figure(); hold(True); plot(curve, 'r*-')
xlabel('iterations'); ylabel('objective function value')

#下面展現的是backtracking line search,速度很快
x = 0
y = f(x)
err = 1.0
alpha = 0.25
beta = 0.8
curve2 = [y]
it = 0

while err > 1e-4 and it < maxIter:
    it += 1
    gradient = f_grad(x)
    step = 1.0
    while f(x - step * gradient) > y - alpha * step * gradient**2:
        step *= beta
    x = x - step * gradient
    new_y = f(x)
    err = y - new_y
    y = new_y
    print 'err:', err, ', y:', y
    curve2.append(y)

print 'iterations: ', it
plot(curve2, 'bo-')
legend(['gradient descent I used', 'backtracking line search'])
show()

運行結果以下圖:spa

 

孰優孰劣,一目瞭然code

個人方法用了25次迭代,而backtracking line search只用了6次。(並且以前我用的方法不必定會收斂的,好比你把第一種方法的stepsize改爲1,就會發現,沒有收斂到最優解就中止了,這是一個bug,要注意)blog

這只是個toy example,在我真實使用的優化問題上,二者的效率差異更加顯著,估計有10倍的樣子it

 

-- io

文章中截圖來自:https://www.youtube.com/watch?v=nvZF-t2ltSMfunction

(是cmu的優化課程)

相關文章
相關標籤/搜索