LLM
什么是 token?
LoRA (Low-Rank Adaptation)
Encoder-Decoder / Encoder-Only / Decoder-Only
现在的 LLM 其实都没有 Encoder 了,因为都是 Decoder-Only 架构的:当前的 ChatGPT、DeepSeek-V3、Gemini、Grok 和 Claude 等模型,均采用 Decoder-only 架构。
Encoder-Only 架构,也被称为单向架构,仅包含编码器部分。它主要适用于不需要生成序列的任务,只需要对输入进行编码和处理的单向任务场景,如文本分类、情感分析等。这种架构的代表是 BERT 相关的模型,例如 BERT、RoBERT 和 ALBERT 等。
Decoder-Only 架构,也被称为生成式架构,仅包含解码器部分。它通常用于序列生成任务,如文本生成、机器翻译等。这种架构的模型适用于需要生成序列的任务,可以从输入的编码中生成相应的序列。同时,Decoder-Only 架构还有一个重要特点是可以进行无监督预训练。在预训练阶段,模型通过大量的无标注数据学习语言的统计模式和语义信息。Decoder-Only 架构的优点是擅长创造性的写作,比如写小说或自动生成文章。它更多关注于从已有的信息(开头)扩展出新的内容。
对于 LLM,首先排除 encoder-only,原因主要有两点:
- 生成能力天生不足;
- 繁琐的任务头不够优雅;
抛开 encoder-only 之后,现在只剩下 encoder-decoder 与 decoder-only 之争了。个人感觉其实这俩之间没啥好纠结的,大道至简的哲学告诉我,无脑选 decoder-only!
【OpenLLM 001】大模型的基石-架构之争,decoder is all you need? - 知乎
SGLang / vLLM
都是伯克利团队开发的。
是和 vLLM 在同一个身位竞争的,也就是大模型服务(Serving)框架。
SGLang 更新,性能更好。
- vLLM:适合高并发场景,如在线客服、实时翻译等需要实时响应和处理大量并发请求的应用。
- SGLang:更适合多轮对话、推理任务和多模态输入等复杂场景,以及需要处理复杂逻辑和多步骤任务的应用。
MTP (Multi-Token Prediction)
次预测多个未来 Token。
什么是 LLM Agent?
LLM Agent 是一种基于大语言模型(如 GPT、PaLM、LLaMA 等)构建的智能系统,能够自主理解目标、规划任务、调用工具并完成复杂操作。它不仅是“生成文本的模型”,更是一个具备推理、决策和行动能力的智能代理,可类比为“能主动思考和行动的 AI 助手”。
和强化学习里的 Agent 是不一样的。
Dense / Sparse 模型
给定一个输入,如果模型的所有参数都参与了计算,那么这就是 dense 稠密模型。反之,如果模型只有部分参数用于处理输入。那就是 sparse 稀疏模型。举例来说。稀疏模型里有稀疏专家模型。这类模型的参数被划分为好几个专家。对于一个输入,只有最适合这个输入的专家将会参与计算,这就是稀疏计算。
Dense 模型一般比较小,一般单机或者说单卡都可以跑。
深度学习中的sparse和dense模型指的是什么? - 知乎
算子优化/加速库和项目
算子实际上是面向深度学习任务高度优化的函数,它是网络中层或者节点的计算逻辑,开发者在实现这些计算逻辑的时候,不仅要实现功能逻辑,还要考虑硬件指令的适配,如何支持不同大小/类型的输入,以及如何针对不同的输入 Shape 进行切分,并保证算子的运行性能。可见,一个算子的代码如此复杂,如果神经网络中的每一个算子都由开发人员实现一遍,那么可想而知,神经网络构建的工作量有多大,难度有多高,特别是面对当前日益复杂的大模型。能否针对某种计算逻辑开发一个通用实现?这样,开发者便像搭房子一样构建网络而无需关注具体的算子实现。
FlashAttention: Dao-AILab/flash-attention: Fast and memory-efficient exact attention
- FlashAttention 属于开源的算子优化项目之一,它主要针对 Transformer 模型中的注意力机制进行优化。本来是一篇论文,是一个新的 attention 算法,能够减小内存压力。
FasterTransformer: NVIDIA/FasterTransformer: Transformer related optimization, including BERT, GPT
- FasterTransformer 是一个用于加速 Transformer 模型推理的开源库。它提供了高度优化的 Transformer 编码器和解码器组件,支持多种模型和精度,包括 FP16、INT8 等。
TensorRT-LLM: NVIDIA/TensorRT-LLM at release/0.5.0
- TensorRT 是一个用于在 NVIDIA GPU 上进行高性能深度学习推理的开源 SDK。它通过优化神经网络模型,提供低延迟和高吞吐量的推理性能,适用于生产环境中的 AI 应用。
什么是 context caching
什么是模型蒸馏?
是一种模型压缩技术。旨在把一个大模型或者多个模型(教师模型) ensemble 学到的知识迁移到另一个轻量级单模型(学生模型)上,方便部署。简单的说就是用新的小模型去学习大模型的预测结果,改变一下目标函数。听起来是不难,但在实践中小模型真的能拟合那么好吗?所以还是要多看看别人家的实验,掌握一些 trick。应用场景:
- 模型压缩与加速:在计算资源有限的情况下,例如移动设备和边缘计算,知识蒸馏可以用于将大模型转化为可以在资源受限的环境中高效运行的小模型。
- 实时推理:对于需要实时响应的应用(如视频监控、自动驾驶等),知识蒸馏可以使得模型在保持较高准确率的同时,减小延迟。
- 迁移学习:在迁移学习场景中,知识蒸馏可以帮助将源领域的知识迁移到目标领域,特别是在目标领域样本稀缺的情况下。
- 多模态学习:在多模态任务中,可以通过知识蒸馏将不同模态下训练得到的知识进行融合,提高模型的综合性能。
- 模型集成:通过将多个模型的知识进行蒸馏,可以在不增加计算复杂度的情况下,继承多个模型的优点,从而提升整体性能。
RAGs(检索增强生成, Retrieval-Augmented Generation)
In-context learning
单机单卡、单机多卡以及多机多卡的业务场景
MoE 架构需要用到多机?
flash-attention
什么是 KV Cache
KV Cache 是 token 级的,一个 token 对应一个 KV Cache。不过推理引擎中一般是以 Block 的方式来管理 KV Cache 的。一个 Block 可以有几十个 token 的 KV Cache。
KV Cache 只有在 decode 过程才能利用上?Prefill 阶段能够利用上 KV Cache 吗?
KV Cache 在 Prefill 时期和 Decode 时期是不是不一样的,一个是输入 token 的 KV Cache,一个是输出过程中输出 token 的 KV Cache?
我们看一下 decode 时候的公式:
大型语言模型在处理每个请求时都会生成 KV Cache,用于存储对话上下文或中间推理“思考”结果。
生成 KV Cache 非常耗时,其计算复杂度随输入长度平方增长。然而在许多场景下,不同请求间存在重复或相似的上下文,例如相同的系统提示、多轮对话中的上下文复用、或多个代理任务共享部分知识。这就意味着如果能复用之前计算得到的 KV Cache,则无需每次都从零计算,能够显著降低延迟和计算消耗。
使用 KV Cache 加速 decode 阶段的一个例子
从上帝视角来看,假设我们最后 decode 要生成的是“遥遥领先”。当生成第一个“遥”时,attention 计算如下:
input="<s>"
(因为还没有输出过任何内容所以只有一个起始字符)。
( 表示已经按行进行了 softmax)。
当模型生成第二个“遥”字时,input="<s>遥"
, Attention 的计算如下:
假设 表示 Attention 输出的第一行, 表示 Attention 输出的第二行。则根据上面推导,其计算公式为:
第三步:
可以看到在每一步的计算中, 矩阵的右上角部分都是灰色的。这是为什么呢?看起来是每一个 里的每一行(token)在乘到自己的 里的那一列之后就不会再往后算了。这是因为 Decoder 有 Casual Mask,在推理的时候前面已经生成的字符不需要与后面的字符产生 attention,从而使得前面已经计算的 和 可以缓存起来。
KV Cache 的代码实现
if layer_past is not None:
past_key, past_value = layer_past
key = torch.cat((past_key, key), dim=-2)
value = torch.cat((past_value, value), dim=-2)
if use_cache is True:
present = (key, value)
else:
present = None
if self.reorder_and_upcast_attn:
attn_output, attn_weights = self._upcast_and_reordered_attn(query, key, value, attention_mask, head_mask)
else:
attn_output, attn_weights = self._attn(query, key, value, attention_mask, head_mask)
LLM Inference Process Overview
大模型推理阶段分为两个过程,prefill 和 decode:
- prefill 是用户输入完 prompt 到生成首个 token 的过程,
- decode 则为生成首个 token 到推理停止的过程。
Prefill (where large prompt embeddings are generated) is highly compute-intensive, while decode (where tokens are generated) is latency-sensitive.
Prefill 长度和 Decode 长度的区别:可能一个是指用户输入的长度,一个是指回答的长度。如何两者相差太大,PD 分离是一个好的选择。
生成一个新 token 需要用到以前所有 token 的 QKV,
大模型推理阶段KV计算分析:prefill和decode - 知乎
LLM Prefill Phase
是 Inference 中的一个阶段,不要把它当成训练中的阶段。
Prefill and Decode for Concurrent Requests - Optimizing LLM Performance
注意不要弄混 Prefill 和 Encoder,这两个不是同一个东西。很多 LLM 都是 Decoder-Only 架构,是没有 encoder 的,但是都还是有 Prefill 阶段的。
在 prefill 阶段,大模型一次性对 prompt 中所有 token(也就是 sequence) 进行计算 QKV,由于不同 token 的计算是独立的,因此该过程可以并行。在 attention 部分,由计算得到的 QKV 进一步计算出 Output 矩阵,再经过后续的 FFN 层和解码得到首字母 token。
Prompt token 的 KV Cache 是在这里生成的,注意是 prompt token,而不是输出的 token。
这一步是计算密集型的。Prefill 阶段的计算量通常较大,尤其是在处理长提示时。
LLM Decode Phase / KV Cache
Decode 阶段负责根据 Prefill 阶段生成的 KV 缓存,依次解码生成后续输出 token,对内存带宽和缓存依赖更强。Decode 阶段的显存消耗通常较大,因为 KV 缓存会随着生成过程不断增长。
基于当前 token 和历史 KV Cache 以自回归(会进行多轮计算,每一轮计算的输出会作为下一次计算的输入,也就是多轮计算)的方式来逐个生成新的 token,在新生成 token 的过程中,会保存当前 token 的 KV Cache。
在 decode 阶段,计算原理和 prefill 完全相同,但计算方式不一样的。原因有两个。一是随着 seqlen 增加,Attention 计算复杂度平方级增长,直接计算代价很大,导致长序列的推理时间极慢,甚至不可行。二是对 decode 阶段的计算过程简单分析发现,该过程可以复用 prefill 阶段的 KV 结果,也可以复用 docode 阶段已经产生的 KV 结果。综上,可以把已产生的 KV 存起来,不必重新计算,这就是 KV cache。对于 Q 矩阵,每次需要计算的只是 Q 的最后一行 q,计算关于 qKV 的 attention,而不是关于 QKV 的 attention,这样复杂度降低了一个量级,实现以存换算。
Decode 过程输出的 token 的长度是由谁决定的呢?
自回归过程直到满足停止条件:
- 所有 LLM 都有一个硬性限制,即输入 + 输出的总 token 数不能超过其上下文窗口大小。例如:GPT-4 通常为 8k/32k tokens,Llama 3 为 8k tokens。因此,如果输入(prompt)过长,剩余可生成的 token 数会减少。
- 调用生成接口(如 model.generate())时,可通过以下参数显式控制生成长度:
max_new_tokens
,max_length
,min_new_tokens/min_length
。 - …
P/D 分离
传统集成式推理流水线往往将 LLM 的 Prefill 和 Decode 阶段置于同一 GPU 上运行,资源需求不匹配导致 GPU 利用率不高。在推理服务中,如果用户请求 prefill 长度和 decode 长度非常不匹配,PD 分离是一个很好的选择。这项技术是由 DistServe 和 Splitwise 等 paper 提出来的。