DeepGPU-LLM作为阿里云开发的一套推理引擎,旨在优化大语言模型在GPU云服务器上的推理过程,为您提供免费的高性能、低延迟推理服务。DeepGPU-LLM提供了一系列的API接口(例如模型加载、模型推理等功能),在GPU云服务器上成功安装DeepGPU-LLM后,您可以调用对应API接口进行模型推理服务,快速提高模型的推理效率和准确性。
DeepGPU-LLM是阿里云研发的基于GPU云服务器的大语言模型(Large Language Model,LLM)推理引擎。更多信息,请参见什么是推理引擎DeepGPU-LLM。
(可选)转换模型格式
使用DeepGPU-LLM时需要将huggingface
格式的开源模型转换为DeepGPU-LLM支持的格式,才能使用DeepGPU-LLM进行模型的推理优化服务。部分大语言模型的格式转换过程对CPU侧内存资源有较高要求,为了避免对CPU内存资源的高需求,您可以提前转换大语言模型格式,或者通过增加CPU内存资源(例如在Docker容器中配置--shm-size
参数来增加资源)便于加载模型时自动转换模型格式。
DeepGPU-LLM加载大语言模型时提供了模型自动转换功能,如果模型对CPU侧内存资源没有特别要求,您可以利用DeepGPU-LLM提供的API接口直接加载原始模型来自动转换模型格式。
DeepGPU-LLM提供了统一的模型转换命令huggingface_model_convert
,在使用模型转换脚本前,请先了解各参数含义:
参数名 | 说明 |
| 获得帮助信息。 |
| 待转换的原始模型路径(该模型可以从Huggingface或Modelscope平台中下载)。 |
| 格式转换后的模型所存放的路径。 |
| 期望使用多少个GPU进行推理运算。 |
| 模型使用的精度,例如fp16或bf16。 |
| 是否进行fp8量化。 |
| fp8量化时使用的标定数据目录。 |
| gptq和awq量化时需要配置量化类型。取值范围:
|
| 模型自定义的名称,可任意填写。 |
| 处理模型转换所使用的CPU线程数。 |
示例1:对llama2-7b-chat模型的转换命令
huggingface_model_convert --in_file /mnt/models/Llama-2-7b-chat-hf/ --saved_dir /mnt/models_deepgpu/llama2-7b-chat --weight_data_type fp16 --model_name llama2-7b --infer_gpu_num 1
示例2:对通义千问qwen2-7b-instruct模型的转换命令
huggingface_model_convert --in_file /mnt/models/Qwen2-7B-Instruct --saved_dir /mnt/models_deepgpu/Qwen2-7B-Instruct --weight_data_type fp16 --model_name qwen2-7b --infer_gpu_num 1
如果无法找到huggingface_model_convert
命令,说明DeepGPU版本较老,您可以升级当前DeepGPU-LLM版本,具体操作,请参见(可选)升级DeepGPU-LLM;或者根据LLM模型类型,将model
字段替换为具体的LLM名称,然后进行模型转换,具体查看help
调整相应参数。
DeepGPU-LLM的API接口说明
模型加载函数
DeepGPU-LLM提供统一的模型处理类deepgpu_model
,具体接口代码如下。其中,该模型处理类包含模型加载函数__init__
函数和from_pretrained
函数。
加载函数介绍
class deepgpu_model(torch.nn.Module):
def __init__(self, model_path: str, tensor_para_size: int, precision: int = 0,
kv_cache_quant_level: int = 0,
generation_config: typing.Optional[DeepGPUGenerationConfig] = None,
is_gemm_tuning: bool = False,
load_pretrained: bool = False,
page_size: int = 16,
gpu_utilization: float = 0.9,
max_batch_size : int = 128,
max_context_token_num: int = 8192,
session_len: int = 2048)
@classmethod
def from_pretrained(cls, model_path, tensor_para_size, precision = 0,
kv_cache_quant_level: int = 0,
generation_config: typing.Optional[DeepGPUGenerationConfig] = None,
page_size: int = 16,
gpu_utilization: float = 0.9,
max_batch_size : int = 128,
max_context_token_num: int = 8192,
session_len: int = 2048,
data_set = None)
__init__
函数:用于加载已转换好格式的模型。具体参数介绍如下:参数名
说明
model_path
指向格式已转换好的模型目录。
说明一般为
x-gpu
目录,其中x为多少个GPU,模型转换时自动生成的目录。tensor_para_size
使用的GPU数量,需要与模型转换设置的GPU数量保持一致。
precision
权重量化级别。取值范围:
0:表示fp16精度。
1:表示int8量化。
3:表示int4量化。
5:表示fp8精度。
默认值:0。
kv_cache_quant_level
kv_cache量化级别。取值范围:
0:表示无量化压缩。
1:表示K8_V8量化,推荐值。
2:表示K8_V4量化。
3:表示K4_V4量化。
默认值:0。
generation_config
模型配置参数。更多信息,请参见模型参数类(DeepGPUGenerationConfig)。
说明若不设置该参数,则会加载模型配置文件中的默认参数。
is_gemm_tuning
是否优化最佳Kernel,常见GPU的最佳Kernel已优化好并存储于安装包内。取值范围:
False:不优化最佳Kernel。
True:优化最佳Kernel。
默认值:False。
load_pretrained
加载的模型是否为原始模型。取值范围:
False:表示加载格式已转换好的模型。
True:表示需要加载格式未转换的原始模型,不可直接调用,主要是提供
from_pretrained
函数内部调用以实现从原始模型加载的功能。
默认值:False。
page_size
page attention所使用的内存块大小。
gpu_utilization
GPU显存容量使用比例。
max_batch_size
能够同时处理的最大请求数。
说明若资源不足以支持配置的值,系统也会根据GPU显存资源进行调整。
max_context_token_num
上下文限制的最大Token数量,该值不能小于
session_len
值。session_len
对话长度限制,即输入和输出的Tokens数量。
若该值超过
session_len
默认值,则需要配置该参数。data_set
配置fp8量化使用的标定数据目录。
若不使用fp8精度,则不需要设置该参数。
from_pretrained
函数:直接加载从huggingface和modelscope平台上下载的开源模型,加载过程中支持在线自动转换模型。该函数是一个classmethod类型的函数,会在内部调用
__init__
创建一个deepgpu_model
类,可以从原始模型目录加载模型,进行模型转换并进行初始化。关于from_pretrained
函数的具体参数介绍,请参见上表中的__init__
函数具体参数介绍。
加载函数使用说明
通过
deepgpu_model
类的__init__
函数来加载模型。从
deepgpu_llm.deepgpu_model
模块中导入deepgpu_model
类,然后调用deepgpu_model
类进行模型初始化,此时输入的args.model_dir
指向格式转换好的模型目录。示例代码如下:from deepgpu_llm.deepgpu_model import deepgpu_model model = deepgpu_model(model_path = args.model_dir, tensor_para_size = args.tpsize, precision = precision, kv_cache_quant_level = args.kv_cache_quant_level, gpu_utilization = args.gpu_utilization, session_len = max_inout_len, max_context_token_num = max_context_token_num)
通过
deepgpu_model
类的from_pretrained
函数来创建模型类并加载原始模型。调用
deepgpu_model.from_pretrained
函数来创建模型类并加载原始模型,在线转换模型并进行初始化,此时args.model_dir
指向huggingface或modelscope的原始模型目录。示例代码如下:from deepgpu_llm.deepgpu_model import deepgpu_model model = deepgpu_model.from_pretrained(model_path = args.model_dir, tensor_para_size = args.tpsize, precision = precision, kv_cache_quant_level = args.kv_cache_quant_level, gpu_utilization = args.gpu_utilization, session_len = max_inout_len, max_context_token_num = max_context_token_num)
模型推理函数
DeepGPU-LLM提供了丰富的推理API接口,您可以根据实际需求选择离线模式(offline)或在线模式(serving)调用API接口。
模型推理离线模式(offline)
推理API函数(offline)分为普通输出函数(一次性输出)和流式输出函数。
普通输出函数generate(一次性输出)
普通输出函数直接返回输出结果,输出结果有多层封装,较为复杂,实际使用时建议打印出进行逐层拆解,最终获得需要的输出信息。普通输出函数generate定义如下:
def generate(self, input_ids, generation_config: typing.Optional[DeepGPUGenerationConfig] = None)
调用
model.generate
执行模型推理时,generation_config
参数通过模型参数类(DeepGPUGenerationConfig)进行设置,更多信息,请参见常用类介绍。调用generate的代码如下所示:inputs = [] inputs.append(tokenizer(query, return_tensors='pt').input_ids) generation_config = DeepGPUGenerationConfig(max_new_tokens = args.output_tokens, top_k = args.top_k, top_p = args.top_p, temperature = args.temperature, repetition_penalty = args.repetition_penalty) output = model.generate(inputs, generation_config) outputX = output[0].tolist() outputY = outputX[0][0][inputs[0].shape[1]:] response = tokenizer.decode(outputY)
参数名
说明
inputs
输入参数,是一个
tokenizer
转换后的token ids的数组。query为实际输入的文本,若有多个输入,可以对所有输入进行token转换,并添加到
inputs
数组中。output
输出参数,需要进行多层拆解以获得
outputY
为实际输出的token ids,然后调用tokenizer.decode
函数解析转换为文本结果。说明若有多个输入,输出也会有多个,您可以通过
outputX[batch_id][0]
来定位对应的输出。流式输出函数(stream_generate)
流式输出可以根据实际推理生成进程,实时地将输出的内容展示给用户。流式输出函数stream_generate定义如下:
def stream_generate(self, input_ids, generation_config: typing.Optional[DeepGPUGenerationConfig] = None, skip_inputs = False)
stream_generate是各模型类的成员函数,具体参数说明:
参数名
说明
input_ids
输入参数,为模型构造输入数据,更多信息,请参见普通输出函数generate(一次性输出)。
generation_config
运行参数。具体参数定义,请参见常用类介绍。
skip_inputs
用于配置是否在生成的输出中屏蔽输入内容。取值范围:
True:屏蔽输出内容。
False:显示输出内容。
调用stream_generate的代码如下所示,首先需要调用
DeepGPUStreamer
构建一个streamer
,然后启动stream_generate
函数开始推理,此时程序返回并继续实时监控最新的生成结果,然后进行实时输出。streamer = DeepGPUStreamer(tokenizer, **{'skip_special_tokens':True}) total_len = 0 response = "" for output in model.stream_generate(inputs, generation_config=generation_config, skip_inputs=True): printable_str = streamer.handel_str(output) response = response + printable_str total_len += 1 yield { "text": response, "prompt_tokens": input_echo_len, "completion_tokens": total_len, "total_tokens": total_len, "finish_reason": None, }
参数名
说明
printable_str
当前时刻生成的token对应的文本。
response
将所有前序生成的文本进行归集。
total_len
统计实际生成的tokens数。
模型推理在线模式(serving)
该模式适用于多用户多请求场景,通过提供3个并发调用函数来适配不同的代码工程场景。其中,并发调用函数包括普通调用函数、async调用函数以及含request_id的async调用函数。
普通调用函数(generate_cb)
上层调用函数为普通函数(非async函数)时,可以调用
generate_cb
函数。普通调用函数定义如下:def generate_cb(self, input_ids, generation_config: typing.Optional[DeepGPUGenerationConfig] = None)
参数名
说明
input_ids
输入参数,为模型构造输入数据,更多信息,请参见普通输出函数generate(一次性输出)。
generation_config
模型推理使用的参数。
调用
generate_cb
函数的代码示例如下所示,启动model.generate_cb
进行模型推理后,程序会返回执行结果,通过监控实时输出的tokens,将当前输出文本printable_str
整合成response
(即输出文本)。streamer = DeepGPUStreamer(tokenizer, **{'skip_special_tokens':True}) total_len = 0 response = "" results_generator = model.generate_cb(inputs, generation_config=generation_config) for request_output in results_generator: if(request_output==-1): printable_str = streamer.end() else: printable_str = streamer.handel_str(request_output) response = response + printable_str total_len += 1 yield { "text": response, "prompt_tokens": input_echo_len, "completion_tokens": total_len, "total_tokens": total_len, "finish_reason": None, }
async调用函数(generate_cb_async)
上层调用函数是async函数,可以调用
generate_cb_async
,async调用函数定义如下:async def generate_cb_async(self, input_ids, generation_config: typing.Optional[DeepGPUGenerationConfig] = None)
调用
generate_cb_async
函数的代码示例如下所示,该函数与generate_cb
函数的用法基本一致,但您需要使用async for进行循环,监控最新结果token的生成。streamer = DeepGPUStreamer(tokenizer, **{'skip_special_tokens':True}) total_len = 0 response = "" results_generator = model.generate_cb_async(inputs, generation_config=generation_config) async for request_output in results_generator: if(request_output==-1): printable_str = streamer.end() else: printable_str = streamer.handel_str(request_output) response = response + printable_str total_len += 1 yield { "text": response, "prompt_tokens": input_echo_len, "completion_tokens": total_len, "total_tokens": total_len, "finish_reason": None, }
含request_id的async调用函数(generate_cb_async_id)
如果您需要对请求数量和请求ID进行管控,可以调用
generate_cb_async_id
函数,该函数的参数与generate_cb_async
相似,配置了额外的变量request_id
,用于区分不同请求及其结果生成。含request_id的async调用函数定义如下:async def generate_cb_async_id(self, input_ids, request_id: int = 0, generation_config: typing.Optional[DeepGPUGenerationConfig] = None)
调用
generate_cb_async_id
函数的代码示例如下所示,调用该代码时,请参考请求ID处理类(RequestCounter)的RequestCounter
类对request_id
进行管理和操纵。from deepgpu_llm.deepgpu_utils import DeepGPUGenerationConfig,DeepGPUStreamer,RequestCounter counter = RequestCounter() streamer = DeepGPUStreamer(tokenizer, **{'skip_special_tokens':True}) request_id = next(counter) total_len = 0 response = "" results_generator = model.generate_cb_async(inputs, generation_config=generation_config) async for request_output in results_generator: if(request_output==-1): printable_str = streamer.end() else: printable_str = streamer.handel_str(request_output) response = response + printable_str total_len += 1 yield { "text": response, "prompt_tokens": input_echo_len, "completion_tokens": total_len, "total_tokens": total_len, "finish_reason": None, }
常用类介绍
deepgpu_utils.py
通常提供一些实用的函数和工具,以支持DeepGPU-LLM的推理API接口,deepgpu_utils.py
定义了一些常用类,例如,模型参数类(DeepGPUGenerationConfig)、并发流处理类(DeepGPUStreamer)以及请求ID处理类(RequestCounter)。这些类可以管理模型的运行环境、处理并发请求以及跟踪请求的执行情况,您可以通过以下代码将这些类导入至deepgpu_utils.py
中。
from deepgpu_llm.deepgpu_utils import DeepGPUGenerationConfig, DeepGPUStreamer, RequestCounter
模型参数类(DeepGPUGenerationConfig)
DeepGPUGenerationConfig
类主要用于给模型传递推理运行相关参数,详见以下代码。具体参数可以不设置,DeepGPU-LLM会自动从模型配置文件里获取相关初始参数。class DeepGPUGenerationConfig(): def __init__(self, **kwargs): self.max_new_tokens = kwargs.pop("max_new_tokens", 512) self.do_sample = kwargs.pop("do_sample", None) self.num_beams = kwargs.pop("num_beams", None) self.temperature = kwargs.pop("temperature", None) self.top_k = kwargs.pop("top_k", None) self.top_p = kwargs.pop("top_p", None) self.repetition_penalty = kwargs.pop("repetition_penalty", None) self.presence_penalty = kwargs.pop("presence_penalty", None) self.len_penalty = kwargs.pop("len_penalty", None) self.beam_search_diversity_rate = kwargs.pop("beam_search_diversity_rate", None) self.min_tokens = kwargs.pop("min_tokens", 0)
并发流处理类(DeepGPUStreamer)
DeepGPUStreamer
类用于处理大语言模型的流式输出和多请求输出,详见以下代码。class DeepGPUStreamer(): def __init__(self, tokenizer: "AutoTokenizer", skip_prompt: bool = False, print_out: bool = True, **decode_kwargs) def handle_str(self, value) def end(self)
函数名
说明
__init__()
初始化内部使用到的tokenizer和用于打印的字符串缓存区。
handle_str()
接受一个token id,并转换为自然语言文本,然后放入字符串缓存区中,返回字符串缓存区中可以打印的字符串。
end()
返回字符串缓存区中剩余的字符串。
请求ID处理类(RequestCounter)
RequestCounter
类主要用于多请求场景中的request_id管理,详见以下代码。class RequestCounter: def __init__(self, start: int = 0) -> None def __next__(self) -> int def reset(self) -> None def add(self, len: int) -> int def cur(self) -> int
函数名
说明
__init__()
对
RequestCounter
类进行初始化,默认值为0,您也可以通过设置start
值对类进行初始化。__next__()
获取当前counter值,并对内部的counter累加1。
reset()
内部的counter重置为0,以便从头开始生成请求ID。
add()
返回内部原始counter值,然后将counter加上len作为新值。
cur()
获取当前counter值,不进行其他操作。
DeepGPU-LLM实例代码
本文提供了一系列DeepGPU-LLM的参考代码,帮助您更快速地上手进行编程开发。
离线(offline)代码示例
简单Llama模型示例
本示例以llama2-7b-chat模型为例,运行以下deepgpu-llm实例代码前,请确保您已经对lama2-7b-chat模型进行模型转换操作,同时,您也可以根据实际情况调整模型目录、GPU数量、量化精度等参数。
import time from deepgpu_llm.deepgpu_model import deepgpu_model from deepgpu_llm.deepgpu_utils import DeepGPUGenerationConfig from transformers import LlamaTokenizer model_path = '/mnt/models_deepgpu/llama2-7b-chat' tokenizer = LlamaTokenizer.from_pretrained(model_path) model_path_conv = "/mnt/models_deepgpu/llama2-7b-chat/1-gpu" tensor_para_size = 1 precision = 0 # 0:fp16 mode, 1:int8 mode, 3:int4 mode kv_cache_quant_level = 0 # 0:no quant, 1:K8_V8, 2:K8_v4, 3:K4_V4 generation_config = DeepGPUGenerationConfig(max_new_tokens=512) model = deepgpu_model(model_path_conv, tensor_para_size, precision, kv_cache_quant_level, generation_config=generation_config) payload = "Hi, please introduce the alibaba?" start_ids = [tokenizer(payload, return_tensors="pt").input_ids] print(payload) for i in range(5): s = time.time() output = model.generate(start_ids, generation_config) e = time.time() print("---- time", e - s) tokens = output[0].tolist() for i in range(len(tokens)): print(tokenizer.decode(tokens[i][0]))
运行上述实例代码后,显示结果如下所示:
流式输出Qwen模型示例
本示例以单卡GPU上运行qwen-7b模型的实例代码为例,您可以调整代码中
precision
量化精度、kv_cache_quant_level
量化级别、tp_size
GPU数量,获得更快的性能和减少GPU显存占用。运行下列代码后将结果流式打印输出,并统计性能。import time from deepgpu_llm.deepgpu_model import deepgpu_model from deepgpu_llm.deepgpu_utils import DeepGPUGenerationConfig, DeepGPUStreamer from transformers import AutoTokenizer model_path = "/mnt/models_deepgpu/Qwen2-7B-Instruct" tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True) model_path_conv = "/mnt/models_deepgpu/Qwen2-7B-Instruct/1-gpu" tp_size = 1 # tensor parallel precision = 0 # 0:fp16 mode, 1:int8 mode, 3:int4 mode kv_cache_quant_level = 0 # 0:no quant, 1:K8_V8, 2:K8_v4, 3:K4_V4 generation_config = DeepGPUGenerationConfig(max_new_tokens=512) model = deepgpu_model(model_path_conv, tp_size, precision, kv_cache_quant_level, generation_config=generation_config) print("model init over!") payload = "<|im_start|>user\n 你好,请介绍下杭州的旅游景区? <|im_end|>\n<|im_start|>assistant\n" start_ids = tokenizer(payload, return_tensors="pt").input_ids streamer = DeepGPUStreamer(tokenizer, **{'skip_special_tokens':True}) total_len = 0 response = "" print("response : ") start = time.time() for output in model.stream_generate([start_ids], generation_config=generation_config, skip_inputs=True): printable_str = streamer.handel_str(output) #response = response + printable_str total_len += 1 print(printable_str, flush=True, end = "") end = time.time() print() print() print("time : ", (end - start)) print("speed: ", total_len/(end - start), " tokens/s")
运行上述实例代码,输出结果如下所示。问题回复结果是流式输出的,此时您可以体验到DeepGPU-LLM推理速度了。
说明如需查看其他类型LLM模型的流式输出实例代码,您可以通过执行以下命令直接查看DeepGPU-LLM的安装目录,找到
llama_cli
、chatglm_cli
、baichuan_cli
和qwen_cli
脚本,即可查看相应代码。pip show -f deepgpu-llm
多batch同时输入的示例
针对于多batch场景,关键是处理输入和输出,各类模型输入输出的处理方法,请参见普通输出函数generate(一次性输出)。
import time from deepgpu_llm.deepgpu_model import deepgpu_model from deepgpu_llm.deepgpu_utils import DeepGPUGenerationConfig from transformers import AutoTokenizer model_path = "/mnt/models_deepgpu/Qwen1.5-72B-Chat" tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True) model_path_conv = "/mnt/models_deepgpu/Qwen1.5-72B-Chat/4-gpu" tp_size = 4 # tensor parallel precision = 0 # 0:fp16 mode, 1:int8 mode, 3:int4 mode kv_cache_quant_level = 0 # 0:no quant, 1:K8_V8, 2:K8_v4, 3:K4_V4 generation_config = DeepGPUGenerationConfig(max_new_tokens=512) model = deepgpu_model(model_path_conv, tp_size, precision, kv_cache_quant_level, generation_config=generation_config) print("model init over!") prompt =["你好,你是谁?", "你好,请介绍下杭州的旅游景区?", "你好,请介绍下北京的旅游景区?", "你好,请介绍下新疆的旅游景区?", "你好,请介绍下西藏的旅游景区?"] batchsize = len(prompt) start_ids = [] for bs in range(batchsize): payload = "<|im_start|>user\n " + prompt[bs] + "<|im_end|>\n<|im_start|>assistant\n" start_ids.append(tokenizer(payload, return_tensors="pt").input_ids) output = model.generate(start_ids, generation_config) tokens = output[0].tolist() for bs in range(batchsize): response = tokenizer.decode(tokens[bs][0], skip_special_tokens=True) print("response [", bs, "] : ", response.rstrip(tokenizer.decode(0)))
运行上述代码,输出结果如下所示:
在线(serving)代码示例
服务端代码示例
执行deepgpu fastapi_server.py脚本文件,实现接收文本生成请求,使用DeepGPU模型进行文本生成,并返回生成的文本。
import argparse import json from typing import AsyncGenerator from fastapi import FastAPI, Request from fastapi.responses import JSONResponse, Response, StreamingResponse import uvicorn from deepgpu_llm.deepgpu_model import deepgpu_model from deepgpu_llm.deepgpu_utils import DeepGPUGenerationConfig,DeepGPUStreamer,RequestCounter from transformers import AutoTokenizer import time TIMEOUT_KEEP_ALIVE = 5 # seconds. TIMEOUT_TO_PREVENT_DEADLOCK = 1 # seconds. app = FastAPI() engine = None counter = RequestCounter() tokenizer = None @app.get("/health") async def health() -> Response: """Health check.""" return Response(status_code=200) @app.post("/generate") async def generate(request: Request) -> Response: request_dict = await request.json() prompt = request_dict.pop("prompt") max_new_token = request_dict.pop("max_tokens") prompt = [tokenizer(prompt, return_tensors='pt').input_ids] stream = request_dict.pop("stream", True) streamer = DeepGPUStreamer(tokenizer=tokenizer) generation_config = DeepGPUGenerationConfig(max_new_tokens = max_new_token) results_generator = engine.generate_cb_async(prompt,generation_config=generation_config) # Streaming case async def stream_results() -> AsyncGenerator[bytes, None]: # await asyncio.sleep(0) async for request_output in results_generator: if(request_output==-1): printable_str = streamer.end() text_outputs = [ printable_str ] ret = {"text": text_outputs} yield (json.dumps(ret) + "\0").encode("utf-8") break else: printable_str = streamer.handel_str(request_output) text_outputs = [ printable_str ] ret = {"text": text_outputs} yield (json.dumps(ret) + "\0").encode("utf-8") if stream: return StreamingResponse(stream_results()) # Non-streaming case total_str = "" async for request_output in results_generator: if(request_output == -1): total_str += streamer.end() break else: total_str += streamer.handel_str(request_output) ret = {"text": total_str} return JSONResponse(ret) if __name__ == "__main__": parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter) parser.add_argument("--host", type=str, default=None) parser.add_argument("--port", type=int, default=8000) parser.add_argument('--model_dir', '-i', type=str, help='converted model dir', required=True) parser.add_argument('--tokenizer_dir', '-t', type=str, help='tokenizer dir', required=False) parser.add_argument('--tp_size', '-tp', type=int, help='tensor para size', required=True) args = parser.parse_args() tokenizer = AutoTokenizer.from_pretrained(args.tokenizer_dir, trust_remote_code=True) model_path = args.model_dir tp_size = args.tp_size precision = 0 # 0:fp16 mode, 1:int8 mode, 3:int4 mode engine = deepgpu_model(model_path, tp_size, precision,is_gemm_tuning=False) uvicorn.run(app, host=args.host, port=args.port, log_level="debug", timeout_keep_alive=TIMEOUT_KEEP_ALIVE)
继续运行以下命令,启动服务。
python3 fastapi_server.py -i /mnt/models_deepgpu/Qwen2-7B-Instruct/1-gpu -t /mnt/models_deepgpu/Qwen2-7B-Instruct -tp 1
如果显示以下结果,表示该服务搭建成功。
说明DeepGPU兼容vLLM的serving实现,您可以直接使用vLLM的官方代码
benchmark_serving.py
作为参考,仅需将其内部的import vllm
更改为import deepgpu
即可。更多信息,请参见更多示例(将vLLM切换为DeepGPU-LLM推理引擎)。客户端python代码
本示例以一个异步的Python脚本为例,实现向一个HTTP服务发送请求,获取文本生成的流式响应,并打印这些响应的功能。
import requests import json import time import aiohttp import asyncio import random import os url = "http://0.0.0.0:8000/generate" # 普通服务模式 # url = "http://0.0.0.0:8000/v1/completions" # openai接口普通服务模式 headers = {"User-Agent": "Benchmark Client"} # 普通服务模式 # headers = { # "Authorization": f"Bearer {os.environ.get('OPENAI_API_KEY')}" #openai接口普通服务模式 # } async def stream_back(data): async with aiohttp.ClientSession() as session: async with session.post(url, headers=headers, data=json.dumps(data)) as response: if response.status == 200: async for chunk, _ in response.content.iter_chunks(): chunk = chunk.rstrip(b'\x00') decoded_chunk = chunk.decode('utf-8') if(not decoded_chunk.strip()): continue try: data = json.loads(decoded_chunk) text_content = data.get('text', []) for text in text_content: if text: print(text,flush=True,end='') continue except json.JSONDecodeError as e: print("JSON decode error! error code:", e) async def fetch_stream(prompt: str): max_tokens = 512 # open ai服务使用的data # data = { # "model": '/root/models/Llama-2-7b-chat-hf/', # "prompt": prompt, # "temperature": 0.0, # "best_of": 1, # "max_tokens": 512, # "stream": True, # } # 普通服务使用的data print("[prompt]: ", prompt) data = {"prompt": prompt, "max_tokens": max_tokens, "stream": True} async with aiohttp.ClientSession() as session: start_time = time.time() await stream_back(data) # await none_stream_back(data) end_time = time.time() latency = end_time - start_time print() print(f"Latency: {latency} seconds") async def main(prompt_num): prompt =["你好,你是谁?", "请介绍下杭州的旅游景区?", "请介绍下北京的旅游景区?", "请介绍下杭州的历史变迁?", "你知道BAT吗?", "考上大学后,需要如何填报志愿?", "介绍下浙江最好的几所大学?"] tasks = [fetch_stream(prompt[random.randint(0,len(prompt)-1)]) for _ in range(prompt_num)] await asyncio.gather(*tasks) if __name__ == "__main__": asyncio.run(main(1))
运行上述代码后,显示结果如下所示:
客户端curl命令
启动服务后,执行以下命令给服务端发送请求,实现一段文本的输出。
curl -X POST "http://0.0.0.0:8000/generate" \ -H "Content-Type: application/json" \ -H "User-Agent: Benchmark Client" \ -d '{"prompt": "请介绍下杭州的历史变迁?", "stream": false, "max_tokens": 128}'
说明curl命令交互不支持流式输出,stream只能设置为false。
运行以上命令后,显示结果如下所示:
更多示例(将vLLM切换为DeepGPU-LLM推理引擎)
DeepGPU-LLM提供了类似vLLM的接口,如果您需要在不改变现有vLLM代码结构的情况下,基于开源vLLM代码切换为DeepGPU-LLM推理引擎,实现DeepGPU-LLM带来的性能提升和功能扩展,请参考以下两种方式的推理示例:
兼容vLLM的DeepGPU-LLM推理示例(offline)
获取vLLM的离线推理示例。
offline_inference.py示例如下:
from vllm import LLM, SamplingParams # Sample prompts. prompts = [ "Hello, my name is", "The president of the United States is", "The capital of France is", "The future of AI is", ] # Create a sampling params object. sampling_params = SamplingParams(temperature=0.8, top_p=0.95) # Create an LLM. llm = LLM(model="facebook/opt-125m") # Generate texts from the prompts. The output is a list of RequestOutput objects # that contain the prompt, generated text, and other information. outputs = llm.generate(prompts, sampling_params) # Print the outputs. for output in outputs: prompt = output.prompt generated_text = output.outputs[0].text print(f"Prompt: {prompt!r}, Generated text: {generated_text!r}")
基于vLLM示例将推理引擎更改为DeepGPU示例。
修改以下代码完成推理引擎切换,即将导入包由
vllm
改为deepgpu_llm
,模型文件改为转换后的DeepGPU模型文件。# from vllm import LLM, SamplingParams 更改为: from deepgpu_llm import LLM, SamplingParams # llm = LLM(model="facebook/opt-125m") 更改为 llm = LLM("path/to/your/deepgpu_model")
兼容vLLM的DeepGPU-LLM多请求推理示例(serving)
在线获取vLLM的推理示例。
获取路径:api_server。
基于vLLM示例将推理引擎更改为DeepGPU示例。
修改以下代码,即将
vllm
在线代码更改为deepgpu_llm
相关示例。# from vllm.engine.arg_utils import AsyncEngineArgs 更改为: from deepgpu_llm.engine.arg_utils import AsyncEngineArgs # from vllm.engine.async_llm_engine import AsyncLLMEngine 更改为: from deepgpu_llm.engine.async_llm_engine import AsyncLLMEngine # from vllm.sampling_params import SamplingParams 更改为: from deepgpu_llm.sampling_params import SamplingParams # from vllm.usage.usage_lib import UsageContext 更改为: from deepgpu_llm.usage.usage_lib import UsageContext # from vllm.utils import random_uuid 更改为: from deepgpu_llm.utils import random_uuid
启动基于DeepGPU-LLM的API服务器,该服务器可以提供模型推理服务。
# 拉起普通服务: python3 -m deepgpu_llm.entrypoints.api_server \ --model <your model> \ --trust-remote-code \ --tensor-parallel-size tp_tpsize \ --gpu-memory-utilization 0.95 # 拉起openai接口服务 python3 -m deepgpu_llm.entrypoints.openai.api_server \ --model <YOUR_MODEL> \ --trust-remote-code \ --tensor-parallel-size tp_tpsize \ --gpu-memory-utilization 0.95
使用
benchmark_serving.py
脚本和ShareGPT数据集进行推理性能基准测试。python3 benchmark_serving.py \ --backend vllm \ --model /root/deepgpu/models/qwen1.5-7b \ --tokenizer /root/deepgpu/models/qwen1.5-7b \ --dataset-name sharegpt \ --dataset-path ShareGPT_V3_unfiltered_cleaned_split.json \ --request-rate 30 \ --num-prompts 2000 \ --port 8000