Yoloモデルをtfliteモデルへ変換する際に、オプション等によりフォーマットが変化し
・入出力のfloat/int
・入力の並び(NCHW/NHWC)
・出力の並び(No-NMS/NMS)
・出力座標の正規化
等の違いが発生します。このフォーマットと推論(物体検出)プログラムの設定が一致
していないと推論が正しく動作しません。同じモデルを同じライブラリで変換した
場合でも設定次第でフォーマットが変わるので、同じtfliteを使用しているのに今まで
動いていたプログラムが動かなくなるということになります。
このフォーマットの違いについて整理します。
なお、各モデルの内部情報は
Netronというサイトで確認することができます。
入出力の float / int
これは比較的判断しやすい内容です。
基本的にユーザーが指定して量子化(int化)しない限りはfloatの場合が多いと思います。
これはロードしたモデルの入出力の要素タイプを確認することで判定できます。
入力テンソルの並び順
変換に使用するプログラム等で変わることがあります。
NCHWとNHWCの2つが主流な様です。
N:バッチサイズ(1回での処理枚数)
C:チャンネル数(RGB:3、グレースケール:1等)
H:画像の高さ
W:画像の幅
NCHWの例 [ 1 , 3 , 320 , 320 ]
NHWCの例 [ 1 , 320 , 320 , 3 ]
推論に使用する画像データはこの順番に合わせて並び替えて入力する必要があります。
データ2 <= 3 → NCHW
データ3 <= 3 → NHWC
等と判定することができます。
出力テンソルの並び順
これは主にNMS(Non Maximum Suppression:重なりの除去機能)を適用した
場合に変わります。また、ダイナミック量子化を適用するとNMS仕様になる
ことがある様です。
No-NMSの例 [ 1 , 7 , 2100 ]
データ1:1 バッチサイズ
データ2:7 (x,y,w,h)+クラス数分の信頼度
データ3:2100 候補数(Candidate)
NMSの例 [ 1 , 300 , 6 ]
データ1:1 バッチサイズ
データ2:300 検出枠の最大数
データ3:6 (x1,y1,x2,y2)+信頼度(confidence)、クラスID
推論に使用するtfliteやLiteRTはこの違いを認識することなく入力に対してモデルを
適用した結果を出力するので、フォーマットに合わせて出力結果を整理する必要
があります。
データ2とデータ3を比較して、
データ2< データ3 → No-NMS
データ3= 6 → NMS
と判定することができます。
出力座標の正規化
入力画像サイズ320x320に対して出力座標は
正規化なし:0~320
正規化あり:0.0~1.0
の1パターンに分かれます。
出力情報を描画する場合は座標を変換する必要があります。
その他の違いはNetroを使えばある程度判定できる内容ですが、出力座標が正規化
されているかは今のところモデルを見ただけで判断する方法がありません。
私はRGB全て0のダミーデータを使って一度推論を実行し、出力された最大座標値が
正規化あり:0~2ぐらいに収まっている ※本来は1以下だが、1を超える場合もある
正規化なし:数百(入力サイズと同程度の値)
として判定を行っています。
まとめ
同じYoloモデルをtfliteモデルに変換した場合でも入出力フォーマットが変わります。
公開されているtfliteの推論プログラムや生成AI等で作成したプログラムを使用する場合
にはこれらのフォーマットが一致しているものを使用しないと推論ができません。
私の場合は
モデルをロード
↓
モデル情報から
・入出力のfloat/int
・入力の並び(NCHW/NHWC)
・出力の並び(No-NMS/NMS)
を判定
↓
ダミーデータで推論
↓
出力座標の正規化を判定
↓
判定結果に合わせてメインの推論を実行
という手順で処理しています。
LiteRT向けにC++でプログラムを作成したので、整理ができたらGitHubで推論の
サンプルプログラムを公開予定です。