一个由tf1.6.0引发的故事|从CUDA到gcc配置,非root用户重装旧版本TF环境

之前尝试复现学姐前几年的一个工作,但是因为框架有点古老而作罢。
然鹅,自己的实验结果一直跑得十分奇怪,为了去学姐的代码中寻找参考,今天再次进行了尝试。

我的需求是安装Tensorflow_gpu_1.6.0(文中简称TensorFlow),目前机器已配置cuda11和cuda10,非root用户。

前置疑问

Q1: 为什么安装TensorFlow需要重装CUDA?

当我安装完毕并运行Tensorflow_gpu_1.6.0时,出现了以下错误:

ImportError: libcublas.so.9.0: cannot open shared object file: No such file

这意味着TensorFlow需要对应版本的CUDA,对于CUDA、cuDNN和TensorFlow的关系,知乎有回答写得很好:

CUDA看作是一个工作台,上面配有很多工具,如锤子、螺丝刀等。
cuDNN是基于CUDA的深度学习GPU加速库,有了它才能在GPU上完成深度学习的计算。
它就相当于工作的工具,比如它就是个扳手。但是CUDA这个工作台买来的时候,并没有送扳手。想要在CUDA上运行深度神经网络,就要安装cuDNN,就像你想要拧个螺帽就要把扳手买回来。这样才能使GPU进行深度神经网络的工作,工作速度相较CPU快很多。
基本上所有的深度学习框架都支持cuDNN这一加速工具,例如:Caffe、Caffe2、TensorFlow、Torch、Pytorch、Theano等。

Q2: nvidia-smi和nvcc -V显示的不是同一版本CUDA?

来自CW大佬的文章,知道只要 nvcc -V 显示的版本高于 nvidia-smi 显示版本就没有问题。

  1. CUDA有runtime APIdriver API,而nvcc -V显示的是前者版本,nvidia-smi显示的是后者版本。

  2. nvidia-smi展示的 driver API 代表机器能够支持的最高版本CUDA,如果driver (nvidia-smi)的版本低于runtime (nvcc -V)版本,通常不会出现问题。

  3. 产生原因:安装CUDA可以通过CUDA Toolkit installer 或 GPU driver installer,如果使用了单独的GPU driver installer来安装CUDA,就可能会出现版本不一致的现象,而通过CUDA Toolkit installer安装则会保持一致。

Q3: 用conda装CUDA不可以吗?

我尝试了通过conda安装对应的CUDA9.0 以及cuDNN,安装过程很顺利,但Tensorflow并不能跑起来,提示缺少对应的.so文件,而在/usr/local 下也并没有找到我装的cuda9.0。

参考知乎回答 , pytorch如何寻找CUDA:

  1. 先取默认 cuda 安装目录 /usr/local/cuda
  2. 如默认目录不存在(例如安装原生 cuda 到其他自定义位置),那么搜索 nvcc 所在的目录
  3. 如果 nvcc 不存在,那么直接寻找 cudart 库文件目录(此时可能是通过 conda 安装的 cudatoolkit,一般直接用 conda install cudatoolkit,就是在这里搜索到 cuda 库的),库文件目录的上级目录就作为 CUDA_HOME。
  4. 如果最终未能得到 CUDA_HOME,那么生成的 pytorch 将不使用 CUDA。

TensorFlow同理,但我并没有成功修复调用顺序的问题。那么如果conda安装正确,且机器没有其他版本CUDA(如/usr/local/cuda),理论上能直接用?

结论

  1. 如果可以用docker,可以移步TF官网docker安装教程-最简单方法
  2. 如果可以用root,可以移步博客TF安装
  3. 如果conda能用,可以移步博客TF安装-conda

0 安装之前——检查机器配置(非root用户)

查询目标配置

安装TensorFlow环境,需要配合对应版本的CUDA、cuDNN和python,而CUDA需要配合对应版本的gcc,
我的目标是装tf_gpu_1.6.0,从官网查到匹配的环境信息如下:官网-TensorFlow对应CUDA

版本 Python 版本 编译器 构建工具 cuDNN CUDA
Tensorflow_gpu-1.6.0 2.7、3.3-3.6 GCC 4.8 Bazel 0.9.0 7 9

检查机器配置

# 查看命令

cat /etc/os-release  
# 或uname -a
gcc --version
nvcc -V 
nvidia-smi
python --version
版本 Python 版本 编译器 构建工具 cuDNN CUDA
None 3.6.1 GCC 8.4.0 -- -- 10.1

安装顺序

按照依赖关系,gcc -> CUDA -> cuDNN -> python -> TensorFlow

1 安装gcc

不同的CUDA支持的gcc版本不同,现在用的服务器gcc版本比较新,实测cuda9.0在gcc8.4.0下安装程序会失败,所以需要降级。

首先在位置/home/[username]/, 建立目录如下:参考博客

.
├── gcc     # 新建,用于存放gcc版本
│   ├──gcc640   # 新建
│   └── gcc-6.4.0.tar.gz    # 下载
└── ... # 其他文件

1.1 下载gcc (以gcc6.4.0为例)

(方式1) 手动下载:http://ftp.gnu.org/gnu/gcc/ 后传输到服务器
(方式2) cmd:

wget http://ftp.gnu.org/gnu/gcc/gcc-6.4.0/gcc-6.4.0.tar.gz

1.2 configure

参考:官方gcc安装教程

下载完成后进行解压

cd /home/[username]/gcc
tar xzf gcc-6.4.0.tar.gz
cd gcc-6.4.0
./contrib/download_prerequisites  # 运行脚本,自动安装依赖
mkdir objdir  # 在gcc-6.4.0源码文件夹下,新建一个文件夹用于编译
cd objdir 

使用configure生成 Makefile,为下一步的编译做准备:

$PWD/../gcc-6.4.0/configure --prefix=$HOME/gcc/gcc640 --enable-checking=release --enable-languages=c,c++ --enable-threads=posix --disable-multilib

# --prefix=/usr/local/gcc6  指定安装路径
# --enable-languages=c,c++  支持的编程语言
# --enable-threads=posix    使用POSIX/Unix98作为线程支持库
# --disable-multilib        取消多目标库编译(取消32位库编译)

1.3 编译

接下来编译

make  # 或者make -j8 使用8个线程并行编译

可能问题1: make[3]: *** No rule to make target '../build-x86_64-pc-linux-gnu/libiberty/libiberty.a', needed by 'build/genmddeps'. Stop.

在解压后需要在源码文件夹下新建一个文件夹,如/home/[username]/gcc/gcc-6.4.0/objdir,之后的make过程均在新建的编译文件夹内

** 可能问题2: ./md-unwind-support.h:65:48: error: dereferencing pointer to incomplete type 'struct ucontext'**

参考博客,原因是现在安装版本的gcc语法不兼容:

如果你机器上已经默认安装的是gcc8.1,现在想要使用gcc6.x,那么编译gcc6.x源码过程中会出现好些错误,这些错误是因为gcc在升级过程中对头文件的一些结构变量的定义的更改变化没有做向后兼容处理,或者某些语法的严格性要求不一样(比较常见的是struct的定义和申明)

打开报错指出的文件地址

/home/[username]/gcc/gcc-6.4.0/x86_64-pc-linux-gnu/libgcc/md-unwind-support.h

修改第61行的

struct ucontext * uc_ = context->cfa;

struct ucontext_t * uc_ = context->cfa; 

接下来继续make

可能问题3: sanitizer_platform_limits_posix.cc:158:23: fatal error: sys/ustat.h: No such file or directory #include <sys/ustat.h>

参考博客,修改代码文件

vim libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc

(1)首先注释158行#include <sys/ustat.h>

(2)将250行语句unsigned struct_ustat_sz = sizeof(struct ustat);注释,修改为如下内容:

  // Use pre-computed size of struct ustat to avoid <sys/ustat.h> which
  // has been removed from glibc 2.28.
#if defined(__aarch64__) || defined(__s390x__) || defined (__mips64) \
  || defined(__powerpc64__) || defined(__arch64__) || defined(__sparcv9) \
  || defined(__x86_64__)
#define SIZEOF_STRUCT_USTAT 32
#elif defined(__arm__) || defined(__i386__) || defined(__mips__) \
  || defined(__powerpc__) || defined(__s390__)
#define SIZEOF_STRUCT_USTAT 20
#else
#error Unknown size of struct ustat
#endif
  unsigned struct_ustat_sz = SIZEOF_STRUCT_USTAT;

(3)保存后,重新make

可能问题4 :../../.././libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc:270:22: error: aggregate ‘sigaltstack handler_stack’ has incomplete type and cannot be defined

(1)打开libsanitizer/sanitizer_common/sanitizer_linux.h文件,注释第22行的struct sigaltstack;

(2)修改31.32行:

uptr internal_sigaltstack(const struct sigaltstack* ss,
                          struct sigaltstack* oss);

uptr internal_sigaltstack(const void* ss, void* oss);

(3)修改libsanitizer/sanitizer_common/sanitizer_linux.cc文件549、550行

uptr internal_sigaltstack(const struct sigaltstack *ss,                                      
                                struct sigaltstack *oss) {

uptr internal_sigaltstack(const void *ss, void *oss) {

(4)修改libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc270行

struct sigaltstack handler_stack;

stack_t handler_stack;

(5)修改libsanitizer/tsan/tsan_platform_linux.cc294行

__res_state *statp = (__res_state*)state;

struct __res_state *statp = (struct __res_state*)state;

(6)继续make

可能问题5: ../../.././libsanitizer/sanitizer_common/sanitizer_internal_defs.h:254:72: error: size of array ‘assertion_failed__1139’ is negative

(1)修改 /gcc-6.3.0/configure文件
(2)删除文件中 target-libsanitizer \,大概在2700多行
(3)继续make

1.4 安装

make install

检查包含以下目录,即安装成功:/home/[username]/gcc/gcc640

1.4.1 覆盖路径

[要安装GCC的路径]:/home/[username]/gcc/gcc640
#路径要在环境变量前

export PATH=[要安装GCC的路径]/bin:[要安装GCC的路径]/lib64:$PATH
export LD_LIBRARY_PATH=[要安装GCC的路径]/lib/:$LD_LIBRARY_PATH

最后刷新

source ~/.bashrc

1.4.2 检查gcc设置

gcc --version

2 安装CUDA

CUDA 下载地址:https://developer.nvidia.com/cuda-toolkit-archive

.
├── cuda      # 新建,用于存放不同的cuda版本,即安装目录
│   ├── cuda-9.0     # 新建
│   └── tem      # 新建,用于cuDNN的解压,安装完成后就删除该目录
│   │     ├── cudnn-9.1-linux-x64-v7.1.tgz     # 后续下载
│   └── cuda_9.1.85_387.26_linux.run       # 后续下载
└── ... # 其他文件

2.1 给cuda可执行权限

chmod +x cuda_9.1.85_387.26_linux.run 

2.2 执行安装

sh cuda_9.1.85_387.26_linux.run 

安装过程记录:

-----------------
Do you accept the previously read EULA?
accept/decline/quit: accept

You are attempting to install on an unsupported configuration. Do you wish to continue?
(y)es/(n)o [ default is no ]: y

# 已有Driver API,不安装
Install NVIDIA Accelerated Graphics Driver for Linux-x86_64 384.81?
(y)es/(n)o/(q)uit: n

Install the CUDA 9.0 Toolkit?
(y)es/(n)o/(q)uit: y

# 非root用户,所以安装在自定义目录
Enter Toolkit Location
 [ default is /usr/local/cuda-9.0 ]: /home/[username]/cuda/cuda-9.0

# 非root用户,尝试过无法链接到/usr/local
Do you want to install a symbolic link at /usr/local/cuda?
(y)es/(n)o/(q)uit: n

Install the CUDA 9.0 Samples?
(y)es/(n)o/(q)uit: y

Enter CUDA Samples Location
 [ default is /home/[username] ]: /home/[username]/cuda/cuda-9.0

Installing the CUDA Toolkit in /home/[username]/cuda/cuda-9.0 ...
Missing recommended library: libGLU.so
Missing recommended library: libXi.so
Missing recommended library: libXmu.so

Installing the CUDA Samples in /home/[username]/cuda/cuda-9.0 ...
Copying samples to /home/[username]/cuda/cuda-9.0/NVIDIA_CUDA-9.0_Samples now...
Finished copying samples.

2.3 卸载CUDA

参考博客
安装程序最后已经准备好了卸载的接口,卸载程序在/[安装目录]/bin下,需要注意的是cuda10.0及之前的版本卸载程序名为uninstall_cuda_xx.x.pl,而cuda10.1及之后的版本卸载程序名为cuda-uninstaller。

找到之后运行卸载程序即可,这里的xx.x表示自己的cuda版本。

3 安装cuDNN

参考博客
cudnn下载地址:https://developer.nvidia.com/rdp/cudnn-archive

3.1 解压安装文件

 tar -zxvf cudnn-9.1-linux-x64-v7.1.tgz 

3.2 拷贝文件到cuda

cp /home/[username]/cuda/include/cudnn.h  /home/[username]/cuda/cuda-9.0/include
cp /home/[username]/cuda/lib64/libcudnn*  /home/[username]/cuda/cuda-9.0/lib64

3.3 添加权限

chmod a+r /home/[username]/cuda/cuda-9.0/include/cudnn.h  /home/[username]/cuda/cuda-9.0/lib64/libcudnn*

3.4 配置用户环境变量

修改个人用户目录下的.bashrc文件(用vi ~/.bashrc编辑),在文件最后面加入以下指令并保存:

export PATH=//home/[username]/cuda/cuda-9.0/bin${PATH:+:${PATH}}
export LD_LIBRARY_PATH=/home/[username]/cuda/cuda-9.0/lib64${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}

最后输入命令source .bashrc 使新配置的环境变量生效

4 安装TensorFlow

可能问题: Could not find a version that satisfies the requirement tensorflow-1.6.0 (from versions: none)

参考:https://stackoverflow.com/questions/38896424/tensorflow-not-found-using-pip

一般情况下是python版本不对应,但目前python版本是正确的,以下两种解决方案:

(1) 把pip install替换成pip3 install --upgrade

pip3 install --upgrade TF_BINARY_URL 

(2) 检查自己的语法(事实证明是我错写成tensorflow-gpu-1.6.0了)

pip3 install tensorflow-gpu==1.6.0

5 检测新环境

import tensorflow as tf
import os
os.environ['CUDA_VISIBLE_DEVICES']='4'   # tensorflow默认占用机器所有卡,所以记得事先选择
from tensorflow.python.client import device_lib
print(device_lib.list_local_devices())   # 检查TF可用的卡

Note: TensorFlow默认会对卡从0开始重新编号

Ref:
[1] https://blog.csdn.net/wanggao_1990/article/details/120989070
[2] https://stackoverflow.com/questions/9450394/how-to-install-gcc-piece-by-piece-with-gmp-mpfr-mpc-elf-without-shared-libra
[3] https://blog.csdn.net/XCCCCZ/article/details/80958414

posted @ 2022-12-02 17:13  Teddyonthebench  阅读(372)  评论(0编辑  收藏  举报