第三章 环境搭建:Docker 容器化部署、CUDA/cuDNN 版本管理、conda 环境隔离

说实话,模型移植这件事,十次有八次的坑都出在环境上。

我见过太多团队,模型在 A 机器上跑得飞起,换到 B 机器直接报错。CUDA 版本不对、cuDNN 不兼容、Python 包冲突……这些破事能把人逼疯。

所以这一章,咱们就把环境搭建这件事彻底聊透。你想想看,如果连地基都不稳,上面盖的楼再漂亮也没用。

3.1 Docker 容器化部署:一次封装,到处运行

Docker 这东西,说白了就是把你的整个运行环境打包成一个「箱子」。你带着这个箱子去任何机器上,都能原样跑起来。

我个人习惯,每个项目都从 Dockerfile 开始写。这样团队新成员来了,直接 docker build 就完事,不用折腾半天环境。

核心思路: 把操作系统、CUDA、cuDNN、Python、依赖库全部写进 Dockerfile,生成镜像。以后部署就是拉镜像、跑容器。

下面是我常用的一个 Dockerfile 模板,专门给模型移植用的:

# 基础镜像选 nvidia 官方提供的,自带 CUDA 和 cuDNN
FROM nvidia/cuda:11.8.0-cudnn8-devel-ubuntu20.04

# 设置非交互模式,避免安装时卡住
ENV DEBIAN_FRONTEND=noninteractive

# 安装系统依赖
RUN apt-get update && apt-get install -y \
    python3.8 \
    python3-pip \
    wget \
    git \
    && rm -rf /var/lib/apt/lists/*

# 设置 Python 软链接
RUN ln -s /usr/bin/python3.8 /usr/bin/python

# 安装 Python 包
COPY requirements.txt /tmp/
RUN pip install --no-cache-dir -r /tmp/requirements.txt

# 设置工作目录
WORKDIR /workspace

# 默认命令
CMD ["/bin/bash"]

小技巧: 我建议把 requirements.txt 单独 COPY,而不是和代码一起 COPY。这样可以利用 Docker 的缓存机制——只要 requirements.txt 没变,就不会重新安装依赖包,能省不少时间。

构建和运行命令也很简单:

# 构建镜像
docker build -t model-porting:v1 .

# 运行容器,挂载当前目录到容器内
docker run --gpus all -it --rm \
    -v $(pwd):/workspace \
    model-porting:v1

这里有个坑,我踩过好几次——--gpus all 这个参数。老版本的 Docker 不支持,得装 nvidia-container-toolkit。我曾经在客户现场折腾了俩小时才发现是这个问题。

注意: 如果你用的是 Docker 19.03 之前的版本,需要手动安装 nvidia-docker2。新版本直接用 --gpus 参数就行。

3.2 CUDA/cuDNN 版本管理:别让版本坑了你

模型移植最头疼的事之一,就是 CUDA 版本不匹配。

你想想看,PyTorch 1.13 要求 CUDA 11.7,TensorRT 8.5 要求 CUDA 11.8,而你的机器上装的是 CUDA 12.0……这就很尴尬了。

我的做法是:用 conda 管理 CUDA 工具包,而不是装系统级的 CUDA

具体来说,你可以通过 conda 安装指定版本的 CUDA 和 cuDNN:

# 创建环境并指定 CUDA 版本
conda create -n porting_env python=3.8
conda activate porting_env

# 安装 CUDA 工具包(注意不是驱动)
conda install cudatoolkit=11.8 -c nvidia

# 安装 cuDNN
conda install cudnn=8.6.0 -c nvidia

这样做的好处是:不同项目可以用不同的 CUDA 版本,互不干扰。

下面这张表是我整理的常见框架和 CUDA 版本的对应关系,你可以参考:

框架 推荐 CUDA 版本 推荐 cuDNN 版本 备注
PyTorch 1.13 11.7 8.5 兼容 11.6-11.8
PyTorch 2.0 11.8 8.7 推荐用 11.8
TensorFlow 2.12 11.8 8.6 官方只支持 11.8
TensorRT 8.5 11.8 8.6 必须匹配
ONNX Runtime 1.15 11.8 8.6 GPU 版本需要

重要提醒: 系统级的 NVIDIA 驱动版本必须 >= 你安装的 CUDA 工具包所需的最低驱动版本。比如 CUDA 11.8 需要驱动版本 >= 520.61.05。这个可以用 nvidia-smi 查看。

3.3 Conda 环境隔离:每个项目一个独立小世界

conda 这东西,我刚开始用的时候觉得麻烦,后来真香了。

为什么?因为 Python 的包依赖管理实在太乱了。A 项目要 numpy 1.21,B 项目要 numpy 1.24,没有 conda 的话,你只能二选一。

我的标准流程是这样的:

  1. 创建环境:每个项目一个独立环境,命名规则是 项目名_python版本
  2. 安装依赖:先用 conda 装,conda 没有的再用 pip
  3. 导出环境:项目完成后导出 environment.yml,方便别人复现

具体操作:

# 创建环境
conda create -n yolo_porting python=3.8

# 激活环境
conda activate yolo_porting

# 安装 PyTorch(用 conda 装,会自动处理 CUDA 依赖)
conda install pytorch=1.13.1 torchvision=0.14.1 cudatoolkit=11.7 -c pytorch

# 安装其他依赖
pip install onnx onnxruntime-gpu tensorrt

# 导出环境配置
conda env export > environment.yml

别人拿到你的 environment.yml 后,直接运行:

conda env create -f environment.yml

就能复现一模一样的运行环境。

个人经验: 我建议把 conda 和 pip 混用的情况降到最低。如果非要用 pip,记得在 conda 装完所有能装的包之后,再用 pip 装剩下的。顺序搞反了容易出问题。

3.4 三剑客组合:Docker + Conda + CUDA 版本管理

你可能会问:这三者到底怎么配合?

我的做法是:Docker 管操作系统和驱动层,conda 管 Python 和框架层

具体来说:

  • Docker 镜像里装好系统级的 CUDA 驱动和 cuDNN
  • 容器启动后,在容器内部用 conda 创建项目环境
  • 每个项目用不同的 conda 环境,互不干扰

这样即使同一个 Docker 镜像,也能跑多个不同依赖的项目。

我曾经在一个项目里,需要同时跑 PyTorch 1.13 和 TensorFlow 2.12 的模型。如果没有 conda 隔离,这两个框架的依赖包会打得不可开交。有了 conda,各玩各的,相安无事。

避坑指南: 注意 conda 环境不要和系统 Python 混用。我见过有人直接在 base 环境里装包,结果把系统搞崩了。记住:永远不要在 base 环境里装项目依赖

3.5 实战:从零搭建一个模型移植环境

好了,理论说完了,咱们来点实际的。

假设你现在要移植一个 YOLOv8 模型到 TensorRT,环境搭建的完整流程如下:

# 第一步:拉取基础镜像
docker pull nvidia/cuda:11.8.0-cudnn8-devel-ubuntu20.04

# 第二步:运行容器
docker run --gpus all -it --rm \
    -v /path/to/your/project:/workspace \
    nvidia/cuda:11.8.0-cudnn8-devel-ubuntu20.04

# 第三步:在容器内安装 miniconda
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
bash Miniconda3-latest-Linux-x86_64.sh -b -p /opt/conda
export PATH=/opt/conda/bin:$PATH

# 第四步:创建项目环境
conda create -n yolo_tensorrt python=3.8 -y
conda activate yolo_tensorrt

# 第五步:安装依赖
conda install pytorch=1.13.1 torchvision=0.14.1 cudatoolkit=11.7 -c pytorch -y
pip install ultralytics onnx onnxruntime-gpu tensorrt

# 第六步:验证环境
python -c "import torch; print(torch.cuda.is_available())"
# 输出 True 就说明环境没问题

整个过程下来,你的环境就是完全可复现的。换台机器,重复上面六步,结果一模一样。

总结一下: Docker 保证操作系统层一致,conda 保证 Python 层一致,CUDA 版本管理保证 GPU 计算层一致。三层隔离,稳如老狗。

嗯,环境搭建这部分就聊到这儿。下一章咱们开始讲模型格式转换,那才是真正有意思的部分。