神經網路入門之Logistic迴歸(分類問題)
Logistic迴歸(分類問題)
這部分教程將介紹一部分:
- Logistic分類模型
我們在上次的教程中給出了一個很簡單的模型,只有一個輸入和一個輸出。在這篇教程中,我們將構建一個二分類模型,輸入引數是兩個變數。這個模型在統計上被稱為Logistic迴歸模型,網路結構可以被描述如下:
Logistic迴歸模型
我們先匯入教程需要使用的軟體包。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import colorConverter, ListedColormap
from matplotlib import cm
定義類分佈
在教程中,目標分類t
將從兩個獨立分佈中產生,當t=1
時,用藍色表示。當t=0
時,用紅色表示。輸入引數X
是一個N*2
的矩陣,目標分類t
是一個N
* 1
的向量。更直觀的表現,見下圖。
# Define and generate the samples
nb_of_samples_per_class = 20 # The number of sample in each class
red_mean = [-1,0] # The mean of the red class
blue_mean = [1,0] # The mean of the blue class
std_dev = 1.2 # standard deviation of both classes
# Generate samples from both classes
x_red = np.random.randn(nb_of_samples_per_class, 2) * std_dev + red_mean
x_blue = np.random.randn(nb_of_samples_per_class, 2) * std_dev + blue_mean
# Merge samples in set of input variables x, and corresponding set of output variables t
X = np.vstack((x_red, x_blue))
t = np.vstack((np.zeros((nb_of_samples_per_class,1)), np.ones((nb_of_samples_per_class,1))))
# Plot both classes on the x1, x2 plane
plt.plot(x_red[:,0], x_red[:,1], 'ro', label='class red')
plt.plot(x_blue[:,0], x_blue[:,1], 'bo', label='class blue')
plt.grid()
plt.legend(loc=2)
plt.xlabel('$x_1$', fontsize=15)
plt.ylabel('$x_2$', fontsize=15)
plt.axis([-4, 4, -4, 4])
plt.title('red vs. blue classes in the input space')
plt.show()
red vs. blue classes in the input space
Logistic函式和交叉熵損失函式
Logistic函式
我們設計的網路的目的是從輸入的x
去預測目標t
。假設,輸入x
= [x1, x2]
,權重w = [w1, w2]
,預測目標t
= 1
。那麼,概率P(t = 1|x, w)
將是神經網路輸出的y
,即y
= σ(x∗wT)
。其中,σ
表示Logistic函式
,定義如下:
Logistic函式
如果,對於Logistic函式和它的導數還不是很清楚的,可以檢視這個教程,裡面進行了詳細描述。
交叉熵損失函式
對於這個分類問題的損失函式優化,我們使用交叉熵誤差函式來解決,對於每個訓練樣本i
,交叉熵誤差函式定義如下:
每個樣本
i
的交叉熵誤差函式
如果我們要計算整個訓練樣本的交叉熵誤差,那麼只需要把每一個樣本的值進行累加就可以了,即:
交叉熵誤差函式
關於交叉熵誤差函式更加詳細的介紹可以看這個教程。
logistic(z)
函式實現了Logistic
函式,cost(y,
t)
函式實現了損失函式,nn(x, w)
實現了神經網路的輸出結果,nn_predict(x,
w)
實現了神經網路的預測結果。
# Define the logistic function
def logistic(z):
return 1 / (1 + np.exp(-z))
# Define the neural network function y = 1 / (1 + numpy.exp(-x*w))
def nn(x, w):
return logistic(x.dot(w.T))
# Define the neural network prediction function that only returns
# 1 or 0 depending on the predicted class
def nn_predict(x,w):
return np.around(nn(x,w))
# Define the cost function
def cost(y, t):
return - np.sum(np.multiply(t, np.log(y)) + np.multiply((1-t), np.log(1-y)))
# Plot the cost in function of the weights
# Define a vector of weights for which we want to plot the cost
nb_of_ws = 100 # compute the cost nb_of_ws times in each dimension
ws1 = np.linspace(-5, 5, num=nb_of_ws) # weight 1
ws2 = np.linspace(-5, 5, num=nb_of_ws) # weight 2
ws_x, ws_y = np.meshgrid(ws1, ws2) # generate grid
cost_ws = np.zeros((nb_of_ws, nb_of_ws)) # initialize cost matrix
# Fill the cost matrix for each combination of weights
for i in range(nb_of_ws):
for j in range(nb_of_ws):
cost_ws[i,j] = cost(nn(X, np.asmatrix([ws_x[i,j], ws_y[i,j]])) , t)
# Plot the cost function surface
plt.contourf(ws_x, ws_y, cost_ws, 20, cmap=cm.pink)
cbar = plt.colorbar()
cbar.ax.set_ylabel('$\\xi$', fontsize=15)
plt.xlabel('$w_1$', fontsize=15)
plt.ylabel('$w_2$', fontsize=15)
plt.title('Cost function surface')
plt.grid()
plt.show()
Cost function surface
梯度下降優化損失函式
梯度下降演算法的工作原理是損失函式ξ
對於每一個引數的求導,然後沿著負梯度方向進行引數更新。
引數w
按照一定的學習率沿著負梯度方向更新,即w(k+1)=w(k)−Δw(k+1)
,其中Δw
可以表示為:
Δw
對於每個訓練樣本i
,∂ξi/∂w
計算如下:
損失函式對於權重的導數
其中,yi=σ(zi)
是神經元的Logistic
輸出,zi=xi∗wT
是神經元的輸入。
在詳細推導損失函式對於權重的導數之前,我們先這個教程中摘取幾個推導。
分步推導
參考上面的分步推導,我們可以得到下面的詳細推導:
詳細推導
因此,對於每個權重的更新Δwj
可以表示為:
每個權重的更新
在批處理中,我們需要將N
個樣本的梯度都進行累加,即:
批處理更新
在開始梯度下降演算法之前,你需要對引數都進行一個隨機數賦值過程,然後採用梯度下降演算法更新引數,直至收斂。
gradient(w, x, t)
函式實現了梯度∂ξ/∂w
,delta_w(w_k,
x, t, learning_rate)
函式實現了Δw
。
# define the gradient function.
def gradient(w, x, t):
return (nn(x, w) - t).T * x
# define the update function delta w which returns the
# delta w for each weight in a vector
def delta_w(w_k, x, t, learning_rate):
return learning_rate * gradient(w_k, x, t)
梯度下降更新
我們在訓練集X
上面執行10
次去做預測,下圖中畫出了前三次的結果,圖中藍色的點表示在第k
次,w(k)
的值。
# Set the initial weight parameter
w = np.asmatrix([-4, -2])
# Set the learning rate
learning_rate = 0.05
# Start the gradient descent updates and plot the iterations
nb_of_iterations = 10 # Number of gradient descent updates
w_iter = [w] # List to store the weight values over the iterations
for i in range(nb_of_iterations):
dw = delta_w(w, X, t, learning_rate) # Get the delta w update
w = w-dw # Update the weights
w_iter.append(w) # Store the weights for plotting
# Plot the first weight updates on the error surface
# Plot the error surface
plt.contourf(ws_x, ws_y, cost_ws, 20, alpha=0.9, cmap=cm.pink)
cbar = plt.colorbar()
cbar.ax.set_ylabel('cost')
# Plot the updates
for i in range(1, 4):
w1 = w_iter[i-1]
w2 = w_iter[i]
# Plot the weight-cost value and the line that represents the update
plt.plot(w1[0,0], w1[0,1], 'bo') # Plot the weight cost value
plt.plot([w1[0,0], w2[0,0]], [w1[0,1], w2[0,1]], 'b-')
plt.text(w1[0,0]-0.2, w1[0,1]+0.4, '$w({})$'.format(i), color='b')
w1 = w_iter[3]
# Plot the last weight
plt.plot(w1[0,0], w1[0,1], 'bo')
plt.text(w1[0,0]-0.2, w1[0,1]+0.4, '$w({})$'.format(4), color='b')
# Show figure
plt.xlabel('$w_1$', fontsize=15)
plt.ylabel('$w_2$', fontsize=15)
plt.title('Gradient descent updates on cost surface')
plt.grid()
plt.show()
weight updates on the error surface
訓練結果視覺化
下列程式碼,我們將訓練的結果進行視覺化。
# Plot the resulting decision boundary
# Generate a grid over the input space to plot the color of the
# classification at that grid point
nb_of_xs = 200
xs1 = np.linspace(-4, 4, num=nb_of_xs)
xs2 = np.linspace(-4, 4, num=nb_of_xs)
xx, yy = np.meshgrid(xs1, xs2) # create the grid
# Initialize and fill the classification plane
classification_plane = np.zeros((nb_of_xs, nb_of_xs))
for i in range(nb_of_xs):
for j in range(nb_of_xs):
classification_plane[i,j] = nn_predict(np.asmatrix([xx[i,j], yy[i,j]]) , w)
# Create a color map to show the classification colors of each grid point
cmap = ListedColormap([
colorConverter.to_rgba('r', alpha=0.30),
colorConverter.to_rgba('b', alpha=0.30)])
# Plot the classification plane with decision boundary and input samples
plt.contourf(xx, yy, classification_plane, cmap=cmap)
plt.plot(x_red[:,0], x_red[:,1], 'ro', label='target red')
plt.plot(x_blue[:,0], x_blue[:,1], 'bo', label='target blue')
plt.grid()
plt.legend(loc=2)
plt.xlabel('$x_1$', fontsize=15)
plt.ylabel('$x_2$', fontsize=15)
plt.title('red vs. blue classification boundary')
plt.show()
訓練結果視覺化