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 のバイナリが、現在の CPU に最適化されたものではなく汎用(安定版)のバイナリを使っているというワーニングです。 - 気になる人はワーニングを非表示にするか、ソースからコンパイルし直します。
このメッセージは、次のように pip
経由で TensorFlow のバイナリをインストールしている場合に表示されるメッセージです。
$ pip install tensorflow
エラー(警告)の意味は以下になります。
- 「GPU を使わず CPU を使う」
- 「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 をコンパイルする必要あります。
- 「Build from source | Install」@ tensorflow.org
- Qiita 記事の「{Mac macOS} TensorFlow ビルド ソース コンパイル」の検索結果 @ Google(直近1年以内の更新・作成絞り)
TS; DR (ワーニング内容を完全に理解した気になるコマケーこと)
Hello? TensorFlow?
2018 年の 6 月ごろの話しです。「Python3 TensorFlow for Mac 環境構築」の Qiita 記事を読みながら Hello World 写経をしていたのですが、途中 tensorflow ライブラリの session
クラス(tf.Session()
)を使うところでエラーメッセージが表示されました。
$ 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 が?」と意味がわかりませんでした。
わかりづらいのですが、"support instructions
"は「指示をサポート」ではなく「命令に対応」の意味で使われています。
つまり、"Your CPU support instructions that ...
" は「あなたの CPU は、次の CPU 命令をサポート(対応)してます」という意味です。"Your CPU supports instructions for ...
" であればわかりやすいのに。
その上で、「AVX2
や FMA
とやらが使えるのに、使えるようにコンパイルされてないよ」と警告してくれているのです。
よって「貴殿の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
とは何なのか」と調べてみたところ、Intel や x86 系 AMD のプロセッサで使える SIMD を実行するのに必要な命令を拡張した「命令セットの呼称」とのこと。
意味がわからないので、さらに調べてみると SIMD とは「1つの命令でベクトルの計算処理を複数のデータにわけて並列で処理するタイプの演算方式」のようです。これを実現するために集めた関数やメソッドのライブラリが AVX のようです。
この AVX により、あれこれと低レベルの CPU 命令を組み合わせて計算していたものが少ない命令で実行できる、ということのようです。つまり「AVX
に対応していたら速くなるぞ」と。「○△□」と打っていたものが「×」で同じことができる、みたいなものでしょうか。
ちなみに「ベクトル」とは「ソートされた数値だけの配列のこと」です。
ベクトルとは
ベクトルと聞いて「sin
cos
とか使ったり、矢印とか引いちゃったりするアレでしょ?」とか、デザイナーだと「フォトショじゃなくイラレのタイプのアレでしょ?」とか思うかもしれません。
おそらく、この用語が機械学習の勉強の最初の妨げになっている気がします。
まず、「ベクター」と「ベクトル」もどちらも vector
です。「ピザ」と「ピッツァ」の違いみたいなものらしいです。
恐れずに言うと、機械学習におけるベクトルとは数値だけで構成された配列データのことです。そう例のアレです。単純に。
[
[ 1, 2, 3 ], // ← これがベクトル。そして機械学習用の 1 データ
[ 4, 5, 6 ], // ← これがベクトル。そして機械学習用の 1 データ
... // 以下同文
]
普通の配列と何が違うかというと、以下の 3 つの条件を網羅していると機械学習の世界では「ベクトル」と呼ぶのです。
- 数値だけで構成されている
- 特定の方向に並んで(ソートされて)いる
- 各値が量を表している
ここで言う「特定の方向」とは、例えば登録順や時間順といったことです。つまり「並び順に意味を持っているもの」です。
次に「各値が量を表している」とは、機械学習の用語で「スカラー」のことです。ゆうて、数値のことです。
数値なのに「スカラー」と名前が付いているのは、我々の世界でいう「型」のようなものです。同じ「12」でも「int(12)
」「int64(12)
」「float32(12)
」では異なるように、一見同じ数値でも性質が違うから名前が付いている(型がある)のです。
「12」だと、ただの整数なのですが「座標の 12」と言われた時点で「0 から 12 移動した量」という意味を持ちます。つまり大きさを表すことになります。
このことからベクトルの各値のことを、大きさを測る「スケール(scale
)」と同じ語源の、大きさを示す「スカラー(scalar
)」と呼びます。
つまり「スカラー」の集合体を「ベクトル」と呼んでいると考えていいでしょう。
そして、プログラムの世界で言う「多次元配列」にしたものを、機械学習の世界では「テンソル」と呼ぶのです。
テンソルとは、伸びたり縮んだりする筋肉の「張筋」の英語である tensor
が語源です。機械学習では、配列を多次元配列化(収縮)させた後、元に戻した(展開させた)時に同じ結果になるかを繰り返して精度を上げていくので、筋肉の伸び縮みと見立てた名前が付いているのです。
- 「数値」→「配列」→「多次元配列」
- 「スカラー」→「ベクトル」→「テンソル」
「んだら、ベクトルとかテンソルとか、小難しい名前を使わないで配列や多次元配列でいいじゃん」と思うかもしれません。
それは、コンパイル型のプログラム言語などで「型々うるさい」と感じるのと似ています。「int(12)
とか float32(12)
とか宣言しなくても、ぜんぶ 12
でいいじゃん。流れをみて理解しろよ」と。
「型」が大事な理由は、処理速度です。その変数の型(値の種類)が「予めわかっている」のと、「使ってみないとわからない」とでは、予め用意できるメモリ領域や最適化の方法が異なるため、処理速度に大きく影響します。
数学の世界でも、「X」と書かれても「これが数値なのか配列なのかわからん」という状況があります。長ったらしい計算式を最初から読み直すのは大変なので、数学の世界では「𝕏」と書かれた場合は配列型(ベクトル)として扱う、といった型が決まっています。
つまり、同じもの同士が迅速に意思疎通し、正確に伝えるために「型」というものが存在します。
そのため、機械学習を勉強していて小難しい専門用語が出てきても、「上から目線」と捉えずに、ライトノベルで魔法を詠唱しているくらいに考えた方が楽しいです。
「(あ、厨二病が発症したんだな)」と。
しかも、すごいことに、我慢強く詠唱を理解しようとすれば、自分でも使えるようになるのですから。
機械学習用のデータの作り方
例えば、下記のような測定データと判定結果をまとめたデータがあったとします。hoge
〜piyo
が測定値で、result
がその結果です。
[
{ "hoge": 123, "fuga": 456, "piyo": 789, "result": "ok" },
{ "hoge": 987, "fuga": 654, "piyo": 321, "result": "ng" },
...
]
このデータを、機械学習用のデータに変換したい場合は以下のステップで可能です。
- 値が文字列である場合は、数値の ID に置き換える。
- CSV 形式に変換する。
- 測定データ以外に判定結果(答え)のデータもある場合は2つにわける
- ヘッダー行を削除し、配列に変換する。
まず、文字列には 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 | result |
---|---|---|---|
123 | 456 | 789 | 1 |
987 | 654 | 321 | 0 |
... | ... | ... | ... |
上記は、以下と同じと思ってください。
"hoge","fuga","piyo","result"
123,456,789,1
987,654,321,0
...
次に、このデータを「測定データ」と「判定結果」」にわけます。
hoge | fuga | piyo |
---|---|---|
123 | 456 | 789 |
987 | 654 | 321 |
... | ... | ... |
result |
---|
1 |
0 |
... |
最後に、CSV からヘッダー行を取り除き、以下のように数値だけの配列になったもの(ベクトルが並んだもの)を機械学習では「学習データ」と呼んでいます。また、ベクトルのうち判定結果のデータを「教師データ」と呼びます。
# 測定データ = 学習データ (train data)
x=[
[ 123, 456, 789 ],
[ 987, 654, 321 ],
...
]
# 判定結果 = 教師データ (target data)
y=[
[ 1 ],
[ 0 ],
...
]
「ベクトル、ベクトル」と言われると、for
ループの足し算を「Σ(シグマ)」で表現されるようなビビり感があります。
単純に時間順だったり登録順だったり、「特定の方向にソートされた、連続した数値の集まり」を「ベクトル」と呼んでいるのです。
逆に言えば、ベクトルは数値だけの配列なので並列処理もしやすいのです。そのため、AVX もしくは AVX2 といった CPU/GPU レベルの並列処理の実装が効果を出すとも言えます。
🐒 機械学習の業界も、同業者間(わかっている人同士)では、伝える時に長ったらしくならないように、数学ベースの機械学習プロトコルで会話しています。素人でアウェイの私には小難しく感じるのですが「Go に入っては Go に従え」と言う IT 業界のことわざのようにプロトコルを合わせる必要があります。しかし、ルール以前に用語に付いて行くのがたいへん。
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 のバイナリが対応していないのでメッセージで教えてくれた、という流れのようです。
$ 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 は機種によって大きく異なります。しかも Windows や Linux などの DOS/V 互換機と違い、おいそれと GPU の交換ができません。
そのため TensorFlow を、どの環境でも pip
で動くようにするためには、GPU でなく CPU、かつ最低限共通する Intel CPU の仕様に対応させたのだと思われます。
つまり、pip
を使わずに手動で TensorFlow をコンパイル(ソースからビルド)してインストールすればワーニングは表示されないし、速度も速くなる、と。
しかし、どの写経も pip install
を前提にしているものが多く、いまの初級のおいどんには速度よりも実際に触れることが優先 アップデートも楽 なので、とりあえず動けばいいためメッセージは無視することにしました、とさ。
でも、「お客さ〜ん」と毎回言われるのが気になる時は、実行クラスを呼び出す前に、以下のように環境設定を変更して警告レベルを下げると表示を回避できます。
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
$ 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()
Hello TensorFlow! よろしくね
FMA(fused multiply–add, 融合積和演算)
FMA も気になったので、ついでに調べてみました。
簡単に言うと「乗算の最終的な誤差を小さくするための命令」です。つまり、掛け算の和を計算する時の Float(浮動小数点数)の値を途中で丸めずに1つの命令で行うのが特徴で、先の AVX2 の命令セットに実装されているものらしいです。つまり、CPU とバイナリが FMA
に対応していたら精度が上がるぞということですな。
TensorFlow のコンパイル
使い方も消化したし、バージョンアップのたびに疲労コンパイるのも大丈夫という方はこちら。
- 「Build from source | Install」@ tensorflow.org
- 「TensorFlow ビルド ソース コンパイル」の検索結果 @ Qiita @ Google
検証環境
- macOS HighSierra (OSX 10.13.5)
-
python --version
: 3.6.0 -
pyenv --version
: 1.2.4 -
pip3 list | grep tensorflow
: tensorflow 1.8.0
参考文献
- Issue #8037「How to compile tensorflow using SSE4.1, SSE4.2, and AVX.」@ TensorFlow @ GitHub
- 「Python3 TensorFlow for Mac 環境構築」@ Qiita
- 「Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX AVX2」@ StackOverflow
- 「Tensorflowの関数理解」@ Qiita