具有一個隱藏層的神經網絡平面數(shù)據(jù)分類
本篇文章將通過python
構建一個簡單淺層神經網絡(具有一個隱藏層)來分類數(shù)據(jù)。
1, 導入相關包
構建一個淺層神經網絡殉挽,需要導入的相關python
包,具體如下所示:
# Package imports
import numpy as np
import matplotlib.pyplot as plt
import sklearn
import sklearn.datasets
import sklearn.linear_model
%matplotlib inline
np.random.seed(1)
導入相關庫的代碼如上所示,其中扰路,一些庫和代碼的解釋如下:
sklearn
:提供了數(shù)據(jù)挖掘和數(shù)據(jù)分析的一些簡單易用的工具。
np.random.seed(1)
保證了每一次生成的隨機數(shù)是一樣的肠牲,保證了代碼每次運行結果能保持不變幼衰。
2. 數(shù)據(jù)可視化
本次作業(yè)中,所加載的數(shù)據(jù)集是通過python
生成的缀雳,加載數(shù)據(jù)并可視化之后渡嚣,數(shù)據(jù)在直角坐標系上呈現(xiàn)出一個簡單的花的形狀,并且具有兩種顏色肥印。具體實現(xiàn)代碼和效果识椰,如下所示:
- 生成數(shù)據(jù)的代碼如下所示:
def load_planar_dataset():
np.random.seed(1) #固定隨機種子
m = 400 # 樣本的個數(shù)
N = int(m/2) # 某一類樣本的個數(shù)
D = 2 # 數(shù)據(jù)維數(shù)
X = np.zeros((m,D)) #利用數(shù)據(jù)生成矩陣大小,其中深碱,每一個行向量代表一個樣本
Y = np.zeros((m,1), dtype='uint8') # 輸出標簽向量腹鹉,0代表紅色,1代表藍色
a = 4 # 生成花的形狀設置敷硅,四條對稱花瓣
"""
在二維平面上生成數(shù)據(jù)的坐標功咒,可以看成一個極坐標,
t代表的是角度绞蹦,r代表由角度生成的半徑力奋,也就是玫瑰花瓣的長度。最后幽七, 利用參數(shù)方程景殷,將極坐標轉換為直角坐標,
以下兩次循環(huán)中澡屡,第一次生成紅色點的坐標猿挚,
第二次生成藍色點的坐標。
"""
for j in range(2):
ix = range(N*j,N*(j+1))
t = np.linspace(j*3.12,(j+1)*3.12,N) + np.random.randn(N)*0.2 # theta
r = a*np.sin(4*t) + np.random.randn(N)*0.2 #極坐標曲線
X[ix] = np.c_[r*np.sin(t), r*np.cos(t)] #參數(shù)方程標出每個點的坐標驶鹉,并賦值給一個二維向量
Y[ix] = j
X = X.T
Y = Y.T
return X, Y
代碼的詳細解釋如上注釋所示绩蜻,最后利用matplotlib
數(shù)據(jù)可視化,如下所示:
X, Y = load_planar_dataset()
plt.scatter(X[0,:], X[1,:], c=np.squeeze(Y), s=40, cmap=plt.cm.Spectral)
對于生成的數(shù)據(jù)室埋,先查看數(shù)據(jù)的維數(shù)和形狀办绝,以確保后續(xù)的算法實現(xiàn)踏兜,具體實現(xiàn)代碼如下所示:
shape_X = X.shape
shape_Y = Y.shape
m = shape_X[1]
print ('The shape of X is: ' + str(shape_X)) #(2,400)
print ('The shape of Y is: ' + str(shape_Y)) #(1,400)
print ('I have m = %d training examples!' % (m)) #m=400
3. 簡單的邏輯回歸實現(xiàn)
在神經網絡實現(xiàn)之前,作為對比八秃,可以先采用機器學習中的邏輯回歸算法對此問題做出解答碱妆,邏輯回歸實現(xiàn)中,可以直接調用sklearn
包實現(xiàn)昔驱,具體實現(xiàn)代碼如下所示:
#直接調用sklearn包中的方法
clf = sklearn.linear_model.LogisticRegressionCV();
clf.fit(X.T, Y.T);
在邏輯回歸算法實現(xiàn)之前疹尾,先繪出其決策邊界,具體代碼實現(xiàn)骤肛,可以如下所示:
def plot_decision_boundary(model, X, y):
# 設置最大纳本,最小值,并給其添加一些填充
# 這里的x和y代表的是直接坐標腋颠,而不是輸入變量與輸出變量
x_min, x_max = X[0, :].min() - 1, X[0, :].max() + 1
y_min, y_max = X[1, :].min() - 1, X[1, :].max() + 1
h = 0.01
#生成點網格繁成,并將其距離設置為h
xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
"""
將兩個向量合成一個矩陣,x為其行向量淑玫,而y形成其列向量
其實就是生成了一個網絡坐標矩陣巾腕,且xx和yy的形狀一樣
"""
# 預測整個網格的函數(shù)值
Z = model(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
# 繪制輪廓和訓練樣本
plt.contourf(xx, yy, Z, cmap=plt.cm.Spectral)
plt.ylabel('x2')
plt.xlabel('x1')
plt.scatter(X[0, :], X[1, :], c=y, cmap=plt.cm.Spectral)
利用python
繪圖并利用邏輯回歸做出預測,其結果如下所示絮蒿,可以看到尊搬,利用機器學習中的邏輯回歸算法,數(shù)據(jù)集的分類精度只達到了47%土涝,距理想結果相去甚遠佛寿。
# 為邏輯回歸繪制決策邊界
plot_decision_boundary(lambda x: clf.predict(x), X, np.squeeze(Y))
plt.title("Logistic Regression")
#打印訓練精確度
LR_predictions = clf.predict(X.T)
print ('Accuracy of logistic regression: %d ' % float((np.dot(Y,LR_predictions) + np.dot(1-Y,1-LR_predictions))/float(Y.size)*100) +
'% ' + "(percentage of correctly labelled datapoints)")
由于數(shù)據(jù)集并不是線性分布的,所以線性分類中的邏輯回歸效果并不理想但壮,采用以下邏輯回歸算法冀泻,效果可能更加理想。
4. 神經網絡模型
在這一部分中蜡饵,需要構建一個簡單的神經網絡分類器來實現(xiàn)數(shù)據(jù)分類弹渔,構建的神經網絡結構如下圖所示:
對于一個樣本 :
給定所有樣本的預測值,可以用如下公式計算函數(shù)損失值:
構建一個神經網絡的步驟可以如下表示“
- 構建神經網絡验残,輸入單元捞附,輸出單元和隱藏單元等
- 初始化模型參數(shù)
- 循環(huán):
- 計算其前向傳播
- 計算損失
- 利用反向傳播算法計算梯度
- 根據(jù)梯度下降算法更新參數(shù)
4.1 定義神經網絡的結構
如上圖所示的神經網絡結構圖巾乳,我們需要定義神經網絡的輸入層您没,隱藏層和輸出層的神經單元數(shù)目,具體實現(xiàn)代碼如下所示:
def layer_sizes(X, Y):
n_x = 2 #輸入層的單元數(shù)胆绊,輸入變量的特征數(shù)
n_h = 4 #隱藏層的單元數(shù)
n_y = 1 #輸出層的單元
return (n_x, n_h, n_y)
4.2 初始化模型參數(shù)
初始化模型參數(shù)時氨鹏,要根據(jù)神經網絡的結構控制輸出隨機矩陣的形狀,如模型結構圖所示压状,權重參數(shù)可以簡單的理解為輸入層到隱藏層的有向線段數(shù)仆抵,從圖中可以看出跟继,從輸入層到隱藏層的有向線段數(shù)目是8條,特征
分別有4條有向線段指向隱藏層镣丑,所以權重從參數(shù)
的形狀可以直接等效為
舔糖,同理,從隱藏層到輸出層的權重參數(shù)
的形狀為
莺匠。最后金吗,采用隨機初始化的方法初始化權重矩陣,再給
分別乘上0.01趣竣,最后摇庙,整個代碼實現(xiàn)方式如下所示;
def initialize_parameters(n_x, n_h, n_y):
W1 = np.random.randn(n_h,n_x)*0.01
b1 = np.zeros((n_h,1))
W2 = np.random.randn(n_y,n_h)*0.01
b2 = np.zeros((1,1))
# 采用斷言語法,確保每一個參數(shù)形狀正確
assert (W1.shape == (n_h, n_x))
assert (b1.shape == (n_h, 1))
assert (W2.shape == (n_y, n_h))
assert (b2.shape == (n_y, 1))
parameters = {"W1": W1,
"b1": b1,
"W2": W2,
"b2": b2}
return parameters
注意:
表示從均值為0的單位標準高斯分布進行取樣遥缕,因為設置了隨機初始化種子卫袒,所以每次都會生成相同的隨機值。
- 權重參數(shù)乘以0.01是為了防止初始化參數(shù)過大单匣,提前進入激活函數(shù)飽和區(qū)夕凝,從而使收斂速度變慢。
4.3 循環(huán)部分的實現(xiàn)
1) 前向傳播算法的實現(xiàn)
根據(jù)公式(1) - 公式(4)和之前得到的初始化權重參數(shù)户秤,整個前向傳播的實現(xiàn)代碼如下所示:
def forward_propagation(X, parameters):
W1 = parameters['W1']
b1 = parameters['b1']
W2 = parameters['W2']
b2 = parameters['b2']
Z1 = np.dot(W1,X)+b1
A1 = np.tanh(Z1)
Z2 = np.dot(W2,A1)+b2
A2 = 1/(1+np.exp(-Z2))
assert(A2.shape == (1, X.shape[1]))
cache = {"Z1": Z1,
"A1": A1,
"Z2": Z2,
"A2": A2}
return A2, cache
2) 損失函數(shù)的計算
有了以上前向傳播函數(shù)的計算迹冤,循環(huán)第二步中計算損失函數(shù)的過程根據(jù)公式(6)如下所示:
def compute_cost(A2, Y):
m = Y.shape[1] #樣本數(shù) m = 400
logprobs = np.multiply(np.log(A2),Y)+np.multiply(np.log(1-A2),(1-Y))
cost = -1/m *np.sum(logprobs)
cost = np.squeeze(cost)
assert(isinstance(cost, float))
return cost
3) 反向傳播函數(shù)的計算
完成以上步驟之后,就可以實現(xiàn)一個反向傳播算法了虎忌,反向傳播算法的計算簡單來說就是一個從后往前按照神經網絡的結構和導數(shù)的鏈式計算法則一次求導的過程泡徙,其具體公式如下所示:
根據(jù)以上公式,其算法實現(xiàn)的代碼如下所示:
def backward_propagation(parameters, cache, X, Y):
m = X.shape[1]
W1 = parameters['W1']
W2 = parameters['W2']
A1 = cache['A1']
A2 = cache['A2']
dZ2 = A2-Y
dW2 = 1/m*np.dot(dZ2,A1.T)
db2 = 1/m*np.sum(dZ2,axis = 1,keepdims = True)
dZ1 = np.dot(W2.T,dZ2)*(1-(np.tanh(np.dot(W1,X)))**2)
dW1 = 1/m*np.dot(dZ1,X.T)
db1 = 1/m*np.sum(dZ1,axis = 1,keepdims = True)
grads = {"dW1": dW1,
"db1": db1,
"dW2": dW2,
"db2": db2}
return grads
4) 梯度更新
有了以上對于梯度的計算膜蠢,現(xiàn)在可以根據(jù)相關公式堪藐,進行梯度更新了,具體公式和代碼實現(xiàn)如下所示:
梯度更新的公式如下所示:
代碼實現(xiàn)如下所示:
def update_parameters(parameters, grads, learning_rate = 1.2):
W1 = parameters['W1']
b1 = parameters['b1']
W2 = parameters['W2']
b2 = parameters['b2']
dW1 = grads['dW1']
db1 = grads['db1']
dW2 = grads['dW2']
db2 = grads['db2']
W1 -=learning_rate*dW1
b1 -= learning_rate*db1
W2 -= learning_rate*dW2
b2 -= learning_rate*db2
parameters = {"W1": W1,
"b1": b1,
"W2": W2,
"b2": b2}
return parameters
綜上挑围,將所有代碼和公式結合在一起礁竞,利用多次迭代實現(xiàn)梯度下降算法的代碼如下所示:
def nn_model(X, Y, n_h, num_iterations = 10000, print_cost=False):
np.random.seed(2)
n_x = layer_sizes(X, Y)[0]
n_y = layer_sizes(X, Y)[2]
parameters = initialize_parameters(n_x,n_h,n_y)
W1 = parameters['W1']
b1 = parameters['b1']
W2 = parameters['W2']
b2 = parameters['b2']
costs = list()
for i in range(0, num_iterations):
A2, cache = forward_propagation(X, parameters)
cost = compute_cost(A2,Y)
grads = backward_propagation(parameters, cache, X, Y)
parameters = update_parameters(parameters,grads)
if print_cost and i % 1000 == 0:
print ("Cost after iteration %i: %f" %(i, cost))
return parameters
為以上代碼,編寫測試代碼如下所示:
parameters,costs = nn_model(X, Y, 4, num_iterations=10000, print_cost=True)
print("W1 = " + str(parameters["W1"]))
print("b1 = " + str(parameters["b1"]))
print("W2 = " + str(parameters["W2"]))
print("b2 = " + str(parameters["b2"]))
x_f = np.linspace(0,1000,10000)
plt.plot(x_f,costs)
plt.show()
運行結果如下所示:
簡單繪出梯度下降的圖形杉辙,可以看出模捂,通過一個淺層的神經網絡,損失逐漸變小并收斂蜘矢。
4.4 做出預測
根據(jù)構建神經網絡并通過梯度下降算法得到了權重參數(shù)之后狂男,根據(jù)公式(17)就可以做出預測了,具體實現(xiàn)代碼如下所示:
predictions =
def predict(parameters, X):
A2, cache = forward_propagation(X, parameters)
predictions = np.zeros((1,m))
for i in range(m):
if A2[0,i]>=0.5:
predictions[0,i] = 1
else:
predictions[0,i] = 0
return predictions
輸出預測結果品腹,如下所示:
parameters,costs = nn_model(X, Y, n_h = 4, num_iterations = 20000, print_cost=False)
predictions = predict(parameters, X)
print(predictions,predictions.shape)
print("predictions mean = " + str(np.mean(predictions)))
根據(jù)代碼繪制決策邊界岖食,并輸出精確度,如下所示舞吭,可以看出泡垃,分類精確度達到了90%析珊,比邏輯回歸算法的47%高出了很多。
parameters,costs= nn_model(X, Y, n_h = 4, num_iterations = 10000, print_cost=True)
print(parameters)
plot_decision_boundary(lambda x:predict(parameters,x.T),X,Y)
plt.title("Decision Boundary for hidden layer size " + str(4))
# Print accuracy
predictions = predict(parameters, X)
print ('Accuracy: %d' % float((np.dot(Y,predictions.T) + np.dot(1-Y,1-predictions.T))/float(Y.size)*100) + '%')