写在最前面,最近做实验需要对比一篇18年的老方法,其代码实现基于老版本Torch(on Lua),而非现在主流的Pytorch或者Tensorflow,我需要在Linux上搭建Torch环境并跑通这个老方法的源码。搜刮了很久,发现可以参考的国内外资料很少,而且大多数都零零散散的并不全面,这里特别感谢另一篇博客的教程(下方附上链接),对我的帮助很大。本篇文章的内容也有部分参考于这篇教程,写的很详细。
集众家之所长,手把手教你如何在Ubuntu18.04上安装CUDA10.0+CUDNN7.5+Torch7(非Pytorch)(保姆级教学)_免费的单身汉RainsdRop的博客-CSDN博客_lubuntu18.04 cuda10.0安装torch0.4.0
折腾了很久终于把环境搭建好过后并运行成功后,决定写一篇教程帮助未来可能有需要的人。写文章不易,如果有不足之处欢迎理性讨论。请勿剽窃和恶意转载。
简单介绍一下搭建环境的硬件配置,Ryzen 3600 + GTX 1660 + 16G RAM + 512G SSD。这里面值得关注的主要是GTX 1660这块显卡,因为CUDA 10.0以下的版本只能支持到Computation Capacity <= 7.0的设备,而GTX 16系列和RTX 20系列后续更新的系列Computation Capacity不满足这个条件,以我手上的1660为例,报错信息里会提到该设备Computation capacity=7.5。因此我们需要选择安装CUDA 10.0以上的版本,否则安装torch的时候会报错:
Unsupported gpu architecture 'compute_75'
但选择10.0以上的CUDA 版本会带来另一个问题:official版本的torch并不支持CUDA 10+(至少我迄今为止没有安装成功过),从一开始就存在这样的硬件冲突,注定正常的路线是很艰难的,解决方案有三种:
至于系统,CUDA 10.2官网下载界面提供的选择有18.04和16.04,建议选择老版本的ubuntu,兼容性更好,当然如果你经验丰富可以尝试在高版本的ubuntu上折腾,也能顺利安装CUDA,但是不排除会带来一些节外生枝的问题。这里个人选择的是ubuntu 16.04,因为其自带gcc/g++版本为5,满足安装的条件,不需要降级,少一步折腾少一点翻车的可能。
cuDNN版本和CUDA版本是对应的,所以确定了CUDA版本后,在cuDNN下载界面选择匹配的版本下载安装即可,我的选择是cuDNN 7.6.5 (for CUDA 10.2)。
Lua版本应该没什么讲究,稳妥起见我选择了5.2版本。
废话不多说,直接开始从系统安装开始教,你可以根据自己的需要跳转到感兴趣的地方看。
清华源下载ubuntu镜像:清华大学开源软件镜像站
下载镜像刻录工具BalenaEtcher(不要去用老毛桃之类的PE系统安装,没什么意义)
准备一个U盘,用BalenaEthcer将Ubuntu镜像写进U盘。
后面的步骤都是老生常谈了:U盘插上要装系统的主机,开机进入BIOS修改Boot顺序把U盘放在前面,然后保存退出重启,这时候会进入Ubuntu的引导界面。选择 Ubuntu / Installation Ubuntu,然后就跟着安装步骤走就行了,很简单,不懂的可以搜一下别人的教程。这里就不再赘述详细步骤了,相信大家都会。
ubuntu 16.04刚装上你会发现显示的分辨率很低,不利于使用,这时候需要你安装显卡驱动。
2.2.1 关闭nouveau(没有vim就先装vim,或者用gedit打开)
sudo vim /etc/modprobe.d/blacklist.conf
在文件末尾插入下面两行语句:
blacklist nouveau
options nouveau modeset=0
:wq 保存退出,命令行执行:
sudo update-initramfs -u
重启电脑,执行命令:
lsmod | grep nouveau # 检查 nouveau 是否关闭(没有输出则已经成功关闭)
2.2.2 安装驱动 NVIDIA 驱动下载
在官网选择你的显卡型号,下载对应的runfile (我的是NVIDIA-Linux-x86_64-515.76.run),执行:
sudo chmod a+x NVIDIA-Linux-x86_64-515.76.run
sudo ./NVIDIA-Linux-x86_64-515.76.run -no-x-check -no-nouveau-check -no-opengl-files
注1:有的教程会提示关闭图形界面,我这里没有关闭而选择直接安装,没有出现任何问题。
注2:驱动安装进行到以下步骤时请选择yes,不然重启后鼠标可能就没法用了。(亲身经历)
Would you like to run the nvidia-xconfigutility to automatically update your x configuration so that the NVIDIA x driver will be used when you restart x? Any pre-existing x confile will be backed up.
安装完毕后,重启电脑,这时候你会发现显示分辨率提高了,这意味着驱动已经打上。执行nvidia-smi,如果输出显卡信息说明驱动确实已经打上。
torch的安装需要低版本的gcc/g++,如果本机的gcc/g++版本过高,请进行降级,如果是ubuntu 16.04,其自带版本为5已经满足要求,可以忽略这个步骤。
2.3.1 更新源
sudo vim /etc/apt/sources.list
# 文件末尾加上语句
deb [arch=amd64] http://archive.ubuntu.com/ubuntu focal main universe
sudo apt-get update
2.3.2 安装所需版本的 gcc/g++
sudo apt-get install gcc-5 g++-5
2.3.3 配置优先级,将版本5的优先级配置为最高(如果存在多个版本)
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-5 50
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-11 20
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-5 50
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-11 20
sudo update-alternatives --config gcc # 查看优先级
注意命令里面的版本需要根据你主机里实际存在的gcc版本修改,当然如果没有多个版本就不需要这一步。
下载对应的CUDA runfile和其对应的补丁(都是.run文件)
2.4.1 安装
sudo sh xxx.run # 别忘了补丁也要安装
注:安装CUDA过程中不要安装驱动。
2.4.2 配置路径
gedit ~/.bashrc
# 文件末尾加上语句
export PATH=/usr/local/cuda-10.2/bin${PATH:+:${PATH} }
export LD_LIBRARY_PATH=/usr/local/cuda-10.2/lib64${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
source ~/.bashrc
nvcc -V # 检查cuda版本是否替换路径
下载CUDA版本对应的cuDNN,注意别选错了,可能会有多个匹配得上的,选择合适的即可。
2.5.1 安装,将cudnn文件移动至对应的cuda目录下
# 解压
tar zxvf cudnn-10.2xxx.tgz
# 复制到cuda-10.2目录下
cd cuda
sudo cp -P lib64/* /usr/local/cuda-10.2/lib64/
sudo cp -P include/* /usr/local/cuda-10.2/include/
sudo chmod a+r /usr/local/cuda-10.2/include/cudnn.h
sudo chmod a+r /usr/local/cuda-10.2/lib64/libcudnn*
# 查看cuDNN版本
cat /usr/local/cuda/include/cudnn.h | grep CUDNN_MAJOR -A 2
2.5.2 (附)移除cuDNN安装的命令,将文件从之前安装的cuda目录下删除即可
sudo rm -rf /usr/local/cuda-10.2/include/cudnn.h
sudo rm -rf /usr/local/cuda-10.2/lib64/libcudnn*
sudo apt install git
sudo apt-get purge cmake
git clone https://github.com/Kitware/CMake.git # 可以自己下载
sudo apt-get install libssl-dev
cd CMake
./bootstrap && make && sudo make install
这一步可能耗时稍微久一点。
下载安装包 lua-5.2.4.tar.gz
# 安装
tar zxf lua-5.2.4.tar.gz
cd lua-5.2.4
sudo apt-get install libreadline-dev
make linux test
sudo make install
# 卸载
cd lua-5.2.4
sudo make uninstall
cd ..
rm -rf lua-5.2.4
wget https://luarocks.org/releases/luarocks-3.9.1.tar.gz
tar zxpf luarocks-3.9.1.tar.gz
cd luarocks-3.9.1
./configure && make && sudo make install
注意安装完lua和luarocks过后可以检查一下彼此config是否对应的上。
上面提到了,我们选择的是non-official版本的torch,但总体的步骤是和official torch类似的。
git clone https://github.com/nagadomi/distro.git ~/torch --recursive
注意这里不能直接到github页面下载.zip,因为git clone xxx.git --recursive会嵌套地clone一些文件,如果直接下载.zip会存在文件缺失。
可能有的朋友会在这一步因为网络问题各种报错不能下载成功,这里提供一个我的解决方案:在Vultr上临时租一台服务器(我用的美国节点),然后在服务器上执行对应的git clone命令,最后通过scp -r拷贝到本地。虽然这个方法比较笨,而且scp也比较慢,但总体是可靠的。如果你们有更方便的方法欢迎提出来。下载过后放在~/torch目录。
当然,没有网络问题的直接clone到本地就完事了。
后续安装依赖的时候需要下载OpenBLAS,但同样很多朋友会碰到网络问题卡在这一步无法获取,所以这里也采用自行下载的方法(github-OpenBLAS),将其放在~/OpenBLAS目录。当然,和尚面一样,没有网络问题的朋友不用理会这一步。
cd torch
rm -fr cmake/3.6/Modules/FindCUDA*
cd torch/extra/cutorch
vim atomic.patch
#将下面的内容复制进去,然后保存并退出
diff --git a/lib/THC/THCAtomics.cuh b/lib/THC/THCAtomics.cuh
index 400875c..ccb7a1c 100644
--- a/lib/THC/THCAtomics.cuh
+++ b/lib/THC/THCAtomics.cuh
@@ -94,6 +94,7 @@ static inline __device__ void atomicAdd(long *address, long val) {
}
#ifdef CUDA_HALF_TENSOR
+#if !(__CUDA_ARCH__ >= 700 || !defined(__CUDA_ARCH__) )
static inline __device__ void atomicAdd(half *address, half val) {
unsigned int * address_as_ui =
(unsigned int *) ((char *)address - ((size_t)address & 2));
@@ -117,6 +118,7 @@ static inline __device__ void atomicAdd(half *address, half val) {
} while (assumed != old);
}
#endif
+#endif
命令行输入:
patch -p1 < atomic.patch
打开~/torch/install-deps (vim或者gedit都行)
3.5.1 OpenBLAS
由于上面已经自行把OpenBLAS下载到了本地~/OpenBLAS,所以需要将install-deps里对应的git clone的语句注释,改为本地的move:
mv ~/OpenBLAS "$tempdir"/OpenBLAS
# git clone https://github.com/xianyi/OpenBLAS.git "$tempdir"/OpenBLAS || { echo "Error. Cannot clone OpenBLAS." >&2 ; exit 1 ; }
3.5.2 python-software-properties & ipython
这里提一下,对于official版本的torch,需要将install-deps的 sudo apt-get install -y python-software-properties语句改为 sudo apt-get install -y software-properties-common。但我们选择的torch已经处理过这个问题了,所以可以忽略这个步骤。
另外一个常遇到的问题是关于ipython的,如果install-deps会报错我们可以选择通过pip安装。但在ubuntu 16.04上我没有遇到这个问题,在别的系统版本上会遇到,至于原因我暂时不知道,总之没遇到问题就皆大欢喜...
bash install-deps
sudo ./clean.sh
sudo TORCH_NVCC_FLAGS="-D__CUDA_NO_HALF_OPERATORS__" TORCH_LUA_VERSION=LUA52 ./install.sh
source ~/.bashrc
注意这里执行install.sh时需要加上
TORCH_NVCC_FLAGS="-D__CUDA_NO_HALF_OPERATORS__"
TORCH_LUA_VERSION=LUA52
不然安装会出问题。这一点和后面提到的编译自定义cunn函数相对应,如果有编译自定义函数的需求,在编译时也务必和执行./install.sh时保持一致,因为本质上编译函数的过程是包含于./install.sh中的,如果./install.sh需要那么后续单独编译也需要,不然会编译不通过。整个过程很顺利,但这几行命令跑通的背后是长达两个星期失败了无数次的血泪史....
安装完毕过后试试在命令行敲th命令,可以看到torch的界面(激动)。
大功告成!
由于这次搭建torch环境就是为了跑通开头提到的18年的代码,而这份源码自定义了几个cunn函数需要在训练和测试之前自行编译,所以这里也顺便把编译的过程记录下来供给有需要的人参考。
源码地址:github
直接按照说明编译可能会报dependencies not satisfied或者permission denied。需要使用sudo并指明luarocks的路径。另外,因为我们在安装torch时加入了下列两行:
TORCH_NVCC_FLAGS="-D__CUDA_NO_HALF_OPERATORS__"
TORCH_LUA_VERSION=LUA52
所以这里编译时我们也要把这两行语句加上去,否则会出现错误:
...make[1]: *** [lib/THC/CMakeFile
s/THC.dir/all] Error 2
Makefile:127: recipe for target 'all' failed
make: *** [all] Error 2
最终使用的编译命令:
# nn
sudo TORCH_NVCC_FLAGS="-D__CUDA_NO_HALF_OPERATORS__" TORCH_LUA_VERSION=LUA52 ~/torch/install/bin/luarocks make ./rocks/nn-scm-1.rockspec
# cunn
sudo TORCH_NVCC_FLAGS="-D__CUDA_NO_HALF_OPERATORS__" TORCH_LUA_VERSION=LUA52 ~/torch/install/bin/luarocks make ./rocks/cunn-scm-1.rockspec
# optim
sudo TORCH_NVCC_FLAGS="-D__CUDA_NO_HALF_OPERATORS__" TORCH_LUA_VERSION=LUA52 ~/torch/install/bin/luarocks make luarocks make optim-1.0.5-0.rockspec
.lua文件的编译按照说明来就行了,关键在于cunn部分的函数编译,需要将.cu和.h文件放到对应的./torch/extra/cunn/lib/THCUNN/ 目录之下,然后在./torch/extra/cunn/lib/THCUNN/generic/THCUNN.h 中申明函数。这里以作者提供的自定义的EdgeComputation函数为例,.cu文件中函数名为void THNN_CudaEdgeComputation_updateOutput和void THNN_CudaEdgeComputation_updateGradInput,直接将其名字拷贝至THCUNN.h编译是无法正常编译运行函数的。
观察THCUNN目录下自带函数的命名格式为THNN_(NAME),其在THCUNN.h的申明格式也为THNN_(NAME),因此考虑是否需要去掉函数名字中的Cuda并加上括号。但这么试了过后发现也不能顺利编译运行。
最终参考issues里提供的解决方案:
.cu和.h文件仍然按照说明放在对应目录下无需改变,但在THCUNN.h中的命名需要去掉Cuda,加上括号。这样能够顺利编译并且运行程序,只不过在导入cunn库的时候会弹出几个warning,应该只是提醒你没有对应的CudaDouble、CudaHalf等数据类型的函数实现,但毕竟我们代码也用不着在这些数据类型上forward,不影响运行,所以就不用额外处理了。
完结撒花!