一、环境准备与基础组件安装
在进行模型部署前,必须确保服务器环境具备GPU驱动、Docker引擎以及NVIDIA Container Toolkit。以下是具体的操作步骤,请按顺序执行。
1. 检查NVIDIA驱动状态
首先确认服务器已安装NVIDIA驱动且GPU正常识别。执行以下命令:
```bash
nvidia-smi
``>
如果输出了GPU型号列表和驱动版本(如CUDA Version: 11.8),则驱动正常。若报错命令未找到,请先前往NVIDIA官网下载并安装对应显卡型号的驱动。
2. 安装Docker与Docker Compose
若服务器尚未安装Docker,执行以下一键安装脚本:
```bash
curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun
systemctl start docker
systemctl enable docker
```
安装完成后,将当前用户添加到docker组以避免每次使用sudo:
```bash
sudo usermod -aG docker $USER
newgrp docker
```
验证Docker是否安装成功:
```bash
docker --version
```
3. 配置NVIDIA Container Toolkit
这是让Docker容器能够调用宿主机GPU的关键组件。执行以下命令进行配置:
```bash
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list
sudo apt-get update
sudo apt-get install -y nvidia-container-toolkit
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker
```
配置完成后,运行测试命令确保GPU调用正常:
```bash
docker run --rm --gpus all nvidia/cuda:11.7.0-base-ubuntu22.04 nvidia-smi
``>
若能看到与宿主机一致的nvidia-smi输出,说明环境准备完毕。
二、算法服务代码编写
本指南以Python为例,构建一个基于ResNet18的图像分类API服务。我们将使用FastAPI作为Web框架,因为它性能优异且原生支持异步。
1. 创建项目目录结构
请在服务器上创建一个工作目录,结构如下:
```text
model_service/
├── app/
│ ├── __init__.py
│ ├── main.py 主程序入口
│ └── model.py 模型加载与推理逻辑
├── requirements.txt 依赖包列表
└── Dockerfile 镜像构建文件
```
2. 编写依赖文件
在requirements.txt中写入以下内容,指定具体版本以避免兼容性问题:
```text
fastapi==0.104.1
uvicorn[standard]==0.24.0
torch==2.0.1
torchvision==0.15.2
pillow==10.1.0
numpy==1.24.3
```
3. 编写模型逻辑代码
在app/model.py中编写模型加载和预处理逻辑。这里使用PyTorch内置的ResNet18,首次运行会自动下载权重:
```python
import torch
import torchvision.transforms as transforms
from torchvision.models import resnet18, ResNet18_Weights
from PIL import Image
import io
class ModelService:
def __init__(self):
self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
self.model = self._load_model()
self.preprocess = self._get_transform()
def _load_model(self):
加载预训练模型
weights = ResNet18_Weights.DEFAULT
model = resnet18(weights=weights)
model.to(self.device)
model.eval()
return model
def _get_transform(self):
图像预处理转换
return transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
])
def predict(self, image_bytes: bytes):
try:
将字节流转换为PIL Image
image = Image.open(io.BytesIO(image_bytes)).convert("RGB")
input_tensor = self.preprocess(image).unsqueeze(0).to(self.device)
with torch.no_grad():
output = self.model(input_tensor)
获取预测结果索引
_, predicted_idx = torch.max(output, 1)
return int(predicted_idx.item())
except Exception as e:
raise RuntimeError(f"推理失败: {str(e)}")
全局单例模式加载模型
model_service = ModelService()
```
4. 编写API接口代码

在app/main.py中编写FastAPI接口,接收Base64编码的图片数据:
```python
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import base64
from typing import Optional
from .model import model_service
app = FastAPI(title="Image Classification Service")
class InferenceRequest(BaseModel):
image_base64: str
@app.get("/health")
def health_check():
return {"status": "ok", "device": str(model_service.device)}
@app.post("/predict")
def predict(request: InferenceRequest):
try:
解码Base64图片
image_data = base64.b64decode(request.image_base64)
class_idx = model_service.predict(image_data)
return {"predicted_class": class_idx}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
```
三、Docker镜像封装
编写Dockerfile将上述代码和环境打包。为了减小镜像体积,我们采用多阶段构建思路,并使用CUDA运行时作为基础镜像。
在项目根目录下创建Dockerfile,内容如下:
```dockerfile
使用PyTorch官方CUDA运行时镜像作为基础镜像
FROM pytorch/pytorch:2.0.1-cuda11.7-cudnn8-runtime
设置工作目录
WORKDIR /app
安装系统依赖(如果需要处理特定图像格式,可能需要libz等)
RUN apt-get update && apt-get install -y --no-install-recommends \
libglib2.0-0 \
libsm6 \
libxext6 \
libxrender-dev \
libgomp1 \
&& rm -rf /var/lib/apt/lists/
复制依赖文件并安装Python包
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
复制项目代码
COPY app ./app
暴露服务端口
EXPOSE 8000
设置环境变量,确保Python不缓冲输出
ENV PYTHONUNBUFFERED=1
启动命令
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
```
四、构建与运行验证
代码和配置文件准备就绪后,执行以下步骤完成部署。
1. 构建Docker镜像
在model_service目录下执行构建命令。注意最后的点(.)不能省略:
```bash
docker build -t resnet-service:v1 .
```
构建过程可能需要几分钟,因为需要下载PyTorch基础镜像和安装依赖。看到"Successfully built ..."即表示构建成功。
2. 启动容器服务
使用以下命令启动容器。关键参数--gpus all用于将宿主机GPU挂载给容器:
```bash
docker run -d \
--name my_model_service \
--gpus all \
-p 8080:8000 \
--restart unless-stopped \
resnet-service:v1
```
参数说明:
- -d:后台运行。
- --name:指定容器名称,方便管理。
- --gpus all:授权容器访问所有GPU。
- -p 8080:8000:将宿主机的8080端口映射到容器内部的8000端口。
- --restart unless-stopped:设置重启策略,除非手动停止,否则随Docker启动自动运行。
3. 查看服务日志
确认服务是否正常启动,检查是否有报错信息:
```bash
docker logs -f my_model_service
``>
看到Uvicorn running on http://0.0.0.0:8000即表示服务启动成功。按Ctrl+C退出日志查看。
4. 接口功能测试
我们使用curl命令模拟客户端发送请求。首先准备一张图片的Base64字符串。假设你有一张test.jpg,可以使用Python生成测试字符串:
```bash
python3 -c "import base64; print(base64.b64encode(open('test.jpg', 'rb').read()).decode())" > img_base64.txt
```
然后读取该文件内容并构造JSON请求(请将YOUR_BASE64_STRING替换为img_base64.txt中的实际内容):
```bash
curl -X POST "http://localhost:8080/predict" \
-H "Content-Type: application/json" \
-d '{"image_base64": "YOUR_BASE64_STRING"}'
```
如果一切正常,你将收到类似以下的JSON响应:
```json
{"predicted_class": 282}
```
至此,一个基于Docker的深度学习模型服务已成功在服务器上部署并运行。后续若需更新模型,只需修改代码,重新构建镜像并重启容器即可。