使用Gunicorn部署Django大模型API遇CUDA多进程初始化错误求助
针对Django大模型API部署的CUDA与显存问题解决方案
方案一:单Worker + 多线程模式(最简便)
直接修改gunicorn启动命令,用单worker配合多线程处理并发,既保证模型只加载一次,又绕开fork进程导致的CUDA初始化错误:
gunicorn model_api.asgi:application -w 1 -k uvicorn.workers.UvicornWorker -b 0.0.0.0:8081 --preload --threads 8
原理:--preload让模型在主进程加载后共享给线程,线程不会触发新的CUDA初始化,同时--threads 8提供并发处理能力,完全适配你的业务场景。
方案二:懒加载模型(适配多Worker场景)
如果必须用多Worker,修改代码让模型在每个Worker启动后按需加载,避免全局预加载导致的冲突。在你的model_api模块中调整模型加载逻辑:
from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig import torch # 全局变量存储模型和tokenizer model = None tokenizer = None def load_model(): global model, tokenizer # 定义4bit量化配置 bnb_config = BitsAndBytesConfig( load_in_4bit=True, bnb_4bit_use_double_quant=True, bnb_4bit_quant_type="nf4", bnb_4bit_compute_dtype=torch.bfloat16 ) # 加载tokenizer和模型 tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-13b-chat-hf") model = AutoModelForCausalLM.from_pretrained( "meta-llama/Llama-2-13b-chat-hf", quantization_config=bnb_config, device_map="auto", trust_remote_code=True ) # 利用ASGI的启动事件加载模型 from django.core.asgi import get_asgi_application import asyncio application = get_asgi_application() async def startup(): await asyncio.to_thread(load_model) # 包装ASGI应用,添加启动钩子 async def wrapped_app(scope, receive, send): if scope["type"] == "lifespan": while True: message = await receive() if message["type"] == "lifespan.startup": await startup() await send({"type": "lifespan.startup.complete"}) elif message["type"] == "lifespan.shutdown": await send({"type": "lifespan.shutdown.complete"}) return else: await application(scope, receive, send)
部署时去掉--preload参数:
gunicorn model_api.asgi:wrapped_app -w 4 -k uvicorn.workers.UvicornWorker -b 0.0.0.0:8081
注:4bit量化后的Llama2-13B单模型显存占用约6-7GB,AWS P3.8xlarge的2张V100(16GB/张)最多支持4个Worker,调整-w参数可避免显存溢出。
方案三:Spawn启动Worker(彻底解决CUDA Fork冲突)
手动编写启动脚本,使用torch.multiprocessing的spawn启动方式替代gunicorn默认的fork,从根源解决CUDA初始化问题:
创建start_server.py脚本:
import torch import multiprocessing from uvicorn import Server, Config def run_worker(): from model_api.asgi import application # 每个Worker独立加载模型 config = Config(app=application, host="0.0.0.0", port=8081) server = Server(config) server.run() if __name__ == "__main__": # 设置Spawn启动方式 torch.multiprocessing.set_start_method('spawn') # 启动指定数量的Worker(建议设为4,适配显存) worker_count = 4 processes = [] for _ in range(worker_count): p = multiprocessing.Process(target=run_worker) p.start() processes.append(p) # 等待所有进程结束 for p in processes: p.join()
运行脚本启动服务:
python start_server.py
内容的提问来源于stack exchange,提问作者Saikat Bhattacharya
相关产品推荐
相关产品推荐

