LoginSignup
1
4

More than 5 years have passed since last update.

TensorFlowをビルドしてcondaでインストールできるようにする

Last updated at Posted at 2018-08-08

TensorFlowをビルドしてcondaでインストールできるようにする

TensorFlowをソースコードからビルドし、さらに、condaでインストールできるようにしました。その結果、1.2倍ほど(雀の涙)速度が速くなりました。

やったこと

大きく分けて、以下二つのことをしました。

  1. TensorFlowのソースコードをビルドして、wheelファイルを作る
  2. 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」です。バージョン管理の一貫性のために、次の二つの選択肢のうち、前者を選んだということです。

ネットの総論では「ソースコードからビルドすれば、このログは出なくなり、多少なりとも速くなる。しかし、手間に見合うかどうか微妙なので、ログを無視するか、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から取得したコードで置き換えてください。

測定結果

比較対象

以下の三環境で性能を測定し、比較しました。

  1. 拡張命令なし(=ANACONDA CLOUDのconda-forgeリポジトリからcondaでインストールした環境)
  2. 拡張命令あり(=今回作った環境)
  3. 公式(=TensorFlow公式サイトからpipでインストールした環境)

比較結果

  1. 拡張命令なし:elapsed_time:1364.960855960846[sec]
  2. 拡張命令あり:elapsed_time:1112.0023930072784[sec]
  3. 公式: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を積んだ高性能マシンを買ってくれないかな。

参考サイト

1
4
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
1
4