ANN ライブラリの Annoy で build index する時に Illegal Instruction Error が発生した

· 6min · Masataka Kashiwagi

Annoy という Spotify が開発している Python 製の ANN (Approximate Nearest Neighbors) のライブラリがあり,それを使ってレコメンドアイテムの類似度を計算する機会があったのだが,コンテナ化したものを Vertex AI Pipelines 上で動かしていたところ,Fatal Python error: Illegal instruction というエラーが発生して困っていたので,今回はこのエラーの対処方法について書いていく.

※ Annoy については,こちらの ZOZO さんの記事が詳しく解説してくれているので,ここでは説明は割愛する.

docker build 時の環境による問題?

発生した事象

Annoy のライブラリを含んだ Docker イメージを作り,それを元に作成したコンポーネントを機械学習パイプラインである Vertex AI Pipelines で動かしたところ,Fatal Python error: Illegal instruction というエラーが発生した.これは具体的には,AnnoyIndex を構築する際に発生している.

※ Annoy を含む Python ライブラリは poetry で管理し,Dockerfile 内で poetry install している.

エラー原因

今回の問題は,Docker コンテナのイメージをビルドする時に指定するオプションが原因だった.

ローカル環境は Apple M1 Max (ARM アーキテクチャ) で開発していたため,イメージ作成時に以下のオプションを指定してビルドしていた.

docker build --platform linux/amd64 -t sample-recsys:latest -f ./Dockerfile .

AMD 環境でも動くように --platform フラグにターゲットプラットフォームである linux/amd64 を指定してビルドしていた.このビルドしたイメージを GCP の Artifact Registry にプッシュし,そのイメージを使って Vertex AI Pipelines で各コンポーネントの検証を行っていた.

一方で,--platform フラグを付けずに M1 Mac からビルドしたイメージを使った場合には,exec format error というエラーが発生する.

検証時には,ローカル環境から直接イメージをビルド & プッシュし,そのイメージを使ったコンポーネントを Vertex AI Pipelines 上で動かして検証を行っていた.その際に使用していたスクリプトをそのまま GitHub Actions での CI/CD 構築時に使用したことで,今回の Fatal Python error: Illegal instruction という事象が発生することになる.

Illegal instruction というエラーが発生するという事象はいくつか Issue が上がっていた.

--platform フラグを付けてイメージをビルドしても問題ないライブラリも多数あるが,Annoy では linux/amd64 を指定したのを GitHub Actions の Runner (ubuntu-latest) で動かしたのがどうも上手く行かなかったみたい...

解決方法

僕の例では,Initializing an AnnoyIndex crashes on AMD processors #472 の Issue に記載されている方法で解決することができた.

Annoy のライブラリをインストールする際に,コンパイルパラメータである ANNOY_COMPILER_ARGS を Dockerfile 内に環境変数として指定することで解決できる.annoy/setup.py を見ると良いかもしれない.

ENV ANNOY_COMPILER_ARGS -D_CRT_SECURE_NO_WARNINGS,-DANNOYLIB_MULTITHREADED_BUILD,-mtune=native

この環境変数を Dockerfile にセットすると,--platformlinux/amd64 を付け Docker イメージを GitHub Actions 経由でビルドしたものを Vertex AI Pipelines で使用しても,エラー無く処理が完了した.

あとは,そもそもこれはローカルの M1 Mac と GitHub Actions の両方で同一のスクリプトを使用したいが為に行っている対応策なので,スクリプトを別々にすれば,GitHub Actions でビルドする際には,上記の ANNOY_COMPILER_ARGS を設定することなく,シンプルに以下のビルドコマンドだけでいける.

docker build -t sample-recsys:latest -f ./Dockerfile .

また,,--platform のオプションを付けてビルドすると時間が余計にかかるので,無駄なものは付けない方が良さそうに思う.


今回は思いもよらないエラーで悩んでいたので,こうして無事?エラーの原因と解決策が分かって良かった.全然このことに気づかなかったので,Annoy をやめて Faiss を使用することも考えたりしていた.

コンテナイメージをビルドする際のローカルとプロダクション適用時のマシンスペックが違うことも考えた上で,再現性を意識したコードを書かなければと改めて感じたので,良い教訓となった.


このエントリーをはてなブックマークに追加

ブログ記事を読んで頂き,ありがとうございます!もしこの記事が良かったり参考になったら,「Buy me a coffee」ボタンから☕一杯をサポートして頂けるとモチベーションが上がります!どうぞよろしくお願いします🤩