书生浦语大模型实战营第四期:LMDeploy 量化部署进阶实践
- 教程链接:https://github.com/InternLM/Tutorial/tree/camp4/docs/L2/LMDeploy
- 视频链接:https://www.bilibili.com/video/BV18aUHY3EEG/?vd_source=b96c7e6e6d1a48e73edafa36a36f1697
- 任务链接:https://github.com/InternLM/Tutorial/blob/camp4/docs/L2/LMDeploy/task.md
- 提交链接:https://aicarrier.feishu.cn/share/base/form/shrcnUqshYPt7MdtYRTRpkiOFJd
任务说明
基础任务(完成此任务即完成闯关)
- 使用结合W4A16量化与kv cache量化的
internlm2_5-1_8b-chat
模型封装本地API并与大模型进行一次对话,作业截图需包括显存占用情况与大模型回复,参考4.1 API开发(优秀学员必做),请注意2.2.3节与4.1节应使用作业版本命令。 - 使用Function call功能让大模型完成一次简单的"加"与"乘"函数调用,作业截图需包括大模型回复的工具调用情况,参考4.2 Function call(选做)
视频教程
LMDeploy部署模型
大模型缓存推理技术
大模型量化技术
大模型外推技术
Function Calling
环境配置
conda create -n lmdeploy python=3.10 -y
conda activate lmdeploy
pip install torch==2.4.1 torchvision==0.19.1 torchaudio==2.4.1 --index-url https://download.pytorch.org/whl/cu121
pip install timm==1.0.8 openai==1.40.3 lmdeploy[all]==0.5.3
pip install datasets==2.19.2
下载internlm2_5-7b-chat
和internlm2_5-1_8b-chat
两个模型至models
文件夹,具体参考之前入门岛的内容即可,然后测试下环境:
lmdeploy chat models/internlm2_5-7b-chat
这样环境基本上就搭建好了,看下显存占用,后面对比下:
显存占用分析
对于一个7B(70亿)参数的模型,每个参数使用16位浮点数(等于 2个 Byte)表示,则模型的权重大小约为:
7×10^9 parameters×2 Bytes/parameter=14GB
70亿个参数×每个参数占用2个字节=14GB
因此,对于internLM2.5 7B模型为bf16,LMDpeloy推理精度为bf16的7B模型权重需要占用14GB显存
然后lmdeploy默认设置cache-max-entry-count为0.8,即kv cache占用剩余显存的80%;
所以,对于24GB的A10显卡,权重占用14GB显存,剩余显存24-14=10GB,因此kv cache占用10GB*0.8=8GB,加上原来的权重14GB,总共占用14+8=22GB。
启动API服务器
conda activate lmdeploy
lmdeploy serve api_server \
models/Shanghai_AI_Laboratory/internlm2_5-7b-chat \
--model-format hf \
--quant-policy 0 \
--server-name 0.0.0.0 \
--server-port 23333 \
--tp 1
参数解释:
- lmdeploy serve api_server:这个命令用于启动API服务器。
- models/Shanghai_AI_Laboratory/internlm2_5-7b-chat :这是模型的路径。
- –model-format hf:这个参数指定了模型的格式。hf代表“Hugging Face”格式。
- –quant-policy 0:这个参数指定了量化策略。
–server-name 0.0.0.0:这个参数指定了服务器的名称。在这里,0.0.0.0是一个特殊的IP地址,它表示所有网络接口。 - –server-port 23333:这个参数指定了服务器的端口号。在这里,23333是服务器将监听的端口号。
- –tp 1:这个参数表示并行数量(GPU数量)
示例:
然后可以通过如下方式调用上面的API服务:
conda activate lmdeploy
lmdeploy serve api_client http://localhost:23333
这个跟上面一样,是在终端的对话,也可以通过网页形式:
lmdeploy serve gradio http://localhost:23333 \
--server-name 0.0.0.0 \
--server-port 6006
环境和基本使用就是这样,后面就是各种量化了~
任务1
使用结合W4A16量化与kv cache量化的
internlm2_5-1_8b-chat
模型封装本地API并与大模型进行一次对话,作业截图需包括显存占用情况与大模型回复,参考4.1 API开发(优秀学员必做),请注意2.2.3节与4.1节应使用作业版本命令。
首先使用下述命令进行W4A16
量化:
lmdeploy lite auto_awq \
models/Shanghai_AI_Laboratory/internlm2_5-1_8b-chat \
--calib-dataset 'ptb' \
--calib-samples 128 \
--calib-seqlen 2048 \
--w-bits 4 \
--w-group-size 128 \
--batch-size 1 \
--search-scale False \
--work-dir models/Shanghai_AI_Laboratory/internlm2_5-1_8b-chat-w4a16-4bit
- lmdeploy lite auto_awq: lite这是LMDeploy的命令,用于启动量化过程,而auto_awq代表自动权重量化(auto-weight-quantization)。
- models/Shanghai_AI_Laboratory/internlm2_5-1_8b-chat: 模型文件的路径。
- –calib-dataset ‘ptb’: 这个参数指定了一个校准数据集,这里使用的是’ptb’(Penn Treebank,一个常用的语言模型数据集)。
- –calib-samples 128: 这指定了用于校准的样本数量—128个样本
- –calib-seqlen 2048: 这指定了校准过程中使用的序列长度—2048
- –w-bits 4: 这表示权重(weights)的位数将被量化为4位。
- –work-dir models/Shanghai_AI_Laboratory/internlm2_5-1_8b-chat-w4a16-4bit: 这是工作目录的路径,用于存储量化后的模型和中间结果。
由于服务器链接huggingface有问题,所以需要手动下载ptb_text_only.py
,然后改一下lmdeploy/lite/utils/calib_dataloader.py
中的get_ptb
函数,具体改动如下:
输入以下指令启动量化后的模型:
lmdeploy chat models/Shanghai_AI_Laboratory/internlm2_5-1_8b-chat-w4a16-4bit --model-format awq
显存占用情况如下:
同时启用W4A16量化后的模型、设定kv cache占用和kv cache int4量化,命令如下:
lmdeploy serve api_server \
models/Shanghai_AI_Laboratory/internlm2_5-1_8b-chat-w4a16-4bit \
--model-format awq \
--quant-policy 4 \
--cache-max-entry-count 0.4\
--server-name 0.0.0.0 \
--server-port 23333 \
--tp 1
看下显存占用情况:
计算一下此刻的显存占用情况(11GB):
- 在 int4 精度下,1.8B模型权重占用0.9GB:3.6/4=0.9GB
- kv cache占用16.4GB:剩余显存24-0.9=23.1GB,kv cache占用40%,即23.1*0.4=9.24GB
- 其他项0.9GB
因此,11GB ∼ \sim ∼权重占用0.9GB+kv cache占用9.2GB+其它项0.9GB
使用下述命令访问上述API服务
lmdeploy serve gradio http://localhost:23333 \
--server-name 0.0.0.0 \
--server-port 6006
开始愉快地对话吧:
感觉1.8B的模型预留9.2GB的KV cache缓存应该有点浪费,继续将比例从0.4往下调,看下模型是否能正常对话:
lmdeploy serve api_server \
models/Shanghai_AI_Laboratory/internlm2_5-1_8b-chat-w4a16-4bit \
--model-format awq \
--quant-policy 4 \
--cache-max-entry-count 0.1\
--server-name 0.0.0.0 \
--server-port 23333 \
--tp 1
lmdeploy serve gradio http://localhost:23333 \
--server-name 0.0.0.0 \
--server-port 6006
然后就会发现只占用了4GB
的显存:
模型也依然可以正常对话:
感觉这个量化还是蛮不错的,马上就开个screen
,把7B的模型量化一波儿:
lmdeploy lite auto_awq \
models/Shanghai_AI_Laboratory/internlm2_5-7b-chat \
--calib-dataset 'ptb' \
--calib-samples 128 \
--calib-seqlen 2048 \
--w-bits 4 \
--w-group-size 128 \
--batch-size 1 \
--search-scale False \
--work-dir models/Shanghai_AI_Laboratory/internlm2_5-7b-chat-w4a16-4bit
同样把cache-max-entry-coun
设置为0.1
测试一下模型占用显存情况,并看看是否能正常对话:
lmdeploy serve api_server \
models/Shanghai_AI_Laboratory/internlm2_5-7b-chat-w4a16-4bit \
--model-format awq \
--quant-policy 4 \
--cache-max-entry-count 0.1\
--server-name 0.0.0.0 \
--server-port 23333 \
--tp 1
lmdeploy serve gradio http://localhost:23333 \
--server-name 0.0.0.0 \
--server-port 6006
可以看到基本上只用了7.5GB左右的显存,相当可以了~
对话目前也是正常的,速度还可以:
作业基本上就这样了,后续可以再试试比较大的模型,比如70B的模型,大约本身是需要140GB的显存,int4
量化后需要35GB,或许两个A10能跑起来,做个实验试试,嘿嘿~
任务2
使用Function call功能让大模型完成一次简单的"加"与"乘"函数调用,作业截图需包括大模型回复的工具调用情况,参考4.2 Function call(选做)
先启动API服务器:
lmdeploy serve api_server \
models/Shanghai_AI_Laboratory/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
新建脚本internlm2_5.py
,贴入下述内容:
# 导入openai模块中的OpenAI类,这个类用于与OpenAI API进行交互
from openai import OpenAI
# 创建一个OpenAI的客户端实例,需要传入API密钥和API的基础URL
client = OpenAI(
api_key='YOUR_API_KEY',
# 替换为你的OpenAI API密钥,由于我们使用的本地API,无需密钥,任意填写即可
base_url="http://0.0.0.0:23333/v1"
# 指定API的基础URL,这里使用了本地地址和端口
)
# 调用client.models.list()方法获取所有可用的模型,并选择第一个模型的ID
# models.list()返回一个模型列表,每个模型都有一个id属性
model_name = client.models.list().data[0].id
# 使用client.chat.completions.create()方法创建一个聊天补全请求
# 这个方法需要传入多个参数来指定请求的细节
response = client.chat.completions.create(
model=model_name,
# 指定要使用的模型ID
messages=[
# 定义消息列表,列表中的每个字典代表一个消息
{"role": "system", "content": "你是一个友好的小助手,负责解决问题."},
# 系统消息,定义助手的行为
{"role": "user", "content": "帮我讲述一个关于狐狸和西瓜的小故事"},
# 用户消息,询问时间管理的建议
],
temperature=0.8,
# 控制生成文本的随机性,值越高生成的文本越随机
top_p=0.8
# 控制生成文本的多样性,值越高生成的文本越多样
)
# 打印出API的响应结果
print(response.choices[0].message.content)
python运行一下:
我们成功地使用本地API与大模型进行了一次对话,服务器终端反馈也是正常的:
关于Function call,即函数调用功能,它允许开发者在调用模型时,详细说明函数的作用,并使模型能够智能地根据用户的提问来输入参数并执行函数。完成调用后,模型会将函数的输出结果作为回答用户问题的依据。
启动API服务器:
lmdeploy serve api_server \
models/Shanghai_AI_Laboratory/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
新建脚本internlm2_5_func.py
,贴入下述内容:
from openai import OpenAI
def add(a: int, b: int):
return a + b
def mul(a: int, b: int):
return a * b
tools = [{
'type': 'function',
'function': {
'name': 'add',
'description': 'Compute the sum of two numbers',
'parameters': {
'type': 'object',
'properties': {
'a': {
'type': 'int',
'description': 'A number',
},
'b': {
'type': 'int',
'description': 'A number',
},
},
'required': ['a', 'b'],
},
}
}, {
'type': 'function',
'function': {
'name': 'mul',
'description': 'Calculate the product of two numbers',
'parameters': {
'type': 'object',
'properties': {
'a': {
'type': 'int',
'description': 'A number',
},
'b': {
'type': 'int',
'description': 'A number',
},
},
'required': ['a', 'b'],
},
}
}]
messages = [{'role': 'user', 'content': 'Compute (3+5)*2'}]
client = OpenAI(api_key='YOUR_API_KEY', base_url='http://0.0.0.0:23333/v1')
model_name = client.models.list().data[0].id
response = client.chat.completions.create(
model=model_name,
messages=messages,
temperature=0.8,
top_p=0.8,
stream=False,
tools=tools)
print(response)
func1_name = response.choices[0].message.tool_calls[0].function.name
func1_args = response.choices[0].message.tool_calls[0].function.arguments
func1_out = eval(f'{func1_name}(**{func1_args})')
print(func1_out)
messages.append({
'role': 'assistant',
'content': response.choices[0].message.content
})
messages.append({
'role': 'environment',
'content': f'3+5={func1_out}',
'name': 'plugin'
})
response = client.chat.completions.create(
model=model_name,
messages=messages,
temperature=0.8,
top_p=0.8,
stream=False,
tools=tools)
print(response)
func2_name = response.choices[0].message.tool_calls[0].function.name
func2_args = response.choices[0].message.tool_calls[0].function.arguments
func2_out = eval(f'{func2_name}(**{func2_args})')
print(func2_out)
python运行一下:
可以看到InternLM2.5将输入’Compute (3+5)*2’根据提供的function拆分成了"加"和"乘"两步,第一步调用function add实现加,再于第二步调用function mul实现乘,再最终输出结果16.
到这里基本上就完成了任务,不过测试的时候发现一个bug,即将输入换成Compute (4+6)*2
时,再执行上述脚本:
根据输出可以发现模型并没有智能的调用function,这应该是因为模型本身就可以解决这个问题,不需要调用function工具,后面可以再测试一下,嘿嘿~