采用L2正则化和随机删除节点的L层神经网络

前言

      这段时间在学习吴恩达的《神经网络和深度学习》课程,在前一篇博客:设计L层网络中有详细介绍如何设计一个L层网络,这篇博客是在前一篇的基础上加上了以下任务:(1)对w和b的三种不同的初始化;(2)是否采用L2正则化;(3)是否随机删除节点。所以如果对网络的实现部分还有不理解的地方,可以看看我的前一篇博客,会有帮助。

      最后,如果有什么写得不对的地方,希望大家不吝赐教,谢谢!

 

 

整个流程:

处理数据\rightarrow初始化参数\rightarrow前向传播\rightarrow损失函数\rightarrow反向传播\rightarrow优化\rightarrow预测\rightarrow构造模型\rightarrow测试并绘制结果

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需要\times \sqrt{\frac{2}{netdims(n-1)}}

#初始化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正则化:J=-\frac{1}{m}\sum_{i=1}^{m}(y^{(i)}log(a^{[l](i)})+(1-y^{(i)})log(1-a^{[l](i)}))

(2)使用L2正则化:J=-\frac{1}{m}\sum_{i=1}^{m}(y^{(i)}log(a^{[l](i)})+(1-y^{(i)})log(1-a^{[l](i)}))+\frac{1}{m}\frac{\lambda }{2}\sum_{l}\sum_{k}\sum_{j}(W_{kj}^{[l]})^{2}

#损失函数
    
'''
函数功能:计算损失函数
输入: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)有正则化   其中: \frac{d}{dW}(\frac{1}{2}\frac{\lambda }{m}W^{2})=\frac{\lambda }{m}W

(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 损失值与迭代次数的关系

 总结:关于很多模式就不在这里一一展示了,大家可以自行测试效果,并对网络各参数进行修改尝试。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

烊萌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值