配置带有 NVIDIA 图形加速卡的深度学习训练环境

一、准备工作

1. 硬件

硬件配置清单可以参考:《NVIDIA 芯片产品比较与选购指南》文末提到的配置清单。

截至发稿时,RTX 2080 Ti 产品还未上市,因此暂时使用 GTX 1080 Ti 产品搭建环境。

2. 软件

2.1 操作系统

Windows 10 Pro 17134 64位,简体中文版:

可以使用微软推出的媒体工具制作 Windows 10 Pro 安装盘,需要准备容量不低于 8 GB 的闪存盘或移动硬盘。制作完成后选择闪存盘或移动硬盘启动即可。注意:制作过程中会清空驱动器内的所有内容。

Ubuntu 18.04.1 64位,英文版:

点击上方的链接下载好 ISO 文件后,可以使用 UltraISO 制作闪存盘。制作完成后选择闪存盘或移动硬盘启动即可。注意:制作过程中会清空驱动器内的所有内容。

安装时选择“最小化安装”即可,不需要安装更新,也不需要安装第三方软件、驱动等。此版本自带 nouveau 图形驱动,不论安装时是否勾选“第三方软件、驱动”,此软件都会安装。而此软件与 nvidia 官方驱动冲突,安装完成后需要先禁用此图形驱动,然后再安装 CUDA。

安装完成后可以参考《使用 Windows 10 的 Linux 子系统》中关于切换软件源的部分,将软件源切换为适合自己的服务器。然后更新所有软件。

2.2 NVIDIA 图形加速卡驱动程序

不论是 Windows 还是 Ubuntu,不要直接使用驱动程序,而是使用 CUDA 自带的驱动程序。即便驱动程序版本比 CUDA 自带的驱动程序更高,也不要更新。

同时建议安装 cudnn注意:下载前需要注册账户并登录。

拥有多张加速卡的 Ubuntu  用户还建议使用 NCCLTensorRT。下载前同样需要注册账户并登录,可能还要填写调查问卷 。

2.3 虚拟化环境

如果是 Ubuntu 用户,建议使用 nvidia-docker2。在此之前需要准备好 docker-ce注意:nvidia-docker2 仅支持 docker-ce stable,不能选用 edge 或 beta。

nvidia-docker 只支持 Debian-based 和 RHEL-based 操作系统。如果其他操作系统想要使用 nvidia-docker,可以在这两类操作系统上安装 docker 服务端(daemon),其他操作系统通过 docker 客户端(client)远程使用。 

由于 Windows 版 docker 依赖 Hyper-V,也即其自身运行在虚拟环境中。而 Hyper-V 虚拟环境中的所有资源均为软件模拟,因此运行在其中的任何软件都无法直接使用宿主机的硬件资源。故 NVIDIA 官方并未开发适用于 Windows 版的 nvidia-docker。

二、使用 Docker 虚拟化环境

使用 docker 可以方便地构建完全与宿主机和其它镜像隔离的虚拟环境,使开发者可以专注某个项目的开发,而不必再担心其他软件和用户对使用环境的影响。同时镜像也可以保存到 Docker Hub (需要 docker 账号),以便永久保存镜像和分发到其它宿主机中,而且虚拟镜像本身也可以将容器运行结果保存在数据卷中,以便数据持久化。

接下来将以“在 Ubuntu 18.04 中编译 TensorFlow 1.10.1”为例,讲解“如何建立镜像”、“如何上传镜像”、“如何持久化编译好的包”、“如何将持久化内容加载到其它卷中”以及“如何将镜像移植到其它计算机”。

1. 建立自己的镜像

为了避免使用过程中可能造成的混乱,在使用他人镜像时,不建议直接运行,而是先建立自己的镜像并构建,然后在自己的镜像中运行相应程序。

1.1 最简单的 Dockerfile

所有镜像都对应一个 Dockerfile。最简单的 Dockerfile 应当包含如下内容:

FROM vistart/cuda:10.0-cudnn7-devel-ubuntu18.04
LABEL maintainer "vistart <i@vistart.me>"

第一行的内容代表此镜像在 vistart/cuda:10.0-cudnn7-devel-ubuntu18.04 基础上构建。

第二行的内容代表给此镜像添加一个标签“维护者(maintainer)”,维护者的地址与电子邮件收件地址相同。

紧接着空一行,开始编写构建此镜像需要用到的一些命令:

RUN echo "deb [arch=amd64] http://storage.googleapis.com/bazel-apt stable jdk1.8" | tee /etc/apt/sources.list.d/bazel.list
RUN apt-get update && apt-get install -y git python python-pip openjdk-8-jdk curl
RUN curl -s https://bazel.build/bazel-release.pub.gpg | apt-key add -
RUN apt-get update && apt-get install -y bazel
RUN pip install numpy mock protobuf absl-py enum34 keras
RUN cd root && git clone --recurse-submodules https://github.com/tensorflow/tensorflow
RUN ln -s /usr/include/nccl.h /usr/local/cuda/include/nccl.h
RUN mkdir /usr/local/cuda/lib
RUN ln -s /usr/lib/x86_64-linux-gnu/libnccl.so.2 /usr/local/cuda/lib/libnccl.so.2

Dockerfile 的具体格式参见官方文档

Dockerfile 的编写需要遵循一些规范,参见《Dockerfile 最好这么写

1.2 构建镜像

将此 Dockerfile 保存到自己的目录中,然后切换到该目录,输入如下命令:

docker build .

由于此 Dockerfile 没有包含任何运行命令、环境变量、添加文件等操作,所以构建很快就结束了。

我这里看到的提示是:

Successfully build a9882cb62070

其中“a9882cb62070”即为构建成功的镜像的名称。

构建镜像的过程中可能会遇到各种问题,找出原因后及时修改构建脚本。

1.3 命名镜像

构建结束后,会提示此次构建的名称,通常是一个 12 位的十六进制数。此数字并不代表具体含义,因此难以记忆,所以构建技术后的第一步是给该镜像命名。

运行以下命令:

docker tag a9882cb62070 vistart/build_tensorflow:py27

第一个参数即为待命名(或改名)的镜像名称,第二个参数为目标名称。

官方文档《docker tag

命名规则请遵循“用户名/镜像名:标签”的格式,例如上述编译适用于 Python 2.7 的 tensorflow 的镜像命名为 vistart/build_tensorflow:py27

1.4 上传到 Docker Hub

改名完成后,可以将镜像上传到 Docker Hub,以便持久保存和分发。

先到 Docker 官方网站注册。注册完成后,前往自己的 Hub 主页。例如,我的 Hub 主页是 https://hub.docker.com/r/vistart/cuda

注册完成后需要使用 docker login 命令登录自己的账号,登录完成后使用 docker push 命令上传,例如:

docker push vistart/build_tensorflow:py27

上传的过程中会看到要上传好多镜像,其中某些镜像提示“Mounted from vistart/cuda”,即此镜像依赖 vistart/cuda 镜像,需要待所有镜像全部上传完毕后才算上传完成。如果其他镜像依赖此镜像,那其他镜像上传时要先等此镜像上传完毕。

上传完毕后,回到自己的 Docker Hub 主页,会看到多出了 vistart/build_tensorflow 页面,同时标签页面会显示有一个 py27 标签,大小约为 2GB。

1.5 移植到其他计算机

在其他计算机上要使用已上传到 Docker Hub 的镜像,除了要先准备好上述环境外,可以直接运行 docker run 命令即可。如果要运行的镜像不在本地,docker 会自动下载。此过程只需保证联网即可,无需登录任何账号。

如果只想把镜像下载到本地,并不打算运行,可以使用 docker pull 命令。

2. 使用数据卷

官方文档《Use volumes

docker 不会保存镜像运行时最后的状态,每次结束运行后重新运行又回到了镜像的初始状态。

为了能使运行结果持久化,可以使用数据卷功能。

接下来,将以使用 tensorflow-pkgs 为例,创建数据卷。创建该数据卷的目的是保存编译好的 tensorflow 代码包。

2.1 创建数据卷

docker volume create tensorflow-pkgs

创建完成后,可以查看此数据卷的信息:

docker volume inspect tensorflow-pkgs

输入该命令后,可以看到类似如下输出:

[
    {
        "CreatedAt": "2018-09-23T21:27:29+08:00",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/tensorflow-pkgs/_data",
        "Name": "tensorflow-pkgs",
        "Options": {},
        "Scope": "local"
    }
]

2.2 加载并写入数据卷

输入如下命令:

nvidia-docker run -v tensorflow-pkgs:/root/tensorflow-packages -it vistart/build_tensorflow:py27

成功加载后,可以切换到 /root/tensorflow 目录下开始编译 tensorflow。

编译过程请参考《在 Ubuntu 中编译 TensorFlow》。从这篇文章的“配置”部分开始即可。

编译并构建代码包后,查看编译好的 whl 包是否已放入 /root/tensorflow-packages 中。如果是的话可以结束当前容器。

2.3 加载到其他镜像中

输入如下命令

nvidia-docker run -v tensorflow-pkgs:/root/tensorflow-packages -it vistart/pointnet2

切换到 /root/tensorflow-packages 目录下,会看到已经加载了刚才编译好的代码包。

使用 pip 安装该代码包,安装前要先卸载已存在的包。

安装完成后即可开始运行训练:

CUDA_VISIBLE_DEVICES=0,1 python train_multi_gpu.py --num_gpus 2

可以看到训练已经开始了。

3. 远程使用(仅供参考,不保证完全可用)

3.1 服务端(daemon)

切换为 root 用户后,编辑 /etc/docker/daemon.json 文件,加入 “hosts” 属性:

"hosts": ["unix:///var/run/docker.sock", "tcp://0.0.0.0:2375"]

更多内容请参考《远程连接docker daemon

注意:此方法在 Ubuntu 18.04.1 上没有完全成功。慎用!

3.2 客户端(client)

由于客户端不会自动连接远程服务器,也不能直接运行 nvidia-docker,故客户端使用 docker 时需要附加 -H 参数,同时 run 还需要附加 –runtime=nvidia 参数。

4. 后台使用

5. 向宿主机开放容器的内部端口

6. Docker 使用规范(建议)

  • 从部署好 docker 和 cuda 环境那一刻起, 宿主机尽量不要新增任何软件,更不要修改软件源;自己账户要用到的数据尽量放在自己的目录下;
  • 不要直接使用他人的或第三方的镜像,而是自己构建一个引用该镜像的镜像,并在自己的镜像上操作,以免影响原始镜像;
  • docker 默认给每个构建好的镜像生成一个 12 位的十六进制数作为名称,该名称难以记忆,所以构建好的镜像一定要命名,并标记标签,否则时间一长,容易忘记;
  • 构建好的镜像要及时上传到自己的 Docker Hub,且要不定期更新维护;
  • 凡是要使用 ubuntu 操作系统的镜像,请从 vistart/ubuntu:16.04 或 vistart/ubuntu:18.04 引出,不要使用官方镜像,因为官方镜像的软件源不适合中国大陆;
  • 构建的镜像往往体积较大,因此不再使用某个镜像时应当尽快删除;
  • 不要删除他人构建的镜像;
  • 如果运行的镜像需要使用宿主机的文件,临时使用的可以挂载本地目录,长期使用的或保存了关键运行结果的情况下,建议自己制作数据卷;同理,不再使用的数据卷应当及时删除;
  • 建议将自己所有的 Dockerfile 保存到自己的 GitHub。

附录 1:目前已构建好的虚拟镜像

使用 docker image ls 或 docker images 命令,可以列出当前宿主机内保存的所有镜像:

REPOSITORY                 TAG                               IMAGE ID            CREATED             SIZE
vistart/build_tensorflow   py27                              a9882cb62070        12 hours ago        4.34GB
<none>                     <none>                            1089d6fdb4b3        18 hours ago        2.97GB
vistart/pointnet2          latest                            17b5b2d762e8        18 hours ago        6.93GB
vistart/cuda               10.0-cudnn7-devel-ubuntu18.04     bcdcd53edd72        19 hours ago        2.97GB
vistart/cuda               10.0-devel-ubuntu18.04            0bf94e103307        19 hours ago        2.3GB
vistart/cuda               10.0-cudnn7-runtime-ubuntu18.04   b25ab346e93b        19 hours ago        1.29GB
vistart/cuda               10.0-runtime-ubuntu18.04          60f74af4a80c        19 hours ago        944MB
vistart/ubuntu             16.04                             a17911499995        20 hours ago        234MB
<none>                     <none>                            a5d9f30f72f9        20 hours ago        166MB
vistart/cuda               10.0-base                         1fd6a108d6d6        20 hours ago        185MB
vistart/cuda               10.0-base-ubuntu18.04             1fd6a108d6d6        20 hours ago        185MB
vistart/ubuntu             18.04                             bcb78e8b931a        20 hours ago        145MB
nvidia/cuda                10.0-cudnn7-devel                 78eb5b07b059        3 days ago          2.91GB
nvidia/cuda                latest                            b6ab25168156        3 days ago          2.24GB
hello-world                latest                            4ab4c602aa5e        2 weeks ago         1.84kB
ubuntu                     16.04                             b9e15a5d1e1a        2 weeks ago         115MB
ubuntu                     18.04                             cd6d8154f1e1        2 weeks ago         84.1MB

 

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据