1.2 logistic 回歸
視訊: 第二周 神經網絡基礎 整理: 飛龍
logistic 回歸屬于廣義線性回歸。所謂廣義線性回歸,就是線上性回歸的模型上加一些東西,使其适應不同的任務。
logitic 回歸雖然名字裡有回歸,但是它解決的是二進制分類問題。二進制分類問題中,标簽隻有兩個值。一個典型的二進制分類是輸入一張圖檔,判斷是不是貓。
首先來看假設,我們的假設是這樣的:
P(y=1|x)=σ(θTx)
某個樣本 (x,y) 是正向分類的機率是 x 乘權重 θ 再套個 sigmoid 函數,非常簡單。這兩個東西都是列向量。
sigmoid 函數用 σ(x) 表示,圖像是 S 型的,值域是 (0,1),正好符合機率的要求。它的導數用函數值來表達更加友善,dσdx=σ(1−σ)。
注:
我的習慣是,把 w(權重)和 b(偏置)打包在一起,稱為 θ,因為這樣節省很多計算。而且易于擴充,如果你需要偏置項,給 w 多加一項,給 x 添加一個 1,如果不需要,保持原樣即可。
為了找出最優的 θ,像通常一樣,我們需要一個損失函數,然後使其最小。
z=θTxa=σ(z)l=−ylog(a)−(1−y)log(1−a)
這個函數為什麼能用,需要解釋一下。當 y 是 1 的時候,l=−log(a)。如果我們要使 l 最小,就是使 a 最大。因為 sigmoid 函數最大值為 1,是以實際上,我們使 a 接近 1。
當 y 是 0 的時候,l=−log(1−a)。同理,我們使 a 最小,因為 sigmoid 函數最小值為 0,就是使 a 接近 0。
無論如何,我們都使 a 盡可能接近 y。
我們需要一個大的損失函數,衡量模型在所有樣本上的表現。我們用 x(i) 表示第 i 個樣本的特征。
J=−∑i(y(i)log(a(i))+(1−y(i))log(1−a(i)))
然後我們需要求 J 對 θ 的導數。
dJda(i)=1−y(i)1−a(i)−y(i)a(i)da(i)dz(i)=a(i)(1−a(i))dz(i)dθ=x(i)dJdz(i)=a(i)−y(i)dJdθ=∑i((a(i)−y(i))x(i))
(1)如果你拆成了 w 和 b,那麼 dJdb 就是 ∑idJdz(i),dJdw 和 dJdθ 一樣。
(2)所有導數以及 J 都需要除以 ndata,但為了簡潔我省略了,下同。
(3)在機器學習(以及數值計算)中,沒有必要區分導數和偏導數,導數可以看出偏導數的一進制特例。是以這裡我都使用了導數的符号。
我們可以看到最終的導數和線性回歸一樣,仍然是損失乘以特征再求和。
向量化
我的習慣是,将 x(i) 按行堆疊變成 X,也就是行是樣本,列是特征,和咱們能夠獲得的絕大多數資料集一緻。
X=⎡⎣⎢⎢⎢⎢⎢⎢⎢⎢⋮− x(i) −⋮⎤⎦⎥⎥⎥⎥⎥⎥⎥⎥=⎡⎣⎢⎢⎢⎢⎢⎢⋯|xj|⋯⎤⎦⎥⎥⎥⎥⎥⎥
由于 X 按行堆疊,我們需要把它放在矩陣乘法的左邊。這樣出來的 Z 也是按行堆疊的。
Z=Xθ=⎡⎣⎢⎢⎢⎢⎢⎢⎢⎢⋮z(i)⋮⎤⎦⎥⎥⎥⎥⎥⎥⎥⎥
A 相當于對 Z 的每個元素應用 sigmoid 函數,也是類似的結構:
A=σ(Z)=⎡⎣⎢⎢⎢⎢⎢⎢⎢⎢⋮a(i)⋮⎤⎦⎥⎥⎥⎥⎥⎥⎥⎥
接下來是損失函數 J:
J=−Sum(Y∗log(A)+(1−Y)∗log(1−A))
其中 ∗ 表示逐元素相乘。
接下來是導數:
dJdZ=A−Y
這個還是比較好求的。
dZdθ=XdJdθ=XT(A−Y)
這裡有一個方法,就是核對矩陣的維數。我們已經知道 dJdθ 是兩個導數相乘,并且 dJdZ 是
n_data x 1
的矩陣,dZdθ 是
n_data x x_feature
的矩陣,dJdθ 是
n_feature x 1
的矩陣。根據矩陣乘法,它隻能是 XT(A−Y)。
嚴格來講,向量化的導數應該稱為梯度。這個筆記中不區分這兩個術語。
梯度下降法
在代數中,如果我們需要求出一個凸函數的最值,我們可能會使導數等于 0,然後解出方程。但在機器學習中,我們使用梯度下降法來求凸函數的最值。
梯度下降法是,對于每個自變量 x,疊代執行以下操作:
x:=x−αdydx
其中 α 是學習率,一般選取 0 ~ 1 之間的值。
下面直覺地解釋一下。這是一個一進制函數,它的形狀是一個碗,或者山谷。
我們可以随便選一個點作為初始值。你可以選
,也可以選
1
或者随機值。這個無所謂,因為函數是凸的,沿任意路徑下降都會達到全局最優值。
如果你的初始值在右側,那麼導數為正,減去它的一部分相當于向左移動了一小步。如果你的初始值在左側,導數為負,減去它的一部分相當于向右移動了一小步。總之,這樣會使 x 向着全局最優的方向移動。
多元的凸函數是這樣。如果你的每個自變量都減去它的導數(梯度)的一部分,那麼所有自變量就相當于向着最陡的方向移動了一小步。如果你在一個山谷中,沿着最陡的方向向下走,就會到達谷底。
代碼
向量化的公式很容易用 NumPy 代碼來表示。
theta = np.random.rand(n_features, 1)
for _ in range(max_iter):
Z = np.dot(X, theta)
A = sigmoid(Z)
dJ_dZ = (A - Y) / n_data
dJ_dtheta = np.dot(X.T, dJ_dZ)
theta -= alpha * dJ_dtheta