大模型微调学习之旅⑤ — LMDeploy 大模型量化部署实践

本文详细介绍了大模型部署的技术背景、LMDeploy的特性与实践步骤,包括环境配置、模型转换、TurboMind推理的多种使用方式,以及KVCache量化以降低显存占用。官方推荐了逐步测试和优化量化策略的过程。
摘要由CSDN通过智能技术生成

目录

一、大模型部署背景

二、LMDeploy简介

三、动手实践环节

1. 环境配置

2. 模型转换

3. TurboMind 推理+命令行本地对话

4. TurboMind推理+API服务

5. 网页 Demo 演示

         6. TurboMind 推理 + Python 代码集成

         7. 不同应用场景的推荐

         8. KV Cache 量化

         9.量化效果

         10. 官方的最佳实践说明


一、大模型部署背景

①由于大模型的规模和复杂性,它们需要大量的计算资源进行训练和推断。通常需要使用高性能的计算单元,如GPU(图形处理单元)或TPU(张量处理单元)来支持大模型的运算。其特点是内存开销巨大,一般的cpu或gpu去部署或者训练显然是不够用的,推理速度慢,部署困难。

②目前大模型部署的方案

  • 技术点
    • 模型并行
    • transformer计算和访存优化
    • 低比特量化
    • Continuous Batch
    • Page Attention·
  • 方案
    • huggingface transformers
    • 专门的推理加速框架


二、LMDeploy简介

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

速度保障:这是 lmdeploy 吞吐量测试结果,已经超过一些常见框架。

支持 Tensor Parallel:可以运行更大模型。不用怕设备性能不够,可以把 65B 或更大的模型,切分到多个 设备上运行。

多并发优化:lmdeploy 不止实现了多 batch,更完成了 kv cache 量化,有效降低单用户成本。

模型转换:只要是 transformer 结构(InternLM/LLaMa/Vicuna),无论 HuggingFace 或 Meta 格式,都可以转成需要的 bin

交互推理:缓存历史会话的 cache feature,避免重复计算

接入方式:lmdeploy 内部是统一的 API 接口,对外提供了 WebUI、命令行和 gRPC 客户端接入

完备的工具链:lmdeploy 和 OpenCompass(大模型评测一站式平台)可以很好的结合,使得 lmdeploy 的浮点、定点版本,都能高并发执行大量数据集验证, 而非单一的 ppl 结果。只有充分测试,才能保障出优秀且稳定的对话体验。 

三、动手实践环节

1. 环境配置

创建虚拟环境

$ conda create -n lmdeploy --clone /share/conda_envs/internlm-base

 激活虚拟环境

$ conda activate lmdeploy

lmdeploy 需要我们自己安装,此处应该会提示“没有这个包”,如下图所示:

 在 InternStudio 开发环境,需要先运行下面的命令

# 解决 ModuleNotFoundError: No module named 'packaging' 问题
pip install packaging
# 使用 flash_attn 的预编译包解决安装过慢问题
pip install /root/share/wheels/flash_attn-2.4.2+cu118torch2.0cxx11abiTRUE-cp310-cp310-linux_x86_64.whl

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

2. 模型转换

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

使用官方提供的模型文件,就在用户根目录执行,如下所示:


3. TurboMind 推理+命令行本地对话

尝试本地对话(Bash Local Chat),下面用(Local Chat 表示)在这里其实是跳过 API Server 直接调用 TurboMind。简单来说,就是命令行代码直接执行 TurboMind


4. TurboMind推理+API服务

上面的我们直接用命令行启动 Client,下面我们使用 lmdepoy 进行服务化。”模型推理/服务“目前提供了 Turbomind 和 TritonServer 两种服务化方式。此时,Server 是 TurboMind 或 TritonServer,API Server 可以提供对外的 API 服务。

 

# 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 参数可以通过 --tp 指定(tp 表示 tensor parallel),该参数默认值为1(也就是一张卡),表示 Tensor 并行。还剩下一个 instance_num 参数,表示实例数,可以理解成 Batch 的大小。执行后如下图所示。 

 

然后,我们可以新开一个窗口,执行下面的 Client 命令。如果使用官方机器,可以打开 vscode 的 Terminal,执行下面的命令。

# ChatApiClient+ApiServer(注意是http协议,需要加http)
lmdeploy serve api_client http://localhost:23333

 

5. 网页 Demo 演示


5.1 TurboMind 服务作为后端

先启动server服务端

lmdeploy serve api_server ./workspace \
	--server_name 0.0.0.0 \
	--server_port 23333 \
	--instance_num 64 \
	--tp 1

然后启动作为前端的 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

 

5.2 TurboMind 推理作为后端

gradio 可以直接和 TurboMind 连接

# Gradio+Turbomind(local)
lmdeploy serve gradio ./workspace

这里不知道为什么没有回复 (是我之前的server端没有关闭)

6. TurboMind 推理 + Python 代码集成

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-20b')
generator = tm_model.create_instance()

# process query
query = "你好啊兄嘚"
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)


7. 不同应用场景的推荐

  • 我想对外提供类似 OpenAI 那样的 HTTP 接口服务。推荐使用 TurboMind推理 + API 服务(2.3)。
  • 我想做一个演示 Demo,Gradio 无疑是比 Local Chat 更友好的。推荐使用 TurboMind 推理作为后端的Gradio进行演示(2.4.2)。
  • 我想直接在自己的 Python 项目中使用大模型功能。推荐使用 TurboMind推理 + Python(2.5)。
  • 我想在自己的其他非 Python 项目中使用大模型功能。推荐直接通过 HTTP 接口调用服务。也就是用本列表第一条先启动一个 HTTP API 服务,然后在项目中直接调用接口。
  • 我的项目是 C++ 写的,为什么不能直接用 TurboMind 的 C++ 接口?!必须可以!大佬可以右上角叉掉这个窗口啦。


7.1 模型配置实践

  文件 config.ini 它里面存的主要是模型相关的配置信息

其中,模型属性相关的参数不可更改,主要包括下面这些。

model_name = llama2
head_num = 32
kv_head_num = 32
vocab_size = 103168
num_layer = 32
inter_size = 11008
norm_eps = 1e-06
attn_bias = 0
start_id = 1
end_id = 2
rotary_embedding = 128
rope_theta = 10000.0
size_per_head = 128

 

和数据类型相关的参数也不可更改,主要包括两个

  weight_type 表示权重的数据类型。目前支持 fp16 和 int4。int4 表示 4bit 权重。当 weight_type 为 4bit 权重时,group_size 表示 awq 量化权重时使用的 group 大小。

weight_type = fp16
group_size = 0

三个可能需要调整的参数。

  • KV int8 开关:
    • 对应参数为 quant_policy,默认值为 0,表示不使用 KV Cache,如果需要开启,则将该参数设置为 4。
    • KV Cache 是对序列生成过程中的 K 和 V 进行量化,用以节省显存。我们下一部分会介绍具体的量化过程。
    • 当显存不足,或序列比较长时,建议打开此开关。
  • 外推能力开关:
    • 对应参数为 rope_scaling_factor,默认值为 0.0,表示不具备外推能力,设置为 1.0,可以开启 RoPE 的 Dynamic NTK 功能,支持长文本推理。另外,use_logn_attn 参数表示 Attention 缩放,默认值为 0,如果要开启,可以将其改为 1。
    • 外推能力是指推理时上下文的长度超过训练时的最大长度时模型生成的能力。如果没有外推能力,当推理时上下文长度超过训练时的最大长度,效果会急剧下降。相反,则下降不那么明显,当然如果超出太多,效果也会下降的厉害。
    • 当推理文本非常长(明显超过了训练时的最大长度)时,建议开启外推能力。
  • 批处理大小:
    • 对应参数为 max_batch_size,默认为 64,也就是我们在 API Server 启动时的 instance_num 参数。
    • 该参数值越大,吞度量越大(同时接受的请求数),但也会占用更多显存。
    • 建议根据请求量和最大的上下文长度,按实际情况调整。


8. KV Cache 量化

KV Cache 量化是将已经生成序列的 KV 变成 Int8,使用过程一共包括三步:

第一步:计算 minmax。

主要思路是通过计算给定输入样本在每一层不同位置处计算结果的统计情况。

  • 对于 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

 

在这个命令行中,会选择 128 条输入样本,每条样本长度为 2048,数据集选择 C4,输入模型后就会得到上面的各种统计值。如果显存不足,可以适当调小 samples 的数量或 sample 的长度。

下面是在interstudio平台上可以用的:

这一步由于默认需要从 Huggingface 下载数据集,国内经常不成功。所以我们导出了需要的数据,大家需要对读取数据集的代码文件做一下替换。共包括两步:

  • 第一步:复制 calib_dataloader.py 到安装目录替换该文件:cp /root/share/temp/datasets/c4/calib_dataloader.py /root/.conda/envs/lmdeploy/lib/python3.10/site-packages/lmdeploy/lite/utils/
  • 第二步:将用到的数据集(c4)复制到下面的目录:cp -r /root/share/temp/datasets/c4/ /root/.cache/huggingface/datasets/

 

第二步:通过 minmax 获取量化参数。

主要就是利用下面这个公式,获取每一层的 K V 中心值(zp)和缩放值(scale)。 

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

有这两个值就可以进行量化和解量化操作了。具体来说,就是对历史的 K 和 V 存储 quant 后的值,使用时在 dequant。

第二步的执行命令如下:

# 通过 minmax 获取量化参数
lmdeploy lite kv_qparams \
  --work_dir ./quant_output  \
  --turbomind_dir workspace/triton_models/weights/ \
  --kv_sym False \
  --num_tp 1

 在这个命令中,num_tp 的含义前面介绍过,表示 Tensor 的并行数。每一层的中心值和缩放值会存储到 workspace 的参数目录中以便后续使用。kv_sym 为 True 时会使用另一种(对称)量化方法,它用到了第一步存储的绝对值最大值,而不是最大值和最小值。

 

 

第三步:修改配置。

也就是修改 weights/config.ini 文件,这个我们在《2.6.2 模型配置实践》中已经提到过了(KV int8 开关),只需要把 quant_policy 改为 4 即可。

这一步需要额外说明的是,如果用的是 TurboMind1.0,还需要修改参数 use_context_fmha,将其改为 0。

接下来就可以正常运行前面的各种服务了,只不过咱们现在可是用上了 KV Cache 量化,能更省(运行时)显存了。


9. 量化效果

 

总结: KV Cache 量化既能明显降低显存占用,还有可能同时带来精准度(Accuracy)的提升


10.  官方的最佳实践说明

首先我们需要明白一点,服务部署和量化是没有直接关联的,量化的最主要目的是降低显存占用,主要包括两方面的显存:模型参数和中间过程计算结果。前者对应《3.2 W4A16 量化》,后者对应《3.1 KV Cache 量化》。

量化在降低显存的同时,一般还能带来性能的提升,因为更小精度的浮点数要比高精度的浮点数计算效率高,而整型要比浮点数高很多。

所以我们的建议是:在各种配置下尝试,看效果能否满足需要。这一般需要在自己的数据集上进行测试。具体步骤如下。

  • Step1:优先尝试正常(非量化)版本,评估效果。
    • 如果效果不行,需要尝试更大参数模型或者微调。
    • 如果效果可以,跳到下一步。
  • Step2:尝试正常版本+KV Cache 量化,评估效果。
    • 如果效果不行,回到上一步。
    • 如果效果可以,跳到下一步。
  • Step3:尝试量化版本,评估效果。
    • 如果效果不行,回到上一步。
    • 如果效果可以,跳到下一步。
  • Step4:尝试量化版本+ KV Cache 量化,评估效果。
    • 如果效果不行,回到上一步。
    • 如果效果可以,使用方案。

另外需要补充说明的是,使用哪种量化版本、开启哪些功能,除了上述流程外,还需要考虑框架、显卡的支持情况,比如有些框架可能不支持 W4A16 的推理,那即便转换好了也用不了。

根据实践经验,一般情况下:

  • 精度越高,显存占用越多,推理效率越低,但一般效果较好。
  • Server 端推理一般用非量化版本或半精度、BF16、Int8 等精度的量化版本,比较少使用更低精度的量化版本。
  • 端侧推理一般都使用量化版本,且大多是低精度的量化版本。这主要是因为计算资源所限。

以上是针对项目开发情况,如果是自己尝试(玩儿)的话:

  • 如果资源足够(有GPU卡很重要),那就用非量化的正常版本。
  • 如果没有 GPU 卡,只有 CPU(不管什么芯片),那还是尝试量化版本。
  • 如果生成文本长度很长,显存不够,就开启 KV Cache。

建议大家根据实际情况灵活选择方案。

  • 37
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值