深度学习-吴恩达第一课第四周课程作业

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Bazingaea/article/details/83244108

在前面两节课的基础上,这次作业是训练一个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 patameters

最后测试一下:

n=train_data_finalX.shape[0]
layer_dims=[n,300,20,1]
parameters=model(train_data_finalX,train_data_finalY,layer_dims,2000,0.07,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.6929658447066274
iteration at  100  cost : 0.6422007446062998
iteration at  200  cost : 0.5894641311680554
iteration at  300  cost : 0.5130977956121289
iteration at  400  cost : 0.47558653523857203
iteration at  500  cost : 0.4331908804755023
iteration at  600  cost : 0.416685808638894
iteration at  700  cost : 0.39907725541040856
iteration at  800  cost : 0.381136318109919
iteration at  900  cost : 0.3680682765093181
iteration at  1000  cost : 0.36115196284724815

c:\users\pc\appdata\local\programs\python\python37\lib\site-packages\ipykernel_launcher.py:3: RuntimeWarning: divide by zero encountered in log
  This is separate from the ipykernel package so we can avoid doing imports until
c:\users\pc\appdata\local\programs\python\python37\lib\site-packages\ipykernel_launcher.py:3: RuntimeWarning: invalid value encountered in multiply
  This is separate from the ipykernel package so we can avoid doing imports until

iteration at  1100  cost : 0.3499213606555943
iteration at  1200  cost : 0.3372865856993948
iteration at  1300  cost : 0.32167777233977757
iteration at  1400  cost : 0.3076942153062946
iteration at  1500  cost : 0.2859132183766111
iteration at  1600  cost : 0.40434131416572433
iteration at  1700  cost : nan
iteration at  1800  cost : 0.3151482077294074
iteration at  1900  cost : nan


train acc is  79.90430622009569 %
test acc is  78.0 %


结果不是很理想,可能和参数设置有很大关系,这也是神经网络更为重要的一部分,吴恩达老师后面的课程会讲到如何调参

警告和nan原因不明。。。

总结:

在最开始的测试过程中,发现代价值降低到64以后,就不再变化了,或者变化微乎其微,我打印出每一次迭代中每一层的A,Z的值发现处理到第三次迭代时,最后得到的预测值几乎都一样,区别只在小数点后3位以上,把整个流程又推了一遍,发现是relu函数的导数有问题,之前用的是网上的一个版本,对照了老师讲的笔记写了这个,然后代价值就降低了

如果遇到预测值几乎都一样的情况,可以分析:

1.初始值是不是没有做预处理(均值化,归一化等)

2.传播过程某个环节出了问题,这个时候仔细推一遍

猜你喜欢

转载自blog.csdn.net/Bazingaea/article/details/83244108