y = a + bx 的目標函數
上一篇文章,我們解釋了線性,本文我們回到求解線性回歸目標函數的問題上。前面已知,線性回歸的目標函數為:
J(a,b)=12m∑mi=1(a+bx(i)?y(i))2
J(a,b) 是一個二元函數。我們要求的是:兩個參數 a 和 b 的值。要滿足的條件是:a 和 b 取這個值的時候,J(a,b) 的值達到最小。
我們現在就來用之前講過的算法:梯度下降法,來對其進行求解。
斜率、導數和偏微分
梯度下降法我們前面也講過步驟,總結起來就是:從任意點開始,在該點對目標函數求導,沿著導數方向(梯度)“走”(下降)一個給定步長,如此循環迭代,直至“走”到導數為0的位置,則達到極小值。
為什么要求導呢?從下圖可以看到:曲線表示一個函數,它在一個點處的導數值就是經過這個點的函數曲線切線的斜率。
導數表現的是函數 f(x) 在 x 軸上某一點 x0 處,沿著 x 軸正方向的變化率/變化趨勢,記作 f′(x0)。
在 x 軸上某一點處,如果 f′(x0)>0 ,說明 f(x) 的函數值在 x0 點沿 x 軸正方向是趨于增加的;如果 f′(x0)<0,說明 f(x) 的函數值在 x0 點沿 x 軸正方向是趨于減少的。
一元函數在某一點處沿 x 軸正方向的變化率稱為導數。但如果是二元或更多元的函數(自變量維度 >=2),則某一點處沿某一維度坐標軸正方向的變化率稱為偏導數。
導數/偏導數表現的是變化率,而變化本身,用另一個概念來表示,這個概念就是微分(對應偏導數,二元及以上函數有偏微分)。
(偏)導數是針對函數上的一個點而言的,是一個值。而(偏)微分則是一個函數,其中的每個點表達的是原函數上各點沿著(偏)導數方向的變化。
直觀而不嚴格的來說,(偏)微分就是沿著(偏)導數的方向,產生了一個無窮小的增量。
想想我們的梯度下降算法,我們要做的不就是在一個個點上(沿著導數方向)向前走一小步嗎?
當我們求出了一個函數的(偏)微分函數后,將某個變量帶入其中,得出的(偏)微分函數對應的函數值,就是原函數在該點處,對該自變量求導的導數值。
所以,只要我們求出了目標函數的(偏)微分函數,那么目標函數自變量值域內每一點的導數值也就都可以求了。
如何求一個函數的(偏)微分函數呢?這個我們只需要記住最基本的求導規則就好,函數(整體,而非在一個點處)求導的結果,就是微分函數了。
本文會用到的僅僅是常用規則中最常用的幾條:
- 常數的導數是零:(c)' = 0;
- x 的 n 次冪的導數是 n 倍的 x 的 n-1 次冪:(xn)′=nxn?1;
- 對常數乘以函數求導,結果等于該常數乘以函數的導數:(cf)' = cf';
- 兩個函數 f 和 g 的和的導數為:(f+g)' = f' + g';
- 兩個函數 f 和 g 的積的導數為:(fg)' = f'g + fg'。
梯度下降求解目標函數
對于 J(a,b) 而言,有兩個參數 a 和 b,函數 J 分別對自變量 a 和 b 取偏微分的結果是:
?J(a,b)?a=1(m)∑mi=1((a+bx(i))?y(i))
?J(a,b)?b=1(m)∑mi=1x(i)((a+bx(i))?y(i))
所以我們要做得是:
Step 1:任意給定 a 和 b 的初值。
a = 0; b = 0;
Step 2:用梯度下降法求解 a 和 b,偽代碼如下:
repeatuntilconvergence{a=a?α?J(a,b)?a
b=b?α?J(a,b)?b
}
當下降的高度小于某個指定的閾值(近似收斂至最優結果),則停止下降。
將上面展開的式子帶入上面的代碼,就是:
repeatuntilconvergence{
sumA=0
sumB=0
fori=1tom{sumA=sumA+(a+bx(i)?y(i))sumB=sumB+x(i)(a+bx(i)?y(i)) }
a=a?αsumAm
b=b?αsumBm
}
通用線性回歸模型的目標函數求解
y = a + bx 是一個線性回歸模型,這個沒問題。不過,反過來,線性回歸模型只能是 y = a + bx 的形式嗎?當然不是。
y = a + bx => f(x) = a + bx 實際上是線性回歸模型的一個特例——自變量只有一個維度的特例,在這個模型中,自變量 x 是一個一維向量,可寫作 [x]。
通用的線性回歸模型,是接受 n 維自變量的,也就是說自變量可以寫作 [x1,x2,...,xn] 形式。于是,相應的模型函數寫出來就是這樣的:
f(x1,x2,...,xn)=a+b1x1+b2x2+...+bnxn
這樣寫參數有點混亂,我們用 θ0 來代替 a, 用 θ1 到 θn 來代替 b1 到 bn,那么寫出來就是這樣的:
f(1,x1,x2,...,xn)=θ0+θ1x1+θ2x2+...+θnxn
我們設 x0=1, 因此:
f(x0,x1,x2,...,xn)=θ0x0+θ1x1+θ2x2+...+θnxn
那么對應的,n 維自變量的線性回歸模型對應的目標函數就是:
J(θ0,θ1,...,θn)=1(2m)∑mi=1(y′(i)?y(i))2=1(2m)∑mi=1(θ0+θ1x(i)1+θ2x(i)2+...+θnx(i)n?y(i))2
再設:
X=[x0,x1,x2,...,xn],Θ=[θ0,θ1,θ2,...,θn]
然后將模型函數簡寫成:
f(X)=ΘTX
根據習慣,我們在這里將 f(X) 寫作 h(X),因此,模型函數就成了:
h(X)=ΘTX
相應的目標函數就是:
J(Θ)=1(2m)∑mi=1(hθ(X(i))?y(i))2
同樣應用梯度下降,實現的過程是:
repeatuntilconvergence{Θ=Θ?α?J(Θ)?Θ
}
細化為針對 theta_j 的形式就是:
repeatuntilconvergence{
forj=1ton{
sumj=0
fori=1tom{
sumj=sumj+(θ0+θ1x(i)1+θ2x(i)2+...+θnx(i)n?y(i))x(i)j
}
θj=θj?αsumjm
}
}
這就是梯度下降的通用形式。
線性回歸的超參數
作為一個線性回歸模型,本身的參數是 Θ,在開始訓練之前,Θ(無論是多少維),具體的數值都不知道,訓練過程就是求解 Θ 中各維度數值的過程。
當我們使用梯度下降求解時,梯度下降算法中的步長參數:α,就是訓練線性回歸模型的超參數。
訓練程序通過梯度下降的計算,自動求出了 Θ 的值。而 α 卻是無法求解的,必須手工指定。反之,如果沒有指定 α,梯度下降運算則根本無法進行。
- 對于線性回歸而言,只要用到梯度下降,就會有步長參數 alpha 這個超參數。
如果訓練結果偏差較大,可以嘗試調小步長;如果模型質量不錯但是訓練效率太低,可以適當放大步長;也可以嘗試使用動態步長,開始步長較大,隨著梯度的縮小,步長同樣縮小……
如果訓練程序是通過人工指定迭代次數來確定退出條件,則迭代次數也是一個超參數。
如果訓練程序以模型結果與真實結果的整體差值小于某一個閾值為退出條件,則這個閾值就是超參數。
在模型類型和訓練數據確定的情況下,超參數的設置就成了影響模型最終質量的關鍵。
而往往一個模型會涉及多個超參數,如何制定策略在最少嘗試的情況下讓所有超參數設置的結果達到最佳,是一個在實踐中非常重要又沒有統一方法可以解決的問題。
在實際應用中,能夠在調參方面有章法,而不是亂試一氣,就有賴于大家對于模型原理和數據的掌握了。
編寫線性回歸訓練/預測程序
如果我們要用代碼實現線性回歸程序應該怎樣做呢?當然,你可以按照上面的描述,自己從頭用代碼實現一遍。
不過,其實不必。因為我們已經有很多現成的方法庫,可以直接調用了。
最常見的是 sklearn 庫。下面的例子就對應最開始的經驗和工資的問題。我們用前 7 個數據作為訓練集,后面 4 個作為測試集,來看看結果:
最終結果是這個樣子的: