TensorFlowをビルドしてcondaでインストールできるようにする
TensorFlowをソースコードからビルドし、さらに、conda
でインストールできるようにしました。その結果、1.2倍ほど(雀の涙)速度が速くなりました。
やったこと
大きく分けて、以下二つのことをしました。
- TensorFlowのソースコードをビルドして、wheelファイルを作る
- wheelファイルを、
conda
でインストール可能な形式にビルドする
1の時点でpip
でインストール可能ですが、私の環境はAnacondaなので、一貫性のため、conda
でインストールできるようにしました。
環境/構成
環境
- iMac (21.5-inch, 2017)
- CPU:2.3 GHz Intel Core i5
- メモリ:8GB
構成
- macOS High Sierra
- Homebrew
- pyenv
- Anaconda(3系)
- TensorFlow / Keras
構築手順にしたがい構築していることを前提にしますが、他の構成でも読み替えればうまくいくと思います。ただし、Xcode、Command Line Toolsをインストールしておかないと、Bazelがコンパイラを見つけられずに失敗しそうな気がします。
動機
以下ログが出力されているのを見つけたこと。
2018-08-07 18:02:45.085140: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
このログは、「君のPCのCPUが『拡張命令』をサポートしているにも関わらず、TensorFlowが拡張命令を使うようにコンパイルされていない」と言っています。 つまり、スペックを引き出しきれていないよ、ということです。
私の使っているTensorFlowは、ANACONDA CLOUDのconda-forgeリポジトリから取得した「tensorflow 1.9.0 py36_0」です。バージョン管理の一貫性のために、次の二つの選択肢のうち、前者を選んだということです。
-
ANACONDA CLOUDから
conda
でインストールする -
TensorFlow公式サイトから
pip
でインストールする
ネットの総論では「ソースコードからビルドすれば、このログは出なくなり、多少なりとも速くなる。しかし、手間に見合うかどうか微妙なので、ログを無視するか、GPUを手に入れたほうがいい」とのことのようです。確かに、GPUだと10〜100倍速くなるらしいですからね。でも、ま、何事も経験ということで、ソースコードからのビルドを試してみました。
wheel作成
JDK8をインストールします。(Bazelを動かすのに必要。)
brew cask install homebrew/cask-versions/java8
ビルドツールBazelをインストールします。
brew install bazel
作業ディレクトリを作成のうえ、TensorFlowのソースコードをクローンしてきます。時間をかけたくなかったので、バージョンをしぼりました。本稿執筆時点(2018/08/08)での最新安定バージョンです。
cd <作業ディレクトリ>
git clone --depth=1 -b v1.9.0 https://github.com/tensorflow/tensorflow
Python3に切り替えの上、構成ファイル作成プログラムを実行します。
pyenv versions
pyenv global <Python3の入っているAnaconda>
cd tensorflow
./configure
質問には基本デフォルトで回答します。つまり、[return]を連打すればよいです。その結果、.bazelrc
と.tf_configure.bazelrc
が生成されます。
さて、Bazelでビルドを開始します。まず、コマンドbazel clean --expunge
を実行します。ビルド時、「ツールチェインの解決」に失敗することがあり、そのための予防措置です。おまじないのようなものだと思ってください。
次に、ビルド。以下、--copt=m
に続いて、ログに出ていた拡張命令を小文字で記述します。mを忘れるとエラーになるので、気をつけてください。
bazel build -c opt --copt=-mavx2 --copt=-mfma -k //tensorflow/tools/pip_package:build_pip_package
***ビルドは時間がかかります。***私の場合、82分かかりました。さらに(TensorFlowのプログラマに対する)警告が山ほど出ますが、気にする必要はありません。
ビルドが完了したら、カレントディレクトリを移動せずに、以下コマンドを実行します。
bazel-bin/tensorflow/tools/pip_package/build_pip_package tensorflow.pkg
結果、カレントディレクトリ内にpkgファイルが生成されます。Finderでpkgファイルを右クリック→「パッケージの内容を表示」から、wheelファイルをコピーして取り出すことができます。
conda-build
wheelファイル保管ディレクトリを作成し、取り出したwheelファイルを置きます。
新たに作業ディレクトリ2を作成し、直下に二種類のファイルを作成します。
まずは、build.sh
。
#!/bin/bash
WHEELHOUSE=<wheelファイル保管ディレクトリへの絶対パス>
pip install --no-deps $WHEELHOUSE/tensorflow-1.9.0-cp36-cp36m-macosx_10_7_x86_64.whl
次に、meta.yaml
。
package:
name: tensorflow
version: "1.9.0"
build:
number: 0
entry_points:
- freeze_graph = tensorflow.python.tools.freeze_graph:run_main
- toco_from_protos = tensorflow.contrib.lite.toco.python.toco_from_protos:main
- tflite_convert = tensorflow.contrib.lite.python.tflite_convert:main
- toco = tensorflow.contrib.lite.python.tflite_convert:main
- saved_model_cli = tensorflow.python.tools.saved_model_cli:main
requirements:
build:
- python
- pip
run:
- python
- absl-py >=0.1.6
- astor >=0.6.0
- gast >=0.2.0
- numpy >=1.13.3
- six >=1.10.0
- protobuf >=3.4.0
- tensorboard 1.9.*
- termcolor >=1.1.0
- grpcio >=1.8.6
test:
imports:
- tensorflow
commands:
- tensorboard --help | grep USAGE
- freeze_graph --help
- toco_from_protos --help
- toco --help
- saved_model_cli --help
about:
home: http://tensorflow.org/
license: Apache 2.0
license_family: Apache
summary: TensorFlow is a machine learning library, base package contains only tensorflow.
description: |
TensorFlow provides multiple APIs.The lowest level API, TensorFlow Core
provides you with complete programming control.
Base package contains only tensorflow, not tensorflow-tensorboard.
dev_url: https://github.com/tensorflow/tensorflow
doc_url: https://www.tensorflow.org/get_started/get_started
doc_source_url: https://github.com/tensorflow/tensorflow/tree/master/tensorflow/docs_src
内容は、conda-forgeの真似事です。より応用の効くやり方としては、維持管理手順を参考に、Pythonのみ、Anaconda無しの仮想環境を新規に追加。さらに、pipdeptreeとTensorFlowをpip
で追加したのち、コマンドpipdeptree
で依存パッケージを調べてみると良いでしょう。
ファイルが作成できたら、conda
のパッケージをビルドします。テストも行われるので、15分はかかるでしょう。途中、新規にパッケージを追加する旨が表示されますが、ビルド/テスト用の環境に追加されるものであり、既存環境に追加されるものではないので安心してください。
conda build -c conda-forge <作業ディレクトリ2>
パッケージは、以下の二箇所に出力されます。
- ~/.pyenv/versions/anaconda<バージョン>/conda-bld/osx-64
- ~/.pyenv/versions/anaconda<バージョン>/pkgs
出力されたパッケージを検証するため、維持管理手順を参考に、TensorFlowの入っていない仮想環境を一つ追加します。
仮想環境が追加できたら、ワークスペースに移動し、仮想環境に入ります。
cd <ワークスペース>
conda activate <作成した仮想環境>
仮想環境にTensorFlowとKerasをインストールします。内容確認、そしてインストールの順です。最後のコマンドは、TensorFlowが確かにローカルからインストールされたことを確かめるためのものです。
conda install --dry-run -c conda-forge --use-local tensorflow
conda install -c conda-forge --use-local tensorflow
conda install --dry-run keras
conda install keras
conda list | grep tensorflow
これで一連の手順は終わりです。最後に仮想環境から抜け、システムのPythonをデフォルト(system)に戻しておきましょう。
conda deactivate
pyenv global system
cd ~
pyenv versions
性能測定
Jupyter Notbookを用いて、性能を測定しましょう。性能測定用のコードはこんな感じです。
from keras.datasets import mnist
mnist.load_data()
import time
start = time.time()
## mnist_cnn.py ##
K.clear_session()
elapsed_time = time.time() - start
print ("elapsed_time:{0}".format(elapsed_time) + "[sec]")
## mnist_cnn.py ##
の箇所は、mnist_cnn.pyから取得したコードで置き換えてください。
測定結果
比較対象
以下の三環境で性能を測定し、比較しました。
- 拡張命令なし(=ANACONDA CLOUDのconda-forgeリポジトリから
conda
でインストールした環境) - 拡張命令あり(=今回作った環境)
- 公式(=TensorFlow公式サイトから
pip
でインストールした環境)
比較結果
- 拡張命令なし:elapsed_time:1364.960855960846[sec]
- 拡張命令あり:elapsed_time:1112.0023930072784[sec]
- 公式:elapsed_time:1381.5033478736877[sec]
epoch | 1.拡張命令なし | 2.拡張命令あり | 3.公式 |
---|---|---|---|
1 | 116s | 95s | 117s |
2 | 115s | 93s | 117s |
3 | 113s | 91s | 113s |
4 | 113s | 92s | 114s |
5 | 113s | 92s | 114s |
6 | 112s | 93s | 114s |
7 | 113s | 91s | 114s |
8 | 113s | 91s | 115s |
9 | 113s | 92s | 113s |
10 | 112s | 91s | 114s |
11 | 112s | 93s | 114s |
12 | 112s | 92s | 115s |
平均 | 113.1s | 92.2s | 114.5s |
考察
t検定を行ってみました。
from scipy import stats
without_expansion = [116,115,113,113,113,112,113,113,113,112,112,112]
with_expansion = [95,93,91,92,92,93,91,91,92,91,93,92]
official = [117,117,113,114,114,114,114,115,113,114,114,115]
res1 = stats.ttest_ind(without_expansion, official, equal_var = False)
res2 = stats.ttest_ind(without_expansion, with_expansion, equal_var = False)
print(res1)
print(res2)
Ttest_indResult(statistic=-2.715855310874572, pvalue=0.012643877897195724)
Ttest_indResult(statistic=42.099960209201704, pvalue=1.6828611571718665e-22)
t検定の結果に対する考察は以下のとおりです。
- 「拡張命令なし」と「公式」は、5%水準で有意差があると言える。だが、実際の差を見ると微差である。結局、バイナリを広く配布するわけで、特定のCPUに特化したビルドは行っていないのである。
- 「拡張命令あり」と「拡張命令なし」は、1%水準で有意差がある。速度にして1.23倍、時間にして0.81倍。CPUの拡張命令を使った結果、処理が速くなったと考えられる。
まとめ
本稿で分かったことを、以下にまとめます。
-
pip
用のwheelファイルを元に、conda
用のパッケージをビルドできる。 - TensorFlowをソースコードからビルドし、CPUの拡張命令を使うようにすることで、1.2倍ほど速度が速くなる。ただし、桁数が変わるほどは速くならない。
この記事で書いたように、機械学習は仮説検証の繰り返しです。検証の精度を上げるには、桁数が変わる程度の変化が欲しいところです。
…誰か、NVIDIAのGPUを積んだ高性能マシンを買ってくれないかな。
参考サイト
- TensorFlowのインストール
- Python: Keras/TensorFlow の学習を CPU の拡張命令で高速化する (Mac OS X)
- 拡張命令セットでTensorFlowをコンパイルする方法
- TensorFlow CPU最適化ビルド
- TensorFlowをソースからインストールしてみる(Mac)
- TensorFlowをソースからビルドする方法とその効果
- Building conda packages from scratch
- Using wheel files with conda
- conda-forge/tensorflow-feedstock/recipe
- AnacondaRecipes/tensorflow_recipes/tensorflow-base
- Python: pipdeptree でパッケージの依存関係を調べる
- Docs » Command reference » conda build
- Docs » Command reference » conda install
- 【Python】処理にかかる時間を計測して表示
- keras-team/keras/examples/mnist_cnn.py