Skip to content

Latest commit

 

History

History
248 lines (186 loc) · 8.73 KB

01-InternLM3-8B-Instruct FastAPI.md

File metadata and controls

248 lines (186 loc) · 8.73 KB

InternLM3-8B-instruct FastAPI部署

InternLM3 开源了一个具有 80 亿参数的指令模型,名为 InternLM3-8B-Instruct,旨在用于通用任务和高级推理。该模型具有以下特点:

  • 在降低成本的同时提升性能:在推理和知识密集型任务中,表现超越了像 Llama3.1-8B 和 Qwen2.5-7B 等模型。值得注意的是,InternLM3 仅在 4 万亿高质量标记上进行训练,比其他同规模的语言模型节省了超过 75% 的训练成本。
  • 深度思考能力:InternLM3 支持两种模式:一种是通过长链思维解决复杂推理任务的深度思考模式,另一种是用于流畅用户交互的正常响应模式。

环境配置

实验所依赖的基础开发环境如下:

----------------
ubuntu 22.04
Python 3.12.3
cuda 12.1
pytorch 2.3.0
----------------

本文默认学习者已安装好以上 Pytorch(cuda) 环境,如未安装请自行安装。

首先 pip 换源加速下载并安装依赖包:

# 升级pip
python -m pip install --upgrade pip
# 更换 pypi 源加速库的安装
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple

# FastAPI 相关依赖
pip install requests==2.32.3
pip install fastapi==0.104.1
pip install uvicorn==0.24.0

# Langchain 相关依赖
pip install langchain==0.3.7

# WebDemo 相关依赖
pip install streamlit==1.41.1

# LoRA微调 相关依赖
pip install peft==0.11.1          # 用于 LoRA 微调

# 通用依赖
pip install modelscope==1.22.0    # 用于模型下载和管理
pip install transformers==4.47.1  # Hugging Face 的模型库,用于加载和训练模型
pip install sentencepiece==0.2.0  # 用于处理文本数据
pip install accelerate==0.34.2    # 用于分布式训练和混合精度训练
pip install datasets==2.20.0      # 用于加载和处理数据集

考虑到部分同学配置环境可能会遇到一些问题,我们在 AutoDL 平台准备了 InternLM3-8b-Instruct 的环境镜像,点击下方链接并直接创建 AutoDL 示例即可。 https://www.codewithgpu.com/i/datawhalechina/self-llm/self-llm-internlm3

模型下载

modelscope 是一个模型管理和下载工具,支持从魔搭 (Modelscope) 等平台快速下载模型。

这里使用 modelscope 中的 snapshot_download 函数下载模型,第一个参数 model_name_or_path 为模型名称或者本地路径,第二个参数 cache_dir 为模型的下载路径,第三个参数 revision 为模型的版本号。

/root/autodl-tmp 路径下新建 model_download.py 文件并在其中粘贴以下代码,并保存文件。

from modelscope import snapshot_download

model_dir = snapshot_download('Shanghai_AI_Laboratory/internlm3-8b-instruct', cache_dir='./', revision='master')

注意:记得修改 cache_dir 为你的模型下载路径哦~

在终端运行 python /root/autodl-tmp/model_download.py 执行下载,模型大小为 18GB 左右,下载模型大概需要5-30分钟。

代码准备

新建 api.py 文件并在其中输入以下内容,粘贴代码后请及时保存文件。记得将tokenizer和model的路径改成上面模型下载的cache_dir的路径。以下代码有很详细的注释,大家如有不理解的地方,欢迎提出 issue 。

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内存碎片

# 创建FastAPI应用
app = FastAPI(
    title="InternLM Chat API",
    description="API for InternLM 3 chat model",
    version="1.0.0"
)

# 添加GET方法的根路由
@app.get("/")
async def root():
    return {
        "message": "Welcome to InternLM Chat API",
        "status": "healthy",
        "timestamp": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    }

# 处理POST请求的端点
@app.post("/v1/chat")
async def create_chat(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')  # 获取用户的问题
    # 构建对话模板
    messages = [
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": prompt},
    ]
    tokenized_chat = tokenizer.apply_chat_template(messages, tokenize=True, add_generation_prompt=True, return_tensors="pt").to("cuda")
    generated_ids = model.generate(tokenized_chat, max_new_tokens=1024, temperature=1, repetition_penalty=1.005, top_k=40, top_p=0.8)
    generated_ids = [
        output_ids[len(input_ids):] for input_ids, output_ids in zip(tokenized_chat, generated_ids)
    ]
    response = tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
    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_path = '/root/autodl-tmp/Shanghai_AI_Laboratory/internlm3-8b-instruct'
    tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
    model = AutoModelForCausalLM.from_pretrained(model_path, torch_dtype=torch.float16, trust_remote_code=True).cuda()
    model = model.eval()

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

然后在当前文件的路径下面运行:

python api.py 

出现下面的信息就说明成功运行了。

01-1.png

调用API

默认部署在 6006 端口,通过 POST 方法进行调用。可以使用命令行curl和代码的方式来调用。

命令行:

curl -X POST "http://localhost:6006/v1/chat" \
     -H 'Content-Type: application/json' \
     -d '{"prompt": "你好"}'

或者使用实际IP地址:

curl -X POST "http://<your-ip>:6006/v1/chat" \
     -H 'Content-Type: application/json' \
     -d '{"prompt": "你好"}'

返回结果:

01-2.png

使用 python 中的 requests 库进行调用,创建 request.py 文件,复制下面的代码,运行 python request.py

import requests
import json

def get_completion(prompt):
    headers = {'Content-Type': 'application/json'}
    data = {"prompt": prompt}
    response = requests.post(url='http://127.0.0.1:6006/v1/chat', headers=headers, data=json.dumps(data))
    return response.json()['response']

if __name__ == '__main__':
    print(get_completion('你好'))

返回结果:

01-3.png

同时, 这是我们部署的FastAPI的Terminal页面, 还可以看到如下信息

01-4.png

这里简要对上述控制台信息进行解释:

INFO: ... "GET /_stcore/health HTTP/1.1" 404 Not Found
INFO: ... "GET /_stcore/host-config HTTP/1.1" 404 Not Found
  • 这些是来自 Streamlit 的健康检查请求,返回 404 是正常的,因为我们的 FastAPI 服务器没有实现这些端点
  • 这表明可能有 Streamlit 应用试图连接到这个端口,但这不影响我们的 API 功能
INFO: ... "POST / HTTP/1.1" 405 Method Not Allowed
  • 这是失败的API调用记录
    • 显示了请求时间、用户输入和模型响应
    • 405 Method Not Allowed 表示请求方法不允许
    • 有请求试图向根路径 ("/") 发送 POST 请求
    • 返回 405 是因为我们只在根路径定义了 GET 方法,而不是 POST
[2025-01-19 12:40:08] ", prompt:"你好", response:"'你好!很高兴见到你。有什么我可以帮助你的吗?'"
INFO: ... "POST /v1/chat HTTP/1.1" 200 OK
  • 这是成功的API调用记录
    • 显示了请求时间、用户输入和模型响应
    • 200 OK 表示请求成功处理