InternLM Training - Lec5

InternLM Training - Lec5

Jan 15, 2024

第五节:LMDeploy 大模型量化部署实践

by HuggingLLM 开源项目负责人 长琴

文档 视频

算力平台ID: 25940

模型部署

将训练好的模型在特定软硬件环境中启动的过程,使模型能够接收输入并返回预测结果

  • 为了满足性能和效率的需求,常常需要对模型进行优化,例如模型压缩和硬件加速

  • 云端、边缘计算端、移动端

  • CPU、 GPU、 NPU、 TPU 等

LMDeploy

LMDeploy 是 LLM 在英伟达设备上部署的全流程解决方案。包括模型轻量化、推理和服务。

written in Python & C++

量化

Weight FP16 + KV Cache FP16 vs Weight INT4 + KV Cache INT8

量化是一种以参数或计算中间结果精度下降换空间节省(以及同时带来的性能提升)的策略。

  • 计算密集 (compute-bound):推理的绝大部分时间消耗在数值计算上;针对计算密集场景,可以通过使用更快的硬件计算单元来提升计算速度,比如量化为 W8A8 使用 INT9 Tensor Core 来加速计算。

  • 访存密集(memory-bound):推理时,绝大部分时间消耗在数据读取上;针对访存密集型场景,一般是通过提高计算访存比来提升性能。

    • 常见的 LLM 模型是 Decoder Only 架构。推理时大部分时间消耗在逐Token 生成阶段(Decoding 阶段),是典型的访存密集型场景。

KV Cache量化

在生成token时,需要历史key/value信息计算attention,可以将生成过程中的上下文 K 和 V 中间结果进行 INT8 量化,在使用时再反量化

  • 计算minimax:给定输入样本在每一层不同位置处计算结果的统计情况

    • 对于 Attention 的 K 和 V:取每个 Head 各自维度在所有Token的最大、最小和绝对值最大值。对每一层来说,上面三组值都是 (num_heads, head_dim) 的矩阵。这里的统计结果将用于本小节的 KV Cache。

    • 对于模型每层的输入:取对应维度的最大、最小、均值、绝对值最大和绝对值均值。每一层每个位置的输入都有对应的统计值,它们大多是 (hidden_dim, ) 的一维向量,当然在 FFN 层由于结构是先变宽后恢复,因此恢复的位置维度并不相同。这里的统计结果用于下个小节的模型参数量化,主要用在缩放环节(回顾PPT内容)。

# 计算 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
  • 通过 minmax 获取量化参数:获取每一层的 K V 中心值(zp)和缩放值(scale)

zp = (min+max) / 2
scale = (max-min) / 255
quant: q = round( (f-zp) / scale)
dequant: f = q * scale + zp

# 通过 minmax 获取量化参数
lmdeploy lite kv_qparams \
  --work_dir ./quant_output  \
  --turbomind_dir workspace/triton_models/weights/ \
  --kv_sym False \
  --num_tp 1
  • 修改 ./workspace/triton_models/weights/config.ini 文件中KV int8 开关,对应参数为quant_policy

    默认值为 0,表示不使用 KV Cache,如果需要开启,则将该参数设置为 4。


Weight Only量化(W4A16量化)

W4A16中的A是指Activation,保持FP16,只对参数进行 4bit 量化。

  • LMDeploy 使用 MIT HAN LAB 开源的 AWQ 算法,量化为 4bit 模型【尽量不量化矩阵或张量计算时的小部分重要参数】

  • 推理时,先把 4bit 权重反量化回 FP16(在 Kernel 内部进行,从Global Memory 读取时仍是 4bit),依旧使用的是 FP16 计算

  • 相较于社区使用比较多的 GPTQ 算法,AWQ 的推理速度更快,量化的时间更短

# 量化权重模型
lmdeploy lite auto_awq \
  --model  /root/share/temp/model_repos/internlm-chat-7b/ \
  --w_bits 4 \
  --w_group_size 128 \
  --work_dir ./quant_output 

# 转换模型的layout,存放在默认路径 ./workspace 
lmdeploy convert  internlm-chat-7b ./quant_output \
    --model-format awq \
    --group-size 128

推理引擎TurboMind

TurboMind 是一款关于 LLM 推理的高效推理引擎,基于英伟达的 FasterTransformer 研发而成。它的主要功能包括:LLaMa 结构模型的支持,persistent batch 推理模式和可扩展的 KV 缓存管理器。

  • continuous batch:请求及时加入、及时退出

    • Persistent线程,请求队列 + Batch Slots

    • 若 batch 中有空闲槽位,从队列拉取请求,尽量填满空闲槽位。若无,继续对当前 batch 中的请求进行forward

    • Batch每forward完一次,判断是否有request 推理结束。对于结束的request,发送结果,释放槽位

  • 有状态推理:server端存储历史对话记录

  • Blocked k/v cache

推理服务API Server


实践

pip install 'lmdeploy[all]==v0.1.0'

默认安装的是 runtime 依赖包,但这里还需要部署和量化,所以选择 [all]

使用 TurboMind 推理模型需要先将模型转化为 TurboMind 格式,目前支持在线转换和离线转换两种形式。在线转换可以直接加载 Huggingface 模型,离线转换需要先保存模型再加载。


”模型推理/服务“目前提供了 Turbomind 和 TritonServer 两种服务化方式。此时,Server 是 TurboMind 或 TritonServer,API Server 可以提供对外的 API 服务。

作业

基础作业

  • 使用 LMDeploy 以本地对话、网页Gradio、API服务中的一种方式部署 InternLM-Chat-7B 模型,生成 300 字的小故事(需截图)

    lmdeploy convert internlm-chat-7b /root/data/model/Shanghai_AI_Laboratory/internlm-chat-7b/
    # 执行完成后将会在当前目录生成一个 workspace 的文件夹
    lmdeploy chat turbomind ./workspace
lmdeploy serve api_server ./workspace \
	--server_name 0.0.0.0 \
	--server_port 23333 \
	--instance_num 64 \
	--tp 1
lmdeploy serve api_client http://localhost:23333
lmdeploy serve gradio http://0.0.0.0:23333 \
	--server_name 0.0.0.0 \
	--server_port 6006 \
	--restful_api True
lmdeploy serve gradio ./workspace

Python 直接与 TurboMind 进行交互,如下所示。

from lmdeploy import turbomind as tm

# load model
model_path = "/root/share/temp/model_repos/internlm-chat-7b/"
tm_model = tm.TurboMind.from_pretrained(model_path, model_name='internlm-chat-7b')
generator = tm_model.create_instance()

# process query
query = "hello"
prompt = tm_model.model.get_prompt(query)
input_ids = tm_model.tokenizer.encode(prompt)

# inference
for outputs in generator.stream_infer(
        session_id=0,
        input_ids=[input_ids]):
    res, tokens = outputs[0]

response = tm_model.tokenizer.decode(res.tolist())
print(response)

进阶作业(可选做)

  • 将第四节课训练自我认知小助手模型使用 LMDeploy 量化部署到 OpenXLab 平台。

  • 对internlm-chat-7b模型进行量化,并同时使用KV Cache量化,使用量化后的模型完成API服务的部署,分别对比模型量化前后(将 bs设置为 1 和 max len 设置为512)和 KV Cache 量化前后(将 bs设置为 8 和 max len 设置为2048)的显存大小。

    • 模型量化前后对比

      • 模型量化前

        • lmdeploy convert internlm-chat-7b /root/data/model/Shanghai_AI_Laboratory/interlm-chat-7b

        • 得到workspace文件夹,配置./workspace/triton_models/weights/config.ini中session_len=512

        • lmdeploy serve api-server ./workspace/ --server_name 0.0.0.0 --server_port 23333 --instance_num 1 --tp 1

      • 量化模型

        • 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

        • lmdeploy lite auto_awq \ --model /root/share/temp/model_repos/internlm-chat-7b/ \ --w_bits 4 \ --w_group_size 128 \ --work_dir ./quant_output

        • lmdeploy convert internlm-chat-7b ./quant_output \

          --model-format awq \

          --group-size 128 \

          --dst_path ./workspace_quant

      • 模型量化后

        • 配置workspace_quant/triton_models/weights/config.ini中session_len=512

        • lmdeploy serve api-server ./workspace_quant/ --server_name 0.0.0.0 --server_port 23333 --instance_num 1 --tp 1

    • KV量化前

      • 配置workspace_quant/triton_models/weights/config.ini中session_len=2048

      • lmdeploy serve api-server ./workspace_quant/ --server_name 0.0.0.0 --server_port 23333 --instance_num 8 --tp 1

    • KV量化后

      • lmdeploy lite kv_qparams \ --work_dir ./quant_output \ --turbomind_dir workspace_quant/triton_models/weights/ \ --kv_sym False \ --num_tp 1

      • 配置workspace_quant/triton_models/weights/config.ini中quant_policy = 4

      • lmdeploy serve api-server ./workspace_quant/ --server_name 0.0.0.0 --server_port 23333 --instance_num 8 --tp 1

  • 在自己的任务数据集上任取若干条进行Benchmark测试,测试方向包括:
    (1)TurboMind推理+Python代码集成
    (2)在(1)的基础上采用W4A16量化
    (3)在(1)的基础上开启KV Cache量化
    (4)在(2)的基础上开启KV Cache量化
    (5)使用Huggingface推理