DeepGPU-LLM的API接口说明及示例

2025-07-07   访问量:1002


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,在使用模型转换脚本前,请先了解各参数含义:



参数名

说明

-h--help

获得帮助信息。

--in_file

待转换的原始模型路径(该模型可以从HuggingfaceModelscope平台中下载)。

--saved_dir

格式转换后的模型所存放的路径。

--infer_gpu_num

期望使用多少个GPU进行推理运算。

--weight_data_type

模型使用的精度,例如fp16bf16。

--model_name

模型自定义的名称,可任意填写。

--cpu_cores

处理模型转换所使用的vCPU核数。

  • 示例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-LLMAPI接口说明

模型加载函数

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。

    kv_cache_quant_level

    kv_cache量化级别。取值范围:

    默认值:0。

    generation_config

    模型配置参数。更多信息,请参见模型参数类(DeepGPUGenerationConfig)

    说明

    若不设置该参数,则会加载模型配置文件中的默认参数。

    is_gemm_tuning

    是否优化最佳Kernel,常见GPU的最佳Kernel已优化好并存储于安装包内。取值范围:

    默认值:False。

    load_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精度,则不需要设置该参数。

    • False:表示加载格式已转换好的模型。

    • True:表示需要加载格式未转换的原始模型,不可直接调用,主要是提供from_pretrained函数内部调用以实现从原始模型加载的功能。

    • False:不优化最佳Kernel。

    • True:优化最佳Kernel。

    • 0:表示无量化压缩。

    • 1:表示K8_V8量化,推荐值。

    • 2:表示K8_V4量化。

    • 3:表示K4_V4量化。

    • 0:表示fp16精度。

    • 1:表示int8量化。

    • 3:表示int4量化。

    • 5:表示fp8精度。

    • from_pretrained函数:直接加载从huggingfacemodelscope平台上下载的开源模型,加载过程中支持在线自动转换模型。

      该函数是一个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指向huggingfacemodelscope的原始模型目录。示例代码如下:

       

      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

      用于配置是否在生成的输出中屏蔽输入内容。取值范围:

      调用stream_generate的代码如下所示,首先需要调用DeepGPUStreamer构建一个streamer,然后启动stream_generate函数开始推理,此时程序返回并继续实时监控最新的生成结果,然后进行实时输出。

       

      streamer = DeepGPUStreamer(tokenizer, **{'skip_special_tokens':True})
      
      total_len = 0response = ""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数。

      • True:屏蔽输出内容。

      • False:显示输出内容。

    模型推理在线模式(serving)

    该模式适用于多用户多请求场景,通过提供3个并发调用函数来适配不同的代码工程场景。其中,并发调用函数包括普通调用函数、async调用函数以及含request_idasync调用函数。

    • 普通调用函数(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 = 0response = ""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 = 0response = ""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_idasync调用函数(generate_cb_async_id)

      如果您需要对请求数量和请求ID进行管控,可以调用generate_cb_async_id函数,该函数的参数与generate_cb_async相似,配置了额外的变量request_id,用于区分不同请求及其结果生成。含request_idasync调用函数定义如下:

       

          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 = 0response = ""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 timefrom deepgpu_llm.deepgpu_model import deepgpu_modelfrom deepgpu_llm.deepgpu_utils import DeepGPUGenerationConfigfrom 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 = 1precision = 0  # 0:fp16 mode, 1:int8 mode, 3:int4 modekv_cache_quant_level = 0 # 0:no quant, 1:K8_V8, 2:K8_v4, 3:K4_V4generation_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]))

      运行上述实例代码后,显示结果如下所示:

      Dingtalk_20241009103755.jpg

    • 流式输出Qwen模型示例

      本示例以单卡GPU上运行qwen-7b模型的实例代码为例,您可以调整代码中precision量化精度、kv_cache_quant_level量化级别、tp_sizeGPU数量,获得更快的性能和减少GPU显存占用。运行下列代码后将结果流式打印输出,并统计性能。

       

      import timefrom deepgpu_llm.deepgpu_model import deepgpu_modelfrom deepgpu_llm.deepgpu_utils import DeepGPUGenerationConfig, DeepGPUStreamerfrom 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 parallelprecision = 0  # 0:fp16 mode, 1:int8 mode, 3:int4 modekv_cache_quant_level = 0 # 0:no quant, 1:K8_V8, 2:K8_v4, 3:K4_V4generation_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 = 0response = ""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[0][0])    #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推理速度了。

      Dingtalk_20241009104920.jpg

      说明

      如需查看其他类型LLM模型的流式输出实例代码,您可以通过执行以下命令直接查看DeepGPU-LLM的安装目录,找到相应llama_cli脚本、chatglm_cli脚本、baichuan_cli脚本、qwen_cli脚本或deepgpu_cli脚本(仅24.9及以上版本的DeepGPU-LLM提供),即可查看相应代码。

       

      pip show -f deepgpu-llm
    • batch同时输入的示例

      针对于多batch场景,关键是处理输入和输出,各类模型输入输出的处理方法,请参见普通输出函数generate(一次性输出)

       

      import timefrom deepgpu_llm.deepgpu_model import deepgpu_modelfrom deepgpu_llm.deepgpu_utils import DeepGPUGenerationConfigfrom 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 parallelprecision = 0  # 0:fp16 mode, 1:int8 mode, 3:int4 modekv_cache_quant_level = 0 # 0:no quant, 1:K8_V8, 2:K8_v4, 3:K4_V4generation_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)))

      运行上述代码,输出结果如下所示:

      Dingtalk_20241009111314.jpg

    在线(serving)代码示例

    • 服务端代码示例

      执行deepgpu fastapi_server.py脚本文件,实现接收文本生成请求,使用DeepGPU模型进行文本生成,并返回生成的文本。

       

      import argparseimport jsonfrom typing import AsyncGeneratorfrom fastapi import FastAPI, Requestfrom fastapi.responses import JSONResponse, Response, StreamingResponseimport uvicornfrom deepgpu_llm.deepgpu_model import deepgpu_modelfrom deepgpu_llm.deepgpu_utils import DeepGPUGenerationConfig,DeepGPUStreamer,RequestCounterfrom transformers import AutoTokenizerimport time
      TIMEOUT_KEEP_ALIVE = 5  # seconds.TIMEOUT_TO_PREVENT_DEADLOCK = 1  # seconds.app = FastAPI()
      engine = Nonecounter = 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

      如果显示以下结果,表示该服务搭建成功。

      Dingtalk_20241009113929.jpg

      说明

      DeepGPU兼容vLLMserving实现,您可以直接使用vLLM的官方代码benchmark_serving.py作为参考,仅需将其内部的import vllm更改为import deepgpu即可。更多信息,请参见更多示例(将vLLM切换为DeepGPU-LLM推理引擎)

    • 客户端python代码

      本示例以一个异步的Python脚本为例,实现向一个HTTP服务发送请求,获取文本生成的流式响应,并打印这些响应的功能。

       

      import requestsimport jsonimport timeimport aiohttpimport asyncioimport randomimport 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))

      运行上述代码后,显示结果如下所示:

      Dingtalk_20241009115520.jpg

    • 客户端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。

      运行以上命令后,显示结果如下所示:

      Dingtalk_20241009133048.jpg

    更多示例(将vLLM切换为DeepGPU-LLM推理引擎

    DeepGPU-LLM提供了类似vLLM的接口,如果您需要在不改变现有vLLM代码结构的情况下,基于开源vLLM代码切换为DeepGPU-LLM推理引擎,实现DeepGPU-LLM带来的性能提升和功能扩展,请参考以下两种方式的推理示例:

    兼容vLLMDeepGPU-LLM推理示例(offline)

    1. 获取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}")
    2. 基于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")

    兼容vLLMDeepGPU-LLM多请求推理示例(serving)

    1. 在线获取vLLM的推理示例。

      获取路径:api_server

    2. 基于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
    3. 启动基于DeepGPU-LLMAPI服务器,该服务器可以提供模型推理服务。

       

      # 拉起普通服务: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
    4. 使用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


    热门文章
    更多>