赞
踩
随着模型训练和推理技术的成熟,我们如何在资源有限的情况下更有效地利用这些技术?
近年来,各种方案的出现极大地降低了科研门槛。从 vLLM 项目的内存优化到端侧小模型和代理运行超大模型,这些方案为模型推理提供了多样化的路径。
本文旨在探讨模型推理的技术方案,提供一个全面的入门指南,包括开源和闭源服务。
我们从模型的性能效率和调用方式两个关键角度切入,涉及项目:
每部分都有很多优秀的开源项目,这里只列举一个有代表性。
实践目标:
自 2023 年 3 月推出 ChatGPT API 服务以来,几乎所有大模型服务和项目都支持 OpenAI 接口,这已然成为行业标准。使用 OpenAI 风格的 API 进行大模型推理有以下好处:
当然,这种方法也有局限,例如部分特性(如 system prompt 和 Function call)可能与某些模型不兼容。不过,诸如 Xinference 和 Langchain Tools 等项目可以弥补这些不足。
OneAPI 是一个 API 管理和分发系统,支持几乎所有主流 API 服务。OneAPI 通过简单的配置允许使用一个 API 密钥调用不同的服务,实现服务的高效管理和分发。
讯飞/智谱/千问/Gemini/Claude,其模型调用方式各不相同,但借助 OneAPI 能统一转化为 OpenAI 格式。
官方提供了一键部署的 docker-compose 方案。部署完成后,访问 http://localhost:3000/ 并使用初始账号(用户名为 root,密码为 123456)进行登录,登录后根据提示修改密码。
类似的开源项目还有 AI GateWay 或者 LiteLLM等,各有优劣,但个人强推 OneAPI。
下表列举了几个 OneAPI 支持的 API 服务,完整的模型列表参见 OneAPI 官方仓库。
所属公司 | 模型 | 文档地址 | 备注 |
---|---|---|---|
面壁智能 | 智谱 glm | 智谱 API 文档 | 新用户 1B Token 免费额度,1个月有效期 |
阿里云 | 通义千问 Qwen | 千问 API 文档 | 新用户 1B Token 免费额度,半年有效期 |
百川智能 | 百川大模型 | 百川 API 文档 | 新用户 8元免费额度,3个月有效期 |
讯飞 | SparkDesk | 讯飞 API 文档 | 新用户 100K Token 免费额度,1年有效期 |
谷歌 | Gemini/PaLM2 | Google API 文档 | 提供免费版 API,存在使用限制 |
OpenAI | GPT | OpenAI API 文档 | 网页版可免登录使用,API 需国外银行卡 |
微软 | Azure | Azure API 文档 | 需注册 Azure 账号,支持国内 visa 信用卡或双币卡 |
集成各类 API 服务添加到 OneAPI 中:
以谷歌的 Gemini 为例:点击渠道 => 新建渠道
内容说明:
{ "dall-e-3": "cogview-3" }
:当用户请求 dall-e-3
时,实际请求了 cogview-3
模型。模型映射关系在一些场景很有用,比如:
dall-e-3
模型添加渠道后,点击令牌,新建令牌,创建密钥,复制密钥。密钥作用等同于 OpenAI 的 API。
渠道存在优先级,如果同一模型有多个渠道支持,OneAPI 会按权重使用不同渠道。但 root 用户可通过 -k
指定渠道,比如下边添加了两个渠道:
通过 sk-xxxxxx-1
指定 ChatAnywhere
渠道,通过 sk-xxxxxx-2
指定 bichat
渠道。
除此之外,你可以让每个模型只对应一个渠道,这样指定模型时,渠道也是确定的。
创建密钥后,走服务地址作为 API 代理地址,比如在本地启动服务,走 localhost
:
OPENAI_API_BASE=http://localhost:3000/v1
OneAPI 支持多用户管理,root 和管理员能管理模型渠道,配置额度。普通用户则在注册后,通过添加兑换码导入额度。
创建密钥的过程与前边一致。
假设服务运行在 3000
端口,配置访问域名为 one-api.example.com
server { listen 80; server_name one-api.example.com; location /{ proxy_pass http://localhost:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; # 流式 chunked_transfer_encoding off; proxy_buffering off; proxy_cache off; # 设置等待响应的时长 proxy_send_timeout 300; # proxy_connect_timeout 300; # proxy_read_timeout 300; # send_timeout 300; } }
类似可配置 https 的访问。
反向代理主要用于 OpenAI, Gemini, Claude 等限制国内 IP 访问服务。以 Gemini 为例,在支持访问的服务器上配置 Nginx:
server {
listen 80;
server_name your.domain.com;
location / {
proxy_pass https://generativelanguage.googleapis.com;
proxy_set_header Host generativelanguage.googleapis.com;
proxy_ssl_server_name on;
proxy_cache off;
proxy_buffering off;
proxy_connect_timeout 7200;
}
}
然后将代理链接 your.domain.com
并导入 OneAPI 的 Gemini 渠道。类似方法适用于对 Claude 和 OpenAI 等服务的转发。
如果硬件资源不足,可以用代理站作为补充。优点是省事,访问快,支持超大模型。缺点是数据经过一手,安全隐患增加一层,使用代理站更多出于实验方便。这里推荐几个站点:
代理站 | 服务地址 | 模型支持 | 备注 |
---|---|---|---|
Chatanywhere | chatanywhere/GPT_API_free | OpenAI 系列 | 速度快,价格低 |
沃卡 | wokaai.com | OpenAI/Claude/Gemini/Midjourney | 基于 OneAPI 项目 |
Chandler.ai | ChandlerAi | OpenAI/Claude/Grok 等 | 需国外信用卡 |
NeutrinoAPP | neutrinoapp.com | OpenAI/开源模型 | 需国外信用卡 |
monsterapi.ai | monsterapi.ai | 仅开源模型 | 支持模型微调,需国外信用卡 |
Predibase | Predibase AI | codellama/llama/gemma/mixtral 等 | 支持模型微调,需国外信用卡 |
后两个网站提供对开源模型的微调和推理服务,支持多种模型和微调方式,比如 MonsterAPI:
前边讲了闭源 API 转成 OpenAI 风格的方式,下边介绍开源模型如何以 OpenAI Style 启动,继而也能导入到 OneAPI 统一管理。这方面我们讲两个比较有代表性的项目。
vLLM 是去年6月推出的一个大模型推理加速框架,通过 PagedAttention 高效管理 attention 中缓存的张量,实现了比 HuggingFace Transformers 高 24 倍的吞吐量。vLLM 支持的开源模型包括 Llama,百川,千问等模型,也支持基于这些模型架构训练或微调得到的模型,比如 Lemur:
vLLM 提供了一个 OpenAI 风格的 API 服务,比如启动百川模型
# pip install vllm
python -m vllm.entrypoints.openai.api_server \
--model /sshfs/pretrains/baichuan-inc/Baichuan2-13B-Chat \
--trust-remote-code \
--tensor-parallel-size 2 \
--served-model-name baichuan \
--api-key sk-xxxx \
--port 8000
参数说明(Ref:官方文档 - OpenAI Compatible Server):
--model
:模型路径,本地路径需加上 --trust-remote-code
参数--tensor-parallel-size
:模型使用的 GPU 数目--served-model-name
:用户访问的模型名称--api-key
:API 密钥,可不填,允许任意密钥访问--port
:服务端口vLLM 还支持 推理量化,加载 Lora 参数和分布式推理等。
类似 vllm 的项目还有 LightLLM 和 FasterTransformer等。
GGUF 格式以及 Ollama 更深入的介绍,另外再开帖子讨论
相比 vllm 或者直接使用 huggingface 的模型推理 Pipeline。ollama 极大降低了模型使用门槛:
从 32 位量化到 4bit,会一定程度降低模型的表现,一种取舍,涉及模型压缩技术。
Docker 部署:https://ollama.com/blog/ollama-is-now-available-as-an-official-docker-image
API 文档:https://github.com/ollama/ollama/blob/main/docs/api.md
推荐使用 docker-compose 部署一键启动服务,方便修改端口,GPU 配置以及模型下载路径等:
version: '3.8' services: ollama: image: ollama/ollama container_name: ollama ports: - "11434:11434" volumes: # 模型路径 - /sshfs/ollama:/root/.ollama environment: - CUDA_VISIBLE_DEVICES=6,7 # - OLLAMA_HOST="http://localhost:11434" # - OLLAMA_KEEP_ALIVE="5m" deploy: resources: reservations: devices: - driver: nvidia count: all capabilities: [gpu] restart: unless-stopped
http://localhost:11434
为 API 服务地址。
创建别名:
alias ollama='docker exec -it ollama ollama'
基本操作:
# 拉取模型,比如千问
ollama pull qwen:0.5b
# 查看拉取的模型列表
ollama list
GGUF: GPT-Generated Unified Format
GGUF:GPT 生成的统一格式
文档:https://github.com/ggerganov/ggml/blob/master/docs/gguf.md
模型量化方式:Which Quantization Method Is Best for You?: GGUF, GPTQ, or AWQ
GGUF 由llama.cpp团队介绍。它是一种为大型语言模型设计的量化方法。它允许用户在 CPU 上运行LLMs,同时通过提供速度改进将某些层卸载到 GPU。
GGUF 对于在 CPU 或 Apple 设备上运行模型的用户特别有用。在 GGUF 上下文中,量化涉及缩小模型权重(通常存储为 16 位浮点数)以节省计算资源。
GGUF 是一种更有效、更灵活的存储和用于LLMs推理的方式。它专为快速加载和保存模型而量身定制,采用用户友好的方法来处理模型文件。
开发者:Georgi Gerganov
文档:https://github.com/ggerganov/ggml/blob/master/docs/gguf.md
HuggingFace 大佬 Tom Jobbins 对大量的主流模型进行了量化。
量化模型的仓库地址:https://huggingface.co/TheBloke
支持列表:https://ollama.com/library
Embedding:Embedding models
以 codellama 为例:
主要的关键字:模型参数量,模型类型,量化级别,量化方式。
模型类型 | 说明 |
---|---|
instruct | Fine-tuned to generate helpful and safe answers in natural language |
python | A specialized variation of Code Llama further fine-tuned on 100B tokens of Python code |
code | Base model for code completion |
内存占用方面,千问 Qwen-72b-1.5 模型,4-bit 量化,推理显存 40G 左右,两张 3090 可用:
文档:https://github.com/ollama/ollama/blob/main/docs/import.md
启动 hf 模型
数据量大,当前仍需要 vllm 等项目。
最后,如果需要对 API 进行灵活定制,可以用 flask 或 FastAPI 手写服务。举个例子,以 OpenAI 风格启动 HuggingFace 的 Embedding 模型:
from flask import Flask, request, jsonify from sentence_transformers import SentenceTransformer app = Flask(__name__) # 加载模型 model_path = '/sshfs/pretrains/moka-ai/m3e-large' model = SentenceTransformer(model_path) @app.route('/v1/embeddings', methods=['POST']) def get_embeddings(): data = request.get_json() if not all((data, 'input' in data, 'model' in data)): return jsonify({"error": "Missing required fields in request body"}), 400 input_text = data['input'] # 将单个输入转换为列表 if isinstance(input_text, str): input_text = [input_text] # 调用模型获取 embeddings embeddings = model.encode(input_text) # 构造响应 embeddings_response = [] for index, embedding in enumerate(embeddings): embedding_dict = { "object": "embedding", "embedding": embedding.tolist(), # 将 numpy 数组转换为列表 "index": index } embeddings_response.append(embedding_dict) # 可选: Token 计数 response = { "object": "list", "data": embeddings_response, "model": data['model'], "usage": { "prompt_tokens": sum(len(text.split()) for text in input_text), "total_tokens": sum(len(text.split()) for text in input_text) } } return jsonify(response) if __name__ == '__main__': app.run(debug=True, port=5000, host='0.0.0.0')
测试请求:
curl -H "Content-Type: application/json" \
-X POST \
-d '{"input": "The food was delicious and the waiter...", "model": "text-embedding-ada-002"}' \
http://localhost:5000/v1/embeddings
除了常规策略,还有基于 ChatGPT 网页端进行逆向白嫖的,比如 FreeGPT35,GPT4Free 和 coze-discord 等,当前暂不讨论。
用 API 跑数据可以直接用官方库 openai
,也可以用 ChatTool,基于 API 的封装,支持多轮对话,异步处理数据等。
先进行配置:
export OPENAI_API_KEY="sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
export OPENAI_API_BASE="https://one-api.example.com/v1"
或者在代码中设置:
import chattool
chattool.api_key = "sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
chattool.api_base = "https://one-api.example.com/v1"
举两个例子。
将数字翻译为罗马数字,串行处理数据,缓存文件为 chat.jsonl
:
def data2chat(msg):
chat = Chat()
chat.system("你是一个熟练的数字翻译家。")
chat.user(f"请将该数字翻译为罗马数字:{msg}")
chat.model = "gpt-3.5-turbo" # 默认模型
# 注意: 在函数内执行 getresponse
chat.getresponse(max_tries=3)
return chat
checkpoint = "chat.jsonl" # 缓存文件的名称
msgs = ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
chats = process_chats(msgs, data2chat, checkpoint)
# chats = load_chats(checkpoint)
用不同语言打印 hello world
,并行处理数据
from chattool import async_chat_completion, load_chats, Chat
langs = ["python", "java", "Julia", "C++"]
def data2chat(msg):
chat = Chat()
chat.user("请用语言 %s 打印 hello world" % msg)
# 注意:不需要 getresponse 而交给异步处理
return chat
async_chat_completion(langs, chkpoint="async_chat.jsonl", nproc=2, data2chat=data2chat)
chats = load_chats("async_chat.jsonl")
在 Jupyter Notebook 中运行,需要使用 await
关键字和 wait=True
参数:
await async_chat_completion(langs, chkpoint="async_chat.jsonl", nproc=2, data2chat=data2chat, wait=True)
以上,将模型整合到 API 网关,统一服务接口供代码调用。这样,我们就能轻松地集成各类大模型,也省去配置环境的麻烦。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。