ポリリズムの提案可能技術紹介 - FlutterとYOLOv5による物体認識
はじめまして、ポリリズムのR&D部門のNです。このnoteでは、弊社が提案可能な技術の紹介をしていくようなシリーズとしていければと思っています。
第一回目は、スマートフォン(iOS)におけるリアルタイム物体検出(Object Detection)技術を紹介します。
リアルタイム物体検出とYOLO
物体検出には様々な手法がありますが、特にリアルタイム検出の文脈でポピュラーな手法としてはYOLO(You only Look Once) があります。YOLOはニューラルネットワークを用いた物体検出手法でして、特に検出スピードに優れていることで知られています。YOLOには投稿時点で、v1からv5までのバージョンが有り、v1からv4まではdarknetで実装されています。(PytorchやTensorflow実装もコミュニティベースであります)特に、YOLOの人気に火がついたのがYOLOv3で、論文の主著であるJoseph Redmonが関わった最後のYOLOとなっているようです。YOLOv3の主なiOS実装として、WWDC 2017で発表されたAppleプラットフォーム上で実行可能な機械学習フレームワークである、CoreMLにも公式実装があります。
YOLOの検出結果のイメージ画像
なお、YOLOの現在の最新版はv5(オリジナルの作者は関わっていないようです)となっており、
のPytorchによる実装があります。弊社ではdarknetの知見がないので、このPytorch実装によるYOLOv5を主に用いています。このブログでも、このあとYolov5で実装した物体検出の結果をお見せします。
iOSでYOLOv5を利用するには
iOSではTensorflowやPytorchで訓練したモデルをmlmodelというiOSで実行可能なフォーマットに変換する必要があります。その変換ツールとして、Apple公式提供のcoremltoolsがあります。
「このcoremltoolsを用いれば、何も考えずにモデルを変換して簡単にiOSで実行できる」と最初は思うのですが、なかなかにブラックボックスな技術であるため、実は結構ハマりどころがありまして、例えば、YOLOv5のバージョンが新しすぎると、coremltoolsが対応しておらず変換に失敗したり、Pytorchで実装されたレイヤーの計算が一部変換後のcoremlのネットワークグラフに入っていなかったりと、地味に原因究明に時間がかかることがあります。特にYOLOv5でもネットワークグラフから除外された計算があるため、その除外された計算をMlMutiArray(CPU)やMPSMatrix(GPU)などのAppleプラットフォーム上での行列表現クラスを用いて、iOS側(Swift)で実装する必要がありました。また、YOLOの予測結果からバウンディングボックスやクラスを取得し、NMS(Non-maximum Suppression)を用いて、画面表示するまでの処理ももちろんSwiftで実装する必要があります。今回は、ultralytics/yolov5 のdetect.pyの実装をSwiftに移植することで対応しました。(Pytorchの便利な行列計算が使えないので、ここがなかなか大変です。)
iOS側でのBoudingBoxの表示用Viewには
のTinyYOLO-CoreML/ViewController.swift を利用しました。
FlutterからCoreMLを扱う
Flutterから直接CoreMLを扱うAPIは(僕が知る限り)ないので、カメラ入力からCoreMLモデルの予測結果表示までをiOS側で行い、FlutterのMethodChannelを用いて、次の画面の「カメラ起動」を押下することで、iOS側のViewController.presentを呼び出すようにしました。(iOS Native Viewの表示がSkiaでどのように行われているかは疑問です。)次は今回実際に作成したアプリのViewを用いて、このフローを図示したものです。
よって、カメラの入力及びバウンディングボックスを表示するViewはFlutterのWidgetではなく、UIKitを用いて作られています。Flutter側でカメラViewを表示して、その入力データをMethodChannelでネイティブ側に送信し、モデルの予測結果を再度MethodChannelを用いてネイティブ側からFlutter側に送りつけるという方法も考えましたが、この送受信ではデータのコピーが行われるので、なかなかパフォーマンス上のボトルネックがあるということで、この案は廃止しました。
その他には、ネイティブ側のコードをプラグインとして提供して、UIKItViewで呼び出すといったことは割と現実的なのではないかと思います。(僕はFlutterの専門家ではないので、この辺はもっといいソリューションがあるのかもしれません。)
iOSでの実機テストの様子
まず、テストに用いたモデルですが、ナイキとアディダス、コンバースの特定のスニーカーを検出するモデルを作成しました。(yolov5s.ptを初期のウェイトとし、大量のスニーカー画像を教師データとして、スニーカーを検出するモデルを作り、そのモデルを上で述べた特定のスニーカーを検出できるようにファインチューニングしています。予測精度は検証データで90%ほどです。)
次の動画(アニGIF)が今回作成したFlutter + CoreMLのテストアプリを使ったスニーカー検出の様子です。(スニーカーは、ナイキのVapor Max FlyKnit)
このように、スニーカーの検出がうまくできていることがわかります。バウンディングボックスのサイズがやや大きいように見受けられるので、もう少し調整は必要そうですが実験はうまくいっています。
その他のスニーカーの検出
その他のスニーカーに関しては現物がないので、PCに表示したスニーカー画像から検出するということを行いました。(異なる向きやアングルから異なるスニーカーを検出してます。)
コンバース・オールスター
アディダス・スタンスミス
アディダス・オールスター
最後に
いかがでしたでしょうか。今回のテーマの詳細な実装技術に興味がある方や企業様は、office@porhy.com までお問い合わせください。その他にも、サービスの仕様策定から実際・公開までをワンストップで担当させて頂くことが可能です。機械学習システムを用いたサービスの開発をご検討中の方はご相談頂ければと思います。