会社のパソコンでM1チップ搭載のMacを使用しており、そこでObject Detection APIを動かそうとしたらx86_64とArm64の違いにより色々苦労したので、備忘録も兼ねてまとめさせていただきます。間違い等あればご指摘いただけますと幸いです。
結論
M1 Macで、Object Detection APIを動かそうと思ったら、現状Anaconda
一択。(miniforgeではなく)
- x86_64アーキテクチャ上(Rosetta2)で動かすAnacondaを使って、Tensorflowをはじめとするライブラリを、condaを使って入れる。
- または、Dockerの上にAnacondaを構築し、その上にcondaでライブラリを導入。
Tensorflowは、Arm64向けのものも出ていますが、apache-beamがArm64上ではどうしても入れられなかったためx86_64上に構築するしかなかったです。(apache-beamが依存関係にある、バージョン3.0.0以下のpyarrowに、arm対応のものが存在しないため?)
Tensorflowは、x86_64上にpipで入れた場合、「illegal...」となって動きません。また、ソースからのビルドもできる人がいたら大丈夫かもなのですが、自分の場合ビルドが最後の最後で毎回失敗してしまい、うまくいきませんでした。
前提知識
M1 Macは、armのチップを搭載していますが、x86_64のアプリケーションもRosetta2というエミュレータ上で動かせます。これに伴い、ややこしいことに、ターミナルもarmベースで動くモードとx86_64ベースで動くモードが用意されています。この切り替えには少なくとも2種類の方法があります。
1つ目が、ターミナル上でコマンドを打ってモード切り替えをする方法です。arch -x86_64 zsh
と打ち込むとx86_64モードに、arch -arm64e zsh
と打ち込むとarm64モードになります。デフォルトではarm64モードであり、現在のモードはuname -m
と打ち込むと確認できます。
2つ目が、ファインダーでアプリケーション>ユーティリティにある「ターミナル」アプリを右クリックして、情報を見るを選択、その中にある「Rosettaを使用して開く」にチェックをつける方法です。これをするとデフォルトでx86_64モードでターミナルが開けるようになります。自分はターミナルアプリを複製して、x86_64版の方を「ターミナル(Intel)」という名前で使っています。
さらに、Macの定番のパッケージマネージャーであるHomebrewにもarm64版とx86_64版があります。arm64版のパスは、/opt/homebrew/bin/brew
で、x86_64版のパスは、/usr/local/bin/brew
となっています。
両方入れた場合、brew
コマンドではarm64版のパスが優先されて実行されるので、自分はalias brew_x86=/usr/local/bin/brew
として登録し、brew_x86 install 〇〇
のような形で実行しています。
インストールの仕方の詳細は、こちらやこちらなどを参考にさせていただきました。
手順解説
Anacondaの導入
- 好きなディレクトリに移動
-
conda create -n yourEnvName python=3.6
で仮想環境を作成(python3.6でないと動かないスクリプトがあるため) -
conda activate yourEnvName
で仮想環境の中に入る
Object Detection APIの導入
6. git clone https://github.com/tensorflow/models.git
でリポジトリをクローン
7. cd models/research
8. brew install protobuf
でprotocol buffersを導入(brewはx86_64版を使う必要あり)
9. protoc object_detection/protos/*.proto --python_out=.
Google公式のGithubでは、このあとsetup.pyを実行することになっているのですが、これはpipでライブラリを入れてしまうので、先にcondaを使って手動でライブラリ追加を行います。
各種ライブラリの導入
1つずつ入れていきます。参考:Anaconda Org
10. conda install -c conda-forge apache-beam -y
11. conda install -c bioconda avro-python3 -y
12. conda install -c conda-forge pillow -y
13. conda install -c conda-forge lxml -y
14. conda install -c conda-forge matplotlib -y
16. conda install -c conda-forge contextlib2 -y
18. conda install -c conda-forge pycocotools -y
19. conda install -c conda-forge scipy -y
残る3つは、condaでは入れられなかったのでpipで入れます
20. pip install lvis
21. pip install tf-slim
22. pip install tf-models-official
tf-models-official
を入れる中で、pip版のTensorFlowが勝手に入るのですが(仮にこれ以前にconda版のTensorflowを入れていても上書きされてしまう)、これはM1チップでは動かないのでcondaで入れ直します。
23. conda install -c conda-forge tensorflow==2.4
(デフォルトだと1.14.0が入ってしまうため)
最後にこれらのライブラリ群をobject-detection-0.1
という名前でまとめるために、setup.pyを実行します。これを行わないと、cannnot find 'object-detection-0.1'...と怒られます。ちなみにこの時のパスはmodels/research
になっていることをご確認ください。
24. cp object_detection/packages/tf2/setup.py .
25. python -m pip install --use-feature=2020-resolver .
最後に、環境構築が成功しているかのテストを行います。
26. python object_detection/builders/model_builder_tf2_test.py
このテストで、無事にOK
が出れば完了です!
Anacondaに落ちつくまでの試行錯誤
それは長い道のりでした。
Tensorflowという強敵
M1 Macは、対応しているアプリケーションがほとんど揃ってきているように思っていたため、油断していました。まさかTensorflowが素直に動いてくれないとは...。
Tensorflowを動かすには、いくつかの選択肢があります。以下は、自分が手を出していった順番です。
arm64で動かす場合
- Apple謹製Tensorflow-macOSを使う
- miniforgeというArmに対応したcondaインストーラを使う
- Dockerにminiforgeを入れて使う
x86_64で動かす場合
- Tensorflowのソースからのビルド
- Rosetta2上でAnacondaを使う(本命)
- DockerにAnacondaを入れて使う
arm64での挑戦
armネイティブで構築した方がきっと計算速いよね、という考えにより、最初に手を出したのはTensorflow-macOS
でした。import tensorflowが無事に動いたときは感動したものの、Object Detection APIには他にもたくさんの手強いライブラリ達がいます。pandasやmatplotlib、scipyなどpipで直接入れられないものが次々と出てきて、撃沈しました。
次に手を出したのが、miniforge
です。tensorflowは無事に入るし、numpyやscipyなど計算系ライブラリもcondaで入り、滑り出しは良好だったものの、待ち構えていたのはapache-beamでした。まず、condaで探してもPackageNameError
を宣告されます。めげずにpipを使って入れようとすると、画面が赤い文字で埋め尽くされます。エラーを解読して色々調べると、どうやらpipのapache-beam(2.30.0)は、pyarrowのバージョン3.0.0以下に依存しているらしい。しかし肝心のpyarrowはバージョン4.0.0以上でないとarmに対応していないようで、入らないという...。
x86_64での挑戦
apache-beamやscipyを入れるには、x86_64を使うしか手がない(2021年6月時点)。そう悟ってからは、x86_64アーキテクチャにて構築する道を模索し始めました。ただ、x86_64はapache-beamをはじめとする他のライブラリには優しいのですが、Tensorflowとの相性がよくありません。そこで選択肢として浮上してきたのが、Tensorflowのソースからのビルドでした。ネット上にはそれを成し遂げた方をちらほら見かけたので、きっとできるに違いないとトライしてみたのですが、bazelでのビルドで最後の最後でエラーが出て失敗...。公式のやり方と、sedをgsedに変えて行うやり方を両方試したものの、うまくいきませんでした。ちなみにbazelではなくbazeliskをbrewでインストールしないとバージョン関連で怒られます。
万事休すかと思われたそのとき、救いの光を差し伸べてくれたのがこの記事でした。Rosetta2上でAnaconda経由でtensorflowを入れれば動く、と。
ということで、miniforgeを削除して、本家のAnacondaを入れてみたところ、ばっちり動くではないですか。そして、condaでちゃんと色々見つかる(condaのchannelが、miniforgeだとosx-arm64
(miniforge+Dockerだとlinux-aarch64
)、Anacondaだとosx-64
のため)。
その後、Docker上に構築したUbuntu+Anacondaにも入れてみましたが、無事に動きました。ただしcondaのチャンネルは、ローカルだとosx-64
ですが、Docker上だとlinux-64
なので、condaでインストールできるものが微妙に異なるようです。
まとめ
M1でもちゃんと機械学習ができる。(ただしarmのネイティブではないのでパフォーマンスの保証なし)
Anacondaが必要なのは、apache-beamやopencvなどの手強いライブラリ達を入れないとダメな場合です。
Anacondaは、環境にガッツリ根付く感じが怖いのとpipとcondaのややこしさが理解できずに今まで避けていました。PATH関係の知識が少しずつつくにつれて大丈夫感が出てきたのとcondaのありがたみを深く実感することになったので、これからもお世話になろうと思います。
-
なお、Anaconda導入後、勝手にAnacondaの仮想環境(base)に入るようになるのが嫌な人は
conda config --set auto_activate_base false
とターミナルで入力 ↩