兄弟萌也可以到我的博客康康:冬于的博客
导致上述问题的原因可能有很多,我们先回忆一下梯度下降算法在现实世界中面临的挑战:
像这种gradient为0的点,统称critical point,我们先从问题1和问题2来看看如何“炼丹”。
gradient为0的点。
**现在所在的位置已经是局部loss最低的点,**往四周走 loss都会比较高,可能没有路可以走。
**saddle point从某个方向还是有可能到达loss更低的位置,**只要逃离saddle point,就有可能让loss更低。
通过泰勒级数展开估计(Tayler Series Approximation)loss function的形状。
也就是,虽然无法完整、准确写出 L ( θ ) L(\theta) L(θ),但如果给定某一组参数 θ ′ \theta' θ′,在 θ ′ \theta' θ′附近的loss function可以通过泰勒级数展开来估计:
总的来说, L ( θ ) L(\theta) L(θ)跟两个东西有关,跟gradient有关,跟hessian有关。gradient就是一次微分,hessian是内含二次微分的项目。
如果我们今天走到了一个critical point,意味着上式中 g = 0 g=0 g=0,只剩下 L ( θ ′ ) L(\theta') L(θ′)和红色的这一项:
于是可以通过红色这一项判断 θ ′ \theta' θ′附近的error surface长什么样,从而判断现在是在local minima、local max还是saddle point。
把 ( θ − θ ′ ) (\theta-\theta') (θ−θ′)用向量 v v v来表示,根据 v T H v v^THv vTHv的值来判断:
线性代数中,如果所有的 v v v带入 v T H v v^THv vTHv的值都大於零,那 H H H叫做positive definite 正定矩阵。所以我们不需要通过穷举所有的点来判断 v T H v v^THv vTHv是大于零还是小于零,而是直接利用 H H H是否正定来判断。而判断 H H H是否是正定矩阵可以通过求解 H H H的特征值来判断。如果所有的eigen value特征值都是正的,那么 H H H就是positive definite 正定矩阵。
所以判断条件就转化为:
** H H H不只可以帮助我们判断,现在是不是在一个saddle point,还指出了参数可以update的方向。**注意这个时候 g = 0 g=0 g=0。
根据 λ x = A x \lambda x=Ax λx=Ax,可以对式子进行转化:
于是如果 λ < 0 λ<0 λ<0(eigen value<0),那 λ ‖ u ‖ ² < 0 λ‖u‖²<0 λ‖u‖²<0,所以eigen value是负的,那这一整项就会是负的,也就是 u T H u u^THu uTHu是负的,也就是红色整项是负的,于是 L ( θ ) < L ( θ ′ ) L(\theta)
这个方法也有一点问题: H H H的运算量非常非常的大,还需要算其特征值和特征向量,运算量惊人,实际操作中还有其他方法可以逃离saddle point,在最糟糕的情况下还有这种方法可以逃离。
**事实上Local Minima没有那么常见。**一个可能的解释是:在低维的空间中,低维的一个参数的error surface,好像到处都是local minima,但是在高维空间来看,它可能只是一个saddle point。
如下图所示,几乎找不到完全所有eigen value都是正的critical point。下图这个例子种,minimum ratio代表正的eigen value的数目占总数的比例,最大也在0.5~0.6,代表只有一半的eigen value是正的,还有一半的eigen value是负的。
在这个图上,越往右代表critical point越像local minima,但是它们都没有真的,变成local minima。
每次在 Update 参数的时候,拿一个batch出来,算个 Loss,算个 Gradient,Update 参数,然后再拿另外个batch,再算个 Loss,算gradient,更新参数,以此类推。
mini-batch就是不把所有训练数据拿出来一起算loss,而是分小块。
所有的 Batch 训练过一遍,叫做一个 Epoch。
在生成batch的时候长春会做shuffle。
Shuffle 有很多不同的做法,常见的一个做法是在每一个 Epoch 开始之前,会分一次 Batch,每一个 Epoch 的 Batch 都不一样。
直接上对比图:
之前提到,更大的batch在看完更多的example后才会更新一次参数,但更新方向可能比小batch更准确(powerful,而小batch可能更noisy)如果都是串行的话,看上去更大的batch的参数更新速度更慢。
但实际上,在有并行计算条件下,比较大的 Batch Size算 Loss再进而算 Gradient所需要的时间,不一定比小的 Batch Size 要花的时间长。而更小的batch一个epoch的时间更长。(一个用于MINIST数据集上的实验如下图。)
所以看上去big batch的时间劣势消失了,那是不是big batch更好呢?
答案是否定的,神奇的地方是 Noisy 的 Gradient,反而可以帮助 Training。
用过大的batch size optimizer可能会有问题。
拿不同的 Batch 来训练模型,可能会得到下图的结果:
Batch Size 越大,Validation Acc 上的结果越差。但这个不是 Overfitting,因为如果 Training也是 Batch Size 越大,Training 的结果越差。
现在用的是同一个模型,它们可以表示的 Function 就是一模一样的,所以这个不是 Model Bias 的问题。这个是 Optimization 的问题,代表当用大的 Batch Size 的时候, Optimization 可能会有问题,小的 Batch Size,Optimization 的结果反而是比较好的。
一个可能的解释是这样子的,如下图所示:
论文On Large-Batch Training For Deep Learning,Generalization Gap And Sharp Minima中,就做了这样一个实验:努力的调big- Batch 的 Learning Rate,然后想办法把big-Batch的训练模型,跟small-Batch 训练得得一样好,结果发现small-Batch在 Testing 的时候是比较好的。
注意这个时候big-batch在训练集中表现和small-batch性能相似,但在测试集表现更差说明的问题才是over fitting。
为什么会这样呢?文章也给了一个解释:
假设这个实线是 Training Loss,那在这个 Training Loss 上面,可能有很多个 Local Minima,这些 Local Minima 它们的 Loss 都很低,它们 Loss 可能都趋近于 0。但是 Local Minima还是有好 Minima 跟坏 Minima 之分。
为什么这么判定呢?
假设现在 Training 跟 Testing 中间,有一个 Mismatch,Training 的 Loss 跟 Testing 的 Loss,它们的Function 不一样。导致这种mismatch的原因可能有两个:
那我们就假设这个 Training 跟 Testing的差距就是把 Training 的 Loss,这个 Function 往右平移一点(上图虚线为testing loss)。这时候会发现,对左边这个在一个盆地的 Minima 来说,它的在 Training 跟 Testing 上面的结果,不会差太多;但是对右边这个在峡谷的 Minima 来说,就差别很大。
它在这个 Training Set 上算出来的 Loss 很低,但是因为 Training 跟 Testing 之间的mismatch,所以 Testing 的时候,这个 Error Surface 变化后,算出来的 Loss 就变得很大。所以猜想这个大的 Batch Size,会让模型倾向于走到峡谷里面,而小的 Batch Size,倾向于让模型走到盆地裡面:
但这只是一个解释,实际上这个还是一个尚待研究的问题。
总的来说,大的 Batch 跟小的 Batch,它们各自有它们擅长的地方,**Batch Size,变成另外一个需要去调整的 Hyperparameter。**一些论文也讨论了如何兼顾鱼和熊掌,需要用一些特殊的方法来解决大的Batch Size 可能会带来的劣势:
Momentum是另外一个有可能可以对抗 Saddle Point,或 Local Minima 的技术。
加上 Momentum 以后,每一次在移动参数的时候,不是只往 Gradient 的反方向来移动参数,是 Gradient 的反方向+前一步移动的方向去调整去到参数
具体来看步骤如下:把蓝色的虚线加红色的虚线,前一步指示的方向跟 Gradient 指示的方向,当做参数下一步要移动的方向。
下面有一个例子来展示:
在第三步,Gradient 变得很小,但是没关系,如果有 Momentum 的话,根据上一步的Momentum 可以继续往前走;
甚至走到第四步时,Gradient 表示应该要往左走了,但是如果前一步的影响力,比 Gradient 要大的话,还是有可能继续往右走,甚至翻过一个小丘,可能可以走到更好 Local Minima。
critical point不一定是训练过程中最大的阻碍,思考一个问题:
并不是的。如下图所示虽然loss不再下降,但是这个gradient的大小并没有真的变得很小。它可能在error surface山谷的两个谷壁间,不断的来回的震荡。
所以有的时候训练不下去的原因不是critical point,而是其他的原因。
举个例子:
在下面这个error surface中,纵轴的参数变化很小就会导致结果变化很大,而横轴参数变化很大结果变化很小。
如果两个参数使用同一个学习率,当学习率调的过大,在纵轴方向可能直接震荡:
如果学习率调的很小,在纵轴可以逐渐找到好的参数,但是在横轴更新时,由于学习率过小,更新速度太慢,也很难找到最优解。
所以可以考虑为不同的参数和不同的iteration设置不同的learning rate。
上面的案例展示了学习率选择的两个大原则:
以一个参数 θ i \theta_i θi为例:
原始策略:
θ i t + 1 ← θ i t − η g i t \theta_i^{t+1}\leftarrow \theta_i^{t}-\eta g_i^t θit+1←θit−ηgit
不同的参数和不同的iteration自动调整策略:
θ i t + 1 ← θ i t − η σ t t g i t \theta_i^{t+1}\leftarrow \theta_i^{t}-\frac{\eta}{\sigma_t^t} g_i^t θit+1←θit−σttηgit
上式中 σ i t \sigma_i^t σit的下标 i i i代表它是depend on i i i的,也就是不同参数有不同的 σ \sigma σ,而上标 t t t表示它是iteration dependent的,不同的iteration会有不同的σ。因此 η σ t t \frac{\eta}{\sigma_t^t} σttη变成parameter dependent的learning rate。
那么如何计算 σ \sigma σ呢?
常见的计算 σ σ σ可以用gradient的Root Mean Square,这种计算方法也被用于Adagrad这一优化器中。
Root mean square计算 σ σ σ是通过求历史梯度的均方根得到的,计算步骤如下图所示:
看看下面这个例子:
现在我们有两个参数: θ ᵢ ¹ θᵢ¹ θᵢ¹和 θ ᵢ ² θᵢ² θᵢ² , θ ᵢ ¹ θᵢ¹ θᵢ¹坡度小 θ ᵢ ² θᵢ² θᵢ²坡度大。
θ ᵢ ¹ θᵢ¹ θᵢ¹因为坡度小,所以在 θ ᵢ ¹ θᵢ¹ θᵢ¹这个参数上面,算出来的gradient值都比较小,那么 σ σ σ也比较小, η σ \frac{\eta}{\sigma} ση就比较大。
所以有了 σ σ σ这一项以后,就可以随iteration gradient的不同,每一个参数的gradient的不同,来自动的调整learning rate的大小。
但是,就算是同一个参数,它需要的learning rate,也可能会随时间而改变,于是还有进阶版的策略自适应learning rate。
同一个参数同一个方向也希望可以自适应调整,比如下面这个新月形的error surface。
在水平方向(同一参数同一方向)在绿色箭头这个地方坡度比较陡峭,需要比较小的learning rate,走到了中间这一段,到了红色箭头坡度又变得平滑,需要比较大的learning rate。
RMSProp和Apagrad在计算 σ \sigma σ时,第一步时一样的,在第二步更新时,通过一个超参数 α \alpha α赋予了历史梯度和当前梯度不一样的权重(而Apagrad中是一样的权重,也就是每一个gradient同样重要)。
计算过程如下图所示:
α就像learning rate一样是一个hyperparameter,需要自己调整:
举个例子看一下RMSProp的效果:
下图中,一开始梯度很小,学习率较大;
到第三步时,梯度变大,原来的Adagrad反应比较慢,可能还会用比较大的学习率,但如果用RMS Prop,把α设小一点,也就是让新的gradient影响比较大,可以很快的让σ的值变大,于是很快的让学习率变小。
还记得前面提到了momentum这个方法,RMSProp+momentum就得到了一个高级版的策略:Adam。
这些优化器在pytorch等框架中都写好了,其中也包括很多超参数。李宏毅老师还提到往往用默认的超参数就够好了,自己调有时候反而会调到比较差的,炼丹玄学~
现在让我们回到前面提到的error surface上,加上Adagrad方法后,训练效果如下图右下角的子图所示:
加了Adagrad以后,在横轴方向learning rate会自动变大,从而能尽快接近最优解。但我们可以看到一个奇怪的现象,走到非常接近终点的位置,梯度突然爆炸了,这是为什么呢?
从Adagrad的 σ \sigma σ计算方式可以回答这个问题,计算 σ σ σ时,把过去所有看到的gradient,都拿来作平均:
所以这个纵轴的方向,在初始的时候gradient很大,学习率比较小;
可是继续走了很长一段路以后,gradient算出来都很小,于是y轴的方向就开始积累很小的σ;
累积到一个地步以后,学习率就变很大,于是发生爆炸;
爆炸后其实也没关系,因为爆炸后就走到gradient比较大的地方,于是σ又慢慢的变大,参数update学习率又慢慢的变小。
但是累计一段时间又会爆炸,然后恢复,反复。
解决这种问题的策略是learning rate scheduling,这里介绍两种:
在前面使用的Adagrad中, η \eta η被当作一个固定的值,而learning rate scheduling是指让 η \eta η和时间有关,常见的策略为:Learning Rate Decay(学习率衰减策略),随着训练不断进行,参数不断更新, η \eta η越来越小。
于是:一开始距离终点很远,随着参数不断update,距离终点越来越近,把learning rate减小,让参数更新减速,所以前面的那个问题,加上Learning Rate Decay可以解决。
Warm Up的方法是让learning rate,要先变大后变小。**其中变大到多大、变大速度、变小到多小、变小速度都是超参数。**如下图所示:
但是为什么需要Warm Up,为什么Warm Up有效都是待研究的问题,但在很多文献中,它就是work了,比如BERT、transformer等等模型中都用到了warm up这个技术。
李宏毅老师提到了一个可能的解释:
当我们在用Adam RMS Prop,或Adagrad的时候,需要计算σ,它是一个统计的结果,σ告诉我们,某一个方向它到底有多陡,或者是多平滑,这个统计的结果,要看得够多笔数据以后才比较精确,所以一开始我们的统计是不精确的。于是我们一开始不要让参数走离初始的地方太远,先让它在初始的做一些探索。所以一开始learning rate比较小,是让它探索 收集一些有关error surface的情报,先收集有关σ的统计数据,等σ统计得比较精準以后,在让learning rate呢慢慢地增大。
我们逐步将原始梯度下降方法进行优化:
注意:momentum和 σ σ σ虽然都与过去所有的gradient有关,一个放在分母,一个放在分子,但是momentum考虑了方向,而 σ σ σ只考虑了gradient的大小。
之前考虑的常见都是假设error surface非常崎岖情况下怎么找到比较好的参数,但其实我们可以从error surface出发,考虑如何把error surface变成一个比较平坦的,好训练的error surface,如下图所示:
通过修改损失函数和batch normalization可能可以做到修改error surface,让模型更好训练。
在讲分类模型的时候,李宏毅老师解释了为什么cross entropy更常用在分类上 ,并且用一个例子展示了loss function对error surface的影响。
我们这里直接看这个例子:
现在我们用下面这个模型做一个3个Class的分类任务,下面两个坐标系中的图是当loss function分别设定为Mean Square Error和Cross-entropy的时候,算出来的Error surface( y ₁ 、 y ₂ y₁、y₂ y₁、y₂的变化对loss的影响)。在红色部分(左上角)loss很大,蓝紫色部分(右下角)loss比较小。所以我们希望在训练后,参数走到右下角的地方。
假设我们开始的地方,都是左上角:
由此例可以发现,Loss function的定义也可能影响error surface从而影响Training,选一个合适的loss function可以改变optimization的难度。
这里补充一个资料,对于一些常见任务应该选择什么样的loss function进行了总结。深度学习中常见的激活函数与损失函数的选择与介绍
Batch Normalization是修改error surface,让模型更好训练的其中一个方法。
比如现在有两个参数,它们对 Loss 的斜率差别非常大,在 w 1 w_1 w1这个方向上面斜率变化很小,在 w 2 w_2 w2这个方向上斜率变化很大。如下图左边所示。
之前提到用daptive 的 learning rate,比如Adam 等等比较进阶的 optimization 的方法去更新参数,其实另一个角度就是**把这种很难训练的error surface改掉,**改成下图中右边所示。
于是我们需要思考:斜率差很多的这种状况,到底是哪里来的?
假设我们的模型上图中下半部分的简单模型:
因此,**希望给不同的 dimension,同样的数值范围(转为上图右边部分),将原本的error surface变成比较好训练的error surface。**可以完成这个操作的方法统称为feature normalization。
feature normalization可以让Loss 收敛更快一点,让梯度下降更顺利一点。
下面举一个常用的feature normalization方法:利用均值和方差进行标准化standardization。
假设 x 1 x^1 x1到 x R x^R xR是所有的训练数据的 feature vector,把所有训练数据的 feature vector ,统统都集合起来, x 1 1 x_1^1 x11代表 x 1 x_1 x1的第一个 element, x 1 2 x_1^2 x12就代表 x 2 x_2 x2的第一个 element,以此类推。
把不同样本即不同 feature vector,同一个 dimension 里面的数值计算均值mean m i m_i mi,并且计算第 i i i 个 dimension 的标准差standard deviation σ i \sigma_i σi。
然后用下式进行标准化standardization,然后用标准化后的 x ~ i r \tilde x_i^r x~ir作为模型的输入。
x ~ i r ← x i r − m i σ i \tilde x_i^r \leftarrow \frac{x_i^r-m_i}{\sigma_i} x~ir←σixir−mi
示意图如下:
做完 normalize 以后,这个 dimension 上面的数值平均是 0, variance是 1,所以一排数值的分布就都会在 0 上下。对每一个 dimension都做一样的 normalization,就会发现所有 feature 不同 dimension 的数值都在 0 上下,那可能就可以构造比较好的 error surface。
我们先用feature normalization对最原始的输入做了处理得到 x ~ \tilde x x~,那么经过第一层参数时,我们的输入各个维度的scale就是差不多的,但是深度学习的模型都是有很多层的,像下图这样**:上一层的输出是下一层的输入,那么经过了一层神经网络的特征(输出 z 1 z^1 z1或经过sigmoid层的输出 a 1 a^1 a1)各个维度可能又会有不同的scale。**
所以我们可以对 z z z或者 a a a做normalization。这里也有一个tips:
我们这边假设对 z z z做feature normalization,举个例子:
和之前对 x x x做的操作类似,对 z z z也是计算均值和方差,然后进行归一化:
这里有个地方需要特别注意:
上图中的 μ \mu μ跟 σ \sigma σ ,它们其实都是根据 z 1 , z 2 , z 3 z^1,z^2,z^3 z1,z2,z3算出来的,那么:
因为彼此关联,于是整个process(包括根据feature算均值方差)就变成了network的一部分,所以现在变成一个比较大的network,如下图所示。
自然而然地产生一个问题,是不能一次性把很大的一个训练集全部输入网络中训练的,因为内存有限。
再自然而然地就可以考虑不输入全部的数据,而是输入一部分(batch),每次只考虑一个batch里的样本,所以在实际操作中,是对一个batch做normalization,于是这个方法叫batch normalization。
显然一定要有一个够大的 batch,才算得出均值和方差,假设batch size=1,那么均值和方差就没啥好算的。
所以Batch Normalization适用于 batch size 比较大的时候。相当于我们用一个batch size的训练数据分布估计整个数据集的数据分布。如果 batch size 比较大,也许这个 batch size 里的 data足以表示整个 corpus 的分布。这个时候就可以把对整个 corpus做 Feature Normalization改成只在一个 batch做 Feature Normalization。
在做 Batch Normalization 的时候,往往还会对计算出来的 z ~ \tilde z z~进行下一步操作,得到最终的 z ^ \hat z z^:
z ^ i = γ ⊙ z ~ i + β \hat z^i=\gamma \odot \tilde z^i+\beta z^i=γ⊙z~i+β
其中 γ \gamma γ和 β \beta β是 network 的参数,在训练过程中被学习到的。如下图所示:
有一种猜测是,做 normalization 以后feature的平均就一定是 0,这可能会给 network 一些限制,也许这个限制会带来什麼负面的影响。所以在训练的时候,将$\beta 和 和 和\gamma$作为训练参数,重新调整其分布,让它的 hidden layer 的 output平均不是 0 。
如果是这样,那可能又会问:上一步做Batch Normalization 就是要让每一个不同的 dimension的 range 都是一样的,现在如果做这一步,不是又让 dimension 的分布不一样了吗?
答案是:确实有可能。以我们**在初始的时候,将$\beta 内 的 元 素 都 设 置 为 1 , 内的元素都设置为 1, 内的元素都设置为1,\gamma 内 的 元 素 都 设 置 为 0 。 ∗ ∗ 于 是 n e t w o r k 在 一 开 始 训 练 的 时 候 , 每 一 个 d i m e n s i o n 的 分 布 , 是 比 较 接 近 的 , 也 许 训 练 到 后 来 , 已 经 找 到 一 个 比 较 好 的 e r r o r s u r f a c e , 走 到 一 个 比 较 好 的 地 方 以 后 , 再 慢 慢 调 整 内的元素都设置为0。**于是 network 在一开始训练的时候,每一个 dimension 的分布,是比较接近的,也许训练到后来,已经找到一个比较好的 error surface,走到一个比较好的地方以后,再慢慢调整 内的元素都设置为0。∗∗于是network在一开始训练的时候,每一个dimension的分布,是比较接近的,也许训练到后来,已经找到一个比较好的errorsurface,走到一个比较好的地方以后,再慢慢调整\beta 和 和 和\gamma$。
之前说的都是training的时候要做什么,在testing(inference)的时候,想用batch normalization会有什么问题呢?
batch normalization需要一个batch的数据计算 μ \mu μ和 σ \sigma σ,在testing的时候,首先遇到的问题是,可能输入不够一个batch size,因为在工程上不可能等数据攒到一个batch size才开始计算输出。
也就是可能根本就不是一个batch的输入,应该怎么获得 μ \mu μ和 γ \gamma γ呢?
在实际操作中,如果是PyTorch 的话,Batch Normalization 在 testing 的时候,其使用的 μ \mu μ和 γ \gamma γ是通过:如果training的时候有做 Batch Normalization 的话,在 training 的时候,每一个 batch 计算出来的 μ \mu μ和 σ \sigma σ 都计算moving average,然后得到平均值( μ ˉ \bar \mu μˉ和 σ ˉ \bar \sigma σˉ),将这两个值作为testing的 μ \mu μ和 σ \sigma σ。如下图所示。
moving average的计算过程是:每一次取一个 batch 出来的时候,就会算一个 μ 1 \mu^1 μ1,取第二个 batch 出来的时候算 μ 2 \mu^2 μ2 ,一直到取第 t 个 batch 出来的时候算 μ t \mu^t μt,利用 μ 1 . . . μ t − 1 \mu^1...\mu^{t-1} μ1...μt−1算一个平均值得到 μ ˉ \bar \mu μˉ然后结合一个超参数 p p p更新 μ ˉ \bar\mu μˉ。
看看加了batch normalization的训练效果:横轴是训练过程,纵轴是在验证集上的精度。
在原始的 Batch Normalization那篇 paper 作者提出来一个概念,叫做 internal covariate shift。(友情先提醒这个猜测已经被推翻了)
其中covariate shift是本身存在的概念:训练集和预测集样本分布不一致的问题就叫做“covariate shift”现象。
internal covariate shift指的是:当我们在计算 B,update 到 B′ 的 gradient 的时候,这个时候前一层的参数是 A (或者说是前一层的 output 是a),那当前一层从 A 变成 A′ 的时候,它的 output 就从 a 变成 a′ 。但是我们计算这个 gradient 的时候,我们是根据这个 a 算出来的,所以这个 update 的方向,也许它适合用在 a 上,但不适合用在 a′ 上面。
所以如果每次都有做 normalization,可能就会让 a 跟 a′ 的分布比较接近,也许这样就会对训练有帮助。
如下图所示:
但是!
有一篇 paperHow Does Batch Normalization,Help Optimization就推翻了internal covariate shift 的这一个观点。
作者从各种各样的角度说明internal covariate shift它不一定是 training network 的时候的一个问题,且Batch Normalization会比较好不一定是因为解决了 internal covariate shift问题。
作者通过比较训练时a 分布的变化发现:
这篇 How Does Batch Normalization,Help Optimization 论文中从实验上、也从理论上至少支持了 Batch Normalization,可以改变 error surface,让 error surface 比较不崎岖这个观点。并且说:如果我们要让 network的error surface 变得比较不崎岖,不一定要做 Batch Normalization,还有很多其他的方法(作者也试了一些其他的方法,见原文实验),batch normalization只是一个serendipitous(意料之外的发现),恰好work了而已。
主要包括以下几种方法:BatchNorm(2015年)、LayerNorm(2016年)、InstanceNorm(2016年)、GroupNorm(2018年)。这几个方法在之前总结Transformer时简单总结过了,可以参考:Transformer相关——(6)Normalization方式
normalization方法和paper原文如下:
Batch Renormalization
Layer Normalization
Instance Normalization
Group Normalization
Weight Normalization
Spectrum Normalization
[李宏毅深度学习2021春季笔记](https://unclestrong.github.io/DeepLearning_LHY21_Notes/Notes_html/05_Batch and Momentum.html)
(强推)李宏毅2021春机器学习课程