【momentum&Adam】对梯度下降法进行优化,加快训练速度

前言

       这一篇博客是在上一篇博客的基础上对网络训练使用梯度下降法进行改进,加快训练的速度,主要从两方面进行改进:(1)对数据集进行分割,以部分数据集为单位进行梯度下降;(2)分别采用momentum和Adam算法进行梯度下降,加快收敛速度。

上一篇博客:采用L2正则化和随机删除节点的L层神经网络

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

一、主要任务(1)对数据集进行分割     (2)采用momentum算法进行梯度下降     (3)采用Adam算法进行梯度下降

二、整个流程构造数据集\rightarrow用随机数初始化w和b参数\rightarrow前向传播\rightarrow损失函数\rightarrow反向传播\rightarrow优化(分割数据\rightarrow梯度下降\rightarrow含momentum的梯度下降\rightarrow含Adam的梯度下降)\rightarrow预测\rightarrow模型

三、引用的包有

import numpy as np
import matplotlib.pyplot as plt
import sklearn.datasets as sd
import math

四、需要准备的函数

激活函数:relu函数和输出层的sigmoid函数

#输出层激活函数
def sigmoid(z):
    
    s=1/(1+np.exp(-z))
    
    return s

#隐藏层激活函数
def relu(z):
    
    s=np.maximum(0,z)
    
    return s

 

1、构造数据集

#构造数据集
def load_datasets(is_plot=False):
    
    np.random.seed(1)
    train_x,train_y=sd.make_moons(n_samples=300,noise=.2)
    
    if is_plot==True:
        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])
    
    print('train_x_shape:',train_x.shape)
    print('train_y_shape:',train_y.shape)
    
    return train_x,train_y

数据集大小:

train_x_shape: (2, 300)
train_y_shape: (1, 300)

2、用随机数初始化w和b参数

#用随机数初始化w和b
def init_w_b(net_dims):
    
    L=len(net_dims)
    np.random.seed(2)
    parms={}
    
    for i in range(1,L):
        
        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))
        
    return parms

 3、前向传播

      这次网络设计的是一个三层的网络

#前向传播
def forward(X,parms):
    
    forward_data={}
    
    W1=parms['W1']
    b1=parms['b1']
    W2=parms['W2']
    b2=parms['b2']
    W3=parms['W3']
    b3=parms['b3']
    
    z1=np.dot(W1,X)+b1
    a1=relu(z1)
    z2=np.dot(W2,a1)+b2
    a2=relu(z2)
    z3=np.dot(W3,a2)+b3
    a3=sigmoid(z3)
    
    forward_data={'W1':W1,
                  'b1':b1,
                  'z1':z1,
                  'a1':a1,
                  'W2':W2,
                  'b2':b2,
                  'z2':z2,
                  'a2':a2,
                  'W3':W3,
                  'b3':b3,
                  'z3':z3,
                  'a3':a3}
    
    return forward_data

4、损失函数

#损失函数
def cost_function(Y,forward_data):
    
    a3=forward_data['a3']
    m=Y.shape[1]
    
    cost=(-1/m)*np.sum(Y*np.log(a3)+(1-Y)*np.log(1-a3))
    
    return cost

5、反向传播

#反向传播
def backward(forward_data,X,Y):
    
    m=Y.shape[1]
    
    dZ3=forward_data['a3']-Y
    dW3=(1/m)*np.dot(dZ3,forward_data['a2'].T)
    db3=(1/m)*np.sum(dZ3,axis=1,keepdims=True)
    
    dZ2=np.dot(forward_data['W3'].T,dZ3)*np.int64(forward_data['a2']>0)
    dW2=(1/m)*np.dot(dZ2,forward_data['a1'].T)
    db2=(1/m)*np.sum(dZ2,axis=1,keepdims=True)
    
    dZ1=np.dot(forward_data['W2'].T,dZ2)*np.int64(forward_data['a1']>0)
    dW1=(1/m)*np.dot(dZ1,X.T)
    db1=(1/m)*np.sum(dZ1,axis=1,keepdims=True)
    
    grads={'dZ3':dZ3,
           'dW3':dW3,
           'db3':db3,
           'dZ2':dZ2,
           'dW2':dW2,
           'db2':db2,
           'dZ1':dZ1,
           'dW1':dW1,
           'db1':db1}
    
    return grads

6、优化

(1)分割数据集

1)先打乱train_x的顺序,即一共有m个数据,原始的排列是:0,1,2,,,m-1,现在随机打乱顺序,train_y对应地也会和train_x随机顺序一样。

#第一步:打乱顺序
    permutation =list(np.random.permutation(m))
    X_random=X[:,permutation]
    Y_random=Y[:,permutation].reshape(1,m)

2)切分数据,把m个数据按照一定大小进行切分,如每一个大小为mini_batch_size=64,即一共分成(m/mini_batch_size)组,例如:

第一组:first_mini_batch=X_random[:,0:mini_batch_size]

第二组:sceond_mini_batch=X_random[:,mini_batch_size:2*mini_batch_size]

,,,

 整个过程如下:

#先进行分割数据
def random_mini_batches(X,Y,mini_batches_size=64):
    
    np.random.randn(3)
    m=Y.shape[1]
    mini_batches=[]
    
    #第一步:打乱顺序
    permutation =list(np.random.permutation(m))
    X_random=X[:,permutation]
    Y_random=Y[:,permutation].reshape(1,m)
    
    #第二步:分割
    num_competed=math.floor(m/mini_batches_size)
    
    for i in range(num_competed):
        
        mini_batch_x=X_random[:,i*mini_batches_size:(i+1)*mini_batches_size]
        mini_batch_y=Y_random[:,i*mini_batches_size:(i+1)*mini_batches_size]
        mini_batch=(mini_batch_x,mini_batch_y)
        mini_batches.append(mini_batch)
        
    if m%mini_batches_size!=0:
        
        mini_batch_x=X_random[:,num_competed*mini_batches_size:]
        mini_batch_y=Y_random[:,num_competed*mini_batches_size:]
        mini_batch=(mini_batch_x,mini_batch_y)
        mini_batches.append(mini_batch)
        
    return mini_batches

(2)梯度下降

W:=W-\alpha *dW

b:=b-\alpha *db

#1、梯度下降
def updata_w_b(parms,grads,learning_rate,net_dims):
    
    L=len(net_dims)
    
    for i in range(1,L):
        
        parms['W'+str(i)]=parms['W'+str(i)]-learning_rate*grads['dW'+str(i)]
        parms['b'+str(i)]=parms['b'+str(i)]-learning_rate*grads['db'+str(i)]
        
    return parms

在进行momentum和Adam梯度下降时,先对算法中需要用到的v和s变量进行初始化

#初始化momentun和Adam算法中需要用到的v和s变量
def init_v_s(net_dims,parms):
    
    L=len(net_dims)
    v={}
    s={}
    for i in range(1,L):
        
        v['dW'+str(i)]=np.zeros_like(parms['W'+str(i)])
        v['db'+str(i)]=np.zeros_like(parms['b'+str(i)])
        
        s['dW'+str(i)]=np.zeros_like(parms['W'+str(i)])
        s['db'+str(i)]=np.zeros_like(parms['b'+str(i)])
        
    return v,s

 

(3)含momentum的梯度下降

算法本身主要利用前面的梯度进行综合求和平均,来进行平滑,防止波动,每次求和个数:n=\frac{1}{1-\beta }

\left\{\begin{matrix} V_{dW}=\beta V_{dW}+(1-\beta )dW\\ V_{db}=\beta V_{db}+(1-\beta )db \end{matrix}\right.   其中一般\beta =0.9

\left\{\begin{matrix} W:=W-\alpha *V_{dW}\\ b:=b-\alpha *V_{db} \end{matrix}\right.

#2、包含动量的梯度下降
def update_w_b_momentum(parms,v,grads,net_dims,learning_rate,beta=0.9):
    
    L=len(net_dims)
        
    for i in range(1,L):
        
        v['dW'+str(i)]=beta*v['dW'+str(i)]+(1-beta)*grads['dW'+str(i)]
        v['db'+str(i)]=beta*v['db'+str(i)]+(1-beta)*grads['db'+str(i)]
        
        parms['W'+str(i)]=parms['W'+str(i)]-learning_rate*v['dW'+str(i)]
        parms['b'+str(i)]=parms['b'+str(i)]-learning_rate*v['db'+str(i)]
        
    return parms,v

(4)含Adam算法的梯度下降

先介绍下RMSprop算法:这个算法主要是加快梯度下降的前进速度,减缓梯度左右波动的速度

\left\{\begin{matrix} S_{dW}=\beta S_{dW}+(1-\beta )dW^{2}\leftarrow small\\ S_{db}=\beta S_{db}+(1-\beta )db^{2}\leftarrow large \end{matrix}\right.    其中一般\beta =0.999

\left\{\begin{matrix} W:=W-\alpha \frac{dW}{\sqrt{S_{dW}}}\\ b:=b-\alpha \frac{db}{\sqrt{S_{db}}} \end{matrix}\right.

Adam算法是将momentum和RMSprop进行结合起来

\left\{\begin{matrix} V_{dW}=\beta1 V_{dW}+(1-\beta 1)dW\\ V_{db}=\beta1 V_{db}+(1-\beta1 )db \end{matrix}\right.

\left\{\begin{matrix} S_{dW}=\beta2 S_{dW}+(1-\beta2 )dW^{2}\\ S_{db}=\beta2 S_{db}+(1-\beta2 )db^{2}\end{matrix}\right.

偏差校正:

\left\{\begin{matrix} V_{dW}^{corrected}=\frac{V_{dW}}{1-\beta _{1}^{t}}\\ V_{db}^{corrected}=\frac{V_{db}}{1-\beta _{1}^{t}} \end{matrix}\right.

\left\{\begin{matrix} S_{dW}^{corrected}=\frac{S_{dW}}{1-\beta _{1}^{t}}\\ S_{db}^{corrected}=\frac{S_{db}}{1-\beta _{1}^{t}} \end{matrix}\right.

update:

\left\{\begin{matrix} W:=W-\alpha \frac{V_{dW}^{corrected}}{\sqrt{S_{dW}}+\epsilon }\\ b:=b-\alpha \frac{V_{db}^{corrected}}{\sqrt{S_{db}}+\epsilon } \end{matrix}\right.     其中一般\epsilon =10^{-8}

#3、Adam算法
def update_w_b_adam(parms,grads,v,s,t,net_dims,learning_rate,beta1=0.9,beta2=0.999,e=1e-8):
    
    L=len(net_dims)
    v_corr={}
    s_corr={}
    
    for i in range(1,L):
        
        v_corr['dW'+str(i)]=np.zeros_like(parms['W'+str(i)])
        v_corr['db'+str(i)]=np.zeros_like(parms['b'+str(i)])
        
        s_corr['dW'+str(i)]=np.zeros_like(parms['W'+str(i)])
        s_corr['db'+str(i)]=np.zeros_like(parms['b'+str(i)])
        
    for i in range(1,L):
        
        v['dW'+str(i)]=beta1*v['dW'+str(i)]+(1-beta1)*grads['dW'+str(i)]
        v['db'+str(i)]=beta1*v['db'+str(i)]+(1-beta1)*grads['db'+str(i)]
        
        s['dW'+str(i)]=beta2*s['dW'+str(i)]+(1-beta2)*np.square(grads['dW'+str(i)])
        s['db'+str(i)]=beta2*s['db'+str(i)]+(1-beta2)*np.square(grads['db'+str(i)])
        
        v_corr['dW'+str(i)]=v['dW'+str(i)]/(1-np.power(beta1,t))
        v_corr['db'+str(i)]=v['db'+str(i)]/(1-np.power(beta1,t))
        
        s_corr['dW'+str(i)]=s['dW'+str(i)]/(1-np.power(beta2,t))
        s_corr['db'+str(i)]=s['db'+str(i)]/(1-np.power(beta2,t))
        
        parms['W'+str(i)]=parms['W'+str(i)]-learning_rate*v_corr['dW'+str(i)]/(np.sqrt(s_corr['dW'+str(i)])+e)
        parms['b'+str(i)]=parms['b'+str(i)]-learning_rate*v_corr['db'+str(i)]/(np.sqrt(s_corr['db'+str(i)])+e)
        
    return parms,v,s

7、预测

#预测
def predict(X,parms,Y):
    
    forward_data=forward(X,parms)
    a3=forward_data['a3']
    m=Y.shape[1]
    y_predict=np.zeros(shape=(1,m))
    
    for i in range(m):
        
        if a3[0,i]>0.5:
            y_predict[0,i]=1
        else:
            y_predict[0,i]=0
            
    print('Accuracy:'+str(np.mean((y_predict[0,:]==Y[0,:]))))
    
    return y_predict

8、模型

首先网络结构:net_dims={0:n,1:5,2:2,3:1},其中n=train_x.shape[0]

#模型
def mole(train_x,train_y,choice,learning_rate,mini_batches_size=64,iterations=5000,
         beta=0.9,beta1=0.9,beta2=0.999,e=1e-8,print_flag=False,is_plot=False):
    
        n=train_x.shape[0]
        net_dims={0:n,1:5,2:2,3:1}
        t=0
        costs=[]
        
        parms=init_w_b(net_dims)
        v,s=init_v_s(net_dims,parms)
        
        for i in range(iterations):
            
            mini_batches=random_mini_batches(train_x,train_y,mini_batches_size)
            
            for mini_batch in mini_batches:
                
                #选择一个batch
                (mini_batch_x,mini_batch_y)=mini_batch
                
                #前向传播
                forward_data=forward(mini_batch_x,parms)
                
                #损失函数
                cost=cost_function(mini_batch_y,forward_data)
                
                #反向传播
                grads=backward(forward_data,mini_batch_x,mini_batch_y)
                
                #更新参数
                if choice=='gd': #梯度下降
                    
                    parms=updata_w_b(parms,grads,learning_rate,net_dims)
                    
                elif choice=='momentum': #包含动量的梯度下降
                    
                    parms,v=update_w_b_momentum(parms,v,grads,net_dims,learning_rate,beta)
                    
                elif choice=='adam': #使用Adam的梯度下降
                    
                    t=t+1
                    parms,v,s=update_w_b_adam(parms,grads,v,s,t,net_dims,learning_rate,beta1,beta2,e)
                    
            if i%100==0:
                
                costs.append(cost)
                
            if (print_flag) and (i%1000==0):
                
                print('迭代次数:%d,损失函数:%f' % (i,cost))
                
        if is_plot==True:
            
            plt.plot(costs)
            plt.ylabel('costs')
            plt.xlabel('epochs(per 100)')
            plt.title('learning_rate='+str(learning_rate))
            plt.show()
            
        return parms

九、结果

(1)梯度下降

plt.figure(1)
train_x,train_y=load_datasets(is_plot=True)

plt.figure(2)
choice='gd'
parms=mole(train_x,train_y,choice,learning_rate=0.0007,mini_batches_size=64,iterations=10000,beta=0.9,
         beta1=0.9,beta2=0.999,e=1e-8,print_flag=True,is_plot=True)
y_predict=predict(train_x,parms,train_y)

迭代次数:0,损失函数:0.591491
迭代次数:1000,损失函数:0.437251
迭代次数:2000,损失函数:0.406010
迭代次数:3000,损失函数:0.466082
迭代次数:4000,损失函数:0.498481
迭代次数:5000,损失函数:0.436827
迭代次数:6000,损失函数:0.414368
迭代次数:7000,损失函数:0.364876
迭代次数:8000,损失函数:0.372451
迭代次数:9000,损失函数:0.344451

Accuracy:0.8566666666666667 

                                                                                                图1 梯度下降

(2)含momentum的梯度下降

plt.figure(1)
train_x,train_y=load_datasets(is_plot=True)

plt.figure(2)
choice='momentum'
parms=mole(train_x,train_y,choice,learning_rate=0.0007,mini_batches_size=64,iterations=10000,beta=0.9,
         beta1=0.9,beta2=0.999,e=1e-8,print_flag=True,is_plot=True)
y_predict=predict(train_x,parms,train_y)

迭代次数:0,损失函数:0.591578
迭代次数:1000,损失函数:0.437270
迭代次数:2000,损失函数:0.406018
迭代次数:3000,损失函数:0.466111
迭代次数:4000,损失函数:0.498487
迭代次数:5000,损失函数:0.436937
迭代次数:6000,损失函数:0.414402
迭代次数:7000,损失函数:0.364930
迭代次数:8000,损失函数:0.372556
迭代次数:9000,损失函数:0.344508

Accuracy:0.8566666666666667 

                                                                               图2 含momentum的梯度下降法

注:由于小的学习速率和小的数据集,所以导致和普通的梯度下降效果差不多。

(3)含Adam的梯度下降

plt.figure(1)
train_x,train_y=load_datasets(is_plot=True)

plt.figure(2)
choice='adam'
parms=mole(train_x,train_y,choice,learning_rate=0.0007,mini_batches_size=64,iterations=10000,beta=0.9,
         beta1=0.9,beta2=0.999,e=1e-8,print_flag=True,is_plot=True)
y_predict=predict(train_x,parms,train_y)

迭代次数:0,损失函数:0.590683
迭代次数:1000,损失函数:0.143360
迭代次数:2000,损失函数:0.072868
迭代次数:3000,损失函数:0.072864
迭代次数:4000,损失函数:0.162808
迭代次数:5000,损失函数:0.042045
迭代次数:6000,损失函数:0.107865
迭代次数:7000,损失函数:0.058769
迭代次数:8000,损失函数:0.043267
迭代次数:9000,损失函数:0.101692

Accuracy:0.9666666666666667 

                                                                                    图3 含Adam的梯度下降法

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,针对使用SGD、MomentumAdaGrad和Adam优化算法来进行优化的问题,我可以给出如下回答: (1)SGD(随机梯度下降):SGD是最基本的优化算法,其每次迭代只使用一个样本更新参数。由于每次迭代只使用一个样本,SGD在训练过程中的收敛速度相对较慢,而且容易陷入局部最优解。但是SGD的计算量较小,在对大规模数据进行训练时,SGD是一种较为常用的优化算法。 (2)Momentum(动量法):Momentum算法是在SGD算法的基础上引入了动量项,用于加速收敛速度Momentum算法能够有效地解决SGD算法在参数更新中出现的震荡现象,使得参数更新更加平滑。Momentum算法的核心思想是在参数更新时加入上一次更新的动量,避免梯度方向变化过快导致的震荡现象。 (3)AdaGrad(自适应梯度算法):AdaGrad算法是一种自适应学习率算法,其主要思想是对每个参数的学习率进行自适应调整。AdaGrad算法能够根据不同参数的梯度大小自动调整学习率,使得梯度较大的参数学习率较小,梯度较小的参数学习率较大。这样能够有效地解决SGD算法在训练过程中学习率过大或过小的问题。 (4)Adam(自适应矩估计算法):Adam算法是一种自适应学习率算法,其主要思想是基于梯度的一阶矩估计和二阶矩估计来更新参数。Adam算法能够自适应地调整每个参数的学习率,并且具有较好的收敛性能。相比于AdaGrad算法,Adam算法能够更加准确地估计每个参数的梯度,从而更加有效地调整学习率。 以上就是使用SGD、MomentumAdaGrad和Adam优化算法来进行优化的回答,希望能够对你有所帮助。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

烊萌

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

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

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

打赏作者

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

抵扣说明:

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

余额充值