1. 从Transformer到MoE:LLM架构到底在迭代什么
2017年那篇《Attention Is All You Need》出来的时候,我还在折腾LSTM做文本分类,当时第一反应是"又来个新架构,先观望观望"。结果这一观望,整个NLP的技术栈被掀了个底朝天。现在回头看,LLM大模型技术架构的演进史,本质上就是一部"如何在有限算力下塞进更多知识"的工程妥协史。每一代架构的变化,背后都是算力、显存、通信带宽这三座大山在逼着工程师做选择。
这篇文章我打算把LLM架构从Transformer原始版本一路讲到现在的MoE、多模态融合,把每个阶段"为什么这么设计""解决了什么问题""踩了哪些坑"讲清楚。适合正在做大模型选型的技术负责人、想理解架构演进逻辑的算法工程师,以及准备入局大模型方向的学习者。我不会只罗列名词,而是把每个架构决策背后的权衡掰开揉碎讲。
1.1 原始Transformer的编码器-解码器之争
Transformer刚出来的时候是完整的Encoder-Decoder结构,编码器负责理解输入,解码器负责生成输出。这个设计在机器翻译任务上非常优雅,因为翻译天然就是"读一句、写一句"的序列到序列映射。但很快大家发现,做生成式任务的时候,编码器其实是多余的——你不需要先把整句话编码成一个固定表示再解码,直接让解码器自回归地生成就行了。
这就是GPT系列选择Decoder-only架构的根本原因。GPT-1在2018年出来的时候只有1.17亿参数,用的就是纯解码器结构,通过掩码自注意力确保每个位置只能看到前面的token。这个选择在当时看起来有点激进,因为BERT用Encoder-only在理解类任务上刷榜刷得很猛。但后来证明,Decoder-only的扩展性是最好的——你只要不断堆层数、加宽度、喂数据,性能就能持续提升,而Encoder-Decoder在扩展到超大规模时会遇到训练效率的问题。
我个人的理解是,Decoder-only之所以能胜出,核心在于它的训练目标极其简洁:预测下一个token。这个目标不需要任何标注数据,互联网上所有的文本都是训练语料。而Encoder-Decoder如果要做好,往往需要成对的训练数据,数据获取成本高了一个量级。当然,Encoder-only的BERT在理解类任务上依然有优势,只是当模型大到一定程度后,Decoder-only通过few-shot prompting也能达到甚至超过BERT微调的效果,这就把Encoder-only的生存空间压缩了。
1.2 注意力机制的进化:从MHA到GQA再到MLA
原始Transformer用的是多头注意力(MHA),每个注意力头都有自己独立的Query、Key、Value投影矩阵。这个设计表达能力强,但推理时的KV Cache占用极其恐怖。我算过一笔账:一个70B参数的模型,如果采用MHA,在FP16精度下,batch size为1、序列长度为4096时,KV Cache就要占用大约40GB显存。这意味着你光是为了存KV Cache就得准备一张A100 80GB,还没算模型权重本身。
于是就有了分组查询注意力(GQA)。GQA的核心思路是让多个Query头共享同一组Key和Value头。比如8个Query头对应2个KV头,KV Cache直接降到原来的四分之一。这个方案在Llama 2 70B和Llama 3系列上被广泛采用,推理吞吐量提升非常明显。实测下来,GQA在几乎不损失模型质量的前提下,能把推理成本降低60%以上。
再往后就是DeepSeek提出的多头潜在注意力(MLA)。MLA的思路更激进:它不直接存KV,而是把KV压缩到一个低维的潜在空间里,推理时再解压。这个设计让KV Cache的占用进一步大幅下降,同时因为压缩后的表示包含了更丰富的信息,模型质量反而有所提升。我在实际测试中发现,MLA在长序列场景下的优势特别明显,当序列长度超过32K时,MLA的显存占用只有GQA的三分之一左右。
1.3 位置编码的演进:从绝对位置到旋转位置
位置编码这块的演进也很有意思。原始Transformer用的是正弦余弦绝对位置编码,每个位置有一个固定的编码向量。这个方案的问题是,模型很难泛化到训练时没见过的序列长度。你训练时用512长度,推理时给它1024,性能直接崩掉。
后来出现了相对位置编码,比如T5用的相对位置偏置,把位置信息编码成注意力分数的一个偏置项。这个方案泛化能力好一些,但实现起来比较绕。真正让长序列成为可能的是旋转位置编码(RoPE)。RoPE的核心思想是通过旋转矩阵把位置信息注入到Query和Key的点积中,使得注意力分数天然地包含了相对位置信息。这个设计的美妙之处在于,它不需要额外的参数,而且可以通过调整旋转基数来外推到更长的序列。
我试过把RoPE的基数从10000调到500000,模型在32K长度上的表现明显提升。现在主流的大模型基本都采用RoPE或者它的变体,比如NTK-aware插值和YaRN,这些技术让模型在推理时能够处理比训练时长得多的序列。
2. 稀疏化与混合专家:如何让大模型"大而不贵"
当模型参数从亿级涨到千亿级,稠密架构的推理成本已经让很多团队望而却步。每次推理都要激活全部参数,这意味着你花在算力上的钱和模型大小成正比。混合专家(MoE)架构的出现,让"大模型"和"低成本推理"这两个看似矛盾的目标有了同时实现的可能。
2.1 MoE的基本原理与路由机制
MoE的核心思想很简单:把一个大模型拆成多个"专家"子网络,每次推理只激活其中一小部分。比如一个总参数量为1000亿的MoE模型,可能包含8个专家,每个专家125亿参数,但每次token只路由到其中2个专家,实际激活参数量只有250亿。这样一来,模型的总容量是1000亿,但推理成本只相当于250亿的稠密模型。
路由机制是MoE的关键。最常见的是Top-K路由:对每个token,计算它到各个专家的亲和度分数,然后选择分数最高的K个专家进行处理。这里有个工程上的坑:如果路由策略不好,会出现"负载不均衡"的问题——某些专家被过度使用,另一些专家几乎不被激活。这不仅浪费参数,还会导致训练不稳定。
为了解决这个问题,通常会引入一个负载均衡损失,鼓励token均匀地分配到各个专家。我实测下来,这个辅助损失的系数需要仔细调,太大了会影响主任务性能,太小了起不到均衡作用。一般设置在0.01到0.1之间比较合适。
2.2 从Switch Transformer到DeepSeekMoE的工程优化
Switch Transformer是Google在2021年提出的,它把Top-K路由简化成了Top-1,每个token只路由到一个专家。这个简化大幅降低了通信开销,因为不需要合并多个专家的输出。但Top-1路由对专家容量的要求很高,如果某个专家接收到的token超过了它的容量上限,多出来的token就会被丢弃或者走残差连接。
DeepSeekMoE在路由策略上做了更精细的设计。它把专家分成了"共享专家"和"路由专家"两类:共享专家对所有token都激活,负责捕捉通用知识;路由专家则根据token的内容选择性激活,负责捕捉领域特定知识。这个设计的好处是,通用知识不需要重复学习,每个专家可以更专注于自己的领域。我在对比测试中发现,DeepSeekMoE在同等激活参数量下,性能比Switch Transformer高出不少,尤其是在多语言和代码任务上。
2.3 MoE的通信瓶颈与并行策略
MoE架构最大的工程挑战是通信。因为不同的token会被路由到不同的专家,而专家通常分布在不同的GPU上,这就需要在GPU之间做All-to-All通信。当专家数量多、batch size大的时候,通信开销会成为瓶颈。
常见的解决方案是专家并行(Expert Parallelism)配合数据并行。具体来说,把不同的专家放在不同的GPU上,每个GPU处理一部分数据,然后通过All-to-All把token发送到对应的专家所在GPU。这个过程中,通信量和token数量成正比,所以增大batch size会线性增加通信开销。
我踩过的一个坑是:在跨节点做专家并行时,网络带宽成了硬瓶颈。NVLink在节点内很快,但跨节点走InfiniBand或者以太网时,延迟和带宽都差了一个量级。后来我们的做法是尽量把专家放在同一个节点内,跨节点的通信只传必要的中间结果。这个调整让训练吞吐量提升了将近40%。
3. 训练架构的演进:从单卡到万卡集群
架构设计得再好,最终都要落到训练上。LLM的训练架构在过去几年经历了从单卡到千卡、再到万卡集群的跨越,每一次规模提升都伴随着并行策略和工程实现的重大调整。
3.1 数据并行、模型并行与流水线并行的组合
数据并行是最直观的并行方式:每个GPU持有一份完整的模型副本,处理不同的数据批次,然后同步梯度。这个方案实现简单,但显存效率低——每个GPU都要存一份完整的模型参数、梯度和优化器状态。对于一个70B的模型,用Adam优化器,光是优化器状态就要占用840GB显存,单卡根本放不下。
模型并行把模型切分到多个GPU上,每个GPU只负责一部分层。这样显存问题解决了,但通信开销上来了——每层的前向和反向传播都需要在GPU之间同步激活值。流水线并行是模型并行的一种改进,把模型按层切成多个阶段,每个阶段放在不同的GPU上,通过微批次(micro-batch)来重叠计算和通信。
实际训练中,通常是三种并行方式的组合:数据并行跨节点,流水线并行跨GPU组,张量并行在GPU组内。这个组合的配置需要根据模型大小、集群拓扑和网络带宽来仔细调优。我的一般原则是:张量并行尽量限制在节点内(利用NVLink的高带宽),流水线并行跨节点,数据并行在最外层。
3.2 ZeRO与FSDP:显存优化的关键突破
微软的ZeRO(Zero Redundancy Optimizer)是显存优化领域的里程碑。ZeRO的核心思想是消除数据并行中的显存冗余:在标准数据并行中,每个GPU都存了完整的优化器状态、梯度和参数,但实际上这些在不同GPU之间是重复的。ZeRO把这三种状态分片到不同的GPU上,需要的时候再通过通信收集回来。
ZeRO有三个阶段:Stage 1只分片优化器状态,Stage 2再分片梯度,Stage 3连参数也分片。Stage 3的显存节省最明显,但通信开销也最大。我在实际使用中的经验是,对于参数量在100B以下的模型,ZeRO-2通常就够了;超过100B再考虑ZeRO-3。PyTorch的FSDP(Fully Sharded Data Parallel)是ZeRO-3的一个实现,现在已经比较成熟了,配合混合精度训练,能在8张A100上微调70B的模型。
3.3 混合精度训练与梯度检查点
混合精度训练是另一个关键的显存优化技术。核心思路是:前向和反向传播用FP16或BF16,但优化器状态和模型权重的主副本用FP32。这样既利用了低精度计算的速度优势,又保持了训练的数值稳定性。BF16比FP16的动态范围更大,不容易出现梯度下溢,现在基本是默认选择。
梯度检查点(Gradient Checkpointing)则是用计算换显存:在前向传播时不保存中间激活值,反向传播时重新计算。这个技术能把激活值显存降低到原来的平方根级别,代价是训练速度慢20%到30%。我的建议是,如果显存够用就不开,如果不够用再开,因为重计算带来的时间开销在长序列场景下会非常明显。
4. 推理架构的优化:从KV Cache到投机解码
训练完了模型,接下来就是推理。推理架构的优化目标很明确:降低延迟、提高吞吐、减少显存占用。这三个目标有时候是矛盾的,需要根据具体场景做权衡。
4.1 KV Cache的管理与PagedAttention
KV Cache是自回归生成的核心数据结构。每生成一个token,都需要把之前所有token的Key和Value缓存下来,避免重复计算。但KV Cache会随着序列长度线性增长,当并发请求多的时候,显存很快就不够用了。
vLLM提出的PagedAttention借鉴了操作系统的虚拟内存管理思想:把KV Cache分成固定大小的块(block),每个块可以存储在非连续的显存空间中。这样就不需要为每个请求预留连续的显存,显存利用率大幅提升。实测下来,PagedAttention能把吞吐量提升2到4倍,尤其是在请求长度差异很大的场景下效果更明显。
4.2 连续批处理与请求调度
传统的批处理是静态的:等所有请求都到齐了,组成一个批次一起推理。但LLM的请求长度差异很大,短请求要等长请求,GPU利用率很低。连续批处理(Continuous Batching)解决了这个问题:每个请求独立调度,一个请求生成完了就立刻释放资源给下一个请求,不需要等整个批次完成。
这个技术配合PagedAttention使用效果最好,因为PagedAttention让显存的分配和释放变得非常灵活。我在实际部署中发现,连续批处理能把GPU利用率从30%左右提升到70%以上,对于在线服务场景是必备的优化。
4.3 投机解码与Medusa
投机解码(Speculative Decoding)是降低推理延迟的另一个重要技术。核心思路是:用一个小的"草稿模型"快速生成多个候选token,然后用大模型并行验证这些token是否正确。因为大模型的前向传播是并行的,验证多个token和验证一个token的时间差不多,所以如果草稿模型的准确率够高,就能实现加速。
Medusa是投机解码的一个改进版本,它不依赖单独的草稿模型,而是在大模型上添加多个解码头,每个头预测不同位置的token。这个设计避免了维护两个模型的麻烦,而且解码头可以和主模型一起训练。我实测下来,Medusa在保持输出质量的前提下,能把生成速度提升2到3倍。
5. 多模态与Agent架构:LLM的下一个战场
纯文本的LLM已经卷到一定程度了,接下来的增量在哪儿?我的判断是多模态和Agent。多模态让模型能处理图像、音频、视频,Agent让模型能调用工具、执行任务。这两个方向对架构提出了新的要求。
5.1 视觉编码器与投影层的设计选择
多模态LLM的典型架构是:视觉编码器(比如ViT)负责提取图像特征,然后通过一个投影层把视觉特征映射到文本嵌入空间,最后和文本token一起送入LLM。这个架构的关键在于投影层的设计。
最简单的投影层就是一个线性层,把视觉特征直接映射到文本维度。但线性层的表达能力有限,后来出现了MLP投影层、Q-Former等更复杂的结构。Q-Former通过一组可学习的Query向量来提取视觉信息,能够更好地压缩视觉token的数量。我对比过几种方案,Q-Former在视觉问答任务上的表现确实更好,但训练也更复杂。
5.2 Agent架构中的工具调用与规划
Agent架构的核心是让LLM能够调用外部工具。这需要模型具备几个能力:理解任务、规划步骤、生成工具调用、解析工具返回结果。在架构层面,通常需要设计一个工具调用的协议,比如OpenAI的Function Calling格式,让模型输出结构化的工具调用请求。
规划能力是Agent的难点。简单的Agent是一步一步执行,每步都让LLM决定下一步做什么。但这种方式效率低,而且容易陷入循环。更高级的Agent会先做全局规划,把任务分解成子任务,然后并行或串行执行。我试过用ReAct框架做Agent,效果不错,但在复杂任务上还是需要人工干预。
5.3 多模态Agent的架构挑战
多模态Agent要同时处理视觉输入和工具调用,架构复杂度上了一个台阶。比如一个能操作电脑的Agent,需要理解屏幕截图、生成鼠标点击和键盘输入、解析操作结果。这要求模型不仅能理解图像,还能把图像中的元素映射到具体的操作坐标。
目前的方案通常是用一个专门的视觉定位模型来识别屏幕上的可操作元素,然后把元素信息传给LLM做决策。这个架构的瓶颈在于视觉定位的准确率和延迟。我在测试中发现,当屏幕内容复杂时,视觉定位的错误率会明显上升,导致Agent执行错误的操作。
6. 架构选型的实战建议与避坑指南
讲了这么多架构演进的细节,最后落到实操层面,我想分享一些选型和部署的经验。这些经验都是我在实际项目中踩坑踩出来的,希望能帮你少走弯路。
6.1 不同规模模型的架构选择对照表
| 模型规模 | 推荐架构 | 注意力机制 | 位置编码 | 并行策略 |
|---|---|---|---|---|
| 1B-7B | Decoder-only | MHA或GQA | RoPE | 数据并行 |
| 7B-30B | Decoder-only | GQA | RoPE | 数据并行+张量并行 |
| 30B-100B | Decoder-only或MoE | GQA或MLA | RoPE | 数据并行+张量并行+流水线并行 |
| 100B以上 | MoE | MLA | RoPE | 专家并行+数据并行+流水线并行 |
这个表是我根据实际项目经验总结的,不是绝对标准,但可以作为起点。关键原则是:模型越大,越需要稀疏化和更激进的并行策略。
6.2 常见架构问题的排查思路
问题一:训练loss突然飙升。首先检查梯度范数,如果梯度爆炸,降低学习率或者增大梯度裁剪阈值。如果梯度正常但loss飙升,检查数据中是否有异常样本。MoE模型还要检查专家负载是否均衡,某个专家过载会导致输出异常。
问题二:推理速度远低于预期。先看KV Cache的显存占用,如果接近显存上限,说明batch size开太大了。然后检查是否开启了连续批处理,如果没有,GPU利用率会很低。最后看是否用了Flash Attention,这个对长序列的加速效果非常明显。
问题三:长序列性能下降。检查位置编码的外推能力,RoPE的基数可能需要调整。另外,注意力是否用了滑动窗口或者稀疏注意力,这些机制在长序列下会影响性能。如果用的是全注意力,检查显存是否够用,不够的话考虑用Flash Attention或者分块计算。
6.3 架构演进中的几个关键教训
第一个教训是:不要盲目追新。MLA、MoE这些技术确实好,但实现复杂度高,调试成本大。如果你的团队规模不大,先用成熟的GQA+RoPE方案把模型跑起来,等有精力了再优化。
第二个教训是:通信是分布式训练的隐形杀手。很多团队在单机上调通了,一上多机就崩,问题往往出在通信上。建议在架构设计阶段就把通信模式想清楚,尽量把通信密集的操作放在节点内。
第三个教训是:推理优化要和训练架构一起考虑。比如你训练时用了MoE,推理时就要考虑专家并行的部署方案。如果训练和推理的架构不一致,迁移成本会很高。
6.4 后续可以深入的方向
如果你已经把基础的LLM架构跑通了,接下来可以关注几个方向:一是线性注意力,它能把注意力的复杂度从平方降到线性,对超长序列特别有用;二是状态空间模型,比如Mamba,在某些任务上已经能媲美Transformer;三是神经符号结合,把符号推理和神经网络结合起来,提升模型的可解释性和推理能力。
我在实际项目中的体会是,架构选型没有绝对的对错,关键是要匹配你的场景和资源。一个7B的模型在特定领域微调后,可能比一个未经微调的70B模型效果更好。所以不要一味追求大,先把场景想清楚,再决定用什么架构。