534
社区成员




产品形态
计算设备:
内存开销巨大:
动态shape
相对视觉模型, LLM结构简单
设备:
推理(这里是指模型的执行过程, 非服务过程):
服务:
技术点:
方案:
云端:
移动端:
是LLM在NVIDIA 设备商不熟的全流程解决方案
包括模型轻量化, 推理(核心是turbomind c++)和服务
性能提升
显存降下来
能容纳更多的长度, 并发
24GB显存
量化前, 7B模型 并发8, max length=2k
量化后, 7B模型 并发8, max length=8k
80GB显存
量化前, 70B模型 oom
量化后, 7B模型 并发8, max length=32k
LLM主要是 访存密集型
先量化成 4bit存起来, 计算时再反量化回FP16
LLM 推理时主流的策略(Decoder 模型)
server端(推理端)一直保存着上下文
支持 Paged Attention, 支撑有状态推理
K part V part 需要缓存起来, 整个过程是要用的
Block状态:
深入优化里面的计算算子(Flash Attention2; Split-K decoding; 高效的 w4a16,kv8 反量化 kernel)
针对解码 生成加速
models completions interaction
安装, 部署, 量化
环境配置
我们把从架构上把整个服务流程分成下面几个模块。
使用 TurboMind 推理模型需要先将模型转化为 TurboMind 的格式,目前支持在线转换和离线转换两种形式。在线转换可以直接加载 Huggingface 模型,离线转换需需要先保存模型再加载。
TurboMind 是一款关于 LLM 推理的高效推理引擎,基于英伟达的 FasterTransformer 研发而成。它的主要功能包括:LLaMa 结构模型的支持,persistent batch 推理模式和可扩展的 KV 缓存管理器
lmdeploy 支持直接读取 Huggingface 模型权重,目前共支持三种类型:
以下命令都会启动一个本地对话界面,通过 Bash 可以与 LLM 进行对话
示例:
# 需要能访问 Huggingface 的网络环境
# 直接加载 Huggingface 的模型
# 1. 加载使用 lmdeploy 量化的版本
lmdeploy chat turbomind internlm/internlm-chat-20b-4bit --model-name internlm-chat-20b
# 2. 加载其他 LLM 模型
lmdeploy chat turbomind Qwen/Qwen-7B-Chat --model-name qwen-7b
也可以直接启动本地的 Huggingface 模型
lmdeploy chat turbomind /share/temp/model_repos/internlm-chat-7b/ --model-name internlm-chat-7b
离线转换需要在启动服务之前,将模型转为 lmdeploy TurboMind 的格式,如下所示
# 转换模型(FastTransformer格式) TurboMind
lmdeploy convert internlm-chat-7b /path/to/internlm-chat-7b
# 这里我们使用官方提供的模型文件,就在用户根目录执行,如下所示
lmdeploy convert internlm-chat-7b /root/share/temp/model_repos/internlm-chat-7b/
执行完成后将会在当前目录生成一个 workspace 的文件夹.
这里面包含的就是 TurboMind 和 Triton “模型推理”需要到的文件
重要的是weights文件
weights 和 tokenizer 目录分别放的是拆分后的参数和 Tokenizer.
如果我们进一步查看 weights 的目录,就会发现参数是按层和模块拆开的
每一份参数第一个 0 表示“层”的索引,后面的那个0表示 Tensor 并行的索引,因为我们只有一张卡,所以被拆分成 1 份。如果有两张卡可以用来推理,则会生成0和1两份,也就是说,会把同一个参数拆成两份
layers.0.attention.w_qkv.0.weight 会变成 layers.0.attention.w_qkv.0.weight 和 layers.0.attention.w_qkv.1.weight。执行 lmdeploy convert 命令时,可以通过 --tp 指定(tp 表示 tensor parallel),该参数默认值为1(也就是一张卡)
就是把一个大的张量(参数)分到多张卡上,分别计算各部分的结果,然后再同步汇总
模型转换完成后,我们就具备了使用模型推理的条件,接下来就可以进行真正的模型推理环节
本地对话(Bash Local Chat) 在这里其实是跳过 API Server 直接调用 TurboMind, 简单来说,就是命令行代码直接执行 TurboMind。所以说,实际和前面的架构图是有区别的.
lmdeploy chat turbomind ./workspace
可以进入对话在上面的部分尝试了直接用命令行启动 Client,接下来尝试如何运用 lmdepoy 进行服务化
"模型推理/服务"目前提供了 Turbomind 和 TritonServer 两种服务化方式。
此时,Server 是 TurboMind 或 TritonServer,API Server 可以提供对外的 API 服务。推荐使用 TurboMind
# ApiServer+Turbomind api_server => AsyncEngine => TurboMind
lmdeploy serve api_server ./workspace \
--server_name 0.0.0.0 \
--server_port 23333 \
--instance_num 64 \
--tp 1
上面的参数中 server_name 和 server_port 分别表示服务地址和端口,tp 参数我们之前已经提到过了,表示 Tensor 并行。还剩下一个 instance_num 参数,表示实例数,可以理解成 Batch 的大小
可以新开一个窗口,执行下面的 Client 命令。如果使用官方机器,可以打开 vscode 的 Terminal,执行下面的命令
# ChatApiClient+ApiServer(注意是http协议,需要加http)
lmdeploy serve api_client http://localhost:23333
将 Gradio 作为前端 Demo 演示。在上一节的基础上,我们不执行后面的 api_client 或 triton_client,而是执行 gradio
由于 Gradio 需要本地访问展示界面,因此也需要通过 ssh 将数据转发到本地。命令如下:
ssh -CNg -L 6006:127.0.0.1:6006 root@ssh.intern-ai.org.cn -p <你的 ssh 端口号>
API Server 的启动和上一节一样,这里直接启动作为前端的 Gradio
# Gradio+ApiServer。必须先开启 Server,此时 Gradio 为 Client
lmdeploy serve gradio http://0.0.0.0:23333 \
--server_name 0.0.0.0 \
--server_port 6006 \
--restful_api True
Gradio 也可以直接和 TurboMind 连接
# Gradio+Turbomind(local)
lmdeploy serve gradio ./workspace
可以直接启动 Gradio,此时没有 API Server,TurboMind 直接与 Gradio 通信
前面介绍的都是通过 API 或某种前端与”模型推理/服务“进行交互,lmdeploy 还支持 Python 直接与 TurboMind 进行交互
“模型推理/服务”,推荐使用 TurboMind,使用简单,性能良好,相关的 Benchmark 对比如下
上面的性能对比包括两个场景:
LMDeploy应该是Transformers的3-5倍左右。
后面的 API 服务和 Client 就得分场景了
# weights/config.ini
tensor_para_size = 1
session_len = 2056
max_batch_size = 64 # 在 API Server 启动时的 instance_num 参数, 吞度量越大(同时接受的请求数),但也会占用更多显存
max_context_token_num = 1
step_length = 1
cache_max_entry_count = 0.5
cache_block_seq_len = 128
cache_chunk_size = 1
use_context_fmha = 1
quant_policy = 0 # KV int8开关 4
max_position_embeddings = 2048
rope_scaling_factor = 0.0 # 外推能力开关
use_logn_attn = 0 # Attention 缩放 外推能力
外推能力开关
rope_scaling_factor 默认值为 0.0,表示不具备外推能力,设置为 1.0,可以开启 RoPE 的 Dynamic NTK 功能,支持长文本推理
use_logn_attn 参数表示 Attention 缩放,默认值为 0,如果要开启,可以将其改为 1。
主要介绍如何对模型进行量化. KV Cache 量化和 4bit Weight Only 量化(W4A16)
主要包括 KV Cache 量化和 模型参数量化. 总的来说,量化是一种以参数或计算中间结果精度下降换空间节省(以及同时带来的性能提升)的策略.
常见的 LLM 模型由于 Decoder Only 架构的特性,实际推理时大多数的时间都消耗在了逐 Token 生成阶段(Decoding 阶段),是典型的访存密集型场景
KV Cache 量化是将已经生成序列的 KV 变成 Int8,使用过程一共包括三步:
# 计算 minmax lmdeploy lite calibrate \ --model /root/share/temp/model_repos/internlm-chat-7b/ \ --calib_dataset "c4" \ --calib_samples 128 \ --calib_seqlen 2048 \ --work_dir ./quant_output
python zp = (min+max) / 2 scale = (max-min) / 255 quant: q = round( (f-zp) / scale) # 量化 dequant: f = q * scale + zp # 反量化
python
W4A16中的 A 是指Activation,保持FP16,只对参数进行 4bit 量化。使用过程也可以看作是三步
第一步:同 1.3.1,不再赘述
第二步:量化权重模型。利用第一步得到的统计值对参数进行量化,具体又包括两小步:
缩放参数。主要是性能上的考虑(回顾 PPT)。
整体量化
最后一步:转换成 TurboMind 格式
服务部署和量化是没有直接关联的,量化的最主要目的是降低显存占用,主要包括两方面的显存:模型参数和中间过程计算结果。前者对应《3.2 W4A16 量化》,后者对应《3.1 KV Cache 量化》
量化在降低显存的同时,一般还能带来性能的提升,因为更小精度的浮点数要比高精度的浮点数计算效率高,而整型要比浮点数高很多.
建议是:在各种配置下尝试,看效果能否满足需要。这一般需要在自己的数据集上进行测试