01
引言
层归一化(Layer normalization ) 是Transformer模型中的一项重要技术,它通过对每一层的输入进行归一化,帮助稳定和加速训练。无论输入的规模或分布如何,它都能确保模型处理信息的一致性。在自注意力机制、多头注意力机制和位置编码等概念的基础上,层归一化在提高Transformer的效率和性能方面发挥着关键作用,使它们更加强大,能够处理复杂的任务。在本博客中,我们将深入探讨层归一化这一Transformer模型中的重要组成部分。
闲话少说,我们直接开始吧!
02
Normalization
让我们快速讨论一下什么是归一化,以及为什么它在深度学习中非常有用。如果你已经研究机器学习有一段时间了,你可能对规范化和标准化等概念并不陌生。但回顾一下,深度学习中的归一化是指将数据转化为符合特定统计属性的过程。
归一化有多种形式。其中一种常见的形式是标准化,即通过减去每列数据的平均值,然后除以标准差来调整每个数据点。这种转换的结果是,新列的平均值为 0,标准差为 1。另一种是最小-最大归一化,即对数据进行缩放,使其符合给定的范围。应用这些技术是为了确保数据具有一致的规模,这在机器学习中至关重要。
在深度学习中,归一化可应用于两个关键领域:
输入数据:输入神经网络的数据(如 f1、f2、f3 等特征)可在进入网络前进行归一化处理。这一步与传统机器学习中的操作类似。
隐藏层激活输出: 大家还可以将神经网络中隐藏层的激活输出归一化。这通常是为了稳定和加速训练,尤其是在深度网络中。
让我们深入了解一下为什么归一化在深度学习中如此重要。想象一下,你正在训练一个神经网络,当你更新权重时,其中一些权重开始变得非常大。当这种情况发生时,与这些权值相关联的激活也会变得很大,从而使你的模型更难有效学习。这会减慢训练速度,并在训练中造成问题。
归一化可以将激活保持在一个稳定的范围内,从而解决这个问题。这不仅能使训练过程更加稳定,还能加快训练速度,让模型更高效地学习。
归一化的另一大好处是可以防止出现内部协变量偏移的问题。当输入数据在网络各层中移动时,其分布会发生变化,这可能会混淆模型。通过对激活值进行归一化处理,可以保持数据的一致性,这样模型就能继续学习,而不会出现偏差。
此外,某些类型的归一化(如批量归一化)甚至有助于正则化,这意味着您的模型可以更好地泛化到新数据。
03
Batch Normalizaition
批量归一化 (Batch Normalization) 旨在解决内部协变量偏移这一特定问题。要理解这个问题,可以想象一个有多个隐藏层的神经网络。在训练过程中,这些层的激活分布会因为权重的更新而发生变化。这种变化的分布使得网络难以有效学习,从而导致训练不稳定。
在上图中,前两行图像用于训练,其余两行图像用于测试。很明显,这些图像的分布不同,这就是协方差偏移的一个例子
04
Batch Norm工作原理
对于批次中的每一行,计算隐藏层中节点的激活值。 为简单起见,我们将重点放在三个隐藏层节点及其激活值 z1、z2 和 z3 上。假设我们为批次中的每一行计算这些值。
计算批次中每个激活值的平均值(μ)和标准偏差(σ), 即分别计算z1 z2 和z3的平均值和方差
用以下公式对每个激活值进行归一化处理,将此应用于 z1、z2 和 z3 等所有值。
归一化后,应用缩放和移动。每个节点都有两个可学习的参数:伽马参数(γ)和贝塔参数(β)。
这里,γ 和 β 最初分别设置为 1 和 0,但在训练过程中会进行调整。
归一化后,将数值通过激活函数,得到每个节点的最终输出。
05
为什么不在Transformer中使用BatchNorm?
在Transformer结构中,归一化技术的选择对模型的性能起着至关重要的作用。在Transformer中,层归一化比批量归一化更受青睐,其主要原因是批量归一化不能有效地与自注意机制配合使用。简单地说,批量归一化难以处理顺序数据,而顺序数据是Transforemr模型的基本输入。
让我们通过一张众所周知的Transformer结构图来深入探讨这个问题。你会发现,归一化步骤是在注意力机制之后进行的。
但为什么不在这里使用批量归一化呢?为了说明这一点,我将演示将批量归一化直接应用于自我关注机制时会发生什么。
06
回顾Self-Attention
在自注意力机制中,通常从一个句子开始,如 "river bank",然后将其分解为单个词或标记。为简单起见,让我们考虑两个标记:"river "和 "bank"。然后,每个词都由一个嵌入向量来表示。虽然嵌入向量通常是高维的,但在本例中,我们假设使用的是四维向量。重要的是,每个词的嵌入向量具有相同的维度。如下图所示:
接下来,这些嵌入向量被送入计算自注意力机制。自注意力机制的作用就是从这些向量中生成上下文嵌入向量。这里看到的是 "river "一词的上下文嵌入向量,它考虑了 "bank"一词的语义信息。请注意,输出向量的维度与输入向量保持一致。
07
Self-Attention中的批量处理
现在,让我们引入一点复杂性。到目前为止,我们一直在考虑一次向自注意力模块输入一个句子。但如果我们想同时处理多个句子呢?这就是批处理发挥作用的地方。我将向你展示如何以批处理的形式通过自注意力模块处理多个句子。
假设我们正在执行一项情感分析任务,数据集包含的句子如下:
为了在这些数据上训练自注意力模块,我们决定一次处理两个句子,这意味着我们的BatchSize大小设置为两个。因此,前两个句子将作为一个批次一起处理,然后再处理后两个句子。
和以前一样,这些句子中的每个单词都由一个嵌入向量表示,为了简单起见,我们将每个嵌入向量的维数保持在三维。下图显示了每个单词的嵌入情况:
在自注意力机制方面,尤其是在处理不同长度的序列时,填充起着至关重要的作用。让我们通过一个实际例子来深入了解填充的工作原理以及它的必要性。
上述两个句子的长度各不相同,一个句子有两个单词,另一个句子有四个单词。然而,在自注意力计算过程中,我们需要确保在处理这些句子时,每个句子中的单词(标记)数量是相等的。这就是填充的作用。
填充后这两个句子的长度相等,可以将它们输入自注意力模块。该模块将根据整个序列计算每个单词的上下文嵌入。
上述嵌入可以用矩阵来表示,就像这样:
将这些矩阵通过自注意力模块后,就能得到以下上下文嵌入。
现在,我们将这两种上下文嵌入堆叠在一起,如下图所示:
现在,如果使用BatchNorm, 则我们需要计算每一列的平均值和标准差,对这一设置进行归一化操作。不过,重要的是要问问自己,计算出的平均值和标准差是否真正代表了数据的分布。答案是否定的,主要是因为存在很多填充的零。如果数据中有多个零,就会严重影响批量归一化的效果。这就是主要问题所在--当数据中存在多个零时,批量归一化就会失效。
最根本的原因在于,填充标记虽然是对齐所必需的,但并不是原始数据的一部分。它们会在数据集中引入大量零,从而误导归一化过程。这也是为什么在Transformer中的自注意力层后不采用批量归一化的原因。
08
LayerNorm的引入
在BatchNorm中,归一化是在整个批次中进行的。例如,如果我们将行视为我们的批次,那么归一化就会在跨批次也就是每一列这个方向上进行。但在层归一化中,归一化是跨特征进行的。这意味着层归一化是在每一行而不是整批数据中进行的。
要计算层归一化的平均值和标准偏差,需要对所有特征的每一行进行计算。例如,计算第一行的平均值 (μ1) 和标准偏差 (σ1),然后计算第二行的 μ2 和 σ2,以此类推,直到计算出最后一行的 μf 和 σf。
有了这些值之后,就可以通过减去各行的平均值,再除以标准差,对每个元素进行归一化处理。例如,要对第一行中的第一个元素进行归一化处理,可以这样写:
normalized_value=7-μ1/σ1
下一步是使用 z1 特有的伽马参数和贝塔参数对该值进行缩放和移动:
output=γ1 × p + β1
09
对比总结
批归一化和层归一化的主要区别在于归一化的方向。BatchNorm是对批次进行归一化,而LayerNorm是对特征进行归一化。这一区别至关重要,尤其是在Transformer中,层归一化在处理数据的顺序性方面起着至关重要的作用。
总之,LayerNorm为Transformer结构提供了一种更合理、更有效的方法,即使在存在填充的情况下,也能确保数据的准确归一化,从而提高模型的性能和稳定性。
点击上方小卡片关注我
添加个人微信,进专属粉丝群!