LoginSignup
77
49

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

Last updated at Posted at 2018-06-18

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 (今北産業)

  1. ノープロブレム。無視しても大丈夫です。
  2. pip でインストールした tensorflow のバイナリが、現在の CPU に最適化されたものではなく汎用(安定版)のバイナリを使っているというワーニングです。
  3. 気になる人はワーニングを非表示にするか、ソースからコンパイルし直します。

このメッセージは、次のように 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?

2018 年の 6 月ごろの話しです。「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 が?」と意味がわかりませんでした。

わかりづらいのですが、"support instructions"は「指示をサポート」ではなく「命令に対応」の意味で使われています。

つまり、"Your CPU support instructions that ..." は「あなたの CPU は、次の CPU 命令をサポート(対応)してます」という意味です。"Your CPU supports instructions for ..." であればわかりやすいのに。

その上で、「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 を実行するのに必要な命令を拡張した「命令セットの呼称」とのこと。

意味がわからないので、さらに調べてみると SIMD とは「1つの命令でベクトルの計算処理を複数のデータにわけて並列で処理するタイプの演算方式」のようです。これを実現するために集めた関数やメソッドのライブラリが AVX のようです。

この AVX により、あれこれと低レベルの CPU 命令を組み合わせて計算していたものが少ない命令で実行できる、ということのようです。つまり「AVX に対応していたら速くなるぞ」と。「○△□」と打っていたものが「×」で同じことができる、みたいなものでしょうか。

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

ベクトルとは

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

おそらく、この用語ベクトルが機械学習の勉強の最初の妨げになっている気がします。

まず、「ベクター」と「ベクトル」もどちらも vector です。「ピザ」と「ピッツァ」の違いみたいなものらしいです。

恐れずに言うと、機械学習におけるベクトルとは数値だけで構成された配列データのことです。そう例のアレarrayです。単純に。

JSONのベクトル例1
[
  [ 1, 2, 3 ], // ← これがベクトル。そして機械学習用の 1 データ
  [ 4, 5, 6 ], // ← これがベクトル。そして機械学習用の 1 データ
  ...          // 以下同文
]

普通の配列と何が違うかというと、以下の 3 つの条件を網羅していると機械学習の世界では「ベクトル」と呼ぶのです。

  1. 数値だけで構成されている
  2. 特定の方向に並んで(ソートされて)いる
  3. 各値が量を表している

ここで言う「特定の方向」とは、例えば登録順や時間順といったことです。つまり「並び順に意味を持っているもの」です。

次に「各値が量を表している」とは、機械学習の用語で「スカラー」のことです。ゆうて、数値のことです。

数値なのに「スカラー」と名前が付いているのは、我々の世界でいう「型」のようなものです。同じ「12」でも「int(12)」「int64(12)」「float32(12)」では異なるように、一見同じ数値でも性質が違うから名前が付いている(型がある)のです。

「12」だと、ただの整数なのですが「座標の 12」と言われた時点で「0 から 12 移動した量」という意味を持ちます。つまり大きさを表すことになります。

このことからベクトルの各値のことを、大きさを測る「スケール(scale)」と同じ語源の、大きさを示す「スカラー(scalar)」と呼びます。

つまり「スカラー」の集合体を「ベクトル」と呼んでいると考えていいでしょう。

そして、プログラムの世界で言う「多次元配列」にしたものを、機械学習の世界では「テンソル」と呼ぶのです。

テンソルとは、伸びたり縮んだりする筋肉の「張筋」の英語である tensor が語源です。機械学習では、配列を多次元配列化(収縮)させた後、元に戻した(展開させた)時に同じ結果になるかを繰り返して精度を上げていくので、筋肉の伸び縮みと見立てた名前が付いているのです。

  • 「数値」→「配列」→「多次元配列」
  • 「スカラー」→「ベクトル」→「テンソル」

「んだら、ベクトルとかテンソルとか、小難しい名前を使わないで配列や多次元配列でいいじゃん」と思うかもしれません。

それは、コンパイル型のプログラム言語などで「型々うるさい」と感じるのと似ています。「int(12) とか float32(12) とか宣言しなくても、ぜんぶ 12 でいいじゃん。流れをみて理解しろよ」と。

「型」が大事な理由は、処理速度です。その変数の型(値の種類)が「予めわかっている」のと、「使ってみないとわからない」とでは、予め用意できるメモリ領域や最適化の方法が異なるため、処理速度に大きく影響します。

数学の世界でも、「X」と書かれても「これが数値なのか配列なのかわからん」という状況があります。長ったらしい計算式を最初から読み直すのは大変なので、数学の世界では「𝕏」と書かれた場合は配列型(ベクトル)として扱う、といった型が決まっています。

つまり、同じもの同士が迅速に意思疎通し、正確に伝えるために「型」というものが存在します。

そのため、機械学習を勉強していて小難しい専門用語が出てきても、「上から目線」と捉えずに、ライトノベルで魔法を詠唱しているくらいに考えた方が楽しいです。

「(あ、厨二病が発症したんだな)」と。

しかも、すごいことに、我慢強く詠唱を理解しようとすれば、自分でも使えるようになるのですから。

機械学習用のデータの作り方

例えば、下記のような測定データと判定結果をまとめたデータがあったとします。hogepiyo が測定値で、result がその結果です。

[
  { "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 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 のバイナリが対応していないのでメッセージで教えてくれた、という流れのようです。

サポートしている命令一覧に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 は機種によって大きく異なります。しかも 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'
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

参考文献

77
49
1

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
77
49