2024.04从源码编译 Tensorflow2.6.5踩坑记录
笔者花了一整天时间,失败4次之后成功
Tensorflow2.6.5是 截止2024.04时,所能从源码编译的最新版本
0 - 前期准备
笔者为爆改Tensorflow,完成科研工作故有从源码编译 Tensorflow的需求;平时更常用的做法是在conda环境中pip install tensorflow
,有时为了环境隔离方便打包,会用docker先套住,再上conda + pip安装
- 个人之前更熟悉的框架是
PyTorch
,经过往后的尝试更证明了Torch
的稳定性和易用性确实强于TF
,本次解决问题的思路也是来自于Torch
者 - 实验硬件:CPU Intel 11th-i7 ,GPU Nivida 3090(24GB),内存 32GB DDR4 + 2TB,宿主系统为ubuntu20.04
- 在宿主上 装了
tmux
以应对长时间运行的程序,免得程序没跑完了但终端挂了
1 - 资料汇总
教程参考:
- 【主要参考 - Tensorflow官方 从源码编译】----但细节太少,作为根本依据而已
- 【知乎 - 全流程参考1】— 但是事实上没这么顺利,至少笔者没有这个运气
- 【CSDN - 全流程参考2】 ---- 收获是构建过程不成功需要
rm -rf ~/.cache/bazel/
然后再bazel build - 【知乎 - 踩坑记录参考】 — 主要关于下载相关文件与
protobuf
版本
另注:bazel的编译 可以使用换源清华镜像(不是必要)
整体配置流程的根本依据还是官方的教程,但它的教程有些点和坑没有涉及到,所以多方材料了解
2 - 整体流程
2.1 确定配置目标
官网上给到了配置目标,和对应的版本匹配关系(这张表里缺少了对numpy的版本要求)
笔者最后(在docker中)配置成功的版本为tensorflow2.6.5 numpy1.19.5 Python3.7.13 GCC7.5.0 CUDA11.3 Bazel3.7.2
2.2 开始配置
为了打包方便和编译环境隔离,在docker中进行了以下配置
- 首先拉一个合适(cuda版本与显卡匹配、内部工具相对齐全)的镜像下来
#选择了PyTorch的镜像,镜像中就包含了cuda、cudnn、gcc
docker pull pytorch/pytorch:1.12.1-cuda11.3-cudnn8-devel
#开一个容器,把文件挂载上来以保存修改; 注意这个挂载路需要换成你的
docker run --gpus all --name tf2.6_build -itd -v /home/tensorflow:/tensorflow pytorch/pytorch:1.12.1-cuda11.3-cudnn8-devel /bin/bash
#进入容器
docker exec -it tf2.6_build /bin/bash
- 安装 TensorFlow pip 软件包依赖项,其编译过程依赖于这些包
#注意这里的numpy版本是个坑,后续踩坑记录具体说明;此处numpy最好指定合理的版本 如笔者为pip install numpy==1.19.5
pip install -U --user pip numpy wheel
pip install -U --user keras_preprocessing --no-deps
- Git Tensorflow源代码包
#Git下来Tensorflow的源代码,这个文件比较大,如果git不成功也可以直接下载zip包下来然后解压
git clone https://github.com/tensorflow/tensorflow.git
#进入到clone下来的目录,然后切换分支到对应的版本下,笔者的目标本版本为2.6
cd tensorflow
git checkout r2.6
- 安装编译工具 Bazel
官网的介绍:(1)您需要安装 Bazel,才能构建 TensorFlow。您可以使用 Bazelisk 轻松安装 Bazel,并且 Bazelisk 可以自动为 TensorFlow 下载合适的 Bazel 版本。为便于使用,请在
PATH
中将 Bazelisk 添加为bazel
可执行文件。(2)如果没有 Bazelisk,您可以手动安装 Bazel。请务必安装受支持的 Bazel 版本,可以是tensorflow/configure.py
中指定的介于_TF_MIN_BAZEL_VERSION
和_TF_MAX_BAZEL_VERSION
之间的任意版本。
但笔者尝试最快的安装方式是,到Github - bazelbuild/build/releases上下载对应的版本,然后使用sh脚本手动安装
比如依据刚才的配置目标,笔者需要的是 Bazel3.7.2
,所以下载的文件为 bazel-3.7.2-installer-linux-x86_64.sh
# 到对应的路径下并执行
./bazel-3.7.2-installer-linux-x86_64.sh --prefix=/usr/local
#检查版本是否正确 确定是否装上bazel
#注意:在这里如果没有git checkout r2.6 则会告诉你bazel版本不对
bazel version
- 配置编译build选项
官网介绍:通过运行 TensorFlow 源代码树根目录下的
./configure
配置系统 build。此脚本会提示您指定 TensorFlow 依赖项的位置,并要求指定其他构建配置选项(例如,编译器标记)
./configure
这一步就是选择 y/N 基本没啥问题,其他参考里都有贴实例。笔者需要GPU的支持,故在CUDA那一栏选择了y,其他部分如Rocm部分就是N(直接按enter也可以)
- 开始编译
# 编译需要:创建一个空的文件夹
mkdir ~/tmp
export TMP=~/tmp
#在tensorflow/目录下 开始正式编译 --- 时间会比较长(大约1小时)
#根据输出信息,编译过程包含了各种compile与link
bazel build --config=cuda //tensorflow/tools/pip_package:build_pip_package
#编译完了安装
./bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg
#进去看看是啥版本tag,依据此来安装 tensorflow-version-tags.whl
cd /tmp/tensorflow_pkg
#对于我来说是tensorflow-2.6.5;注意这个tag包含了python版本
pip install /tmp/tensorflow_pkg/tensorflow-2.6.5-cp37-cp37m-linux_x86_64.whl
编译完成应输出
7.检查TF是否能用
还可以用下面的程序检查一下
import tensorflow as tf
# 检查TensorFlow是否可以使用GPU/CUDA
if len(tf.config.list_physical_devices('GPU')) > 0:
print("TensorFlow can use the GPU.")
else:
print("TensorFlow cannot use the GPU.")
# 输出TensorFlow版本
print("TensorFlow version:", tf.__version__)
3 - 踩坑记录
3.1 cuda11.0在编译时不支持sm_86
笔者最初选择的 docker是cuda11.0的,在bazel build --config=cuda //tensorflow/tools/pip_package:build_pip_package
过程中出现了错误。所以之后选择了上面提到的cuda11.3的docker
-
查询 https://en.wikipedia.org/wiki/CUDA#GPUs_supported 得知, sm_86的显卡(30系)并不支持11.0;
-
并不是说nvcc 11.0的程序在30系的显卡上就不能跑,但在此处的编译就是有问题,至少笔者的问题出在了这里
-
所以逐渐理解了为啥CUDA11.X出了这么多的版本,其兼容关系几何
3.2 问题2: numpy、TF、python版本匹配
-
tensorflow2.6.5
必须要求numpy~=1.19.2
,也就是必须是``numpy==1.19.X`系列 + 以上错误是在编译成功后,安装tensorflow时输出的,由于我此时的python3.9.X,所以装不上它所需要的numpy版本 -
numpy1.19.2
与python3.9.5
不匹配 , 匹配关系列表-
由于这个docker中编译的东西比较多,不愿放弃 — 所以切python版本
-
但切换python版本以后发现pip也需要切,而且tensorflow的编译结果 是带有python版本的tag的,所以编译完了切python版本是不可取的。在一开始就匹配好numpy与python版本再来编译才是正解。
-
-
import tensorflow时,numpy不正确。
- 在编译tensorflow的时候 是需要用到numpy的,然而在编译时numpy(1.21.X)的版本和我此时,即import时的numpy版本(1.19.5)不匹配;
- 注意这里
API version 0xe 与 0xd
这两个十六进制数,和对应的版本数值(1.19.X或1.21.X)没有关系,但能告诉你当前的numpy与编译tensorflow时的版本相比是高了还是低了,比如我这里 e > d e > d e>d 显然就是现在的版本低了。
4 - 启示
配置环境还是要在docker的环境下进行,以方便环境打包和隔离,同时涉及到编译的环境,往往需要比较纯净,docker就是很好的选择。而且环境“脏了“,直接重开docker也免去了各种卸载刷新环境的的问题。conda的隔离效果还是不够强,一些编译选项、GCC版本、CUDA版本这些是全局的,切换了以后别的环境又被破坏了。
配置环境的参考材料,以官网材料为准,但也需要多方了解,官网材料对于一些坑没有涉及到(比如numpy与python的版本匹配问题)。看一些配置全流程的帖子了解个大概,上手配置后出了问题在具体查问题的点就行。
CUDA、python、GCC、numpy、Tensorflow的版本匹配关系很拧巴:
- 太低的GCC装不了高cuda,太高的GCC不支持numpy
- 太低的CUDA 可能显卡不支持,太高的CUDA可能不兼容框架
- python和numpy版本是有对应关系的,python太高装不了低版本numpy
- numpy与tensorflow版本几乎是一一对应,高numpy可以编译tensorflow但无法正常import使用
- 最佳方案:提前匹配好CUDA、python、GCC、numpy、Tensorflow的关系,然后再开始编译