7.15. 独自に記述する¶
カタログがモデルをカバーしていない場合(出力レイアウトが独自の研究ネットワーク、既存アーキテクチャへの改変、意味的解釈がアプリケーション固有のテンソルなど)、アプリケーションは独自の後処理を提供します。プロトコルは単純です。(model, inputs, outputs) を受け取り、アプリケーションが predict() から期待するものを返す呼び出し可能オブジェクトです。
__call__ を持つクラスが慣例的な形式です:
class MyPostprocessor:
def __init__(self, threshold=0.5):
self.threshold = threshold
def __call__(self, model, inputs, outputs):
...
return result
通常の関数でも機能します。エンジンはオブジェクトが呼び出し可能であることだけを確認します。
7.15.1. 組み込む¶
接続点は2つあります。コンストラクタの postprocess= キーワード引数は、そのモデルに対するすべての predict() 呼び出しに対して呼び出し可能オブジェクトをバインドします:
model = ml.Model("/rom/my_model.tflite",
postprocess=MyPostprocessor())
単一の呼び出しに対してバインディングを上書きするには(モデルを再ロードせずにデコーダを差し替えるには)、predictに直接 callback= を渡します:
result = model.predict([img], callback=MyOtherPostprocessor())
呼び出し可能オブジェクトのシグネチャはどちらの場合も同じです。
7.15.2. 呼び出し可能オブジェクトが受け取るもの¶
model--Modelインスタンスで、量子化パラメータ(output_scale、output_zero_point、output_dtype)や入力次元(input_shape)に役立ちます。inputs-- アプリケーションがpredict()に渡した入力のリストです。最初の要素は通常、バインドされたNormalizationインスタンスです。そのroi属性は、NMSがボックスを元画像に再マッピングするために期待するものです。outputs-- 生の出力テンソルで、ネイティブのdtypeのままのndarrayオブジェクトのリストです。浮動小数点出力はそのまま到着し、整数出力は量子化された状態で到着します。
7.15.3. 量子化演算¶
出荷されるデコーダはすべて ml.utils の同じヘルパーを利用しており、カスタムのものも通常は同じパターンを必要とします。quantize() は浮動小数点のしきい値をモデルの量子化空間に持ち上げ、threshold() はテンソル全体を逆量子化せずにフィルタリングし、dequantize() は生き残ったものに対して一度だけ実行されます。sigmoid() と logit() は、出力チャンネルがシグモイド適用前のロジットであるネットワーク向けに利用できます(MediaPipe検出器が典型的なケースです)。
浮動小数点出力を持つモデル(回帰ヘッド、最終的な逆量子化レイヤーが組み込まれたモデル)の場合、量子化ヘルパーは変更を加えずにそのまま通すため、同じ後処理コードが特別な分岐なしにどちらのdtypeに対しても機能します。
7.15.4. 戻り値¶
呼び出し可能オブジェクトが返すものが、そのまま predict() が返すものになります。ボックスを出力するデコーダでは、候補を NMS に通し、そのクラスごとのリストを返すのが慣例です。これは non-max suppression が文書化し、YOLOv8ウォークスルー が文脈の中で構築する呼び出しの形状です。それ以外の場合は、アプリケーションが便利だと思うものを何でも返せます。単一の ndarray、ラベル文字列、(class, score, embedding) のタプル、辞書などです。