Transformer 的计算复杂度为什么是瓶颈?

Transformer的计算复杂度,为什么是它的阿喀琉斯之踵?
上回聊完BERT和GPT,一个擅长"做完形填空",一个擅长"写作文"——它们本质上都在用Transformer。但你有没有想过,当你想让模型读一篇万字论文时,它为什么开始"喘粗气"了?
问题就出在Transformer的计算复杂度上。下面我把这个问题讲清楚。
先说清楚,"复杂度"到底是个什么东西?
你可能听说过"O(n²)"、"O(n)"这些词,但它们到底啥意思?
简单说,复杂度不是指具体的计算时间。而是说:当输入变大的时候,计算量是怎么跟着涨的。
举两个例子:
- O(n):排队检票。10个人要10次操作,100个人要100次。翻多少倍,涨多少倍。
- O(n²):100个人开会,如果每个人都要和所有人单独聊一遍,需要4950次对话。人一多,次数就爆炸了。
Transformer的核心问题,就出在这个O(n²)上。
Self-Attention的计算量,到底有多大?
先回顾一下Self-Attention的四个计算步骤:
- QKV投影:输入X变成Q、K、V三个矩阵
- 注意力矩阵计算:QK^T,算两两之间的相关性
- Softmax归一化
- 加权求和:V乘上注意力权重
关键在第二步。
你需要构建一个n×n的矩阵,每个格子填一个数——代表当前位置和所有其他位置的关系。
n是序列长度。512个token就要算262144次。翻到1024?直接变成1048576次。翻4倍,涨16倍。
这就是O(n²·d)的由来。d是向量维度,一般768或者1024。n²才是主角。

FFN真的比Attention更轻量吗?
等等,Transformer里可不只有Attention。还有个Feed-Forward Network,也就是那个FFN。
FFN的计算量是O(n·d_inner),d_inner一般比d大4倍。看起来也不小。
但它是线性的!n翻倍,计算量就翻倍。不会爆炸。
我之前用BERT-base(d=768)做过实验,n超过1536的时候,Attention的计算量就开始超过FFN了。
换句话说:
- 短文本(n < 1500):FFN才是主力,Attention还算小弟弟
- 长文本(n ≈ 5000):Attention的计算量已经是FFN的好几倍了
这就解释了为什么在很多"正常长度"的任务上,Transformer跑得还挺欢。但一处理长文档,就卡成PPT。

为什么偏偏是O(n²)?
你可能会问:能不能设计成O(n)或者O(n log n)?
能。但要付出代价。
n²的本质是:每个token都要和所有其他token"打招呼"。
100个人开会,每个人都要和99个人单独聊——这是全连接的代价。
但这个设计是有道理的。
你想啊,如果只让每个token只看隔壁几个token,它就变成了"近视眼"——无法捕捉远距离的依赖关系。
"这座城市去年GDP增长了5%"和"这座城市在东南亚",这两个词隔了老远,但它们说的是一件事。没有全局注意力,模型根本不知道它们有关系。
还有一个原因:d维向量点积得到的注意力矩阵,秩最多是d。当d远小于n的时候,信息本身就受限了。强行降低复杂度,可能让模型丢失重要信息。
那Softmax呢?它会让注意力分布变得更"极端",突出最重要的几个位置。但本质上,还是在处理n²个关系。

业界都在怎么解决这个问题?
聪明人不只有我们。学术界早就开始解决这个问题了。
主要有两个方向:
第一招:稀疏化。
既然n²太大,那就"少算点"。
- 窗口注意力:只看周围几个token,不看全部
- 随机注意力:随机选几个token建立连接
- 全局注意力:只有几个特殊token能看到所有位置
代表工作:Sparse Transformer、Longformer、Big Bird。
这就像开会的时候,不是所有人两两聊天,而是分组讨论,或者只让几个代表去收集信息。
第二招:线性化。
换个思路,不算n²个关系,而是用数学技巧"近似"。
- 矩阵分解:把大矩阵拆成小矩阵的乘积
- 随机投影:用低维空间近似高维计算
- 核函数近似:用核函数替代点积
代表工作:Linformer、Performer、FLASH。
这就像与其让100个人互相握手,不如先让每个人和自己的"小组长"汇报,小组长再汇总。
但每种方法都有权衡。稀疏化可能漏掉重要信息,线性化可能损失模型精度。没有免费的午餐。

实际应用中该怎么选?
说了这么多,该怎么选?
有个原则:先别急着优化,先搞清楚瓶颈在哪。
日常任务,n < 2000?直接用BERT、RoFormer这些标准模型。Attention的计算量占比其实不大,FFN和IO才是瓶颈。
长文档场景,n > 2000?考虑Longformer、Big Bird这些稀疏注意力模型。效果损失不大,但能省下大量计算。
超长序列,n > 5000?评估一下能否用线性注意力,比如FLASH。同时注意效果可能有所下降。
最怕的是什么呢?为了"显得技术含量高"强行上新技术,结果效果反而变差了。
这就像城市交通优化,你得先确认是主干道堵车还是毛细血管路堵车,再对症下药。

总结一下
回顾整个Transformer系列:从注意力机制,到多头设计,到位置编码,再到BERT和GPT的架构差异——我们其实一直在讲一件事:
模型的能力和代价,往往是一枚硬币的两面。
Attention让Transformer能"眼观六路",但代价是O(n²)的计算复杂度。稀疏化和线性化试图减轻这个代价,但可能会牺牲部分能力。
理解了这些,你就不只是会"调API"了,而是真正明白自己在用什么、为什么用它。
系列回顾
从第1篇的"Attention到底在注意什么",到今天的计算复杂度,我们一起走过了:
- Attention的的本质是"加权求和"
- Multi-Head让模型能关注不同类型的相关性
- 位置编码让序列有了"顺序感"
- BERT擅长理解,GPT擅长生成
- 代价和能力,总是一起出现的
希望这个系列,能帮你把Transformer从"黑箱"变成"白盒"。有问题,随时聊。
