微信扫一扫,关注公众号

  • 科技行者

  • 算力行者

见证连接与计算的「力量」

首页 DOSA:当AI读一百万字时,怎么让它不用把每个字都"认真看一遍"

DOSA:当AI读一百万字时,怎么让它不用把每个字都"认真看一遍"

2026-11-12 14:27
分享至:
----..---.-...-/--...-.-......./-...-....-..--../-............-.- ----..---.-...-/--...-.-......./-...-....-..--../-............-.- ----..---.-...-/--...-.-......./-...-....-..--../-............-.- ----..---.-...-/--...-.-......./-...-....-..--../-............-.-
2026-11-12 14:27 • 科技行者

2026年某天,如果你问一个正在处理百万字长文档的大模型"现在最耗时间的环节是什么",答案可能会让你意外。

不是生成答案,不是理解语义,而是一个你可能从没听说过的环节:决定该把注意力放在哪里。

这件事听起来荒谬。模型还没开始"思考",光是"往哪看"这个动作,就能吃掉七成以上的计算时间。这篇论文揭开的正是这个隐藏的性能黑洞,以及一个巧妙到近乎偷懒的解决办法。

**一、当"找重点"比"做重点"还贵**

先说说问题出在哪。

大模型处理长文本时,用的是一种叫注意力机制的东西,模型要判断当前这个词该和前面哪些词产生关联。

注意力机制:模型在处理一个词时,给前文所有词打分,分数高的词说明关联更紧密,模型会重点参考它们。

当文本只有几千字时,让模型把每个词和每个词都两两比对一遍,开销可以接受。但现在动辄百万字级别的上下文,两两比对的计算量会随长度平方增长,这谁都扛不住。

于是业界想出了稀疏注意力这个思路:既然不是每个词都重要,那就先粗略筛一遍,只挑出最相关的一小撮词,真正做精细计算的时候只看这一小撮。DeepSeek提出的DSA(DeepSeek Sparse Attention)就是这个思路的代表,它用一个叫"indexer"的打分器给每个候选词算分,再取分数最高的Top-K个。

Top-K:从一堆候选项里,按分数排序,只保留分数最高的K个,K是提前设定好的数字,比如2048。

Indexer:DSA里专门负责给每个词打分、决定要不要关注它的小模块,可以理解成一个"筛选员"。

问题来了。这个"筛选员"本身也不便宜。

论文给出的数据很直接:当上下文长度接近一百万token时,indexer这个筛选环节占掉了GLM-5.2模型73%的预填充(prefill)时间,在DeepSeek-V3.2上这个比例更夸张,达到90.8%。

token:大模型处理文本的最小单位,大致可以理解成一个字或一个词。

预填充(prefill):模型正式开始生成回答之前,先把输入的长文本整体处理一遍、建立内部表示的阶段。

这是什么概念?你本来期待的是,模型把大部分时间花在"真正思考"上,结果九成时间它都在"决定要不要思考这个词"。筛选员比干活的人还贵,这就是研究者面对的真实处境。

更扎心的是,筛选这个动作本身理论上计算量只占47%到83%,但实际耗时却远超这个比例。这说明问题不只是算得多,还有算得"碎",调度开销、显存搬运这些隐性成本同样在吃掉时间。

**二、一个反直觉的洞察:拒绝一个候选人,不需要看完它的简历**

面对这个问题,业内已经有几条尝试路径。有的利用解码阶段相邻步骤的相关性做预测,有的把打分结果流式处理减少中间存储,还有的干脆少用几个"打分头"先粗筛一遍再用全部打分头复核。

但这些方法有个共同的软肋:复核这个动作意味着你得先筛出一批候选,如果筛错了,真正该被选中的词已经被漏掉了,后面再怎么复核也救不回来。

DOSA(Dots Sparse Attention)的研究者换了个角度想这个问题。他们的核心洞察是:

要拒绝一个候选人,你不需要知道他的完整分数,只需要知道他的分数上限不可能超过及格线。

这句话值得多读一遍。它说的不是"算得更快",而是"根本不用算完"。

想象你是一家公司的招聘负责人,手头有一千份简历,但只要招10个人。传统做法是把每份简历从头到尾看完,打出精确分数,再排序挑前10名。DOSA的做法是:先快速扫一眼每份简历的关键信息,如果能确定这个人的分数上限连及格线都够不着,直接扔掉,不用再细看。只有那些"上限分数"还有机会冲进前10的简历,才值得你坐下来逐字细读。

如果不这样做会怎样?你就得把一千份简历全部精读一遍,哪怕其中九百份一眼就能看出没戏。这正是DSA原始方案的做法:每个候选词都要让全部打分头认认真真算一遍完整分数,哪怕这个词大概率根本进不了前2048名。

这里的关键是"上限分数"怎么算才靠谱又便宜。这就是DOSA真正的技术核心。

**三、种子阈值:先找几个"肯定及格"的样本,画出一条底线**

DOSA的第一步,是先建立一条可信的及格线。

做法是从所有候选词里选一个子集(叫种子集),这个子集的大小至少要等于K(也就是最终要选的数量)。对这个种子集里的每个词,老老实实用全部打分头算出精确分数,取里面第K大的那个分数,作为初始阈值τ。

种子集(seed set):预先精确打分的一小撮候选词,它们的分数被用来建立一个可信的参考线。

阈值τ:种子集里第K大的精确分数,后续所有候选词的"上限分数"都要和它比较,比它低的直接出局。

这个阈值有个数学上站得住脚的性质:它一定不高于真正的全局Top-K及格线。换句话说,这是一条稳妥偏保守的底线,宁可多留几个嫌疑候选,也绝不会误杀真正该入选的词。

这就好比你组织一场马拉松选拔赛,名额10个,你没法让所有报名者都先跑一圈试试看,但你可以先找10个你确定实力不错的人认真测一次成绩,取他们里面最慢的那个成绩作为"参考及格线"。任何一个候选人,只要你能证明他哪怕发挥到极限也达不到这条线,就可以提前刷掉,不用让他真的跑一次。

有了这条底线,接下来就是怎么给每个候选词快速估算一个"分数上限",而且这个上限估算本身得足够便宜,不然等于白忙活。

**四、正负两套账:把打分头拆成"该加的"和"该减的"分别处理**

DSA的打分公式里有个特点:每个打分头(head)都有一个权重,权重可能是正的也可能是负的,正权重的头会给分数加分,负权重的头会减分。

打分头(head):indexer内部多个独立的小型评分单元,每个head从不同角度给候选词打分,最后加权汇总成总分。ReLU:一种只保留正值、把负值归零的数学操作,这里用来确保每个打分头的贡献不会是负的"原始贡献"。

这个一正一负的结构,恰恰是估算"分数上限"最大的麻烦所在。

如果你想省事,直接把所有正权重的头都丢掉不算,那上限肯定估不准,因为你漏掉了真正加分的部分,上限会虚高到没有意义。但如果你把所有负权重的头都丢掉不算,倒是安全的,因为少减了分,上限只会偏高不会偏低,这在数学上是合法的,但如果估得太松,几乎所有候选词的"上限"都会超过及格线,筛选就形同虚设。

DOSA的做法是只精确计算一小部分最关键的打分头(保留集R),这些通常是权重绝对值最大、影响最显著的几个头。剩下的正权重头,用一种几何投影的方法,把它们的贡献近似折算到已经算过的保留头上,再加一个安全余量,确保这个近似值绝不会低估真实贡献。剩下的负权重头,则反过来操作:选出一批"大概率会被激活"的负权重头,把它们加总起来算一个"至少会减多少分"的保守估计,这部分只会减得不够多,不会减过头,所以最终的上限依然是合法的上限。

这里有个很聪明的细节:怎么判断哪些负权重头"大概率会被激活"?论文给出的办法是先在种子集上统计每个头在采样键上被激活(也就是点积结果为正)的频率,频率超过一半的头,才纳入负向加总的名单。这是因为如果把一个几乎不会被激活的头也算进去,它的负贡献在真实计算里本该是零,但你硬要把它的负值加进汇总,反而会人为压低估算出的上限,导致该保留的候选被误杀,破坏了"上限必须真正是上限"这条红线。

这就像财务做预算审批,你要卡一个支出的上限,有些支出项目几乎每次都会发生(高频负向头),这些你必须精打细算地扣除;但有些支出项目历史上很少发生(低频负向头),如果你每次都假设它一定会发生,那你估出来的"剩余预算上限"会系统性偏低,很多本该通过的申请就会被误拦下来。所以聪明的做法是只对高频必发生的支出做保守扣除,低频的就干脆不算,宁可预算宽松一点,也不要错杀。

**五、四步流水线:从粗筛到精算到落盘,层层压缩工作量**

把这套数学证明落地到GPU上,DOSA设计了一条四阶段的执行流水线。

第一阶段是粗筛打分,只用保留集里的那几个关键打分头,对所有候选词快速算一遍初步点积,这一步用GPU的Tensor Core完成,效率很高。

Tensor Core:现代GPU里专门为矩阵乘法优化的硬件单元,算密集型的矩阵运算比通用计算单元快得多。

第二阶段是组装上限并剪枝,把刚才算出的粗筛结果,加上前面讲的正向余量和负向扣除,拼出每个候选词的"分数上限",凡是上限低于阈值τ的候选词,当场淘汰,不进入后续任何计算,幸存者的ID被压缩打包,方便后续批量处理。

第三阶段是对幸存候选词做全头精确打分,这时候才真正把全部打分头都算一遍,拿到精确分数。因为前面已经淘汰了绝大多数候选,这一步要处理的数据量通常只有原始规模的百分之几。

第四阶段是精确筛选与写回,只有分数确实达到阈值的候选词,才会被写入最终的输出记录,这一步同样是为了减少显存读写的开销,因为把大量不会被选中的分数写进显存再读出来排序,本身也是一笔不小的浪费。

论文里有张图清楚地展示了这个流程,灰色区块代表被剪掉的无效计算,紫色区块代表被省掉的写回操作。整个设计的精髓在于:越往后的阶段越精确、越昂贵,但也越少执行,像一个漏斗,把计算资源集中在真正有悬念的候选词身上。

这就像机场安检,大部分乘客只需要过个金属探测门(粗筛),绝大多数人直接通过,只有触发警报的极少数人才会被叫去做更细致的开箱检查(精算)。如果让每个乘客都做一次完整的开箱检查,安检口排队的长度和耗时可想而知。

**六、剪枝效果有多猛**

数字说话最有说服力。

论文在GLM-5.2的21个产生indexer打分的层上做了统计,剪枝率,也就是被筛掉的候选词占比,在其中20层都超过了95%,三种语言(英语、中文、代码)的平均剪枝率在97.2%到97.5%之间。

也就是说,一百个候选词里,真正需要全头精确计算的,平均只剩两三个。

这个比例其实还隐藏了一个有意思的规律:所有层里,剪枝率最低的都出现在第一层,大概89%到93%,其余所有层都稳稳超过95%。研究者分析,这说明剪枝效果更多由模型深度和分数几何结构决定,而不是输入是什么语言、什么类型的文本。

反过来验证这套机制有多关键的,是论文做的一个消融实验:如果把负权重头的聚合估计直接去掉(也就是不再扣减负向贡献,只用一个宽松上限),候选词的存活率会从2.65%暴涨到95.06%,几乎等于没剪枝,整体indexer耗时直接涨到9.51倍。这组数字清楚地说明,负向扣减这一步不是锦上添花的优化,而是整套剪枝机制能不能生效的命门。

**七、端到端收益:长文本处理时间直接腰斩**

光是indexer模块快了没用,得看整体推理速度有没有真正受益。

论文在GLM-5.2和DeepSeek-V3.2两个模型上,测量了首字生成时间(TTFT,Time To First Token)这个用户最直观能感受到的指标。

TTFT:从用户提交请求到模型吐出第一个字之间的等待时间,是衡量长文本处理体验最直接的指标。

在大约一百万token的输入长度下,DOSA相比原始SGLang框架,在GLM-5.2上实现了1.86倍加速,在DeepSeek-V3.2上达到1.94倍,接近把等待时间砍掉一半。相比另一个已经做过融合优化的基线LiteTopK,也分别有1.26倍和1.50倍的提升。

这个收益为什么会随着文本变长而越来越明显?论文用一个简单的阿姆达尔定律做了解释:如果indexer占用的时间比例是f,indexer本身加速了s倍,那整体加速比大约是1除以(1减f加f除以s)。随着上下文从十几万token涨到一百万token,indexer占比从二三十个百分点涨到七八成,这个"瓶颈模块"在总耗时里权重越来越大,优化它带来的整体收益自然也水涨船高。

在微基准测试里,DOSA在全部60个测试配置下都是最快的方法,相比SGLang最高加速2.74倍,相比LiteTopK最高加速1.69倍。在解码阶段(也就是生成回答文字的过程,不同于处理输入的预填充阶段),因为每一步只有少量查询,重用空间有限,但DOSA依然靠"时间相关性"这个技巧,复用最近几步选中的候选词作为参考阈值,实现了1.06到1.26倍的加速。

**八、这个思路从哪儿来,又借鉴了什么**

有意思的是,这篇论文用的"上限剪枝"思路,并不是什么全新发明。

论文里提到,早在上世纪九十年代,信息检索领域就有一套叫MaxScore和WAND的经典算法,思路完全一致:给每个文档的分数估算一个上限,配合一个动态更新的及格线,提前跳过那些不可能进入Top-K的文档,避免对它们做完整的打分计算。后续还有Block-Max WAND对这个思路做了进一步细化,按数据块而不是单个文档来做上限估算。

DOSA可以理解成把这套诞生于搜索引擎时代的古老智慧,重新应用到了今天大模型的注意力计算上,并且针对DSA打分公式里"正权重加分、负权重减分"这个特殊结构,专门设计了一套新的数学证明。

这也是论文里提到的一个开放方向:未来或许可以把现在这种逐个候选词的精细上限,扩展成按数据块的粗粒度上限,先用一个压缩摘要判断整个数据块是否值得细看,如果整块都不达标,连读取每个具体候选词的数据这一步都可以省掉,进一步压缩内存访问的开销。

**九、这事到底意味着什么**

拉回到开头那个问题:为什么"决定往哪看"会比"真正去看"还贵?

这篇论文给出的答案其实有点朴素:因为之前没人真正把"剪枝"这件事做到底。大家都在想办法让打分算得更快、让存储搬得更省,但没有人去问一个更根本的问题,这个分数到底有没有必要算完整。

DOSA证明了一件事:在Top-K选择这种任务里,很多时候你压根不需要精确答案,你只需要一个足够紧的上限估计,就能把大部分计算直接省掉,而且是严格无损的,不会漏选一个真正该被选中的候选。

这种"用保守估计换取确定性剪枝"的思路,某种程度上也是一种关于信息价值的洞察:不是所有信息都需要被充分获取才能做决策,有时候一个粗略但可靠的边界,比精确但昂贵的答案更有用。

写在后面

读这篇论文时,最触动我的不是最终那几个加速倍数,而是那个核心的数学嗅觉:研究者没有去优化"怎么算得更快",而是去问"这个计算到底有没有必要存在"。这是两种完全不同的优化哲学,前者是在既定任务框架内抠效率,后者是在重新审视任务本身的必要边界。

论文里那个负向头消融实验的数字也让我愣了一下,去掉负向聚合这一步,候选存活率从2.65%直接跳到95.06%。这说明整套方法的真正难点,根本不在"怎么估算正向贡献的上限",而在"怎么处理那些会减分的负权重头"。正权重头天然就好处理,因为丢掉它们只会让上限偏高(安全但松),但负权重头如果处理不好,要么估算过于悲观导致误杀,要么处理不当导致松到没意义,这中间的平衡点才是真正的技术难度所在,而这恰恰是论文花了最多篇幅去论证的部分。

这也让我想到一个更泛化的问题:在很多需要"从大量候选中挑出少数"的系统里,是不是都存在类似的、被忽视的"筛选成本"?搜索引擎、推荐系统、甚至人类自己做决策时的信息过滤,是不是也存在同样的结构,大家默认"筛选"是廉价的前置步骤,但实际上它可能正是整个系统里最该被重新设计的部分。

Q&A

Q1:DOSA是什么,它解决了什么问题?

A:DOSA(Dots Sparse Attention)是一种让大模型长文本处理中的注意力打分环节变得更高效的方法。它通过先给每个候选词估算一个分数上限,提前排除不可能入选的候选,只对少数幸存候选做完整精确打分,从而大幅减少计算量,同时保证结果和原始方法完全一致,不会漏选。

Q2:DOSA相比原有方法能带来多少加速?

A:在GPU微基准测试中,DOSA相比SGLang框架最高可实现2.74倍加速,相比LiteTopK最高1.69倍加速。在真实模型端到端测试中,百万token级别输入下,GLM-5.2的首字生成时间加速1.86倍,DeepSeek-V3.2加速1.94倍,接近把等待时间砍掉一半。

Q3:DOSA是如何保证不会漏掉真正重要的候选词的?

A:DOSA依靠一个数学上严格证明的"分数上限"机制,任何候选词的上限估算都保证不低于其真实分数,只有当上限确实低于及格线时才会被剪枝,所以不会误杀任何本该进入Top-K的候选,整个过程是严格无损的。

分享至
0赞

好文章,需要你的鼓励

推荐文章
----..---.-...-/--...-.-......./-...-....-..--../-............-.- ----..---.-...-/--...-.-......./-...-....-..--../-............-.- ----..---.-...-/--...-.-......./-...-....-..--../-............-.- ----..---.-...-/--...-.-......./-...-....-..--../-............-.-