2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

最新のTensorFlow 2(GPU版)をCentOS7上で極力root権限なしにソースからビルド&インストールする

Last updated at Posted at 2021-01-29

ネット上にはCentOS7かつ最新のTensorflow 2(GPU対応版)のインストール方法手順が書かれた記事がほとんどなかったので書いてみる。

Ubuntu 20と違ってCentOS 7.8にはお手軽にtensorflow-gpuを入れる手段がないので、ソースからビルドを行う。あとついでにgccやpythonもソースからビルドしてインストールする。

かなり難しいインストール作業で、トータルで5時間くらいかかる。

参考資料

マシン環境

  • CentOS 7.8.2003
  • GPU: NVIDIA RTX 3090 2枚差し (CUDA 11.1.105)

以下ではTensorFlow2のソースからのビルド&インストールに必要となるソフトウェア類gcc, python, javaSDK, bazelを/home/apps以下に置いて適宜利用していくことにする。

CUDA 11.1, cudnn 8, CUDA SDK

root権限を持っている場合はCUDA Toolkit 11.1を普通にインストールすればよい。rootを持っていない場合はcudaのインストーラでrunfileを使えばインストール先をホームディレクトリ以下に指定できるはず。cudnn 8も同様に公式サイトからダウンロードする。これについてはGPU版を使う上で避けて通れないので、なんらかの形でインストールされていることを前提にする。

参考:https://stackoverflow.com/questions/39379792/install-cuda-without-root。

gcc 8.4.0

CentOS7の/usr/bin/gccにデフォルトで存在するgcc 4.8.5は古すぎて使いたくなかったので(パフォーマンスも落ちる?)、ソースからビルドしたgcc 8.4.0を使う。

gccnum="8.4.0"
wget https://ftp.gnu.org/gnu/gcc/gcc-${gccnum}/gcc-${gccnum}.tar.xz
tar Jxvf gcc-${gccnum}.tar.xz
cd gcc-${gccnum}
./contrib/download_prerequisites
./configure --with-system-zlib --disable-multilib --disable-bootstrap --enable-languages=c,c++,fortran --prefix=/home/apps/compiler/gcc/${gccnum}
make -j8 && make install

/home/apps/compiler/gcc/8.4.0以下にインストールされた。

python 3.8.7

module load gcc/8.4.0
wget https://www.python.org/ftp/python/3.8.7/Python-3.8.7.tar.xz
tar xf Python-3.8.7.tar.xz
cd Python-3.8.7
./configure --prefix=/home/apps/python/3.8.7 --enable-ipv6 --enable-loadable-sqlite-extensions --with-system-ffi --enable-optimizations
make -j8 altinstall

オプションはHomebrewで使われているものを流用したが、実質--enable-optimizations以外はあまり関係ないと思われる。/home/apps/compiler/python/3.8.7以下にインストールされた。

Java SDK 15.0.2

bazelのビルドに必要らしい。_linux-x64_bin.tar.gzのものをダウンロードする。以下ではwgetでとってこようとしているが、素直にブラウザを使って公式ページ上からJava SDKをダウンロードしてきたほうがいい。

# wget https://download.oracle.com/otn-pub/java/jdk/15.0.2+7/hogehogehoghoge/jdk-15.0.2_linux-x64_bin.tar.gz
tar zxvf jdk-15.0.2_linux-x64_bin.tar.gz
mv jdk-15.0.2 /home/apps
export JAVA_HOME=/home/apps/jdk-15.0.2/

/home/apps/jdk-15.0.2/以下にインストールし、環境変数JAVA_HOMEを設定しておく。

bazel 3.1.0

バイナリ版のインストーラもあるけれど、あれだとうまくいかないみたいなので仕方なくソースビルドすることにする。ちなみに元GitHubのマスター(2.4.2以降も?)ではbazelの要求バージョンが3.7.2になっているかもしれないので、その場合はダウンロードするbazelのバージョン番号を変更して以下の操作を行う。

wget https://github.com/bazelbuild/bazel/releases/download/3.1.0/bazel-3.1.0-dist.zip
unzip bazel-3.1.0-dist.zip -d bazel-3.1.0
cd bazel-3.1.0

ここで、third_party/grpc/bazel/generate_cc.bzlファイルに対して https://github.com/bazelbuild/bazel/pull/11860/files にかかれてあるように、use_default_shell_env = True,の一行を入れて修正する。終わったらコンパイルを行う。

# さっき入れたgcc 8.4.0をGCCROOTに設定する
GCCROOT=/home/apps/compiler/gcc/8.4.0
export GCC_HOST_COMPILER_PATH=$GCCROOT/bin/gcc
export GCC_HOST_COMPILER_PREFIX=$GCCROOT/bin
export CXX=$GCCROOT/bin/gcc
export CC=$GCCROOT/bin/gcc
export LD_LIBRARY_PATH=$GCCROOT/lib64
export LDFLAGS="-L$GCCROOT/lib -L$GCCROOT/lib64"
export CXXFLAGS="-L$GCCROOT/lib -L$GCCROOT/lib64"

export JAVA_HOME=/home/apps/jdk-15.0.2/
env BAZEL_LINKOPTS=-static-libstdc++:-static-libgcc BAZEL_LINKLIBS=-l%:libstdc++.a:-lm bash ./compile.sh

コンパイル時にBAZELのリンクオプションを付けておく。でき上がったbazelを/home/apps/bazel/3.1.0/binに置く

mkdir -p /home/apps/bazel/3.1.0/bin
cp output/bazel /home/apps/bazel/3.1.0/bin

bintools

gcc 8.4.0のbinディレクトリにはgcc-arがあってもarがないので、bintoolsを入れることで解決できる(ような気がする)

wget https://ftp.gnu.org/gnu/binutils/binutils-2.36.tar.gz	
tar zxvf binutils-2.36.tar.gz	
cd binutils-2.36
./configure --prefix=/home/apps/binutils/2.36
make -j 16 MAKEINFO=true	
make install MAKEINFO=true

終わったら、先程インストールしたgcc 8.4.0のbinディレクトリに一時的にこのbinutilsでインストールしたarのシンボリックリンクを貼っておく

ln -s /home/apps/binutils/2.36/bin/ar /home/apps/compiler/gcc/8.4.0/bin/ar

こうすることで後のtensorflowのbazel build処理中のリンク処理がうまくいった。

tensorflow 2.4.1

まずtensorflow 2.4.1をダウンロードする。

# tensorflow 2.4.1のダウンロード
$ git clone https://github.com/tensorflow/tensorflow.git -b v2.4.1 --recursive --depth 1

Tensorflowのコンパイル時のエラーを解決するためのワークアラウンド(応急処置回避策)を以下に示す。

protocが正しくないバージョンのstdc++にリンクされてしまう問題を次のようにして解決する。third_party/gpus/crosstool/cc_toolchain_config.bzl.tplのファイルの543行目を以下のように変更する

- flag_group(flags = ["-lc++" if cpu == "darwin" else "-lstdc++"]),
+ flag_group(flags = ["-lc++" if cpu == "darwin" else "-l:libstdc++.a"]),

third_party/gpus/crosstool/cc_toolchain_config.bzl.tplファイルの241行目あたり、objcopyが上でインストールしたbinutilsのものを使うように変更する。

def _tool_paths(cpu, ctx):
    if cpu in ["local", "darwin"]:
        return [
            tool_path(name = "gcc", path = ctx.attr.host_compiler_path),
            tool_path(name = "ar", path = ctx.attr.host_compiler_prefix + (
                "/ar" if cpu == "local" else "/libtool"
            )),
            tool_path(name = "compat-ld", path = ctx.attr.host_compiler_prefix + "/ld"),
            tool_path(name = "cpp", path = ctx.attr.host_compiler_prefix + "/cpp"),
            tool_path(name = "dwp", path = ctx.attr.host_compiler_prefix + "/dwp"),
            tool_path(name = "gcov", path = ctx.attr.host_compiler_prefix + "/gcov"),
            tool_path(name = "ld", path = ctx.attr.host_compiler_prefix + "/ld"),
            tool_path(name = "nm", path = ctx.attr.host_compiler_prefix + "/nm"),
-           tool_path(name = "objcopy", path = ctx.attr.host_compiler_prefix + "/objcopy"),
+           tool_path(name = "objcopy", path = "/home/apps/binutils/2.36/bin/objcopy"),
            tool_path(name = "objdump", path = ctx.attr.host_compiler_prefix + "/objdump"),
            tool_path(name = "strip", path = ctx.attr.host_compiler_prefix + "/strip"),
        ]

システムデフォルトのgcc(/bin/gcc)を使わない場合(例えば上のように/home/apps/以下にインストールしたgcc 8.4.0を使おうとしているとき)、TensorFlow 2.4.1では以下の修正を third_party/flatbuffers/build_defs.bzl に適用しておく。将来的に2.4.2以降は修正されているはず。
https://github.com/tensorflow/tensorflow/pull/46550/files/60aea05061a01b18ff02582341ab374abf253437

./configureでの設定に進む前に、gcc, python3.8, bazelへのPATHを通しておく。

$ export PATH="/home/apps/bazel/3.1.0/bin:$PATH"
$ echo $PATH
/home/apps/bazel/3.1.0/bin:/home/apps/python/3.8.7/bin:/home/apps/compiler/gcc/8.4.0/bin:/home/yoshitakam/.local/bin:/usr/bin:/home/moriwaki/bin:/usr/local/sbin:/usr/sbin

/home/apps/bazel/3.1.0/bin:/home/apps/python/3.8.7/bin:/home/apps/compiler/gcc/8.4.0/binが入っていることを確認する(順不同) 終わったら./configureでの設定へ。

# configureでbazel buildのための設定ファイルを作る
$ ./configure
You have bazel 3.1.0- (@non-git) installed.
Please specify the location of python. [Default is /bin/python3]: /home/apps/python/3.8.7/bin/python3.8


Found possible Python library paths:
  /home/apps/python/3.8.7/lib/python3.8/site-packages
Please input the desired Python library path to use.  Default is [/home/apps/python/3.8.7/lib/python3.8/site-packages]

Do you wish to build TensorFlow with ROCm support? [y/N]: N
No ROCm support will be enabled for TensorFlow.

Do you wish to build TensorFlow with CUDA support? [y/N]: y
CUDA support will be enabled for TensorFlow.

Do you wish to build TensorFlow with TensorRT support? [y/N]: N
No TensorRT support will be enabled for TensorFlow.

Found CUDA 11.1 in:
    /usr/local/cuda-11.1/targets/x86_64-linux/lib
    /usr/local/cuda-11.1/targets/x86_64-linux/include
Found cuDNN 8 in:
    /usr/local/cuda-11.1/targets/x86_64-linux/lib
    /usr/local/cuda-11.1/targets/x86_64-linux/include


Please specify a list of comma-separated CUDA compute capabilities you want to build with.
You can find the compute capability of your device at: https://developer.nvidia.com/cuda-gpus. Each capability can be specified as "x.y" or "compute_xy" to include both virtual and binary GPU code, or as "sm_xy" to only include the binary code.
Please note that each additional compute capability significantly increases your build time and binary size, and that TensorFlow only supports compute capabilities >= 3.5 [Default is: 3.5,7.0]: 8.6


Do you want to use clang as CUDA compiler? [y/N]: N
nvcc will be used as CUDA compiler.

Please specify which gcc should be used by nvcc as the host compiler. [Default is /home/apps/compiler/gcc/8.4.0/bin/gcc]:


Please specify optimization flags to use during compilation when bazel option "--config=opt" is specified [Default is -Wno-sign-compare]:


Would you like to interactively configure ./WORKSPACE for Android builds? [y/N]: N
Not configuring the WORKSPACE for Android builds.

Preconfigured Bazel build configs. You can use any of the below by adding "--config=<>" to your build command. See .bazelrc for more details.
        --config=mkl            # Build with MKL support.
        --config=mkl_aarch64    # Build with oneDNN support for Aarch64.
        --config=monolithic     # Config for mostly static monolithic build.
        --config=ngraph         # Build with Intel nGraph support.
        --config=numa           # Build with NUMA support.
        --config=dynamic_kernels        # (Experimental) Build kernels into separate shared objects.
        --config=v2             # Build TensorFlow 2.x instead of 1.x.
Preconfigured Bazel build configs to DISABLE default on features:
        --config=noaws          # Disable AWS S3 filesystem support.
        --config=nogcp          # Disable GCP support.
        --config=nohdfs         # Disable HDFS support.
        --config=nonccl         # Disable NVIDIA NCCL support.
Configuration finished

CUDA compute capabilitiesのところで入力する数字は https://developer.nvidia.com/cuda-gpus ここで確認する。RTX3090の場合は8.6になる。

./configureが終わったら、公式ガイドに従って次にbazel buildを行うが、このとき以下のようなリンクオプションをたくさん付けておく。また、cudaを使いたい場合は必ず--config=cudaをつける。gcc-5以降の互換性を保ちたい場合は--cxxopt="-D_GLIBCXX_USE_CXX11_ABI=0"をつける。

env BAZEL_LINKOPTS=-static-libstdc++:-static-libgcc BAZEL_LINKLIBS=-l%:libstdc++.a:-lm BAZEL_CXXOPTS=-std=gnu++0x bazel build --config=opt --config=cuda --cxxopt="-D_GLIBCXX_USE_CXX11_ABI=0" //tensorflow/tools/pip_package:build_pip_package --action_env="LD_LIBRARY_PATH=${LD_LIBRARY_PATH}" --verbose_failures

ビルドには8コアマシンで4時間くらいかかるので、ssh先でビルドが終わるまで監視するのがめんどくさい場合は、nohup env BAZEL //(途中コマンド省略)// --verbose_failures &としておけば良けば、sshが切れても処理が続けられる。他にはdisownコマンドを使う方法もある。

ビルドに失敗したとき、やり直す前にbazel clean --expungeで一度ビルド途中のファイルを消去しておく。

正しくビルドが成功すると、TensorFlowのディレクトリから見て./bazel-bin/tensorflow/tools/pip_package/build_pip_packageというファイルが作られているはずなので、これを以下のコマンドでwheelファイル化させる。

# リリース版(2.4.1とかバージョン番号がついている方)はこちらのコマンド
./bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg
# githubのマスターから直接引っ張ってきた場合はnightly buildフラグを付けると良い
# ./bazel-bin/tensorflow/tools/pip_package/build_pip_package --nightly_flag /tmp/tensorflow_pkg

成功すると/tmp/tensorflow_pkg以下にwhlファイルが生成されているので、任意のディレクトリ上に移す(例:/home/apps)。

mv /tmp/tensorflow_pkg/tensorflow-2.4.1-cp38-cp38-linux_x86_64.whl /home/apps

あとはこれをpython3.8のpip3.8などでインストールすれば使えるようになる(依存パッケージ解決のためにインターネット環境が必要かも)。

/home/apps/python/3.8.7/bin/python3.8 -m pip install /home/apps/tensorflow-2.4.1-cp38-cp38-linux_x86_64.whl --user

--userの代わりに、-tオプションを付けて-t /home/apps/tensorflow-gpu/2.4.1_python3.8_cuda11とすれば、そのディレクトリにパッケージをインストールすることもでき、あとで環境変数PYTHONPATHを通せば使えるようになる。

動作テスト

最後にテストしてみる。python3.8起動前に、上記のpython3.8, gcc-8.4.0, cuda-11.1について環境変数PATHLD_LIBRARY_PATHを通しておく。私はPATHの管理についてenvironment moduleを使っています。

$ python3.8
Python 3.8.7 (default, Jan 29 2021, 03:36:15)
[GCC 8.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from tensorflow.python.client import device_lib

2021-01-29 15:47:38.281608: I tensorflow/stream_executor/platform/default/dso_loader.cc:49] Successfully opened dynamic library libcudart.so.11.0
>>> device_lib.list_local_devices()
2021-01-29 15:47:44.310282: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  SSE3 SSE4.1 SSE4.2 AVX AVX2 FMA
To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
2021-01-29 15:47:44.313095: I tensorflow/compiler/jit/xla_gpu_device.cc:99] Not creating XLA devices, tf_xla_enable_xla_devices not set
2021-01-29 15:47:44.315158: I tensorflow/stream_executor/platform/default/dso_loader.cc:49] Successfully opened dynamic library libcuda.so.1
2021-01-29 15:47:44.553626: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1720] Found device 0 with properties:
pciBusID: 0000:01:00.0 name: GeForce RTX 3090 computeCapability: 8.6
coreClock: 1.695GHz coreCount: 82 deviceMemorySize: 23.70GiB deviceMemoryBandwidth: 871.81GiB/s
2021-01-29 15:47:44.554559: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1720] Found device 1 with properties:
pciBusID: 0000:81:00.0 name: GeForce RTX 3090 computeCapability: 8.6
coreClock: 1.695GHz coreCount: 82 deviceMemorySize: 23.70GiB deviceMemoryBandwidth: 871.81GiB/s
2021-01-29 15:47:44.554693: I tensorflow/stream_executor/platform/default/dso_loader.cc:49] Successfully opened dynamic library libcudart.so.11.0
2021-01-29 15:47:44.560335: I tensorflow/stream_executor/platform/default/dso_loader.cc:49] Successfully opened dynamic library libcublas.so.11
2021-01-29 15:47:44.560419: I tensorflow/stream_executor/platform/default/dso_loader.cc:49] Successfully opened dynamic library libcublasLt.so.11
2021-01-29 15:47:44.568157: I tensorflow/stream_executor/platform/default/dso_loader.cc:49] Successfully opened dynamic library libcufft.so.10
2021-01-29 15:47:44.573367: I tensorflow/stream_executor/platform/default/dso_loader.cc:49] Successfully opened dynamic library libcurand.so.10
2021-01-29 15:47:44.591659: I tensorflow/stream_executor/platform/default/dso_loader.cc:49] Successfully opened dynamic library libcusolver.so.11
2021-01-29 15:47:44.597937: I tensorflow/stream_executor/platform/default/dso_loader.cc:49] Successfully opened dynamic library libcusparse.so.11
2021-01-29 15:47:44.600959: I tensorflow/stream_executor/platform/default/dso_loader.cc:49] Successfully opened dynamic library libcudnn.so.8
2021-01-29 15:47:44.609122: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1862] Adding visible gpu devices: 0, 1
2021-01-29 15:47:44.609182: I tensorflow/stream_executor/platform/default/dso_loader.cc:49] Successfully opened dynamic library libcudart.so.11.0
2021-01-29 15:47:45.879186: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1261] Device interconnect StreamExecutor with strength 1 edge matrix:
2021-01-29 15:47:45.879243: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1267]      0 1
2021-01-29 15:47:45.879253: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1280] 0:   N N
2021-01-29 15:47:45.879261: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1280] 1:   N N
2021-01-29 15:47:45.883077: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1406] Created TensorFlow device (/device:GPU:0 with 22428 MB memory) -> physical GPU (device: 0, name: GeForce RTX 3090, pci bus id: 0000:01:00.0, compute capability: 8.6)
2021-01-29 15:47:45.886622: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1406] Created TensorFlow device (/device:GPU:1 with 22428 MB memory) -> physical GPU (device: 1, name: GeForce RTX 3090, pci bus id: 0000:81:00.0, compute capability: 8.6)
[name: "/device:CPU:0"
device_type: "CPU"
memory_limit: 268435456
locality {
}
incarnation: 12593410599457824982
, name: "/device:GPU:0"
device_type: "GPU"
memory_limit: 23518436480
locality {
  bus_id: 4
  numa_node: 3
  links {
  }
}
incarnation: 9832514123427674549
physical_device_desc: "device: 0, name: GeForce RTX 3090, pci bus id: 0000:01:00.0, compute capability: 8.6"
, name: "/device:GPU:1"
device_type: "GPU"
memory_limit: 23518436480
locality {
  bus_id: 2
  numa_node: 1
  links {
  }
}
incarnation: 10036722414424779821
physical_device_desc: "device: 1, name: GeForce RTX 3090, pci bus id: 0000:81:00.0, compute capability: 8.6"
]

1ノードに2つあるRTX3090が正しく認識されているのでこれで使えるはず。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?