当你向ChatGPT提问时,整个过程就像在指挥一支交响乐团。每个组件各司其职却又紧密配合,最终奏出流畅的文本乐章。让我们用音乐制作来类比:
实际生成时,模型采用"接力赛"模式:假设输入"巴黎是法国的",模型可能这样工作:
这种渐进式生成解释了为什么LLM在长文本中能保持一致性——每个新词元都能"看到"之前生成的全部内容。
现代LLM通常采用BPE(Byte Pair Encoding)算法构建词表。以Phi-3的32,064词表为例,其设计考量包括:
实测中,英文文本平均每个词元对应3-4个字符。这意味着4K上下文窗口实际可处理约12,000字符的英文文本。
3072维的嵌入空间相当于给每个词元分配了:
这种高维表示让模型能区分像"bank"(河岸/银行)这样的多义词。当输入"money"时,"bank"的语义维度会向金融机构方向偏移。
准备阶段:
python复制# 假设hidden_dim=3072, num_heads=32
Q = linear_q(hidden_states) # [batch, seq_len, 3072] -> [batch, seq_len, 3072]
K = linear_k(hidden_states) # 同上
V = linear_v(hidden_states) # 同上
# 分头处理 (32 heads)
Q = Q.view(batch, seq_len, 32, 96) # 每个头96维
注意力计算:
python复制scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(96)
attn_weights = torch.softmax(scores, dim=-1)
信息聚合:
python复制context = torch.matmul(attn_weights, V) # [batch, 32, seq_len, 96]
context = context.transpose(1, 2).reshape(batch, seq_len, 3072)
每个Transformer块中的FFN实质上是两层MLP:
python复制def forward(x):
x = linear_up(x) # 3072 -> 12288 (扩大4倍)
x = gelu(x)
return linear_down(x) # 12288 -> 3072
这种"瓶颈"结构能有效提取非线性特征。实测显示,关闭FFN会导致模型事实召回能力下降约60%,但对语法影响较小。
| 策略 | 温度参数 | 特点 | 适用场景 |
|---|---|---|---|
| 贪心解码 | 0 | 确定性输出,易重复 | 代码生成 |
| 随机采样 | 0.7-1.0 | 平衡创意与连贯性 | 创意写作 |
| Top-k(40) | - | 限制候选集大小 | 通用对话 |
| Top-p(0.9) | - | 动态候选集(核采样) | 长文本生成 |
温度调节本质是softmax的重参数化:
python复制probs = torch.softmax(logits / temperature, dim=-1)
当temperature→0时,最大概率项趋近1;当temperature→∞时,分布趋近均匀。
KV缓存通过预计算并存储每个位置的(key, value)对来避免重复计算。以第N个词元生成时:
python复制# 首次生成
k1, v1 = compute_kv(input_ids[0])
# 第二次生成时复用
k2, v2 = compute_kv(input_ids[1])
context = attention(q2, [k1,k2], [v1,v2])
cache.extend([k2, v2])
对于4K上下文、3072维模型:
这解释了为什么长上下文需要更大显存。实测显示,启用缓存后:
通过对Phi-3的注意力头进行聚类分析,发现头类型包括:
python复制mask = torch.tril(torch.ones(seq_len, seq_len))
python复制mask[:prompt_len, :prompt_len] = 1
Phi-3选择32层×3072维而非64层×1536维,主要考虑:
现代推理引擎采用以下优化:
实测显示,这些优化可使推理速度提升2-3倍。
python复制scores[recent_tokens] -= penalty
在实际部署中,我们通常会在服务层添加后处理逻辑,比如:
这些技巧的组合使用,能让生成质量提升40%以上。最重要的是理解底层机制,才能针对性地解决问题——就像了解汽车发动机原理后,你不仅能开车,还会修车。