基于不同优化算法更新神经网络中的参数

学习记录自:deeplearning.ai-andrewNG-master

一、 优化算法概述

1.1 常用优化算法
在机器学习或深度学习中,一般采取梯度下降对参数进行优化更新,本文主要讨论Mini-Batch算法、Momentum算法、RMSprop以及Adam算法。
1.2 为什么要改进梯度下降
对于一个数据量适中的数据集而言,可以直接利用梯度下降或者随机梯度下降(Stochastic Gradient Descent)。此时在整个训练集进行梯度下降优化不会消耗太多的时间,效率也不会受太大影响。
但是在深度学习中,往往有巨大的数据样本,如果这种情况下,依然对整个样本数据集进行梯度下降,那么整个训练速度很非常慢。以上算法针对此问题进行了探索,提出更合理的梯度下降优化方法。

二、 优化算法原理与实现

2.1 Mini-Batch梯度下降
对非常庞大的数据样本进行整个数据集梯度下降往往耗时耗力,Mini-Batch梯度下降算法很好的解决了这个问题。主要思路在于对庞大的数据集进行样本划分,把原本特别大的数据样本随机划分为一个个的小样本集,其中每个小样本集中含有数量相同的样本个数。再分别对每个小样本集进行训练,实施梯度下降。样本划分的操作涉及Shuffle和Partition。

Shuffle
如下所示,创建训练集(X,Y)的随机打乱版本。X和Y中的每一列代表一个训练示例。注意,随机打乱是在X和Y之间同步完成的。这样,在随机打乱之后,X的列就是对应于Y中标签的示例。打乱步骤可确保该示例将随机分为不同小批,如图1所示。

图 1 样本数据集shuffle操作
Partition
将打乱后的(X,Y)划分为大小为mini_batch_size(此处为64)的小批样本。因为训练示例的数量并不总是可以被mini_batch_size整除,所以取最后剩下的数据样本作为一个小样本集。


图 2 数据样本重组为一个个小的数据样本集

下图是利用梯度下降和Mini-batch梯度下降的训练结果。

图 3 梯度下降与Mini-batch梯度下降损失函数对比图

Mini-batch梯度下降法因为样本划分的原因,每个样本集的梯度下降不一定会始终朝着损失函数最小化的方向迭代,所以噪声会更大,但整体趋势也是趋于损失函数最优化。
另外对于Mini-batch算法,如何选择mini-batch-size也是一个问题,根据相关实验与经验,一般的在样本集不超过2000个时,选择一般梯度下降即可。当样本集超过2000个时,经典的mini-batch-size为64、128、256、512等。

2.2 Momentum与RMSprop
从刚刚Mini-batch梯度下降法的损失函数迭代图来看,它的收敛速率并不是特别好,并且优化时存在数值振荡,为了减小优化时的震荡,提出了动量梯度下降法(Momentunm)。
动量梯度下降算法实际上是用了指数加权平均的原理,在讨论Momentum与RMSprop之前,先对指数加权平均进行说明。

指数加权平均
指数加权平均(Exponentially weighted averges),也叫指数加权移动平均,是一种常用的序列数据处理方式,下面给出了某地一年的温度的变化曲线。

图 4 某地一年的温度变化曲线
其中红色的线条就是利用指数加权平均后拟合得到的温度预测曲线,从图中可以看出,该曲线较好的说明了该地的温度变化情况,以下是指数加权平均的计算公式:

利用指数加权的思想,我们在动量梯度下降中,也采取用这样的方法,把划分好的每个样本集计算得到的梯度拿来平均,以此来表示整个样本集的梯度。在平均的过程中,与优化方向不一致的梯度值会得到中和,达到了减小震荡的目的,如下图所示:
图 5 指数平均达到减小优化时的噪声与震荡

Momentum采用的是常规的指数加权平均,而RMSprop采用的是均方根平均,两种方法都可以消除梯度下降时的摆动,进而达到快速且稳定收敛到最值点附近的目的。
Momentum的实现过程如下:

图 6 Momentum算法实现过程

RMSprop算法的实现与Momentum稍微不同,是对计算到的梯度的平方进行平均,实现过程如下:

图 7 RMSprop算法实现过程

分母中的 eplison,是为了防止出现除零情况而增加的一个小量,另外alpha 和beta 都是超参数。

三、 算法在模型中的效果

3.1 Momentum算法效果
本文以一个简单的深层神经网络作为模型,对各种算法进行测试。损失函数迭代图和模型分类效果如下图所示:

图 8 Momentum算法损失函数迭代图

图 9 Momentum算法模型分类效果

3.2 Adam算法效果
Adam算法损失函数迭代图和模型分类效果如下图所示:


图 10 Adam 损失函数迭代图

图 11 Adam算法模型分类效果

3.3 对比分析
从结果来看Adam明显胜过Mini-batch和Momentum。如果在简单的数据集上运行,那么这三种方法都将产生非常好的结果。但是,Adam收敛得更快。Adam的优势包括:相对较低的内存要求,即使很少调整超参数,通常也能很好地工作。

本文所用到的代码如下:


"""优化算法的学习 Mini-Batch  Momentum  Adam时间: 1/03/2020
"""
#首先导入 需要的包
import numpy as np
import matplotlib.pyplot as plt
import scipy.io
import math
import sklearn
import sklearn.datasetsfrom opt_utils import load_params_and_grads, initialize_parameters, forward_propagation, backward_propagation
from opt_utils import compute_cost, predict, predict_dec, plot_decision_boundary, load_dataset
from testCases import *#首先是最常用的 梯度下降
def update_parameters_with_gd(parameters, grads, learning_rate):L = len(parameters) // 2 # number of layers in the neural networksfor 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#Mini-batch梯度下降"""
涉及 样本划分   以mini-batch-size 划分   每一个小批次样本 都含有 size个数据  最后一组可能小于size
涉及操作  shuffle -> partition
"""#从(X,Y)创建随机小批量列表
def random_mini_batches(X, Y, mini_batch_size = 64):"""从(X,Y)创建随机小批量列表Arguments:X -- input data, of shape (input size, number of examples)Y -- true "label" vector (1 for blue dot / 0 for red dot), of shape (1, number of examples)mini_batch_size -- size of the mini-batches, integer返回值:mini_batches -- 小批量后的数据列表 (mini_batch_X, mini_batch_Y)"""m = X.shape[1]                  # 样本数据个数mini_batches = []# Step 1: Shuffle (X, Y)permutation = list(np.random.permutation(m)) shuffled_X = X[:, permutation]shuffled_Y = Y[:, permutation].reshape((1,m))# Step 2: Partition (shuffled_X, shuffled_Y). Minus the end case.num_complete_minibatches = math.floor(m/mini_batch_size) # 每一块数据的最小批量大小(取下整数)for k in range(0, num_complete_minibatches):mini_batch_X = shuffled_X[:, k * mini_batch_size : (k+1) * mini_batch_size]mini_batch_Y = shuffled_Y[:, k * mini_batch_size : (k+1) * mini_batch_size]mini_batch = (mini_batch_X, mini_batch_Y)mini_batches.append(mini_batch)# 处理最后一块数据个数小于mini_batch_size的情况 (last mini-batch < mini_batch_size)if m % mini_batch_size != 0:#最后剩余的数据 分为一块mini_batch_X = shuffled_X[:, num_complete_minibatches * mini_batch_size : m]mini_batch_Y = shuffled_Y[:, num_complete_minibatches * mini_batch_size : m]mini_batch = (mini_batch_X, mini_batch_Y)mini_batches.append(mini_batch)return mini_batches#Momentum梯度下降   (动量梯度下降法)
"""
利用了指数加权平均 的思想
利用dw 的平均来描述  vdw    在利用vdw 来进行参数更新冲量beta越大,更新越平滑,因为我们对过去的梯度的考虑也更多。但是,如果太大,也可能使更新变得过于平滑。beta的常用值范围是0.8到0.999。如果你不想调整它,则0.9通常是一个合理的默认值。
"""
#首先初始化   V[dw1,db1,dw2,db2,....]   注意 这里是 速度  不是梯度
def initialize_velocity(parameters):"""Initializes the velocity as a python dictionary with:- keys: "dW1", "db1", ..., "dWL", "dbL" - values: numpy arrays of zeros of the same shape as the corresponding gradients/parameters.Arguments:parameters -- python dictionary containing your parameters.parameters['W' + str(l)] = Wlparameters['b' + str(l)] = bl返回值:v -- python dictionary containing the current velocity.v['dW' + str(l)] = velocity of dWlv['db' + str(l)] = velocity of dbl"""L = len(parameters) // 2 # 神经网络层数v = {}# 初始化 Vfor l in range(L):v["dW" + str(l+1)] = np.zeros(parameters['W' + str(l+1)].shape)v["db" + str(l+1)] = np.zeros(parameters['b' + str(l+1)].shape)return v

#利用Momentum 进行梯度下降 参数更新

def update_parameters_with_momentum(parameters, grads, v, beta, learning_rate):"""利用 momentum 进行参数更新"""L = len(parameters) // 2 # 神经网络层数# 对每一个参数进行更新 (Mometnum梯度下降)for l in range(L):# 计算速度  vdw  vdb    (vdw = beta*vdw + (1-beta)*dw ) v["dW" + str(l + 1)] = beta*v["dW" + str(l + 1)]+(1-beta)*grads['dW' + str(l+1)]v["db" + str(l + 1)] = beta*v["db" + str(l + 1)]+(1-beta)*grads['db' + str(l+1)]# 利用vdw vdb 进行参数更新parameters["W" + str(l + 1)] = parameters['W' + str(l+1)] - learning_rate*v["dW" + str(l + 1)] parameters["b" + str(l + 1)] = parameters['b' + str(l+1)] - learning_rate*v["db" + str(l + 1)] return parameters, v

Adam算法代码:

#Adam 优化算法   """Adam算法 会很复杂   它结合了 Mometnum梯度下降 和 RMSprop梯度下降
需要用指数加权平均 计算 vdw vdb        需要用梯度的平方指数加权平均 计算 sdw sdb
需要修正 vdw vdb sdw sdb ->   ( vdw vdb sdw sdb )_corrected
需要利用 ( vdw vdb sdw sdb )_corrected  来更新参数   W  b
需要利用   epsilon  来避免零除"""##初始化参数 V[dw1,db1,...]     S[dw1,dw2,...]
def initialize_adam(parameters) :"""Initializes v and s as two python dictionaries with:- keys: "dW1", "db1", ..., "dWL", "dbL" - values: numpy arrays of zeros of the same shape as the corresponding gradients/parameters.Arguments:parameters -- python dictionary containing your parameters.parameters["W" + str(l)] = Wlparameters["b" + str(l)] = blReturns: v -- python dictionary that will contain the exponentially weighted average of the gradient.v["dW" + str(l)] = ...v["db" + str(l)] = ...s -- python dictionary that will contain the exponentially weighted average of the squared gradient.s["dW" + str(l)] = ...s["db" + str(l)] = ..."""L = len(parameters) // 2 # 神经网络层数v = {}s = {}# Initialize v, s. Input: "parameters". Outputs: "v, s".for l in range(L):v["dW" + str(l + 1)] = np.zeros(parameters["W" + str(l+1)].shape)v["db" + str(l + 1)] = np.zeros(parameters["b" + str(l+1)].shape)s["dW" + str(l + 1)] = np.zeros(parameters["W" + str(l+1)].shape)s["db" + str(l + 1)] = np.zeros(parameters["b" + str(l+1)].shape)return v, s
##利用 Vdw..  Sdw..  beta1(for V) beta2(for S)   epsilon  进行参数更新
def update_parameters_with_adam(parameters, grads, v, s, t, learning_rate = 0.08,beta1 = 0.9, beta2 = 0.9,  epsilon = 1e-8):"""Adam梯度下降 进行参数更新 Arguments:parameters -- python dictionary containing your parameters:parameters['W' + str(l)] = Wlparameters['b' + str(l)] = blgrads -- python dictionary containing your gradients for each parameters:grads['dW' + str(l)] = dWlgrads['db' + str(l)] = dblv -- Adam variable, moving average of the first gradient, python dictionarys -- Adam variable, moving average of the squared gradient, python dictionarylearning_rate -- the learning rate, scalar.beta1 -- Exponential decay hyperparameter for the first moment estimates beta2 -- Exponential decay hyperparameter for the second moment estimates epsilon -- hyperparameter preventing division by zero in Adam updatesReturns:parameters -- python dictionary containing your updated parameters v -- Adam variable, moving average of the first gradient, python dictionarys -- Adam variable, moving average of the squared gradient, python dictionary"""L = len(parameters) // 2                 # 神经网络层数v_corrected = {}                         # Initializing first moment estimate, python dictionarys_corrected = {}                         # Initializing second moment estimate, python dictionary# Perform Adam update on all parametersfor l in range(L):#计算 mometnum中的 V  (指数加权平均)v["dW" + str(l + 1)] = beta1*v["dW" + str(l + 1)] +(1-beta1)*grads['dW' + str(l+1)]v["db" + str(l + 1)] = beta1*v["db" + str(l + 1)] +(1-beta1)*grads['db' + str(l+1)]#对V 进行修正v_corrected["dW" + str(l + 1)] = v["dW" + str(l + 1)]/(1-(beta1)**t)v_corrected["db" + str(l + 1)] = v["db" + str(l + 1)]/(1-(beta1)**t)# 计算 RMSprop中的 S (平方指数加权平均)s["dW" + str(l + 1)] =beta2*s["dW" + str(l + 1)] + (1-beta2)*(grads['dW' + str(l+1)]**2)s["db" + str(l + 1)] = beta2*s["db" + str(l + 1)] + (1-beta2)*(grads['db' + str(l+1)]**2)#对S 进行修正s_corrected["dW" + str(l + 1)] =s["dW" + str(l + 1)]/(1-(beta2)**t)s_corrected["db" + str(l + 1)] = s["db" + str(l + 1)]/(1-(beta2)**t)#利用 修正后的 S V  和学习率  epsilon 进行参数更新parameters["W" + str(l + 1)] = parameters["W" + str(l + 1)]-learning_rate*(v_corrected["dW" + str(l + 1)]/np.sqrt( s_corrected["dW" + str(l + 1)]+epsilon))parameters["b" + str(l + 1)] = parameters["b" + str(l + 1)]-learning_rate*(v_corrected["db" + str(l + 1)]/np.sqrt( s_corrected["db" + str(l + 1)]+epsilon))return parameters, v, s

模型整合

#整合了各种 优化算法的 模型
def model(X, Y, layers_dims, optimizer, learning_rate = 0.0005, mini_batch_size = 64, beta = 0.9,beta1 = 0.9, beta2 = 0.9,  epsilon = 1e-8, num_epochs = 10000, print_cost = True):"""3-layer neural network model which can be run in different optimizer modes.Arguments:X -- input data, of shape (2, number of examples)Y -- true "label" vector (1 for blue dot / 0 for red dot), of shape (1, number of examples)layers_dims -- python list, containing the size of each layerlearning_rate -- the learning rate, scalar.mini_batch_size -- the size of a mini batchbeta -- Momentum hyperparameterbeta1 -- Exponential decay hyperparameter for the past gradients estimates beta2 -- Exponential decay hyperparameter for the past squared gradients estimates epsilon -- hyperparameter preventing division by zero in Adam updatesnum_epochs -- number of epochsprint_cost -- True to print the cost every 1000 epochsReturns:parameters -- python dictionary containing your updated parameters """L = len(layers_dims)             # number of layers in the neural networkscosts = []                       # to keep track of the costt = 0                            # initializing the counter required for Adam update# 先初始化神经网络 参数parameters = initialize_parameters(layers_dims)# 初始化优化算法  if optimizer == "gd":pass # no initialization required for gradient descentelif optimizer == "momentum":v = initialize_velocity(parameters)elif optimizer == "adam":v, s = initialize_adam(parameters)# 优化迭代 (外层为迭代次数)for i in range(num_epochs):#先进行  数据批次划分  Mini_batch 的过程minibatches = random_mini_batches(X, Y, mini_batch_size)#对每一块数据 minibatch 进行 遍历for minibatch in minibatches:# 数据提取(minibatch_X, minibatch_Y) = minibatch# 正向传播a3, caches = forward_propagation(minibatch_X, parameters)# 损失计算cost = compute_cost(a3, minibatch_Y)# 反向传播grads = backward_propagation(minibatch_X, minibatch_Y, caches)# 参数更新if optimizer == "gd":parameters = update_parameters_with_gd(parameters, grads, learning_rate)elif optimizer == "momentum":parameters, v = update_parameters_with_momentum(parameters, grads, v, beta, learning_rate)elif optimizer == "adam":t = t + 1 # Adam counterparameters, v, s = update_parameters_with_adam(parameters, grads, v, s,t, learning_rate, beta1, beta2,  epsilon)# 损失函数输出if print_cost and i % 1000 == 0:print ("Cost after epoch %i: %f" %(i, cost))if print_cost and i % 100 == 0:costs.append(cost)# 损失函数可视化plt.plot(costs)plt.ylabel('cost')plt.xlabel('epochs (per 100)')plt.title("Learning rate = " + str(learning_rate))plt.show()return parameters

好了 ,这次的优化算法分享就到这儿了!!

深度学习入门——Mini-batch、Momentum与Adam算法相关推荐

  1. 【视频课】深度学习入门必修,子欲学算法,必先搞数据!

    前言 欢迎大家关注有三AI的视频课程系列,我们的视频课程系列共分为5层境界,内容和学习路线图如下: 第1层:掌握学习算法必要的预备知识,包括Python编程,深度学习基础,数据使用,框架使用. 第2层 ...

  2. 深度学习入门之PyTorch学习笔记:多层全连接网络

    深度学习入门之PyTorch学习笔记 绪论 1 深度学习介绍 2 深度学习框架 3 多层全连接网络 3.1 PyTorch基础 3.2 线性模型 3.2.1 问题介绍 3.2.2 一维线性回归 3.2 ...

  3. Day9 深度学习入门

    参数的更新 神经网络学习的目的是找到使损失函数的值尽可能小的参数.常见的有以下四种: SGD(stochastic gradient descent).Momentum.AdaGrad.Adam. A ...

  4. python深度学习入门-与学习相关的技巧

    深度学习入门-与学习相关的技巧 博主微信公众号(左).Python+智能大数据+AI学习交流群(右):欢迎关注和加群,大家一起学习交流,共同进步! 目录 摘要 1. 参数的更新 1.1 SGD 1.2 ...

  5. 《深度学习入门——基于Python的理论与实现》笔记

    PS:写这篇博客主要是记录下自己认为重要的部分以及阅读中遇到的些问题,加深自己的印象. 附上电子书及源代码: 链接:https://pan.baidu.com/s/1f2VFcnXSSK-u3wuvg ...

  6. 深度学习入门笔记(七):深层神经网络

    欢迎关注WX公众号:[程序员管小亮] 专栏--深度学习入门笔记 声明 1)该文章整理自网上的大牛和机器学习专家无私奉献的资料,具体引用的资料请看参考文献. 2)本文仅供学术交流,非商用.所以每一部分具 ...

  7. 《深度学习入门》笔记(一)

    <深度学习入门1>笔记(一) 神经网络的传播 如下图,我们把最左边的一列称为输入层,最右边的一列称为输出层,中间的一列称为中间层,也称为隐藏层."隐藏"一词的意思是,隐 ...

  8. 【《深度学习入门》—— 学习笔记(二)】

    <深度学习入门>-- 学习笔记(二)_5-8章 第五章 误差反向传播法 方法一:基于数学式 - 严密简洁 方法二:基于计算图(computational graph) - 直观 5.1 计 ...

  9. 【AI参赛经验】深度学习入门指南:从零开始TinyMind汉字书法识别——by:Link

    各位人工智能爱好者,大家好! 由TinyMind发起的#第一届汉字书法识别挑战赛#正在火热进行中,比赛才开始3周,已有数只黑马冲进榜单.目前TOP54全部为90分以上!可谓竞争激烈,高手如林.不是比赛 ...

最新文章

  1. 用python画玫瑰花代码-Python | 用turtle库画玫瑰花
  2. Notepad++插件总结
  3. UNIX网络编程——TCP/IP简介
  4. GitHub托管BootStrap资源汇总(持续更新中…)
  5. Leetcode--11. 盛水最多的容器
  6. Android adb命令选择设备操作
  7. python os库使用
  8. 如何在CentOS 7中配置静态IP地址
  9. 【MySQL】MySQL异常Lock wait timeout exceeded try restarting transaction
  10. ABP理论学习之内嵌资源文件
  11. 关于Redis缓存和数据库一致性问题
  12. 1005: 整数幂 Java
  13. 技术笔记:.Net全套就业班视频教程——数据库
  14. java闰年_编写java程序判断闰年。
  15. SQL UCASE() 函数、 LCASE() 函数
  16. IOS开发百度地图API入门到精通-用点生成路线,导航,气泡响应
  17. 第一个Flutter demo——实现无限循环列表
  18. ERP系统对服装行业的帮助有哪些?
  19. 陈式太极拳小架一路拳谱(陈鑫拳架)
  20. python 召回率_使用sklearn获取精确性和召回率

热门文章

  1. 计算机在线是什么,TIM电脑在线是什么意思?如何设置QQ显示tim电脑在线
  2. Linux防火墙(firewalld)使用方法,
  3. 牛客优聘,易上手、人才优、双奔赴,招聘神器真香了!
  4. echarts实现象形柱状图
  5. 【Leetcode】Number of Islands
  6. python批量下载文件只有1kb_python 批量下载文件
  7. 提高英语听力最好的学习方法
  8. 《精益创业》读后思考 2
  9. 【课程设计】重温经典,推箱子游戏,你能闯到第几关?可自行添加关卡(源码 + 详解)
  10. 利用数组操作实现灰度图像放大两倍(C++opencv)