概述
在完成吴恩达第一课第四周,即L层neuralnetwork学习后,了解了深层神经网络的结构,然后参考网上的资料,完成该周作业,现将心得体会记录如下。
核心代码
调用库如下所示
import numpy as np
import matplotlib.pyplot as plt
初始化参数函数
def init_para(layer_dims):
L = len(layer_dims) #L为总层数
np.random.seed(0)
parameters = {}
for l in range(1,L): #初始化W1~WL,b1~bL
n1 = layer_dims[l]
n2 = layer_dims[l-1]
parameters['W'+str(l)] = np.random.randn(n1, n2) * np.sqrt(1.0/n2)
parameters['b'+str(l)] = np.zeros((n1, 1))
return parameters
单次前向运算函数
def single_forward(A_pre, W, b, mode):
Z = np.dot(W, A_pre) + b #根据上一层的输出A_pre,以及本层的W b计算本层的Z
if mode=='sigmoid': #根据所选定的激活函数计算本层的输出
A = 1.0/(1+np.exp(-Z))
if mode=='ReLU':
A = (Z+abs(Z))/2
if mode=='tanh':
A = np.tanh(Z)
cache = {'A_pre':A_pre,
'W':W,
'b':b,
'Z':Z,
'A':A}
return cache
前向传播函数
def prop_forward(X, parameters):
caches = []
L = len(parameters)//2
for l in range(1,L+1): #l从1到L,调用L次前向运算
if l==1: #第一次运算时,A_pre=X
A_pre = X
else:
A_pre = cache['A']
if l==L: #最后一次运算时,激活函数为sigmoid
mode = 'sigmoid'
else:
mode = 'tanh'
W = parameters['W'+str(l)]
b = parameters['b'+str(l)]
cache = single_forward(A_pre, W, b, mode)
caches.append(cache)
AL = caches[L-1]['A']
return AL, caches
成本函数
def compute_cost(AL,Y):
m = Y.shape[1] #-1/m*[Ylog(A) + (1-Y)log(1-A)]
cost = -1.0/m * np.sum(Y*np.log(AL) + (1-Y)*np.log(1-AL))
cost = np.squeeze(cost)
return cost
单次后向运算函数
def single_backward(dA, cache, mode):
A_pre = cache['A_pre']
W = cache['W']
b = cache['b']
A = cache['A']
m = A_pre.shape[1]
if mode=='sigmoid': #根据本层激活函数计算本层的dZ
dZ = dA*A*(1-A) #sigmoid函数:dZ=dA*[A(1-A)]
if mode=='ReLU':
dZ = dA #ReLU函数:A>=0,dZ=dA
dZ[A<0] = 0 #ReLU函数:A<0, dZ=0
if mode=='tanh':
dZ = dA*(1-A**2) #tanh函数: dZ=dA*(1-A*A)
grad = {'dW':1.0/m*np.dot(dZ, A_pre.T),
'db':1.0/m*np.sum(dZ, axis=1, keepdims=True),
'dA_pre':np.dot(W.T, dZ)}
return grad
后向传播函数
def prop_backward(AL, Y, caches):
grads = {} #注意:使用append时应初始化为[],否则应为{}
L = len(caches)
for l in reversed(range(L)): #计算梯度
if l==L-1: #计算dAL,因输出层使用的损失函数为-1/m*[Ylog(A) + (1-Y)log(1-A)]
dA = -(Y/AL - (1-Y)/(1-AL))
mode = 'sigmoid'
else:
dA = grad['dA_pre']
mode = 'tanh'
grad = single_backward(dA, caches[l], mode)
grads['dW'+str(l+1)] = grad['dW']
grads['db'+str(l+1)] = grad['db']
return grads
参数更新函数
def update_para(parameters, grads, learning_rate):
L = len(parameters)//2
for l in range(L):
parameters['W'+str(l+1)] = parameters['W'+str(l+1)] - learning_rate * grads['dW'+str(l+1)]
parameters['b'+str(l+1)] = parameters['b'+str(l+1)] - learning_rate * grads['db'+str(l+1)]
return parameters
构建模型函数
def NN_model(X, Y, layer_dims, learning_steps, learning_rate, print_flag):
np.random.seed(1)
costs=[]
parameters = init_para(layer_dims) #初始化参数
for i in range(0, learning_steps): #进行learning_steps次训练
AL, caches = prop_forward(X, parameters) #前向传播,计算A1~AL
cost = compute_cost(AL,Y) #计算成本
grads = prop_backward(AL, Y, caches) #反向传播,计算dW1~dWL,db1~dbL
parameters = update_para(parameters, grads, learning_rate) #更新参数
if print_flag==True and i%1000==0:
print('cost at %i steps:%f'%(i, cost))
costs.append(cost)
return parameters,costs
预测函数
def predict(X,parameters):
AL, caches = prop_forward(X, parameters)
prediction = (AL>0.5)
return prediction
二元分类问题
二元分类问题1
训练数据为二维平面的坐标点,形状呈8瓣花瓣,其中设置部分点标签为0,另一部分为1,绘出后如下图所示(与第三周样本的略有区别)。
用这些点训练L层NN。当layer_dims = [2,4,3,1],steps=20000,rate=0.5时,很快收敛,cost变化如下图所示(横坐标1个数代表1000步)。
用该网络对样本重新预测准确率为0.990000,二维平面预测并分区,结果如下图所示:
当layer_dims = [2,4,3,2,1],即多了一层,steps与rate不变,一开始收敛很慢,到某一时刻突然收敛,cost变化如下图所示(横坐标1个数代表1000步)。
用该网络对样本重新预测准确率为0.980000,二维平面预测并分区,结果如下图所示:
二元分类问题2
训练的坐标点更改为两组环形圈,两层标签分别为0和1。点绘出后如下图所示。
用这些点训练L层的neuralnetwork,令layer_dims = [2,6,3,1]。训练一开始收敛很慢,到某一时刻突然收敛,cost变化如下图所示(横坐标1个数代表1000步)。
用该网络对样本重新预测准确率为1,二维平面预测并分区,结果如下图所示。虽然收敛较慢,但经调参后,其效果优于单隐层的网络。
三元分类问题
直接尝试解决有交叉的三元分类问题。训练集绘出后如下图所示。
用这些点训练L层的neuralnetwork,令layer_dims=[2,18,6,3]。训练一开始收敛很慢,到某一时刻突然收敛,cost变化如下图所示(横坐标1个数代表1000步)。
用该网络对样本重新预测准确率为1,二维平面预测并分区,结果如下图所示。虽然收敛较慢,但经调参后,其效果明显优于单隐层的网络。
猫识别问题
数据文件,在datasets文件夹内,分别包括训练数据和测试数据;
自己的图片文件,在images内,用于检验网络;
代码文件,CatRecognition_NN_Llayer.py。
代码文件中前面主要是读取文件代码,其中样本文件有209个,读取后的数据维度为209×64×64×3,其中209为样本数,两个64分别为图片的横纵像素个数,最后的3对应每个像素的RGB值。读取后将其转换为12288×209的二维矩阵,其中12288=64×64×3,即每个样本有12288个特征。
将深层NN的核心代码敲入,网络第一层激活函数用tanh,中间层用ReLU,最后层用sigmoid,并令layer_dims=[12288,500,20,1],步长为0.02,学习次数为1100,用训练数据集进行训练,然后对训练数据和测试数据分别进行预测,准确率分别为0.918660和0.800000,相较于第三周的网络,虽然训练集的测试准确率降低,但是测试集的准确率进一步提高,可知过拟合程度进一步降低。
对"images/cat7.jpg"(如下图所示)进行预测来检验网络。网络认为其是猫,该网络准确率基本可以(这是为数不多的能将下面这张图片识别为猫的网络,其他参数不变,把学习次数改为1000时也可以识别出这张图片。注意学习次数更多时将发生过拟合,再对这张图预测,结果将不是猫...)。
总结
通过学习和实践,掌握了深层NN的设计方法。
另有感悟:
深层神经网络调参困难,尤其时层数L和每层的维度,以及学习次数和步长,非常难以找到很快收敛的参数。往往是很长时间不收敛,然后突然收敛或突然爆炸,又或者梯度消失,永远也无法找到最优解;
在网上查找资料,包括吴恩达后续的课程,好像都有解决这些问题的方法,这些才应该时今后学习的重心,而不是调参。
附
本周作业源代码,可在本人csdn的资源里下载,含上面几个文件源代码,均为py文件。另含本篇博客的word和pdf版本。如有需要需要请自行下载,资源名称为“吴恩达深度学习第一课第四周作业及学习心得体会.zip”