昨天DeepSeek发布了V3.2-Exp,API价格直接减少75%。看了下论文,核心改进是一个叫DSA(DeepSeek Sparse Attention)的机制。花了点时间研究,记录一下。
问题背景
先说说为什么需要这个东西。
Transformer的attention机制有个老大难问题:就是O(L²)的复杂度,计算量随序列长度平方增长。具体来说,如果你有128K个tokens,每个位置都要和其他所有位置算一遍相关性。
这意味着在128K上下文的情况下,需要128K乘以128K,大概是170亿次计算。存储这个中间结果的矩阵需要32GB内存(bf16精度)。
这还只是单层attention。一个完整的模型有几十层。
所以处理长文本的时候,成本和延迟都很要命。
核心想法
DSA的思路其实挺直接的:大部分token对当前任务来说并不重要,为什么要全部算一遍?
比如你在读这样一段话:
“小明2020年去了北京开会。会上讨论了很多技术话题。他见到了一些老朋友,大家一起吃了顿饭。第二天有个技术分享,讲的是分布式系统。第三天参观了故宫。五年后,他…”
读到”他”的时候,你会怎么理解这个指代?会仔细分析前面每个词吗?
不会。大脑会快速定位到”小明”,然后确认中间没有其他可能的指代对象。至于”吃了顿饭”、”参观故宫”这些细节,扫一眼就过去了。
DSA想做的就是这个:让模型学会有选择地关注。
两个步骤
具体实现分两步。
第一步是快速筛选。用一个轻量级的小模型(叫Lightning Indexer)快速给所有tokens打分,判断它们可能有多重要。这个模型很小,只用少数的attention head,而且用FP8低精度计算,所以虽然还是要扫一遍所有位置,但速度很快。
打个比方,这就像图书馆的索引系统。你不需要翻每本书,先查索引,知道哪几本可能有你要的内容。
第二步是精确计算。根据第一步的分数,选出top-2048个最相关的tokens。然后主模型只对这2048个做真正的attention计算。
这样一来,原本128K × 128K的计算量,变成了128K × 2048,直接省掉98%以上。
训练过程
这里有个关键问题:Lightning Indexer怎么知道什么是”重要”?
DeepSeek的做法是两阶段训练。
第一阶段叫warm-up。让完整的dense attention先跑一遍,记录下它给每个token分配了多少权重。这相当于”标准答案”。然后训练Lightning Indexer去学习这个分布,用的是KL散度这个经典方法。这个阶段主模型是冻结的,只训练Indexer,数据量大概2B tokens。
第二阶段才是真正的稀疏训练。这时候主模型解冻,整个系统用sparse attention来跑,Indexer和主模型一起训练。但有个细节:Indexer的梯度和主模型的语言建模loss是分开的。这个阶段用了接近1T的tokens。
为什么要分两阶段?因为如果从随机初始化开始sparse训练,Indexer根本不知道该选什么,可能很长时间都学不到有用的模式。warm-up相当于给它一个合理的起点。
一个具体场景
假设你让模型看一个大型代码库,然后问:”calculate_roi这个函数是干什么的?”
文件里有几百个函数,几千行代码。传统attention会把所有代码行都扫一遍,包括开头的几十个import语句,中间的各种helper函数,以及完全不相关的其他函数。
DSA的做法不同。Lightning Indexer会快速扫一遍,给不同部分打分。import语句?分数很低。helper函数?也不高。但当它看到”def calculate_roi”这一行,分数就上来了。函数的docstring、函数体里的关键语句,都会得到高分。
最后选出来可能就几十行代码,集中在这个函数周围。主模型只需要仔细分析这几十行,就能回答问题。
速度快了几十倍,但答案质量基本不变。
实际效果
论文里有详细的benchmark。几个有意思的点:
MMLU-Pro这种知识问答任务,分数完全没变,都是85.0。说明对于这类任务,稀疏化没有损失关键信息。
编程任务上反而提升了。Codeforces rating从2046涨到2121。我猜可能是因为代码结构性很强,稀疏attention帮助模型更聚焦在函数定义和调用关系上,反而减少了噪音干扰。
但复杂推理任务上有轻微下降。比如GPQA从80.7降到79.9,降了不到1分。还有一些数学任务也有类似情况。
为什么?这些任务往往需要长距离依赖,每一步推理可能引用很前面的信息。如果Indexer没选中某个关键步骤,推理链就断了。
不过总体来说,大部分任务上都保持了性能,这个trade-off是值得的。
成本优势
DeepSeek把API价格降到了惊人的程度。Output从12元降到3元,成了Grok-4-fast外成本最低的高性能模型。
如果你经常处理长文档,这个差异很明显。比如每天分析1000个100K tokens的报告,以前一个月要花几千美元,现在可能只要几百。
为什么能降这么多?因为计算量和内存占用都大幅下降了。原来需要的GPU资源少了,单位时间能处理的请求多了,成本自然降下来。
适用场景
DSA不是万能的。它有明确的适用范围。
适合用的情况:文档问答、代码分析、对话系统、摘要生成。这些任务的特点是信息有冗余,关键内容相对集中,不需要对每个细节都同等关注。
不太适合的情况:复杂的数学推理、需要精确统计的任务、信息密度极高的场景。比如你要在一篇论文里数出所有引用,或者推导一个多步证明,DSA可能会漏掉一些东西。
所以实际使用的时候,还是要看具体任务。DeepSeek也保留了V3.1的接口,如果V3.2跑出来的结果不满意,可以fallback回去。
一些思考
这个设计挺巧妙的,但也留了一些问题。
k=2048这个数字应该是在多个任务上试出来的平衡点。不同任务如果用不同的k,效果可能会更好。比如代码任务可能k=1024就够了,但复杂推理任务可能需要k=4096。
Lightning Indexer虽然轻量,但它的计算复杂度还是O(L²)。这部分可以用hierarchical的方式优化,先粗选一批候选,再在候选中精选。或者借鉴一些近似算法,比如局部敏感哈希。
另外这个机制跟MoE确实很像,都是”选择性激活”的思路。MoE在参数维度做稀疏,DSA在序列维度做稀疏。两者应该可以结合得更紧密,比如让Router和Indexer共享部分网络结构,或者根据选中的tokens来动态决定激活哪些experts。
总的来说,DSA是个在效率和质量之间找到不错平衡点的方案。对于大部分实际应用场景,这个trade-off是合理的。