1. 程式人生 > >深度學習-吳恩達第一課第四周課程作業

深度學習-吳恩達第一課第四周課程作業

在前面兩節課的基礎上,這次作業是訓練一個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.傳播過程某個環節出了問題,這個時候仔細推一遍