最近在搞 HF-Net,无奈它发布的时间比较老(2019年),使用 TensorFlow 版本是 1.12(1.15.0 也能用)。为了在 C++ 上跑 HF-Net,需要搭建 docker 环境。docker 相对于物理机的好处有:
- 目前物理机 cuda 版本往往比较高(10.1 以上),而低版本 tf 需要低版本的 cuda+cudnn。使用 docker 的话,对物理机只有显卡驱动的要求
- 弄好了 docker 环境,能够很方便地分享给其他人,而不需要每个人都编译一次 tf,另外也方便部署到服务器上
需注意的是,docker-ce 版本需要至少 19.03 才能使用 --gpus
参数来直接调用 GPU,否则需要用 nvidia-docker。
TensorFlow 编译(Bazel)
最坑爹的就是 TensorFlow 的编译,tf 没有官方发布的 C++ 包!(唉,还是 PyTorch 好)
官方给了一个非常简略的源码编译教程,但如果你照着那个做,大概率会碰到各种奇奇怪怪的问题,特别是编译 tf1.x 版本。
这个是比较靠谱一点的编译教程,从里面驱动安装、Bazel 配置、问题汇总可以看到整个过程有多复杂。另外,由于 tf 源码是用 Bazel 管理构建,安装后没有 cmake 支持!可以从 hfnet_ros 感受一下 cmake 项目中使用 tensorflow 有多么蛋疼。这操作太反人类了,果断弃之。下面介绍一个更好的方法。
TensorFlowCC
强烈推荐一个非官方的仓库:TensorFlowCC,作者使用 CMake 管理 tf 的编译安装(编译时调用了 bazel),简化了编译流程,同时安装后在 cmake 工程中能够直接通过 find_package(TensorflowCC)
来使用 tf,对比前面的原版感受一下 TensorFlowCC 在 CMakeLists 中的使用体验:example。
TensorFlowCC 的作者提供了相关的 docker 镜像,可惜并没有我想要的 tf1.15.0,只有较新的 tf2.x 版本,所以还是需要自己整。
Docker 镜像构建
首先将 TensorFlowCC 源码 pull 到本地,并 checkout 到 v1.15.0,里面提供了构建镜像用的 Dockerfiles。在构建之前,有两个地方需要做小小的修改:
首先,打开 tensorflow_cc/cmake/TensorflowBase.cmake
,在第23行(COMMAND tensorflow/contrib/makefile/download_dependencies.sh
之前)加入:
COMMAND sed -i "s#EIGEN_URL=.*#EIGEN_URL=\"https://gitlab.com/libeigen/eigen/-/archive/3.3.7/eigen-3.3.7.tar.gz\"#g" tensorflow/contrib/makefile/download_dependencies.sh
这是因为 Eigen3 的仓库曾经发生过迁移,原先的链接失效了,需要手动修正。
其次在 Dockerfiles/install-ubuntu.sh
中,apt-get -y install ...
后面(第41行后)可以加入设置环境变量的语句来加快后续的下载速度(make 过程中会从 github 下载 tf 源码),比如:
export all_proxy=$whatever_you_own_proxy
export http_proxy=$all_proxy
export https_proxy=$all_proxy
然后按照 readme 的指导构建镜像:
# 镜像名称和标签可自定
docker build -t floopcz/tensorflow_cc:ubuntu-shared-cuda -f Dockerfiles/ubuntu-shared-cuda .
这里我选择用 ubuntu 而不是 archlinux 来做 docker 镜像(虽然作者提供了不同方案),因为 ubuntu 软件版本相对稳定。
温馨提示:tf 编译非常慢,感觉比编译 OpenCV、PCL、或是 Qt 都慢,i7-8700 CPU 12核全开貌似编译了一两个小时,而且会消耗大量内存(github issue 上有人提到内存不足而编译失败的情况,此时需要限制核心或内存使用)。
Docker 镜像优化
构建完成后,你会发现 docker 镜像有 12.5GB,其实里面很多东西是没用的,主要有:
/root/.cache/bazel
6.4GB/usr/local/include/tensorflow
目录下bazel-bin
、bazel-out
、bazel-tensorflow
、bazel-testlogs
文件夹,总计 1.7GB
我们可以按照 TensorFlowCC 构建镜像的流程重新做一个更小的镜像:
- 基于
nvidia/cuda:10.1-cudnn7-devel-ubuntu18.04
开一个容器 - 参照
install-ubuntu.sh
安装build-essential
等一系列的包 - 从之前构建的镜像中拷贝
/usr/local/include
(删掉前述不需要的文件夹) 和/usr/local/lib
(删掉python2.7
和python3.6
文件夹) 到新的容器中 docker commit
将容器保存为镜像
这里是我构建好的 docker 镜像。