【Tensorflow2】Object DetectionでDeep写輪眼

この記事は[TensorFlow Advent Calendar 2020](https://qiita.com/advent-calendar/2020/tensorflow)の19日目の記事です。

# 2019年08月20日：Deep写輪眼V1
「[【Tensorflow】Object DetectionでDeep写輪眼](https://qiita.com/Kazuhito/items/e8d35730488278a4d4f1)」を投稿しました。
そう、__Deep写輪眼__の研究は1年以上前から始まっていたのです。

当初、印を認識するための手法として「Object Detection」と「Hand Pose Estimation」を考えました。
しかし、印の性質上、常に片方の手が、もう片方の手によるオクルージョンにさらされます。
その頃の「Hand Pose Estimation」モデルでは、隠れた手の推定は難しかったため、<br>「Object Detection」による認識に挑戦しました。

* フレームワーク：Tensorflow1系 Object Detection API
* モデル：MobileNet v2 SSD
* 学習画像：約2000枚(自分で撮影した画像＋アニメ画像)
* 印の種類：12種類(子～亥)

上記の条件で物体検出モデルを訓練しました。
その結果が以下の動画です。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">夏休みの自由研究で、NARUTOの印をObject Detection🐤<br>正直、組手をObject Detectionして、そのあと、Classificationで分類した方が良い気もする。。。🐤🐤<a href="https://t.co/K1pdBCsiau">pic.twitter.com/K1pdBCsiau</a></p>&mdash; 高橋 かずひと@孫請級プログラマー🦔 (@KzhtTkhs) <a href="https://twitter.com/KzhtTkhs/status/1163053334766354432?ref_src=twsrc%5Etfw">August 18, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


見てわかるように「子」「未」「申」の検出精度が少々低いです。
「子」「未」「申」は以下の印です。
![95611897-6d032d00-0a9d-11eb-86c4-de1c50c0d7b6.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140207/1190c061-987e-52ce-21f1-517f27b12f3a.jpeg)　![95611930-768c9500-0a9d-11eb-81c6-067b632dc43d.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140207/daa8ddb6-3006-1620-6792-cd8e66f837a1.jpeg)　![95611931-77252b80-0a9d-11eb-97d6-e3efc6f1aac3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140207/f4ca3975-246b-1402-71e5-944d254917ba.jpeg)
このままでは忍び同士の戦闘での使用に耐えません。

検出精度に不満は残るものの「Object Detection」での印認識の実現性を予感させる動きをしています。
この時点の__Deep写輪眼__を仮に「__Deep写輪眼V1__」と呼称します。特に呼び方に意味はありません。

# 2020年10月2日：Deep写輪眼V2
時は流れ、Tensorflow2のObject Detection APIがリリースされました(2020年7月11日)
EfficientDet、CenterNet、RetinaNetが新たにサポートされた強力なAPIです。
(少々怪しい挙動があったり、動かないチュートリアルがあったり、メモリ食いすぎじゃねえ？って思うことがあったり、Tensorflow-Liteへの変換がSSD系しかサポートしていなかったりしますが、強力なAPIです）

Tensorflow2 Object Detection APIの使い方を確認しつつ、<br>新たにデータセットを集め、以下条件でモデルを訓練しました。

* フレームワーク：Tensorflow2系 Object Detection API
* モデル：EfficientDet-D0
* 学習画像：約5000枚<br>(自分で撮影した画像＋アニメ画像＋[Naruto Hand Sign Dataset](https://www.kaggle.com/vikranthkanumuru/naruto-hand-sign-dataset))
* 印の種類：14種類(子～亥、壬、合掌)<br>※壬と合掌を追加することによって、NARUTO一コスパの悪い術(水遁・水龍弾の術)、<br>　NARUTO一卑劣な術(穢土転生の術)に対応可能となる見込み

結果が以下の動画です。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Deep写輪眼の現時点の完成度です🦔 <a href="https://t.co/KEyURRlZQY">pic.twitter.com/KEyURRlZQY</a></p>&mdash; 高橋 かずひと@孫請級プログラマー🦔 (@KzhtTkhs) <a href="https://twitter.com/KzhtTkhs/status/1312038931848855552?ref_src=twsrc%5Etfw">October 2, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

検出精度が改善しています。
「水遁・水龍弾の術」もあと一歩のところまで来ています。

ただし、新たに追加した「壬」が「申」と似ているため、誤検出が少々目立ちます。
グラフを後述しますが、新たに追加した「壬」と「合掌」のデータ数が少なく不均衡になっていることも要因の一つかと思います。

まだまだ改善の余地はあるものの「EfficientDet」の検出能力の高さを実感できました。
この時点の__Deep写輪眼__を仮に「__Deep写輪眼V2__」と呼称します。特に呼び方に意味はありません。

# 2020年10月10日：Deep写輪眼V2 Githubリポジトリ公開
服装や背景の色柄によっては不安定になることはありますが、多少遊べるレベルに達したと判断したため、Githubで訓練済みモデル＆サンプルプログラムを公開しました。
<a href="https://github.com/Kazuhito00/NARUTO-HandSignDetection"><img src="https://github-link-card.s3.ap-northeast-1.amazonaws.com/Kazuhito00/NARUTO-HandSignDetection.png" width="460px"></a>
![](https://user-images.githubusercontent.com/37477845/95490010-93a86180-09d2-11eb-8185-e50fd2b5c137.gif)

また、からあげさんがGoogle Colaboratoryでお手軽に試すことのできるノートブックを作成してくれました。
ありがとうございます。
ネットワークを経由するため少々の遅延はありますが、雰囲気を体感できます。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">.<a href="https://twitter.com/KzhtTkhs?ref_src=twsrc%5Etfw">@KzhtTkhs</a> さんの「Deep写輪眼」ブラウザ上で動くGoogle ColabのNotebook作ってみました。カメラ付きのPCなら、ChromeブラウザでアクセスしてクリックしていけばDeep写輪眼ができます　<a href="https://t.co/l8fpPrUH1l">https://t.co/l8fpPrUH1l</a></p>&mdash; からあげ (@karaage0703) <a href="https://twitter.com/karaage0703/status/1316047921821872128?ref_src=twsrc%5Etfw">October 13, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 利用ツール
学習モデル作成やプロトタイプは、からあげさんの「object_detection_tools」を参考にいたしました。
<a href="https://github.com/karaage0703/object_detection_tools"><img src="https://github-link-card.s3.ap-northeast-1.amazonaws.com/karaage0703/object_detection_tools.png" width="460px"></a>

# データセット
データセットは非公開です（訓練済みのモデルは公開しています）
以下の枚数を使用しています。
総枚数：6377枚(内アニメ画像：2651枚)
タグ付き枚数：4903枚
タグ無し枚数：1474枚
アノテーションボックス数：6037個
![95611950-7e4c3980-0a9d-11eb-9bcb-72888a9aaebb.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140207/188cfb59-7d73-5028-5d5a-949af60eb25a.png)

# データ拡張
学習時には以下のデータ拡張を実施しています。
　random_horizontal_flip：左右反転
　　※上下反転をすると「巳」と「亥」を混同するためvertical_flipは未指定
　random_rgb_to_gray：グレースケール
　random_adjust_brightness：明度変更
　random_adjust_contrast：コントラスト変更
　random_adjust_hue：色相変更
　random_adjust_saturation：彩度変更
　random_distort_color：明度、コントラスト、色相、彩度の変更をランダムに適用
　random_black_patches：黒点付与
　random_crop_image：画像切り抜き
　random_absolute_pad_image：パディング付与
　random_self_concat_image：同画像の連結
　random_scale_crop_and_pad_to_square：ランダムスケールクロップ

# 公開モデル
以下のモデルをリポジトリにて公開しています。

* EfficientDet D0
* MobileNetV2 SSD FPNLite 640x640
* MobileNetV2 SSD FPNLite 640x640(TensorFlow Liteモデル)
* MobileNetV2 SSD 300x300

# おわりに
昨年作成したDeep写輪眼V1に比べて大分精度が向上しました。<br>（MobileNetv2-SSDとEfficientDet-D0では当然と言えば当然ですが）
今後はTensorflow-Lite化してスマートグラスに載せたり、より良いモデルが出たら、そちらで再訓練したいと思っています。

次は、12/20：tonouchi510様の「tf2での開発の個人的ベストプラクティスを書こうと思います。」です。