一、fastapi

FastAPI 是一个现代、快速(高性能)的 Python Web 框架,用于构建基于标准 Python 类型提示的 API。以下是 FastAPI 的主要特点及其入门方法的简要说明:

主要特点:

  1. 开发速度快:提高开发功能的速度,大约是 200% 到 300%。
  2. 更少的错误:减少约 40% 的人为(开发人员)引入的错误。
  3. 直观:出色的编辑器支持,随处都有代码补全功能,减少调试时间。
  4. 易用:设计易于使用和学习,减少阅读文档的时间。
  5. 简洁:最小化代码重复,从每个参数声明中获得多个功能。
  6. 健壮:生产就绪代码,具有自动交互文档。
  7. 基于标准:基于(并完全兼容)API 的开放标准:OpenAPI 和 JSON Schema。

二、代码封装api前端请求与后端响应

from fastapi import FastAPI, Request
from transformers import AutoTokenizer, AutoModelForCausalLM, GenerationConfig
import uvicorn
import json
import datetime
import torch

# 设置设备参数
DEVICE = "cuda"  # 使用CUDA
DEVICE_ID = "0"  # CUDA设备ID,如果未设置则为空
CUDA_DEVICE = f"{DEVICE}:{DEVICE_ID}" if DEVICE_ID else DEVICE  # 组合CUDA设备信息

# 清理GPU内存函数
def torch_gc():
    if torch.cuda.is_available():  # 检查是否可用CUDA
        with torch.cuda.device(CUDA_DEVICE):  # 指定CUDA设备
            torch.cuda.empty_cache()  # 清空CUDA缓存
            torch.cuda.ipc_collect()  # 收集CUDA内存碎片

# 构建 chat 模版
def bulid_input(prompt, history=[], system_message=None):
    system_format = 'system\n\n{content}\n'
    user_format = 'user\n\n{content}\n'
    assistant_format = 'assistant\n\n{content}\n'

    prompt_str = ''

    # 添加system消息
    if system_message:
        prompt_str += system_format.format(content=system_message)

    # 拼接历史对话
    for item in history:
        if item['role'] == 'user':
            prompt_str += user_format.format(content=item['content'])
        else:
            prompt_str += assistant_format.format(content=item['content'])

    # 添加当前用户输入
    prompt_str += user_format.format(content=prompt)

    return prompt_str

# 创建FastAPI应用
app = FastAPI()

# 处理POST请求的端点
@app.post("/")
async def create_item(request: Request):
    global model, tokenizer  # 声明全局变量以便在函数内部使用模型和分词器
    json_post_raw = await request.json()  # 获取POST请求的JSON数据
    json_post = json.dumps(json_post_raw)  # 将JSON数据转换为字符串
    json_post_list = json.loads(json_post)  # 将字符串转换为Python对象
    prompt = json_post_list.get('prompt')  # 获取请求中的提示
    history = json_post_list.get('history', [])  # 获取请求中的历史记录
    system_message = json_post_list.get('system_message')  # 获取请求中的system消息

    messages = [
        {"role": "user","content": prompt}
    ]

    # 调用模型进行对话生成
    input_str = bulid_input(prompt=prompt, history=history, system_message=system_message)
    input_ids = tokenizer.encode(input_str, add_special_tokens=False, return_tensors='pt').cuda()

    generated_ids = model.generate(
        input_ids=input_ids, max_new_tokens=1024, do_sample=True,
        top_p=0.5, temperature=0.95, repetition_penalty=1.1
    )
    outputs = generated_ids.tolist()[0][len(input_ids[0]):]
    response = tokenizer.decode(outputs)
    response = response.strip().replace('assistant\n\n', '').strip()  # 解析 chat 模版

    now = datetime.datetime.now()  # 获取当前时间
    time = now.strftime("%Y-%m-%d %H:%M:%S")  # 格式化时间为字符串
    # 构建响应JSON
    answer = {
        "response": response,
        "status": 200,
        "time": time
    }
    # 构建日志信息
    log = "[" + time + "] " + '", prompt:"' + prompt + '", response:"' + repr(response) + '"'
    print(log)  # 打印日志
    torch_gc()  # 执行GPU内存清理
    return answer  # 返回响应

# 主函数入口
if __name__ == '__main__':
    # 加载预训练的分词器和模型
    model_name_or_path = '/root/LLaMA-Factory/models/llama3_lora_sft'
    tokenizer = AutoTokenizer.from_pretrained(model_name_or_path, use_fast=False)
    model = AutoModelForCausalLM.from_pretrained(model_name_or_path, device_map="auto", torch_dtype=torch.bfloat16).cuda()

    # 启动FastAPI应用
    # 用6006端口可以将autodl的端口映射到本地,从而在本地使用api
    uvicorn.run(app, host='0.0.0.0', port=6006, workers=1)  # 在指定端口和主机上启动应用

三、代码具体解释

1. 引入库和设置设备参数

from fastapi import FastAPI, Request
from transformers import AutoTokenizer, AutoModelForCausalLM, GenerationConfig
import uvicorn
import json
import datetime
import torch
  • FastAPI:一个现代、快速(高性能)的 Web 框架,用于构建 API。
  • transformers:Hugging Face 提供的库,用于加载预训练模型和分词器。
  • uvicorn:一个用于运行 ASGI 应用的轻量级服务器。
  • jsondatetimetorch:标准库和 PyTorch 库,用于 JSON 操作、时间操作和深度学习操作。

2. 设置设备参数与清理 GPU 内存函数

DEVICE = "cuda"  # 使用CUDA
DEVICE_ID = "0"  # CUDA设备ID,如果未设置则为空
CUDA_DEVICE = f"{DEVICE}:{DEVICE_ID}" if DEVICE_ID else DEVICE  # 组合CUDA设备信息
def torch_gc():
    if torch.cuda.is_available():  # 检查是否可用CUDA
        with torch.cuda.device(CUDA_DEVICE):  # 指定CUDA设备
            torch.cuda.empty_cache()  # 清空CUDA缓存
            torch.cuda.ipc_collect()  # 收集CUDA内存碎片

3.构建对话输入模版

def bulid_input(prompt, history=[], system_message=None):
    system_format = 'system\n\n{content}\n'
    user_format = 'user\n\n{content}\n'
    assistant_format = 'assistant\n\n{content}\n'

    prompt_str = ''

    if system_message:
        prompt_str += system_format.format(content=system_message)

    for item in history:
        if item['role'] == 'user':
            prompt_str += user_format.format(content=item['content'])
        else:
            prompt_str += assistant_format.format(content=item['content'])

    prompt_str += user_format.format(content=prompt)

    return prompt_str
  • system_formatuser_formatassistant_format:定义不同角色的消息格式。
  • bulid_input 函数将系统消息、历史对话和当前用户输入拼接成一个字符串。

4.创建 FastAPI 应用

app = FastAPI()

5.处理 POST 请求的端点

@app.post("/")
async def create_item(request: Request):
    global model, tokenizer  # 声明全局变量以便在函数内部使用模型和分词器
    json_post_raw = await request.json()  # 获取POST请求的JSON数据
    json_post = json.dumps(json_post_raw)  # 将JSON数据转换为字符串
    json_post_list = json.loads(json_post)  # 将字符串转换为Python对象
    prompt = json_post_list.get('prompt')  # 获取请求中的提示
    history = json_post_list.get('history', [])  # 获取请求中的历史记录
    system_message = json_post_list.get('system_message')  # 获取请求中的system消息

    input_str = bulid_input(prompt=prompt, history=history, system_message=system_message)
    input_ids = tokenizer.encode(input_str, add_special_tokens=False, return_tensors='pt').cuda()

    generated_ids = model.generate(
        input_ids=input_ids, max_new_tokens=1024, do_sample=True,
        top_p=0.5, temperature=0.95, repetition_penalty=1.1
    )
    outputs = generated_ids.tolist()[0][len(input_ids[0]):]
    response = tokenizer.decode(outputs)
    response = response.strip().replace('assistant\n\n', '').strip()

    now = datetime.datetime.now()  # 获取当前时间
    time = now.strftime("%Y-%m-%d %H:%M:%S")  # 格式化时间为字符串

    answer = {
        "response": response,
        "status": 200,
        "time": time
    }
    log = "[" + time + "] " + '", prompt:"' + prompt + '", response:"' + repr(response) + '"'
    print(log)  # 打印日志
    torch_gc()  # 执行GPU内存清理
    return answer  # 返回响应
  • 这个端点处理 POST 请求,接收用户输入和对话历史,调用模型生成对话响应,并返回响应结果。
  • bulid_input 函数用于构建输入字符串。
  • model.generate 函数用于生成模型的输出。
  • torch_gc 函数用于清理 GPU 内存。

6.主函数入口

if __name__ == '__main__':
    model_name_or_path = '/root/LLaMA-Factory/models/llama3_lora_sft'
    tokenizer = AutoTokenizer.from_pretrained(model_name_or_path, use_fast=False)
    model = AutoModelForCausalLM.from_pretrained(model_name_or_path, device_map="auto", torch_dtype=torch.bfloat16).cuda()

    uvicorn.run(app, host='0.0.0.0', port=6006, workers=1)

四、postman测试

基于模型的输入json样式,向本地localhost:6006发送POST请求,发现能够正常返回模型的输出结果!

Logo

加入社区!打开量化的大门,首批课程上线啦!

更多推荐