大模型 LMDeploy 量化部署

1 模型部署

定义:

  • 在软件工程中,部署通常指的是将开发完毕的软件投入使用的过程。
  • 在人工智能领域,模型部署是实现深度学习算法落地应用的关键步骤。简单来说,模型部署就是将训练好的深度学习模型在特定环境中运行的过程。

场景:

  • 服务器端:CPU部署,单GPU/TPU/NPU部署,多卡/集群
    部署.
  • 移动端边缘端:移动机器人,手机……

2 大模型缓存推理技术

在大模型中,Transformer模型扮演着至关重要的角色。它通过自注意力机制(Self-Attention)来捕捉文本中的上下文信息,实现对文本的深入理解和推理。这种机制允许模型在处理每个token时都考虑到整个输入序列的上下文信息,从而提高了模型的表达能力和准确性。
在这里插入图片描述

  • 对于新的请求Query,需要与历史的Key、Value计算注意力分数。
  • 如果每次都重新计算历史的Key、Value,会浪费大量计算资源。
  • 每轮新迭代时将Key、Value进行缓存,共下次迭代使用。

KV Cache的全称是key-value cache,可以简单理解为对大模型推理过程中的key-value缓存的优化。
在这里插入图片描述

LMDeploy 对 KV Cache 的实现:

  • 预先申请策略,减少运行时因申请/释放内存的消耗时间。
  • 通过设置cache_max_entry_count参数来调节 KV Cache 占用内存的大小,为占用剩余显存的比例。

下图0.2表示KV Cache 可以占用的显存大小是在加载玩模型权重后所剩余的显存的20%。
在这里插入图片描述

3 大模型量化技术

量化技术将传统的表示方法中的浮点数转换为整数或其他离散形式,以减轻深度学习模型的存储和计算负担。

为什么要做量化:

  • 提升推理的速度
  • 增加上下文长度
  • 速度更快的kernel
  • 降低I/0延迟
  • 降低推理成本

量化思路,将原来浮点数所在区间做一个线性映射,映射为一些列整数。以 INT8 的8位二进制数为例,通用公式:
Z P = min ⁡ + max ⁡ 2 量化: q = r o u n d ( f − Z P S ) S = max ⁡ − min ⁡ 255 反量化: f = q × S + Z P ZP=\frac{\min+\max} {2} \quad\text{量化:} \, q=\mathrm{round}\left(\frac{f-ZP}{S}\right) \\ S=\frac{\max-\min}{255}\quad \text{反量化:} \, f=q\times S+ZP ZP=2min+max量化:q=round(SfZP)S=255maxmin反量化:f=q×S+ZP

在这里插入图片描述

量化方法的分类
(1)按量化对象分:

  • KV Cache量化
  • 模型权重量化
  • 激活值量化 (例如对于一个线性层 y = w x y = wx y=wx w w w为权重, x x x为激活值)

(2)按量化阶段分

  • 量化感知训练(QAT)
  • 量化感知微调(QAF)
  • 训练后量化(PTQ,训练好模型后,在完成量化,常用这种方式)

由于QAT和QAF一般在模型训练后仍然需要做微调操作量化,通常不采用这两种方式。

3.1 LMDeploy 量化方案

LMDeploy 量化方式:KV Cache量化 + 模型权重量化 + 训练后量化

3.1.1 KV Cache量化

  • 在线KVCacheINT4/INT8量化,粒度为 per-head per-token
  • 与FP16相比,INT4/INT8的KVBlock数量分别可以提升4倍和2倍。意义:更长的上下文、更高的并发吞吐
  • 精度上INT8几乎无损,INT4略有损失

在这里插入图片描述

3.1.2 模型权重量化(W4A16量化)

  • 基于 AWQ 算法,对权重进行4bit量化,计算时返量化使用FP16
  • 性能是FP16的2.4倍以上
  • 权重大小、显存降为FP16的的1/4

3.1.3 AWQ 量化原理**:

参考论文:AWQ

核心观点1权重并不等同重要,仅有0.1~1%小部分显著权重对推理结果影响较大

如果有办法将这0.1~1%的小部分显著权重保持FP16,对其他权重进行低比特量化,可以大幅降低内存占用。那么问题来了:如果选出显著权重?
(1)随机挑选-听天由命
(2)基于权重分布挑选-好像应该这样
(3)基于激活值挑选-竟然是这样

AWQ 论文对三者做了实验对比,返实验结果表明基于激活值挑选显著权重效果显著。

在这里插入图片描述

基于激活值,按通道“组团”挑选显著权重权重。为了避免实现上过于复杂,在挑选显著权重时,并非在“元素”级别进行挑选,而是在“通道”级别进行挑选。 首先将激活值对每一列(channel)求绝对值的平均值,把平均值较大一列对应的通道视作显著权重

在这里插入图片描述

但是,随之伴随问题:

  • 显著权重INT4,非显著权重FP16?
  • “显著”的阈值?
  • 如何实现一个通道粒度上混合精度的kernel?
  • 这是硬件不友好的行为!
  • 这更是开发者不友好的行为!

核心观点2量化前对显著权重进行放大可以降低量化误差
在这里插入图片描述

考虑权重矩阵w,线性运算写作y=wx。对权重矩阵进行量化后,可以写作y=Q(w)x。Q(·)定义如下:实验表现:

  • 随着s增大,假设成立的概率越来越低,但在s<2之前,概率还是很低的(<5%)
  • 在一定范围内,随着s的增大,误差比值越来越小,完全支持作者观点

所有权重均低比特量化。显著权重乘以较大s,等效于降低量化误差。非显著权重乘以较小的s,等效于给予更少的关注。

在这里插入图片描述

LMDeploy 采用分组计算每个通道的缩放系数:

在这里插入图片描述

4 大模型外推技术

大模型长度外推性是一个训练和预测的长度不一致的问题。

外推引发的两大问题:

  • 预测阶段用到了没训练过的位置编码
    模型不可避免地在一定程度上对位置编码“过拟合”
  • 预测注意力时注意力机制所处理的token数量远超训练时的数量
    导致计算注意力“熵”的差异较大

4.1 为什么需要位置编码

因为并行化的自注意力机制并不具备区分token相对位置的能力。位置编码用于为输入序列的每个位置添加一种表示其位置信息的编码。通过引入位置编码,Transformer模型可以更好地捕捉序列中不同位置之间的关系,从而更好地处理长距离依赖关系。

  • 如果直接使用一个整数作为位置信息提供给模型,则会造成数值跨度过大,对梯度优化器不友好,模型学习困难。

  • 如果将数值缩放到 [0-1] 区间,则会造成数值跨度过小,模型和优化器都难以分辨位置。

  • 使用向量表示位置:
    “10进制”为例,位置1234可以用4维向量[1 2 3 4]表示。一般地,位置N可以用如下向量表示:
    ∣ N 1 0 3 ∣ m o d 10 ∣ N 1 0 2 ∣ m o d 10 ∣ N 1 0 2 ∣ m o d 10 ∣ N 1 0 0 ∣ m o d 10 \left|\frac{N}{10^{3}}\right|\mathrm{mod}10\quad\left|\frac{N}{10^{2}}\right|\mathrm{mod}10\quad\left|\frac{N}{10^{2}}\right|\mathrm{mod}10\quad\left|\frac{N}{10^{0}}\right|\mathrm{mod}10 103N mod10 102N mod10 102N mod10 100N mod10
    更一般地,果不是10进制,是β进制呢?第i位数是为:
    ⌊ N β i ⌋ m o d β \left\lfloor\frac{N}{\beta^i}\right\rfloor\mathrm{mod~}\beta βiNmod β
    这里的取余重在表示周期性。

Transformer使用的 Sinusoidal 位置编码
p i , 2 j = sin ⁡ ( i 1000 0 2 j / d ) , p i , 2 j + 1 = cos ⁡ ( i 1000 0 2 j / d ) p_{i,2j}=\sin\left(\frac i{10000^{2j/d}}\right),\quad p_{i,2j+1}=\cos\left(\frac i{10000^{2j/d}}\right) pi,2j=sin(100002j/di),pi,2j+1=cos(100002j/di)

  • "mod”的主要特性是周期性,因此与周期函数cos/sin具有一定的等效性
  • 因此,Sinusoidal 位置编码可以认为是一种特殊的β进制编码

4.2 从位置编码角度解决外推引发的问题

方案:训练阶段就预留好足够的位数

Transformer的原作者就是这么想的,认为预留好位数后模型就能具备对位置编码的泛化性。

在这里插入图片描述

  • 现实情况:模型并没有按照我们的期望进行泛化
  • 训练阶段大多数高位都是“0”,因此这部分位数没有被充分训练,模型无法处理这些新编码。

线性内插法

  • 方案:把“新长度范围”,等比例缩放至训练阶段的长度范围。
  • 如训练时使用1k训练,需外推至4k,就将 [0,4k] 的范围线性缩放至 [0,1k]。
    n / k β d / 2 − 1 \frac{n/k}{\beta^{d/2-1}} βd/21n/k在这里插入图片描述
    但是这会使最低位非常“拥挤”,通常需要进行微调,使模型适应拥挤的映射关系。各维度差异较大!其他位置差异为1,个位差异较小,模型不易分辨,效果不佳。

进制转换法

  • 大模型其实并不知道我们输入的位置编码具体是多少“进制”的,他只对相对大小关系敏感
  • 能否通过“进制转换”来等效“内插”?
    如:10进制下,3位表示范围是0~999;16进制下,3位表示范围是0 ~ FFF(FFF16=4095)
    在这里插入图片描述
    虽然每一位上都有可能出现大于“9”的数,但相对大小差异仍为“1”,模型有能力进行泛化。把内插的压力平均分摊到了每一位上。

4.2.1 NTK-aware 外推技术

预测阶段,计算系数,对位置编码的底数base进行缩放,使得与线性内插法值相等:
n ( β λ ) d / 2 − 1 = n / k β d / 2 − 1 \frac{n}{(\beta\lambda)^{d/2-1}}=\frac{n/k}{\beta^{d/2-1}} (βλ)d/21n=βd/21n/k
n 是实际预测长度,k 是实际长度与训练长度的比值。求得:
λ = k 2 / ( d − 2 ) \lambda=k^{2/(d-2)} λ=k2/(d2)

可得位置编码为:
sin ⁡ ( n ( β λ ) i ) = sin ⁡ ( n ( θ 2 / d k 2 / ( d − 2 ) ) i ) = sin ⁡ ( n ( θ k d / ( d − 2 ) ) 2 i ) \sin\left(\frac{n}{(\beta\lambda)^{i}}\right)=\sin\left(\frac{n}{(\theta^{2/d}k^{2/(d-2)})^{i}}\right)=\sin\left(\frac{n}{(\theta k^{d/(d-2)})^{2i}}\right) sin((βλ)in)=sin((θ2/dk2/(d2))in)=sin((θkd/(d2))2in)

5 Function Calling

什么是Function Calling?为什么要有FunctionCalling?

FunctionCalling,即为让LLM调用外部函数解决问题,从而拓展LLM的能力边界。

  • 指的是在语言模型中集成外部服务或API的调用能力。
  • 模型可以在生成文本的过程中调用外部函数或服务,获取额外的数据或执行特定的任务。

Function Calling的意义?

  • 解决时效性问题
    今天是哪年哪日?今天天气如何?
  • 拓展LLM能力边界
    帮我算一下 e 8 / 12345 e^8/12345 e8/12345 等于多少?帮我搜索一下这篇论文?

5.1 Function Calling 与 RAG

工作原理

  • Function Calling:
    指的是在语言模型中集成外部功能或API的调用能力;
    模型可以在生成文本的过程中调用外部函数或服务,获取额外的数据或执行特定的任务。
  • RAG:
    结合了信息检索和文本生成;
    它首先从一个大型的文档数据库中检索与输入查询相关的文档,然后将这些文档的信息融入到语言模型的生成过程中。

应用场景

  • Function Calling:
    适用于需要模型执行特定操作或与外部系统交互的场景。
    例如,模型可以调用天气API来回答关于当前天气的问题,或者调用翻译服务来提供翻译;
    在动态数据查询、任务自动化、系统集成以及结构化数据获取等方面有广泛应用。
  • RAG:
    适用于那些需要外部信息来提供准确回答的场景;
    如问答系统,它可以通过检索到的信息来丰富和支模型的回答;
    在医疗、法律、研究等领域,使用RAG可以保证提供的答案与权威文献一致。

6 LMDeploy 量化部署实践

6.1 配置LMDeploy环境

6.1.1 环境搭建

创建一个名为lmdeploy的conda环境,python版本为3.10,创建成功后激活环境并安装0.5.3版本的lmdeploy及相关包。

conda create -n lmdeploy  python=3.10 -y
conda activate lmdeploy
conda install pytorch==2.1.2 torchvision==0.16.2 torchaudio==2.1.2 pytorch-cuda=12.1 -c pytorch -c nvidia -y
pip install timm==1.0.8 openai==1.40.3 lmdeploy[all]==0.5.3pip install datasets==2.19.2

6.1.2 InternStudio 环境获取模型

InternStudio统一把模型放置在/root/models/目录。
运行以下命令,创建文件夹并设置开发机共享目录的软链接。

mkdir /root/models
ln -s /root/share/new_models/Shanghai_AI_Laboratory/internlm2_5-7b-chat /root/models
ln -s /root/share/new_models/Shanghai_AI_Laboratory/internlm2_5-1_8b-chat /root/models
ln -s /root/share/new_models/OpenGVLab/InternVL2-26B /root/models

本实战使用internlm2_5-7b-chat和InternVL2-26B作为演示。由于上述模型量化会消耗大量时间(约8h),量化请使用internlm2_5-1_8b-chat模型完成。

6.1.3 LMDeploy 验证启动模型文件

在量化工作正式开始前,我们还需要验证一下获取的模型文件能否正常工作,以免竹篮打水一场空。

让我们进入创建好的conda环境并启动InternLM2_5-1_8b-chat

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

启动成功后,可以提问:
在这里插入图片描述

启动大模型后查看资源监控:

现在显存占用约23GB。

我们要运行参数量为7B的InternLM2.5,由InternLM2.5的码仓查询InternLM2.5-7b-chat的config.json文件可知,该模型的权重被存储为bfloat16格式:

在这里插入图片描述
对于一个7B(70亿)参数的模型,每个参数使用16位浮点数(等于 2个 Byte)表示,则模型的权重大小约为:

7×10^9 parameters×2 Bytes/parameter=14GB

为什么现在显存占用约23GB呢?
这是因为LMDeploy设置了kv cache量化占剩余显存的80%:
在这里插入图片描述
此时对于24GB的显卡,即30%A100,权重占用14GB显存,剩余显存24-14=10GB,因此kv cache占用10GB*0.8=8GB,加上原来的权重14GB,总共占用14+8=22GB。
实际加载模型后,其他项也会占用部分显存,因此剩余显存比理论偏低,实际占用会略高于22GB。

6.2 LMDeploy与InternLM2.5

前面我们直接在本地部署InternLM2.5。而在实际应用中,我们有时会将大模型封装为API接口服务,供客户端访问。

6.2.1 LMDeploy API部署InternLM2.5

启动API服务器
首先让我们进入创建好的conda环境,并通下命令启动API服务器,部署InternLM2.5模型:

conda activate lmdeploy
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

命令解释:

  1. lmdeploy serve api_server:这个命令用于启动API服务器。
  2. /root/models/internlm2_5-7b-chat:这是模型的路径。
  3. --model-format hf:这个参数指定了模型的格式。hf代表“Hugging Face”格式。
  4. --quant-policy 0:这个参数指定了量化策略。
  5. --server-name 0.0.0.0:这个参数指定了服务器的名称。在这里,0.0.0.0是一个特殊的IP地址,它表示所有网络接口。
  6. --server-port 23333:这个参数指定了服务器的端口号。在这里,23333是服务器将监听的端口号。
  7. --tp 1:这个参数表示并行数量(GPU数量)。

这一步由于部署在远程服务器上,所以本地需要做一下ssh转发才能直接访问。在你本地打开一个cmd或powershell窗口,输入命令如下:

 ssh -CNg -L 23333:127.0.0.1:23333 root@ssh.intern-ai.org.cn -p 你的ssh端口号

打开浏览器,访问http://127.0.0.1:23333看到如下界面即代表部署成功:
在这里插入图片描述

6.2.2 以命令行形式连接API服务器

关闭http://127.0.0.1:23333网页,但保持终端和本地窗口不动,新建一个终端。

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

稍待片刻,等出现double enter to end input >>>的输入提示即启动成功,此时便可以随意与InternLM2.5对话,同样是两下回车确定,输入exit退出。

6.2.3 以Gradio网页形式连接API服务器

保持启动23333端口的服务,在新建终端中输入exit退出。

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

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

启动后,关闭之前的cmd/powershell窗口,重开一个,再次做一下ssh转发(因为此时端口不同)。在你本地打开一个cmd或powershell窗口,输入命令如下。

ssh -CNg -L 6006:127.0.0.1:6006 root@ssh.intern-ai.org.cn -p <你的ssh端口号>

打开浏览器,访问地址http://127.0.0.1:6006,然后就可以与模型尽情对话了:
在这里插入图片描述

6.3 LMDeploy Lite

随着模型变得越来越大,我们需要一些大模型压缩技术来降低模型部署的成本,并提升模型的推理性能。LMDeploy 提供了权重量化和 k/v cache两种策略。

6.3.1 设置最大kv cache缓存大小

kv cache是一种缓存技术,通过存储键值对的形式来复用计算结果,以达到提高性能和降低内存消耗的目的。在大规模训练和推理中,kv cache可以显著减少重复计算量,从而提升模型的推理速度。理想情况下,kv cache全部存储于显存,以加快访存速度。

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

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

自 v0.4.0 起,LMDeploy 支持在线 kv cache int4/int8 量化,量化方式为 per-head per-token 的非对称量化。此外,通过 LMDeploy 应用 kv 量化非常简单,只需要设定 quant_policycache-max-entry-count参数。目前,LMDeploy 规定 quant_policy=4 表示 kv int4 量化,quant_policy=8 表示 kv int8 量化。

例如,输入以下指令,启动API服务器:

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

相比使用BF16精度的kv cache,int4的Cache可以在相同4GB的显存下只需要4位来存储一个数值,而BF16需要16位。这意味着int4的Cache可以存储的元素数量是BF16的四倍。

6.3.3 W4A16 模型量化和部署

  • W4:这通常表示权重量化为4位整数(int4)。这意味着模型中的权重参数将从它们原始的浮点表示(例如FP32、BF16或FP16,Internlm2.5精度为BF16)转换为4位的整数表示。这样做可以显著减少模型的大小。
  • A16:这表示激活(或输入/输出)仍然保持在16位浮点数(例如FP16或BF16)。激活是在神经网络中传播的数据,通常在每层运算之后产生。

使用1.8B模型进行量化:

lmdeploy lite auto_awq \/root/models/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 /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': 这个参数指定了一个校准数据集,这里使用的是’ptb’(Penn Treebank,一个常用的语言模型数据集)。
  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: 这是工作目录的路径,用于存储量化后的模型和中间结果。

等终端输出如下时,说明正在推理中,稍待片刻:

在这里插入图片描述

报错解决:

  1. 如果此处出现报错:TypeError: 'NoneType' object is not callable。原因datasets3.0 无法下载calibrate数据集,解决办法:pip install datasets==2.19.2

等待推理完成,便可以直接在你设置的目标文件夹看到对应的模型文件。

那么推理后的模型和原本的模型区别在哪里呢?最明显的两点是模型文件大小以及占据显存大小。

我们可以输入如下指令查看在当前目录中显示所有子目录的大小:

cd /root/models/
du -sh *

输出结果如下(其余文件夹都是以软链接的形式存在的,不占用空间,故显示为0):
在这里插入图片描述

那么原模型大小呢?输入以下指令查看。

cd /root/share/new_models/Shanghai_AI_Laboratory/
du -sh *

在这里插入图片描述

那么显存占用情况对比呢?

输入以下指令启动量化后的模型:在这里插入图片描述

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

显存占用情况:

对于修改kv cache默认占用之前,即如1.3 LMDeploy验证启动模型文件所示直接启动模型的显存占用情况(23GB):

  1. 在 BF16 精度下,7B模型权重占用14GB:70×10^9 parameters×2 Bytes/parameter=14GB
  2. kv cache占用8GB:剩余显存24-14=10GB,kv cache默认占用80%,即10*0.8=8GB
  3. 其他项1GB

故23GB=权重占用14GB+kv cache占用8GB+其它项1GB

对于修改kv cache占用之后的显存占用情况(19GB):

  1. bfloat16是16位的浮点数格式,占用2字节(16位)的存储空间。int4是4位的整数格式,占用0.5字节(4位)的存储空间。因此,从bfloat16到int4的转换理论上可以将模型权重的大小减少到原来的1/4,即7B个int4参数仅占用3.5GB的显存。
  2. kv cache占用16.4GB:剩余显存24-3.5=20.5GB,kv cache默认占用80%,即20.5*0.8=16.4GB
  3. 其他项约为1GB

故20.9GB=权重占用3.5GB+kv cache占用16.4GB+其它项1GB

6.3.4 W4A16 量化+ KV cache+KV cache 量化

输入以下指令,让我们同时启用量化后的模型、设定kv cache占用和kv cache int4量化:

lmdeploy serve api_server \/root/models/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

显存占用11.3GB:

在这里插入图片描述

7 LMDeploy之FastAPI与Function call

7.1 API开发

与之前一样,让我们进入创建好的conda环境并输入指令启动API服务器:

conda activate lmdeploy
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

保持终端窗口不动,新建一个终端,新建文件:

touch /root/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,  # 指定要使用的模型IDmessages=[  # 定义消息列表,列表中的每个字典代表一个消息{"role": "system", "content": "你是一个友好的小助手,负责解决问题."},  # 系统消息,定义助手的行为{"role": "user", "content": "帮我讲述一个关于狐狸和西瓜的小故事"},  # 用户消息,询问时间管理的建议],temperature=0.8,  # 控制生成文本的随机性,值越高生成的文本越随机top_p=0.8  # 控制生成文本的多样性,值越高生成的文本越多样
)# 打印出API的响应结果
print(response.choices[0].message.content)

执行代码:

conda activate lmdeploy
python /root/internlm2_5.py

终端会输出如下结果:
在这里插入图片描述

此时代表我们成功地使用本地API与大模型进行了一次对话,如果切回第一个终端窗口,会看到如下信息,这代表其成功的完成了一次用户问题GET与输出POST:
####

7.2 Function call

关于Function call,即函数调用功能,它允许开发者在调用模型时,详细说明函数的作用,并使模型能够智能地根据用户的提问来输入参数并执行函数。完成调用后,模型会将函数的输出结果作为回答用户问题的依据。

首先让我们进入创建好的conda环境并启动API服务器。

启动服务:

conda activate lmdeploy
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

让我们使用一个简单的例子作为演示。输入如下指令,新建internlm2_5_func.py,写入内容:

from openai import OpenAIdef add(a: int, b: int):return a + bdef mul(a: int, b: int):return a * btools = [{'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 /root/internlm2_5_func.py

输出结果:

在这里插入图片描述

我们可以看出InternLM2.5将输入'Compute (3+5)*2'根据提供的function拆分成了"加"和"乘"两步,第一步调用function add实现加,再于第二步调用function mul实现乘,再最终输出结果16:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/63587.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI赋能:构建安全可信的智能电子档案库

在档案的政策与法规上&#xff0c;《中华人民共和国档案法》2020年修订新增&#xff0c;对电子档案的合法要件、地位和作用、安全管理要求和信息化系统建设等方面作出了明确规定&#xff0c;保障数字资源的安全保存和有效利用。 日前&#xff0c;国家档案局令第22号公布《电子…

C++入门项目:Linux下C++轻量级Web服务器 项目详解(小白篇)

拿到一个项目首先先跑通&#xff0c;然后再慢慢来看代码&#xff0c;关于怎么将这个项目跑通&#xff0c;上一篇已经讲过&#xff0c;感兴趣的小伙伴可以移步下面的链接&#xff0c;或者其他博主的教程。 C入门项目&#xff1a;Linux下C轻量级Web服务器 跑通|运行|测试&#xf…

【Linux】开机进入grub/怎么办?

开机进入grub/怎么办&#xff1f; 1、利用ls命令查看磁盘 ls执行后提示&#xff1a; &#xff08;hd0&#xff09;&#xff08;hd0,msdo1&#xff09;&#xff08;hd0,msdo3&#xff09;&#xff08;hd0,msdo5&#xff09;(lvm-cd****-Home)(lvm-cd****-Root)2、利用cat查看f…

Java版-图论-拓扑排序与有向无环图

拓扑排序 拓扑排序说明 对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边<u,v>∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列…

前沿重器[56] | google search: 用emb模型做个性化语言prompt

前沿重器 栏目主要给大家分享各种大厂、顶会的论文和分享&#xff0c;从中抽取关键精华的部分和大家分享&#xff0c;和大家一起把握前沿技术。具体介绍&#xff1a;仓颉专项&#xff1a;飞机大炮我都会&#xff0c;利器心法我还有。&#xff08;算起来&#xff0c;专项启动已经…

【adb】iqoo系统精简垃圾内置应用

免责声明 这个得谨慎点&#xff0c;虽然我验证过两部手机和不同版本的系统&#xff0c;但是总会有特殊的存在、 本教程来自于互联网搜集整理&#xff0c; 按照本教程造成的用户设备硬件或数据损失&#xff0c;本人概不承担任何责任&#xff0c;如您不同意此协议&#xff0c;请不…

用最小的代价解决mybatis-plus关于批量保存的性能问题

1.问题说明 问题背景说明&#xff0c;在使用达梦数据库时&#xff0c;mybatis-plus的serviceImpl.saveBatch()方法或者updateBatchById()方法的时候&#xff0c;随着数据量、属性字段的增加&#xff0c;效率越发明显的慢。 serviceImpl.saveBatch(); serviceImpl.updateBatch…

使用 EasyExcel 提升 Excel 处理效率

目录 前言1. EasyExcel 的优点2. EasyExcel 的功能3. 在项目中使用 EasyExcel3.1 引入依赖3.2 实体类的定义与注解3.3 工具类方法的实现3.4 在 Controller 中使用 4. 总结5. 参考地址 前言 在日常开发中&#xff0c;Excel 文件的处理是不可避免的一项任务&#xff0c;特别是在…

Linux上的C语言编程实践

说明&#xff1a; 这是个人对该在Linux平台上的C语言学习网站笨办法学C上的每一个练习章节附加题的解析和回答 ex1: 在你的文本编辑器中打开ex1文件&#xff0c;随机修改或删除一部分&#xff0c;之后运行它看看发生了什么。 vim ex1.c打开 ex1.c 文件。假如我们删除 return 0…

Elasticsearch vs 向量数据库:寻找最佳混合检索方案

图片来自Shutterstock上的Bakhtiar Zein 多年来&#xff0c;以Elasticsearch为代表的基于全文检索的搜索方案&#xff0c;一直是搜索和推荐引擎等信息检索系统的默认选择。但传统的全文搜索只能提供基于关键字匹配的精确结果&#xff0c;例如找到包含特殊名词“Python3.9”的文…

SpringCloudAlibaba学习路线:全面掌握微服务核心组件

大家好&#xff0c;我是袁庭新。 星友给我留言说&#xff1a;“新哥&#xff0c;我最近准备开始学Spring Cloud Alibaba技术栈&#xff0c;计划冲刺明年的春招&#xff0c;想全面掌握微服务核心组件。但不知从何学起&#xff0c;没有一个有效的学习路线&#xff0c;我需要学习…

Java阶段三06

第3章-第6节 一、知识点 理解MVC三层模型、理解什么是SpringMVC、理解SpringMVC的工作流程、了解springMVC和Struts2的区别、学会使用SpringMVC封装不同请求、接收参数 二、目标 理解MVC三层模型 理解什么是SpringMVC 理解SpringMVC的工作流程 学会使用SpringMVC封装请求…

租赁系统|租赁小程序|租赁小程序成品

租赁系统是现代企业管理中不可缺少的数字化工具&#xff0c;它通过高效的信息整合与流程管理&#xff0c;为企业带来极大的便利和效益。一个完善的租赁系统开发应具备以下必备功能&#xff1a; 一、用户管理 用户管理模块负责系统的访问控制&#xff0c;包括用户注册、登录验证…

product/admin/list?page=0size=10field=jancodevalue=4562249292272

文章目录 1、ProductController2、AdminCommonService3、ProductApiService4、ProductCommonService5、ProductSqlService https://api.crossbiog.com/product/admin/list?page0&size10&fieldjancode&value45622492922721、ProductController GetMapping("ad…

java+ssm+mysql美妆论坛

项目介绍&#xff1a; 使用javassmmysql开发的美妆论坛&#xff0c;系统包含超级管理员&#xff0c;系统管理员、用户角色&#xff0c;功能如下&#xff1a; 用户&#xff1a;主要是前台功能使用&#xff0c;包括注册、登录&#xff1b;查看论坛板块和板块下帖子&#xff1b;…

Java-21 深入浅出 MyBatis - 手写ORM框架2 手写Resources、MappedStatment、XMLBuilder等

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 大数据篇正在更新&#xff01;https://blog.csdn.net/w776341482/category_12713819.html 目前已经更新到了&#xff1a; MyBatis&#xff…

专业135+总分400+华中科技大学824信号与系统考研经验华科电子信息与通信工程,真题,大纲,参考书。

考研成功逆袭985&#xff0c;上岸华科电子信息&#xff0c;初试专业课824信号与系统135&#xff0c;总分400&#xff0c;成绩还是很满意&#xff0c;但是也有很多遗憾&#xff0c;总结一下自己的复习&#xff0c;对于大家复习给些参考借鉴&#xff0c;对自己考研画个句号&#…

ElementUI:el-tabs 切换之前判断是否满足条件

<div class"table-card"><div class"card-steps-class"><el-tabsv-model"activeTabsIndex":before-leave"beforeHandleTabsClick"><el-tab-pane name"1" label"基础设置"><span slot&…

java中的数组(2)

大家好&#xff0c;我们今天继续来看java中数组这方面的知识点&#xff0c;那么话不多说&#xff0c;我们直接开始。 一.数组的使用 1.数组中元素访问 数组在内存中是一段连续的空间,空间的编号都是从0开始的,依次递增,数组可以通过下标访问其任意位置的元素. 也可以进行修改…

#渗透测试#红蓝对抗#SRC漏洞挖掘# Yakit(6)进阶模式-Web Fuzzer(下)

免责声明 本教程仅为合法的教学目的而准备&#xff0c;严禁用于任何形式的违法犯罪活动及其他商业行为&#xff0c;在使用本教程前&#xff0c;您应确保该行为符合当地的法律法规&#xff0c;继续阅读即表示您需自行承担所有操作的后果&#xff0c;如有异议&#xff0c;请立即停…