简要介绍

1 Model

1.1 Rope

一种Transformer的position注入方案。Transformer本身是不感知输入序列token顺序的,原版transformer需要positional embedding引入位置信息,这种方案要求infer时序列的长度不能大于训练时,而LLM需要进行长度外推。

Rope认为好的postional机制应该满足:1.attention值和相对位置有正相关关系;2.对attention值的影响和相对位置(两个token的位置之差有关),但对Q和K的modify只和绝对位置有关(这样modify才是可复用的)。

Rope的解决方案是:根据绝对位置n,将Q和K旋转n倍theta角

1.2 MQA/GQA/MLA

MHA计算太复杂了,需要一些简化;KV-cache存储空间太大,长序列显存不够用了。因为Q是用过即抛的,所以压缩都集中在KV上。

MQA:K和V只用一个head,大幅降低了kv-cache存储。

GQA:MQA走得太远了,折中一下(KV多于1个,Q-head数量的几分之一)。

MLA:把经典的low-rank省空间/算力加入进来(类似lora、matrix-factorization、LDA、Glove等等),hidden-state先映射到Q和KV的两个相对低维的latent空间,再通过矩阵升维升上来。这样kv-cache只保留一份kv共享latent向量就可以了;并且K的升维矩阵可以被Q吸收,直接在latent空间做attention。这里为了兼容Rope,在实现上保留了一部分MHA的部分去apply-rope。

1.3 MoE

保持激活参数不变、扩大总参数量的一种方法;同时影响了训练过程中的显存、算力消耗关系。

在Transformer层中,Attention后面有一个 MLP(Activation(MLP(X)))操作。这里的MLP是multi-layer-perceptron,就是乘一个矩阵。LLM-MoE把这里修改为,有N个可选MLP和少量必选MLP,通过router根据当前hidden从N中选择少数几个可选MLP与必选MLP分别乘以hidden,再把运算结果求和作为输出。

通过控制实际选择MLP和必选MLP的数量,可以有效控制激活参数量;增加可选MLP可以扩大LLM的总参数量。

2 Inference

2.1 Dynamic Batching

LLM处理请求时会将一个时间窗口内的多个请求组和起来统一运算(batching),这样可以利用GPU上较多的计算单元(SIMD),提高吞吐量。优于LLM给batch中每个request生成多少个新token是无法提前知道的,因此一个batch部分完成时存在算力浪费。

2.2 Dynamic Batching

将组batch的控制级别从request级别下降到token(也称为iteration)级别,使新到的request马上就可以得到处理,解码完成的request马上就可以构造response发给client,降低了latency;同时解决了上述batch部分完成时的算力浪费问题,提高了算力利用率和吞吐量。为了在iteration级别对batch内容进行调整,request之间差异较大的attention计算不进行batch计算,实际对效率影响很小。

2.3 Paged Attention

KV-cache因为要参与矩阵运算,因此一般用一个Tensor存储,Tensor这个数据类型决定了其在显存中是连续的;此外,KV-cache是通过估计将要生成的长度预分配的。

这导致了三重浪费:1.多次申请整块内存导致碎片化;2.预估时多估计了;3.KV预分配显存的尾部,即使最后用到了,在整个解码过程的大部分时间中这部分显存是浪费了的。

PagedAttention打破了KV-cache在显存空间必须连续的前提,利用操作系统中经典的内存page方案,在server启动时直接申请一整块显存自己管理,按需按block申请,解决了上述三重浪费,大幅提高了吞吐量。此外,在n-sampling/beam-search等场景下,存在基于request-id的prefix-kv-cache共享。

2.4 Radix-Tree prefix caching

sglang提出。LLM请求通常有一个很长的共享prompt,因此跨request也有很高的kv-cache复用空间。sglang用一棵内存上的radix-tree基于请求的文本内容管理kv-cache,实现了跨request复用。

radix-tree是一种边是字符串的trie树,prefix查询效率非常高。

显存满时,通过LRU淘汰已有内容的kv-cache块。

2.5 PD分离

LLM推理时,prefix是固定的prompt拼接用户的输入,这部分一次性拿到了大量token,运算特点类似于bert/encoder/LLM-train,称为prefix-filling;在实际生成回复时,整个LLM走一遍只能解码出一个token,运算特点类似于decoder,称为decoding阶段。因为这两个阶段的负载特点存在显著差异(尤其是prefix长度非常大时,比如一些宣传超长context的功能),所以针对这两种负载的特性分别开发inference-engine并部署在不同的机器上可以提高算力利用率。

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

0%