Edited at

macOS で「this TensorFlow binary was not compiled to use: AVX2 FMA」エラー

Python3 + tensorflow で tf.Session() を実行するとワーニングが表示される。


2018-06-18 13:51:51.762563: I tensorflow/core/platform/cpu_feature_guard.cc:140] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA



TL;DR

ノープロブレム。無視しても大丈夫です。

これは、次のように pip 経由で TensorFlow のバイナリをインストールしている場合に表示されるメッセージです。

$ pip install tensorflow

エラー(警告)の意味は以下になります。


  1. 「GPU を使わず CPU を使う」

  2. 「CPU は AVX2 + FMA に対応しているが、この tensorflow のバイナリでは使えないなり」

TensorFlow は AVX2 の代わりに AVX を使うので(速度や精度が気にならなければ)スルーしても大丈夫です。メッセージ内容や AVX FMA の詳細については以下の TS;DR をご覧ください。

なお、警告レベルを変えるとワーニングは表示されなくなるので、表示が気になる場合は TF_CPP_MIN_LOG_LEVEL の値を '2' に設定してください。


>>> import os
>>> os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

注意:上記設定で警告レベルを変えても AVX2 FMA とやらは使われません。それらを使いたい場合は、別途 TensorFlow をコンパイルする必要あります。


TS;DR (Hello? TensorFlow?)

Python3 TensorFlow for Mac 環境構築」の Qiita 記事を読みながら Hello World 写経をしていたのですが、途中 tensorflow ライブラリの session クラスtf.Session())を使うところでエラーメッセージが表示されました。


HelloWorld

$ python

Python 3.6.0 (default, Jun 18 2018, 13:35:26)
[GCC 4.2.1 Compatible Apple LLVM 10.0.0 (clang-1000.10.25.5)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> import tensorflow as tf
>>>
>>> hello = tf.constant('Hello, TensorFlow!')
>>> sess = tf.Session()
2018-06-18 13:51:51.762563: I tensorflow/core/platform/cpu_feature_guard.cc:140] Your CPU
supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
>>>
>>> print(sess.run(hello))
b'Hello, TensorFlow!'
>>>
>>> exit();

しかし「b'Hello, TensorFlow!'」と、何故か b と OK(👌)をもらいながらも "Hello world" は動いたことは動いたので、エラーでなくワーニング(警告)のようです。

ただ、そのメッセージ内容が「なんか違うバイナリ使ってね?」っぽい内容なので気になりました。


Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA

🐒訳)このコンパイル済み TensorFlow のバイナリでは利用できない次の命令を、あなたの CPU はサポートしています:AVX2 FMA


最初メッセージを読んだ時、"support instructions" とあるので「なに?指示をサポート?CPUが?」と、わかりづらかったのですが、「指示をサポート」ではなく「命令をサポート」の意味で使われています。

"Your CPU support instructions that ..." は「あなたの CPU は(次の)CPU 命令をサポートしてます」という意味です。

その上で AVX2FMA とやらが使えるのに「バイナリが使えるようにコンパイルされてないよ」と警告してくれているのです。

よって「貴殿のCPU はAVX2 FMA に対応しているなり」と言うことと「現在ご利用中の TensorFlow バイナリは AVX2 FMA 非サポート版なり」と言うことのようです。

TensorFlow 公式の Issue にもあがっていました。


This isn't an error, just warnings saying if you build TensorFlow from source it can be faster on your machine.

TensorFlow 公式リポジトリ Issue #8037 @ GitHub より)

訳) こんたエラーじゃらせん。 TensorFlow をソースからビルドすっと速う動作すっよと注意してくれちょっだけじゃ。


では AVX2 でなくデフォルトで AVX で動くのに、なぜわざわざ警告してくれているのでしょうか?


AVX(Advanced Vector Extension)とは

気になったので「AVX とは何なのか」と調べてみたところ、Intelx86 系 AMD のプロセッサで使えるベクトル演算(SIMD)に必要な命令を拡張した「命令セットの呼称」とのこと。

ベクトル演算とは、1つの命令で処理を複数のデータにわけ並列で処理するタイプの演算方式らしく、AVX により、あれこれと低レベルの CPU 命令を組み合わせて計算していたものが少ない命令で実行できる、ということのようです。

つまり「AVX に対応していたら速くなるぞ」と。「○△□」と打っていたものが「×」で同じことができる、みたいなものでしょうか。

ちなみに「ベクトル」とは「ソートされた数値だけの配列のこと」です。


ベクトルとは

ベクトルと聞いて「sin cos とか使ったり、矢印とか引いちゃったりするアレでしょ?」とか、デザイナーだと「フォトショじゃなくイラレのタイプのアレでしょ?」とか思うかもしれません。

おそらく、この用語が機械学習の勉強の一番の妨げになっている気がします。

機械学習におけるベクトルとは数値だけの配列データのことです。単純に。

例えば、下記のような測定データと判定結果(hogepiyoresult)をまとめたデータがあったとします。

{

[ "hoge": 123, "fuga": 456, "piyo": 789, "result": "ok" ],
[ "hoge": 987, "fuga": 654, "piyo": 321, "result": "ng" ],
...
}

このデータを、機械学習用のデータに変換したい場合は以下のステップで可能です。


  1. 値が文字列である場合は、数値の ID に置き換える。

  2. CSV 形式に変換する。

  3. 測定データ以外に判定結果(答え)のデータもある場合は2つにわける

  4. ヘッダー行を削除し、配列に変換する。

まず、文字列には ID を振り数値に置き換えます。ここでは文字列 "ok" を数値の 1、"ng" を 0 としました。

{

[ "hoge": 123, "fuga": 456, "piyo": 789, "result": 1 ],
[ "hoge": 987, "fuga": 654, "piyo": 321, "result": 0 ],
...
}

次に CSV 形式に変換し、測定データと判定結果のデータをわけます。

hoge
fuga
piyo

123
456
789

987
654
321

...
...
...

result

1

0

...

最後に、CSV からヘッダー行を取り除き、以下のように数値だけの配列になったものを機械学習では「ベクトル」と呼んでいます。また、ベクトルのうち判定結果のデータを「教師データ」と呼びます。

# 測定データ(data)

x={
[ 123, 456, 789 ],
[ 987, 654, 321 ],
...
}
# 判定結果(target)
y={
[ 1 ],
[ 0 ],
...
}

「ベクトル、ベクトル」と言われると、for ループの足し算を「Σ(シグマ)」で表現されるようなビビり感があります。単純に時間順だったり登録順だったり、「特定の方向にソートされた、連続した数値の集まり」を「ベクトル」と呼んでいるのです。

逆に言えば、ベクトルは数値だけの配列なので並列処理もしやすいのです。そのため、AVX もしくは AVX2 といった CPU/GPU レベルの並列処理の実装が効果を出すとも言えます。


🐒 機械学習の業界は、同業者間(わかっている人同士)では伝える時に長ったらしくならないように、数学ベースの機械学習プロトコルで会話しています。素人でアウェイの私には小難しく感じるのですが「Goに入ってはGoに従え」と言うようにプロトコルを合わせる以前に理解するのが大変。



Word2Vec もそうですが、昨今の機械学習はベクトルの計算をしまくっています。こういった CPU/GPU 命令レベルの差が最終的な速度に大きく影響を与えるため、実行ファイルが CPU/GPU の「どの拡張命令をサポートしているか」は重要な要素なのだと思われます。

そして問題の「AVX2」は AVX の後継で、整数演算命令が 128 ビットから倍の 256 ビットに拡張されたものです。つまり、1 回の処理で扱えるデータ量が増えたぶんAVX2 に対応していたら早く処理が終わるぞ、と。Intel は Haswell、AMD は Excavator 以降のプロセッサから AVX2 が使えるようになっているらしいです。

おいどんの MacBookPro は Early 2015 の 2.7 GHz Intel Core i5(5257U) なので記憶が正しければ Haswell の次の Broadwell なはず。となると AVX2 とやらも使えるはずなのですが、肝心の TensorFlow のバイナリが対応していないのでメッセージで教えてくれた、という流れのようです。


FMA,AVX,AVX2がいる([]は筆者)

$ sysctl -a machdep.cpu | grep features

machdep.cpu.features: FPU VME DE PSE TSC MSR PAE MCE CX8 APIC SEP MTRR PGE MCA CMOV PAT PSE36
CLFSH DS ACPI MMX FXSR SSE SSE2 SS HTT TM PBE SSE3 PCLMULQDQ DTES64 MON DSCPL VMX EST TM2
SSSE3 [FMA] CX16 TPR PDCM SSE4.1 SSE4.2 x2APIC MOVBE POPCNT AES PCID XSAVE OSXSAVE SEGLIM64
TSCTMR [AVX1.0] RDRAND F16C
machdep.cpu.leaf7_features: RDWRFSGS TSC_THREAD_OFFSET BMI1 [AVX2] SMEP BMI2 ERMS INVPCID
FPU_CSDS RDSEED ADX SMAP IPT MDCLEAR IBRS STIBP L1DF SSBD
machdep.cpu.extfeatures: SYSCALL XD 1GBPAGE EM64T LAHF LZCNT PREFETCHW RDTSCP TSCI

大抵の GPU はそもそも SIMD(ベクトル演算) で動いているのですが、Mac の GPU は機種によって大きく異なります。そのため pip で TensorFlow をどの環境でも動くようにするために、GPU でなく CPU、かつ最低限共通する Intel CPU の仕様に対応させたのだと思われます。

つまり、pip を使わずに手動で TensorFlow をコンパイル(ソースからビルド)してインストールすればワーニングは表示されないし、速度も速くなる、と。

しかし、どの写経も pip install を前提にしているものが多く、いまの初級のおいどんには速度よりも実際に触れることが優先 アップデートも楽 なので、とりあえず動けばいいためメッセージは無視することにしました、とさ。

でも、「お客さ〜ん」と毎回言われるのが気になる時は、実行クラスを呼び出す前に、以下のように環境設定を変更して警告レベルを下げると表示を回避できます


警告レベルを下げる例

import os

os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'


HelloWorldのワーニングなし

$ python

Python 3.6.0 (default, Jun 18 2018, 13:35:26)
[GCC 4.2.1 Compatible Apple LLVM 10.0.0 (clang-1000.10.25.5)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> import os
>>> import tensorflow as tf
>>>
>>> os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
>>>
>>> hello = tf.constant('Hello, TensorFlow!')
>>> sess = tf.Session()
>>>
>>> print(sess.run(hello))
b'Hello, TensorFlow!'
>>>
>>> exit()

:ok_hand: Hello TensorFlow! よろしくね


FMA(fused multiply–add, 融合積和演算

FMA も気になったので、ついでに調べてみました。

簡単に言うと「乗算の最終的な誤差を小さくするための命令」です。つまり、掛け算の和を計算する時の Float(浮動小数点数)の値を途中で丸めずに1つの命令で行うのが特徴で、先の AVX2 の命令セットに実装されているものらしいです。つまり、CPU とバイナリが FMA に対応していたら精度が上がるぞということですな。


TensorFlow のコンパイル

使い方も消化したし、バージョンアップのたびにコンパイるのも大丈夫という方はこちら。


検証環境


  • macOS HighSierra (OSX 10.13.5)


  • python --version: 3.6.0


  • pyenv --version: 1.2.4


  • pip3 list | grep tensorflow: tensorflow 1.8.0



参考文献