Skip to content

Latest commit

 

History

History
477 lines (350 loc) · 14.4 KB

L2 G3000.md

File metadata and controls

477 lines (350 loc) · 14.4 KB

LMDeploy 部署与量化

1. 配环境

可以复用 L2 G4000 创建的 lmdeploy 环境,可以顺利运行。

2. 部署

第一,运行下面的指令,启动API服务器:

lmdeploy serve api_server \
    /root/models/internlm2_5-7b-chat \
    --model-format hf \
    --quant-policy 0 \
    --server-name 0.0.0.0 \
    --server-port 23333 \
    --tp 1

image

第二,执行下面的指令,在终端连接API服务器,进行对话:

lmdeploy serve api_client http://localhost:23333

image

第三,输入以下命令,使用Gradio作为前端,启动网页:

lmdeploy serve gradio http://localhost:23333 \
    --server-name 0.0.0.0 \
    --server-port 6006

image

3. 量化

3.1 理论基础

KV Cache的核心思想就是缓存已经计算过的Key和Value向量,避免重复计算。让我详细解释一下: 在 Transformer 架构中:

  1. 输入token经过词嵌入(embedding)后
  2. 分别通过WK矩阵得到Key向量,通过WV矩阵得到Value向量
  3. 这些Key和Value向量被用于注意力计算:
    • Query和Key做点积得到注意力分数
    • 注意力分数与Value加权求和得到输出

KV Cache的优化点在于:

  1. 当生成新token时,之前已经计算过的token的K、V向量可以直接复用
  2. 不需要重新:
    • 对这些token做embedding
    • 通过WK、WV矩阵计算它们的Key、Value向量
  3. 只需要:
    • 计算新token的K、V向量
    • 将其加入缓存中的序列
    • 用完整的K、V序列计算注意力

这样做的好处:

  1. 减少重复计算,提高推理速度
  2. 特别是在长文本生成时效果明显,因为序列越长重复计算的部分就越多
  3. 代价是需要额外的显存来存储这些K、V向量

W4A16量化与kv cache量化: W4A16量化:

  1. "W4"代表将模型的权重(Weights)量化为4位整数(int4)
  2. "A16"表示激活值(Activations)保持16位精度(如FP16或BF16)
  3. 主要优势是显著减少模型大小:
    • 例如将原本BF16精度的7B参数模型从14GB压缩到约3.5GB
    • 因为从16位(2字节)压缩到4位(0.5字节),理论上可以减少到原来的1/4大小

KV Cache量化:

  1. KV cache是一种缓存键值对(Key-Value pairs)的技术,用于复用计算结果以提高推理速度
  2. KV Cache量化是指将这些缓存的数据进行压缩:
    • 可以选择int4(4位)或int8(8位)精度
    • 使用"per-head per-token"的非对称量化方式
  3. 优势:
    • 在相同显存空间下可以存储更多数据
    • 例如用int4量化后,相同4GB显存可以存储BF16精度4倍的数据量

两种量化方式可以结合使用:

  • W4A16量化减少模型本身占用的显存
  • KV Cache量化减少缓存占用的显存

让我通过一个具体例子来解释KV cache的量化过程。

假设我们有一个简单的场景:

  • 一个transformer模型,hidden size为8
  • 有2个attention heads,每个head的维度是4
  • 使用int4量化(每个数用4位表示,范围是0-15)

image

让我详细解释量化的过程:

  1. 非对称量化的原理:

    • 使用scale(缩放因子)和zero_point(零点偏移)将浮点数映射到int4范围(0-15)
    • 对每个attention head分别计算量化参数
    • 公式:quant_value = round((float_value / scale) + zero_point)
  2. 量化步骤:

    • 找到每个head中的最大值和最小值
    • 计算scale = (max - min) / (2^4 - 1) = (max - min) / 15
    • 计算zero_point使得最小值映射到0,最大值映射到15
    • 用公式将每个浮点数转换为0-15的整数
  3. 反量化(恢复)过程:

    • float_value = (quant_value - zero_point) * scale
  4. 存储效率:

    • 原始float16:每个数占16位
    • 量化后:每个数占4位,外加每个head存储一个scale和zero_point
    • 当序列很长时,存储空间可以节省约75%

这种"per-head per-token"的方式意味着:

  • 每个attention head有自己的scale和zero_point
  • 这些参数是针对当前token的K或V向量独立计算的
  • 这样可以更精确地保持每个head中数值的相对关系

这种量化方式在保持模型性能的同时,显著减少了KV cache的显存占用。


W4A16量化是权重量化的一种形式,我来详细解释它是如何工作的,以一个简化的例子说明。

image

W4A16量化的具体流程如下:

  1. W4:权重量化

    • 将权重矩阵按group_size(如128)分成多个组
    • 对每个组:
      • 找到组内最大值和最小值
      • 计算量化参数(scale和zero_point)
      • 将权重量化为4位整数(0-15)
    • 特点:
      • 每组独立量化,保持局部数值分布
      • 存储时每个组需要额外存储其scale和zero_point
  2. A16:激活值保持16位

    • 模型的输入和中间激活值保持BF16精度
    • 不对激活值进行量化
    • 原因:
      • 保持激活值的精度对模型性能很重要
      • 激活值相比权重数量少,占用显存较小
  3. 计算过程:

    • 输入:BF16格式的向量
    • 权重:INT4格式存储,计算时临时反量化到BF16
    • 矩阵乘法在BF16精度下进行
    • 输出:保持BF16格式
  4. AWQ (Activation-aware Weight Quantization) 优化:

    • 考虑激活值分布来优化量化
    • 为不同层设置不同的量化参数
    • 可以更好地保持模型性能

3.2 设置最大kv cache缓存大小

执行这条命令,默认的 cache-max-entry-count 是0.8

lmdeploy chat /root/models/internlm2_5-7b-chat

执行后占用24G

image

执行这条命令,设置 cache-max-entry-count 为0.4

lmdeploy chat /root/models/internlm2_5-7b-chat --cache-max-entry-count 0.4

执行后占用21G

image

3.3 设置在线 kv cache int4/int8 量化

通过 LMDeploy 应用 kv 量化非常简单,只需要设定 quant_policy 参数。

目前,LMDeploy 规定 quant_policy=4 表示 kv int4 量化,quant_policy=8 表示 kv int8 量化。

lmdeploy serve api_server \
    /root/models/internlm2_5-7b-chat \
    --model-format hf \
    --quant-policy 4 \
    --cache-max-entry-count 0.4\
    --server-name 0.0.0.0 \
    --server-port 23333 \
    --tp 1

显存占用21G。但quant-policy 设置为4时,LMDeploy将会使用int4精度提前开辟4GB的kv cache。

image

3.4 W4A16 模型量化和部署

lmdeploy lite auto_awq \
   /root/models/internlm2_5-1_8b-chat \
  --calib-dataset 'pileval' \
  --calib-samples 128 \
  --calib-seqlen 2048 \
  --w-bits 4 \
  --w-group-size 128 \
  --batch-size 1 \
  --search-scale False \
  --work-dir /root/models/internlm2_5-1_8b-chat-w4a16-4bit

命令解释:

  1. lmdeploy lite auto_awq: lite这是LMDeploy的命令,用于启动量化过程,而auto_awq代表自动权重量化(auto-weight-quantization)。
  2. /root/models/internlm2_5-7b-chat: 模型文件的路径。
  3. --calib-dataset 'ptb': 这个参数指定了一个校准数据集,这里使用的是’pileval’
  4. --calib-samples 128: 这指定了用于校准的样本数量—128个样本
  5. --calib-seqlen 2048: 这指定了校准过程中使用的序列长度—2048
  6. --w-bits 4: 这表示权重(weights)的位数将被量化为4位。
  7. --work-dir /root/models/internlm2_5-7b-chat-w4a16-4bit: 这是工作目录的路径,用于存储量化后的模型和中间结果。

image


存储占用对比:

量化前:

image

量化后:

image


显存占用对比:

量化前:

image

量化后:

image

分析1.8B模型的显存占用情况:

对于1.8B模型的BF16精度(量化前21.3GB):

  1. BF16精度下权重占用:

    • 1.8×10^9 参数 × 2 Bytes/参数 = 3.6GB 权重占用
  2. KV cache占用:

    • 剩余显存 = 24GB - 3.6GB = 20.4GB
    • KV cache(80%) = 20.4GB × 0.8 = 16.3GB
  3. 其他项占用:1.4GB

总计:21.3GB = 权重(3.6GB) + KV cache(16.3GB) + 其他项(1.4GB)

对于W4A16量化后(20.9GB):

  1. Int4精度下权重占用:

    • 3.6GB ÷ 4 = 0.9GB 权重占用
  2. KV cache占用:

    • 剩余显存 = 24GB - 0.9GB = 23.1GB
    • KV cache(80%) = 23.1GB × 0.8 = 18.5GB
  3. 其他项占用:1.5GB

总计:20.9GB = 权重(0.9GB) + KV cache(18.5GB) + 其他项(1.5GB)

3.5 W4A16 量化+ KV cache+KV cache 量化

lmdeploy serve api_server \
    /root/models/internlm2_5-1_8b-chat-w4a16-4bit \
    --model-format awq \
    --cache-max-entry-count 0.4 \
    --quant-policy 4 \
    --server-name 0.0.0.0 \
    --server-port 23333 \
    --tp 1

image

让我分析一下当KV cache占比调整为40%(0.4)时的显存占用情况:

  1. Int4精度下权重占用保持不变:

    • 0.9GB 权重占用
  2. KV cache占用调整:

    • 剩余显存 = 24GB - 0.9GB = 23.1GB
    • KV cache(40%) = 23.1GB × 0.4 = 9.2GB (之前是80%时的18.5GB)
  3. 其他项占用:2.3GB

总计:12.4GB = 权重(0.9GB) + KV cache(9.2GB) + 其他项(2.3GB)


lmdeploy serve api_client http://localhost:23333

image

附录1:API服务器基础知识

  1. 当你运行这个命令时,背后发生了以下步骤:
lmdeploy serve api_server /share/new_models/Shanghai_AI_Laboratory/internlm2_5-7b-chat --model-name internlm2_5-7b-chat

主要步骤:

  • 模型加载:加载指定路径的模型文件到内存
  • TurboMind初始化:设置推理引擎参数
  • API服务器启动:
    • 创建FastAPI应用实例
    • 注册路由端点(endpoints)
    • 启动HTTP服务器(默认端口23333)
  • WebUI初始化(如果启用)
  1. http://0.0.0.0:23333/ 页面内容解析:
  • 这是一个OpenAPI(Swagger UI)文档页面,显示了所有可用的API端点
  • 主要部分:
    /v1/completions  # 用于单轮对话
    /v1/chat/completions  # 用于多轮对话
    /v1/models  # 查询可用模型信息
    
  • 每个端点都包含:
    • HTTP方法(GET/POST)
    • 请求参数说明
    • 响应格式说明
    • 可以直接在页面测试API
  1. 使用curl测试API:

基础调用:

# 查看可用模型
curl http://localhost:23333/v1/models

# 简单的聊天完成请求
curl -X POST http://localhost:23333/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "internlm2_5-7b-chat",
    "messages": [
      {"role": "user", "content": "你好"}
    ]
  }'

更复杂的示例:

# 多轮对话
curl -X POST http://localhost:23333/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "internlm2_5-7b-chat",
    "messages": [
      {"role": "user", "content": "你好"},
      {"role": "assistant", "content": "你好!有什么我可以帮你的吗?"},
      {"role": "user", "content": "请介绍一下你自己"}
    ],
    "temperature": 0.7,
    "max_tokens": 1024,
    "stream": false
  }'

# 流式输出(stream模式)
curl -X POST http://localhost:23333/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "internlm2_5-7b-chat",
    "messages": [
      {"role": "user", "content": "写一首诗歌"}
    ],
    "stream": true
  }'

附录2:AWQ量化时校准数据集报错

  1. 最初的问题:
# 运行量化命令时遇到错误
lmdeploy lite auto_awq ... --calib-dataset 'ptb' ...
错误:TypeError: 'NoneType' object is not callable
  1. 问题的根本原因:

    • 量化过程需要校准数据集
    • 默认的 'ptb' 数据集无法正确下载和使用
    • 这导致数据集加载器返回了 None,引发了类型错误
  2. 解决步骤:

# 1. 首先安装解压工具(因为新数据集用了zstd压缩格式)
pip install zstandard

# 2. 更换为更稳定的校准数据集
# 把命令中的这部分:
--calib-dataset 'ptb' \
# 改成:
--calib-dataset 'pileval' \

# 3. 完整的修改后命令:
lmdeploy lite auto_awq \
   /root/models/internlm2_5-1_8b-chat \
   --calib-dataset 'pileval' \
   --calib-samples 128 \
   --calib-seqlen 2048 \
   --w-bits 4 \
   --w-group-size 128 \
   --batch-size 1 \
   --search-scale False \
   --work-dir /root/models/internlm2_5-1_8b-chat-w4a16-4bit
  1. 为什么这样改有效:
    • 'pileval' 是一个更稳定的校准数据集
    • 通过安装 zstandard 解决了数据集的解压问题
    • 更换数据集不影响量化效果,因为校准数据集只是用来帮助确定量化参数

核心就是:原来的数据集下载有问题,换一个更稳定的数据集并安装必要的解压工具就可以解决这个报错。


让我解释一下校准数据集(Calibration Dataset)的概念:

  1. 什么是校准数据集:
  • 在模型量化过程中,校准数据集用于帮助确定最佳的量化参数
  • 它就像是一个参考样本,用来帮助量化过程更好地保持模型的性能
  • 校准数据集不会改变模型的知识,只是用来调整量化时的参数
  1. 为什么可以换:
  • 不同的校准数据集只要具有足够的代表性和多样性就可以
  • 比如 'ptb'、'pileval'、'c4'、'wikitext2' 这些都是经过验证的标准文本数据集
  • 更换校准数据集不会影响模型本身的知识和能力
  1. 具体到你的情况:
  • 原来用的 'ptb' 数据集出现了技术问题
  • 换成 'pileval' 是完全没问题的,因为:
    • 这也是一个被广泛使用的校准数据集
    • 在 lmdeploy 的官方讨论中也推荐使用这个数据集
    • 它包含了足够丰富的文本样例

所以你可以放心使用 'pileval' 或其他推荐的校准数据集,这不会影响模型的基本能力。