Transformer 中的张量形状怎么变化:从词向量到注意力输出
围绕张量流动和维度示例,梳理输入嵌入、Q/K/V、注意力矩阵、多头拆分与拼接的形状变化。
相关工具
先把三个维度看明白
Transformer 里的张量形状,最常见的是 [batch, seq, d_model]。batch 表示一次处理多少条样本,seq 表示每条样本被补齐后的序列长度,d_model 表示每个 token 的隐藏向量维度。三个维度分别回答“有多少条”“每条多长”“每个位置有多少个特征”。
资料 以 512 维词向量作为说明。假设一次放入 32 条样本,每条最多 128 个 token,那么词嵌入后的张量可以记成 [32, 128, 512]。这并不表示每条句子真的有 128 个有效词,较短句子后面的部分可能是 Padding。
后续很多形状变化,都只是把最后一维拆开、把序列维度用于两两计算,或者把多个头重新拼回去。只要始终记住每个轴的含义,复杂的矩阵运算就容易定位。

从 Token ID 到嵌入、Q/K/V、注意力权重和最终输出的主要形状变化。
Token ID 如何变成词向量矩阵
分词器先把文本转换成整数 ID,因此最初的输入通常是 [batch, seq]。这个二维矩阵中的每个数字只是词表索引,还没有包含语义。Embedding 层根据索引查表,把每个 ID 替换成一个 d_model 维向量。
查表之后,形状从 [batch, seq] 变成 [batch, seq, d_model]。如果 d_model 是 512,每个位置就从一个整数变成长度为 512 的浮点向量。位置编码随后会与这些向量相加,形状保持不变,因为它表达的是同一批位置上的额外特征。
这一步也解释了为什么 Padding 需要单独处理。补齐位置同样会得到一个向量,但它不代表真实内容,后面的注意力掩码和损失掩码需要保证这些位置不会被当成有效语义使用。
单头注意力里的 Q、K、V 形状
对一个注意力头来说,输入可以写成 X ∈ R^(seq × d_model)。通过三个可学习的线性投影,X 分别变成 Q、K、V。资料 用 d_model 为 512、Q/K/V 维度为 64 的例子说明这一过程,因此单头的 Q、K、V 形状都是 [seq, 64]。
Q 和 K 的最后一维必须相同,因为它们要进行点积。V 的序列长度要与 K 对齐,因为注意力权重最终会沿着 Key 的位置对 Value 做加权求和;V 的特征维度可以记作 d_v,常见设置下也可能等于 64。
从形状上看,线性投影并没有改变序列长度,只把每个 token 的表示从 512 维压到单个头使用的 64 维。这个压缩让多个头可以在不同子空间里并行计算。

输入 [seq, 512] 经过三个投影得到 Q/K/V,再形成 [seq, seq] 注意力矩阵和 [seq, 64] 输出。
为什么 QK^T 会得到 seq 乘 seq
Q 的形状是 [seq, d_k],K 的形状也是 [seq, d_k]。计算 QK^T 时,K 先转置成 [d_k, seq],于是结果变成 [seq, seq]。结果矩阵的每一行对应一个 Query 位置,每一列对应一个 Key 位置。
这个矩阵不是新的 token 表示,而是位置之间的关系分数。第 i 行第 j 列表示第 i 个位置在计算注意力时,对第 j 个位置的匹配程度。经过缩放、掩码和 Softmax 后,它变成第 i 个位置对所有位置的注意力权重。
序列长度一变,这个矩阵就会沿两个方向同时变大。seq 从 128 变成 512 时,注意力分数矩阵的元素数量大约按平方增长,这也是长文本注意力成本较高的根本原因。
加权求和如何回到每个位置的表示
Softmax 后的注意力权重矩阵仍然是 [seq, seq],Value 矩阵是 [seq, d_v]。两者相乘后得到 [seq, d_v]。对每一行来说,它是在所有 Value 位置之间做加权求和,因此输出仍然对应原序列的每个位置。
这一步不会把序列压缩成一个向量。每个 token 都会得到一个融合上下文的新表示:它可以从其他位置吸收信息,但最终仍保留自己的位置索引。只有在后续做池化或取特定位置时,才会进一步改变序列维度。
如果注意力矩阵的某一行在 Padding 位置上有较大权重,输出就会混入无意义的补齐向量;如果因果掩码失效,解码器输出就可能包含未来位置的信息。形状正确并不代表权重语义正确。
多头注意力到底做了什么拆分
多头注意力把 d_model 维表示拆成 h 个子空间。以 d_model = 512、h = 8 为例,每个头的 d_k 可以是 64,因为 8 × 64 = 512。实现上通常先得到一个大张量,再把最后一维拆成 head 数和每头维度。
拆分后常见形状是 [batch, heads, seq, d_k]。把 heads 这一维提前,是为了让矩阵运算在多个头之间批量执行。每个头都会形成自己的 [seq, seq] 注意力权重,并得到 [seq, d_v] 的输出。
多头不是简单复制八份完全相同的注意力。每个头拥有自己的投影参数,可能分别学到相邻关系、远距离指代、语法结构或其他模式。形状上的拆分,为这些不同关系提供了并行的表示空间。

512 维表示拆成 8 个 64 维头,分别计算后重新拼回 512 维,再经过输出投影。
拼接不是求平均
各个头的输出通常沿最后一维拼接,而不是直接相加或求平均。8 个头各产生 [seq, 64],拼接后得到 [seq, 512]。这样,不同头学到的信息可以在不同的特征区间里同时保留下来。
拼接后的结果还会通过一个输出线性层,重新混合各个头的特征。这个投影可以让模型学习不同头之间如何组合,而不是把每个头当成彼此完全独立的结果。
如果把拼接误解成平均,就会忽略多头结构最重要的表达能力:多个头可以分别关注不同关系,然后把这些关系放在同一个位置表示中交给后续层继续处理。
残差连接为什么要求形状一致
注意力子层的输出通常会与子层输入做残差相加。输入是 [batch, seq, d_model],注意力经过多头拼接和输出投影后,也必须回到 [batch, seq, d_model],这样两个张量才能逐元素相加。
前馈网络虽然会先把最后一维扩展到更大的中间维度,再压回 d_model,但最终输出仍要保持 [batch, seq, d_model]。形状回不来,残差路径就无法连接。
这也是 Transformer 里经常看到“中间维度很大,模块输出维度不变”的原因。模块内部可以暂时改变特征维度,但模块边界通常要回到统一的 d_model,方便残差堆叠。
Encoder-Decoder Attention 的形状有什么不同
编码器自注意力中,Q、K、V 都来自同一个输入序列,所以分数矩阵通常是 [source_seq, source_seq]。解码器自注意力中,Q、K、V 来自目标前缀,矩阵则是 [target_seq, target_seq],还需要因果掩码。
Encoder-Decoder Attention 中,Q 来自解码器当前表示,K 和 V 来自编码器输出。于是注意力矩阵形状是 [target_seq, source_seq]:每个目标位置都在查询输入序列的所有源位置。
虽然两边序列长度可以不同,但 Q 和 K 的最后一维仍必须一致,V 的序列长度也必须与 K 对齐。形状变化体现了它的语义:解码器位置在查看编码器位置,而不是在目标序列内部自我查看。
Batch 和 Padding 如何影响形状
为了把不同长度的句子放在同一个 batch 中,通常先补齐到当前 batch 的最大长度,于是 seq 是一个批次级别的统一尺寸。换一个 batch,seq 可能变化;固定长度训练或推理时,也可能使用预先设定的最大长度。
Padding 不改变张量形状,但改变哪些位置有效。注意力计算会通过 Padding Mask 排除补齐位置,损失计算会忽略对应标签。可以把它理解成“形状里有这些位置,语义上却不让它们参与”。
实际排查时,先打印 batch、seq、d_model 和 heads,再检查有效长度和掩码范围。很多看似是模型能力的问题,最后只是某个 batch 的 Padding 位置没有被正确屏蔽。
看形状排查 Transformer 问题
遇到维度错误时,先从输入开始逐层记录:Token ID 是 [batch, seq],Embedding 后是 [batch, seq, d_model],Q/K/V 在多头布局下是 [batch, heads, seq, d_k],注意力矩阵是 [batch, heads, seq, seq],输出再回到 [batch, seq, d_model]。
如果矩阵乘法报错,重点检查相乘的内维是否一致;如果注意力权重形状正确但结果异常,检查 Softmax 维度和 Mask;如果残差相加报错,检查模块输出是否回到了 d_model;如果多头拼接后维度不对,检查 heads × d_k 是否等于 d_model。
形状检查不能代替语义检查,但它能快速缩小范围。把每个轴都写成有含义的名字,比只写一串数字更容易发现错误:seq 不是隐藏维度,heads 不是 batch,注意力矩阵的两个 seq 也分别代表 Query 位置和 Key 位置。
把张量流动放回 Transformer 主线
Transformer 的计算可以看成一条形状稳定、内部不断变换的路径:Token ID 通过 Embedding 进入 [batch, seq, d_model],线性投影生成各头的 Q/K/V,QK^T 形成位置关系矩阵,Softmax 后对 V 加权,再把多头结果拼回 d_model。
资料 用 512 维输入和 64 维 Q/K/V 来说明这个过程,数字本身不是唯一答案,重要的是它们之间的关系:每个头的维度乘以头数回到模型维度,注意力矩阵的两个轴对应两个位置集合,残差连接要求模块输入输出维度一致。
当你能沿着形状读懂一层 Transformer,Encoder、Decoder、交叉注意力和前馈网络就不再是互相孤立的黑盒。每次维度变化都有原因,每次回到 d_model 都是在为下一条残差路径做准备。
常见问题
为什么 Q、K、V 常见是 64 维,而输入是 512 维?
多头注意力会把 512 维模型表示拆到多个头中。以 8 个头为例,每个头使用 64 维,8 × 64 正好回到 512 维。具体数字可以变化,关系需要保持一致。
注意力矩阵为什么是 [seq, seq]?
每个 Query 位置都要和所有 Key 位置比较,所以矩阵的一条轴是 Query 位置,另一条轴是 Key 位置。自注意力两边来自同一序列,因此通常都是 seq。
Padding 会改变 Transformer 的张量形状吗?
Padding 会让不同长度样本补到统一的 seq 长度,但不会改变张量的规则形状。它需要通过 Padding Mask 和损失忽略机制避免补齐位置参与有效计算。