书生浦语第二期实战营学习笔记(作业)(第五节课)

书生浦语第二期实战营系列—综述加技术报告研读
书生浦语第二期实战营系列—Tutorial1:demo体验
书生浦语第二期实战营系列—Tutorial2:RAG
书生浦语第二期实战营系列—Tutorial3:Xtuner微调
书生浦语第二期实战营系列—Tutorial4:Lmdeploy量化部署
书生浦语第二期实战营系列—Tutorial5:Agent
书生浦语第二期实战营系列—Tutorial6:OpenCompass

1 模型部署基础

1.1 模型部署的定义

当模型训练,微调,评测等系列工作完成,得到想要的模型后。将模型放到实际的使用环境中使用,这个过程叫做部署
请添加图片描述

1.2 大模型部署的挑战

模型部署有面临许多的调整,特别是大模型

1.2.1 计算量大

由于大模型的参数量非常巨大,导致模型在推理过程中的计算量也非常大,具体可以看下图中OpenAI团队提供的估算公式
请添加图片描述

1.2.2 内存开销大

LLM的transformer采用了self-attention,其中有大量q,k,v矩阵乘法运算。LLM在做生成任务的时候,新来的token需要和之前所有token的k,v做矩阵乘法,之前生成的k,v是固定的,不受新来的token的影响,所以为了避免重复计算,每一步还会将生成的k,v缓存下来,减少计算量,用空间换时间。但这会增加内存消耗,特别是上下文越长,kv缓存越多
请添加图片描述

1.2.3 访存瓶颈

大量的参数在计算的时候,需要频繁访问显存和内存中的数据,而当前硬件的计算速度远大于硬件的存储带宽,所以访存存在瓶颈
请添加图片描述

1.2.4 动态请求

LLM可能面对很多不同用户,所以可能会有请求数量不稳定,时间不一致,和batch token数据长度不一致的问题

1.3 模型部署优化方法

1.3.1 剪枝

剪枝可以直接减少计算参数
请添加图片描述

1.3.2 知识蒸馏

知识蒸馏是一种在CV界非常流行的方案,也是直接减少计算参数
请添加图片描述

1.3.3 量化

量化则是将模型参数和中间结果用整数来表示原本的浮点数,减少计算量,提高访存效率。量化分为:
1.训练后量化
2.量化感知训练
3.量化感知微调
请添加图片描述

1.4 LMDeploy

1.4.1 LMDeploy简介

LMDeploy有以下特点:
1.高效推理:continuous batch,blocked k/v cache,动态拆分和融合任务,张量并行,TurboMind高效的kenel设计
2.量化结果可靠
3.便捷的服务,完整的pipeline
4.有缓存状态的推理
请添加图片描述

1.4.2 LMDeploy核心功能

1.用于模型推理
2.模型量化
3.服务端部署pipeline
请添加图片描述

1.4.3 LMDeploy支持模型

LMDeploy支持众多的LLM,包括:llama、qwen、baichuan、mistral等
请添加图片描述

2 LMDeploy运行

2.1 环境部署(基础作业)

在之前安装的机器上,继续安装lmdeploy的依赖

pip install packaging
pip  install xxx/flash_attn-2.4.2+cu118torch2.0cxx11abiTRUE-cp310-cp310-linux_x86_64.whl
pip install lmdeploy[all]==0.3.0

请添加图片描述

2.2 模型下载(基础作业)

实战营第二节已经做过下载internlm2-chat-1.8b这里可以直接使用。开发机上可以加个软连接。

mkdir /root/models
ln -s /root/share/new_models/Shanghai_AI_Laboratory/internlm2-chat-1_8b /root/models

2.3 以命令行方式与模型对话(基础作业)

lmdeploy chat xxx/Shanghai_AI_Laboratory/internlm2-chat-1_8b

这里问了下大模型的优势,double hit后,回答如下:
请添加图片描述

3 LMDeploy量化

本部分内容主要介绍如何对模型进行训练后量化。主要包括 KV Cache 量化和模型参数量化。总的来说,量化是一种以参数或计算中间结果精度下降换空间节省(以及同时带来的性能提升)的策略。
正式介绍 LMDeploy 量化方案前,需要先介绍两个概念:
1.计算密集(compute-bound): 指推理过程中,绝大部分时间消耗在数值计算上;针对计算密集型场景,可以通过使用更快的硬件计算单元来提升计算速。
2.访存密集(memory-bound): 指推理过程中,绝大部分时间消耗在数据读取上;针对访存密集型场景,一般通过减少访存次数、提高计算访存比或降低访存量来优化。
常见的 LLM 模型由于 Decoder Only 架构的特性,实际推理时大多数的时间都消耗在了逐 Token 生成阶段(Decoding 阶段),是典型的访存密集型场景。
那么,如何优化 LLM 模型推理中的访存密集问题呢? 我们可以使用 KV Cache 量化和 4bit Weight Only 量化(W4A16)。KV Cache 量化是指将逐 Token(Decoding)生成过程中的上下文 K 和 V 中间结果进行 INT8 量化(计算时再反量化),以降低生成过程中的显存占用。4bit Weight 量化,将 FP16 的模型权重量化为 INT4,Kernel 计算时,访存量直接降为 FP16 模型的 1/4,大幅降低了访存成本。Weight Only 是指仅量化权重,数值计算依然采用 FP16(需要将 INT4 权重反量化)。

常见的 LLM 模型由于 Decoder Only 架构的特性,实际推理时大多数的时间都消耗在了逐 Token 生成阶段(Decoding 阶段),是典型的访存密集型场景。

那么,如何优化 LLM 模型推理中的访存密集问题呢? 我们可以使用 KV Cache 量化和 4bit Weight Only 量化(W4A16)。KV Cache 量化是指将逐 Token(Decoding)生成过程中的上下文 K 和 V 中间结果进行 INT8 量化(计算时再反量化),以降低生成过程中的显存占用。4bit Weight 量化,将 FP16 的模型权重量化为 INT4,Kernel 计算时,访存量直接降为 FP16 模型的 1/4,大幅降低了访存成本。Weight Only 是指仅量化权重,数值计算依然采用 FP16(需要将 INT4 权重反量化)。

3.1 设置最大KV Cache缓存大小

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

模型在运行时,占用的显存可大致分为三部分:模型参数本身占用的显存、KV Cache占用的显存,以及中间运算结果占用的显存。LMDeploy的KV Cache管理器可以通过设置–cache-max-entry-count参数,控制KV缓存占用剩余显存的最大比例。默认的比例为0.8。

lmdeploy chat xxx/Shanghai_AI_Laboratory/internlm2-chat-1_8b --cache-max-entry-count 0.4

3.2 W4A16量化

W4A16即为权重4bit,激活值16bit, Weight Only 量化。Weight Only 是指仅量化权重,数值计算依然采用 FP16(需要将 INT4 权重反量化)

这里下载ptb较慢,因为之前下载得有c4,修改以下文件,使用c4量化

vim xxx/envs/internlm/lib/python3.10/site-packages/lmdeploy/lite/utils/calib_dataloader.py

++93 95 96 97

–98~109
在这里插入图片描述
开启量化

lmdeploy lite auto_awq \
   xxx/Shanghai_AI_Laboratory/internlm2-chat-1_8b \
  --calib-dataset 'c4' \
  --calib-samples 128 \
  --calib-seqlen 1024 \
  --w-bits 4 \
  --w-group-size 128 \
  --work-dir xxx/internlm2-chat-1_8b-4bit

3.3 W4A16量化效果测试(进阶作业)

设置KV Cache最大占用比例为0.4,开启W4A16量化,以命令行方式与模型对话

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

这里再次问了下大模型的优势,double hit后,回答如下:
请添加图片描述

3.4 API Server方式启动 LMDeploy

先看框图:

我们把从架构上把整个服务流程分成下面几个模块。
1.模型推理/服务。主要提供模型本身的推理,一般来说可以和具体业务解耦,专注模型推理本身性能的优化。可以以模块、API等多种方式提供。
2.API Server。中间协议层,把后端推理/服务通过HTTP,gRPC或其他形式的接口,供前端调用。
3.Client。可以理解为前端,与用户交互的地方。通过通过网页端/命令行去调用API接口,获取模型推理/服务。
值得说明的是,以上的划分是一个相对完整的模型,但在实际中这并不是绝对的。比如可以把“模型推理”和“API Server”合并,有的甚至是三个流程打包在一起提供服务。

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

3.4.1 打开服务器端

以API Server方式启动 lmdeploy,开启 W4A16量化,调整KV Cache的占用比例为0.4

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

–model-format: 使用模型格式(awq:量化格式,hf:huggingface未量化格式);
–quant-policy:kv量化开关,需要和前面的量化保持一致(0表示不使用kv量化,4表示开启kv量化);
–server-name:API服务器的服务;
–server-port:API服务端口;
–tp:表示参数并行数量(GPU数量);
打开服务器端口,似曾相识,openai风格的接口

在这里插入图片描述

3.4.2 命令行客户端与模型对话(进阶作业)

以API Server方式启动 lmdeploy,开启 W4A16量化,调整KV Cache的占用比例为0.4,使用命令行客户端与模型对话

lmdeploy serve api_client http://localhost:23333

这里又问了下大模型的优势,double hit后,回答如下:
在这里插入图片描述

3.4.3 Gradio网页客户端与模型对话(进阶作业)

以API Server方式启动 lmdeploy,开启 W4A16量化,调整KV Cache的占用比例为0.4,使用Gradio网页客户端与模型对话

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

–server-name:gradio 作为server的地址
–server-port:gradio 作为server的端口
这里也问了下大模型的优势,量化后的模型速度是真快,回答如下:
在这里插入图片描述

3.4.4 Python代码集成的方式与模型对话(进阶作业)

使用W4A16量化,调整KV Cache的占用比例为0.4,使用Python代码集成的方式运行internlm2-chat-1.8b-4bit模型

vim pipeline_kv.py
from lmdeploy import pipeline, TurbomindEngineConfig

# 调低 k/v cache内存占比调整为总显存的 40%
backend_config = TurbomindEngineConfig(cache_max_entry_count=0.4, model_format='awq')
# 这里最后一个反斜杠非常重要,不加上会报错,lmdeploy中未给这个容错
model_path = 'xxx/internlm2-chat-1.8b-4bit/'
pipe = pipeline(model_path,
                backend_config=backend_config)
response = pipe(['Hi, pls intro yourself', '请描述一下大模型的优势'])
print(response)
python pipeline_kv.py

这里问了下大模型的优势,回答如下:
在这里插入图片描述

4 使用 LMDeploy 运行视觉多模态大模型 llava gradio demo

4.1 安装依赖

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

4.2 下载模型

因为huggingface老断,所以用镜像手动将权重下载到本地

vim download.py
import os
from huggingface_hub import snapshot_download
snapshot_download(repo_id="liuhaotian/llava-v1.6-vicuna-7b", local_dir="xxx/llava-v1.6-vicuna-7b", resume_download=True)
export HF_ENDPOINT="https://hf-mirror.com"
python download.py

在这里插入图片描述

4.3 使用 LMDeploy 运行llava(进阶作业)

vim pipeline_llava.py
from lmdeploy.vl import load_image
from lmdeploy import pipeline, TurbomindEngineConfig
import gradio as gr

backend_config = TurbomindEngineConfig(session_len=8192) # 图片分辨率较高时请调高session_len
# pipe = pipeline('liuhaotian/llava-v1.6-vicuna-7b', backend_config=backend_config) 非开发机运行此命令
pipe = pipeline('xxx/liuhaotian/llava-v1.6-vicuna-7b', backend_config=backend_config) # xxx为本地下载的目录
# image = load_image('https://raw.githubusercontent.com/open-mmlab/mmdeploy/main/tests/data/tiger.jpeg')
# response = pipe(('describe this image', image))
# print(response)

def model(image, text):
    if image is None:
        return [(text, "请上传一张图片。")]
    else:
        response = pipe((text, image)).text
        return [(text, response)]

demo = gr.Interface(fn=model, inputs=[gr.Image(type="pil"), gr.Textbox()], outputs=gr.Chatbot())
demo.launch() 

给了一张Mamba大战Transformer的图片,分析的有点好玩,显然还不能理解背后的含义
在这里插入图片描述
注:图片来自DeepHub IMBA,如侵立删。

5 KV Cache 量化

在第3节中的量化只讲了W4A16,即为权重量化,还有KV Cache 量化,KV Cache 量化是将已经生成序列的 KV 变成 Int8,使用过程一共包括三步:

5.1 计算 minmax。

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

对于 Attention 的 K 和 V:取每个 Head 各自维度在所有Token的最大、最小和绝对值最大值。对每一层来说,上面三组值都是 (num_heads, head_dim) 的矩阵。这里的统计结果将用于本小节的 KV Cache。
对于模型每层的输入:取对应维度的最大、最小、均值、绝对值最大和绝对值均值。每一层每个位置的输入都有对应的统计值,它们大多是 (hidden_dim, ) 的一维向量,当然在 FFN 层由于结构是先变宽后恢复,因此恢复的位置维度并不相同。这里的统计结果用于下个小节的模型参数量化,主要用在缩放环节(回顾PPT内容)。

5.1.1 下载量化数据集:

使用3.2小节中的c4数据集

5.1.2 KV量化计算minmax:

# 计算 minmax
lmdeploy lite calibrate xxx/internlm-chat-7b/ \
  --calib-dataset "c4" \
  --calib-samples 128 \
  --calib-seqlen 2048 \
  --work-dir ./quant_output

5.1.3 通过 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 ./quant_output  workspace/triton_models/weights/ \
  --kv_sym \
  --num_tp 1

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

5.1.4 修改配置

这个我们在3.4.1中已经提到过了(KV int8 开关),只需要把 quant_policy 改为 4 即可。

5.2 转换成 TurboMind 格式。

这个 group-size 就是上一步的那个 w_group_size。转换模型的layout,存放在默认路径 ./workspace 下,如果不想和之前的 workspace 重复,可以指定输出目录:–dst-path,比如:

lmdeploy convert  internlm2-chat-7b ./quant_output \
    --model-format awq \
    --group-size 128 \
    --dst-path ./workspace_quant4

6 部署应用到OpenXLab

将 LMDeploy Web Demo 部署到 OpenXLab (TODO)

附录

1.报错:
ImportError: cannot import name ‘LlavaLlamaForCausalLM’ from ‘llava.model’
按照参考1中的方法,目前我的flash-attn 版本为2.4.2,升级到2.5.2

pip install flash-attn==2.5.2

参考链接:
1.https://github.com/haotian-liu/LLaVA/issues/1101
2.https://github.com/InternLM/Tutorial/blob/camp2/lmdeploy/lmdeploy.md

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值