资讯动态

深入解析Softmax除以根号d的数学原理与应用

发布时间:2026/10/29 20:56:29 来源:尧图企业网站定制
1. 为什么softmax要除以根号d这个问题看似简单却触及了深度学习中最基础也最重要的数学原理。我第一次在面试中被问到这个问题时虽然知道这是为了缩放但真正理解其背后的数学原理却花了很长时间。今天我们就来彻底拆解这个看似简单却暗藏玄机的问题。1.1 softmax的基本形式首先回顾一下标准的softmax函数形式softmax(x_i) exp(x_i) / sum(exp(x_j) for j in range(n))这个函数将任意实数向量转换为概率分布保证输出在0到1之间且和为1。但在Transformer等模型中我们看到的却是softmax(QK^T / sqrt(d_k))这里多了一个除以根号d_k的操作d_k是key向量的维度。为什么要这样做1.2 点积的尺度问题关键在于点积QK^T的性质。假设Q和K的每个元素都是独立同分布的随机变量均值为0方差为1。那么点积Q·K sum(q_i * k_i)的期望是0而方差会怎样根据独立随机变量乘积的性质 Var(Q·K) sum(Var(q_i * k_i)) d_k * Var(q_i)Var(k_i) d_k也就是说点积的方差随着维度d_k线性增长。当d_k很大时点积的绝对值会变得非常大。1.3 梯度消失问题在softmax函数中过大的输入值会导致输出接近one-hot分布某个位置接近1其余接近0。这种情况下梯度会变得非常小# 当x_i远大于其他x_j时 ∂softmax(x_i)/∂x_i ≈ softmax(x_i)(1 - softmax(x_i)) ≈ 0 ∂softmax(x_j)/∂x_i ≈ -softmax(x_i)softmax(x_j) ≈ 0这会导致梯度消失模型难以训练。1.4 数学推导让我们严格推导一下为什么除以sqrt(d_k)是合理的选择。假设q和k是独立随机向量每个元素i.i.d.E[q_i] E[k_i] 0Var(q_i) Var(k_i) 1。点积q·k sum(q_i k_i)的期望 E[q·k] sum(E[q_i k_i]) 0方差 Var(q·k) sum(Var(q_i k_i)) d_k * (E[q_i^2 k_i^2] - E[q_i k_i]^2) d_k因此标准差就是sqrt(d_k)。通过除以sqrt(d_k)我们将点积的标准差重新缩放为1保持数值稳定。1.5 实验验证我们可以用简单的Python代码验证这个现象import numpy as np d_k 256 # 典型维度 num_samples 10000 # 生成随机Q,K矩阵 Q np.random.randn(num_samples, d_k) K np.random.randn(num_samples, d_k) # 计算点积 dot_products np.sum(Q * K, axis1) print(原始点积的均值:, np.mean(dot_products)) print(原始点积的标准差:, np.std(dot_products)) print(缩放后的标准差:, np.std(dot_products / np.sqrt(d_k)))输出结果会显示缩放后的标准差确实接近1。1.6 历史背景这个缩放因子最早出现在Attention Is All You Need论文中作者在3.2.1节提到We suspect that for large values of d_k, the dot products grow large in magnitude, pushing the softmax function into regions where it has extremely small gradients.他们通过除以sqrt(d_k)来解决这个问题使点积的尺度不随d_k变化。2. 深入理解缩放的影响2.1 对softmax分布的影响不缩放时随着d_k增大softmax输出会趋向于一个非常尖锐的分布。例如import torch d_k 256 x torch.randn(10) * d_k**0.5 # 模拟未缩放的点积 print(torch.softmax(x, dim0))输出可能接近[0,0,...,1,...,0]这不利于模型学习丰富的注意力模式。2.2 对梯度的影响计算softmax的梯度def softmax_grad(x): s torch.softmax(x, dim0) return torch.diag(s) - torch.outer(s, s)当x很大时这个梯度矩阵会接近零矩阵导致参数更新困难。2.3 与其他归一化方法的比较为什么选择除以sqrt(d_k)而不是其他方法比如LayerNorm会改变注意力模式的性质除以d_k过度缩小可能导致注意力过于分散sqrt(d_k)在数学上是最自然的选择因为它正好抵消了点积方差的增长。3. 实际应用中的变体3.1 其他缩放方式虽然sqrt(d_k)是最常见的但也有一些变体可学习的缩放因子α/sqrt(d_k)其中α是可学习参数按头的维度缩放有些模型对不同注意力头使用不同的缩放因子3.2 混合精度训练中的考量在使用混合精度训练时softmax通常保持在FP32以避免数值问题即使其他计算在FP16。缩放因子在这里尤为重要因为FP16的范围有限。3.3 硬件优化实现现代Transformer实现如FlashAttention会特别优化缩放操作通常将缩放与矩阵乘法融合以减少内存访问。4. 常见误区与问题排查4.1 为什么我的模型去掉缩放也能训练虽然在小模型或小d_k时可能不明显但随着规模增大不缩放会导致训练不稳定需要更小的学习率收敛速度变慢4.2 缩放因子是否可以调节虽然理论上可以但实践中sqrt(d_k)几乎总是最佳选择。如果必须调整建议在0.8-1.2/sqrt(d_k)范围内微调。4.3 如何诊断缩放问题监控以下指标注意力权重的熵应适中不过低梯度范数不应过早消失训练损失下降曲线应平稳5. 扩展到其他相似场景这个缩放思想也适用于余弦相似度的缩放核方法的温度参数对比学习中的温度调节核心思想都是控制logits的尺度保持数值稳定性和有意义的梯度。在实际实现Transformer时我通常会这样写注意力计算class ScaledDotProductAttention(nn.Module): def __init__(self, d_k): super().__init__() self.scale 1 / (d_k ** 0.5) def forward(self, Q, K, V): scores torch.matmul(Q, K.transpose(-2, -1)) * self.scale attn torch.softmax(scores, dim-1) return torch.matmul(attn, V)这种实现清晰地将缩放因子分离出来便于调试和修改。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑