狠下心来重新装了系统,探索一下 gpu 版本的安装。比较令人可喜的是,跟着前辈们的经验,还是让我给安装成功了。由于我是新装的系统,就像婴儿般纯净,所以进入系统的第一步就是安装 cuda,只要这个不出错,后面的几乎就不会出错了。
首先,得先确定自己的显卡是否支持(这个一般支持,我这几年前的电脑的显卡都支持安装 cuda)。然后确定自己要安装的是什么版本的 TensorFlow,因为不同的版本对 cuda 和 cudnn 的版本要求不一样。具体可以参考此链接:https://tensorflow.google.cn/install/source_windows
我安装的是最新的 1.12 版本,所以支持的是 cuda 9 系列版本,我选择安装的是 cuda9.0,所以下载的 cudnn 版本也和 cuda9.0 版本对应。安装 cuda 当然少不了关于 gpu 的显卡驱动,这里不同的 cuda 版本要求的显卡驱动是有要求的,可参见此链接:https://docs.nvidia.com/cuda/cuda-toolkit-release-notes/index.html
但是需要说明的是,我并没有单独安装显卡驱动,而是在安装 cuda 的过程中自动安装显卡驱动。所以打开电脑的第一步就是安装 cuda。哦,不对,第一步是更改 apt 下载源,在 Ubuntu 的软件和更新中选择第一项 “Ubuntu 软件”,然后选择 “下载自” 中的其他站点,选择一个就可以了,这里我选择的是阿里云的源。接下来可以选择 sudo apt install fcitx,然后安装一个搜狗拼音输入法。当然直接进入主题也是很棒的。
进入下载好的 cuda 的 deb 包所在的目录,使用命令: sudo dpkg --install cuda9.0.deb,然后一通设置后,会提示你什么 key 没添加,然后可以去 /var/cuda-repo-×× 目录下找到一个以 .pub 结尾的文件,一般是第一个,我这里是 /var/cuda-repo-cuda-9-0-local/7fa2af80.pub,然后使用: sudo apt-key add /var/cuda-repo-cuda-9-0-local/7fa2af80.pub 进行添加。如果之前安装过其他版本的 cuda,并且也进行了这一步,不会进行提示,但是最后安装得到的版本号有问题(我这里之前安装过 cuda10,没有去掉这个添加的什么 .pub,所以后来安装 cuda9.2 时最后的版本依旧是 10,我也不懂为什么)。然后 sudo apt update 更新仓库,然后 sudo apt install cuda 就完成了基本的安装操作。如果不出错的话会直接开始安装 cuda。
但是这里我安装 cuda9.0 版本的时候出现了一个错误:“cuda : 依赖: cuda-9-0 (>= 9.0.176) 但是它将不会被安装E: 无法修正错误”。我也不知道这个错误是什么意思,一般不应该出现才对,因为我安装 cuda10 的时候没出现过,会很直接的开始安装,我姑且认为是我安装的 cuda 版本低了(瞎猜的),是不是我应该安装 9.1 或者 9.2 版本呢?这个我也没有去验证,因为我最后还是成功地安装了 cuda9.0。
当我出现这个错误后,我没有选择另外的版本进行安装,而是按照某个网友的解决方案,使用 aptitude 来安装,所以使用命令 sudo aptitude install cuda 来开始安装 cuda,没错一切又开始正常运行了。如果没有安装 aptitude,需要先安装: sudo apt install aptitude。
无论正常使用 apt 还是使用 aptitude 进行 cuda 的安装,中途都不会出现任何提示,如果你提前安装了显卡驱动的话,会粗暴地给你卸载掉,然后安装 cuda 自带的显卡驱动。所以在安装过程中会弹出一个淡紫色(不能确定是否记错)的提示框,会告诉你一堆东西,然后确定就可以了,然后会让你输入一个密码,输入完之后,会要求重复输入密码进行确认。都确定完之后,会继续进行 cuda 的安装。静待安装完成。安装完成后将 cuda 安装路径写入 PATH,打开用户配置文件 gedit ~/.bashrc,然后 将以下内容加到 .bashrc 文件的最后:
export PATH=/usr/local/cuda-9.0/bin${PATH:+:${PATH}}
export LD_LIBRARY_PATH=/usr/local/cuda-9.0/lib64${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
可以使用 echo $PATH 命令查看系统中的 PATH 变量,对 LD_LIBRARY_PATH 同样适用。
安装完之后需要重启电脑,这次重启十分重要。因为一开始会出现一个蓝色的界面,问你是否进入什么 enroll mok,这时候千万要选是,进入这个,然后会问你是否 view mok key,选择是,然后好像就可以看到一些东西,这时候要输入你安装 cuda 时设置的密码(我记不得这个输入密码的步骤在前还是在后,但一定要输入的),然后选择 continue,然后 reboot,重启电脑,然后在设置里面查看计算机的详细信息可以看到使用的图形卡是 NVIDIA 的显卡,而不是集成显卡了。这时候使用 nvidia-smi 指令即可查看 gpu 信息。整个过程中我觉得重启这个步骤最重要。
如果想确认是否成功安装 cuda,可以验证一下跑 cuda 自带的样例的结果。因为 Ubuntu 18.04 自带的 gcc g++ 版本号是 7,而 cuda9.0 不能使用高于 6.0 版本的 gcc 进行编译(如果我没记错的话),反正想要验证就必须将 gcc 版本降级。首先安装你喜欢的低级的 gcc 版本,我安装的是:sudo apt install gcc-5 g++-5。然后使用如下的指令对不同的 gcc g++ 版本指定优先程度:
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-5 70,sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 50。这里我指定 gcc-5 的分数为 70,gcc-7 分数为 50。对 g++ 使用相同的命令,将 gcc 替换成 g++ 就行。使用 update-alternatives --config gcc 命令可以查看当前多版本 gcc 的情况,对 g++ 也是一样。这时候再使用 gcc --version 命令查看,可以看到当前 gcc 默认版本为 5.5.0。
这时候进入 cuda 的安装目录,cd /usr/local/cuda,如果不知道 cuda 安装目录的话可以使用 whereis cuda 命令进行查看。然后进入 cuda 安装目录下的 samples 目录,cd ./samples,然后使用 sudo make 命令开始所有样例的编译环节,这会花很长的时间。等到编译完成,进入 samples 下的 bin 文件夹,然后一路进入,直到存储编译结果的文件夹,我这里是 /usr/local/cuda/samples/bin/×86_64/linux/release,然后随便选择一个文件,例如旗下的 deviceQuery 文件,终端输入 ./deviceQuery 便可以看到输出内容,最后显示 Result = PASS 表示编译成功,也预示着 cuda 安装成功。
在终端输入 nvidia-smi 命令可以看到 gpu 的具体使用情况,也可以看到使用的显卡驱动号,我这里 cuda 给我安装的是版本号为 390.77 的显卡驱动。nvidia-smi 命令很重要,因为我们可以根据这个指令确定 gpu 还不是处于满负荷状态,所以训练模型的时候 就可以根据这个命令的显示信息进行 batch 的设置等等。然后接下来就是其他组件的安装。
我首先安装了一个 miniconda,miniconda 安装实在不要太简单,安装过程中指定安装目录即可。然后打开新的终端,可以查看 conda 的信息,例如 conda --version。然后使用命令:conda create --name tensorflow-gpu python=3.6 创建一个名为 tensorflow-gpu 的环境,这里的 Python 版本千万不能选择很低的版本,也不能选择 Python 3.7,否则后续无法安装 tensorflow-gpu 版本,各个 tensorflow 需要的 Python 版本详见给出的第一个链接。这里不在创建环境的同时安装 tensorflow,因为 conda 源速度很慢,我也没有试过更改 conda 的下载源,当然也可以在修改下载源后直接在创建环境时安装 tensorflow,这样的话 conda 会自动给我们配置各种依赖。如果修改了 conda 的下载源,可以这样安装 tensorflow:conda create --name tensorflow-gpu python=3.6 tensorflow-gpu,这时候会自动安装 tensorflow-gpu 版本。针对第一种情况,也就是我的做法,只会安装 Python 和一些简单的包,很快就创建完毕。打开新的终端,使用命令:source activate tensorflow-gpu 就可以激活我们创建的 tensorflow-gpu 环境。然后使用 pip 来进行 tensorflow 的安装:pip install tensorflow-gpu,这会自动安装 1.12 版本的 gpu 版本的 tensorflow 和对应的 numpy 库。安装成功后使用 python 进入 Python 环境,然后 import tensorflow,会出现 cudnn.so(好像是这个)缺失的错误,此时需要安装 cudnn。我下载的是 cudnn 的压缩包,而不是 deb 包。进入解压后的 cudnn 目录,然后使用以下命令进行 cudnn 的安装:
sudo cp cuda/include/cudnn.h /usr/local/cuda/include
sudo cp cuda/lib64/libcudnn* /usr/local/cuda/lib64
我看到有的人还加上了这个命令:sudo chmod a+r /usr/local/cuda/include/cudnn.h /usr/local/cuda/lib64/libcudnn*,我不知道有没有必要,但是使用了肯定是没错的。
这时候重新进入 Python 环境,import tensorflow 就不会出错了。而且第一次导入时会出现很多信息,其中就包括使用的 gpu 的信息。这时候进行简单的测试,可以知道 tensorflow-gpu 版本安装成功。
按照我的安装过程,可以知道此时系统中存在 3 个版本的 Python,系统自带的,miniconda 安装的,以及 tensorflow-gpu 环境下的。如果需要使用不同的 Python 进行工作,需要对不同的 Python 进行别名的设置。其中 tensorflow-gpu 环境下的 Python 不用管,因为需要使用 source activate tensorflow-gpu 命令激活环境后才能使用,此时输入 Python 进入的就是此环境下的 Python 环境。如果你的计算机自带的 Python 版本和你安装到 tensorflow-gpu 中的 Python 版本是一样的,你可能会发现在 tensorflow-gpu 环境下的 pip 来源于系统中的 pip,但是不用理会,这时候使用 pip 安装的包会处于 tensorflow-gpu 环境中,而不是系统中。系统中一开始是不会自带 pip 的,需要使用 sudo apt install python3-pip 进行简单的安装,如果没有更新过仓库,安装的 pip 版本可能很低,可以进行升级,升级后使用 pip 可能会出现错误:Import Error: cannot import name main,这时候需要修改系统中的文件,sudo gedit /usr/bin/pip3,将其中的 from pip import main 修改成 from pip._internal import main 即可。话题扯远了,当没有激活 tensorflow-gpu 环境时,系统中存在两个 Python 版本,而且 miniconda 下的 Python 好像会覆盖掉系统自带的 Python,所以使用别名机制,打开配置文件:gedit ~/.bashrc,然后可以在末尾添加如下指令:
alias python3=/usr/bin/python3.6
alias pip3=/usr/bin/pip3
alias python3-conda=/home/xyf/Install/miniconda3/bin/python3.7
alias pip3-conda=/home/xyf/Install/miniconda3/bin/pip
这时候在终端中输入 python3 使用的就是系统自带的 Python,输入 python3-conda 使用的就是 miniconda 中的 Python。pip 同理。如果激活了 tensorflow-gpu 环境后需要退出该环境,最简单粗暴的方法就是直接关闭该终端,温和一点的方法是使用指令:source deactivate tensorflow-gpu。如果需要在每次启动终端时自动激活 tensorflow-gpu 环境,可以在 .bashrc 文件的最后加上:source activate tensorflow-gpu 即可,每次打开终端自动读取配置文件 ~/.bashrc 文件,所以会自动激活 tensorflow-gpu 环境。
最后说明一点,默认 pip 下载源实在太慢,需要更改默认下载源。在 home 目录下,也就是用户目录下:mkdir .pip,然后 cd ~/.pip,然后 gedit ./pip.conf,在 pip.conf 中加上自己喜欢的源即可,这里我:
[global]
index-url = https://mirrors.aliyun.com/pypi/simple
喜欢其他源的将 https://mirrors.aliyun.com/pypi/simple 进行替换即可。