
DeepSeek LLM
代码地址:
背景
量化巨头幻方探索AGI(通用人工智能)新组织“深度求索”在成立半年后,发布的第一代大模型,免费商用,完全开源。作为一家隐形的AI巨头,幻方拥有1万枚英伟达A100芯片,有手撸的HAI-LLM训练框架HAI-LLM:高效且轻量的大模型训练工具。
概述
DeepSeek LLMs,这是一系列在2万亿标记的英语和中文大型数据集上从头开始训练的开源模型
在本文中,深入解释了超参数选择、Scaling Laws以及做过的各种微调尝试。校准了先前工作中的Scaling Laws,并提出了新的最优模型/数据扩展-缩放分配策略。此外,还提出了一种方法,使用给定的计算预算来预测近似的batch-size和learning-rate。进一步得出结论,Scaling Laws与数据质量有关,这可能是不同工作中不同扩展行为的原因。在Scaling Laws的指导下,使用最佳超参数进行预训练,并进行全面评估。
作者还对DeepSeek LLM基础模型进行了SFT和直接偏好优化(DPO),从而创建了DeepSeek Chat模型。
最后,评估结果表明,DeepSeek LLM 67B在各种基准测试中超过了LLaMA-2 70B,特别是在代码、数学和推理领域。此外,开放式评估显示,与GPT-3.5相比,DeepSeek LLM 67B Chat表现出更优越的性能。
模型框架

DeepSeek LLM基本上遵循LLaMA的设计,采用Pre-Norm结构,并使用RMSNorm函数和SwiGLU作为Feed-Forward Network(FFN)的激活函数,中间层维度为8/3 。它还集成了RoPE。为了优化推理成本,67B模型使用分组查询注意力(GQA)而不是传统的多头注意力(MHA)。
在宏观设计方面,DeepSeek LLM略有不同。DeepSeek LLM 7B是一个30层的网络,DeepSeek LLM 67B有95层。这些层调整在保持与其他开源模型参数一致的同时,也有助于优化训练和推理的模型管道划分。
与大多数使用分组查询注意力(GQA)的模型不同,deepseek扩大了67B模型的参数网络深度,而不是常见的拓宽FFN层中间宽度的做法,旨在获得更好的性能。详细的网络规格可以在上表中找到。
另外作者对比了学习率Multi-Step和Cosin decay的方案,发现两者在最终的表现相差不大,但是在保持模型大小不变的情况下调整训练规模,Multi-Step的方式允许第一阶段的训练重复使用,为连续训练提供了便利。因此,作者选择了多步学习速率调度器作为默认设置。为了平衡持续训练中的重用率和模型性能,作者选择了 80% ,10% 和 10% 的三个阶段训练。

Scalling Laws
关于缩放定律的研究早于大型语言模型的涌现。缩放定律表明,随着计算预算(C)、模型规模(N)和数据规模(D)的增加,模型性能可以得到可预测的改善。当模型规模由模型参数表示,数据规模由token数表示时,C可以近似为 = 6ND。
为了降低实验成本和拟合难度,采用了Chinchilla中的IsoFLOP profile方法来拟合缩放曲线。为了更准确地表示模型规模,采用了一种新的模型规模表示方法,即非嵌入FLOPs/token-M,替换了先前使用的模型参数N,并将近似计算预算公式C = 6ND替换为更精确的C = MD。实验结果提供了关于最佳模型/数据扩展分配策略和性能预测的见解,并准确地预测了DeepSeek LLM 7B和67B模型的预期性能。

Alignment
收集了大约 150 万个中英文数据,涵盖了范围广泛且无害的主题。有用数据包含 120 万个实例,其中 31.2% 用于一般语言任务,46.6% 用于数学问题,22.2% 用于编码练习。安全数据由 300K 实例组成,涵盖各种敏感主题。
整体对齐流程包含两个阶段。
- SFT:对7B模型进行了4个epoch的微调,但对67B模型只进行了2个epoch的微调,因为观察到67B模型存在严重的过拟合问题。GSM8K和HumanEval在7B模型上得到了持续改进,而67B模型很快达到了上限。7B和67B模型的学习率分别为1e-5和5e-6。
- DPO:为了进一步提高模型的能力,作者使用了DPO算法,该算法被证明是一种简单而有效的LLM对齐方法。根据有用性和无害性构建了DPO训练所需的偏好数据。对于有用性数据,收集了多语言提示,涵盖了创意写作、问答、指令跟随等类别。然后,使用DeepSeek Chat模型作为候选响应生成响应。类似的操作也应用于无害性偏好数据构建。
模型评估
由于模型评估表格很多,这里直接用图大概看下DeepSeek LLM模型的表现

DeepSeek Math
Github:
这部分主要介绍了强化部分将PPO改进为GRPO
详细可以参考 :
DeepSeek MoE
DeepSeek V2
Github:
背景补充
这一节主要将回顾一下一些基础知识,因为DeepSeek-V2的主要创新点在:
- MLA,即Multi Latent Attention,对传统多头注意力(Multi Head Attention)的改进,降低KV Cache开销。
- DeepseekMOE,改进了传统MOE结构。
所以,这一节将回顾KV Cache和传统MOE结构的基本原理。
KV Cache
KV Cache是大模型标配的推理加速功能,也是推理过程中,显存资源巨大开销的元凶之一。在模型推理时,KV Cache在显存占用量可达30%以上。

目前大部分针对KV Cache的优化工作,主要集中在工程上。比如著名的VLLM,基于paged Attention,最大限度地利用碎片化显存空间,从而提升了空间利用率。
但是这些方案并没有从根本上改变KV Cache占用空间巨大的问题。
我们先来看看KV Cache的基本原理,然后在文章后面详细介绍DeepSeek MLA机制时,再来看DeepSeek-V2是怎么解决这个问题的。
KV Cache基本原理
如果不熟悉Transformer 的生成过程,这部分推荐看看国外博主Jay Alammar的这篇文章:
🔖 https://jalammar.github.io/illustrated-gpt2/
我们先回到Transformer计算Attention的公式,
Attention(Q,K,V)=softmax(QKTdk)V
大模型的推理是一个自回归的过程,即一个从头到尾逐步生成的过程。下一步的输出,取决于上一步。
假如我们需要输出Robot must obey orders这四个字。

模型生成第一步Robot时,会接收一个特殊字符,作为第一步的输入,然后输出Robot。接着将“ Robot”作为第二步的输入,生成must,以此类推,直到模型输出遇到最大长度限制,或者输出了停止字符,则停止输出过程。
我们来模拟一个输出过程中每一步全局的Masked Attention的计算过程。这里公式中忽略了 \(\sqrt{d_k}\) 以便展示。

每一行代表一个查询向量与所有键向量的点积,但由于掩码的存在,每个查询只能访问它自己和之前的键(因果关系)。毕竟在生成的过程中,是不能看到后续的值的。
最后输出的softmax结果大概如下:

然后再将这个softmax结果,和对应的V值进行计算。在这个过程中,上面的矩阵计算,四行的Attention拆解下来如下,
我们可以发现这么一些规律:
- 每一个 \(Att_n\) 的计算,只取决于当前步的 \(Q_n\),不需要以前的 $Q
$。 - 之前的 \(K\) 和\(V\),在后面会被重复利用。
那么这里就很清楚了,随着生成序列的增加,计算Attention的增多,前面步骤的K和V都需要参与后续的计算。
所以我们如果将之前的K和V都存储下来,就不用在当前这一步,再重新生成计算一次以前生成过的K和V。这就是KV Cache。一种空间换时间的做法。
所以可以看出,随着序列增长,需要存储的K和V逐渐增多,因此推理中产生的开销也会越大。
Multiple Latent Attention (MLA)
说完了背景知识,KV Cache和MOE,以及它们存在的一些问题。
我们可以来看看DeepSeek-V2对上述两个核心部分到底做了哪些改进。

MLA是对传统多头注意力做的改进,其目的有两个:
- 降低推理过程中的KV Cache资源开销。
- 缓解MQA、MGA对性能的损耗。
首先来说第一点,之前介绍KV Cache中,提到每一步都需要将K和V缓存下来。假设单个Attention Block块中的多头注意力,有 \(n_h\) 个头,每个k和v的维度为\(d_h\),则每一步需要缓存的参数量为\(2n_hd_hl\),\(l\)为block的块数。
因此,MLA立足于在推理中,降低\(n_hd_h\)。对Key和Value进行了一个低秩联合压缩。
简单理解就是,假设有个矩阵的维度是\(n*n\),那么可以将其分解为两个 \(n*d\) 的矩阵相乘,而\(d≪n\) 。这样就降低了存储量。
具体来看看DeepSeek中的具体实现公式:
- \({c}_{t}^{K V}\in R^{d_c}\) 是对Key和Value压缩后的隐向量,通过一个降维映射矩阵 \(W^{DKV}\) 和模型输入 \(h_t\) 得到。\(c_t\) 的维度 \(d_c\),远小于多头key和value的原始维度 \(n_hd_h\)。
- 得到这个 \(c_t\) 后,具体的key和value,由两个对应的升维矩阵 \(W^{U K}\) 和 \(W^{U V}\) 还原。
在推理的过程中,只需要缓存每一步的\({c}_{t}^{K V}\),然后再计算还原回原始的 \(K\) 和 \(V\) 即可。由于 \(c_t\) 的维度远小于\(K\)、\(V\)。因此每一步token的推理产生的缓存由之前的\(2n_hd_hl\),变成\(d_cl\)。
💡 这里其实原文也提到了,在推理的过程中,其实不需要显示的计算 \(\mathbf{k}_{t}^{C}\)和 \(\mathbf{v}_{t}^{C}\),因为在做Attention时,$W^{U K} $ 会被 \(W^Q\)吸收掉,\(W^{UV}\) 会被\(W^O\)吸收掉,具体来说,
另外,之前提到KV Cache中,\(Q\)的作用只发生在当下,但是在模型训练的过程中,每个输入的token会通过多头注意力机制生成对应的query、key和value。这些中间数据的维度往往非常高,因此占用的内存量也相应很大。所以论文中也提到,为了降低训练过程中的激活内存activation memory,DeepSeek-V2还对queries进行低秩压缩,即便这并不能降低KV Cache。
对Q的压缩方式和K、V一致。
位置编码解耦
从架构图中发现,DeepSeek-V2的 \(q\) 和 \(k\) 各自都有2个部分。1个部分是刚刚解释过的压缩部分,而另外的1个部分,加上了RoPE位置编码。做了一个位置编码的解耦。
在RoPE的实现中,如果我们要让Q、K带上位置信息, 位置编码是通过复数旋转实现的。对于位置 \(m\) 的token,其Query和Key的计算变为: