[InternLM训练营第二期笔记]5. LMDeploy 量化部署 LLM 实践

embedded/2024/10/4 17:19:28/

该系列是上海AI Lab举行的书生 浦语大模型训练营的相关笔记部分。
笔记是第五节课,学习语言模型量化的基本概念,以及利用LMDeploy工具进行微调。


0. 模型部署的概念

0.0 背景

如果要将大模型在特定平台(大到服务器集群,小到端侧设备比如说手机等),都需要经过部署步骤。然而,LLM的模型计算量是非常大的,具体如下图:

在这里插入图片描述

对于LLM的推理过程,计算量大概是2倍的参数量,加2倍的模型层数 * 上下文长度 * 注意力维度,单位为FLOPs

C f o r w a r d = 2 N + 2 n l a y e r n c o n t e x t n a t t n d i m C_{forward} = 2N + 2 n_{layer} n_{context} n_{attn dim} Cforward=2N+2nlayerncontextnattndim

此外,不仅推理时的计算量大,而且存储模型参数本身的开销也很大:

在这里插入图片描述

此外,在GPU的推理过程中,访存速度远小于计算速度,因此存在访存性能瓶颈。也就是说,由于Transformer的参数量比较大,因此它是只能保存在GPU周围的显存中,而不是速度较快的缓存中,而从显存中访问的速度又远小于计算速度。

在这里插入图片描述

因此,针对以上三个难点,我们就必须用一定的部署手段,来减少计算量或占用资源量。目前主要有三种流派:

0.1 剪枝

剪枝是一个很成熟的技术,就是在于将模型中不重要的参数去掉:

在这里插入图片描述

0.2 蒸馏

在这里插入图片描述
蒸馏就是用一个教师模型去指导学生模型的训练,通常学生模型是小参数模型。

0.3 量化

在这里插入图片描述
量化就是将模型参数转换为特定位数的整数,例如原来是32位的fp32,可以量化成8位int。

那么量化为什么可以降低计算量呢?一种错误的观点是,认为量化后是int型,计算机计算int型所需要的时钟周期更少。然而,我们只是按照int型存储模型,在计算的时候,我们仍然需要将其反量化恢复成float。

量化的主要意义是,可以降低访存量,让访存量和计算量更加平衡。也就是降低了数据传输的时间,对访存量的需求。

1. 实战:配置LMDeploy和chat 1.8B模型对话(基础作业)

LMDeploy的核心功能如下:

在这里插入图片描述
首先还是创建开发机,GPU选择10% * A100. 注意选择CUDA12.2的版本。

随后创建环境:

studio-conda -t lmdeploy -o pytorch-2.1.2

安装LMDeploy:

conda activate lmdeploy
pip install lmdeploy[all]==0.3.0

然后我们创建本次实验的目录,并创建预训练模型的软链接

cd ~
mkdir lmdeployln -s /root/share/new_models/Shanghai_AI_Laboratory/internlm2-chat-1_8b /root/lmdeploy

随后,我们用Huggingface社区中推出的Transformer库运行一下chat1.8B模型,然后感受一下推理速度。

我们首先创建文件

cd ~/lmdeployvim pipeline_transformer.py

然后插入以下内容:

import torch
from transformers import AutoTokenizer, AutoModelForCausalLMtokenizer = AutoTokenizer.from_pretrained("/root/lmdeploy/internlm2-chat-1_8b", trust_remote_code=True)# Set `torch_dtype=torch.float16` to load model in float16, otherwise it will be loaded as float32 and cause OOM Error.
model = AutoModelForCausalLM.from_pretrained("/root/lmdeploy/internlm2-chat-1_8b", torch_dtype=torch.float16, trust_remote_code=True).cuda()  
# 以fp16加载模型
model = model.eval()inp = "hello"
print("[INPUT]", inp)
response, history = model.chat(tokenizer, inp, history=[])
print("[OUTPUT]", response)inp = "please provide three suggestions about time management"
print("[INPUT]", inp)
response, history = model.chat(tokenizer, inp, history=history)
print("[OUTPUT]", response)

然后运行

conda activate lmdeploypython /root/lmdeploy/pipeline_transformer.py

运行结果如下:

在这里插入图片描述
时间应该在大概5s左右

之后,我们再用LMDeploy进行对话:

lmdeploy chat /root/lmdeploy/internlm2-chat-1_8b

在这里插入图片描述
这个生成速度是秒生成,可以说是快多了

2. 实战:W4A16量化(进阶作业)

2.1 什么是KV cache

KV Cache是一种缓存技术,通过存储键值对的形式来复用计算结果,以达到提高性能和降低内存消耗的目的。在大规模训练和推理中,KV Cache可以显著减少重复计算量,从而提升模型的推理速度。理想情况下,KV Cache全部存储于显存,以加快访存速度。当显存空间不足时,也可以将KV Cache放在内存,通过缓存管理器控制将当前需要使用的数据放入显存。

模型在运行时,占用的显存可大致分为三部分:模型参数本身占用的显存、KV Cache占用的显存,以及中间运算结果占用的显存。

2.2 实践

直接运行

pip install einops==0.7.0lmdeploy lite auto_awq \/root/lmdeploy/internlm2-chat-1_8b \--calib-dataset 'ptb' \--calib-samples 128 \--calib-seqlen 1024 \--w-bits 4 \--w-group-size 128 \--work-dir /root/lmdeploy/internlm2-chat-1_8b-4bit

可以看到,新的模型被保存了:

在这里插入图片描述

随后,我们将KV Cache最大占用比例为0.4,运行:

lmdeploy chat /root/lmdeploy/internlm2-chat-1_8b-4bit --model-format awq --cache-max-entry-count 0.4

在这里插入图片描述
对于同样的问题,回答速度非常快,此时显存占用为4.9G

在这里插入图片描述

2.3 API Server部署

我们都是在本地直接推理大模型,这种方式成为本地部署。在生产环境下,我们有时会将大模型封装为API接口服务,供客户端访问。

在这里插入图片描述
运行

lmdeploy serve api_server -h

查看api server的用法。

在这里插入图片描述
因此和lmdeploy chat一样,更改kv缓存就直接增加--cache-max-entry-count命令。

我们启动API Server服务:注意,我们启动刚刚量化后的4bit模型,并且把模型格式改为awq, 把KV缓存占用比例改为0.4

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

出现以下界面后,说明server启动成功。
在这里插入图片描述

然后新建terminal,运行

conda activate lmdeploy
lmdeploy serve api_client http://localhost:23333

运行结果:
在这里插入图片描述

可以看到运行结果和直接命令行运行是一样的,期间显存占用4.9G

在这里插入图片描述

2.4 Gradio前端部署

接下来用Gradio网页端进行部署

运行

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

然后在Windows的powershell中运行:

ssh -CNg -L 6006:127.0.0.1:6006 root@ssh.intern-ai.org.cn -p 45344

运行结果:

在这里插入图片描述

2.5 Python代码集成

Python代码集成就是将大模型的推理部分集成到某些代码里面

这部分主要是借助于lmdeploy中的pipeline包完成的。

运行以下命令:

cd ~/lmdeploy
conda activate lmdeployvim pipeline.py

复制以下内容:其中注意,要将KV cache比例调成0.4

from lmdeploy import pipelinepipe = pipeline('/root/lmdeploy/internlm2-chat-1_8b-4bit', cache_max_entry_count=0.4)
response = pipe(['Hi, pls intro yourself', '上海是'])
print(response)

随后运行

python pipeline.py

结果:

在这里插入图片描述

3. 实战:使用LMDeploy运行多模态大模型Llava

注意将GPU调大一点,调成30% * A100. 首先安装依赖库:

conda activate lmdeploy
pip install git+https://github.com/haotian-liu/LLaVA.git@4e2277a060da264c4f21b364c867cc622c945874

随后新建文件

cd ~/lmdeployvim pipeline_llava.py

复制以下内容:

from lmdeploy.vl import load_image
from lmdeploy import pipeline, TurbomindEngineConfigbackend_config = TurbomindEngineConfig(session_len=8192) # 图片分辨率较高时请调高session_len
# pipe = pipeline('liuhaotian/llava-v1.6-vicuna-7b', backend_config=backend_config) 非开发机运行此命令
pipe = pipeline('/share/new_models/liuhaotian/llava-v1.6-vicuna-7b', backend_config=backend_config)image = load_image('https://raw.githubusercontent.com/open-mmlab/mmdeploy/main/tests/data/tiger.jpeg')
response = pipe(('describe this image', image))
print(response)

运行结果:

python pipeline_llava.py

在这里插入图片描述


http://www.ppmy.cn/embedded/14238.html

相关文章

【七】jmeter5.5+influxdb2.0+prometheus+grafana

参考文章:https://blog.csdn.net/wenxingchen/article/details/126892890 https://blog.csdn.net/Zuo19960127/article/details/119726652 https://blog.csdn.net/shnu_cdk/article/details/132182858 promethus参考 由于自己下载的是infuldb2.0,所以按照…

sql 笛卡尔积

隐式联接:一种在SQL查询中不使用显式的JOIN语句,而是通过在WHERE子句中指定条件来连接两个或多个表的方法。 在早期的SQL实践中,隐式联接是非常常见的,尤其是在早期版本的数据库系统中。隐式联接的工作原理是通过在WHERE子句中指…

用户中心 -- 代码理解

一、删除表 & if 删除表 1.1 DROP TABLE IF EXISTS user 和 DROP TABLE user 网址: 用户管理第2节课 -- idea 2023.2 创建表--【本人】-CSDN博客 二、 代码 2.1 清空表中数据 的 命令 【truncate 清空】 网址: 用户管理第2节课 -- idea 2…

【k8s】Kubernetes 1.29.4离线安装部署(总)

(一)kubernetes1.29.4离线部署之-安装文件准备 (二)kubernetes1.29.4离线部署之-镜像文件准备 (三)kubernetes1.29.4离线部署之-环境初始化 (四)kubernetes1.29.4离线部署之-组件安装…

CSS的网页美化功能

<1>文字类 通常情况下&#xff0c;一般使用span对文字进行重点突出&#xff0c;用div来操作一段代码块。 字体的所有属性&#xff1a; 属性描述font在一个声明中设置所有的字体属性font-family指定文本的字体系列font-size指定文本的字体大小font-style指定文本的字体样…

1 Java 泛型

概述 泛型&#xff0c;即“参数化类型”。一提到参数&#xff0c;最熟悉的就是定义方法时有形参&#xff0c;然后调用此方法时传递实参。那么参数化类型怎么理解呢&#xff1f;顾名思义&#xff0c;就是将类型由原来的具体的类型参数化&#xff0c;类似于方法中的变量参数&…

golang调用阿里通义千问的接口

有的项目可能需要用到直接外部调用阿里通义千问的接口。官方只有python和java的sdk。 其实golang简单的调用也非常简单&#xff0c;就是一个封装的http调用&#xff0c;下面是具体的代码。 注意提前申请apiKey. package tongyiimport ("bytes""context"…

【网站项目】校园商铺系统小程序

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…