【Qwen2.5】采用 RoPE、SwiGLU、RMSNorm、Attention QKV bias 和 tied word embeddings 的 transformers 结构
原文
This repo contains the instruction-tuned 0.5B Qwen2.5 model, which has the following features:
- Type: Causal Language Models
- Training Stage: Pretraining & Post-training
- Architecture: transformers with RoPE, SwiGLU, RMSNorm, Attention QKV bias and tied word embeddings
- Number of Parameters: 0.49B
- Number of Paramaters (Non-Embedding): 0.36B
- Number of Layers: 24
- Number of Attention Heads (GQA): 14 for Q and 2 for KV
- Context Length: Full 32,768 tokens and generation 8192 tokens
For more details, please refer to our blog, GitHub, and Documentation.
5 个组件
文章目录
与所熟知的“原始” Transformer(即 2017 年《Attention Is All You Need》中的标准架构)相比,Qwen2.5 使用的这 5 个组件都有显著不同或增强。
但这并不意味着“标准 Transformer”不能用这些,而是说这些组件代表了现代高性能 LLM 的工业标准配置,它们解决了标准 Transformer 在深度训练稳定性、计算效率和大模型扩展性上的痛点。
下面逐一解析这五个模块与原始 Transformer 的区别:
一、 RoPE (Rotary Positional Embedding)
- 原始 Transformer: 使用绝对位置编码(Absolute Positional Encoding)。直接给每个位置的向量加上一个固定的正弦/余弦向量。这种编码方式难以处理训练长度和推理长度不一致的情况,也不具备良好的外推性。
- Qwen2.5 (RoPE): 使用旋转位置编码。它将位置信息编码为旋转矩阵,使得向量之间的相对位置关系能够被模型更好地捕捉。
- 优势: 支持更好的长上下文外推(Extrapolation),即训练时看 32k,推理时看 128k 效果衰减较小;符合物理直觉(相对距离不变)。
1. 什么是 RoPE?
Rotary Position Embedding (RoPE) 是一种用于 Transformer 模型的位置编码方法。与传统的绝对位置编码(如正弦位置编码)不同,RoPE 将位置信息注入到查询(Query)和键(Key)向量中,使得模型能够捕捉序列中元素之间的相对位置关系。
RoPE 的核心思想是:通过旋转操作,将位置信息编码到向量的角度中。当计算 Query 和 Key 的点积时,位置信息会以相对角度的形式体现出来。
2. RoPE 的具体方案
2.1 数学原理
假设我们有一个向量 x ∈ R d x \in \mathbb{R}^d x∈Rd,我们可以将其分解为 d / 2 d/2 d/2 个二维子向量。对于第 m m m 个位置,RoPE 通过一个旋转矩阵 R m R_m Rm 对每个二维子向量进行旋转。
对于二维向量 ( x 2 i x 2 i + 1 ) \begin{pmatrix} x_{2i} \\ x_{2i+1} \end{pmatrix} (x2ix2i+1),旋转矩阵定义为:
R m = ( cos ( m θ ) − sin ( m θ ) sin ( m θ ) cos ( m θ ) ) R_m = \begin{pmatrix} \cos(m\theta) & -\sin(m\theta) \\ \sin(m\theta) & \cos(m\theta) \end{pmatrix} Rm=(cos(mθ)sin(mθ)−sin(mθ)cos(mθ))
其中 θ \theta θ 是基础频率,通常定义为:
θ i = 10000 − 2 i / d , i = 0 , 1 , … , d / 2 − 1 \theta_i = 10000^{-2i/d}, \quad i = 0, 1, \dots, d/2-1 θi=10000−2i/d,i=0,1,…,d/2−1
2.2 高维推广
对于高维向量 x ∈ R d x \in \mathbb{R}^d x∈Rd,RoPE 将向量分为 d / 2 d/2 d/2 对,每对应用上述二维旋转。最终的位置编码向量 x m x_m xm 为:
x m = R m x x_m = R_m x xm=Rmx
2.3 在注意力机制中的应用
在 Transformer 的注意力机制中,Query q m q_m qm 和 Key k n k_n kn 经过 RoPE 编码后变为 q m R m q_m R_m qmRm 和 k n R n k_n R_n knRn。它们的点积为:
( q m R m ) ⋅ ( k n R n ) = q m ⋅ ( R m T R n k n ) (q_m R_m) \cdot (k_n R_n) = q_m \cdot (R_m^T R_n k_n) (qmRm)⋅(knRn)=qm⋅(RmTRnkn)
由于旋转矩阵的性质, R m T R n = R n − m R_m^T R_n = R_{n-m} RmTRn=Rn−m,即点积结果只依赖于相对位置 n − m n-m n−m。这使得模型能够捕捉相对位置信息。
3. RoPE 的实现过程
- 计算频率: 根据维度 d d d 计算基础频率 θ i \theta_i θi。
- 应用旋转: 对于每个位置 m m m,将 Query 和 Key 向量分解为二维子向量,并应用旋转矩阵。
- 计算注意力: 使用旋转后的 Query 和 Key 计算注意力分数。
4. 代码实现
以下是 RoPE 的 Python 实现:
import torch
import math
def apply_rope(q, k, cos, sin):
"""
应用 RoPE 到 Query 和 Key 向量
Args:
q: Query 向量, shape [batch, heads, seq_len, dim]
k: Key 向量, shape [batch, heads, seq_len, dim]
cos: 余弦值, shape [seq_len, dim]
sin: 正弦值, shape [seq_len, dim]
Returns:
q_rope: 应用 RoPE 后的 Query
k_rope: 应用 RoPE 后的 Key
"""
# 将向量分为偶数和奇数部分
q_embed = (q * cos) + (rotate_half(q) * sin)
k_embed = (k * cos) + (rotate_half(k) * sin)
return q_embed, k_embed
def rotate_half(x):
"""
将向量分为两半并交换符号
"""
x1, x2 = x.chunk(2, dim=-1)
return torch.cat((-x2, x1), dim=-1)
def precompute_rope_params(head_dim, seq_len, theta=10000.0):
"""
预计算 RoPE 参数
Args:
head_dim: 每个头的维度
seq_len: 序列长度
theta: 基础频率参数
Returns:
cos: 余弦值
sin: 正弦值
"""
assert head_dim % 2 == 0
# 计算频率
theta = 1.0 / (theta ** (torch.arange(0, head_dim, 2).float() / head_dim))
# 生成位置索引
position = torch.arange(seq_len).float()
# 计算角度
freqs = torch.einsum('i,j->ij', position, theta)
# 计算正弦和余弦
emb = torch.cat((freqs, freqs), dim=-1)
cos = emb.cos()
sin = emb.sin()
return cos, sin
# 测试代码
if __name__ == "__main__":
# 参数设置
batch_size = 2
num_heads = 4
seq_len = 10
head_dim = 64
# 预计算 RoPE 参数
cos, sin = precompute_rope_params(head_dim, seq_len)
# 创建随机的 Query 和 Key
q = torch.randn(batch_size, num_heads, seq_len, head_dim)
k = torch.randn(batch_size, num_heads, seq_len, head_dim)
# 应用 RoPE
q_rope, k_rope = apply_rope(q, k, cos, sin)
print("Query shape:", q.shape)
print("Key shape:", k.shape)
print("RoPE Query shape:", q_rope.shape)
print("RoPE Key shape:", k_rope.shape)
print("RoPE 应用成功!")
5. 总结
RoPE 是一种有效的位置编码方法,它通过旋转操作将位置信息注入到向量中,使得模型能够捕捉相对位置关系。与传统的绝对位置编码相比,RoPE 具有更好的外推能力和相对位置感知能力。
import torch
import math
def apply_rope(q, k, cos, sin):
"""
应用 RoPE 到 Query 和 Key 向量
Args:
q: Query 向量, shape [batch, heads, seq_len, dim]
k: Key 向量, shape [batch, heads, seq_len, dim]
cos: 余弦值, shape [seq_len, dim]
sin: 正弦值, shape [seq_len, dim]
Returns:
q_rope: 应用 RoPE 后的 Query
k_rope: 应用 RoPE 后的 Key
"""
# 将向量分为偶数和奇数部分
q_embed = (q * cos) + (rotate_half(q) * sin)
k_embed = (k * cos) + (rotate_half(k) * sin)
return q_embed, k_embed
def rotate_half(x):
"""
将向量分为两半并交换符号
"""
x1, x2 = x.chunk(2, dim=-1)
return torch.cat((-x2, x1), dim=-1)
def precompute_rope_params(head_dim, seq_len, theta=10000.0):
"""
预计算 RoPE 参数
Args:
head_dim: 每个头的维度
seq_len: 序列长度
theta: 基础频率参数
Returns:
cos: 余弦值
sin: 正弦值
"""
assert head_dim % 2 == 0
# 计算频率
theta = 1.0 / (theta ** (torch.arange(0, head_dim, 2).float() / head_dim))
# 生成位置索引
position = torch.arange(seq_len).float()
# 计算角度
freqs = torch.einsum('i,j->ij', position, theta)
# 计算正弦和余弦
emb = torch.cat((freqs, freqs), dim=-1)
cos = emb.cos()
sin = emb.sin()
return cos, sin
# 测试代码
if __name__ == "__main__":
# 参数设置
batch_size = 2
num_heads = 4
seq_len = 10
head_dim = 64
# 预计算 RoPE 参数
cos, sin = precompute_rope_params(head_dim, seq_len)
# 创建随机的 Query 和 Key
q = torch.randn(batch_size, num_heads, seq_len, head_dim)
k = torch.randn(batch_size, num_heads, seq_len, head_dim)
# 应用 RoPE
q_rope, k_rope = apply_rope(q, k, cos, sin)
print("Query shape:", q.shape)
print("Key shape:", k.shape)
print("RoPE Query shape:", q_rope.shape)
print("RoPE Key shape:", k_rope.shape)
print("RoPE 应用成功!")
2. SwiGLU (Swish-Gated Linear Unit)
- 原始 Transformer: 使用标准的前馈神经网络(FFN),结构通常是
Linear -> ReLU/GELU -> Linear。也就是两层全连接层中间夹一个激活函数。

- Qwen2.5 (SwiGLU): 使用了门控线性单元结构。
- 标准 FFN: W 2 ⋅ GELU ( W 1 ⋅ x ) W_2 \cdot \text{GELU}(W_1 \cdot x) W2⋅GELU(W1⋅x)
将 Swish 激活函数 与 门控线性单元 (GLU) 结合在一起的产物。在学术测试中,它被证明比传统的 ReLU 或 GELU 能让模型收敛得更快、效果更好。
SwiGLU 采用的是一种“左右开弓、互相控制”的机制,它的结构就像一个门控开关 (Gate):
- 左路(数据通道): 输入数据经过一层线性变换,直接准备输出。
- 右路(控制通道/门控): 输入数据经过另一层独立的线性变换,然后通过 Swish 激活函数。Swish 的输出结果在 0 0 0 到 1 1 1 之间,就像一个“阀门”。
- 合并: 将左路的数据和右路的“阀门”逐元素相乘 (Element-wise multiplication)。如果右路的阀门接近 0 0 0,对应位置的数据就被过滤掉;如果接近 1 1 1,数据就顺利通过。
如果用数学公式来表达,SwiGLU 的形态非常简洁:
SwiGLU ( x ) = Swish β ( x W + b ) ⊗ ( x V + c ) \text{SwiGLU}(x) = \text{Swish}_\beta(xW + b) \otimes (xV + c) SwiGLU(x)=Swishβ(xW+b)⊗(xV+c)
为了更清晰地看清它的网络结构,我们通常可以忽略偏置项(Bias,在现代大模型中为了稳定往往会省略),它的计算流程如下:
- 右路(门控): x W xW xW 是对输入 x x x 进行第一次线性变换,接着作用 Swish 函数: Swish ( x W ) = x W ⋅ σ ( β ⋅ x W ) \text{Swish}(xW) = xW \cdot \sigma(\beta \cdot xW) Swish(xW)=xW⋅σ(β⋅xW),其中 σ \sigma σ 是 Sigmoid 函数。
- 左路(数据): x V xV xV 是对输入 x x x 进行第二次独立的线性变换。
- 门控相乘: ⊗ \otimes ⊗ 表示将两路的结果按位置对应相乘。
最终,这个输出还会再乘以第三个权重矩阵 W 2 W_2 W2,构成了大模型中完整的前馈网络 (FFN) 层:
FFN SwiGLU ( x ) = ( Swish ( x W ) ⊗ x V ) W 2 \text{FFN}_{\text{SwiGLU}}(x) = \left( \text{Swish}(xW) \otimes xV \right) W_2 FFNSwiGLU(x)=(Swish(xW)⊗xV)W2
相比于老一辈的 ReLU,SwiGLU 有三个核心优势:
- 没有“神经元死亡”问题: ReLU 在输入小于 0 0 0 时导数完全为 0 0 0,容易导致部分神经元永久失效。而 SwiGLU 的门控通道使用的是 Swish,它在负数区域有一段平滑的“非单调”下凹,保留了微弱的梯度传导。
- 平滑的几何特性: Swish 函数处处可导且非常平滑,这种平滑性有助于深度模型在训练时更容易找到全局最优解。
- 更强的表达能力: 因为它引入了两个独立的权重矩阵( W W W 和 V V V)来进行元素级别的乘法交互,这相当于给网络增加了一个非线性的“动态筛选器”,让模型能够学习到更复杂的特征组合。
💡 代价是什么?
世界上没有免费的午餐。传统的 FFN 只需要两个权重矩阵(一进一出),而 SwiGLU 因为分成了左路和右路,一共需要三个权重矩阵。为了保持参数量和计算量与传统网络相当,大模型在设计时通常会按比例缩小中间隐藏层的维度(一般缩小到原本的 2 3 \frac{2}{3} 32 左右),从而在不增加计算负担的前提下,纯粹靠结构优势提升模型性能。
3. RMSNorm (Root Mean Square Layer Normalization)

- 原始 Transformer: 没有明确的 LayerNorm 标准化步骤(原始论文中在 Encoder/Decoder 内部使用了残差连接后的标准化,但在后续演进中 LayerNorm 成为标配)。即使后来引入了 LayerNorm,它也是减去均值并除以标准差。
LayerNorm 做的事情可以拆解为两步:
- 平移与缩放(Standardization): 先算出这个向量所有元素的均值 μ \mu μ,让向量减去均值(中心化);再算出方差 σ 2 \sigma^2 σ2,除以标准差。
LayerNorm ( x ) = x − μ σ 2 + ϵ ⊙ γ + β \text{LayerNorm}(x) = \frac{x - \mu}{\sqrt{\sigma^2 + \epsilon}} \odot \gamma + \beta LayerNorm(x)=σ2+ϵx−μ⊙γ+β
- 可学习参数: 这里的 γ \gamma γ 是缩放因子(Scale), β \beta β 是平移偏置(Shift)。
- Qwen2.5 (RMSNorm): 使用 RMSNorm。它去掉了 LayerNorm 中的“减去均值”这一步,只除以均方根(Root Mean Square)。
- 公式差异: LayerNorm 计算 μ \mu μ 和 σ \sigma σ,RMSNorm 只计算 1 n ∑ x i 2 \sqrt{\frac{1}{n}\sum x_i^2} n1∑xi2。
- 优势: 计算更简单、更快(少了一次减法运算),且在现代大模型中证明效果与 LayerNorm 相当甚至更好,尤其在深层网络中更稳定。
RMSNorm 的作者发现: LayerNorm 之所以能稳定模型训练,核心功劳在于那个分母(对激活值的缩放),它限制了梯度爆炸或消失;而分子上减去均值 μ \mu μ 以及可学习的平移参数 β \beta β,对模型最终性能的贡献微乎其微。
于是,RMSNorm 做了一个大胆的减法:不减均值了,也不要偏置 β \beta β 了,直接除以均方根!
RMSNorm 的数学原理
对于一个输入的特征向量 x = ( x 1 , x 2 , . . . , x d ) x = (x_1, x_2, ..., x_d) x=(x1,x2,...,xd),RMSNorm 的计算过程分为以下几步:
第一步:计算均方根 (RMS)
不求均值,而是把向量里每个元素的平方加起来求平均,再开根号:
RMS ( x ) = 1 d ∑ i = 1 d x i 2 \text{RMS}(x) = \sqrt{\frac{1}{d} \sum_{i=1}^{d} x_i^2} RMS(x)=d1i=1∑dxi2
第二步:归一化
用原向量直接除以这个均方根(为了防止分母为 0,会加上一个微小的超参数 ϵ \epsilon ϵ):
x ^ i = x i RMS ( x ) + ϵ \hat{x}_i = \frac{x_i}{\text{RMS}(x) + \epsilon} x^i=RMS(x)+ϵxi
第三步:缩放(Scale)
最后,乘上一个和 LayerNorm 一样的可学习的缩放向量 γ \gamma γ(维度与 x x x 相同),但不加偏置 β \beta β:
RMSNorm ( x ) i = x ^ i ⋅ γ i \text{RMSNorm}(x)_i = \hat{x}_i \cdot \gamma_i RMSNorm(x)i=x^i⋅γi
| 特性 / 步骤 | LayerNorm (层归一化) | RMSNorm (均方根归一化) |
|---|---|---|
| 减去均值 ( μ \mu μ) | 需要(将数据中心化) | 不需要 |
| 分母计算 | 标准差(需先算均值,再算方差) | 均方根(直接平方求和,一步到位) |
| 可学习参数 | γ \gamma γ (缩放) + β \beta β (平移) | 只有 γ \gamma γ (缩放) |
| 计算开销 | 较高(包含两次向量均值相关的遍历) | 较低(减少了计算损耗和内存读写) |
换成了 RMSNorm?
- 计算速度显著提升: 在大模型(LLM)的实际计算中,归一化操作是一个典型的 GPU 内存带宽受限(Memory-Bound) 任务。LayerNorm 需要计算均值和方差,意味着 GPU 要反复读写两次数据。而 RMSNorm 不需要均值,只需要遍历一次数据算出平方和即可,这显著减少了 GPU 显存的读写开销,能带来 7% ~ 50% 的层级加速。
- 效果完全不打折: 实验证明,虽然 RMSNorm 舍弃了均值中心化,但在千亿参数级的大模型训练中,其收敛速度和最终的下游任务准确率与 LayerNorm 几乎完全一致。
总结来说: RMSNorm 通过“砍掉” LayerNorm 中性价比极低的均值计算和平移偏置,在不损失模型性能的前提下,实现了更快的计算速度和更低的显存带宽占用。
4. Attention QKV Bias
- 原始 Transformer: 在 Multi-Head Attention 的 Query, Key, Value 线性变换中,通常不使用 Bias。原始论文为了保持注意力机制的平移不变性和计算简洁性,去掉了 Bias。
- Qwen2.5 (QKV Bias): 在生成 Q、K、V 的线性层中加入了 Bias。
- 优势: 对于某些模型架构和训练策略,加入 Bias 有助于模型更快地收敛,或者在微调阶段提供额外的表达能力。虽然理论上注意力机制对 Bias 不敏感,但在实际大模型训练中,这是一个常见的工程优化选择。
5. Tied Word Embeddings (权重共享)
- 原始 Transformer: 输出层的权重矩阵与输入的词嵌入(Embedding)矩阵是共享的。即,如果你有一个 V × d V \times d V×d 的词嵌入矩阵,输出层也是用这个矩阵的转置来映射回词汇表。
- Qwen2.5: 也使用了 Tied Embeddings。
- 优势: 可以大幅减少参数量。对于较小的模型(如 0.5B, 1.5B),嵌入层的参数量占比很高,共享权重可以节省约 10%-20% 的总参数量,同时保持性能。这也是为什么你的文档中提到“Number of Paramaters: 0.49B”,但“Non-Embedding: 0.36B”,说明嵌入层占了约 0.13B 的参数。
Tied Word Embeddings(权重绑定词嵌入),在学术界也常被称为 Weight Tying(权重绑定)。它是自然语言处理和大语言模型中一种非常经典的参数优化技术。
核心思想非常简单直接:让自然语言模型“输入端”的词嵌入矩阵(Word Embedding)和“输出端”的线性投影矩阵(Output Projection / LM Head)共享同一个权重矩阵。
我们可以通过大模型的结构工作流来观察这两个矩阵所处的位置:
在一个常规的语言模型中,有两处涉及全量词表(Vobabulary Size = V V V)和隐藏层维度(Hidden Dimension = d d d)的大型矩阵:
- 输入端(Embedding Layer): 负责把离散的 Token ID 映射成连续的稠密向量(从 V → d V \to d V→d)。权重矩阵大小为 W i n ∈ R V × d W_{in} \in \mathbb{R}^{V \times d} Win∈RV×d。
- 输出端(LM Head): 负责把模型最后一层输出的语义向量,投影回词表大小的对数几率(Logits),用来预测下一个词(从 d → V d \to V d→V)。权重矩阵大小为 W o u t ∈ R d × V W_{out} \in \mathbb{R}^{d \times V} Wout∈Rd×V。
如果不做任何处理,这意味着同一个词表要在模型里存两份独立的巨大矩阵,带来极大的资源开销。
Tied Embeddings 的工作原理
Tied Embeddings 直接打破了这种独立性,它的计算逻辑如下图右侧所示:
- 实现方法: 设共享的矩阵为 W ∈ R V × d W \in \mathbb{R}^{V \times d} W∈RV×d。
- 输入端变换: 正常的查表操作,输入 Token x x x,得到嵌入向量 e = W [ x ] e = W[x] e=W[x]。
- 输出端变换: 模型最后的隐藏状态向量为 h ∈ R d h \in \mathbb{R}^{d} h∈Rd。要得到它属于每个词的概率,直接乘以共享矩阵的转置 W T W^T WT:
Logits = h ⋅ W T \text{Logits} = h \cdot W^T Logits=h⋅WT
通过 W T W^T WT,输出层线性投影就完美复用了输入层的矩阵。
这个设计在学术论文 《Using the Output Embedding to Improve Language Models》(Press & Wolf, 2016) 被系统提出后,迅速成为标配,主要带来三大收益:
- 大幅削减参数量与显存占用:
在大模型中,词表 V V V 通常在几万到十几万不等(如 LLaMA 3 的词表约为 128k)。以 V = 130 , 000 , d = 4096 V = 130,000, d = 4096 V=130,000,d=4096 为例,一个矩阵的参数量就是 5.3 亿(530M)。如果不绑定,光是输入输出的矩阵就要吃掉 10 亿多参数。使用 Weight Tying 能直接省下这 5.3 亿参数的显存,这对于轻量级模型(如 1B~3B 级别)的性价比提升极其夸张。 - 正向特征对齐与联合优化:
直观上讲,如果“把一个词翻译成语义(输入)”和“把语义还原成词(输出)”用的是同一套刻度尺,两端的特征空间就能自动对齐。每一次反向传播,输入和输出的特征表达都能同时得到训练和修正。 - 防止稀有词过拟合:
在训练语料中,很多冷门或稀有的词可能只在输入端被模型看到过几次。如果输出层独立,输出端的对应参数几乎得不到有效更新。绑定权重后,输入端学到的特征能够直接反哺输出端,增强模型对罕见词的鲁棒性。
现代大模型的工业界现状:Tied 还是 Untied?
好玩的是,技术的发展是一个轮回。在今天的大模型时代,是否选择 Tied Embedding 取决于模型的规模和设计偏好:
- 选择 Tied(绑定)的模型: Gemma 系列 (Google)、Gemma 2、Qwen 系列的部分小参数版本。Google 倾向于在小参数模型(如 2B、7B)中疯狂使用 Weight Tying,把省下来的参数和显存额度全部挪给 Transformer 内部的注意力层和 FFN 层,从而在同等体积下榨干性能。
- 选择 Untied(不绑定)的模型: LLaMA 系列 (Meta)、Mistral。Meta 的 LLaMA 采用了标准的 Untied 结构。因为当模型总参数量达到 70B 甚至 405B 时,区区 500M 的词嵌入矩阵只占总体积的冰山一角。不绑定可以赋予输出层更高的表达自由度,允许输入语义空间和输出预测空间存在微小的几何偏置,从而略微提升极大规模模型的能力上限。
总结: Tied Word Embeddings 是一种高效的参数复用技术,通过转置共享同一个词表矩阵,在小参数和中型大模型中是极佳的“显存省钱利器”;而在超大规模模型中,为了极致的特征拟合,工程师才会选择将它们解耦。
总结对比表
| 模块 | 原始 Transformer (2017) | Qwen2.5 / 现代 LLM 标准 | 主要改进目的 |
|---|---|---|---|
| 位置编码 | 绝对位置编码 (Sin/Cos) | RoPE | 更好的长文本外推性、相对位置感知 |
| FFN 激活 | GELU / ReLU (全连接) | SwiGLU (门控) | 更强的非线性表达能力、训练更稳定 |
| 层归一化 | (原始无,后期加 LayerNorm) | RMSNorm | 计算更快、内存占用更少、深层训练更稳 |
| Attention Bias | 无 Bias | 有 QKV Bias | 微调灵活性、潜在的性能微调增益 |
| Embedding 权重 | 共享 (Tied) | 共享 (Tied) | 节省参数,对小模型尤其重要 |
结论
看到的这些配置,实际上是当前最先进的开源大语言模型(如 Llama 3, Qwen, Mistral 等)的标准技术栈。
它们不是“错误”,而是经过多年实践验证的最优解组合。如果你是在复现或对比实验,直接使用这些现代组件通常会比“原始 Transformer”获得更好的效果,尤其是对于小参数模型(如 0.5B)而言,SwiGLU 和 RMSNorm 的贡献尤为关键。
更多推荐


所有评论(0)