機器學習中常見優化方法彙總

世有因果知因求果發表於2018-08-25

http://www.scipy-lectures.org/advanced/mathematical_optimization/index.html#a-review-of-the-different-optimizers

機器學習中數學優化專門用於解決尋找一個函式的最小值的問題。這裡的函式被稱為cost function或者objective function,或者energy:損失函式或者目標函式。

更進一步,在機器學習優化中,我們並不依賴於被優化的函式的數學解析表示式,我們通過使用$scipy.optimize$從而實現類似黑盒優化。

瞭解你的優化問題本身

並不是所有的優化問題都是一樣的,如果你能對你待優化的問題本身有一個深刻的理解,這樣可以選擇正確的優化方法。

1.其中非常重要的一點就是要考察問題本身的維數。問題本身資料的維數(標量變數的個數)決定了優化問題的規模。

2.convex和non-convex優化

 

凸函式的特徵:

  • $f$總是在其切線之上
  • 或者說,對於兩個點$A,B$,如果$A<C<B$,則$f(C)$總是線上段$f(A),f(B)$之間

凸函式優化相對非常簡單。

 3.函式光滑與否(是否處處可導)

4. loss函式以及gradient函式是否存在噪聲

如果gradient沒有解析式,那麼我們都須通過計算式計算,這必然導致誤差。

5. 是否有限制條件

比如,下圖中就要求優化只能在$x_1,x_2 \in (-1,1)$間優化

常見的優化方法

Brent’s method 

理論依據是中值定理,對於一個連續函式,$f$,如果兩個端點a,b的函式值$f(a)f(b)<0$,則$(a,b)$之間必然存在一個駐點(導數為0),我們可以不斷迭代最終求得駐點;

from scipy import optimize
def f(x):
    return -np.exp(-(x - 0.7)**2)
result = optimize.minimize_scalar(f)
result.success # check if solver was successful

x_min = result.x

gradient based methods

簡單梯度下降法

原理如教科書的描述,根據梯度下降的方向去做數值變更和迭代,最終求得駐點。

存在的問題是:引數調整時可能反覆跨過駐點從而形成震盪,雖然減少引數調整的布幅可以減輕這個問題,但是無法徹底解決。

共軛梯度下降

共軛演算法在簡單梯度下降基礎上增加一個摩擦項(friction term),每個step依賴於梯度最近的兩個值,這樣可以有效解決反覆震盪問題。

def f(x):   # The rosenbrock function
    return .5*(1 - x[0])**2 + (x[1] - x[0]**2)**2
optimize.minimize(f, [2, -1], method="CG")    

梯度優化方法需要loss函式的雅可比(梯度)值,雖然即使你不傳入導數(雅可比矩陣是針對y值為向量的情況下的梯度向量),演算法也能夠通過數值計算方法算出來,但是如果有解析表示式,我們傳入這個值會大大提升收斂效率.

def jacobian(x):
    return np.array((-2*.5*(1 - x[0]) - 4*x[0]*(x[1] - x[0]**2), 2*(x[1] - x[0]**2)))
optimize.minimize(f, [2, 1], method="CG", jac=jacobian)    

注意:通過傳入解析表示式後,只需要28次就能收斂,而之前需要108次迭代才能收斂。

牛頓梯度法(Newton and quasi-newton methods)

def f(x):   # The rosenbrock function
    return .5*(1 - x[0])**2 + (x[1] - x[0]**2)**2
def jacobian(x):
    return np.array((-2*.5*(1 - x[0]) - 4*x[0]*(x[1] - x[0]**2), 2*(x[1] - x[0]**2)))
optimize.minimize(f, [2,-1], method="Newton-CG", jac=jacobian)    

BFGS

BFGS在牛頓法基礎上細調了Hessian矩陣的估算方法

L-BFGS

L-BFGS位於BFGS和共軛梯度法之間。對於非常高維(大於250個)的loss函式,Hessian矩陣的計算是非常耗時的,L-BFGS keeps a low-rank version.

非梯度優化方法

Powell演算法

Nelder-Mead

帶約束條件的函式優化

盒子邊界

 

def f(x):
   return np.sqrt((x[0] - 3)**2 + (x[1] - 2)**2)
optimize.minimize(f, np.array([0, 0]), bounds=((-1.5, 1.5), (-1.5, 1.5))) 

 通用約束:拉格朗日乘數法化約束為對偶無約束的優化問題

 

def f(x):
    return np.sqrt((x[0] - 3)**2 + (x[1] - 2)**2)

def constraint(x):
    return np.atleast_1d(1.5 - np.sum(np.abs(x)))

x0 = np.array([0, 0])
optimize.minimize(f, x0, constraints={"fun": constraint, "type": "ineq"}) 

 

相關文章