作者:罗辑
目录
MLA(Multi-head Latent Attention多头潜空间注意力)的缘起
MLA(Multi-head Latent Attention)
摘要:最近DeepSeek在国际很火,甚至引起了美国总统的关注,一方面效果比肩闭源模型ChatGPT/O1,另外它开启了除openAI的pretrain+SFT+RLHF之外的新范式,同时训练和运行成本极低,引起国内讨论DeepSeek是否是国运级的创新。网上文章很多,但是真正能讲清楚原理的却少有。本博客的特点是结合图示,去深刻理解论文中的各种数学公式,极大的加深对模型原理的理解。
关于DeepSeek在网上文章很多,但是愿意讲清楚算法细节原理和设计思路的的却少有。本博客的特点是结合大量的示意图图示,去深刻理解算法的设计原理和设计思路,极大的加深对模型原理的理解。特别感谢苏建林老师的博客引导。
Deepseek技术创新分为3大块,分别为:模型结构、训练方法、工程优化3个方面,难以一次性讲解清楚。慢工出细活,本人计划分3个博客进行讲解。本次重点讲解deepseek模型结构方面的创新。deepseek模型结构方面创新有MLA和MOE结构优化。本次说MLA
MLA(Multi-head Latent Attention多头潜空间注意力)的缘起
一切要从transformer架构说起,transformer架构创新的使用3个向量,来表征一个词(token),通过向量之间的相关性,来表征两个词与词之间的相关性。当然,词语意思还会结合在句子中的语境,有多个含义。比如“苹果”,可以表示手机,也可以是水果。通过词与词的相关性,通过transformer block逐层调整,也能间接的表示整个句子的含义。
这3个向量就是Q、K、V向量。他们都是需要存储在GPU显存中的,非常占显存,显存是非常昂贵的。所以MLA目标就是想办法减少QKV向量的存储空间。
MHA(Multi-Head Attention)
要彻底理解MLA,就必须得从祖先MHA说起。MHA(Multi-Head Attention),也就是多头注意力,是LLM开山之作《Attention is all you need》所提出的一种Attention形式,是当前主流LLM的基础。
图示和对应的公式如下,这样就能看懂公式的含义了。简单起见,这里省略了Attention矩阵的缩放因子。h是多头注意力的头,d为输入x经过embeding之后的维度,常见的设置是
,对于LLAMA2-7b有
主流的自回归LLM所用的Causal 因果Attention,也就是预测出1个新token时,前面已经输入的token和计算的K和V不会变。
比如预测:“跟着罗辑学大模型”。
当预测到“学”时,前面的“跟着罗辑”已经之前算好了KV,当接下来预测“大”时,前面“跟着罗辑”的KV不会改变,因此,这部分KV结果我们可以缓存下来供后续生成调用,避免不必要的重复计算,这就是所谓的KV Cache。这样就能看懂论文中的第一个图了。斜杠表示需要缓存的向量。
瓶颈:为什么降低KV Cache的大小如此重要?
一般情况下LLM的推理都是在GPU上进行,单张GPU的显存是有限的,一部分我们要用来存放模型的参数和前向计算的激活值,这部分依赖于模型的体量,选定模型后它就是个常数;另外一部分我们要用来存放模型的KV Cache,这部分不仅依赖于模型的体量,还依赖于模型的输入长度,也就是在推理过程中是动态增长的,当Context长度足够长时,它的大小就会占主导地位,可能超出一张卡甚至一台机(8张卡)的总显存量。
在GPU上部署模型的原则是:能一张显卡部署的,就不要跨多张卡;能一台服务器机器能部署的,就不要跨多台机。这是因为“卡内通信带宽 > 卡间通信带宽 > 机间通信带宽”,由于“木桶效应”,模型部署时跨的设备越多,受设备间通信带宽的的“拖累”就越大,模型推理就越慢。所以美国限制高端英伟达GPU出口中国,除了限制GPU运算量,卡的通信带宽也是限制得死死的。
MQA(Multi-Query Attention)
MQA,是减少KV Cache的一次非常朴素的尝试,首次提出自2019年《Fast Transformer Decoding: One Write-Head is All You Need》。思路很简单,直接让所有Attention Head共享同一个K、V。因为KV本来也是可训练矩阵Wk、Wv通过和X相乘得到的,相当于神经元的个数,可多可少,因此相当于减少了神经元的个数,模型的正向传播和反向传播还是能正常走得通。
这里重点解释一下图示表示的是8个注意力头head,这里的QKV都是对应一个token的,部分人认为是输入x不同的token共享一个K/V是理解错误的。不同的token,KV是不一样的,仅仅是同一个token的不同注意力头共享一个KV。因此MQA直接将KV Cache减少到了原来的1/h,这是非常可观的,单从节省显存角度看已经是天花板了。
使用MQA的模型包括PaLM、StarCoder、Gemini等。效果方面,目前看来大部分任务的损失都比较有限,且MQA的支持者相信这部分损失可以通过进一步训练来弥补回。此外,注意到MQA由于共享了K、V,将会导致Attention的参数量减少了将近一半,而为了模型总参数量的不变,通常会相应地增大FFN/GLU的规模,这也能弥补一部分效果损失。本身原理没有问题。
GQA(Grouped-Query Attention)
当然有人担心MQA对KV Cache的压缩太严重,以至于会影响模型的学习效率以及最终效果。事情做太绝,未来不相见。
为此,一个MHA与MQA之间的过渡版本GQA(Grouped-Query Attention)应运而生,出自23年论文《GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints》。
整体思想就是:不要所有的head共享一个KV,分个组,比如第1-2个head共享一个KV,第3-4个head共享一个KV。这样就形成了如下的图。
DeepSeek-V1用的就是GQA,还包括llama2/3-70B、StarCoder2、Yi、ChatGLM2、ChatGLM3等,比使用MQA的模型更多。
MLA(Multi-head Latent Attention)
有了MHA、MQA、GQA的铺垫,理解MLA(Multi-head Latent Attention)就相对容易了。
可以从两个方面去理解MLA,第一,不管是GQA还是MQA,都需要缓存K、V两个值,两个值不一样,能不能进一步压缩,只缓存一个值,然后通过两个矩阵反向生成两个不同的向量,当成KV,这样就仅仅缓存一个字就好了。比如以下公式,缓存ci就好了。
可以通过矩阵Wk和Wv生成kv,其中的Wk和Wv作为模型参数的一部分。有了这样想法,之前MHA的公式就可以改写一下,变成如下的公式:
ci怎么来的?通过输入X乘以一个矩阵Wc变换得来的。
于是就能深刻理解论文里面画的这个示意图。
另一个方面,如果把MQA中的KV,强制让它合并成一个C向量,理论上也是可行的,貌似就变成和MLA大同小异的模型结构了。但是在GPU计算时,都是通过矩阵批量运算的,为了保持运算的矩阵维度,我们会把C向量复制多份,可以理解为MLA实际上是把C向量单纯复制动作,变成了两个矩阵的投影,从而等同增加了神经元个数,提升了模型容量。
图示为MQA共用KV时计算时的复制示意图。
晴天霹雳
一切似乎都很完美,看上去一个又好又省的理想模型设计就要出炉了。但我们一直没有考虑token的位置信息,考虑文本的位置编码,用的最多的是苏神发明的RoPE(旋转位置编码),基本上绝大部分开源LLM都用它,也充分证明了其有效性。但是很遗憾,刚开始设想那种MLA并不兼容RoPE,准确来说MLA不是不能加RoPE,而是加了RoPE之后无法用恒等变换技巧来减少KV Cache。为此,DeepSeek团队还特地邀请苏神去讨论过这个问题寻求建议。当时苏神坦言他实际上也没能提出什么有效的建议,最简单的方式是放弃RoPE,换用其他基于Attention Bias的位置编码,如ALIBI,但DeepSeek的实验显示它明显不如RoPE好。
算法的折中
算法似乎走进了死胡同,但是deepseek采用了一种折中的方法,那就是向量的前一半使用不带RoPE,后一半带RoPE,折中的方式也能减少KV Cache。
于是才有了论文公式中的这个等式,
同理,Q也是同样的操作。
以下是Llama运用RoPE的架构图,可以作为对比。RoPE是作用在Q和K中添加。
神来之笔
算法似乎设计完了,缓存一个ci给KV使用就好了,但是deepseek V3最终采用的模型结构貌似又有不同,颇有种“说好一起穿开裆裤,你却包上了尿不湿”的感觉,论文中还没有特别的解释。
是什么呢?就是MLA的最终版本,还将Q的输入也改为了低秩投影形式,这与减少KV Cache无关。单纯是为了降低过度压缩向量维度带来的对模型伤害。在deepseek公布的模型配置文件可看到。"hidden_size": 7168, "num_attention_heads": 128,如果按照MHA的设定,我们会缓存128个维度为7168/128=56维的向量,等同拼在一起就是缓存了个7168维的长向量,但是deepseek最后将KV缓存的ci向量维度设为512,也就是参数"kv_lora_rank": 512,相当于把缓存7168维的向量降低到了缓存512维。一般情况下,我们会设计q的输入向量维度和kv的输入向量维度相同,也是512维,但是Q向量我们并不需要缓存啊,为何不把输入搞大点,不需要将7168维的向量也降低到了缓存512维,deepseek设置的"q_lora_rank": 1536,也就是1536维是512维的3倍。这里没什么算法将就,单纯人为设定去平衡模型参数大小和训练高效性而设定。只要最终经过矩阵映射后的qkv维度一致就行。也即是说,q的投影矩阵会比kv的投影矩阵大3倍。
分拆成公式,q就
如下:
而KV如下:
也可以认为这个是一个神来之笔,不需要缓存的向量,可以搞大点,大不了增加一点计算量,但是并不增加显存占用,可以提升模型容量和能力。
彩蛋
还有个小细节一般人注意不到,就是K矩阵,说好后半段运用RoPE,咋公式还变了呢?仔细看论文。对比看K和Q的计算公式。
对比Q,可以看到,q用的都是ct,而K不是。
对比写成更直观的公式更明显。
K的后半部分,也就是带RoPE的部分,其输入还是xi而不是ci。这里苏神都不知道原因。从算法理论上这里用ci也没有问题,可能是deepseek试验后发现输入xi更好?有机会更deepseek交流询问一下。
模型架构
通过这样的讲解,就能看懂论文中的如下模型结构示意图。对应的计算公式也能更模型结构对应上。
用一个模型实例去看模型参数量更直观。如下:
能理清楚此图中的维度时,就表示看懂了。
总结
洋洋洒洒已经3千字,本文详细描述了多头注意力的演变历程,从MHA向MQA、GQA,最终到MLA的变化理念,详细展开MLA的介绍。在本文中,MLA被视为GQA/MQA的一般化,它用投影矩阵的方式替代了MQA的分割、重复,并引入了一个恒等变换技巧来可以进一步压缩KV Cache,同时采用了一种向量混合方法来兼容RoPE。总的来说,MLA称得上是一种非常实用、高效的注意力变体,但整体还是transform框架,单纯的MLA并非是从0到1打破传统的国运级的创新。
下回讲模型MTP多词预测原理和设计思路。请持续关注我。
参考文献
- 缓存与效果的极限拉扯:从MHA、MQA、GQA到MLA - 科学空间|Scientific Spaces
- https://zhuanlan.zhihu.com/p/720106482
- https://zhuanlan.zhihu.com/p/720718887
- 【LLM】(KV cache优化)MHA、MQA、GQA、MLA、YOCO机制的区别_mla llm-优快云博客
- https://zhuanlan.zhihu.com/p/18071594122
- https://dataturbo.medium.com/deepseek-technical-analysis-2-mla-74bdb87d4ad2