网络训练技巧--参数初始化与优化方法
实验日期
- 2021.10.07
实验环境
- python 3.8.8 64-bit(‘base’:conda)
Initialization
深度学习的参数权重是很重要的,设置不当可能会导致梯度消失或梯度爆炸(W的权重造成的影响)
- 深度学习会有比较多的层数
- 正向传播存在连乘
- 反向传播也存在连乘
- 连乘就意味着
- 连乘的数大于1,乘积就会一直变大
- 连乘的数小于1 , 乘积就会一直缩小
- 深度学习会有比较多的层数
一个好的初始化有以下两个主要优点
- 能够加快梯度下降的收敛
- 增加梯度下降收敛到较低训练(和泛化)误差的几率
初始化为0
for l in range(1, L):### START CODE HERE ### (≈ 2 lines of code)parameters['W' + str(l)] = np.zeros((layers_dims[l] , layers_dims[l - 1]))parameters['b' + str(l)] = np.zeros((layers_dims[l] , 1))
On the train set: Accuracy: 0.5
On the test set: Accuracy: 0.5
事实证明,这个神经网络将所有输入都标记为 0 , 没起到分类的作用
将所有参数都初始化为0 , 将导致不能打破神经元的对称性。
- 因为每一层的神经元接收的都是同样的输入,他们的初始参数相同,这将导致同一层的神经元经历相同的训练过程,所以相当于每一层都只有一个神经元。
- 若第一层为W1X1+b1W_1X_1+b_1W1X1+b1 , 第二层为W2X2+b2W_2X_2 + b_2W2X2+b2 , 两层连起来就是W2(W1X1+b1)+b2W_2(W_1X_1+b1) + b_2W2(W1X1+b1)+b2 , 这其实就是WX1+bWX_1 + bWX1+b , 神经网络将退化成一个简单的线性分类器
初始化为随机数
for l in range(1, L):### START CODE HERE ### (≈ 2 lines of code)parameters['W' + str(l)] = np.random.randn(layers_dims[l] , layers_dims[l - 1]) * 10parameters['b' + str(l)] = np.zeros((layers_dims[l] , 1))### END CODE HERE ###
On the train set: Accuracy: 0.83
On the test set: Accuracy: 0.86
起到分类作用
有些初始权值很大,激活函数的输出对于某些示例来说会非常接近 0 或 1,这样会带来一系列问题
- 比如算log( ) 时出现log( 0 )
He initialization
- 随机后乘以2dimension of the previous layer\sqrt{\frac{2}{\text{dimension of the previous layer}}}dimension of the previous layer2
for l in range(1, L + 1):### START CODE HERE ### (≈ 2 lines of code)parameters['W' + str(l)] = np.random.randn(layers_dims[l] , layers_dims[l - 1]) * np.sqrt((2 / layers_dims[l - 1]))parameters['b' + str(l)] = np.zeros((layers_dims[l] , 1))### END CODE HERE ###
- On the train set: Accuracy: 0.9933333333333333
- On the test set: Accuracy: 0.96
Gradient Checking
梯度验证时为了验证我们使用解析解所求的梯度是否正确
- 通过∂J∂θ=limε→0J(θ+ε)−J(θ−ε)2ε\frac{\partial J}{\partial \theta} = \lim_{\varepsilon \to 0} \frac{J(\theta + \varepsilon) - J(\theta - \varepsilon)}{2 \varepsilon}∂θ∂J=limε→02εJ(θ+ε)−J(θ−ε)来算的梯度的近似数值解
- 通过数值解与解析解的比较,来判断解析解的正确性
- 一般数值解只是用来验证解析解的正确性
一维Gradient Checking
- 假设J=θxJ = \theta xJ=θx
### START CODE HERE ### (approx. 1 line)J = theta * x### END CODE HERE ###
- 求梯度
### START CODE HERE ### (approx. 1 line)dtheta = x### END CODE HERE ###
- 用∂J∂θ=limε→0J(θ+ε)−J(θ−ε)2ε\frac{\partial J}{\partial \theta} = \lim_{\varepsilon \to 0} \frac{J(\theta + \varepsilon) - J(\theta - \varepsilon)}{2 \varepsilon}∂θ∂J=limε→02εJ(θ+ε)−J(θ−ε)计算数值解 , 并计算difference=∥grad−gradapprox∥2∥grad∥2+∥gradapprox∥2difference = \frac {\| grad - gradapprox \|_2}{\| grad \|_2 + \| gradapprox \|_2 }difference=∥grad∥2+∥gradapprox∥2∥grad−gradapprox∥2
### START CODE HERE ### (approx. 5 lines)thetaplus = theta + epsilon # Step 1thetaminus = theta - epsilon # Step 2J_plus = thetaplus * x # Step 3J_minus = thetaminus * x # Step 4gradapprox = (J_plus - J_minus) / (2 * epsilon) # Step 5### END CODE HERE #### Check if gradapprox is close enough to the output of backward_propagation()### START CODE HERE ### (approx. 1 line)grad = x### END CODE HERE ###### START CODE HERE ### (approx. 1 line)numerator = np.linalg.norm(grad - gradapprox) # Step 1'denominator = np.linalg.norm(grad) + np.linalg.norm(gradapprox) # Step 2'difference = numerator / denominator # Step 3'### END CODE HERE ###
- 得到结果
- The gradient is correct!
- difference = 2.919335883291695e-10
N维Gradient Checking
- 与1维的比较类似,只不过要分层进行 , 分别对每一层进行检验
for i in range(num_parameters):#将第 i 层的 W 增加 epsilon , 计算最终lossthetaplus = np.copy(parameters_values) thetaplus[i][0] = thetaplus[i][0] + epsilon J_plus[i], _ = forward_propagation_n(X,Y,vector_to_dictionary(thetaplus)) #将第 i 层的 W 减少 epsilon , 计算最终lossthetaminus = np.copy(parameters_values) thetaminus[i][0] = thetaminus[i][0] - epsilon J_minus[i], _ = forward_propagation_n(X,Y,vector_to_dictionary(thetaminus)) #求的梯度的数值解gradapprox[i] = (J_plus[i] - J_minus[i]) / (2 * epsilon)#计算 difference numerator = np.linalg.norm(grad -gradapprox) denominator = np.linalg.norm(grad) + np.linalg.norm(gradapprox) difference = numerator / denominator
- 得到结果: difference = 1.1885552035482147e-07
Optimization Methods
BGD & SGD & MBGD
BGD
- 就是正常的梯度下降,每一次迭代都使用所有的输入来进行参数更新
- θj:=θj−α1m∑i=1m(hθ(x(i))−y(i))xj(i)\theta_j := \theta_j - \alpha \frac{1}{m} \sum_{i=1}^{m} (h_{\theta}(x{(i)})-y{(i)})x_j^{(i)}θj:=θj−αm1∑i=1m(hθ(x(i))−y(i))xj(i)
- 注意这里的求和符号,这是与SGD的差别
- 优点
- 一次迭代是对所有样本进行计算,此时利用矩阵进行操作,实现了并行。
- 由全数据集确定的方向能够更好地代表样本总体,从而更准确地朝向极值所在的方向。当目标函数为凸函数时,BGD一定能够得到全局最优
- 缺点
- 当样本数目很大时,每迭代一步都需要对所有样本计算,训练过程会很慢
SGD
- 与BGD的区别是,随机梯度下降是每次迭代使用一个样本来对参数进行更新。使得训练速度加快
- θj:=θj−α(hθ(x(i))−y(i))xj(i)\theta_j := \theta_j -\alpha (h_{\theta}(x{(i)})-y{(i)})x_j^{(i)}θj:=θj−α(hθ(x(i))−y(i))xj(i)
- 优点
- 由于不是在全部训练数据上的损失函数,而是在每轮迭代中,随机优化某一条训练数据上的损失函数,这样每一轮参数的更新速度大大加快
- 缺点
- 准确度下降。由于即使在目标函数为强凸函数的情况下,SGD仍旧无法做到线性收敛
- 可能会收敛到局部最优,由于单个样本并不能代表全体样本的趋势
- 不易于并行实现
- 搜索比较盲目
MBGD
- 每次迭代 使用 batch_size个样本来对参数进行更新。是对上面两种方法的折中
- 比如batch_size = 10
- θj:=θj−α110∑k=ii+9(hθ(x(k))−y(k))xj(k)\theta_j := \theta_j - \alpha \frac{1}{10} \sum_{k=i}^{i+9}(h_{\theta}(x{(k)})-y{(k)})x_j{(k)}θj:=θj−α101∑k=ii+9(hθ(x(k))−y(k))xj(k)
- 优点
- 通过矩阵运算,每次在一个batch上优化神经网络参数并不会比单个数据慢太多
- 每次使用一个batch可以大大减小收敛所需要的迭代次数,同时可以使收敛到的结果更加接近梯度下降的效果
- 可实现并行化。
- 缺点
- batch_size的不当选择可能会带来一些问题。
- 振荡前进
(Batch)Gradient Descent
- 对每一层的参数来说 , 更新都是以当前值减去学习率乘以梯度
- W[l]=W[l]−αdW[l]W^{[l]} = W^{[l]} - \alpha \text{ } dW^{[l]}W[l]=W[l]−α dW[l]
- $ b^{[l]} = b^{[l]} - \alpha \text{ } db^{[l]}$
- 代码实现
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)]
Mini-Batch Gradient Descent
- 原理上面已经进行介绍
- 代码实现
for k in range(0, num_complete_minibatches):#shuffled_X是被打乱顺序的 X , 为了保持数据的随机性 , 生成所有整块的mini-batchmini_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的情况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)
动量学习法(Momentum)
可以用来减少迭代过程中的振荡,加快搜寻速度
该方法考虑了之前参数的迭代方向
更新方式为
- v=βv−α▽wv = \beta v - \alpha \bigtriangledown wv=βv−α▽w
- w=w+vw = w + vw=w+v
- vvv 就代表着 www 的更新方向和大小
- β\betaβ 是超参 , 代表着之前的 vvv 对当前影响的衰减
- α\alphaα 为学习率
- −▽w-\bigtriangledown w−▽w 代表着当前数据的梯度方向 , 也就是当前 www 应该进行更新的方向
- 合起来看 vvv 就是当前 www 在之前的梯度和当前梯度的影响下应该进行的更新
初始化 v
for l in range(L):### START CODE HERE ### (approx. 2 lines)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)### END CODE HERE ###
实验中的更新方式 , 与上面原理相同,方式有差异
- vdW[l]=βvdW[l]+(1−β)dW[l]v_{dW^{[l]}} = \beta v_{dW^{[l]}} + (1 - \beta) dW^{[l]}vdW[l]=βvdW[l]+(1−β)dW[l]
- W[l]=W[l]−αvdW[l]W^{[l]} = W^{[l]} - \alpha v_{dW^{[l]}}W[l]=W[l]−αvdW[l]
for l in range(L):# compute velocitiesv["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)]# update parametersparameters["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)]### END CODE HERE ###
自适应动量优化(Adam)
- 初始化参数
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)
- 参数更新
- 更新公式
- vW[l]=β1vW[l]+(1−β1)∂J∂W[l]v_{W^{[l]}} = \beta_1 v_{W^{[l]}} + (1 - \beta_1) \frac{\partial J }{ \partial W^{[l]} }vW[l]=β1vW[l]+(1−β1)∂W[l]∂J
- vW[l]corrected=vw[l]1−(β1)tv^{corrected}_{W^{[l]}} = \frac{v_{w^{[l]}}}{1 - (\beta_1)^t}vW[l]corrected=1−(β1)tvw[l]
- sW[l]=β2sW[l]+(1−β2)(∂J∂W[l])2s_{W^{[l]}} = \beta_2 s_{W^{[l]}} + (1 - \beta_2) (\frac{\partial J }{\partial W^{[l]} })^2sW[l]=β2sW[l]+(1−β2)(∂W[l]∂J)2
- sW[l]corrected=sW[l]1−(β2)ts^{corrected}_{W^{[l]}} = \frac{s_{W^{[l]}}}{1 - (\beta_2)^t}sW[l]corrected=1−(β2)tsW[l]
- W[l]=W[l]−αvW[l]correctedsW[l]corrected+εW^{[l]} = W^{[l]} - \alpha \frac{v^{corrected}_{W^{[l]}}}{\sqrt{s^{corrected}_{W^{[l]}}}+\varepsilon}W[l]=W[l]−αsW[l]corrected+εvW[l]corrected
- 第一项就是 v , 考虑了动量
- 第二项是对第一项做的修正。因为初始时 , vWv_WvW 为 0 , 如果β1\beta_1β1还比较大 , 那么在利用 v 更新 w 时的变化就会很小
- 如果没有考虑动量 , 则第一次更新时使用的梯度为 $ \frac{\partial J }{ \partial W^{[l]} }$ , 考虑了动量之后,第一次更新时使用的梯度为(1−β1)∂J∂W[l](1 - \beta_1) \frac{\partial J }{ \partial W^{[l]} }(1−β1)∂W[l]∂J , 显然变小了,我么不想让前面的更新太慢,进行修正。其中 t 为迭代次数 。 t 小时 1−(β1)t1 - (\beta_1)^t1−(β1)t 就比较小 , 这样可以让 v 除以一个比较小的数,从而变大
- 当迭代次数增加后,我们不需要让 v 变大了 , 这时 t 已经变大了 1−(β1)t1 - (\beta_1)^t1−(β1)t 就变得很小 , v 除以一个接近 1 的数,就不会变大了
- 第三项 , 考虑了之前的梯度(类似动量 v ) , 是为了调节学习率的衰减量 , α\alphaα 除以第三项的根号用来调节学习率
- 针对每个参数设置学习率 , 因为所有参数不一定适应同一个学习率
- 在过去和现在的梯度之间做一个均衡
- 平方是为了防止梯度之间相互抵消
- 第四项和第二项作用相同
for l in range(L): 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_corrected["dW" + str(l+1)] = v["dW" + str(l+1)] / (1 - pow(beta1 , t))v_corrected["db" + str(l+1)] = v["db" + str(l+1)] / (1 - pow(beta1 , t))s["dW" + str(l+1)] = beta2 * s["dW" + str(l+1)] + (1 - beta2) * pow(grads["dW" + str(l+1)] , 2)s["db" + str(l+1)] = beta2 * s["db" + str(l+1)] + (1 - beta2) * pow(grads["db" + str(l+1)] , 2)s_corrected["dW" + str(l+1)] = s["dW" + str(l+1)] / (1 - pow(beta2 , t))s_corrected["db" + str(l+1)] = s["db" + str(l+1)] / (1 - pow(beta2 , t))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))
不同优化方法之间的效果差异
MBGD
- Accuracy: 0.7966666666666666
MBGD with momentum
- Accuracy: 0.7966666666666666
MBGD with Adam
- Accuracy: 0.94
结论分析与体会
参数初始化实验
- 深度学习模型参数 W 都初始化为 0 , 会退化为线性分类器
- 深度学习模型的参数初始化过大或过小 , 在模型层数较多的情况下都不太好 , 可能造成梯度爆炸或梯度消失
梯度检验实验
- 运算过程中,我们倾向于使用解析解得到的梯度
- 数值解得到的梯度可以用来检验解析解的正确性
优化方法实验
- 对BGD , SGD , MBGD的原理有了一定的了解 , 并对这三个梯度下降方法的优缺点有了了解
- 了解了动量学习法,这种方法可以减少在寻找最优解时的振荡,能够加快学习过程
- 了解了Adam , 这种方法的特点是
- 考虑了动量
- 构造了合理的学习率的衰减因子
- 可以针对每个参数设置学习率
网络训练技巧--参数初始化与优化方法相关推荐
- 深度学习 网络训练技巧
网络训练技巧: 1.数据增强:缩放.随机位置截取.翻卷.随机旋转.亮度.对比度.颜色变化等方法. 2.学习率衰减:随着训练的进行不断的减小学习率. 例如:一开始学习率0.01,在10000步后降为0. ...
- 深度学习网络训练技巧
(改了点) 转载请注明:炼丹实验室 新开了一个专栏,为什么叫炼丹实验室呢,因为以后会在这个专栏里分享一些关于深度学习相关的实战心得,而深度学习很多人称它为玄学,犹如炼丹一般.不过即使是炼丹也是可以摸索 ...
- 深度学习-网络训练技巧
1.深度学习的一些基本概念,学习率.batch.epoch.optimizer.评价函数(损失函数)等 1.1 学习率(Learning Rate) 学习率:是控制模型学习效率(步长)的权重. 学习率 ...
- 设置随机种子之后,网络训练结果仍然不同的解决方法(针对随机采样的数据集)torch设置随机种子,num_worker对数据采样的影响。
网络训练结果无法复现 设置随机种子 应该为torch, numpy,以及Python设置随机种子,并提高torch卷积精度. def set_seed(seed):random.seed(seed)n ...
- 鱼眼参数的数值计算优化方法
在下面两篇文章中,我们大概介绍了开源图像处理软件 Hugin 中鱼眼图像的矫正方法,即如何将目标全景图上的坐标映射到鱼眼图像上,从而获取相应的像素信息. https://blog.csdn.net/q ...
- CPU CACHE优化 性能优化方法和技巧
转载来源:性能优化方法和技巧 系列目录 性能优化方法和技巧 性能优化的方法和技巧:概述 性能优化的方法和技巧:代码 性能优化的方法和技巧:工具 这是一个可以用一本书来讲的话题,用一系列博客来讲,可能会 ...
- Numpy实现BP神经网络(包含Dropout、BN等训练技巧)
BP神经网络 简介 本文主要通过在MNIST数据集上使用全连接神经网络对比有无归一化.有无Dropout以及有无Batch Normalization进行训练,可视化分析常用的深度网络训练技巧的原因及 ...
- TensorFlow2-网络训练技巧
TensorFlow2网络训练技巧 文章目录 TensorFlow2网络训练技巧 简介 过拟合与欠拟合 过拟合问题 动量(Momentum)SGD 学习率衰减(learning rate decay) ...
- caffe训练技巧总结
一 数据集的制作 我们经常用到的原始数据是图片文件,如jpg,jpeg,png,tif等格式的,而且有可能图片的大小还不一致,而在caffe中经常使用的数据类型是lmdb或leveldb. 1. 数据 ...
最新文章
- MAC OS X El CAPITAN 搭建SPRING MVC (1)- 目录、包名、创建web.xml
- GoldenGate SQL error 1403 mapping 错误解决方案
- 获取Dataset前几条数据的两种方法
- Coursera自动驾驶课程第2讲:The Requirements for Autonomy
- Linux 系统中的dvfs功能
- gcn代码pytorch_GCN的简单实现(pytorch)
- Unit01: Servlet基础 、 HTTP协议
- 2021-02-22 【转载】什么是GCJ-02火星坐标系;为什么天地图没有偏移
- 配置devtools热部署
- 大数据系列2-liunx基础-2基本操作
- ubuntu 18.04忘记登录密码的破解方法
- 程序化广告(二)- 考核指标如CTR/CVR/ROI/ARPU等
- 2017年mysql考试时间_2017年计算机二级考试时间是哪一天
- 体积光渲染——SRP实现
- 教你如何玩转豆瓣(douban) 豆瓣使用入门!
- unbuntu samba共享文件夹
- python快乐数字怎么表达_Python中的快乐数字
- 图像运动模糊及其去除
- 读《MBA教不会的创富课》
- python 异步爬取必应搜索结果
热门文章
- 二维和三维CAD设计Autodesk AutoCAD 2021
- 动力节点老杜javaweb笔记丰富总结
- 基于人形检测的划区域客流统计
- 埃森哲全球“技术展望2018”报告解析(附下载链接)
- 【Java集合】List接口常用方法及实现子类
- 简单说 CSS中的mask—好好利用mask-image
- 新智元【Yoshua Bengio 亲自解答】机器学习 81 个问题及答案(最全收录)
- 技术精湛,保障有力!麒麟信安获国网重庆市电力公司感谢信
- 【案例分享】高效率利器 - SC 频谱分析仪
- 表示自己从头开始的句子_形容“从头开始”的诗句有哪些?