前言
这段时间在学习吴恩达的《神经网络和深度学习》课程,在前一篇博客:设计L层网络中有详细介绍如何设计一个L层网络,这篇博客是在前一篇的基础上加上了以下任务:(1)对w和b的三种不同的初始化;(2)是否采用L2正则化;(3)是否随机删除节点。所以如果对网络的实现部分还有不理解的地方,可以看看我的前一篇博客,会有帮助。
最后,如果有什么写得不对的地方,希望大家不吝赐教,谢谢!
整个流程:
处理数据初始化参数
前向传播
损失函数
反向传播
优化
预测
构造模型
测试并绘制结果
1、处理数据
需要引用的包有:
import numpy as np
import scipy.io as sio
import matplotlib.pyplot as plt
import sklearn
import sklearn.datasets
import operator
from functools import reduce
(1)生成随机数据
'''
函数功能:随机生成数据集
输入:is_plot:是否绘制出数据集
输出:train_x:训练集,train_y:训练集标签,test_x:测试集,test_y:测试集标签
'''
def load_dataset_1(is_plot=False):
np.random.seed(1)
#x:有n对横纵坐标,代表一个点 y:每个点代表的标签,即0或1
train_x,train_y=sklearn.datasets.make_circles(n_samples=300, noise=.05)
np.random.seed(2)
test_x,test_y=sklearn.datasets.make_circles(n_samples=100,noise=.05)
if is_plot:
plt.figure(1)
plt.scatter(train_x[:,0],train_x[:,1],c=train_y,s=40,cmap=plt.cm.Spectral)
train_x=train_x.T
train_y=train_y.reshape(1,train_y.shape[0])
test_x=test_x.T
test_y=test_y.reshape(1,test_y.shape[0])
print('train_x_shape:',train_x.shape)
print('train_y_shape:',train_y.shape)
print('test_x_shape:',test_x.shape)
print('test_y_shape:',test_y.shape)
return train_x,train_y,test_x,test_y
结果:
train_x_shape: (2, 300)
train_y_shape: (1, 300)
test_x_shape: (2, 100)
test_y_shape: (1, 100)
图1 绘制数据集
(2)下载数据集
先下载数据:链接:https://pan.baidu.com/s/1qMtGeyRKUYtd-bg2slW5_Q
提取码:s72v
然后把数据文件名称改成data.mat
'''
函数功能:通过下载数据得到数据集
输入:is_plot:是否绘制出数据集
输出:train_x:训练集,train_y:训练集标签,test_x:测试集,test_y:测试集标签
'''
def load_dataset_2(is_plot=False):
data=sio.loadmat('data.mat')
train_x=data['X'].T
train_y=data['y'].T
test_x=data['Xval'].T
test_y=data['yval'].T
train_y=reduce(operator.add, train_y)
test_y=reduce(operator.add, test_y)
if is_plot:
plt.scatter(train_x[0,:],train_x[1,:],c=train_y,s=40,cmap=plt.cm.Spectral)
train_y=train_y.reshape(1,train_y.shape[0])
test_y=test_y.reshape(1,test_y.shape[0])
print('train_x_shape:',train_x.shape)
print('train_y_shape:',train_y.shape)
print('test_x_shape:',test_x.shape)
print('test_y_shape:',test_y.shape)
return train_x,train_y,test_x,test_y
结果:
train_x_shape: (2, 211)
train_y_shape: (1, 211)
test_x_shape: (2, 200)
test_y_shape: (1, 200)
图2 绘制数据集
2、初始化w和b参数
(1)用0来初始化参数
(2)用随机数来初始化参数
(3)使用抑梯度异常初始化参数(w需要)
#初始化w和b
'''
函数功能:初始化w和b
输入:choice:用来选择初始化的方式,1为0,2为随机,3为抑制初始化
net_dims:网络每层的维度,是一个字典变量,例如:{0:12288,1:4,2:3,3:1}
输出:初始化后的w和b,保存在一个字典parms中
'''
def init_w_b(choice_init,net_dims):
parms={}
l=len(net_dims)
np.random.seed(1)
for i in range(1,l):
if choice_init==1: #用0来初始化
parms['W'+str(i)]=np.zeros(shape=(net_dims[i],net_dims[i-1]))
parms['b'+str(i)]=np.zeros(shape=(net_dims[i],1))
elif choice_init==2: #用随机数来初始化
parms['W'+str(i)]=np.random.randn(net_dims[i],net_dims[i-1])
parms['b'+str(i)]=np.zeros(shape=(net_dims[i],1))
elif choice_init==3: #用抑制初始化
parms['W'+str(i)]=np.random.randn(net_dims[i],net_dims[i-1])\
*(np.sqrt(2/net_dims[i-1]))
parms['b'+str(i)]=np.zeros(shape=(net_dims[i],1))
assert(parms['W'+str(i)].shape==(net_dims[i],net_dims[i-1]))
assert(parms['b'+str(i)].shape==(net_dims[i],1))
#print('W'+str(i)+':'+str(parms['W'+str(i)]))
return parms
3、前向传播
(1)不随机删除节点
(2)随机删除节点 :我们采用一个和A大小一样的随机数生成的一个掩码D和A相乘,达到随机删除节点的效果
#前向传播
'''
函数功能:前向传播,得到每一层的Z、A和掩码D
输入:X:训练集,Y:训练标签,parms:w和b参数,net_dims:网络每一层的维度信息
del_node_flag:是否采取随机删除节点,keep_prob:随机删除节点的概率
输出:Z:需要缓存下来的每层Z变量 A:每一层的输出变量 D:需要随机删除节点的掩码
'''
def forward(X,Y,parms,net_dims,is_del_node=False,keep_prob=0.5):
l=len(net_dims) #l=4
m=Y.shape[1]
Z={}
A={}
D={}
np.random.seed(2)
for i in range(1,l):
Z[i]=np.zeros(shape=(net_dims[i],m))
A[i]=np.zeros(shape=(net_dims[i],m))
D[i]=np.random.randn(net_dims[i],m)
Z[1]=np.dot(parms['W1'],X)+parms['b1']
A[1]=relu(Z[1])
if is_del_node==True:
D[1]=D[1]<keep_prob
A[1]=A[1]*D[1]
A[1]=A[1]/keep_prob
for i in range(2,l-1):
Z[i]=np.dot(parms['W'+str(i)],A[i-1])+parms['b'+str(i)]
A[i]=relu(Z[i])
if is_del_node==True:
D[i]=D[i]<keep_prob
A[i]=A[i]*D[i]
A[i]=A[i]/keep_prob
Z[l-1]=np.dot(parms['W'+str(l-1)],A[l-2])+parms['b'+str(l-1)]
A[l-1]=sigmoid(Z[l-1])
return Z,A,D
4、损失函数
(1)不使用L2正则化:
(2)使用L2正则化:
#损失函数
'''
函数功能:计算损失函数
输入:Y:训练集标签,A_last:最后一层的输出,net_dims:网络维度信息
is_regulization:是否使用L2正则化,默认不使用,lambd:正则化所需参数,
输出:损失值
'''
def cost_function(Y,parms,A,net_dims,is_regulization=False,lambd=0):
m=Y.shape[1]
l=len(net_dims)
cost1=0.0
#print('A[l-1]:',A[l-1])
cost=(-1/m)*(np.sum(Y*(np.log(A[l-1]))+(1-Y)*(np.log(1-A[l-1]))))
if is_regulization==True:
for i in range(1,l):
cost1+=np.sum(np.square(parms['W'+str(i)]))
cost1=cost1*lambd/(2*m)
cost=cost+cost1
return cost
5、反向传播
(1)没使用正则化,也没删除节点
(2)有正则化 其中:
(3)有删除节点:即dA需要和掩码D相乘
#反向传播
'''
函数功能:反向传播
输入:D:掩码,parms:w和b参数,A:每一层的输出,Y:训练集标签,net_dims;维度信息
is_regulization:是否有正则项,lambd:正则项参数,is_del_node:是否随机删除节点,
keep_prob:随机删除节点概率
输出:grads:包括dw和db
'''
def backward(D,parms,A,Z,X,Y,net_dims,is_regulization=False,lambd=0,
is_del_node=False,keep_prob=0.5):
l=len(net_dims)
m=Y.shape[1]
dZ={}
dW={}
dA={}
db={}
g={}
for i in range(1,l):
dZ[i]=np.zeros(shape=(net_dims[i],m))
dA[i]=np.zeros(shape=(net_dims[i],m))
dW[i]=np.zeros(shape=(net_dims[i],net_dims[i-1]))
db[i]=np.zeros(shape=(net_dims[i],1))
g[i]=np.zeros(shape=(net_dims[i],m))
dZ[l-1]=A[l-1]-Y
i=l-1 #3
while(i):
dW[i]=(1/m)*(np.dot(dZ[i],A[i-1].T))
if is_regulization==True:
dW[i]=dW[i]+lambd/m*parms['W'+str(i)]
db[i]=(1/m)*np.sum(dZ[i],axis=1,keepdims=True)
i-=1
g[i]=relu(Z[i])
dA[i]=np.dot(parms['W'+str(i+1)].T,dZ[i+1])
if is_del_node==True:
dA[i]=dA[i]*D[i]
dA[i]=dA[i]/keep_prob
dZ[i]=dA[i]*g[i]
if i==1:
break
dW[1]=(1/m)*np.dot(dZ[1],X.T)
db[1]=(1/m)*np.sum(dZ[1],axis=1,keepdims=True)
grads={'dW':dW,
'db':db}
return grads
6、优化
#优化
'''
函数功能:对w和b进行迭代优化
输入:parms:需要优化的w和b参数,net_dims:网络维度信息,X:训练集,Y:训练标签,
is_del_node:是否删除节点,keep_prob:删除节点概率,is_regulization:是否正则化
lambd:正则化参数,iterations:迭代次数,learning_rate:学习速度,print_flag:是否打印损失值
输出:costs:损失值,parms:优化后的w和b,grads:dw和db
'''
def optimize(parms,net_dims,X,Y,is_del_node=False,keep_prob=0.5,is_regulization=False,
lambd=0,iterations=2000,learning_rate=0.5,print_flag=False):
l=len(net_dims)
costs=[]
for j in range(iterations):
Z,A,D=forward(X,Y,parms,net_dims,is_del_node,keep_prob)
cost=cost_function(Y,parms,A,net_dims,is_regulization,lambd)
grads=backward(D,parms,A,Z,X,Y,net_dims,is_regulization,lambd,is_del_node,keep_prob)
for i in range(1,l):
parms['W'+str(i)]=parms['W'+str(i)]-learning_rate*grads['dW'][i]
parms['b'+str(i)]=parms['b'+str(i)]-learning_rate*grads['db'][i]
if j%1000==0:
costs.append(cost)
if (print_flag) and (j%1000==0):
print('迭代次数:%d,损失值:%f' % (j,cost))
#print('grads:',grads['dW'])
return costs,parms,grads
7、预测
#预测
'''
函数功能:对数据进行预测
输入:parms:预测网络的参数w和b,X:数据集,Y:数据集的标签,net_dims:网络维度信息
输出:y_predict:对数据集预测的结果
'''
def predict(parms,X,Y,net_dims):
l=len(net_dims)
Z,A,D=forward(X,Y,parms,net_dims)
m=Y.shape[1]
y_predict=np.zeros(shape=(1,Y.shape[1]))
for i in range(m):
if A[l-1][0,i]>0.5:
y_predict[0,i]=1
else:
y_predict[0,i]=0
return y_predict
8、模型
#模型
'''
函数功能:构造整个网络的模型
输入:train_x:训练集,train_y:训练集标签,test_x:测试集,test_y:测试集标签,
choice_init:选择初始化参数的方式,is_del_node:是否随机删除节点,keep_prob:随机删除节点的概率
is_regulization:是否采用L2正则化,lambd:正则化参数,iterations:迭代次数,
learning_rate:学习速度,print_flag:是否打印损失值
输出:res:包含所有的参数和结果
'''
def modle(train_x,train_y,test_x,test_y,choice_init,is_del_node=False,keep_prob=0.5,
is_regulization=False,lambd=0,iterations=2000,learning_rate=0.5,print_flag=False):
n=train_x.shape[0]
net_dims={0:n,1:10,2:5,3:1}
print('网络每层的维度:')
print(net_dims)
parms=init_w_b(choice_init,net_dims)
costs,parms,grads=optimize(parms,net_dims,train_x,train_y,is_del_node,keep_prob,
is_regulization,lambd,iterations,learning_rate,print_flag)
train_y_predict=predict(parms,train_x,train_y,net_dims)
test_y_predict=predict(parms,test_x,test_y,net_dims)
print("train Accuracy: " + str(np.mean((train_y_predict[0,:] == train_y[0,:]))))
print("test Accuracy: " + str(np.mean((test_y_predict[0,:] == test_y[0,:]))))
#print('test_y_pre-test_y:',np.abs(test_y_predict-test_y))
res={'cost':costs,
'parms':parms,
'grads':grads,
'choice_init':choice_init,
'is_del_node':is_del_node,
'is_regulization':is_regulization,
'iterations':iterations,
'learning_rate':learning_rate,
'train_y_predict':train_y_predict,
'test_y_predict':test_y_predict}
return res
9、测试结果和绘制结果
train_x,train_y,test_x,test_y=DB.load_dataset_1(is_plot=True)
#train_x,train_y,test_x,test_y=DB.load_dataset_2(is_plot=True)
choice_init=2
res=modle(train_x,train_y,test_x,test_y,choice_init,is_del_node=False,
keep_prob=0.5,is_regulization=False,lambd=0,iterations=15000,
learning_rate=0.05,print_flag=True)
#绘制图
costs = np.squeeze(res['cost'])
plt.figure(2)
plt.plot(costs)
plt.ylabel('cost')
plt.xlabel('iterations (per hundreds)')
plt.title("Learning rate =" + str(res["learning_rate"]))
plt.show()
结果:
train_x_shape: (2, 300)
train_y_shape: (1, 300)
test_x_shape: (2, 100)
test_y_shape: (1, 100)
网络每层的维度:
{0: 2, 1: 10, 2: 5, 3: 1}
迭代次数:0,损失值:0.802594
迭代次数:1000,损失值:0.639227
迭代次数:2000,损失值:0.533256
迭代次数:3000,损失值:0.201055
迭代次数:4000,损失值:0.876939
迭代次数:5000,损失值:0.118036
迭代次数:6000,损失值:0.837444
迭代次数:7000,损失值:0.063780
迭代次数:8000,损失值:0.063195
迭代次数:9000,损失值:0.075295
迭代次数:10000,损失值:0.036202
迭代次数:11000,损失值:0.094898
迭代次数:12000,损失值:0.064526
迭代次数:13000,损失值:0.256240
迭代次数:14000,损失值:0.232988
train Accuracy: 0.94
test Accuracy: 0.92
图3 损失值与迭代次数的关系
总结:关于很多模式就不在这里一一展示了,大家可以自行测试效果,并对网络各参数进行修改尝试。