notebook notebook
首页
  • 计算机网络
  • 计算机系统
  • 数据结构与算法
  • 计算机专业课
  • 设计模式
  • 前端 (opens new window)
  • Java 开发
  • Python 开发
  • Golang 开发
  • Git
  • 软件设计与架构
  • 大数据与分布式系统
  • 常见开发工具

    • Nginx
  • 爬虫
  • Python 数据分析
  • 数据仓库
  • 中间件

    • MySQL
    • Redis
    • Elasticsearch
    • Kafka
  • 深度学习
  • 机器学习
  • 知识图谱
  • 图神经网络
  • 应用安全
  • 渗透测试
  • Linux
  • 云原生
面试
  • 收藏
  • paper 好句
GitHub (opens new window)

学习笔记

啦啦啦,向太阳~
首页
  • 计算机网络
  • 计算机系统
  • 数据结构与算法
  • 计算机专业课
  • 设计模式
  • 前端 (opens new window)
  • Java 开发
  • Python 开发
  • Golang 开发
  • Git
  • 软件设计与架构
  • 大数据与分布式系统
  • 常见开发工具

    • Nginx
  • 爬虫
  • Python 数据分析
  • 数据仓库
  • 中间件

    • MySQL
    • Redis
    • Elasticsearch
    • Kafka
  • 深度学习
  • 机器学习
  • 知识图谱
  • 图神经网络
  • 应用安全
  • 渗透测试
  • Linux
  • 云原生
面试
  • 收藏
  • paper 好句
GitHub (opens new window)
  • 深度学习

    • Posts

    • PyTorch 入门

    • 鱼书进阶-自然语言处理

    • 深度学习-李宏毅

      • Regression
      • 神经网络训练不起来怎么办
        • 1. General Guidance
          • 1.1 model bias
          • 1.2 optimization issue
          • 1.3 overfitting
        • 2. local minima 与 saddle point
          • 2.1 Critical Point
          • 2.2 判断是 local minima 还是 saddle point
          • 2.3 Saddle Point v.s. Local Minima
        • 3. Batch
          • 3.1 larger batch 可能花费时间更少
          • 3.2 small batch 训练得到的精确度可能更好
          • 3.3 small batch 更容易泛化
        • 4. Momentum
        • 5. Adaptive Learning Rate
          • 5.1 training stuck ≠ small gradient
          • 5.2 Different parameters needs different learning rate
          • 5.3 Root mean square 与 Adagrad
          • 5.4 RMSProp
          • 5.5 Adam
          • 5.6 Learning Rate Scheduling
        • 6. Batch Normalization
          • 6.1 Introduction
          • 6.2 Feature Normalization
          • 6.3 Considering Deep Learning
          • 6.4 Comparison
      • CNN
      • Self-Attention
      • 各式各样的 Attention
      • Pointer Network
      • 图神经网络
      • Transformer
      • 生成对抗网络 GAN
      • Self Supervised Learning
      • BERT and its family
      • Data Efficient & Parameter-Efficient Tuning
      • Auto-Encoder
      • 机器学习的可解释性
      • Adversarial Attack
      • Domain Adaptation
      • 强化学习
      • 神经网络压缩
      • Life Long Learning
      • Meta Learning
      • ChatGPT 是怎样炼成的
    • 李宏毅-2017版

    • 李宏毅-2019版

    • 预训练语言模型-邵浩2021版

    • 王树森

  • 机器学习

  • 知识图谱

  • AI
  • 深度学习
  • 深度学习-李宏毅
yubin
2022-04-03
目录

神经网络训练不起来怎么办

# 1. General Guidance

训练模型的过程中,以下就是如何让你做得更好的攻略:

image-20220403195635625

当对训练结果不满意时(testing data 的 loss 太大),首先应检查你的 training data,看看你的 model 有没有在 training data 上学起来,再去看 testing 的结果。如果你发现你的 training data 的 loss 很大,显然它在训练集上面也没有训练好,接下来你要分析一下在训练集上面没有学好是什么原因。一种原因是 model bias,一种是 optimization 的问题。

# 1.1 model bias

所谓 model bias 的意思是说,你的 model 太过简单。

img

举例来说,我们现在写了一个有未知 parameter 的 function,这个未知的 parameter,我们可以代各种不同的数字,你代 就可以得到一个 function ,代 就可以得到一个 function ,把所有的 function 集合起来,可以得到一个 function set。

如果 model 太简单,那么这个 function set 太小了,使得它没有包含任何一个 function 可以让我们的 loss 变得够低。这时即便找到这里面最好的那个 function ,依然无济于事,这个 loss 还是不够低。

这个状况就像你想要在大海里面捞针,这个针指的是一个 loss 低的 function,结果针根本就不在海里面。

Solution:重新设计一个 model,给你的 model 更大的弹性。比如增加输入的 features、设计一个更大的 model …

# 1.2 optimization issue

但是并不是 training 的时候,loss 大就代表一定是 model bias,你可能会遇到另外一个问题:optimization 做得不好。

我们可能卡在一个 local minima 的地方,这时你没有办法找到一个真的可以让 loss 很低的参数,如图:

img

这就好像是说我们想大海捞针,针确实在海里,但是我们却没有办法把针捞起来。

这就产生了一个问题:training data 的 loss 不够低的时候,到底是 model bias,还是 optimization 的问题呢?一个建议判断的方法,就是你可以透过比较不同的模型,来得知你的 model 现在到底够不够大。

image-20210311214054168

举一个例子,如上图,有两个 network,一个有 20 层,一个有 56 层,现在我们把它们测试在测试集上,这个横轴指的是 training 的过程。随着参数的 update,当然你的 loss 会越来越低,但是结果 20 层的 loss 比较 56 层的 loss还高,这说明 56 层的 network 的 optimization 没有做好,因为 20 层 network 能做到的事,56 层可以轻而易举地做到。

所以如果 56 层的 optimization 成功的话,它的 loss 应当是比 20 层的 network 低的。

那么,我们怎样知道我们的 optimization 有没有做好?这边给的建议是:看到一个你从来没有做过的问题,也许你可以先跑一些比较小的、比较浅的network,这些 model 会竭尽全力地找出一组最好的参数,不太会有失败的问题。所以我们可以先 train 一些比较简单的 model,先可以知道它们可以得道什么样的 loss。

If deeper networks do not obtain smaller loss on training data, then there is optimization issue.

img
  • 这个 5 layer 的 model 就是 optimization 没有做好

如果 optimization 没有做好该怎么办?我们会在之后讲。

# 1.3 overfitting

假设你现在经过一番的努力,你已经可以让 training data 的 loss 变小了,那接下来你就可以来看 testing data loss,如果它仍很大,那可能真的遇到 overfitting 的问题了。

注意,training 的 loss 小,testing 的 loss 大,才有可能是 overfitting,而不是一看到 testing 上结果不好就说是 overfitting 了。

什么是 overfitting 不再介绍了。

# 2. local minima 与 saddle point

# 2.1 Critical Point

我们只讨论 Optimization 的时候,怎么把 gradient descent 做得更好,为什么 Optimization 会失败呢?

常常在做 Optimization 时,你会发现,随着你的参数不断的 update,你的 training 的 loss 不会再下降,但是你对这个 loss 仍然不满意。比如你把 deep 的 network 与 shallow network 比较,发现 deep 的并没有做得更好,所以你会觉得 deep network 没有发挥它完整的力量,所以 Optimization 显然是有问题的。有时候甚至会发现,一开始你的 model 就 train 不起来,不管你怎样 update 你的参数,你的 loss 通通掉不下去,这时候到底发生了什么事呢?

过去常见的一个猜想是我们走到了一个地方,这个地方参数对 loss 的微分为零,这样 gradient descent 就没有办法再 update 参数了,loss 当然就不会再下降了。

img

local minima 和 saddle point 的 gradient 都是 0,所以当你的 loss 没有办法再下降时,也许就是因为卡在了这样的地方,它们统称为 critical point。

但是今天如果你发现你的 gradient 真的很靠近 0,卡在了某个 critical point,我们有没有办法知道,到底是 local minima 还是 saddle point?其实是有办法的。

为什么我们想知道到底是卡在 local minima 还是卡在 saddle point 呢?

  • 如果卡在 local minima,那可能就没有路可以走了。因为四周都比较高,你所在的位置就是最低点了
  • 如果卡在 saddle point 的话,它的旁边是还有路可以让 loss 变低的,只要你逃离 saddle point,你就有可能让你的 loss 更低

如何鉴别今天的一个 critical point 是属于 local minima 还是 saddle point 呢?

# 2.2 判断是 local minima 还是 saddle point

虽然我们没有办法完整知道整个 loss function 的样子,但如果给定某一组参数,比如说蓝色的这个 ,在 附近的 loss function 是有办法写出来的。所以 完整的样子写不出来,但它在 附近,既可以用一个 Taylor 级数展开来表示它:

image-20220404073642773
  • 第一项是 ,当 与 很近时, 与 也是很靠近的
  • 第二项是 ,这个绿色的 是一个向量,它就是我们的 gradient,它会弥补 与 之间的差距,这个向量的第 i 个元素就是 的第 i 个元素对 L 的微分,如下图:
image-20220404074527896
  • 第三项会再补足加上 gradient 之后与真正的 之间的差距。其中有一个 Hessian 矩阵 ,计算方式为:。

比如参数有 和 ,那分别求出 、、、 即可得到 。

当我们走到一个 critical point 时,意味着 gradient 为 0,也就是绿色的这一项完全不见了,只剩下红色的这一项。所以在 critical point 处,它的 loss function 可以被近似为 加上红色这一项。根据红色这一项,我们就可以判断 附近的 error surface 长什么样,从而判断是 local minima 还是 saddle point。

image-20220404075617386

怎样根据 Hessian,即红色这一项,来判断附近的地貌呢?这可以通过将附近的 代入计算:

img

但是我们怎么可能把所有的 都拿来试一下呢,所以需要一个更加简便的方法来确认。这就需要线性代数的知识了,如果对于所有的 而言, 都大于 0,那这个矩阵 叫做正定矩阵(positive definite matrix),它的所有 eigen value(特征值)都是正的。于是我们可以得出如下的结论:

判断是 local minima 还是 saddle point

求出 的 eigen value,如果:

  • 所有 eigen value 都是正的,那代表 ,这是一个 local minima;
  • 所有 eigen value 都是负的,那代表 ,这是一个 local maxima;
  • 如果 eigen valule 有正有负,那代表这是一个 saddle point。

以上我们借助 Hessian 矩阵来判断出了一个 critical point 是属于 local minima 还是 saddle point,但在实际的 implementation 里面,你几乎不会真的把 Hessian 算出来,这个要是二次微分,需要的运算量非常大,更遑论还要求它的eigen value,所以你几乎看不到有人用这一个方法来逃离 saddle point。之后我们会讲其他的方法来逃离 saddle point,我们这里讲这个方法,是想说,如果是卡在 saddle point,也许没有那么可怕,最糟的状况下你还有这一招可以告诉你要往哪一个方向走。

# 2.3 Saddle Point v.s. Local Minima

一个问题是,到底 saddle point 跟 local minima 谁比较常见呢?

我们先讲一个可能不太相关的故事。1543 年东罗马帝国的国王不知道要怎么对抗土耳其人,这时有人找来一个魔法师,叫做狄奥伦娜。他有一个能力跟张飞一样,可以“万军从中取上将首级如探囊取物”,这个狄奥伦娜也一样,他可以直接取得那个苏丹的头。大家想让狄奥伦娜展示一下他的能力,于是他一下拿出了一个圣杯,这个圣杯本来是放在圣索菲亚大教堂的地下室,而且它是被放在一个石棺里面,这个石棺是密封的,没有人可以打开它,但狄奥伦娜却取了出来。为什么他可以做到呢?因为这个石棺你觉得它是封闭的,那是因为你是从三维的空间来看,但狄奥伦娜可以进入四维的空间,从高维的空间中这个石棺是有路可以进去的,它并不是封闭的。

image-20220404084246805

总之这个从三维的空间来看,是没有路可以走的东西,在高维的空间中是有路可以走的,那 error surface 会不会也一样呢?

当你在一维的空间中,一维的一个参数的 error surface,你会觉得好像到处都是 local minima,但是会不会在二维空间来看,它就只是一个 saddle point 呢?如下图所示:

img

略过实验过程,从经验上看起来,其实 local minima 并没有那么常见,多数的时候,你觉得你 train 到一个地方,你的 gradient 真的很小,然后你的参数不再 update 了,往往是因为你卡在了一个 saddle point。

# 3. Batch

实际上在算微分的时候,并不是真的对所有 data 算出来的 L 作微分,而是把所有的 data 分成一个一个的 mini-batch,每次拿一个 batch 来算 loss、算 gradient,从而 update 参数。所有的 batch 看过一遍,叫做一个 epoch。

image-20210315142626597

Small Batch v.s. Large Batch

image-20220404085703048

考虑如上的两个极端情况,假设我们有 20 笔训练资料:

  • 左边的 case 就是没有用 batch,batch size 设的跟训练资料一样多,这种情况叫做 Full Batch,就是没有 batch 的意思
  • 右边的 case 就是 batch size = 1

比较两者,会发现左边没有用 Batch 的方式,它蓄力的时间比较长,还有它技能冷却的时间比较长,你要把所有的资料都看过一遍才能够 update 一次参数。而右边的方法 batch size = 1 的时候,蓄力的时间比较短,每次看到一笔参数,你就会更新一次你的参数。

# 3.1 larger batch 可能花费时间更少

但实际上考虑并行运算的话,左边这个并不一定时间比较长。从真正的实验结果来看,比较大的 batch size,你要算 loss,再进而算 gradient,所需要的时间不一定比小的 batch size 要花的时间长。

Larger batch size does not require longer time to compute gradient.

一个实验结果如下图:

image-20220404090543327
  • 纵轴是花费的时间
  • 因为 GPU 有平行运算的能力,因此实际上当你的 batch size 小的时候,你要跑完一个 epoch 花的时间是比大的 batch size 还要多的
  • 但它平行运算能力终究是有个极限,所以你 batch size 真的很大的时候,时间还是会增加的

# 3.2 small batch 训练得到的精确度可能更好

可以看到 Large Batch 在时间上是有优势的。那在训练结果上呢?小的 batch 在训练过程中每一步会受到 noisy 的影响,而 noisy 的 gradient 反而可以帮助 training。我们来看一个实验结果,来比较不同 batch size 在精确度方面的不同:

image-20210315153147903
  • 横轴代表的是 Batch Size,从左到右越来越大
  • 纵轴代表的是正确率,越上面正确率越高,当然正确率越高越好

可以看到 batch size 越大,它在 training 和 validation 中的 acc 都在降低,这是一个 optimization issue。当你用大的 Batch Size 的时候,你的 optimization 可能会有问题。

为什么 small batch 的 noisy update 会在 training 中更好呢?一个可能的解释是:

image-20210315155345489
  • 假如你是 Full Batch,那你今天在 update 你的参数的时候,你就是沿著一个 loss function 来 update 参数,如果走到一个 critical point,就会停下来了从而不再更新参数
  • 假如你是 Small Batch,因为我们是每次挑出一个 batch 来算 loss,这样 update 参数的时候 loss function 是有差异的,比如第一个 batch 中用 L1 来算 gradient,到第二个 batch 时用 L2 来算 gradient,这样假设 L1 算 gradient 是 0,卡住了,但 L2 的 function 与 L1 不同,这样 L2 不会卡住从而 update。

# 3.3 small batch 更容易泛化

image-20210315160405510
  • 会发现,小的 batch 居然在 testing 的时候会比较好

一个解释是,大的 Batch Size,会让我们倾向于走到峡谷里面,而小的 Batch Size,倾向于让我们走到盆地里面:

img
  • local minima 也有好坏之分,好的 minima 更容易有好的 generalization。

Large Batch 比较 Small Batch

image-20210315164405953

它们各有擅长的地方,所以 batch size 变成另外一个你需要去调整的 hyperparameter。

那我们能不能够鱼与熊掌兼得呢,我们能不能够截取大的 Batch 的优点,跟小的 Batch 的优点,我们用大的 Batch Size 来做训练,用平行运算的能力来增加训练的效率,但是训练出来的结果同时又得到好的结果呢,又得到好的训练结果呢?这时有可能的,有多篇论文给出了一些思路,这里不再介绍。

image-20220404094100122

# 4. Momentum

Momentum 是另外一个可以对抗 critical point 的技术。

image-20220404094558500
  • 考虑物理世界,当一个球滚到 local minima 时,由于惯性,他可能继续向前走,从而翻过小坡逃离 local minima。

,一般的 Gradient Descent 长什么样子呢:

image-20210315170131552
  • 有一个初始参数 ,然后计算一下 gradient,再往 gradient 的反方向去 update 参数:。

而 Gradient Descent + Momentum 是不只往 Gradient 的反方向来移动参数,而是 Gradient 的反方向,加上前一步移动的方向,用两者加起来的结果去调整去到我们的参数。

image-20210315171104120
  • 先初始化一个参数 ,在 的地方计算 gradient 的方向 ,之后决定下一步怎么走:

之后一直进行这个过程。

来看一个简单的例子:

image-20220404095604056

当走到一个 local minima 的点时,已经没有 gradient 的方向了 ,但如果有 momentum 的话,就有办法继续走下去,因为下一步的方向不只看 gradient,这样翻过这个小丘的话,也许就走到了一个更好的 local minima。这就是 Momentum 有可能带来的好处。

# 5. Adaptive Learning Rate

critical point 可能并不是训练过程的最大障碍,本节介绍一个叫做 Adaptive Learning Rate 的技术,可以给每一个参数不同的 learning rate。

# 5.1 training stuck ≠ small gradient

为什么我们说 critical point 不一定是我们训练过程中最大的阻碍呢?大家训练 network 时会记录 loss,随着参数的 update,loss 会越来越小,最后卡住了,即 loss 不再下降,多数这时候大家会猜想是不是走到了 critical point 导致没有办法再更新参数。但实际真的这样吗?

当走到 critical point 时 gradient 会很小,但如果在你 loss 不再下降时确认一下 gradient,它并不一定很小,比如下面这个例子,当 loss不再下降时 gradient 并没有真的很小:

image-20220404202604212

gradient 是一个向量,下面是 gradient 的 norm,即 gradient 这个向量的长度,随着参数更新,你会发现说虽然 loss 不再下降,但是这个 gradient 的 norm 并没有真的变得很小。这样子的结果也许是遇到了这样的情况:

image-20220404202827560
  • 它的 gradient 仍然很大,只是 loss 不再减小了

所以你在 train 一个 network 的时候,发现 loss 不再下降,这时不要随便说卡在了 critical point,有时候可能就是单纯地 loss 没有办法再下降了。

在实际中,用一般的 gradient descend 其实很难让参数走到 critical point,多数时候还没有走到 critical point 就已经停止了。这不代表说 critical point 不是一个问题,而是说,当你用gradient descend 来做 optimization 的时候,你真正应该要怪罪的对象往往不是 critical point,而是其他的原因。

如果不是 critical point,那我们的 training 为什么会卡住呢?举下面一个简单的 error surface 的例子,我们有两个参数,两个参数值不一样时 loss 值也不一样,这样就画出了一个 convex 形状的 error surface,它的最低点在黄色的 X 处:

image-20210319095748513
  • 它在横轴的地方 gradient 非常小,也就是坡度变化非常平滑
  • 相比于横轴,其纵轴的 gradient 变化较大,也就是坡度变化非常陡峭

我们从黑色的点开始走,来做 gradient descend,会发现它做不好:

image-20220404210713530
  • 参数在峡谷的两端来回震荡,使得 loss 掉不下去。

这也许你会归因于 learning rate 太大导致步伐太大了,如果将 learning rate 调小之后呢?将 调到 之后终于不再震荡了,但走到坡度平滑的地方,这么小的 learning rate 根本没有办法再让我们的训练前进:

image-20220404211049091
  • 在左拐的这个小地方有十万个点,所以说很难前进。

显然就算是一个 convex 的 error surface,你用 gradient descend 也很难 train。所以我们需要更好的 gradient descend 版本,之前的所有参数设同样的 learning rate 是不太行的,而应该为每一个参数定制化其 learning rate。

# 5.2 Different parameters needs different learning rate

我们要怎样定制化 learning rate 呢?不同的参数需要什么样的 learning rate 呢?

从刚才的例子中可以看到一个大原则:在某一个方向上,如果 gradient 很小,非常平坦,那我们会希望 learning rate 调大一点;如果非常陡峭,则希望 learning rate 调小一点。

image-20220404212238607

那这个 learning rate 要如何自动调整呢?我们改一下 gradient descend 原来的式子,这里我们只看某一个参数 的情况,它在第 t 个 iteration 的值表示为 ,原先的 gradient descend 的更新方式为:

现在要为每一个参数定制化其 learning rate,我们就把 这一项改写成 ,于是有:

  • 这个 有一个上标 t 和一个下标 i,这说明它是 depend on 的,不同的参数我们要给它不同的 ;同时也是 iteration dependent 的,不同的 iteration 有不同的 。

所以现在的 learning rate 是一个 parameter dependent 的。那么这个 learning rate 有什么常见的计算方式呢?

# 5.3 Root mean square 与 Adagrad

有什么方式可以计算 呢?一个常见的方式是计算 gradient 的 Root Mean Square:

img

这一招经常用在 Adagrad 中。

为什么这一招可以做到坡度比较大的时候 learning rate 就减小,而坡度比较小的时候 learning rate 就放大呢?

image-20210319160639783
  • 在上面蓝色曲线的图中,坡度较小,gradient 值较小,这个 是 gradient 的平方和取平均再开根号,因此算出来的 也较小,这样 learning rate 就较大。
  • 下面绿色曲线则与蓝色的相反,其 learning rate 就相对较大。

所以有了 这一项,便可以根据每一个参数的 gradient 不同来自动调整 learning rate 的大小。

# 5.4 RMSProp

在刚刚的版本里,同一个参数的 learning rate 也会随着时间改变,但在刚刚假设中,好像同一个参数的 gradient 的大小是固定差不多的值,但事实上并不一定是这个样子的。

我们举下面这个新月形的 error surface:

image-20220404220401169
  • 考虑横轴方向,会发现绿色箭头这个地方坡度比较陡峭,所以我们需要比较小的 learning rate;而在红色箭头的时候坡度又变得平滑了起来,需要比较大的 learning rate。

所以,就算是同一个参数同一个方向,我们也期待说 learning rate 是可以动态调整的,于是就有了一个叫做 RMSProp 的新招数:

image-20210319212301760
  • 它的第一步跟刚刚讲的 Adagrad 方法一样
  • 在第二步中,刚刚算 Root Mean Square 时每一个 gradient 都有同等重要性,但在 RMSProp 里面,你可以自己调整现在这个 gradient 的重要程度:

这里面的 就像 learning rate 一样,是一个 hyperparameter:

  • 如果把 设很小,就代表说觉得新鲜热腾的 相较于之前算出来的 gradient 而言比较重要
  • 如果把 设很大,就代表我觉得新算出来的 gradient 不如之前的重要
image-20220404222210626

我们形象化地展示一个例子,下面这个黑线代表一个 error surface:

image-20220404222344056
  • 在陡峭的地方,你可以借助 来让 的计算更看重当前的 gradient,使得 step 小一些。

# 5.5 Adam

今天最常用的 optimization 策略就是 Adam:

image-20210319220458633

Adam 就是 RMSProp + Momentum,Adam 原始论文 (opens new window)。

在 pytorch 里面该 optimizer 已经帮我们写好了,里面也有一些参数需要调,但往往用预设的就够好了。

# 5.6 Learning Rate Scheduling

普通的 gradient descend 训练不起来 convex 形的 error surface,那加上 Adaptive Learning Rate 以后呢?

image-20220405063413039

a 图是普通的 gradient descend 训练的效果,b 图是加上 Adaptive Learning Rate 之后的效果。

之前是卡在了左转的地方,现在有了 Adagrad 之后,就可以继续走下去了,因为在左转处,左右方向的 gradient 很小,因此 learning rate 会自动调整,使得步伐变大从而不断前进。

接下来的问题是为什么快到终点时突然爆炸了呢?想想看,在计算 时是把过去所有看到的 gradient 都拿来做平均,这时:

  • 在纵轴方向上,初始地方的 gradient 很大
  • 在左转走了一段路以后,这个纵轴方向的 gradient 算出来都很小,因此这个纵轴方向就累积了很小的 ,累积到一定地步后,这个 step 就变很大,然后就暴走喷出去了
  • 喷出去以后也没关系,他就走到了一个 gradient 比较大的地方,以后这个 慢慢变大,这个参数 update 的步伐就慢慢变小
  • 所以你会发现,突然左右喷了一下,但这个喷了一下不会永远震荡,摩擦力会让他慢慢地又回到中间这个峡谷中。

但是累计一段时间后又会喷一下,怎么办呢?有一个办法也许可以解决这个问题,叫做 learning rate 的 scheduling:

image-20220405064432370

我们之前的 是一个固定值,而 learning rate scheduling 的意思是说我们不要把 当一个常数,而是让它跟时间有关。最常见的策略是 Learning Rate Decay,也就是随著时间的不断地进行,随著参数不断的 update,我们让这个 越来越小。

这是合理的,因为一开始我们距离终点很远,随著参数不断 update,我们距离终点越来越近,所以我们把 learning rate 减小,让我们参数的更新踩了一个煞车从而能够慢慢地慢下来。采取了 Learning Rate Decay 之后,可以看到消除了之前的“喷一下”(如下图 b 图):

image-20220405064924437

还有另外一个经典常用的 Learning Rate Scheduling 方式叫做 Warm Up:

image-20220405065215913
  • Warm Up 的方法是让 learning rate 先变大后变小。但这个变化的速度也是一个 hyperparameter。

在很多 network 的训练中都使用了 Warm Up:

img

Warm Up 这个黑科技用在了很多知名 network 中,但这些论文里面不解释说为什么用它,却在你不注意的地方告诉你说这个 network 要用这个黑科技才能训练起来。

一个可能的解释是说, 是用一个统计结果来告诉我们某一个方向的陡峭程度,但要看多笔数据之后这个统计才精确,所以一开始的统计是不精确的。

关于更多,有一个 Adam 的进阶版叫做 RAdam,细节可参考论文 RAdam (opens new window)

小结

我们对 optimization 的方法进行了改进,将原始的 gradient descend 进化到了这样一个版本:

image-20220405070202982

其实关于 optimizer 还有很多东西,这里不再展开了。

# 6. Batch Normalization

# 6.1 Introduction

之前我们说 error surface 如果很崎岖的话,会比较难 train,而 Batch Normalization 就是其中一个把山铲平的方法,从而变得容易去 train。

再来看 optimization 的问题,有时会发现 error surface 是 convex 的,即一个碗的形状,会很难去 train,即两个参数的 loss 斜率相差很大,一个很陡峭,一个很平坦,这时使用 adaptive learning rate 会有好的结果。但从另一个角度想,如果能把难做的 error surface 改掉,不就可以更好做了吗?

image-20220411163135642

假设我们有如下 model,输入是 和 ,没有 activation function:

image-20220411163250731

计算 loss 的过程如上图。

那什么样的情况会产生比较不好 train 的 error surface 呢?在上面的计算 loss 的过程中,如果 值很 small,那么当 有了一个 变化时,由此对最终的 loss 产生的变化 也很 small。如下图所示:

image-20220411164117732

反之,如果 值很 large,那么当 有了一个 变化时,由此对最终的 loss 产生的变化 也很 large:

image-20220411164324945

由此便产生了之前所说的很难 train 的情况。可以发现,当 input 的 feature 中每一个 dimension 的值的 scala 差距很大时就可能产生不同方向上斜率非常不同的 error surface 导致难以 train。

一个想法是给 feature 里不同 dimension 有同样的数值范围。其实有很多种不同的方法,合起来统称为 Feature Normalization。

# 6.2 Feature Normalization

以下所讲的方法只是Feature Normalization 的一种可能性。

假设 是我们所有的训练资料的 feature vector,再把所有训练资料的 feature vector 统统集合起来:

image-20220411165219525
  • 表示第二个样本的 feature 1

然后我们把不同笔资料里的同一个 dimension 里面的数值取出来,去计算某一个 dimension 的 mean 和 standard deviation 来做标准化。

以后我们用带 tilde 符号的表示被 normalize 后的数值。 经过 normalize 后所有 feature 不同 dimension 的数值都符合标准正态分布。这样的 gradient descent 会让训练更顺利。

# 6.3 Considering Deep Learning

# 6.3.1 对中间层的 feature 也做 normalize

刚刚我们对 做了标准化,但将 输入 network 后,中间层得到的 却又有了“different dims have different ranges”的现象,所以可以进一步做 normalize:

image-20220411170515131

这里有一个问题是:对 activation function 的输入做 normalize 还是对输出做?其实差异不大。一个经验是,如果 activate function 是 sigmoid 的话建议在输入前做。但其实也没差啦。

怎样对 做 Feature Normalization 呢?见下图:

image-20220411171233086

之后再往下就是:

image-20220411171301431
  • 注意计算 时做的是 element wise 操作。

# 6.3.2 考虑 “batch”

本来如果我们没有做 normalize,那改变 只会影响 ,但现在改变 会跟着改变 和 ,因此会接着改变 。对 也是如此,本来他们是分开独立处理,现在加了 Feature Normalization 以后,这三个 example,它们变得彼此关联了。因此,我们可以把 network 视为一个 large network。之前的 network 只吃一个 input 得到一个 output,而现在的 large network 是吃一堆 input 并产生一堆 output。

由于 GPU 的 memoey 不可能把整个 data set 都 load 进去,因此实际中,我们只会对一个 batch 里的 data 做 normalization,所以这招叫做 Batch Normalization。

这里有一个问题,你一定要有一个够大的 batch,才可以算得出近似于整个 corpus 的分布(即足够大的 batch 才能算出合理的 和 作为 approximation)。

# 6.3.3 normalize 后的额外操作

在做 Batch Normalization 的时候,往往还会在算出 后再额外做一个操作:

image-20220411172804946

这里的 和 可以想成是 network 的参数,是需要另外被 learn 出来的。这样网络结构如下:

image-20220411173020025

为什么要这个设计呢?因为 normalize 后均值就是 0 了,这给 network 加了限制,也许这个限制会产生一些负面影响,因此把 和 加回去,让 network 自己学习两个参数。

又有人会问加了这个操作,这不会又让不同的 dimension 有不同的 range 了嘛?有可能会吧,但设置初始值时 的元素会都设为 1, 的元素都初始为 0。这样一开始训练时每个 dimension 的分布还是很接近的,等训练时间够长后,逐渐找到一个比较好的 error surface 后, 和 才会逐渐起作用,这往往对训练是有帮助的。

# 6.3.4 inference 过程中的 moving average

以上说的是 training 过程,在 testing 过程中(也称为 inference),会产生一个问题:training 时是一个一个 batch 的,但当服务上线成一个 application 后,inference 过程不可能等一个 batch size 的数据来了再运算一次。那么 inference 时没有了 batch,该怎么计算这个均值 和方差 呢?

实际上,pytorch 已经帮我们做好了,Batch Normalization 在 testing 的时候,你不需要做什么特别处理,pytorch 就帮我们处理好了。如果有用 batch normalization,在 training 的时候,你每一个 batch 计算出来的 跟 ,他都会拿出来算 moving average。

image-20220411185802962
  • 在 training 时,每取一个 batch 时计算出来的 都会用来计算更新一个 ,过程如上图。

等到 inference 的时候,他会这样做:

image-20220411190034666
  • 这样在 testing 的时候就不用算 和 了。

# 6.4 Comparison

image-20220411190252164
  • 对比黑线和红线,可以看到使用了 batch normalization 后可以更快地得跑到最后收敛的 accuracy。尽管随着数据量的增多,最终收敛结果差不多。

关于 Batch Normalization 为什么会起作用,可以参考原论文,但目前也没有特别肯定的说法。但理论上至少支持了 Batch Normalization 可以改变 error surface,让其比较不崎岖的这个观点。

其实除了 Batch Normalization 还有很多其他的方法,更多可参考如下:

更多的 normalization 方法
  • Batch Renormalization (opens new window)
  • Layer Normalization (opens new window)
  • Instance Normalization (opens new window)
  • Group Normalization (opens new window)
  • Weight Normalization (opens new window)
  • Spectrum Normalization (opens new window)
编辑 (opens new window)
上次更新: 2022/10/03, 13:55:17
Regression
CNN

← Regression CNN→

最近更新
01
Deep Reinforcement Learning
10-03
02
误删数据后怎么办
04-06
03
MySQL 一主多从
03-22
更多文章>
Theme by Vdoing | Copyright © 2021-2024 yubincloud | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×