7.7. 正規化¶
ml.Model.predict() は入力のリストを受け取ります。これは一部のネットワークが複数の入力テンサーを持つためですが、リストには入力ごとの引数をインラインで運ぶ手段がありません -- 「この入力を (x, y, w, h) に切り抜くが他の入力はそのままにする」というkwargスロットは存在しないのです。ml.preprocessing.Normalization はそのギャップを埋めるラッパーです。Normalization インスタンスは1つの入力のパラメータを保持します。スクリプトはデフォルト以外のものが必要なときはいつでも、ラップされた入力をpredictリストに渡します。
これに手を伸ばす最も一般的な理由は、画像全体ではなくキャプチャされたフレームの特定の領域をネットワークに切り抜くためです。
7.7.1. パラメータ¶
Normalization(scale=(0.0, 1.0),
mean=(0.0, 0.0, 0.0),
stdev=(1.0, 1.0, 1.0),
roi=None)
roi-- リサイズ前に切り抜くソースフレーム内の(x, y, w, h)矩形。デフォルトはフレーム全体です。Normalizationのほとんどの用途はこのパラメータだけを設定します。scale-- 浮動小数点入力テンサーが正規化後に期待する(min, max)範囲。ピクセル範囲0..255がこの範囲に線形にマッピングされます。一般的な値は、ReLUで学習されたネットワークでは(0.0, 1.0)、対称的に正規化されたネットワークでは(-1.0, 1.0)です。mean-- スケーリング後に画像から減算されるチャンネルごとの(R, G, B)平均。ネットワークが学習されたチャンネル統計に一致します -- ImageNet由来のネットワークでは(0.485, 0.456, 0.406)が代表的な例です。グレースケールネットワークは、標準的な0.299*R + 0.587*G + 0.114*Bを使って平均を輝度値に縮約します。stdev-- 平均が減算された後に画像が除算されるチャンネルごとの(R, G, B)標準偏差で、これもネットワークの学習統計に一致します。グレースケールネットワークでは同じ方法で輝度に縮約されます。
7.7.2. パラメータが重要になるとき¶
scale、mean、stdev は、ネットワークの input_dtype が int8 または uint8 の場合は無視されます。整数入力のネットワークでは、切り抜かれた画像バイトがテンサーに直接書き込まれ、ネットワーク自身の input_scale と input_zero_point が整数から実数への変換を処理します。これら3つのパラメータは、ネットワークが浮動小数点入力を期待する場合にのみ重要です。
roi はすべてのケースで読み取られます -- 入力dtypeに関係なく、ソースフレームのどの部分がネットワークに到達するかを制御します。
7.7.3. ROIとリサイズ¶
ROIはソース寸法からネットワークの入力寸法へバイリニアにスケーリングされます。画像はデスティネーションの中央に配置され、スケーリングはデスティネーションを埋めます -- アスペクト比は保持されません。正方形のネットワーク入力に与えられた非正方形のROIは、水平方向または垂直方向に引き伸ばされて出力されます。
引き伸ばしが重要かどうかはネットワークによります。MediaPipeファミリー(BlazeFace、FaceLandmarks、HandLandmarks、MoveNet)のような顔検出・ランドマークモデルは正方形の切り抜きに対して学習されており、入力アスペクト比がずれると急速に劣化します。それらの場合、アプリケーションは正方形のROIを与える必要があります -- window() を通じて正方形のフレームサイズでキャプチャするか、roi= パラメータで切り抜くかのいずれかです。YOLOファミリーの物体検出器は通常、ランダムな引き伸ばしを含むオーグメンテーションで学習されており、精度をあまり損なわずに非正方形のROIを受け入れます。キャプチャしたフレーム全体をそのまま渡しても通常は問題ありません。
ネットワークの入力寸法がROIと正確に一致する場合、スケールはコピーに崩れ、これが最も安価なケースです。
7.7.4. デフォルトの上書き¶
predict() は各 image.Image 入力を Normalization() で自動的にラップします -- 上記のデフォルトパラメータです。カメラに同梱されているほとんどのモデルは、デフォルトが既にカバーするピクセル範囲に対して学習されているため、一般的なケースは画像を直接渡すことです:
result = model.predict([img])
カスタムROIを使用するには -- 最も一般的な上書きです -- ROIを設定した Normalization を構築し、画像をそれにバインドします:
from ml.preprocessing import Normalization
norm = Normalization(roi=(80, 60, 160, 120))
result = model.predict([norm(img)])
ネットワークの学習時のチャンネル統計に一致させるには、浮動小数点パラメータを設定します:
norm = Normalization(scale=(0.0, 1.0),
mean=(0.485, 0.456, 0.406),
stdev=(0.229, 0.224, 0.225))
result = model.predict([norm(img)])
Normalization インスタンスを画像に対して呼び出すと、エンジンがそこからテンサーを埋める新しいバインド済みインスタンスが返されます。バインド済みインスタンスは、生の画像の代わりにpredictが受け付けるものであり、入力ごとのオブジェクトであるため、複数入力のネットワークは同じpredictリスト内で異なるROIを持つ画像を混在させることができます。
アプリケーションが既にテンサー形式で生成した入力 -- ペリフェラルからのバッファ、別のパイプラインで計算された ndarray、画像でない数値データ -- を期待するネットワークの場合は、Normalization を完全にスキップして、ndarrayまたはそれを生成する呼び出し可能オブジェクトを渡します。predict() はそれらをラップせずにエンジンへ通過させます。