ViT-Adapter复现

ViT-Adapter 复现

​ 好久没被工程问题折磨了,又被折磨了好惨,不过每次折磨总是能学到新东西

不要轻易尝试重构代码

​ 我在复现 ViT-Adapter/segmentation at main · czczup/ViT-Adapter 这个仓库的时候,由于官方 repo 给出的 mmcv 环境太老,必须使用 cuda=11.1 的环境,但是服务器的版本是 cuda=12.2,并不能适配 repo 的 mmcv 环境,于是我想着一般来说 mmcv 的旧版本的函数在新版本中一般有对应,直接安装了新版本的 mmcv 环境,并慢慢修改官方 repo 的代码,无奈的是失败了(代码量太大了,我又不是写这个仓库的不可能对代码结构很清晰,而且容易改错)

不要轻易尝试重构一个陌生 repo 的代码,让代码匹配环境比让环境匹配代码的工作量大得多

配置 CUDA 驱动

​ 既然放弃了让代码匹配环境这个方式,我们只能配置官方 repo 的环境了,但是服务器的 cuda=12.2 太新了怎么办呢,一般来说常用的方式有两种:

  • Docker:配置虚拟环境,是一种很方便的方法,但是我目前还不会
  • Conda:Conda 也可以配置在虚拟环境内配置 CUDA 版本!
  • 服务器多 CUDA:不推荐,步骤折磨而且繁琐,而且需要管理员权限

​ conda 可以在创建环境时通过指定安装特定版本的 CUDA 工具包(cudatoolkit)来间接实现CUDA版本的配置。以下是具体方法及依据

1
2
3
4
5
conda create -n myenv python=3.7
conda install cudatoolkit=11.1 -c nvidia
conda install cudnn # 一般而言指定了cudatoolkit的版本conda会自动适配cudnn的版本的
conda install torch==1.9.0+cu111 torchvision==0.10.0+cu111 torchaudio==0.9.0 -f https://download.pytorch.org/whl/torch_stable.html
...

​ 按照这个方式就配置好了低版本的 CUDA 了,但是这时候在终端中使用 nvcc -V 命令之后显示的仍然是全局环境的 CUDA 版本,不过这不影响,因为这个命令链接到的路径不是我们在虚拟环境的 CUDA 路径:

1
2
3
4
5
6
7
8
9
10
11
nvcc -V

nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2023 NVIDIA Corporation
Built on Tue_Aug_15_22:02:13_PDT_2023
Cuda compilation tools, release 12.2, V12.2.140
Build cuda_12.2.r12.2/compiler.33191640_0

which nvcc # 查看nvcc路径

/usr/local/cuda/bin/nvcc # 并不是我们虚拟环境的 CUDA

如果想要输出虚拟环境的 CUDA 版本,改变一下环境变量就行了:

1
export PATH="~/.conda/envs/your_env_name/bin:$PATH"

为什么 conda 可以配置 CUDA

​ CUDA的驱动与工具包是解耦的,运行依赖两部分:驱动(Driver)和 工具包(Toolkit),驱动由操作系统管理(如Linux的 nvidia-driver),负责与GPU硬件通信。而工具包是包含编译器(nvcc)和运行时库(libcudart)等用户态组件的。我们常说的 CUDA 版本是 CUDA Toolkit(工具包)的版本而非驱动的版本,因此没有必要重新安装一个驱动

libstdc++ error

1
ImportError: /lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.29' not found (required by /home/wuye/anaconda3/envs/tf2/lib/python3.8/site-packages/google/protobuf/pyext/_message.cpython-38-x86_64-linux-gnu.so)

​ 这种错误属于动态链接库版本不兼容导致的运行时错误,GCC(GNU Compiler Collection)环境主要用于将高级编程语言(如C、C++)的源代码编译为可执行程序或库文件,在 torch,numpy,pandas,scipy 等库里面都常见碰到,原因在于:

  • 系统自带的 libstdc++.so.6 版本较低(如缺少 GLIBCXX_3.4.29),而程序或依赖库需要更高版本的库支持。例如,Ubuntu 20.04 默认的 libstdc++6 包可能仅提供到 GLIBCXX_3.4.28,而某些新编译的程序需要 3.4.29

这时候解决方式也一半有以下几种:

  • 升级系统 libstdc++(推荐,一劳永逸),但是我没有管理员权限,用不了这种方式
  • 在 Conda 环境中安装 libstdcxx-ng:如果升级系统库遇到问题,可以在 Conda 环境中覆盖依赖(conda 的功能是真的强大,这种都可以安装)
  • 降级依赖库版本:比如我是在 scipy=1.7.3 版本下遇到的这个问题,我降级了它的版本到 1.6.0,这时候就解决问题了

至此这次的折磨的问题也全部解决!