MobileNet V1をローカルで学習してK210で分類器を動作させるチュートリアル
概要
この記事はUnit V AI Cameraや、Maixduinoなどで動作する機械学習モデルのkmodelをDockerコンテナ上でビルドして生成するチュートリアルです。この記事では、
- MobileNet V1(0.75)モデルをDockerコンテナ上で学習させ、.tfliteモデルを生成する。
- Grad-CAMでCNN(生成された.tfliteモデル)の判断根拠を可視化する
- nncaseを用いて.tfliteから.kmodelに変換する
を扱います。このチュートリアルを通して機械学習モデルを組み込み機器で動作させるための基本的な流れを学ぶことができます。
このチュートリアルはsipeed/maix_trainをベースに私独自で改変・修正したものです。私が作成した部分以外(=sipeed/maix_trainから引っ張ってきている部分)は原作のライセンス(Apache-2.0 license)が適用されます。
今回の記事のチュートリアルの動作例です。必要な用途に適しているか、大方こちらの動画で把握してください。これは本来レスキュー・メイズ競技用に開発したものですが、汎用性はかなり高いので他の用途でも動作すると思います。
この記事で詳しく扱わないこと
- 簡単なCUI操作(cd, ls, pwdなどなど…)
- Git操作
- Dockerの導入・操作
- GPUを利用した機械学習(tensorflow-gpu, tensorflow-metal等)
- チュートリアル用のリポジトリに含まれるYOLOによる物体認識
「チュートリアル用のリポジトリに含まれるYOLOによる物体認識」というのは、このチュートリアルリポジトリをクローンしたらMobileNetだけじゃなくてYOLOも一応できてしまうのですが、あまり需要がなさそうなので記事にはしませんよという意味です。(maix_trainの元ソースをみてください。ソフト屋じゃない僕でもできたので多分詳しい方ならすぐにできると思います。)
MobileNet V1とは
参照元: MobileNets: Open-Source Models for Efficient On-Device Vision
MobileNetsとはGoogleが発表したTensorFlow向けの軽量で高速な画像認識モデルのファミリーのことです。組み込み機器などの性能の制約がある端末上で動作するように設計されており、画像分類や検出などのタスクに利用することができます。
現在(2024/04/24)はMobileNetにはV3などの改良版が発表されていますが、今回は初期型のV1を用います。(まだ私の環境ではV2以降でkmodelを生成したことがないです。)
私の環境
念のため確認したいって方はこちらをご覧ください!👇
長いので折りたたみました! 見なかったことにする
PythonのバージョンやTensorFlowのバージョン等はDockerfileに従うので省略します。また、Windowsの方も、WSLで同様にこのチュートリアルを動作させられることを確認しています。
環境構築
まずこちらのリポジトリをクローンしてください。このリポジトリはApache-2.0 licenseライセンスが適用されてます。
% git clone https://github.com/shirokuma89dev/kmodel_MobileNet_Tutorial.git
% cd kmodel_MobileNet_Tutorial
次にDockerイメージをビルドして、コンテナを立ち上げます。またkmodel変換に必要なnncaseも導入します。コマンドは全てinitial_setup.shにまとめてあるので、これを走らせてください。このコマンドは初回のみ行います。
% cd maix_train
% sh initial_setup.sh
【参考】initial_setup.sh 見なかったことにする
次にDockerコンテナを立ち上げます。
% docker-compose start
% docker compose exec python3_native bash
現時点でdocker psなどを確認すると、
- python3_native
- linux_amd64
の2つが立ち上がっているはずです。
nativeは機械学習を行うコンテナで、linux_amd64はnncaseでkmodelへ変換するためのコンテナです。nncaseがlinux x86-64にしか対応していなかったので、AMD64環境(またはそれに準ずる仮想環境)が用意されることを保障するためにこのような実装になっています。
ただし、エミュレータ上で機械学習を行うのは、時間もかかり好ましくないので、機械学習はpython3_nativeのコンテナで行えます。私がネイティブのAMD64環境だったらこんなことしなくていいのですが、M2 MacBook AirはAArch64なので…。
AMD64マシンを使っている方はAMD64のコンテナが2つも立ち上がるという意味のわからないことになっていると思いますが、AArch64勢への配慮の結果だと飲み込んでください。もっとスマートな方法があった気がしてなりません…
学習
学習の章です。
作業ディレクトリ移動
ここから先はpython3_nativeコンテナ上で作業を行います!!先ほどのコマンドがうまく通っていればすでにアタッチできているはずです。
$ cd ~/maix_train
$ pwd
/root/maix_train
⚠️補足: 以降Docker内でのコマンドは上記のように$で始めて表記しますが、実際はroot@fd209255ab0b:~#のようになっていると思います。rootユーザなので本来#ですが、シンタックスハイライトの都合上#にすると全部コメント扱いされちゃうので許してください…。
学習パラメータの設定
$ python3 train.py init
init done, please edit instance/config.py
$ vi instance/config.py
# Mobilenet(分類器)
classifier_train_epochs = 40 # 分類器の訓練エポック数
classifier_train_batch_size = 5 # 分類器の訓練バッチサイズ
classifier_train_max_classes_num = 15 # 分類器の訓練で扱う最大クラス数
classifier_train_one_class_min_img_num = 40 # クラスに必要な最小画像数
(以下省略)
instance/config.pyが初期化されるので、これをいじって学習パラメータを適切に設定してください。initするときに
[WARNING] instance/config.py already exists, sure to rewrite it? [yes/no]
と聞かれたら基本yes。複数回学習をかけたりして実験する場合で、前回の学習設定を引き継ぎたいときはnoで拒否してください。
データの準備
任意の場所にimagesディレクトリを作ります。その中にラベル名(認識したい物体ごとにつける)のディレクトリを作り、その中に学習用の画像を用意します。画像のファイル名は0から連番になるようにします。(詳しい方へ: trainingとvalidationは学習の段階で自動的に分別されるので気にしなくていいです。)
🥸推論のコツ
時と場合にもよりますが、個人的には対象を分類したい場合は、「何もない」ダミー画像もひっくるめて学習させることをお勧めします!!(背景から特徴量を拾わなくなったり、似たものされど違うものを誤認識しなくなったりしました。)
データが整ったらimagesディレクトリを丸ごとzipします。.zipは任意の名前に変更してdatasetsの中に移動させておいてください。この説明がもし腑に落ちなかったら、datasets/tororo_qiitan.zipを解凍して参考にしてください。
🐿️macOS標準圧縮機能では失敗します!
なんかmacOS標準だとゴミをたくさん含んだりしてしまうみたいで、後のpythonで学習させる段階でエラーが起きてしまいました。私が普段使っている圧縮アプリのKekaではエラーは起きなかったのでこちらを推奨します。
学習
いよいよ学習です!!
$ python3 train.py -t classifier -z datasets/[zipファイルの名前].zip train
2024-05-01 18:28:28,063 - [INFO]: progress: 0%, start
2024-05-01 18:28:28,063 - [INFO]: progress: 1%, start train
2024-05-01 18:28:28,064 - [INFO]: no GPU, will use [CPU]
['qiitan', 'tororo', 'NOT_DETECTED'] ---------
(以下省略)
後は進捗状況がずっと表示されます。時々出てくるWARNINGは気にしなくていいです。(後々この関数や機能は廃止されますよーっていう警告です。エラーではなくわざわざ警告にとどめるためだけにDockerでPython 3.7にしてあげてるので気にするだけ無駄です。漢らしく警告は無視。)
終わりがけにエラーっぽい挙動をしたとしてもout内にm.tfliteが出現していれば学習は完了しているとみなして良いです。先へ進んでください。
kmodel変換
学習が終わった段階でout/result内(またはその配下)に.kmodelが出現していますか?出現しているならこの章をスキップしてください。
出現していなかったり、学習の最後にb'rosetta error: failed to open elf at /lib64/ld-linux-x86-64.so.2\n '
などのエラーが出ているなら学習は成功しているものの.kmodel変換に失敗している可能性があります。
これはkmodelに変換するためのnncaseがlinux x86-64にしか対応していないためです。これはこのチュートリアルを実行しているパソコンのアーキテクチャに依存するので各自判断してください。
まず、一回python3_nativeコンテナから脱出して
$ exit
linux_amd64コンテナに入り直します。
% docker compose exec linux_amd64 bash
次に変換コマンドを実行します。
$ /root/maix_train/tools/ncc/ncc_v0.1/ncc -i tflite -o k210model --dataset /root/maix_train/out/sample_images /root/maix_train/out/m.tflite /root/maix_train/out/result/m.kmodel
この時点でout/result内にm.kmodelが生成されていればkmodelは完成です。生成後はpython3_nativeコンテナに入り直してください。
$ exit
% docker compose exec python3_native bash
$ cd maix_train
Grad-CAMによる可視化
Grad-CAMを用いるとCNNの判断根拠を可視化することができます。つまり、画像認識モデルがどのように画像を認識しているのかをヒートマップで理解することができます。
$ python grad-cam.py
このコマンドを実行するとout内にheatmapディレクトリが作成され、その中にGrad-CAMにより可視化されたヒートマップが作成されています。このヒートマップの元となった画像はout/sample_images内のものです。
赤いところが推論結果に大きく影響したところです。これをみてモデル改良に役立ててください。
🐶シベリアンハスキー現象
ちょっと前にどこかのネット記事で見たことがある程度なので出典を示せないのが申し訳ないのですが、シベリアンハスキーと何かを分類させようとした結果、シベリアンハスキーそのものではなく背景の雪を学習して判別していたということがあったようです。これでは良いモデルとは言えませんよね。(出典をご存知の方いましたら教えてください!!)
実行
生成した.kmodelをSDカード等に入れて以下のコードを実行してください。14行目のlabelsのリストや68行目の閾値は適宜調整をしてください。本記事はkmodelを自力で作ろうのチュートリアルなので、この先は割愛します。(kmodelさえあれば後はいっぱい情報がネットの海に漂流しているのでなんとかなります。)
終わりに
このチュートリアルでは、Unit V AI CameraやMaixduinoなどで動作する機械学習モデルのkmodelをDockerコンテナ上でビルドして生成する方法を解説しました。主な手順は以下の通りです。
- MobileNet V1(0.75)モデルをDockerコンテナ上で学習させ、.tfliteモデルを生成する。
- Grad-CAMでCNN(生成された.tfliteモデル)の判断根拠を可視化する。
- nncaseを用いて.tfliteから.kmodelに変換する。
- お手持ちの組み込み用カメラにぶち込んでDone✅
誰が使うかは分かりませんが、割と簡単にできるのでぜひ試してみてください。ではまた。
🐻❄️編集後記
高専なので事情はあんまり分かりませんが、高校の情報の授業で機械学習を扱うようになったっぽいです。これからは「機械学習ができないと高校生以下😁」と年下に煽られるリスクが存在します。この前はEテレで、お姉さんが軽いノリでお団子とおはぎを機械学習で分類していました。怖いですね。オフロスキーやうーたんが機械学習する日もそう遠くないのかもしれません。
Comments