深度學習-吳恩達第一課第三週課程作業
第二週的課程作業是利用邏輯迴歸來訓練一個分類器來辨別一張圖片是否為貓,這周老師講了單隱層的神經網路,所以先看看利用這個模型能否在上次作業的基礎上對訓練準確度作出改善
訓練一個神經網路
- 神經網路分為幾層,隱藏層中包含幾個神經元,使用的啟用函式
- 初始化引數 W(i)和 B(i) 搞清楚引數的維度
- 準備資料 X ,Y 同樣的要搞清楚維度
- 向前傳播,計算代價函式,反向傳播,更新參數
下面我們就按這個流程來訓練一個神經網路模型
1.單隱藏層
隱藏層有多少個處理單元可以先設定為引數,方便後面在訓練模型時可以改動,測試處理單元數量不同對模型預測準確度造成的影響。這個神經網路模型只有三層(把輸入層也算進去了),分別用n_x,n_h,n_y表示輸入層,隱藏層,輸出層的處理單元數量。
n_x也就是特徵值(或者稱為屬性)的個數,因為這個 “是不是貓” 的問題是一個二分類問題,所以輸出結果非0即1,輸出層n_y其實為1,但為了統一化標識,還是用n_y來表示。
這個函式輸入訓練資料,獲取每層處理單元數並返回
def layer_size(X,Y):
n_x=X.shape[0]
n_y=Y.shape[0]
return (n_x,n_y)
啟用函式,在隱藏層選了tanh,在輸出層選了sigmoid,一般二分類問題輸出層都會選擇sigmoid,隱藏層可以選擇tanh,ReLU等,有時間可以試試在隱藏層選擇不同啟用函式會有什麼結果,如果要測試的話,可以在向前傳播那裡隱藏層計算時把啟用函式包裝一下,方便後面更改。
2.初始化引數
這裡有四個引數,w1(n_h,n_x),w2(n_y,n_h),b1(n_h,1),b2(n_y,1),其實他們的維度是有規律的,每一個w都是 本層處理單元數*上一層單元數,b都是本層單元數*1,也就是b是一個列向量
def initialize_parameters(n_x,n_h,n_y): np.random.seed(1) #引數要隨機初始化,b可直接初始化為0,*0.01是使得引數儘量小 W1=np.random.randn(n_h,n_x)*0.01 b1 = np.zeros((n_h, 1)) * 0.01 W2=np.random.randn(n_y,n_h)*0.01 b2=np.zeros((n_y,1))*0.01 #檢測引數維度,萬全之策 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
3.資料準備 (X . Y)
這和第二週的資料處理過程是一樣的,這裡直接把程式碼貼過來,不理解處理過程的,走傳送門
train_data = h5py.File('D:\\jupyter\\datasets\\train_catvnoncat.h5','r')
test_data = h5py.File('D:\\jupyter\\datasets\\test_catvnoncat.h5','r')
train_data_x=train_data['train_set_x'][:]
train_data_y=train_data['train_set_y'][:]
test_data_x=test_data['test_set_x'][:]
test_data_y=test_data['test_set_y'][:]
m_train=train_data_x.shape[0]
train_data_finalX=train_data_x.reshape(m_train,-1).T
m_test=test_data_x.shape[0]
test_data_finalX=test_data_x.reshape(m_test,-1).T
train_data_finalY=train_data_y.reshape(1,m_train)
test_data_finalY=test_data_y.reshape(1,m_test)
train_data_finalX=train_data_finalX/255
test_data_finalX=test_data_finalX/255
4.模型訓練
建議自己把向前傳播和反向傳播在紙上畫一畫,搞清楚每個步驟的由來,程式碼其實和那個一模一樣
向前傳播:
def foward_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
計算代價函式:
def compute_cost(A2,Y,parameters):
m=Y.shape[1]
#注意矩陣相乘和矩陣點乘的不同
cost=-np.sum(np.multiply(np.log(A2),Y)+np.multiply(np.log(1-A2),1-Y))/m
#不加這一步可能會出錯
cost=np.squeeze(cost)
assert (isinstance(cost, float))
return cost
反向傳播:
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 = np.dot(dZ2, A1.T) / m
db2 = np.sum(dZ2, axis=1, keepdims=True) / m
dZ1 = np.multiply(np.dot(W2.T, dZ2), (1 - np.power(A1, 2)))
dW1 = np.dot(dZ1, X.T) / m
db1 = np.sum(dZ1, axis=1, keepdims=True) / m
grads = {"dW1": dW1,
"db1": db1,
"dW2": dW2,
"db2": db2}
return grads
整合訓練模型:
def nn_model(X,Y,n_h,num_iterations,alphs,print_cost=False):
n_x,n_y=layer_size(X,Y)
parameters=initialize_parameters(n_x,n_h,n_y)
for i in range(0,num_iterations):
A2,cache=foward_propagation(X,parameters)
#計算代價函式
cost=compute_cost(A2,Y,parameters)
W1 = parameters["W1"]
b1 = parameters["b1"]
W2 = parameters["W2"]
b2 = parameters["b2"]
grads=backward_propagation(parameters,cache,X,Y)
dW1 = grads["dW1"]
db1 = grads["db1"]
dW2 = grads["dW2"]
db2 = grads["db2"]
#更新引數
W1 = W1 - alphs * dW1
b1 = b1 - alphs * db1
W2 = W2 - alphs * dW2
b2 = b2 - alphs * db2
parameters = {"W1": W1,"b1": b1, "W2": W2, "b2": b2}
if print_cost and i%100==0:
print("cost after iteratin %i:%f"%(i,cost))
return parameters
5.模型預測
向前傳播得到的值是一個0.幾,並不是我們需要的預測值,所以還需要對其作出處理,才能得到我們想要的y^
def predict(X,parameters):
A2,cache=foward_propagation(X,parameters)
temp=A2.shape[1]
Y_pred=np.zeros([1,temp])
for i in range(temp):
if A2[:,i]>0.5:
Y_pred[:,i]=1
else:
Y_pred[:,i]=0
return Y_pred
最後帶入資料測試一下:
隱藏層處理單元數為4,迭代次數為2000,學習因子為0.035
parameters = nn_model(train_data_finalX, train_data_finalY, n_h =4, num_iterations = 2000,alphs=0.035, print_cost=True)
y_pred_train=predict(train_data_finalX,parameters)
print('train acc is ',np.mean(y_pred_train == train_data_finalY)*100,'%')
y_pred_test=predict(test_data_finalX,parameters)
print('test acc is ',np.mean(y_pred_test == test_data_finalY)*100,'%')
測試結果:
cost after iteratin 0:0.695140
cost after iteratin 100:0.611964
cost after iteratin 200:0.587018
cost after iteratin 300:0.434994
cost after iteratin 400:0.408077
cost after iteratin 500:0.416949
cost after iteratin 600:0.389969
cost after iteratin 700:0.195698
cost after iteratin 800:0.246980
cost after iteratin 900:0.146227
cost after iteratin 1000:1.087110
cost after iteratin 1100:0.637578
cost after iteratin 1200:0.350186
cost after iteratin 1300:0.266292
cost after iteratin 1400:0.114502
cost after iteratin 1500:0.092060
cost after iteratin 1600:0.077828
cost after iteratin 1700:0.070697
cost after iteratin 1800:0.065766
cost after iteratin 1900:0.062147
train acc is 98.08612440191388 %
test acc is 78.0 %
總結:
相較邏輯迴歸模型這個結果確實是有所提升,但也要選擇合適的引數,如果選擇引數不合適,比如隱藏層單元數過高,迭代數次過高,得到的結果有時還沒有邏輯迴歸的準確度高,怎麼選擇合適的引數也需要不斷嘗試和摸索,但有時候選擇引數不同但得到的結果卻變化不大,也有可能是資料過少。