linux部署Mixtral-8x7B-Instruct实践(使用vLLM/ transformer+fastapi)
Linux下用vLLM本地部署Mixtral-8x7B-instruct,部署成功
前提说明:
- 这次实践用了两张A800(80G),每张卡消耗70G显存,总计140G
step1:下载模型
从huggingface(需科学上网)和modelscope两个平台下载模型
step2:安装vLLM
之前部署大模型用transformer库+OpenAI api,会有推理速度慢,server部署起来比较复杂的缺点,vLLM是一个LLM推理和服务库,原理类似于操作系统的虚拟内存。
现在说怎么安装,安装很简单
pip install vLLM
要安装3G左右的包。
#step3 使用vLLM部署Mixtral 8*7b(重点)
先丢一串命令
python -u -m vllm.entrypoints.openai.api_server --host 0.0.0.0 --model /data/models/Mixtral-8x7B-Instruct-v0.1 --tensor-parallel-size 2
别着急,一个一个解释,先说跟python命令相关的,-u
指python输出不缓冲,-m
告诉python运行一个库模块,--host
指定服务器监听的主机地址,--model
指定要使用的模型的路径,--tensor-parallel-size
使得模型的张量可以分布在两个及以上GPU上,一张80G的A800放不下Mixtral 8*7b的参数(140),指定tensor-parallel-size=2
将参数拆到两块上面,一张卡70G。
--host 0.0.0.0
允许任何IP地址的设备都能访问这个服务--port
指定服务端口,默认是8000
--model /data/models/Mixtral-8x7B-Instruct-v0.1
可以是模型名称或者本地路径。指定咱们使用Mixtral-8x7B-Instruct-v0.1
模型,注意这里指定了模型所在路径,如果模型需要在线下载,直接指定模型名称,超大模型不建议在线下载,因为不稳定,而且代理没有那么多流量啊。--tensor-parallel-size 2
指定张量并行的GPU数量,Mixtral模型有32个注意力头,必须均匀的分在GPU中,所以必须是32的因数(2、4、8、16),否则会报ValueError: Total number of attention heads (32) must be divisible by tensor parallel size (3).
错误
其他没有用到的参数:
--chat-template
聊天的模板,用户的输入+模板=最后的prompt--trust-remote-code
默认为false,如果人为修改过下载后的模型的话,会报错,建议设置成True--download-dir
在线下载模型权重时,指定的下载路径,默认是~/.cache
--worker-use-ray
是否用ray来实现分布式推理服务,在GPU>2时默认开启--gpu-memory-utilization
GPU的利用率,0~1之间,默认是0.9,比如我是两张80G的卡,参数0.9,每张卡最高使用72G显存。如果显卡多,4张80G的卡,参数设置成0.5,就是每张显卡最多占40G显存,需要4张卡才能跑。感觉用不到,设置成0.5四张卡,不如0.9两张卡,还能有两张卡空闲着,除非四张卡的并行推理能提高推理速度。
step4 发请求
用requests
库来模拟请求。model
换成模型的目录
import requests
import json
# 定义请求的 URL 和数据
url = "http://<IP>:8000/v1/completions"
data = {
"model": "/data/models/Mixtral-8x7B-Instruct-v0.1",
"prompt": "请介绍一下AI的发展历史,AI的未来会如何发展?",
"max_tokens": 1000,
"temperature": 0.2
}
# 发送 POST 请求
response = requests.post(url, json=data)
# 检查响应
if response.status_code == 200:
print("请求成功!")
print("响应内容:", response.json()['choices'][0]["text"])
else:
print("请求失败,状态码:", response.status_code)
解释一下参数:
max-tokens
:inputs_tokens+response_tokens的最大值,这里设置成1000temperature
:温度越低,选可能性更高的token作为response,也就是回答越精炼、准确、字数越少。反之,更有多样性、发散、字数更多。建议值是0.2~1,如果设置成0,会导致每次询问都是同样的回答。
总结
vLLM作为一个推理和部署库,一条命令就能部署大模型推理服务。覆盖了用transformer和openapi或者FastAPI部署服务的过程,用起来很方便。
使用Transformer+fastapi
Step1:从本地加载模型
model_id = "/data/models/Mixtral-8x7B-Instruct-v0.1"
tokenizer = AutoTokenizer.from_pretrained(model_id, padding_side='left')
model = AutoModelForCausalLM.from_pretrained(model_id, torch_dtype=torch.float16, device_map="auto")
float16
精度下只能在GPU上推理,占用显存90G
device_map="auto"
自动把模型的不同层放到三块GPU上。
Step2:构造prompt模板
参考:huggingface Mixtral-8x7B-Instruct-v0.1主页 Instruction format部分
prompt必须严格遵循下面的格式,否则模型会胡言乱语(盲猜模型训练格式就是这个)
<s> [INST] Instruction [/INST] Model answer</s> [INST] Follow-up instruction [/INST]
def add_template_to_prompt(prompt):
# prompt_templated = f"<s> [INST] {prompt} [/INST] Model answer </s> [INST] Follow-up instruction [/INST]"
prompt_templated = f"<s> [INST] {prompt} [/INST] </s>"
return prompt_templated
Step3: fastapi
app = FastAPI()
@app.post("/v1/completions")
async def chat(argument: ModelAugument):
prompt_templated = add_template_to_prompt(argument.prompt)
inputs = tokenizer(text=prompt_templated, return_tensors="pt")
outputs = model.generate(**inputs, max_new_tokens=argument.max_tokens)
outputs_text = tokenizer.decode(outputs[0], skip_special_tokens=True)
return outputs_text[outputs_text.find("[/INST]") + 7:] # truncate the prompt(as prefix)
Mixtral的又把prompt作为前缀输出了一遍,在Mistral的回答中prompt后面的才是真正的回答,所以做了个截断。举个例子:
prompt:
你好
模板化后:
<s> [INST] 你好 [/INST] </s>
Mistral回答
[INST] 你好 [/INST] Hello! 你需要什么帮助吗?(Hello! Do you need any help?)
完整代码:
from transformers import AutoTokenizer, AutoModelForCausalLM
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
model_id = "/data/models/Mixtral-8x7B-Instruct-v0.1"
tokenizer = AutoTokenizer.from_pretrained(model_id, padding_side='left')
model = AutoModelForCausalLM.from_pretrained(model_id)
class ModelAugument(BaseModel):
prompt: str
temperature: float
max_tokens: int
def add_template_to_prompt(prompt):
# prompt_templated = f"<s> [INST] {prompt} [/INST] Model answer </s> [INST] Follow-up instruction [/INST]"
prompt_templated = f"<s> [INST] {prompt} [/INST] </s>"
return prompt_templated
@app.post("/v1/completions")
async def chat(argument: ModelAugument):
prompt_templated = add_template_to_prompt(argument.prompt)
inputs = tokenizer(text=prompt_templated, return_tensors="pt")
outputs = model.generate(**inputs, max_new_tokens=argument.max_tokens)
outputs_text = tokenizer.decode(outputs[0], skip_special_tokens=True)
# outputs_text = outputs_text[outputs_text.find("[/INST]") + 7:] # truncate the prompt(as prefix)
return outputs_text
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)