self-attention至最终概率输出

在前文《深入了解self-attention》中我们了解了自注意力模式的工作原理,它主要关注每个token和上下文之间的关系,self-attention后输出每个token和上下文加权后的向量,那么怎么用这个加权后的向量得到下一个词的概率分布呢?本文主要关注这个过程。

先用一张图画出整个transformer架构的过程:

接上前文,“它”经过一层 的self-attention 后得到一个混淆了上下文相关表示的向量[0.031,0.111],对比原始”它“的embedding向量[0.19, -0.37, 0.28, 0.06]少了两个维度,这里是因为,还需要靠Multi-head补齐剩下的维度,比如两个head可以输出两个向量,两个向量拼接成一个和原始向量相同维度的向量。

head1head2mix上下文的向量
[0.031,0.111][-0.08, 1.231][0.031,0.111,-0.08, 1.231 ]

得到mix上下文的向量后,进入残差连接+LayerNorm。

残差连接+LayerNorm

目的:把向量的数值稳定在一个合理范围内,防止深层网络训练时梯度爆炸或消失。它对同一个 token 内部的所有维度做归一化。

残差连接

将mix上下文的向量加回原始向量,[0.19, -0.37, 0.28, 0.06]+[0.031,0.111,-0.08, 1.231 ],这就像说”我在原来’它’这个词的基础上,叠加一点从上下文学到的新信息”,而不是完全替换掉原来的向量。

LayerNorm具体公式:

LayerNorm(z)=γzμσ2+ϵ+β\text{LayerNorm}(z) = \gamma \cdot \frac{z – \mu}{\sqrt{\sigma^2 + \epsilon}} + \beta

z:向量,例子如上文的[0.031,0.111,-0.08, 1.231 ](这里示例省略了残差连接的计算),实际再过一层矩阵做信息融合。

μ:z 向量所有维度的均值。

σ²:z 向量所有维度的方差(各个维度的离散程度)。

ε:一个很小的常数(比如 1e-5),防止除以 0报错。

γ、β:两个可训练的参数向量,分别叫”缩放”和”平移”,让模型有能力把归一化后的分布重新调整成最适合的样子。

手算体验一下(可展开)

z=[0.031,0.111,-0.08, 1.231 ]

μ=(0.031+0.111+(-0.08)+1.231) / 4 = 0.32325

σ²=[(0.031-0.32325)2+(0.111-0.32325)2+(-0.08-0.32325)2+(1.231-0.32325)2] / 4 = [0.0854+0.045+0.1626+0.824] / 4 = 0.27925

假设训练好的 γ=[1,1,1,1],β=[0,0,0,0]

LayerNorm(z)=[(0.031-0.32325)+(0.111-0.32325)+(-0.08-0.32325)+(1.231-0.32325)]/0.5284411=[-0.55, -0.402, -0.763, 1.718]

前馈神经网络 Feed-Forward Network

目的:对每个 token 单独做非线性加工——它不看其他 token,只对当前这一个向量做变换,相当于给模型增加”思考深度”。

FFN(z)=W2Activation(W1z+b1)+b2\text{FFN}(z) = W_2 \cdot \text{Activation}(W_1 \cdot z + b_1) + b_2

W₁:形状 [d_model, d_ff],把向量从d_model维放大到d_ff维(通常 d_ff = 4×d_model)。

Activation:激活函数,早期用 ReLU,现代模型(GPT、Claude 这类)更常用 GELU 或 SwiGLU。

W₂:形状[d_ff, d_model],再把向量压缩回原始维度。

b₁、b₂:偏置项。(给了模型一个”基准线”、一个”默认偏好”,不需要完全依赖输入的具体数值,才能产生某种输出。相当于给每个”特征探测器”设置了一个独立的激活阈值,让不同神经元可以对不同强度的信号做出反应,而不是所有神经元共享同一个”零点”标准)

注:真实模型里,一层 FFN 里的 W₁+W₂,就有约 1.34 亿个参数。W₁ 的每一列(或者说每个”中间神经元”),往往对应某种特定的、可被人类识别的”特征检测器”。而 W₂ 则负责把这些被激活的特征检测器的意见,重新组合、投票,汇总成一个更新后的语义表示。

Activation激活函数,以以 ReLU 为例,负数变 0。如放大为d_ff维的矩阵为[0.31, -0.85, 0.42, -1.20, 0.55, 0.08, -0.63, 0.97],过激活函数后得到:[0.31, 0, 0.42, 0, 0.55, 0.08, 0, 0.97],负数置为了0。

整个前馈神经网络,可以做这样一个类比:像把一张小图片的信息,同时喂给 8 个不同的、各自关注不同特征组合的”滤镜”(比如一个专门检测”是不是偏暖色调”、一个专门检测”是不是有强对比边缘”……),每个滤镜产出一个响应值;响应为负的滤镜,说明”这个特征在这张图里根本没检测到”,直接归零、不参与后续;剩下响应为正的滤镜结果,再重新按权重组合、投票汇总,压缩回原来的通道数,得到一张”被这8个滤镜重新解读过”的新图。

线性投影到词表大小

直接看个示例:

假设经过残差连接+layerNorm+FFN后得到最后一个token的向量为:[0.15, -0.32, 0.48, 0.21]。我们需要预测输出它的下一个词,我们需要将它映射到词表中。

假设词表里有5 个候选词,真实模型词表通常几万到十几万。

词表 = [“。”, “,”, “但是”, “所以”, “呢”]

词表矩阵 = [
  [0.9, -0.2,  0.1,  0.3, -0.5],
  [0.4,  0.7, -0.3,  0.1,  0.2],
  [-0.1, 0.5,  0.8, -0.4,  0.3],
  [0.2, -0.6,  0.2,  0.9,  0.1]
]

每一列代表一个词

1.算出的 logits(每个词一个原始分数):

计算logits得分
0.15×0.9 + (-0.32)×0.4 + 0.48×(-0.1) + 0.21×0.2-0.006
0.15×(-0.2)+ (-0.32)×0.7 + 0.48×0.5 + 0.21×(-0.6)-0.156
但是0.549
所以0.086
0.024
logits得分计算

2.Softmax将得到分数,归一为概率分布

elogits ≈ [0.994, 0.856, 1.732, 1.090, 1.024]

sum≈5.696

P(“。”) ≈ 0.994 / 5.696 ≈ 17.4%

P(“,”) ≈ 0.856 / 5.696 ≈ 15.0%

P(“但是”) ≈ 1.732 / 5.696 ≈ 30.4%

P(“所以”) ≈ 1.090 / 5.696 ≈ 19.1%

P(“呢”) ≈ 1.024 / 5.696 ≈ 18.0%

至此示例中,按最大概率取,模型预测得到下一词为“但是”。

实际拿到概率分布后,不一定取概率最高的词,会有几种不同的采样策略。

策略做法特点
贪心解码(Greedy)直接选概率最高的词确定性强,但容易生硬、重复
Top-k 采样只在概率最高的 k 个词里按概率随机抽平衡随机性和质量
Top-p (nucleus) 采样只在累计概率达到 p(如90%)的最小词集合里抽目前最常用,更自然
温度(Temperature)调节在 softmax 前把 logits 除以一个温度值 TT越低越保守(接近贪心),T越高越随机、越”有创意”
采样策略

一句话总结整个流程

输入词 → embedding → N层Transformer(attention+FFN反复处理) 
        → 最终向量 → × W_U 得到logits → softmax得到概率 → 采样得到下一个词

这也是为什么大语言模型本质上是在做”预测下一个词的概率分布“这一件事——但因为这个过程会在生成完一个词后,把新词加回输入序列、再走一遍整个流程(自回归生成),所以最终能连续生成一整段连贯的文本。

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注