目录
0 前言
本文为李宏毅学习笔记——2024春《GENERATIVE AI》篇——作业笔记HW4的补充内容3。
如果你还没获取到LLM API,请查看我的另一篇笔记:
HW1~2:LLM API获取步骤及LLM API使用演示:环境配置与多轮对话演示-CSDN博客
完整内容参见:
李宏毅学习笔记——2024春《GENERATIVE AI》篇
目标:指导你在本地或云端部署一个(小型)语言模型,并将其封装为 API 服务。
在之前的章节中,我们已经了解了 Hugging Face 中
AutoModel系列的不同类。现在,我们将使用一个参数量较小的模型进行演示,并展示如何使用 FastAPI 和 Flask 将模型部署为 API 服务。
1 为什么选择较小的模型?
大型语言模型(LLMs)通常拥有数十亿甚至上千亿的参数,除了对显存要求很高以外,还会占用大量的磁盘空间,下载费时,为了方便学习和复现,本文选择参数量较小的模型(如小型 GPT、BERT 等)进行演示,你应该可以在任何机器上完成学习。
2 环境准备
- 硬件要求:建议有 GPU,但本章内容对硬件要求不高,没有 GPU 也可以完成。
- 操作系统:Windows、macOS 或 Linux 均可。
3 安装库
- !pip install torch torchvision torchaudio
- !pip install transformers
- !pip install sentencepiece
torch:这是 PyTorch 库,用于深度学习和机器学习。它提供了高效的张量计算和自动求导功能,支持 GPU 加速。
torchvision:这是 PyTorch 的一个附加库,主要用于处理图像数据,包括常用的图像预处理、数据集和模型(如卷积神经网络)等功能。
torchaudio:这是 PyTorch 的音频处理库,主要用于音频数据的加载、预处理和特征提取等。
transformers:这是 Hugging Face 提供的一个库,包含了大量预训练的自然语言处理(NLP)模型,适用于文本分类、翻译、生成等任务。
sentencepiece:这是一个文本分词工具库,常用于处理和训练基于子词的分词模型(如 BERT、GPT 等)。它支持多种语言,并且可以灵活地处理文本的分词方式。
4 选择并加载模型
4.1 加载Tokenizer和模型
我们选择一个参数量较小的模型,如 `distilgpt2`,这是 GPT-2 的精简版本(或者说蒸馏),只有约 8820 万参数。
- import torch
- from transformers import AutoTokenizer, AutoModelForCausalLM
-
- # 指定模型名称
- model_name = "distilgpt2"
-
- # 加载 Tokenizer
- tokenizer = AutoTokenizer.from_pretrained(model_name)
-
- # 加载预训练模型
- model = AutoModelForCausalLM.from_pretrained(model_name)
4.2 将模型移动到设备
如果你的计算机有 GPU,可将模型移动到 GPU,加快推理速度。如果你使用的是 Apple 芯片的 Mac,可以移动到 `mps` 上。
- device = torch.device("cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu")
- model.to(device)
GPT2LMHeadModel(
(transformer): GPT2Model(
(wte): Embedding(50257, 768)
(wpe): Embedding(1024, 768)
(drop): Dropout(p=0.1, inplace=False)
(h): ModuleList(
(0-5): 6 x GPT2Block(
(ln_1): LayerNorm((768,), eps=1e-05, elementwise_affine=True)
(attn): GPT2Attention(
(c_attn): Conv1D()
(c_proj): Conv1D()
(attn_dropout): Dropout(p=0.1, inplace=False)
(resid_dropout): Dropout(p=0.1, inplace=False)
)
(ln_2): LayerNorm((768,), eps=1e-05, elementwise_affine=True)
(mlp): GPT2MLP(
(c_fc): Conv1D()
(c_proj): Conv1D()
(act): NewGELUActivation()
(dropout): Dropout(p=0.1, inplace=False)
)
)
)
(ln_f): LayerNorm((768,), eps=1e-05, elementwise_affine=True)
)
(lm_head): Linear(in_features=768, out_features=50257, bias=False)
)
5 进行推理
现在,我们可以使用模型进行文本生成。
- # 设置模型为评估模式
- model.eval()
-
- # 输入文本
- input_text = "Hello GPT"
-
- # 编码输入文本
- inputs = tokenizer(input_text, return_tensors="pt")
- inputs = {key: value.to(device) for key, value in inputs.items()}
-
- # 生成文本
- with torch.no_grad():
- outputs = model.generate(
- **inputs,
- max_length=200,
- num_beams=5,
- no_repeat_ngram_size=2,
- early_stopping=False
- )
-
- # 解码生成的文本
- generated_text = tokenizer.decode(outputs[0], skip_special_tokens=True)
- print("模型生成的文本:")
- print(generated_text)
参数说明:
max_length:生成文本的最大长度。num_beams:Beam Search 的数量,提高生成文本的质量。no_repeat_ngram_size:防止生成重复的 n-gram。early_stopping:当使用 Beam Search 时,若所有候选序列都生成了结束标记(如),则提前停止生成,这有助于生成更自然和适当长度的文本。
输出:
因为我们使用的是较小的 GPT-2 模型,它可能更加倾向于生成较为模板化或常见的回答。
Setting `pad_token_id` to `eos_token_id`:50256 for open-end generation.
模型生成的文本:
Hello GPT.This article was originally published on The Conversation. Read the original article.
下面是 early_stopping 设置为 False 时的输出:
Setting `pad_token_id` to `eos_token_id`:50256 for open-end generation.
模型生成的文本:
Hello GPT.This article was originally published on The Conversation. Read the original article and follow us on Twitter @theconversation.
6 为啥要将模型部署为API服务?
将模型部署为 API 服务的主要目的是实现远程访问、提高可扩展性、方便集成与复用。通过 API,多个应用可以共享模型,减轻客户端负担,支持大规模并发请求,并且可以跨平台和跨语言调用。此外,API服务简化了客户端开发,集中管理和维护模型变得更容易。
7 部署服务为API服务
如果你希望将模型部署为一个 API 服务,供其他应用调用,可以使用 FastAPI 或 Flask 框架。
选择 FastAPI 还是 Flask?
- Flask:
- 优点:简单易用,适合小型项目和快速原型开发。
- 缺点:性能相对较低,异步支持较弱。
- FastAPI:
- 优点:高性能,基于 ASGI,原生支持异步编程,自动生成交互式文档(Swagger UI),方便测试和调试。
- 缺点:相对于 Flask,学习曲线稍陡一些。
如果追求高性能和现代特性,建议使用 FastAPI。如果只是简单的演示或对性能要求不高,可以选择 Flask。
接下来将分别介绍如何使用 FastAPI 和 Flask 部署模型。
7.1 使用FastAPI部署模型
安装fastapi和uvicorn
- !pip install fastapi
- !pip install uvicorn[standard]
fastapi:用于创建高性能的 API 服务。uvicorn:ASGI 服务器,用于运行 FastAPI 应用。
创建API服务
创建一个名为 app_fastapi.py 的文件,写入以下代码:
- from fastapi import FastAPI, HTTPException
- from pydantic import BaseModel
- from transformers import AutoTokenizer, AutoModelForCausalLM
- import torch
-
- # 定义请求体的数据模型
- class PromptRequest(BaseModel):
- prompt: str
-
- app = FastAPI()
-
- # 加载模型和分词器
- model_name = "distilgpt2"
- tokenizer = AutoTokenizer.from_pretrained(model_name)
- model = AutoModelForCausalLM.from_pretrained(model_name)
- device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
- model.to(device)
-
- @app.post("/generate")
- def generate_text(request: PromptRequest):
- prompt = request.prompt
- if not prompt:
- raise HTTPException(status_code=400, detail="No prompt provided")
-
- inputs = tokenizer(prompt, return_tensors="pt").to(device)
- with torch.no_grad():
- outputs = model.generate(
- **inputs,
- max_length=200,
- num_beams=5,
- no_repeat_ngram_size=2,
- early_stopping=True
- )
- generated_text = tokenizer.decode(outputs[0], skip_special_tokens=True)
- return {"generated_text": generated_text}
在终端中运行以下命令启动服务:
uvicorn app_fastapi:app --host 0.0.0.0 --port 8000
app:app:第一个app是文件名,第二个app是 FastAPI 实例的名称。--host和--port:指定主机和端口。
启动成功后,终端输出示例:
![]()
交互界面
打开浏览器,访问 http://localhost:8000/docs,你将看到自动生成的交互式 API 文档:
![]()
你可以点击 POST /generate,然后点击 Try it out 直接测试 API:
![]()
在 Request body 部分修改你的 prompt,然后点击 Execute:
![]()
你将在下方看到具体的生成文本。
![]()
通过API调用模型
使用以下代码发送请求(在 notebook 运行或者创建一个新的 Python 脚本,例如 client.py):
- import requests
-
- response = requests.post(
- "http://localhost:8000/generate",
- json={"prompt": "Hello GPT"}
- )
- print(response.json())
{'generated_text': 'Hello GPT.\n\nThis article was originally published on The Conversation. Read the original article.'}
7.2 使用Flask部署模型
安装Flask
!pip install flask
Flask 是一个轻量级的 Python Web 框架,用于快速开发和部署 Web 应用,提供了简单易用的工具和灵活的功能,适合构建小型到中型的 Web 服务。
创建API服务
创建一个名为 app_flask.py 的文件,写入以下代码:
- from flask import Flask, request, jsonify
- from transformers import AutoTokenizer, AutoModelForCausalLM
- import torch
-
- app = Flask(__name__)
-
- # 加载模型和分词器
- model_name = "distilgpt2"
- tokenizer = AutoTokenizer.from_pretrained(model_name)
- model = AutoModelForCausalLM.from_pretrained(model_name)
- device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
- model.to(device)
-
- @app.route('/generate', methods=['POST'])
- def generate():
- prompt = request.form.get('prompt')
- if not prompt:
- return jsonify({'error': 'No prompt provided'}), 400
-
- inputs = tokenizer(prompt, return_tensors="pt").to(device)
- with torch.no_grad():
- outputs = model.generate(
- **inputs,
- max_length=200,
- num_beams=5,
- no_repeat_ngram_size=2,
- early_stopping=True
- )
- generated_text = tokenizer.decode(outputs[0], skip_special_tokens=True)
- return jsonify({'generated_text': generated_text})
-
- if __name__ == '__main__':
- app.run(host='0.0.0.0', port=8000)
运行服务
python app_flask.py
![]()
通过API调用模型
使用以下代码发送请求:
- import requests
-
- response = requests.post('http://localhost:8000/generate', data={'prompt': 'Hello GPT'})
- print(response.json())
{'generated_text': 'Hello GPT.\n\nThis article was originally published on The Conversation. Read the original article.'}
8 总结
通过以上步骤,我们成功地部署了一个参数量较小的语言模型 distilgpt2,并将其封装为 API 服务,你可以根据实际需求决定使用 FastAPI 还是 Flask。
你也可以在 Hugging Face 模型库 选择其他模型进行尝试,如 distilbert-base-uncased(使用 AutoModelForMaskedLM,用于填空任务)。
评论记录:
回复评论: