多版本CUDA和TensorFlow共存
文章目录
直奔主题,为什么要做这件事情?
- 服务器目前安装了CUDA 8.0、TensorFlow 1.3.0,并已有线上服务基于该版本环境配置开发,无法轻易修改本机环境版本
- TensorFlow版本迭代很快,新版本使用更高版本的CUDA,不仅计算速度上更快,而且还有一些更加丰富的API可供使用,例如TensorFlow 1.8.0版本中的eager模式
所以通过查资料以及实验完成了这件事情,并记录下来以供有同样需求的朋友参考
文章修改记录:
- 2018.11.25:统一路径信息、修改部分链接、增加全局pip源设置以及一些小问题修复
前言
文章开头说了为什么要做这件事,所以其实本质就是为了在不改变原有版本的基础上能够使用新版本,那么便需要调研多版本共存的可行性
经过调研,CUDA和TensorFlow均可以做到多版本共存,障碍只剩一个——显卡驱动。因为目前的显卡驱动384.66是支持CUDA 8.0的最新版本驱动,然而其不支持更高版本的CUDA。所以考虑使用支持更高版本CUDA的显卡驱动,并测试其是否向下兼容低版本CUDA。测试结果是可行的,这也才有了这篇文章
整篇文章分为两部分:使用方法、安装过程
- 使用方法是将安装过程中创建虚拟环境并配置的过程使用脚本实现,以达到一步到位的便捷使用。脚本内容可以见文后
- 安装过程叙述了为了达成多版本共存的目的所做的一些操作或者配置
本文所使用的Anaconda软件以root权限安装在/home/anaconda3
目录下,可根据需要自行修改。安装后服务器上所有用户均可使用Anaconda来创建虚拟环境
本文由 @李君阳 与我一同完成
使用方法
若要创建指定CUDA版本的虚拟环境,请运行 create_virtual_env.sh 脚本(见文末,或查看该链接),根据提示输入虚拟环境名称、Python版本、CUDA版本即可
1 | Enter the name of Anaconda virtual environment: |
创建完成后会显示 Everything is DONE!
随后使用source activate XXX(或者conda activate XXX)
命令进入虚拟环境,在虚拟环境中可以使用创建时指定的Python版本和CUDA版本,可自由使用pip安装自己所需要的Python包,不影响本机环境
要回到本机环境使用source deactivate(或者conda deactivate)
退出虚拟环境
安装过程
1、安装显卡驱动
目前服务器上安装的显卡驱动版本为384.66,是支持CUDA 8.0的最新版本驱动。目前已知该驱动无法支持更高版本的CUDA,所以需要验证安装支持高版本CUDA的显卡驱动是否能正常向下兼容低版本CUDA
下载
去 http://www.nvidia.cn/Download/index.aspx 这里寻找对应的显卡驱动即可,这里选择:
- Product Type: Tesla
- Product Series: M-Series
- Product: M40 24GB
- Operating System: Linux 64-bit
- CUDA Toolkit: 9.1
- Language: English(US)
这里下载的文件名是:NVIDIA-Linux-x86_64-390.46.run
安装
首先先卸载旧版本驱动
1 | ./NVIDIA-Linux-x86_64-384.66.run --uninstall |
然后对新驱动添加可执行权限,安装
1 | chmod u+x NVIDIA-Linux-x86_64-390.46.run |
进入安装界面后一路同意就可以
验证是否支持低版本CUDA
使用CUDA自带的samples进行验证
1 | cd /usr/local/cuda-8.0/samples/1_Utilities/deviceQuery |
如果在最后看到以下信息,则证明该驱动能够支持低版本CUDA
1 | deviceQuery, CUDA Driver = CUDART, CUDA Driver Version = 9.1, CUDA Runtime Version = 8.0, NumDevs = 2, Device0 = Tesla M40 24GB, Device1 = Tesla M40 24GB |
一些错误
- ERROR: An NVIDIA kernel module ‘nvidia-uvm’ appears to already be loaded in your kernel. This may be because it is in use (for example, by an X server, a CUDA program, or the NVIDIA Persistence Daemon), but this may also happen if your kernel was configured without support for module unloading. Please be sure to exit any programs that may be using the GPU(s) before attempting to upgrade your driver. If no GPU-based programs are running, you know that your kernel supports module unloading, and you still receive this message, then an error may have occured that has corrupted an NVIDIA kernel module’s usage count, for which the simplest remedy is to reboot your computer.
使用nvidia-smi命令查看有哪些程序在使用显卡,kill掉。如果没有使用显卡的程序依旧报错,可以重启服务器
2、安装CUDA-9.0 & cuDNN-7.1
CUDA下载
注意:目前CUDA最新版本为9.1,但是TensorFlow的最新版本1.8还未支持CUDA 9.1,所以只能安装CUDA 9.0
去 https://developer.nvidia.com/cuda-downloads 这里寻找对应平台的文件下载即可。进入后默认显示最新版本CUDA,选择靠右侧的Legacy Releases,进入后选择CUDA Toolkit 9.0 (Sept 2017)
这里一些选项的选择为:
- Operating System: Linux
- Architecture: x86_64
- Distribution: CentOS
- Version: 7
- Installer Type: runfile(local)
下面会显示两个安装文件,一个 Base Installer ,两个Patch。安装完Base后再安装Patch即可
直接复制下载链接,在服务器上wget下载即可
CUDA安装
添加可执行权限,安装
1 | chmod u+x cuda_9.0.176_384.81_linux.run |
接下来会有一系列选择
- 是否安装显卡驱动:选no,因为已经装了最新的驱动
- 是否安装CUDA 9.0:选yes
- 输入安装位置:默认即可,因为默认位置就区分开了不同的CUDA版本
- 是否创建软链:选no,因为要实现多版本CUDA共存。如果以前安装过CUDA并创建过软链,需要删除
- 是否安装sample:选no,因为在安装路径下会有一份sample,这个是问是否要在自己的目录下再安装一份
然后再安装一下两个补丁即可:cuda_9.0.176.1_linux.run、cuda_9.0.176.2_linux.run
CUDA测试
进入samples目录,选择第一个例子进行测试
1 | cd /usr/local/cuda-9.0/samples/1_Utilities/deviceQuery |
如果在最后看到以下信息,则证明CUDA 9.0安装成功
1 | deviceQuery, CUDA Driver = CUDART, CUDA Driver Version = 9.1, CUDA Runtime Version = 9.0, NumDevs = 2 |
cuDNN下载
去 https://developer.nvidia.com/rdp/cudnn-download 选择对应的版本下载即可。不过需要先注册开发者账号后才可以下载
刚才安装的CUDA是9.0,所以我们选择
- Download cuDNN v7.1.3 (April 17, 2018), for CUDA 9.0
- cuDNN v7.1.3 Library for Linux
cuDNN安装
执行解压操作
1 | mkdir cuda-9.0_cudnn |
解压后的文件夹是cuda。执行以下操作把文件复制到相应的位置
1 | cp cuda/include/cudnn.h /usr/local/cuda-9.0/include/ |
注意
以上过程基于服务器上已经有一个CUDA版本。如果服务器上未安装过CUDA,按照这个过程依次安装两个版本CUDA即可,只需注意不要创建软链。如果打算在本机环境使用CUDA,则需要配置环境变量。如果打算都在虚拟python环境下运行,则本机不需要配置相关环境变量,在之后启动虚拟环境时配置
3、安装Anaconda
下载安装
使用该下载链接下载Anaconda安装脚本,默认Python版本是3.6.5
添加可执行权限后,执行安装
安装完一堆包之后会询问是否要添加环境变量,这里选择no,稍后再添加。然后会继续询问是否安装VSCode,选择no。此时安装完成
因为我们使用Anaconda只是作为虚拟python环境管理,不需要用到其自带的python以及相关包,所以需要将Anaconda的bin放到path后,否则系统的python会失效。所以将下面这一行添加到需要使用Anaconda账户的.bashrc
文件中
1 | export PATH=$PATH:/home/anaconda3/bin |
source一下或者退出重新登陆
然后执行ln -s /home/anaconda3/etc/profile.d/conda.sh /etc/profile.d/conda.sh
,这是为了服务器上所有用户都可以使用conda activate
和conda deactivate
来进入和退出虚拟环境(即source和conda都可以)
修改国内镜像仓库
因为Anaconda默认使用国外的下载地址,为了提高国内的下载速度,可以使用国内的清华镜像源或者中科大镜像源,二选一即可,执行三条命令
加入–system是配置全局的conda config。若个人账户想修改,则取消–system即可,此时在个人账户下会覆盖全局配置(类似 git config )。个人账号相关配置会写在 ~/.condarc 里面
- 清华Anaconda镜像
1 | conda config --system --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ |
- 中科大Anaconda镜像
1 | conda config --system --add channels http://mirrors.ustc.edu.cn/anaconda/pkgs/free/ |
创建虚拟环境
基本命令为 conda create --name XXX
,–name可缩写为-n
如果在创建虚拟环境时报错(跟urls.txt或者environments.txt有关,一般是第一次使用Anaconda时会出现),参考下方一些错误部分
关于创建虚拟环境,分以下三种情况陈述
conda create --name test1
此时虚拟环境并不起作用,进入test1后会发现实际上使用的依旧是本机Python环境,并且在test1中使用pip安装或者删除包均是对本机环境操作
所以不要使用这种方式
conda create --name test2 python=X.X.X
该命令会创建一个名为test2的纯净虚拟环境,并且会安装python X.X.X版本,无其他Python包。进入test2后,使用python -V
和pip -V
可以看到使用的的确是该虚拟环境,并且在test2中使用pip安装或者删除包均是对该虚拟环境进行操作,不会影响本机环境
这里python的入参有多种
如果只写python,则安装的是Anaconda自带的Python版本(在这里是3.6.5)
如果是python=2或者python=3,则安装的是python2或者python3的最新版本(目前是2.7.15和3.6.5)
如果写了二级版本号,例如python=2.6或者python=3.5,则安装的是python2.6或者python3.5分支的最新版本(目前是2.6.9和3.5.5)
如果写了最小的版本号,例如python=2.7.8或者python=3.6.2,则安装的便是输入的特定版本
conda create --name test3 python=2.7 numpy
该命令会创建一个名为test3的纯净虚拟环境,并且会安装python2.7的最新版本,在此基础上还会额外安装numpy包。当然numpy包也可以类似Python一样指定版本,例如numpy=1.10,则会安装1.10.4版本。不指定则安装的就是最新版本。其他同上
conda create --name test4 numpy
该命令会创建一个名为test4的纯净虚拟环境,并且会安装Anaconda自带的Python版本(在这里是3.6.5),在此基础上还会额外安装numpy包。其他同上
启动和退出虚拟环境
- 启动
1 | source activate XXX(或者conda activate XXX) |
启动成功后在命令行前会有虚拟环境的名字(XXX)
- 退出
1 | source deactivate(或者conda deactivate) |
其他常用指令
查看有哪些虚拟环境:conda env list
删除虚拟环境:conda env remove -n XXX
多版本TensorFlow共存
在不同的虚拟环境中安装不同版本的TensorFlow即可。若不同版本的TensorFlow依赖的CUDA版本不同,则参照下一小节“给虚拟环境指定CUDA版本”来操作
设置全局pip源配置
进入到虚拟环境后,使用pip安装Python包的时候会发现其从原始的国外地址进行下载。有时下载速度较慢,所以我们要更新pip源为国内源
编辑 /etc/pip.conf
文件(若无则创建),添加以下内容
1 | [global] |
该方式可以进行全局pip源配置,便于服务器上所有用户均可使用。若只要某些用户使用,那么编辑的就是~/.pip/pip.conf
文件
一些错误
NotWritableError: The current user does not have write permissions to a required path.
path: /home/username/.conda/pkgs/urls.txt
uid: 1001
gid: 1002
If you feel that permissions on this path are set incorrectly, you can manually change them by executing
$ sudo chown 1001:1002 /home/username/.conda/pkgs/urls.txt
In general, it’s not advisable to use ‘sudo conda’.
自己创建该文件。类似的还有 /home/username/.conda/environments.txt
4、给虚拟环境指定CUDA版本
处理环境变量
假设此时服务器上安装了两个CUDA版本,分别为CUDA 8.0(/usr/local/cuda-8.0)和CUDA 9.0(/usr/local/cuda-9.0),并且在本机上配置了一个版本(例如8.0)的环境变量($CUDA_HOME, $LD_LIBRARY_PATH)。没配置更好,这里配置是为了验证切换虚拟环境时指定的CUDA版本是否发生相应的改变
首先创建一个虚拟环境,让这个虚拟环境使用CUDA 9.0的lib
1 | conda create -n cuda_test python=3 |
然后设定启动虚拟环境以及退出时需要执行的脚本,为了使虚拟环境启动时环境变量不同于本机环境,退出时又恢复为本机环境
1 | mkdir -p /home/username/.conda/envs/cuda_test/etc/conda/activate.d |
- 编辑启动脚本
vim /home/username/.conda/envs/cuda_test/etc/conda/activate.d/activate.sh
输入以下内容
1 | ORIGINAL_CUDA_HOME=$CUDA_HOME |
添加执行权限 chmod +x /home/username/.conda/envs/cuda_test/etc/conda/activate.d/activate.sh
- 编辑退出脚本
vim /home/username/.conda/envs/cuda_test/etc/conda/deactivate.d/deactivate.sh
输入以下内容
1 | export CUDA_HOME=$ORIGINAL_CUDA_HOME |
添加执行权限 chmod +x /home/username/.conda/envs/cuda_test/etc/conda/deactivate.d/deactivate.sh
测试
首先先在本机查看环境变量 CUDA_HOME 和 LD_LIBRARY_PATH
echo $CUDA_HOME
结果为/usr/local/cuda-8.0
echo $LD_LIBRARY_PATH
结果为/usr/local/cuda-8.0/lib64
进入虚拟环境
1 | source activate cuda_test |
查看此时的环境变量
echo $CUDA_HOME
结果为/usr/local/cuda-9.0
echo $LD_LIBRARY_PATH
结果为/usr/local/cuda-9.0/lib64:/usr/local/cuda-8.0/lib64
退出虚拟环境
1 | source deactivate |
再次查看环境变量,会发现恢复为/usr/local/cuda-8.0和/usr/local/cuda-8.0/lib64,证明在虚拟环境中指定CUDA版本lib成功
PS:也可以通过在虚拟环境中安装1.8.0版本的tensorflow-gpu来验证,因为其必须使用CUDA 9.0才能正确import,否则会报错ImportError: libcublas.so.9.0: cannot open shared object file: No such file or directory
5、小结
至此,完成以上操作后,在服务器上即可达到多版本CUDA、TensorFlow共存的目的
注意事项
通过第四小节可以看到,可以通过编写虚拟环境的启动脚本和退出脚本来管理虚拟环境中的环境变量,使其启动时不同于本机环境,退出时又恢复为本机环境。但是如果需要在脚本中对PATH环境变量做改变的话,会发生一些问题——退出时没有正确恢复PATH环境变量
在对虚拟环境启动和退出的过程做了梳理后,可以有办法解决这个问题(使用上述ORIGINAL_的方式做中间转换是无法解决的)
假设启动前PATH内容为/usr/bin
启动过程:
- 在启动时,conda会先修改PATH,在本机PATH的前面加上
/home/username/.conda/envs/cuda_test/bin:
,这是为了在虚拟环境中能够使用虚拟环境自己的Python。此时PATH内容为PATH=/home/username/.conda/envs/cuda_test/bin:/usr/bin
,然后export该PATH - 然后执行添加的启动脚本activate.sh。假如在其中对PATH做了添加,此时PATH内容为
PATH=/xxxx/bin:/home/username/.conda/envs/cuda_test/bin:/usr/bin
。进入虚拟环境中echo $PATH得到的内容也是/xxxx/bin:/home/username/.conda/envs/cuda_test/bin:/usr/bin
- 然后conda会将此时的PATH在某个地方备份记录一下,并且将其在第一步添加的内容删掉。也就是说这时conda会保留一个内容为
/xxxx/bin:/usr/bin
的PATH
退出过程:
- 首先执行添加的退出脚本deactivate.sh
- 将启动第三步存下来的PATH拿出来直接export。所以在deactivate.sh中使用ORIGINAL_的方式做恢复是无效的
当恢复到本机环境时,PATH的内容为/xxxx/bin:/usr/bin
的PATH,与启动前不一样
启动过程主要执行的是/home/anaconda3/etc/profile.d/conda.sh
中的_conda_activate()
方法。退出过程主要执行的是/home/anaconda3/etc/profile.d/conda.sh
中的_conda_deactivate()
方法
目前想到的一种解决方案如下:(未尝试)
- 在退出脚本deactivate.sh的头部添加
FIX_PATH=$CUDA_HOME
- 在
/home/anaconda3/etc/profile.d/conda.sh
的_conda_deactivate()
方法中的eval "$ask_conda"
之后,在PATH中正则匹配FIX_PATH的内容并将其删掉,再重新export PATH
Reference
https://www.jianshu.com/p/4ac737fd6b45
https://blog.kovalevskyi.com/multiple-version-of-cuda-libraries-on-the-same-machine-b9502d50ae77
create_virtual_env.sh
链接:https://gist.github.com/bluesmilery/b1b4a840fcfabcda8ae26144988480d2
1 | !/bin/bash |