Macで外付けGPU使用しTensorflow1.4GPUをソースからコンパイル

書き忘れがあれば逐次編集予定

環境

ハード

  • MacBook Pro (Retina, 13-inch, Early 2015)
  • eGFX Breakaway Box (eGPU Expansion System)
  • - (これ以外のハードも試してみたので、機会があれば記載)
  • nVidia GeForce 1060

ソフト

  • MacOS10.13.1

  • Nvidia Webドライバ

  • XcodeCommandLineTool 8.3.2

  • cuda 9.0

  • cudnn 7

  • HomeBrew

  • Bazel

  • Anaconda

SIPについて

SIPは最近のMacのシステム整合性保護というやつで、野良ドライバの排除等の機能を担っており、Command + Rでシステム起動した状態でコマンドプロンプトでcsrutilから記入する方式で変更可能です。(具体的な方法は後述)

eGPUを認識させる

基本的にはこちらの引用元そのまま
https://egpu.io/forums/mac-setup/wip-nvidia-egpu-support-for-high-sierra/

以前にeGPUにトライした人は

SierraでeGPUのためにInfo.plistを変更していたら元に戻します。(何もしていない人は気にしなくていいです)

GPUドライバ

SIPを有効にしたままWebドライバをインストールします。NVIDIAのwebサイトから最新のWebドライバをダウンロードしてインストール

CUDAドライバ

NVIDIAのwebサイト上にあるCUDAドライバインストーラを使ってインストール

オフィシャルの説明
http://docs.nvidia.com/cuda/cuda-installation-guide-mac-os-x/index.html

SIP

先述のSIPを変更するためcommand + Rを押しながら起動。リカバリモードからの起動になり、そこからターミナルを起動してcsrutil disable(SIPを停止させる。)もしくは、csrutil enable --without kext(ドライバのインストール可能にする)を実行。(どちらにせよ後述のコンパイラ使用する場合はSIP停止する。)

High SierraでNVidiaの動作をさせる。

リンク先のnvidia-egpu-v2-1013-1.zipをダウンロードしてインストール。ダウンロードできないときは、safariを使ってダウンロードを試してください。

ディスプレイの表示や、省エネルギー設定にあるはずのGPU切り替え関連は変わっていないが、システムレポートのグラフィックス/ディスプレイ項目にはちゃんと表示されている。
スクリーンショット 2017-11-20 12.09.27.png

https://hnakamur.github.io/blog/2015/07/25/setup_cuda_on_macbook_pro_with_geforce/

ここまでで注意すべきところ

eGPU接続して起動時に真っ暗な状態から起動しない場合

一部の機種では、eGPUを接続した状態で起動した場合、真っ暗なままで起動画面が映らないことがある(当方そんな感じ)。
対処法は、一旦eGPUを切断した状態で起動してからeGPUを接続、電源を入れて、その後に一旦ログアウトする。すると、eGPU側のディスプレイも、元のディスプレイも表示されるし、認識もされる。
さらに、外部ディスプレイを繋いでディスプレイをミラーリングすると使用GPUがeGPUになるっぽい。

03bgqho4lugtlnmi.png

その他注意点

  • 上記の真っ暗な画面になる端末の場合、eGPUが有効(ケーブルが刺さっていてeGPUの電源が入っている)場合は通常の再起動をすると再起動後真っ暗になりますので、再起動は使わずにシステム終了してから起動したほうが良い。
  • ケーブルを抜くとクラッシュします。

Tensorflowをソースからコンパイル

ここからは各自の環境に強く左右されてエラーが起きやすいです。

このスレッドでエラー対応とか色々ノウハウが記載されています。上手く行かないときはこちらを読んでみては。
https://github.com/tensorflow/tensorflow/issues/12052#issuecomment-341937498

Anacondaをインストール

https://anaconda.org

Anacondaをインストールします。
python関連の処理をするまでであれば、特にどのタイミングでインストールしなければというわけではないです。

JDK

Homebrew関連の処理の前にJDKをインストール。

http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html

Homebrew

Homebrewをインストール

https://brew.sh/index_ja.html

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Homebrewを使って色々インストール

brew update
brew upgrade

brew install coreutils
brew install swig
brew install bazel

Homebrewを使ってnvidia-cudaをインストール

最近、cask上ではcudaではなくnvidia-cudaという名前に変更されたらしい。
このタイミングでもドライバをインストールするので、前述のWebドライバはインストールする必要があるのかどうかは不明。

brew tap caskroom/drivers
brew cask install nvidia-cuda
# 確認
brew cask info nvidia-cuda

ejib8jhcr6tlz0k9.png

インストール後

BrewによるCUDAインストール後はバージョンが少し古くなっているので、「システム環境設定」の「CUDA」項目にある「Install Cuda Updage」をクリックしてバージョンを最新にしておく。
Webドライバも同じくバージョンを最新にしておく。

9zqv5d2ktgh3q5mi.png

cuDNN

NVIDIAにしてサインインする。

https://developer.nvidia.com/accelerated-computing-developer

cuDNNをダウンロードする

https://developer.nvidia.com/cudnn

kqgzaxlibz2awcdi.png

ダウンロードしたら、cudnn-9.0-osx-x64-v7.tgzのようなものがダウンロードされたかと思うので解凍。
解凍すると、

- cuda
- lib
- - libcudnn_static.a
- - libcudnn.dylib
- - libcudnn.7.dylib
- NVIDIA_SLA_cuDNN_Support
- include
- - cudnn.h

f4gksy6es4jf9a4i.png

のようになっていると思います。
ダウンロードフォルダにダウンロードされたと仮定して、新しくターミナルを開いて下記を実行

cd Downloads
sudo cp cuda/include/cudnn.h /usr/local/cuda/include/
sudo cp cuda/lib/libcudnn* /usr/local/cuda/lib/

実行したら、そのターミナルは閉じて構いません。

.bash_profile

.bash_profileを編集します。
(ユーザ名)は適宜変更。

# Anacondaインストール時に作られると思います。
# added by Anaconda3 5.0.1 installer
export PATH="/Users/(ユーザ名)/anaconda3/bin:$PATH"

# ここから追記

# export DYLD_LIBRARY_PATH="/usr/local/cuda/lib":$DYLD_LIBRARY_PATH

export CUDA_HOME=/usr/local/cuda
export DYLD_LIBRARY_PATH=/Users/(ユーザ名)/lib:/usr/local/cuda/lib:/usr/local/cuda/extras/CUPTI/lib:/Developer/NVIDIA/CUDA-9.0/lib
export LD_LIBRARY_PATH=$DYLD_LIBRARY_PATH
export PATH=$DYLD_LIBRARY_PATH:$PATH

export PATH=/Developer/NVIDIA/CUDA-9.0/bin${PATH:+:${PATH}}

出来れば再起動したいところですが、bash_profileを再読込でも対応出来ます。

source ~/.bash_profile

コンパイル

1回のコンパイルで大体2,3時間ほどかかるかと思います。

参考
https://gist.github.com/smitshilu/53cf9ff0fd6cdb64cca69a7e2827ed0f
https://github.com/nathanielatom/tensorflow/releases/tag/v1.4.0-mac

Xdoce command line tools

Xcodeとは別にXcode command line toolsをインストール。
バージョンは8.3.2か8.2

https://developer.apple.com/download/more/

pihs46b9x0jgiudi.png

なお、ソフトウェア・アップデートが最新版をインストールさせようと邪魔をしてくるので要注意。

clangの切り替え

# 現在のclangのバージョン
/usr/bin/clang --version
# コマンドラインツールに変更
sudo xcode-select -s /Library/Developer/CommandLineTools
# バージョンが変わったのを確認
/usr/bin/clang --version
# パスの確認
sudo xcode-select -p
# 元に戻すときは下記を実行
# sudo xcode-select -r

GPUのCompute Capabilityを確認する。

下記URLから利用するGPUのCompute Capabilityを確認。

https://developer.nvidia.com/cuda-gpus

GPU Compute Capability
... ...
GeForce GTX 1060 6.1
... ...

私はGTX1060を利用するので、この場合6.1という番号が必要です。

skhjy157tujzia4i.png

Gitからクローン

新たにターミナルを開いて下記を実行。
作業フォルダにtensorflowフォルダが出来ると思います。

git clone https://github.com/tensorflow/tensorflow
cd tensorflow
git checkout r1.4

コードを書き換える

特定のファイルの__align__(sizeof(T))の記述を削除する。
下記の行数になると思いますが、行番号が変わってる可能性もあります。

ファイル名 行番号
tensorflow/core/kernels/depthwise_conv_op_gpu.cu.cc 166
436
1054
1313
tensorflow/core/kernels/split_lib_gpu.cu.cc 122
tensorflow/core/kernels/concat_lib_gpu.impl.cu.cc 72

例えば

extern __shared__ __align__(sizeof(T)) unsigned char shared_memory[];

の場合は

extern __shared__ unsigned char shared_memory[];

となる。

さらにコードを書き換える。

少し前のclangにはOpenMPという並列スレッドのライブラリに対応していないようで、これが原因で下記のようなエラーが表示され、コンパイルが通らない時があります。

clang: warning: argument unused during compilation: '-pthread'
ld: library not found for -lgomp
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Target //tensorflow/tools/pip_package:build_pip_package failed to build
Use --verbose_failures to see the command lines of failed build steps.

https://qiita.com/r9y9/items/2e382887ee7e9fa0fb9f

対応策として、gens4でTensorflowを構築するか、該当部分のコードを消す必要があります。(今回は後者を選びました。)

https://medium.com/@mattias.arro/installing-tensorflow-1-2-from-sources-with-gpu-support-on-macos-4f2c5cab8186

(TensorflowのGitクローン先)/third_party/gpus/cuda/BUILD.tplが書き換え対象で、念のためにこのファイルのバックアップを取ったら112行目あたり(バージョンによって誤差あり)の

linkopts = [“-lgomp”]

を消して保存します。

SIPを無効にする

先述の方法でSIPを無効にします。

仮想環境を作る

ターミナルで下記のコードを使ってPythonの仮想環境を構築します。

sudo conda create -n tensor_env python=3.6.3 anaconda
source activate tensor_env
# 色々インストール
sudo pip install six numpy wheel --upgrade
# 失敗して環境を削除する場合
# sudo conda remove -n tensor_env --all

注意

仮想環境上にtensorflowをインストールしていても、ルート環境のパッケージが優先されるので、ルート環境にはTensorflowもkerasも入れないようにしましょう。
ルート環境上に構築しても良い場合は、ルート環境上で構築してください。

シンボリックリンク

エラー回避のため、いくつかのシンボリックリンクを張ります。
新しいターミナルを開いて 下記を実行。ここで使用したターミナルは閉じて構いません。

# 必ず必要っぽい
cd /usr/local/cuda/lib
sudo ln -s libcuda.dylib libcuda.1.dylib
# (ユーザ名)を適宜変更
sudo ln /Users/(ユーザ名)/anaconda3/lib/libgomp.1.dylib /usr/local/lib/libgomp.1.dylib
# シンボリックリンク解除方法
# unlink /usr/local/lib/libcuda.1.dylib
# unlink /usr/local/lib/libgomp.1.dylib

# 余談ですがCUDAのバージョン確認方法
# nvcc -V

configure

作業ディレクトリはGitのクローン上で行います。もし新しいターミナルで作業する場合はcd tensorflowsource activate tensor_env(仮想環境名)を実行し、もし、.bash_profileを変更後に再起動していなければsource ~/.bash_profileで再読込をしてから下記を実行してください。

./configure

もし、コンパイルが失敗したりした場合、下記を実行してから./configureをやり直す。

# やり直しの場合等
# https://qiita.com/tnzk/items/111a4450142fbb250b0b
bazel clean

./configureを実行すると、質問形式での入力を行うことになります。
私は下記のように実行。
その際にPlease note that each additional compute capability significantly increases your build time and binary size. [Default is: 3.5,5.2]には、GPUのCompute Capabilityを確認する。で調べておいた数値を入力。

You have bazel 0.7.0-homebrew installed.
Please specify the location of python. [Default is /Users/XXX/anaconda3/envs/tensor_env/bin/python]: 


Found possible Python library paths:
  /Users/XXX/anaconda3/envs/tensor_env/lib/python3.6/site-packages
Please input the desired Python library path to use.  Default is [/Users/XXX/anaconda3/envs/tensor_env/lib/python3.6/site-packages]

Do you wish to build TensorFlow with Google Cloud Platform support? [Y/n]: n
No Google Cloud Platform support will be enabled for TensorFlow.

Do you wish to build TensorFlow with Hadoop File System support? [Y/n]: n
No Hadoop File System support will be enabled for TensorFlow.

Do you wish to build TensorFlow with Amazon S3 File System support? [Y/n]: n
No Amazon S3 File System support will be enabled for TensorFlow.

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

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

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

Do you wish to build TensorFlow with OpenCL support? [y/N]: n
No OpenCL 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.

Please specify the CUDA SDK version you want to use, e.g. 7.0. [Leave empty to default to CUDA 8.0]: 9.0


Please specify the location where CUDA 9.0 toolkit is installed. Refer to README.md for more details. [Default is /usr/local/cuda]: 


Please specify the cuDNN version you want to use. [Leave empty to default to cuDNN 6.0]: 7


Please specify the location where cuDNN 7 library is installed. Refer to README.md for more details. [Default is /usr/local/cuda]:


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.
Please note that each additional compute capability significantly increases your build time and binary size. [Default is: 3.5,5.2]6.1


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 /usr/bin/gcc]: 


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

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


Add "--config=mkl" to your bazel command to build with MKL support.
Please note that MKL on MacOS or windows is still not supported.
If you would like to use a local MKL instead of downloading, please set the environment variable "TF_MKL_ROOT" every time before build.
Configuration finished

ビルド

大体2,3時間以上かかります。

bazel build --config=cuda --config=opt --action_env PATH --action_env LD_LIBRARY_PATH --action_env DYLD_LIBRARY_PATH //tensorflow/tools/pip_package:build_pip_package

エラーメモ

ここまででエラーが出たら下記を見直したり試したりしてみる。

  • bazel clean してから./configureのやり直し。
  • source activate (pythonの仮想環境名)でアクティベートした状態でコンパイルしてみる。
  • .bash_profileの書き換え。
  • 先述のさらにコードを書き換える。項目の内容を試してみる。
  • bazel buildコマンド内に--cxxopt="-D_GLIBCXX_USE_CXX11_ABI=0"を追記してビルド。

既にコンパイル済みのパッケージを利用する

どうしてもコンパイルが通らないという人は、前述したスレッド にコンパイル済みの環境をアップロードしている人がいるので、そちらをパッケージ化してインストールして試してみるというのも一つの手です。ただし当然ですがオフィシャルではないので利用は自己責任で。

Pythonへパッケージのインストール

setuptoolsをインストール

sudo pip install -U pip setuptools

パッケージ化

source activate tensor_env(仮想環境名)で仮想環境に入っている状態で下記を実行。

bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg

多少エラーが出ても通っていても、出力がされていればOK

パッケージのインストール

sudo pip install /tmp/tensorflow_pkg/tensorflow-1.4.1-cp36-cp36m-macosx_10_7_x86_64.whl

もしくは

# キャッシュ無効、再インストール
sudo pip --no-cache-dir install -I /tmp/tensorflow_pkg/tensorflow-1.4.1-cp36-cp36m-macosx_10_7_x86_64.whl

keras

kerasを使うのであれば、それも入れてみましょう。

pip install keras --upgrade

https://gist.github.com/smitshilu/53cf9ff0fd6cdb64cca69a7e2827ed0f

実際にkerasを使って実行したら下記のような感じで動作しました。

/Users/XXX/anaconda3/envs/tensor_env/bin/python /Users/XXX/python/projects/プロジェクト名/main.py
Using TensorFlow backend.
2017-11-27 17:40:08.986765: I tensorflow/core/platform/cpu_feature_guard.cc:137] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
2017-11-27 17:40:09.250666: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:856] OS X does not support NUMA - returning NUMA node zero
2017-11-27 17:40:09.252086: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1030] Found device 0 with properties: 
name: GeForce GTX 1060 6GB major: 6 minor: 1 memoryClockRate(GHz): 1.759
pciBusID: 0000:c3:00.0
totalMemory: 6.00GiB freeMemory: 5.49GiB
2017-11-27 17:40:09.252127: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1120] Creating TensorFlow device (/device:GPU:0) -> (device: 0, name: GeForce GTX 1060 6GB, pci bus id: 0000:c3:00.0, compute capability: 6.1)
/Users/XXX/python.py:154: UserWarning: Update your `Model` call to the Keras 2 API: `Model(inputs=Tensor("in..., outputs=Tensor("de...)`
  model = Model(input=inputs, output=predictions)
Train on 351 samples, validate on 50 samples
Epoch 1/10

  8/351 [..............................] - ETA: 3:36 - loss: 0.7039 - acc: 0.5000
 48/351 [===>..........................] - ETA: 32s - loss: 0.6816 - acc: 0.6250 
 96/351 [=======>......................] - ETA: 13s - loss: 0.6604 - acc: 0.6354
152/351 [===========>..................] - ETA: 6s - loss: 0.6430 - acc: 0.6776 
以下略

d002ltqo8mt5ipb9.png

その他参考

https://gist.github.com/ageitgey/819a51afa4613649bd18
日本語訳
http://tensorflow.hatenablog.com/entry/2015/12/31/210000
https://github.com/tensorflow/tensorflow/issues/13243
https://srikanthpagadala.github.io/notes/2016/11/07/enable-gpu-support-for-tensorflow-on-macos
http://docs.nvidia.com/cuda/cuda-installation-guide-mac-os-x/index.html
https://medium.com/@mattias.arro/installing-tensorflow-1-2-from-sources-with-gpu-support-on-macos-4f2c5cab8186