实验日期

  • 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_1W1​X1​+b1​ , 第二层为W2X2+b2W_2X_2 + b_2W2​X2​+b2​ , 两层连起来就是W2(W1X1+b1)+b2W_2(W_1X_1+b1) + b_2W2​(W1​X1​+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ε→0​2ε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ε→0​2ε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]​=β1​vW[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]​=β2​sW[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. 深度学习 网络训练技巧

    网络训练技巧: 1.数据增强:缩放.随机位置截取.翻卷.随机旋转.亮度.对比度.颜色变化等方法. 2.学习率衰减:随着训练的进行不断的减小学习率. 例如:一开始学习率0.01,在10000步后降为0. ...

  2. 深度学习网络训练技巧

    (改了点) 转载请注明:炼丹实验室 新开了一个专栏,为什么叫炼丹实验室呢,因为以后会在这个专栏里分享一些关于深度学习相关的实战心得,而深度学习很多人称它为玄学,犹如炼丹一般.不过即使是炼丹也是可以摸索 ...

  3. 深度学习-网络训练技巧

    1.深度学习的一些基本概念,学习率.batch.epoch.optimizer.评价函数(损失函数)等 1.1 学习率(Learning Rate) 学习率:是控制模型学习效率(步长)的权重. 学习率 ...

  4. 设置随机种子之后,网络训练结果仍然不同的解决方法(针对随机采样的数据集)torch设置随机种子,num_worker对数据采样的影响。

    网络训练结果无法复现 设置随机种子 应该为torch, numpy,以及Python设置随机种子,并提高torch卷积精度. def set_seed(seed):random.seed(seed)n ...

  5. 鱼眼参数的数值计算优化方法

    在下面两篇文章中,我们大概介绍了开源图像处理软件 Hugin 中鱼眼图像的矫正方法,即如何将目标全景图上的坐标映射到鱼眼图像上,从而获取相应的像素信息. https://blog.csdn.net/q ...

  6. CPU CACHE优化 性能优化方法和技巧

    转载来源:性能优化方法和技巧 系列目录 性能优化方法和技巧 性能优化的方法和技巧:概述 性能优化的方法和技巧:代码 性能优化的方法和技巧:工具 这是一个可以用一本书来讲的话题,用一系列博客来讲,可能会 ...

  7. Numpy实现BP神经网络(包含Dropout、BN等训练技巧)

    BP神经网络 简介 本文主要通过在MNIST数据集上使用全连接神经网络对比有无归一化.有无Dropout以及有无Batch Normalization进行训练,可视化分析常用的深度网络训练技巧的原因及 ...

  8. TensorFlow2-网络训练技巧

    TensorFlow2网络训练技巧 文章目录 TensorFlow2网络训练技巧 简介 过拟合与欠拟合 过拟合问题 动量(Momentum)SGD 学习率衰减(learning rate decay) ...

  9. caffe训练技巧总结

    一 数据集的制作 我们经常用到的原始数据是图片文件,如jpg,jpeg,png,tif等格式的,而且有可能图片的大小还不一致,而在caffe中经常使用的数据类型是lmdb或leveldb. 1. 数据 ...

最新文章

  1. MAC OS X El CAPITAN 搭建SPRING MVC (1)- 目录、包名、创建web.xml
  2. GoldenGate SQL error 1403 mapping 错误解决方案
  3. 获取Dataset前几条数据的两种方法
  4. Coursera自动驾驶课程第2讲:The Requirements for Autonomy
  5. Linux 系统中的dvfs功能
  6. gcn代码pytorch_GCN的简单实现(pytorch)
  7. Unit01: Servlet基础 、 HTTP协议
  8. 2021-02-22 【转载】什么是GCJ-02火星坐标系;为什么天地图没有偏移
  9. 配置devtools热部署
  10. 大数据系列2-liunx基础-2基本操作
  11. ubuntu 18.04忘记登录密码的破解方法
  12. 程序化广告(二)- 考核指标如CTR/CVR/ROI/ARPU等
  13. 2017年mysql考试时间_2017年计算机二级考试时间是哪一天
  14. 体积光渲染——SRP实现
  15. 教你如何玩转豆瓣(douban) 豆瓣使用入门!
  16. unbuntu samba共享文件夹
  17. python快乐数字怎么表达_Python中的快乐数字
  18. 图像运动模糊及其去除
  19. 读《MBA教不会的创富课》
  20. python 异步爬取必应搜索结果

热门文章

  1. 二维和三维CAD设计Autodesk AutoCAD 2021
  2. 动力节点老杜javaweb笔记丰富总结
  3. 基于人形检测的划区域客流统计
  4. 埃森哲全球“技术展望2018”报告解析(附下载链接)
  5. 【Java集合】List接口常用方法及实现子类
  6. 简单说 CSS中的mask—好好利用mask-image
  7. 新智元【Yoshua Bengio 亲自解答】机器学习 81 个问题及答案(最全收录)
  8. 技术精湛,保障有力!麒麟信安获国网重庆市电力公司感谢信
  9. 【案例分享】高效率利器 - SC 频谱分析仪
  10. 表示自己从头开始的句子_形容“从头开始”的诗句有哪些?