首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

一文通透DeepSeek V2——通俗理解多头潜在注意力MLA:改进MHA,从而压缩KV缓存,提高推理速度

  • 25-02-15 07:00
  • 4644
  • 13286
blog.csdn.net

前言

成就本文有以下三个因素

  1. 24年5.17日,我在我司一课程「大模型与多模态论文100篇」里问道:大家希望我们还讲哪些论文
    一学员朋友小栗说:幻方旗下公司深度求索于24年5.7日发布的deepseek-v2
  2. 24年5.24日,我司一课程「大模型项目开发线上营1」里的一学员朋友问我:校长最近开始搞deepseek了吗?刚看了论文,没搞懂MLA那块的cache是怎么算的,我总觉得他的效果应该类似MQA才对,但是反馈是挺好的

    我当时回复他道:目前团队项目上的事情太多,然后近期在写那个KAN
    确实还没来得及看这个deepseek,我近期看下
  3. 我们在继英文层面的论文翻译、审稿、对话、idea提炼之后(其中的审稿和翻译已于24年8月底上线七月官网 )

    打算再整一下中文层面的「硕士论文修订助手(不限学科,CS和非CS的都涵盖)」,预计24年9月份上线七月官网
    对于模型的选择,在闭源之外,在开源模型上 有两个选择,一个chatglm4,一个DeepSeek(后来实际上线时,一开始用的deepseek v2,后来改成了deepseek v3)

而搞DeepSeek之前——近几天,会先写一下它的论文解读(当然,因为DeepSeek-V2从DeepSeek LLM、DeepSeekMoE迭代而来,且用到了DeepSeekMath中的GRPO算法,故第一部分会先讲DeepSeek LLM、DeepSeekMoE、DeepSeekMath),故本文就来了,且DeepSeek也算证明了在国内也可以做出有效果、有影响力的创新

且一如既往做到——对于几乎每一个主题,都如本博客万千读者或七月学员所说的:“还是看校长的文章好理解”,而其中的关键之一是做好图、文、公式的一一对应,不一笔带过、不自以为然,本文亦如此

同时本文也见证了自己从技术人到产品人定位的过渡

  1. 23上半年 侧重原理,系统大量读paper,深挖原理
  2. 23下半年 侧重工程,和项目组不断优化各种工程问题
  3. 24上半年 侧重研究,横跨或综合多个领域(比如llm+机器人),继续各种抠paper
  4. 24下半年 侧重产品,把世界级前沿落地成产品 给用户使用,以发挥更大的价值和影响力(希望有机会早日达到世界级影响力)

第一部分 从DeepSeek LLM、DeepSeekMoE到DeepSeekMath

友情提醒,如不需要透彻深入理解,或者想直接看DeepSeek-V2的,可以直接跳到本文的第二部分,本文第二部分也是本文的最精华所在

当然,如果你就是想先从本第一部分 开始看则非常好,但里面的数学公式比较多,喜欢抠公式的可以细抠,不喜欢抠公式的则不用抠太细,不影响对DeepSeek-V2的整体理解

原标题1.1 DeepSeek LLM的预训练与对齐1.2 DeepSeekMoE的创新:细粒度专家分割与共享专家隔离1.3 DeepSeek-Coder、DeepSeekMath及其提出的GRPO
提出时间

24年1.5日,量化巨头幻方旗下的杭州深度求索公司提出DeepSeek LLM,其对应的论文为《DeepSeek LLM: Scaling Open-Source Language Models with Longtermism》

24年1.11日,深度求索公司很快又提出了DeepSeekMoE,其对应的论文为《DeepSeekMoE: Towards Ultimate Expert Specialization in Mixture-of-Experts Language Models》

24年1.25,深度求索公司又提出DeepSeek-Coder

因为DeepSeek-V2涉及到了DeepSeekMath「其对应论文为 24年2月发表的《DeepSeekMath: Pushing the Limits of Mathematical Reasoning in Open Language Models》」中提出的群体相对策略优化——Group Relative Policy Optimization(简称GRPO)

改动本1.1节后已独立成文,详见下文的「3.1节DeepSeek LLM的预训练与对齐」因为MoE架构的重要性,本1.2节后已独立成文,详见下文的「3.2节DeepSeekMoE的创新:细粒度专家分割与共享专家隔离」对应的论文为《DeepSeek-Coder: When the Large Language Model Meets Programming -- The Rise of Code Intelligence》后本1.3节已独立成文,详见下文
对应的新文章一文速览DeepSeekMoE及相关MoE大模型:从Mixtral 8x7B到DeepSeekMoE(含DeepSeek LLM的简介)、Qwen2.5-Max一文速览DeepSeekMoE及相关MoE大模型:从Mixtral 8x7B到DeepSeekMoE(含DeepSeek LLM的简介)、Qwen2.5-Max一文速览DeepSeekMath及GRPO:通俗理解群体相对策略优化GRPO(含DeepSeek-Coder的简介)

第二部分 DeepSeek-V2:提出多头潜在注意力MLA且改进MoE

DeepSeek-V2属于DeepSeek的第二代版本,参数规模虽然达到了庞大的236B,但由于其MoE的结构,使得其中每个token激活仅21B的参数,且支持128K的上下文(It is equipped with a total of 236B parameters, of which 21B are activated for each token, and supports a context length of 128K tokens)

其对应论文为《DeepSeek-V2: A Strong, Economical, and Efficient Mixture-of-Experts Language Model》,发布于24年5.7日

  1. 他们首先在完整的预训练语料库上预训练DeepSeek-V2
  2. 然后,收集了150万个对话会话,涵盖了数学、代码、写作、推理、安全等各个领域,以对DeepSeek-V2 Chat(SFT)进行监督微调(SFT)
  3. 最后,他们遵循DeepSeekMath的方法,采用组相对策略优化(GRPO)进一步使模型与人类偏好对齐,并生成DeepSeek-V2 Chat(RL)

DeepSeek-V2主要有两大创新点,其在Transformer架构「一个注意力模块和一个前馈网络(FFN),如对transformer还不够熟练,请看此文:Transformer通俗笔记:从Word2Vec、Seq2Seq逐步理解到GPT、BERT」的基础上

  1. 改造注意力模块
    其通过创造性的提出多头潜在注意力:Multi-head Latent Attention(简称MLA),替代传统多头注意力(Multi Head Attention)
    具体而言,MLA利用低秩键值联合压缩(low-rank key-value joint compression)来降低推理时的KV Cache开销——相当于low-rank joint compression for keys and values to reduce KV cache,且性能不输于MHA(论文中说的是性能比MHA还更好)

    我个人认为,MLA本质上也是受到了​LoRA和Stable Diffusion的启发「前者详见此文《LLM高效参数微调方法:从Prefix Tuning、Prompt Tuning、P-Tuning V1/V2到LoRA、QLoRA(含对模型量化的解释)》,后者详见此文《AI绘画原理解析:从CLIP、BLIP到DALLE、DALLE 2、DALLE 3、Stable Diffusion(含ControlNet详解)》」
    所以MLA 是多头潜在注意力,在多头注意力上 加上了低秩KV压缩
  2. 改造FFN
    其把FFN的结构改成DeepseekMoE——是对传统MoE结构的改进(下图各种结构、表示很多,初看难以一看就懂,没事,下文会逐一详解,任何一个符号都不会放过——最后,反复琢磨之后,你也可以和我一样:脱离本文,手绘下图、手推下图背后的公式)

值得一提的是,他们还一块发布了 DeepSeek-V2-Lite,相当于配备 MLA 和 DeepSeekMoE 的较小模型,它总共有15.7B参数,其中每个token激活2.4B参数(we also release DeepSeek-V2-Lite, a smaller model equipped with MLA and DeepSeekMoE, for the open-source community. It has a total of 15.7B parameters, where 2.4B are activated for each token)

  • DeepSeek-V2-Lite 有 27 层,隐藏维度为 2048。 它还采用 MLA,并具有 16 个注意力头,每个头的维度为 128
    其 KV 压缩维度为 512,但与 DeepSeek-V2 略有不同,它不压缩查询
    对于解耦查询和键,每头维度为 64
  • DeepSeek-V2-Lite 还采用 DeepSeekMoE,除了第一层外,所有前馈神经网络 (FFNs) 都被 MoE 层替换
    每个 MoE 层由 2 个共享专家和 64 个路由专家组成,每个专家的中间隐藏维度为 1408。 在这些路由专家中,每个token将激活6个专家
  • DeepSeek-V2-Lite 也在与 DeepSeek-V2 相同的预训练语料库上从头开始训练,该语料库未被任何 SFT 数据污染
    它使用 AdamW 优化器,超参数设置为 ?1 = 0.9, ?2 =0.95,权重衰减 =0.1

    学习率使用预热和阶梯衰减策略进行调度
    最初,在前2000步期间,学习率从0线性增加到最大值
    随后,在训练了大约80%的tokens后,学习率乘以0.316,并在训练了大约90%的tokens后再次乘以0.316
    最大学习率设置为4.2 × 10−4,梯度裁剪范数设置为1.0

    没有采用批量大小调度策略,而是以恒定的批量大小4608个序列进行训练
    在预训练期间,将最大序列长度设置为4K,并在5.7T tokens上训练DeepSeek-V2-Lite

2.1 DeepSeek-V2提出MLA的背景与作用

2.1.1 KV Cache所导致的显存消耗大,需要尽可能降低

众所周知,KV Cache是大模型标配的推理加速功能——也是推理过程中,显存资源巨大开销的元凶之一。如下图所示,在模型推理时,KV Cache在显存占用量可达30%以上

目前大部分针对KV Cache的优化工作

  1. 比如著名的vLLM「这是其介绍页面、这是其对应的GitHub、其论文则为:Efficient Memory Management for Large Language Model Serving with PagedAttention,当然了,我也写了一篇专门介绍vLLM的博客,详见《一文通透vLLM与其核心技术PagedAttention:减少KV Cache碎片、提高GPU显存利用率(推理加速利器)》」,其基于paged Attention,最大限度地利用碎片化显存空间,从而提升了空间利用率
  2. 再比如GQA、MQA
    GQA是query数不变,但多个query(比如2个)组成一个group以共享一个key value
    MQA则query也不变,但所有query(比如8个)共享一个key、一个value

    至于更多,详见此文:一文通透各种注意力:从多头注意力MHA到分组查询注意力GQA、多查询注意力MQA

这些方案的问题是什么呢?在于

  • 第一类方案并没有从根本上改变KV Cache占用空间巨大的问题
  • 而第二类方案中的MQA虽然较大降低了KV cache计算量,但性能相比MHA下降太多了
    至于第二类方案中的GQA则取了个折中:不好的是缓存下降的不够多、好的是相比MHA性能没有下降太多,毕竟我们追求的是缓存下降、性能不降

那KV Cache到底是什呢

  1. 对此,我们先来回顾下transformer当中的注意力计算公式
    \operatorname{Attention}(Q, K, V)=\operatorname{softmax}\left(\frac{Q K^{T}}{\sqrt{d_{k}}}\right) V
  2. GPT预测下一个token时,其只能看到待预测token之前的所有token,故在最终生成Q_1,Q_2,Q_3,Q_4整个序列的过程中,会涉及到如下计算过程
    \operatorname{softmax}\left(\begin{array}{cccc} Q_{1} K_{1}^{T} & -\infty & -\infty & -\infty \\ Q_{2} K_{1}^{T} & Q_{2} K_{2}^{T} & -\infty & -\infty \\ Q_{3} K_{1}^{T} & Q_{3} K_{2}^{T} & Q_{3} K_{3}^{T} & -\infty \\ Q_{4} K_{1}^{T} & Q_{4} K_{2}^{T} & Q_{4} K_{3}^{T} & Q_{4} K_{4}^{T} \end{array}\right)\left[\begin{array}{c} \overrightarrow{V_{1}} \\ \overrightarrow{V_{2}} \\ \overrightarrow{V_{3}} \\ \overrightarrow{V_{4}} \end{array}\right]
  3. 然后把上面的softmax结果和对应的V值一相乘,便可得到
    \begin{array}{l} \operatorname{Att}_{1}(Q, K, V)=\operatorname{softmaxed}\left(Q_{1} K_{1}^{T}\right) \overrightarrow{V_{1}} \\ \operatorname{Att}_{2}(Q, K, V)=\operatorname{softmaxed}\left(Q_{2} K_{1}^{T}\right) \overrightarrow{V_{1}}+\operatorname{softmaxed}\left(Q_{2} K_{2}^{T}\right) \overrightarrow{V_{2}} \\ \operatorname{Att}_{3}(Q, K, V)=\operatorname{softmaxed}\left(Q_{3} K_{1}^{T}\right) \overrightarrow{V_{1}}+\operatorname{softmaxed}\left(Q_{3} K_{2}^{T}\right) \overrightarrow{V_{2}} + \operatorname{softmaxed}\left(Q_{3} K_{3}^{T}\right) \overrightarrow{V_{3}} \\ \operatorname{Att}_{4}(Q, K, V)=\operatorname{softmaxed}\left(Q_{4} K_{1}^{T}\right) \overrightarrow{V_{1}}+\operatorname{softmaxed}\left(Q_{4} K_{2}^{T}\right) \overrightarrow{V_{2}} + \operatorname{softmaxed}\left(Q_{3} K_{3}^{T}\right) \overrightarrow{V_{3}} + \operatorname{softmaxed}\left(Q_{4} K_{4}^{T}\right) \overrightarrow{V_{4}} \end{array}
    可以很明显的看到,上述计算过程中,有不少的K V重复计算,比如K_{1}^{T}\overrightarrow{V_{1}}、K_{2}^{T}\overrightarrow{V_{2}}、K_{3}^{T}\overrightarrow{V_{3}}
    上面这句话值得反复品味三遍!

如果序列长度越长,类似这样的K V重复计算会越多,从而势必将白白消耗那么大的显存,所以才说需要降低这种K V重复计算

2.1.2 Multi-head Latent Attent:致力于在推理中降低n_{h} d_{h}

MLA是对传统多头注意力做的改进,其目的有两个:首先是,降低推理过程中的KV Cache资源开销,其次,缓解MQA、MGA对性能的损耗

如上文所说,KV Cache中,提到每一步都需要将K和V缓存下来

具体而言,对于单个Attention Block块中的多头注意力(下图来自上文提到过的Transformer通俗笔记)

比如,举个例子,假设

  • 输入embedding的维度为d,比如512
  • 然后有n_h个头,比如8个头
  • 每个头——k和v的维度为d_h,比如64
  • \mathbf{h}_{t} \in \mathbb{R}^{d}为注意力层中第t个token的输入
  • transformer的层数为l,比如上图中的X——Thinking
  1. 首先,标准的MHA会通过三个矩阵W^{Q}, W^{K}, W^{V} \in \mathbb{R}^{d_{h} n_{h} \times d}分别生成\mathbf{q}_{t}, \mathbf{k}_{t}, \mathbf{v}_{t} \in \mathbb{R}^{d_{h} n_{h}},即
    \begin{aligned} \mathbf{q}_{t} & =W^{Q} \mathbf{h}_{t} \\ \mathbf{k}_{t} & =W^{K} \mathbf{h}_{t} \\ \mathbf{v}_{t} & =W^{V} \mathbf{h}_{t} \end{aligned}
  2. 然后,\mathbf{q}_{t}, \mathbf{k}_{t}, \mathbf{v}_{t}将被切分成n_h个头用于多头注意力计算
    \begin{array}{l} {\left[\mathbf{q}_{t, 1} ; \mathbf{q}_{t, 2} ; \ldots ; \mathbf{q}_{t, n_{h}}\right]=\mathbf{q}_{t}} \\ {\left[\mathbf{k}_{t, 1} ; \mathbf{k}_{t, 2} ; \ldots ; \mathbf{k}_{t, n_{h}}\right]=\mathbf{k}_{t}} \\ {\left[\mathbf{v}_{t, 1} ; \mathbf{v}_{t, 2} ; \ldots ; \mathbf{v}_{t, n_{h}}\right]=\mathbf{v}_{t}} \\ \quad \mathbf{o}_{t, i}=\sum_{j=1}^{t} \operatorname{Softmax}_{j}\left(\frac{\mathbf{q}_{t, i}^{T} \mathbf{k}_{j, i}}{\sqrt{d_{h}}}\right) \mathbf{v}_{j, i} \\ \quad \mathbf{u}_{t}=W^{O}\left[\mathbf{o}_{t, 1} ; \mathbf{o}_{t, 2} ; \ldots ; \mathbf{o}_{t, n_{h}}\right] \end{array}

    其中
    \rightarrow  \mathbf{q}_{t, i}, \mathbf{k}_{t, i}, \mathbf{v}_{t, i} \in \mathbb{R}^{d_{h}}分别表示第i个注意力头的查询、键和值
    \rightarrow  W^{O} \in \mathbb{R}^{d \times d_{h} n_{h}}表示输出投影矩阵
  3. 最终,在推理过程中,需要缓存所有的键和值以加速推理,因此MHA需要为每个token缓存的参数量为2 n_{h} d_{h} l(注意,是针对每个token,总之,如论文中所说,During inference, all keys and values need to be cached to accelerate inference, so MHA needs to cache 2 n_{h} d_{h} l elements for each token)

因此,MLA致力于在推理中降低n_{h} d_{h},具体而言,其不直接减少cache数量,而是类似Lora微调方法

  • 对Key和Value进行了一个低秩联合压缩(即Low-Rank Key-Value Joint Compression,通过低秩转换为一个压缩的KV,使得存储的KV的维度显著减小)

  • 如上图所示(在MHA GQA中大量存在于keys values中的KV缓存——带阴影表示,到了MLA中时,只有一小部分的被压缩Compressed的Latent KV了)
    那,MLA具体如何做压缩呢,详看下节

2.2 详解MLA的两个部分:一部分做压缩、一部分做RoPE编码

DeepSeek通过对Query和Key进行拆分为\left[q_{t}^{R}, q_{t}^{C}\right]和\left[k_{t}^{R}, k_{t}^{C}\right],其中一部分做压缩\left(q_{t}^{C}, k_{t}^{C}\right)、一部分做RoPE编码\left(q_{t}^{R}, k_{t}^{R}\right)「R可以理解为RoPE的标识符」

2.2.1 MLA对Q K V的压缩:先对KV联合压缩后升维,再对Q压缩后升维

2.2.1.1 先对KV联合压缩(Low-Rank Key-Value Joint Compression)、后升维

首先,对于上图右下角的\mathbf{c}_{t}^{K V}、\mathbf{k}_{t}^{C}、\mathbf{v}_{t}^{C}

可以看到先降维down(公式表示时用D表示降维),再升维up(公式表示用U表示升维),如下三个公式

\begin{array}{l} \mathbf{c}_{t}^{K V}=W^{D K V} \mathbf{h}_{t} \\ \mathbf{k}_{t}^{C}=W^{U K} \mathbf{c}_{t}^{K V} \\ \mathbf{v}_{t}^{C}=W^{U V} \mathbf{c}_{t}^{K V} \end{array}

  1. 先针对KV联合压缩以降维,降维到d_{c}\left(\ll d_{h} n_{h}\right) (即指上面的第一个公式)
    对于上述第一个公式\mathbf{c}_{t}^{K V}=W^{D K V} \mathbf{h}_{t},其中的c_{t}^{K V} \in R^{d_{c}}是对key和value压缩后的潜在向量
    \rightarrow  对于c_t
    其维度d_{c}\left(\ll d_{h} n_{h}\right)表示KV被压缩后的维度——有意思的是很快下文会讲到deepseek v2中d_{c}被设置为4 d_{h}
    且d_c远小于到头key和value的原始维度n_{h} d_{h}
    「 上文有说,输入embedding的维度为d 比如512,然后有n_h个头 比如8个头(不过,deepseek v2中设置的128个头)
    每个头——k和v的维度为d_h 比如64(不过,deepseek v2中头的维度设置的128) 」

    \rightarrow  具体如何被压缩的呢?
    很简单,其通过一个降维映射矩阵W^{D K V} \in \mathbb{R}^{d_{c} \times d}和模型输入h_t 相乘得到
  2. 再对K、V分别升维到以还原 (即指上面的第二、第三公式)
    至于上述的第二公式\mathbf{k}_{t}^{C}=W^{U K} \mathbf{c}_{t}^{K V}、第三公式\mathbf{v}_{t}^{C}=W^{U V} \mathbf{c}_{t}^{K V}怎么个具体计算过程呢?

    过程也很简单
    在于通过第一个公式得到c_t后,具体的key和value由两个对应的升维矩阵W^{U K}, W^{U V} \in \mathbb{R}^{d_{h} n_{h} \times d_{c}}还原——见下图的最右下角,就得到了上面的第二、第三公式拉
    \begin{array}{l} \mathbf{k}_{t}^{C}=W^{U K} \mathbf{c}_{t}^{K V} \\ \mathbf{v}_{t}^{C}=W^{U V} \mathbf{c}_{t}^{K V} \end{array}

    且在推理的过程中
    1) 只需要缓存每一步的\mathbf{c}_{t}^{K V},然后再计算还原回原始的K和V即可,由于c_t的维度远小于K、V,因此每一步token的推理产生的缓存由之前的2 n_{h} d_{h} l,变成d_c l
    2) 由于W^{U K}可以吸收到 W^Q中,而W^{U V}可以吸收到W^{O}中,如此甚至不需要计算注意力的键和值(即如论文中所说,during inference, since ??? can be absorbed into ??, and ??? can be absorbedinto ??, we even do not need to compute keys and values out for attention)

注,为方便大家更好的理解,我于24年8月27日晚上特地花了个把小时(反复琢磨、反复修改),用手头的iPad Pro + apple pencil画了下上述过程,以方便大家一目了然的对比前后维度的变化(至于下图底部中“除了c_{t}^{K V}之外”的怎么回事,不急,下文很快会逐一阐述)

2.2.1.2 再对Q压缩后升维

其次,对于上图左下角的c_{t}^{Q}、q_{t}^{C}

之前提到KV Cache中,Q的作用只发生在当下(预测下一个token时,其只能看到待预测token之前的所有token),但是在模型训练的过程中,每个输入的token会通过多头注意力机制生成对应的query、key和value

这些中间数据的维度往往非常高,因此占用的内存量也相应很大

所以论文中也提到,为了降低训练过程中的激活内存activation memory,DeepSeek-V2还对queries进行低秩压缩——即便这并不能降低KV Cache,而其对Q的压缩方式和K、V一致,依然是先降维再升维

\begin{array}{l} c_{t}^{Q}=W^{D Q} h_{t} \\ q_{t}^{C}=W^{U Q} c_{t}^{Q} \end{array}

其中

  1. \mathbf{c}_{t}^{Q} \in \mathbb{R}^{d_{c}^{\prime}}是查询向量的压缩潜在向量(the compressed latent vector for queries)d_{c}^{\prime}\left(\ll d_{h} n_{h}\right)表示查询向量压缩后的维度(为了区别上面的d_c,所以用d_{c}^{\prime}表示)
  2. 而W^{D Q} \in \mathbb{R}^{d_{c}^{\prime} \times d}、W^{U Q} \in \mathbb{R}^{d_{h} n_{h} \times d_{c}^{\prime}}则分别表示查询向量的下投影矩阵、上投影矩阵(相当于还是先降维再升维)

2.2.2 MLA对query和key的RoPE编码

先说结论,如下图红框所示,需要对\left(q_{t}^{R}, k_{t}^{R}\right)做RoPE编码,并对其中的Key位置编码的部分进行Cache,从而在推理时不需要对Key进行位置编码的计算,提高了推理效率

再说原因,即选择对\left(q_{t}^{R}, k_{t}^{R}\right)做RoPE编码的背后有何深意呢?且听我july慢慢道来

首先,在RoPE的实现中,如果要让Q、K带上位置信息,会分别乘以相应的位置编码矩阵

\begin{array}{l} \tilde{Q}=R_{m} Q \\ \tilde{K}=R_{n} K \end{array}

如果计算QK时,自然就变成了

S=R_{m}^{T} Q^{T} R_{n} K

通过上一节可知,DeepSeek-V2对Q和K都进行了压缩(如下图 带着蓝色下划线的):q_{t}^{C}=W^{U Q} c_{t}^{Q}、\mathbf{k}_{t}^{C}=W^{U K} \mathbf{c}_{t}^{K V}​​​​​​

则整个过程变成

S=\left(W^{U Q}\right)^{T}\left(c_{t}^{Q}\right)^{T} R_{m}^{T} R_{n} c_{t}^{K V} W^{U K}

其中的W^{U Q}和W^{U K}——如上节所述,分别是用于从低秩表示恢复到原始维度的解压缩矩阵(说白了,就是升维的)

然问题是

  1. 由于低秩表示已经是压缩了的状态,故直接在c_{t}^{Q}和c_{t}^{K V}上应用R_m和R_n,不等价于在完整的Q和K上应用位置编码(因为压缩操作可能已经丢失了某些信息,使得位置编码不能直接和有效地反映原始Q和K的位置关系)
    换言之,RoPE与低秩KV压缩不兼容——RoPE is incompatible with low-rank KV compression
  2. 为了解决这问题,Deepseek-V2设计了两个pe结尾的变量——\mathbf{q}_{t, i}^{R} \in \mathbb{R}^{d_{h}^{R}}、\mathbf{k}_{t}^{R} \in \mathbb{R}^{d_{h}^{R}}(如论文中所说,we propose the decoupled RoPE strategy that uses additional multi-head queries q??,? ∈ R??ℎ and a shared key k?? ∈ R??ℎ to carry RoPE, where d_{h}^{R} denotes the per-head dimension of the decoupled queries and key,即表示解耦查询和键的每头维度)——亦即如下图红框里的两个变量

    以用于储存旋转位置编码的信息,从而将信息存储和旋转编码解耦开
    \mathbf{q}_{t}^{R}=\operatorname{RoPE}\left(W^{Q R} \mathbf{c}_{t}^{Q}\right)
    \mathbf{k}_{t}^{R}=\operatorname{RoPE}\left(W^{K R} \mathbf{h}_{t}\right)
    其中,W^{Q R} \in \mathbb{R}^{d_{h}^{R} n_{h} \times d_{c}^{\prime}}、W^{K R} \in \mathbb{R}^{d_{h}^{R} \times d}分别是用于生成解耦查询和键的矩阵,如下图的最右下角所示「为方便大家更好的理解,我把我自己上面画的手绘图又加了一些内容,好与上述这些公式逐一比对」

    且顺带总结一下
    首先,因为q_{t}^{C}=W^{U Q} c_{t}^{Q}、\mathbf{k}_{t}^{C}=W^{U K} \mathbf{c}_{t}^{K V}做了压缩
    故不能直接在c_{t}^{Q}和c_{t}^{K V}上应用R_m和R_n
    从而也就不能
    S=\left(W^{U Q}\right)^{T}\left(c_{t}^{Q}\right)^{T} R_{m}^{T} R_{n} c_{t}^{K V} W^{U K}

    故额外设计两个变量——如上图左下角所示
    \mathbf{q}_{t, i}^{R} \in \mathbb{R}^{d_{h}^{R}}
    \mathbf{k}_{t}^{R} \in \mathbb{R}^{d_{h}^{R}}

    使得有
    \mathbf{q}_{t}^{R}=\operatorname{RoPE}\left(W^{Q R} \mathbf{c}_{t}^{Q}\right)
    \mathbf{k}_{t}^{R}=\operatorname{RoPE}\left(W^{K R} \mathbf{h}_{t}\right)
  3. 可能如果没有再三强调,有的宝子们便不太注意
    故,我july再强调一遍上面所说的 “将信息存储和旋转编码解耦开”,即如下图所示

     \rightarrow  对\mathbf{k}_{t}^{R}进行RoPE编码时,它是直接从input hidden h_t上来的
    「 相当于此时的k不搞上一节所述的先降维、后升维那一套
    \begin{array}{l} \mathbf{c}_{t}^{K V}=W^{D K V} \mathbf{h}_{t} \\ \mathbf{k}_{t}^{C}=W^{U K} \mathbf{c}_{t}^{K V} \\ \mathbf{v}_{t}^{C}=W^{U V} \mathbf{c}_{t}^{K V} \end{array}」
    所以才有的
    \mathbf{k}_{t}^{R}=\operatorname{RoPE}\left(W^{K R} \mathbf{h}_{t}\right)
    \rightarrow  对\mathbf{q}_{t}^{R}进行RoPE编码时,它取自的latent \mathbf{c}_{t}^{Q}「相当于此时的Q做了潜在压缩c_{t}^{Q}=W^{D Q} h_{t},但没做升维q_{t}^{C}=W^{U Q} c_{t}^{Q}」
    所以才有的
    \mathbf{q}_{t}^{R}=\operatorname{RoPE}\left(W^{Q R} \mathbf{c}_{t}^{Q}\right)


    请注意上面这两句话的含金量,这点几乎没有文章会给你特地强调出来的,虽然它本身就是个事实性的存在

压缩完、且RoPE编码完之后,最后将这4个变量——q_{t}^{C}=W^{U Q} c_{t}^{Q}、\mathbf{k}_{t}^{C}=W^{U K} \mathbf{c}_{t}^{K V}、\mathbf{q}_{t}^{R}、\mathbf{k}_{t}^{R},分别拼接起来,形成

  • 带信息压缩的Q——\mathbf{q}_{t}^{C}、K——\mathbf{k}_{t}^{C}
  • 带位置信息的Q——\mathbf{q}_{t}^{R}、K——\mathbf{k}_{t}^{R}

以进行最后的计算

  • 其中蓝色框中的向量\mathbf{c}_{t}^{K V}、\mathbf{k}_{t}^{R}需要缓存以进行生成。 在推理过程中,the naive formula需要从\mathbf{c}_{t}^{K V}中恢复\mathbf{k}_{t}^{C}和\mathbf{v}_{t}^{C}以进行注意力计算
    \begin{array}{l} \mathbf{c}_{t}^{K V}=W^{D K V} \mathbf{h}_{t} \\ \mathbf{k}_{t}^{C}=W^{U K} \mathbf{c}_{t}^{K V} \\ \mathbf{v}_{t}^{C}=W^{U V} \mathbf{c}_{t}^{K V} \end{array}
    \begin{array}{l} c_{t}^{Q}=W^{D Q} h_{t} \\ q_{t}^{C}=W^{U Q} c_{t}^{Q} \end{array}
  • 幸运的是,由于矩阵乘法的结合律,可以将W^{U K}吸收到W^{U Q}中,并将W^{U V}吸收到W^{O}中。 因此,不需要为每个查询计算键和值。 通过这种优化,避免了在推理过程中重新计算\mathbf{k}_{t}^{C}和\mathbf{v}_{t}^{C}的计算开销

最终,单个Token产生的缓存包含了两个部分,即\left(d_{c}+d_{h}^{R}\right) l

其中,如上文说过的

  • 有n_h个头 比如8个头,每个头——k和v的维度为d_h 比如64,l 表示为transformer的层数
  • n_g表示为GQA中的组数
  • d_{c}、d_{h}^{R}分别表示MLA中的KV压缩维度、解耦查询和键的the per-head dimension

在DeepSeek-V2中,d_{c}被设置为4 d_{h},d_{h}^{R}被设置为\frac{d_{h}}{2}

  • 把我上面画的手绘图


  • 翻转一下,可以对比下d_h、d_c、d_{h}^{R}之间的换算关系

因此,它的KV缓存等于只有2.25组的GQA,但其性能强于MHA

2.3 DeepSeekMoE:以经济成本训练强大的模型

2.3.1 基本架构与Device-Limited Routing

由于在上文的1.3节,详细的介绍了DeepSeekMoE(包括细粒度专家分割和共享专家隔离),故本节描述从简

DeepSeekMoE有两个关键理念:

  1. 将专家细分为更细的粒度以实现更高的专家专业化和更准确的知识获取
  2. 隔离一些共享专家以减轻路由专家之间的知识冗余

最终,在激活和总专家参数数量相同的情况下,DeepSeekMoE 可以大幅超越传统的 MoE 架构

设u_{t}为第t 个标记的 FFN 输入,我们计算 FFN 输出\mathbf{h}_{t}^{\prime}如下:

\begin{array}{l} \mathbf{h}_{t}^{\prime}=\mathbf{u}_{t}+\sum_{i=1}^{N_{s}} \operatorname{FFN}_{i}^{(s)}\left(\mathbf{u}_{t}\right)+\sum_{i=1}^{N_{r}} g_{i, t} \operatorname{FFN}_{i}^{(r)}\left(\mathbf{u}_{t}\right), \\ g_{i, t}=\left\{\begin{array}{ll} s_{i, t} & s_{i, t} \in \operatorname{Topk}\left(\left\{s_{j, t} \mid 1 \leqslant j \leqslant N_{r}\right\}, K_{r}\right) \\ 0, & \text { otherwise, } \end{array}\right. \\ s_{i, t}=\operatorname{Softmax}_{i}\left(\mathbf{u}_{t}^{T} \mathbf{e}_{i}\right) \end{array}

其中

  • N_{s}和N_{r}分别表示共享专家和路由专家的数量
  • \mathrm{FFN}_{i}^{(s)}(\cdot)和\mathrm{FFN}_{i}^{(r)}(\cdot)分别表示第i 个共享专家和第i个路由专家
  • K_{r}表示激活的路由专家数量
  • g_{i, t}是第i 个专家的门控值
  • s_{i, t}是token到专家的亲和度
  • \mathbf{e}_{i}是这一层中第i个路由专家的质心
  • 而\operatorname{Topk}(\cdot, K)表示由计算出的第t 个token和所有路由专家的亲和度得分中最高的K个得分组成的集合

对于DeepSeek-V2,除了简单的top-K路由专家选择外,其还确保每个token的目标专家最多分布在 ?个设备上。 具体来说,对于每个token,我们首先选择 ?个设备,这些设备中有专家具有最高的亲和分数

然后,在这些 ?个设备上的专家中进行top-K选择。 在实践中,我们发现当 ? ⩾3 时,设备限制路由可以实现与不受限制的 top-K 路由大致一致的良好性能

2.3.2 负载均衡的辅助损失(Auxiliary Loss for Load Balance)

首先,不平衡的负载会增加路由崩溃的风险,防止某些专家得到充分的训练和利用。 其次,当采用专家并行时,不平衡的负载会降低计算效率

故在 DeepSeek-V2 的训练过程中,设计了三种辅助损失,分别用于控制专家级负载均衡\mathcal{L}_{\text {ExpBal }}、设备级负载均衡\mathcal{L}_{\text {DevBal }}和通信均衡\mathcal{L}_{\text {CommBal }}

  • 专家级均衡损失
  • 设备级平衡损失
  • 通信平衡损失

此外,虽然平衡损失旨在鼓励负载平衡,但需要承认它们不能保证严格的负载平衡

为了进一步减轻由于负载不平衡导致的计算浪费,他们在训练期间引入了设备级的Token-Dropping策略

  1. 这种方法首先计算每个设备的平均计算预算,这意味着每个设备的容量因子相当于1.0
  2. 然后,受Riquelme等人的启发,在每个设备上丢弃具有最低亲和力分数的token,直到达到计算预算
  3. 此外,确保大约10%的训练序列中的token永远不会被丢弃。 通过这种方式,可以根据效率要求灵活决定在推理过程中是否丢弃标记,并始终确保训练和推理之间的一致性

第三部分 DeepSeek-V2的预训练与对齐

3.1 预训练(含数据构建与参数设置)、长度扩展、训练和推理效率

为提高其性能,他们构建了一个高质量的多源预训练语料库,包括8.1T的token,与DeepSeek 67B使用的语料库相比,该语料库的数据量有所增加,特别是中文数据,并且数据质量更高

且其采用与DeepSeek 67B相同的分词器,该分词器基于字节级字节对编码(BBPE)算法构建,词汇量为100K,其分词预训练语料库包含8.1T个token,其中中文token比英文标记多约12%

3.1.1 模型超参数

对于模型超参数,将Transformer层数设置为60,隐藏维度设置为5120——即d = 5120。 所有可学习参数均以标准差0.006随机初始化

在MLA中

  • 将注意力头的数量n_{h}设置为128
  • 每头维度d_{h}设置为128
  • KV压缩维度d_{c}设置为512「可以看出d_{c}\left(\ll d_{h} n_{h}\right)」,其实也远远小于d = 5120
    查询压缩维度d_{c}^{\prime}设置为1536——依然远小于d = 5120
    对于解耦查询和键,设置每头维度d_{h}^{R}为64

    上述3个数据的设置,其实也刚好呼应了上文2.2节最后说的
    “在DeepSeek-V2中,
    d_{c}被设置为4 d_{h},d_{h}^{R}被设置为\frac{d_{h}}{2}”

在DeepSeekMoE中,按照Dai等人的做法

  • 将除第一层外的所有前馈神经网络替换为专家混合层
    每个专家混合层由2个共享专家和160个路由专家组成,每个专家的中间隐藏维度为1536
  • 在这些路由专家中,每个token将激活6个专家
    此外,低秩压缩和细粒度专家分割将影响层的输出规模
  • 因此,在实践中,在压缩的潜在向量之后使用额外的RMS Norm层,并在宽度瓶颈处(即压缩的潜在向量和路由专家的中间隐藏状态)乘以额外的缩放因子,以确保训练的稳定性

在这种配置下,DeepSeek-V2总参数量为236B,其中每个token激活21B

3.1.2 训练超参数

以下是论文中所述的训练超参数设置

  • 使用AdamW优化器(Loshchilov和Hutter,2017),超参数设置为 ?1 = 0.9, ?2 =0.95,权重衰减 =0.1
  • 学习率使用预热和阶梯衰减策略进行调度(DeepSeek-AI,2024)
    最初,学习率在前2K步期间从0线性增加到最大值。
    随后,在训练约60%的token后,学习率乘以0.316,并在训练约90%的token后再次乘以0.316
    其中,最大学习率设置为2.4 × 10−4,梯度裁剪范数设置为1.0
  • 还使用批量大小调度策略,在前225B token的训练中,批量大小从2304逐渐增加到9216,然后在剩余的训练中保持9216
  • 将最大序列长度设置为4K,并在8.1T个tokens上训练DeepSeek-V2
  • 利用流水线并行技术在不同设备上部署模型的不同层,对于每一层,路由的专家将均匀部署在8个设备上 (? =8)
    至于设备限制路由,每个token最多会被发送到3个设备上 (? =3)。 关于平衡损失,我们将 ?1设置为0.003, ?2设置为0.05, ?3设置为0.02
  • 在训练期间采用Token-Dropping策略以加速,但在评估时不丢弃任何token

此外,DeepSeek-V2基于HAI-LLM框架(High-flyer, 2023)进行训练,这是高效且轻量的训练框架

  1. 它采用了16路零气泡流水线并行(Qi等,2023),8路专家并行(Lepikhin等,2021),以及ZeRO-1数据并行(Rajbhandari等,2020)
  2. 鉴于DeepSeek-V2激活的参数相对较少,并且部分操作符会重新计算以节省激活内存,因此可以在不需要张量并行的情况下进行训练,从而减少通信开销
  3. 此外,为了进一步提高训练效率,我们将共享专家的计算与专家并行的全对全通信重叠
  4. 且还为通信、路由算法和融合定制了更快的CUDA内核
    以及还基于改进版的 FlashAttention-2 (Dao, 2023) 进行了优化

最终,他们在配备 NVIDIA H800 GPU 的集群上进行所有实验。H800 集群中的每个节点包含 8 个GPU,这些 GPU 在节点内使用 NVLink 和 NVSwitch 连接。 在节点之间,使用 InfiniBand 互连来促进通信

3.1.3 长上下文扩展

在 DeepSeek-V2 的初始预训练之后,他们采用 YaRN「关于YaRN,详见此文《大模型长度扩展综述:从直接外推ALiBi、插值PI、NTK-aware插值(对此介绍最详)、YaRN到S2-Attention》的第四部分」将默认上下文窗口长度从 4K 扩展到 128K

  • YaRN 专门应用于解耦的共享key \mathbf{k}_{t}^{R},因为它负责携带 RoPE (Su et al.,2024)
    YaRN was specifically applied to the decoupled shared key k?? as it is responsible for carrying RoPE
  • 对于 YaRN,将比例scale s设置为 40,\alpha设置为 1,\beta设置为 32,并将目标最大上下文长度设置为 160K

另由于 DeepSeek-V2独特的注意力机制——MLA,与原始 YaRN 略有不同,故调整了长度缩放因子以调节注意力熵。 因子\sqrt{t}计算为\sqrt{t}=0.0707 \ln s+1,旨在最小化困惑度

且另外训练了模型 1000 步,序列长度为 32K,批量大小为 576 个序列。 尽管训练仅在32K的序列长度下进行,但在128K的上下文长度下评估时,该模型仍表现出强大的性能

如下图所示,“大海捞针”(NIAH)测试的结果表明,DeepSeek-V2在所有上下文窗口长度(最长至128K)上表现良好

3.1.4 训练和推理效率

如论文中所说

在训练成本上

  • 由于 DeepSeek-V2 对每个 token 激活的参数较少且所需的 FLOPs 少于 DeepSeek 67B,理论上训练 DeepSeek-V2 将比训练 DeepSeek 67B 更经济
  • 尽管训练一个 MoE 模型会引入额外的通信开销,但通过相应的操作和通信优化,DeepSeek-V2 的训练可以达到相对较高的模型 FLOPs 利用率 (MFU)
  • 在对 H800 集群的实际训练中,每训练一万亿个 token,DeepSeek 67B 需要 300.6K GPU 小时,而 DeepSeek-V2 仅需 172.8K GPU 小时,即稀疏的 DeepSeek-V2 比密集的 DeepSeek 67B 节省了 42.5% 的训练成本

在推理效率上

  • 为了高效地部署DeepSeek-V2服务,首先将其参数转换为FP8精度。此外,我们还对DeepSeek-V2进行KV缓存量化(Hooper等,2024;赵等,2023),以进一步将其KV缓存中的每个元素平均压缩到6位

    得益于MLA和这些优化,实际部署的DeepSeek-V2所需的KV缓存显著少于DeepSeek 67B,因此可以服务更大的批处理大小
  • 基于实际部署的DeepSeek 67B服务的提示和生成长度分布评估了DeepSeek-V2的生成吞吐量

    在单个节点上配备8个H800 GPU,DeepSeek-V2实现了超过每秒50K个token的生成吞吐量,是DeepSeek 67B最大生成吞吐量的5.76倍
    此外,DeepSeek-V2 的提示输入吞吐量超过每秒 100K 个token

3.2 对齐:监督微调与强化学习

3.2.1 DeepSeek-V2的一些微调、评估细节

基于之前DeepSeek-AI,他们整理了包含 150 万实例的指令微调数据集,其中包括 120 万个有用性实例和 30 万个安全性实例

与初始版本相比,改进了数据质量,以减少幻觉反应并提高写作能力且对 DeepSeek-V2 进行了 2 个周期的微调,学习率设置为 5 × 10−6

为了评估 DeepSeek-V2 Chat(SFT)

  1. 主要包括基于生成的基准测试,除了几个具有代表性的多项选择任务(MMLU 和 ARC)
  2. 且还对 DeepSeek-V2 Chat(SFT)进行了指令跟随评估(IFEval),使用提示级松散准确率作为指标
  3. 此外,我们使用2023年9月1日至2024年4月1日期间的LiveCodeBench (Jain et al., 2024)问题来评估聊天模型
  4. 除了标准基准测试外,还在开放式对话基准测试中评估了模型,包括MT-Bench (Zheng et al., 2023)、AlpacaEval 2.0 (Dubois et al., 2024)和AlignBench (Liu et al., 2023)

3.2.2 DeepSeek-V2通过GRPO训练策略模型

为了进一步释放DeepSeek-V2的潜力并使其与人类偏好对齐,进行强化学习(RL)以调整其偏好,且为了节省强化学习的训练成本,采用了上文第一部分介绍过的GRPO——详见《一文速览DeepSeekMath及GRPO:通俗理解群体相对策略优化GRPO(含DeepSeek-Coder的简介)》

具体来说,对于每个问题q,GRPO 从旧策略\pi_{\theta_{o l d}}中采样一组输出\left\{O_{1}, O_{2}, \cdots, O_{G}\right\}——即对同一个问题的不同回答,然后通过最大化以下目标来优化策略模型\pi_{\theta}目标「Specifically, for each question ?, GRPO samples a group of outputs {?1, ?2, · · · , ?? }from the old policy ????? and then optimizes the policy model ?? by maximizing the following objective」

\begin{aligned} \mathcal{J}_{G R P O}(\theta) & =\mathbb{E}\left[q \sim P(Q),\left\{o_{i}\right\}_{i=1}^{G} \sim \pi_{\theta_{\text {old }}}(O \mid q)\right] \\ & \frac{1}{G} \sum_{i=1}^{G}\left(\min \left(\frac{\pi_{\theta}\left(o_{i} \mid q\right)}{\pi_{\theta_{\text {old }}}\left(o_{i} \mid q\right)} A_{i}, \operatorname{clip}\left(\frac{\pi_{\theta}\left(o_{i} \mid q\right)}{\pi_{\theta_{\text {old }}}\left(o_{i} \mid q\right)}, 1-\varepsilon, 1+\varepsilon\right) A_{i}\right)-\beta \mathbb{D}_{K L}\left(\pi_{\theta} \| \pi_{r e f}\right)\right) \end{aligned}
\mathbb{D}_{K L}\left(\pi_{\theta} \| \pi_{r e f}\right)=\frac{\pi_{r e f}\left(o_{i} \mid q\right)}{\pi_{\theta}\left(o_{i} \mid q\right)}-\log \frac{\pi_{r e f}\left(o_{i} \mid q\right)}{\pi_{\theta}\left(o_{i} \mid q\right)}-1

其中\varepsilon和\beta是超参数;A_{i}是优势,使用一组奖励\left\{r_{1}, r_{2}, \ldots, r_{G}\right\}对应于每组内的输出计算得出

A_{i}=\frac{r_{i}-\operatorname{mean}\left(\left\{r_{1}, r_{2}, \cdots, r_{G}\right\}\right)}{\operatorname{std}\left(\left\{r_{1}, r_{2}, \cdots, r_{G}\right\}\right)}

在具体的训练策略上,采用了两阶段的强化学习训练策略,首先进行推理对齐,然后进行人类偏好对齐

  1. 在第一个推理对齐阶段,我们训练了一个奖励模型R M_{\text {reasoning }}用于代码和数学推理任务,并通过R M_{\text {reasoning }}的反馈优化策略模型
    r_{i}=R M_{\text {reasoning }}\left(o_{i}\right)
  2. 在第二个人类偏好对齐阶段,采用了一个多奖励框架,即
    一个有帮助的奖励模型R M_{\text {helpful }}
    一个安全奖励模型R M_{\text {safety }}
    一个基于规则的奖励模型R M_{\text {rule }}获取奖励

    从而一个响应的最终奖励 ??是
    r_{i}=c_{1} \cdot R M_{\text {helpful }}\left(o_{i}\right)+c_{2} \cdot R M_{\text {safety }}\left(o_{i}\right)+c_{3} \cdot R M_{\text {rule }}\left(o_{i}\right)
    其中 ?1, ?2, 和 ?3是相应的系数

更多,可以参见原论文

注:本文转载自blog.csdn.net的v_JULY_v的文章"https://blog.csdn.net/v_JULY_v/article/details/141535986"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2024 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top