深度學習-吳恩達第一課第四周課程作業
在前面兩節課的基礎上,這次作業是訓練一個N層神經網路,來判斷一張圖片是否有貓,實現過程其實和第三週很相似,因為層數不確定,所以在向前傳播和反向傳播的時候會用到for迴圈,程式碼相對而言反而更精簡了。貼出的程式碼可能和老師給的模板不一樣,我沒有看到老師的原版課程作業,也是在網上找的資料自己寫的,但是網上的程式碼大部分函式封裝度高,但初學為了方便,也好理解,我沒有采用那種方法。
簡單介紹一下模型,N層,傳入每層的單元數,包括最後的輸出層,這裡我們是一個二分類問題,最後一層單元數就是1,隱藏層啟用函式使用relu,最後輸出層使用sigmoid
可能有人不好理解這個N層,和傳入引數的問題,舉個栗子就很好理解了。比如我們Layer維度傳入的list是[4,3,2,1],這其實是一個三層神經網路,因為4是第0層,也就是輸入層的特徵值有4個,然後兩個隱藏層,單元數分別為3,2,最後輸出層
但在程式碼中會通過這個list來計算我們模型的層數,使用 len(layer_list)來計算,得到的結果是4,這就把第一層也算進去了,但這裡得到的L=4其實不是真正意義上的我們模型的層數,這裡不給它減1,而是保留4的值是因為,即使他是4,但list儲存元素是從0開始的,也就是list[0]=4,list[1]=3,list[2]=2,這樣子,而我們無論在計算w還是b的時候,都是(w1,b1),(w2,b2)直到3,可以發現數標是正好吻合的。
說了這麼多廢話,下面貼程式碼了:
1.導庫
import numpy as np import matplotlib.pyplot as plt import h5py
2.引數初始化
#引數初始化,將所有w/b都封裝在一個dict中 def initialize_parameters(layer_dims): parameters = {} L = len(layer_dims) for i in range(1,L): parameters['w'+ str(i)] = np.random.randn(layer_dims[i],layer_dims[i-1])*0.01 parameters['b'+ str(i)] = np.zeros((layer_dims[i],1)) assert(parameters['w'+ str(i)]).shape == (layer_dims[i],layer_dims[i-1]) assert(parameters['b'+ str(i)]).shape == (layer_dims[i],1) return parameters
3.向前傳播
#定義啟用函式
def relu(Z):
A=(Z+abs(Z))/2
assert(A.shape == Z.shape)
return A
def sigmoid(Z):
A=1.0/(1+np.exp(-Z))
assert(A.shape == Z.shape)
return A
#向前傳播
def forward_propagation(X,parameters):
#caches儲存了每一層計算得到的A,Z值
caches = {}
L=len(parameters)//2
A_prev=X
for i in range(1,L):
Z=np.dot(parameters['w'+str(i)],A_prev)+parameters['b'+str(i)]
A=relu(Z)
caches['Z'+str(i)]=Z
caches['A'+str(i)]=A
#這一層計算得到的A需要保留,下一層計算Z要用
A_prev=A
#輸出層的啟用函式時sigmoid
Z=np.dot(parameters['w'+str(L)],A_prev)+parameters['b'+str(L)]
A=sigmoid(Z)
caches['Z'+str(L)]=Z
caches['A'+str(L)]=A
#這裡多存一個X是因為反向傳播的時候要用到
caches['A0'] = X
return A,caches
4.代價
#計算代價
def cpmpute_cost(A,Y):
m=Y.shape[1]
cost=-1/m*np.sum(np.multiply(np.log(A),Y)+np.multiply((1-Y),np.log(1-A)))
cost=np.squeeze(cost)
return cost
5.反向傳播
#relu函式的導數
def relu_back(Z,dA):
deri = Z
deri[Z < 0]=0
deri[Z >=0]=1
return deri
#反向傳播
def back_propagation(Y,caches,parameters):
#所有的dw和db
grads={}
L=len(caches)//2
m=Y.shape[1]
#AL其實就是一次迭代得到的預測值
AL=caches['A'+str(L)]
#因為sigmoid反向傳和relu不同,所以單獨處理
dZ=AL-Y
dW=np.dot(dZ,caches['A'+str(L-1)].T)/m
db=np.sum(dZ,axis=1,keepdims=True)/m
grads['dw'+str(L)]=dW
grads['db'+str(L)]=db
for i in reversed(range(1,L)):
dA=np.dot(parameters['w'+str(i+1)].T,dZ)
dZ=np.multiply(dA,relu_back(caches['Z'+str(i)],dA))
dW=1.0/m * np.dot(dZ,caches['A'+str(i-1)].T)
db=1.0/m * np.sum(dZ,axis=1,keepdims=True)
grads['dw'+str(i)]=dW
grads['db'+str(i)]=db
return grads
6.引數更新
#更新引數
def update_parameters(parameters, grads, alphs):
L = len(parameters)//2
for l in range(L):
parameters['w'+str(l+1)] = parameters['w'+str(l+1)] - alphs * grads['dw'+str(l+1)]
parameters['b'+str(l+1)] = parameters['b'+str(l+1)] - alphs * grads['db'+str(l+1)]
return parameters
7.資料(貓,也可以用其他資料集試試)
#處理資料
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
8.模型預測
#模型預測
def predict(X,parameters):
A2,caches=forward_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
#模型整合
def model(X,Y,layer_dims,iter_times,alphs,print_flag):
np.random.seed(1)
parameters=initialize_parameters(layer_dims)
for i in range(0,iter_times):
A,caches=forward_propagation(X,parameters)
cost=cpmpute_cost(A,Y)
grads=back_propagation(Y,caches,parameters)
parameters=update_parameters(parameters,grads,alphs)
if print_flag and i % 100 == 0:
print('iteration at ',i,' cost :',cost)
return parameters
最後測試一下:
n=train_data_finalX.shape[0]
layer_dims=[n,20,4,1]
parameters=model(train_data_finalX,train_data_finalY,layer_dims,2500,0.05,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,'%')
得到的結果:
iteration at 0 cost : 0.6932015486338629
iteration at 100 cost : 0.6482987506672847
iteration at 200 cost : 0.6443527436694975
iteration at 300 cost : 0.6439059082659386
iteration at 400 cost : 0.6436651460852033
iteration at 500 cost : 0.6431109804509275
iteration at 600 cost : 0.6428896805499592
iteration at 700 cost : 0.6433981174416904
iteration at 800 cost : 0.6424129644194355
iteration at 900 cost : 0.6101151197326483
iteration at 1000 cost : 0.48396387299853605
iteration at 1100 cost : 0.42416172606012914
iteration at 1200 cost : 0.38773483207677206
iteration at 1300 cost : 0.3540606824486229
iteration at 1400 cost : 0.3387176239551042
iteration at 1500 cost : 0.3238536531634526
iteration at 1600 cost : 0.3148366753236183
iteration at 1700 cost : 0.3069509047774539
iteration at 1800 cost : 0.29751081135148866
iteration at 1900 cost : 0.28693234063058815
iteration at 2000 cost : 0.2870926250045233
iteration at 2100 cost : 0.3030038796284433
iteration at 2200 cost : 0.34263222828051587
iteration at 2300 cost : 0.23760048293266464
iteration at 2400 cost : 0.23174642600881754
train acc is 96.65071770334929 %
test acc is 74.0 %
總結:
在最開始的測試過程中,發現代價值降低到64以後,就不再變化了,或者變化微乎其微,我打印出每一次迭代中每一層的A,Z的值發現處理到第三次迭代時,最後得到的預測值幾乎都一樣,區別只在小數點後3位以上,把整個流程又推了一遍,發現是relu函式的導數有問題,之前用的是網上的一個版本,對照了老師講的筆記寫了這個,然後代價值就降低了
如果遇到預測值幾乎都一樣的情況,可以分析:
1.初始值是不是沒有做預處理(均值化,歸一化等)
2.傳播過程某個環節出了問題,這個時候仔細推一遍