我们将点积注意力除以 √dₖ 进行缩放,因为随着维度 dₖ 的增大,点积也会变大。这么大的数值会把 softmax 推向极端值,而除以 √dₖ 可以把它们拉回健康的范围。

在这篇博客中,我们将通过一个循序渐进的数值示例,学习在 Transformer 架构中为什么要对点积注意力除以 √dₖ 进行缩放。

如果你已经读过我们关于 Attention 背后的数学 - Q、K 和 V 的博客,你应该已经了解注意力公式和计算步骤。在那篇博客中,我们将注意力分数除以

sqrt(d_k)

然后就继续往下讲了。现在,是时候理解

why

我们为什么要这样做了。为什么偏偏是

sqrt(d_k)

?为什么不除以 2 或 10 或其他任何数字呢?

本文的目标是让你理解为什么要用 √dₖ 进行缩放,这意味着在写作过程中做了一些简化。如果你理解了缩放背后的原理,那我的使命就完成了。如果你完整读完这篇文章,我相信我的使命一定会完成。

我们将涵盖以下内容:

  • 注意力公式(快速回顾)
  • 不缩放会发生什么?
  • 为什么点积会随 dₖ 增大?
  • 理解点积的方差
  • 逐步证明:点积的方差是 dₖ
  • 大的点积对 softmax 的影响
  • 为什么 √dₖ 是正确的缩放因子
  • 用真实数字验证
  • 总结

我是 Amit Shekhar,Outcome School 的创始人,我教导和指导过许多开发者,他们的努力为他们赢得了高薪的技术工作,帮助许多科技公司解决了他们的独特问题,并创建了许多被顶级公司使用的开源库。我热衷于通过开源、博客和视频分享知识。

我在 Outcome School 教授 AI 和机器学习。

让我们开始吧。

注意力公式(快速回顾)

这个缩放步骤位于更大的 Transformer 架构之中。缩放点积注意力的公式是:

Attention(Q, K, V) = softmax(Q x K^T / sqrt(d_k)) x V

其中:

  • Q 是 Query 矩阵
  • K 是 Key 矩阵
  • V 是 Value 矩阵
  • d_k 是 Key 向量的维度
  • sqrt(d_k) 是 d_k 的平方根

我们今天关注的部分是

/ sqrt(d_k)

。这就是

scaling factor

。我们在将点积分数传入

softmax

.

现在,问题是:为什么需要这个缩放?答案在于理解不缩放会发生什么。

不缩放会发生什么?

假设我们跳过缩放步骤,直接按如下方式计算注意力:

Attention = softmax(Q x K^T) x V

在真实的 Transformer 模型中,

d_k

是 64、128 甚至更大。当

d_k

很大时,分数

Q x K^T

可能会变成非常大的数字(我们将在下一节解释原因)。而当我们把非常大的数值传入 softmax 时,就会出问题。

softmax 函数(用于将分数转换为概率)产生的输出会极其接近 0 和 1。 一个词几乎获得全部注意力(接近 1.0),而其他所有词几乎得不到任何注意力(接近 0.0)。模型不再把注意力分散到多个相关词上,而是对某一个词变得过于自信。

这是一个大问题,因为:

  • 模型无法同时从多个词中学习。
  • 梯度(训练过程中用于更新模型的信号)变得极小,几乎为零。这就是所谓的 梯度消失问题。
  • 当梯度过小时,模型就无法有效学习。

于是,缩放因子

sqrt(d_k)

应运而生,来解决这个问题。

Softmax 还有一个值得了解的后果。它的输出总和总是等于 1,因此一个 token 必须把全部注意力分配出去,即使句子里没有任何内容值得关注。我们有一篇关于 Attention Sinks 的详细博客,解释了这些多余的注意力最终去了哪里。

但在理解解决方案之前,我们必须先弄清楚当

d_k

增大时,点积为什么会变大。

为什么点积会随 dₖ 增大?

两个向量的点积是通过将每一对元素相乘,然后把它们全部相加来计算的。

假设我们有两个向量

q

和

k

,每个的维度都是

d_k

:

dot_product = q_1*k_1 + q_2*k_2 + q_3*k_3 + ... + q_{d_k}*k_{d_k}

这里,我们把

d_k

个项加在一起。

现在,让我们简单地思考一下。每一项

q_i * k_i

都是一个数字,可以是正数或负数。当我们把这些数字越加越多时,它们并不总能完美地相互抵消。有些相加,有些抵消,但总体上总和的绝对值往往会增大。维度越多,相加的项就越多,点积就可能变得越大。

例如,如果

d_k = 4

,我们只相加 4 个项,所以点积保持较小。但如果

d_k = 512

,我们就要相加 512 个项。尽管一些正负值会相互抵消,但项数之多使得总和的绝对值大得多。

点积随

d_k

增长。这就是核心问题。维度越大,点积越大,softmax 的表现就越差。

现在,让我们用方差的概念来更精确地理解这一点。

理解点积的方差

别担心,我们会保持简单。

方差衡量一组数值相对于平均值的离散程度。方差大意味着数值远离平均值;方差小意味着数值接近平均值。

假设我们要测量一个班级学生的身高。如果所有学生的身高都在 5.0 到 5.5 英尺之间,那么方差就低。如果学生的身高范围从 3.0 到 7.0 英尺,那么方差就高。同样,当我们谈论点积的方差时,我们是在问:点积的值能有多分散?

现在,假设 Query 向量和 Key 向量中的每个元素都是一个随机数,且满足:

  • 均值(平均值)= 0
  • 方差 = 1

这是机器学习中的标准假设。输入值通常会被归一化,使其均值为零、方差为一。

那么,单个乘积的方差是多少

q_i * k_i

?

当我们把两个独立的随机数相乘,每个随机数的均值都是 0、方差都是 1 时,结果具有:

  • 均值 = 0
  • 方差 = 1 x 1 = 1(我们将在下一节解释原因)

所以,每个单独的乘积

q_i * k_i

的方差都是 1。

现在,点积是

d_k

个这样的乘积之和:

dot_product = q_1*k_1 + q_2*k_2 + ... + q_{d_k}*k_{d_k}

当我们把

d_k

个独立项相加,每项的方差都是 1 时,总方差为:

Variance(dot_product) = d_k x 1 = d_k

这就是关键洞察。点积的方差等于 dₖ。

d_k

越大,点积的值就越分散。而值越分散,就会给 softmax 带来问题。

正在规划进入 AI 领域?

无论你今天在哪个技术领域工作,只要付出努力,你都可以转型到以下这些角色:

  • AI 工程师
  • 前沿部署工程师
  • AI Agent 工程师
  • Harness 工程师
  • 语音 AI 工程师
  • AI 架构师
  • LLM 工程师
  • LLM 推理工程师
  • 生成式 AI 工程师
  • MLOps 工程师
  • 机器学习工程师
  • 深度学习工程师

Outcome School 的 AI 与机器学习课程 助你达成目标。

逐步证明:点积的方差是 dₖ

现在,为了便于理解,让我们一步一步地证明为什么方差等于

d_k

。别担心,我们会保持简单。

我们已经知道,点积的均值为零(因为每个

q_i

和

k_i

的平均值都是零)。

现在,一般来说,方差的计算方式如下:

Variance = Average of (value - mean)^2

但由于我们的均值为零,这就变成了:

Variance = Average of (value - 0)^2
         = Average of value^2

所以,当均值为零时,方差就简化为平方值的平均值。这意味着我们需要求点积平方的平均值。

现在,让我们看看对点积取平方会发生什么。我们举一个

d_k = 3

:

dot_product = q_1*k_1 + q_2*k_2 + q_3*k_3

对它取平方时,我们把和与自身相乘。这就像展开

(a + b + c)^2

:

(a + b + c)^2 = a*a + a*b + a*c
              + b*a + b*b + b*c
              + c*a + c*b + c*c

其中:

a = q_1*k_1

,

b = q_2*k_2

,

c = q_3*k_3

。所以我们得到 9 项(3 x 3)。现在,关键问题是:这 9 项中每一项的平均值是多少?

这 9 项分为两类:

第一类:一项与自身相乘的项(如 a*a、b*b、c*c)

这些是同一对元素与自身相乘的项。例如,

(q_1*k_1) * (q_1*k_1) = q_1^2 * k_1^2

。共有 3 个这样的项。

每一项的平均值是多少?让我们用上面学到的方差公式。我们知道:

Variance = Average of value^2    (when mean is zero)

由于

q_1

的均值为 0,方差为 1:

1 = Average of q_1^2
Average of q_1^2 = 1

同理,由于

k_1

的均值为 0,方差为 1:

Average of k_1^2 = 1

由于

q_1

和

k_1

相互独立,它们乘积的平均值等于各自平均值的乘积:

Average of (q_1^2 * k_1^2) = Average of q_1^2 * Average of k_1^2 = 1 * 1 = 1

这些项中每一项的平均值都是 1。

第 2 组:不同配对相乘的项(如 a*b、a*c、b*c)

这些是两个不同配对混合在一起的项。例如,

(q_1*k_1) * (q_2*k_2) = q_1 * k_1 * q_2 * k_2

。共有 6 个这样的项。

每一项的平均值是多少?由于

q_1

,

k_1

,

q_2

,

k_2

都相互独立,它们乘积的平均值等于各自平均值的乘积:

Average of (q_1 * k_1 * q_2 * k_2) = Average of q_1 * Average of k_1 * Average of q_2 * Average of k_2
                                    = 0 * 0 * 0 * 0
                                    = 0

这里,由于每一项的平均值(均值)都为零,整个乘积就变为零。

这些项中每一项的平均值都是 0。

综合起来:

在 9 个项中:

  • 3 个项(第 1 组)每项平均贡献 1
  • 6 个项(第 2 组)每项平均贡献 0
Variance = 3 * 1 + 6 * 0 = 3

和

d_k = 3

。所以方差等于

d_k

.

现在,同样的逻辑适用于任何

d_k

的取值。如果

d_k = 64

,我们得到

64 * 64 = 4096

个总项数。其中,64 个项(第 1 组)每项贡献 1,其余 4032 个项(第 2 组)每项贡献 0。所以方差是 64,正好等于

d_k

.

点积的方差总是恰好等于 dₖ。 这不是近似值,而是数学上精确的。

如果我们想从头深入了解 Q/K/V、自注意力机制以及 Transformer 架构背后的数学原理,我们有一个完整的课程——请查看 Outcome School 的 AI 与机器学习课程。

大的点积对 softmax 的影响

Softmax 函数将一组数字转换为概率。公式为:

softmax(x_i) = e^(x_i) / sum(e^(x_j) for all j)

其中:

e

是数学常数(约为 2.718)。

现在,需要理解的重要一点是:

e^x

会随着

extremely fast

的增大而

x

增长。让我们用实际数字来看看它增长得有多快:

e^1   = 2.718
e^5   = 148.4
e^10  = 22,026
e^20  = 485,165,195
e^50  = 5,184,705,528,587,072,045

这里,我们可以看到

e^10

和

e^50

之间的差异是天文数字级别的。

现在,假设我们有三个注意力分数:

[50, 10, 5]

(只是为了理解 softmax 在大数字下的表现)。当我们应用 softmax 时:

e^50 = 5,184,705,528,587,072,045
e^10 = 22,026
e^5  = 148

softmax = [5,184,705,528,587,072,045 / total, 22,026 / total, 148 / total]

第一个值完全占主导地位。softmax 的输出将近似为

[1.0, 0.0, 0.0]

.

现在,将其与较小的分数进行比较:

[5, 1, 0.5]

。当我们应用 softmax 时:

e^5   = 148.4
e^1   = 2.718
e^0.5 = 1.649

Sum = 152.780

softmax = [148.4/152.780, 2.718/152.780, 1.649/152.780]
        = [0.971, 0.018, 0.011]

这里,我们可以看到即使分数较小,第一个值仍然获得最多的注意力。但其他值并非完全为零。模型仍然可以从所有位置学习。

这就是问题所在。当

d_k

很大且我们不进行缩放时,点积得分会变得非常大,以至于 softmax 的输出几乎变成 one-hot。One-hot 意味着一个值为 1.0,其余都是 0.0。模型表现得好像只有一个词重要,而忽略了其他所有内容。梯度消失,学习停止。

给你的一点提示

无论你在哪个技术领域工作,都要熟悉这些主题:

  • LLM
  • RAG
  • MCP
  • Agent
  • 微调
  • 量化

我们把它们全部整合在一个视频中:

AI 工程详解:LLM、RAG、MCP、Agent、微调与量化

不必停止阅读——先收藏起来,等有空时再看。未来的你会感谢现在的你。

现在,让我们回到正题。

为什么 √dₖ 是正确的缩放因子

现在我们理解了问题所在,解决方案也就清晰了。我们需要让点积值保持足够小,以便 softmax 能产生分布良好的注意力权重。

无论

d_k

有多大,我们都需要把点积的方差重新拉回到 1。

我们知道:

Variance(dot_product) = d_k

如果我们把点积除以某个常数

c

,方差就变为:

Variance(dot_product / c) = d_k / c^2

注意: 当我们把一个随机变量除以常数

c

时,方差会被除以

c^2

(而不是

c

)。这是统计学中的标准规则。让我们来理解为什么。

方差衡量的是数值相对于均值的离散程度。它是用与均值的平方差来计算的。所以,当我们把所有值除以

c

时,每个与均值的差也会被除以

c

。但由于方差对这些差进行平方运算,除以

c

就变成了除以

c^2

.

让我们用一个简单的例子来看。假设我们有三个值:

[2, 4, 6]

.

Mean = (2 + 4 + 6) / 3 = 4

Differences from mean: [2-4, 4-4, 6-4] = [-2, 0, 2]

Squared differences: [4, 0, 4]

Variance = (4 + 0 + 4) / 3 = 2.67

现在,把所有值除以

c = 2

。新值为

[1, 2, 3]

.

New Mean = (1 + 2 + 3) / 3 = 2

Differences from mean: [1-2, 2-2, 3-2] = [-1, 0, 1]

Squared differences: [1, 0, 1]

New Variance = (1 + 0 + 1) / 3 = 0.67

这里可以看到,原来的方差是

2.67

,新的方差是

0.67

和

2.67 / 4 = 0.67

。我们除以了

c = 2

,但方差被除以了

c^2 = 4

.

这是因为方差使用的是平方差。当每个值缩小

c

倍时,平方差会缩小

c^2

.

现在,回到我们的点积。我们有:

Variance(dot_product / c) = d_k / c^2

我们希望这个方差等于 1,以便点积值保持在可管理的范围内。所以,我们设:

d_k / c^2 = 1
c^2 = d_k
c = sqrt(d_k)

这就是为什么我们要除以

sqrt(d_k)

。它正是能把方差拉回到 1 的那个值。

缩放之后:

Variance(dot_product / sqrt(d_k)) = d_k / d_k = 1

缩放后的点积值方差为 1,这意味着无论

d_k

有多大,它们都保持在可管理的范围内。softmax 函数接收到合理的输入,并产生分布良好的注意力权重。

这不是一个随意的选择。它在数学上正是正确的缩放因子。原始 《Attention Is All You Need》 论文(提出 Transformer 架构的论文)的作者正是出于这个原因选择了这个值。

要深入掌握《Attention Is All You Need》论文、缩放点积注意力以及 Transformer 内部机制,请查看 Outcome School 的 AI 与机器学习课程。

用真实数字验证

现在,让我们用两个不同的维度来看看缩放的效果。

示例 1:小维度(dₖ = 4)

假设我们有:

q = [1, 0, 1, 0]
k = [0, 1, 1, 1]
dot_product = 1*0 + 0*1 + 1*1 + 0*1 = 1
sqrt(d_k) = sqrt(4) = 2
scaled_score = 1 / 2 = 0.5

原始分数是

1

,缩放后的分数是

0.5

。两个值都很小,所以无论哪种情况下 softmax 都表现良好。当

d_k

较小时,缩放并不重要。

示例 2:大维度(dₖ = 64)

假设我们有三个词,其点积分数为:

[14, 10, 12]

.

不缩放时:

e^14 = 1,202,604
e^10 = 22,026
e^12 = 162,755

Sum = 1,387,386

softmax = [0.867, 0.016, 0.117]

这里,第一个词获得了 86.7% 的注意力。第二个词只获得 1.6%。尽管原始分数(14、10、12)相差并不大,但分布却相当极端。

缩放后(除以 sqrt(64) = 8):

缩放后的分数:

[14/8, 10/8, 12/8]

=

[1.75, 1.25, 1.5]
e^1.75 = 5.755
e^1.25 = 3.490
e^1.5  = 4.482

Sum = 13.727

softmax = [5.755/13.727, 3.490/13.727, 4.482/13.727]
        = [0.419, 0.254, 0.326]

这里我们可以看到差别。缩放之后,注意力分布得更加均匀:41.9%、25.4% 和 32.6%。模型现在可以从所有三个词中学习,而不是几乎完全聚焦于一个词。

这就是除以

sqrt(d_k)

解决问题的方式。

保持更新: 订阅我们的 新闻通讯,将最新的 AI 与机器学习博客直接发送到您的邮箱。

总结

让我们总结一下所学到的内容:

问题所在: 查询(Query)和键(Key)向量的点积会随着维度

d_k

的增加而增大。点积的方差等于

d_k

。较大的点积值会把 softmax 推向极端区域,使其输出接近 0 或 1 的值。这会导致梯度消失问题,模型停止学习。

解决方案: 在应用 softmax 之前,我们将点积除以

sqrt(d_k)

。这样可以把方差拉回 1,无论维度大小如何,都能使分数保持在可管理的范围内。

为什么是 sqrt(d_k)? 因为当一个方差为

d_k

的值除以

sqrt(d_k)

后,新的方差变为

d_k / d_k = 1

。这在数学上正是完全正确的值。

带缩放的完整注意力公式:

Attention(Q, K, V) = softmax(Q x K^T / sqrt(d_k)) x V

这一行代码,

/ sqrt(d_k)

,看起来很简单。但没有它,Transformer 架构就难以有效学习,尤其是在维度较大时。这是一个虽小却非常重要的细节,正是它让整个注意力机制得以正常运作。

现在,我们应该已经理解了为什么要将点积注意力除以 √dₖ。

常见问题

当 d_k 较小时,除以 sqrt(d_k) 的缩放重要吗?

不太重要。当

d_k

较小时,点积保持较小,因此无论是否缩放,softmax 都表现良好。例如,当

d_k = 4

时,分数 1 缩放后变为 0.5,两个值都很小。随着

d_k

变大,缩放才变得重要起来。

为什么我们除以 sqrt(d_k) 而不是其他数字?

当我们用一个常数去除一个值时

c

,它的方差会除以

c^2

。点积的方差为

d_k

,因此我们需要

d_k / c^2 = 1

,即得到

c = sqrt(d_k)

。它正是能把方差拉回到 1 的那个值。

点积的方差只是近似等于 d_k 吗?

不是。点积的方差精确等于

d_k

,而不是近似值。这在 Query 和 Key 向量的每个元素均值为 0、方差为 1 且各元素相互独立的标准假设下成立。

是谁在注意力机制中引入了 sqrt(d_k) 缩放因子?

该缩放因子来自最初提出 Transformer 架构的论文《Attention Is All You Need》。作者选择

sqrt(d_k)

是因为从数学上讲,这是使分数方差保持为 1 的正确值。

今天就到这里。

谢谢

Amit Shekhar Outcome School 创始人

你可以通过以下方式与我联系:

关注 Outcome School: