TT Lab
はじめる
学ぶ 学習パス コース

AIダイエット失敗事件

同じ数字でも単位が違った

TT Labで続きを見る

一言でいうと

入力の単位とサンプルの役割を固定してこそ、モデルの比較が実験になります。

なぜ必要なのか

宅配の仕分けロボットの数字読み取り器を、小さな装置に移すところを想像してください。開発PCではよく読めていたモデルが、デプロイ後は数字を間違えます。モデルファイルは正常に開き、エラーログもありません。この種の故障は、プログラムが動くかどうかを確認するだけでは見つかりません。入力の単位とデータ分割を先に固定しておかないと、あとで結果が変わったときに原因を探せません。

今回のコースでは、すでに学習済みの小さな手書き文字分類器を受け取ります。課題は新しいモデルの学習競争ではなく、モデルの変換と検証です。Pythonの関数・リスト・JSON・NumPy配列の基礎が必要です。GPUや実物のロボットなしでLinux CPU上で実行するため、実際のMCU・NPUの速度や消費電力は、このラボでは証明できません。

どう動くのか

提供されるdigitsデータは、8×8の画像を64個の特徴量に展開した配列です。ピクセル値は0–16です。よく見る画像だからという理由だけで255で割ると、学習時と入力範囲が変わってしまいます。normalize(pixels)はfloat32配列に変換して16で割り、入力のシェイプを保つ必要があります。元の配列自体を変更する必要はありません。

画像のピクセル値とサンプルIDは別物です。IDは元データの行を識別する整数です。digits.npzのx_train・x_calibration・x_testには画像が、y_testには評価用の正解が、ids_train・ids_calibration・ids_testには各分割のIDが入っています。提供された分割は、学習1,077個、キャリブレーション360個、評価360個です。分割をやり直さず、提供されたIDをそのまま使います。

キャリブレーションデータは変換器の数値範囲を決める材料で、評価データは変換後の品質を判断する材料です。評価の正解を見ながらキャリブレーションサンプルを選んで成績を上げると、両者の役割が混ざります。キャリブレーションファイルに評価IDが1つ入っている場合もリークです。IDの個数だけを数えず、集合と重複を確認してください。ただし、この小さな公開評価セットを繰り返し使った成績は、独立した現場での汎化性能ではありません。

現場での姿

前処理関数は、データチームとアプリケーションチームの間にある小さなAPIです。一方は0–1の実数を期待しているのに、もう一方が0–16の整数を渡しても、配列のサイズが同じなら呼び出しは成功してしまいます。そのため、契約には特徴量の数だけでなく、データ型と値の範囲も必要です。カメラ・センサー入力を扱う実際のシステムでは、ここにチャンネルの順序・時間の単位・欠損値の処理も加わります。今回の入力には、その複雑さをあえて入れていません。まず、範囲を1つ間違えたときにエラーがどのように静かに広がるかを確認します。

小さな計算を先に紙でやってみてください。ピクセルが3つで0、8、16なら、正しい正規化結果は0.0、0.5、1.0です。255で割ると、最後の値でさえ約0.0627にしかなりません。プログラムから見ればどちらも有限の実数なので、例外は発生しません。モデルは、普段より暗い入力を受け取ったことになります。エラーがないという事実と、入力が正しいという事実を分けて考えなければならない理由です。

配列全体を書き換える関数と、新しい配列を返す関数も区別する必要があります。元のx_testを書き換えてしまうと、同じプロセスで次のモデルを評価するときに、すでに正規化された値をもう一度割ってしまうことがあります。各モデルの評価入力が変わるため、性能の差を量子化のせいだと誤って説明することになります。今回のnormalizeの契約は、入力配列を保持します。関数単体のテストでは、実際のサンプルのほかに、すべて0の行とすべて16の行も入れて、両端の値も確認します。

IDの選択は、「個数・重複・集合」の3つの質問に分けると考えやすくなります。360個入っているか、同じIDを2回入れていないか、提供されたキャリブレーション集合と同じか、をそれぞれ答えてみてください。最後の質問は、順序が違っても通る必要があります。順序を固定すると、同じデータを別の順序で読む正常な実装を拒否してしまうからです。単に0から359まで埋めると、IDが元データのどの行を指すのかを見失います。キャリブレーションサンプルを読むときは、元のIDからキャリブレーション配列内の行位置を探す対応表を作れば済みます。

すでに学習済みのFP32モデルとデータが固定されているので、同じバイト列から出発します。それでもこのデータは、手書き文字のあらゆるスタイルを代表しているわけではありません。公開データの再現性と、実際の顧客入力の代表性は別の問題です。現場へのデプロイ前には、別の筆跡・撮影条件・汚れ具合のデータを集めて評価する必要があり、このコースでの高い成績でその作業を省くことはできません。直後のクイズで入力と分割を確認したあと、最後のモジュールの統合ラボへ進みます。

次のラボですること

ステップ1–3で、contract.jsonに入力の契約を記録し、preprocess.pyの正規化関数を実装し、calibration.jsonにキャリブレーション用のIDだけを保存します。先に単位をわざと間違えて、どの検査がそれを捕まえるかを確認してみてください。最初のステップは、提供された配列のシェイプと長さを読むという小さな成功から始まります。

データの出典: scikit-learn load_digits、UCIの元データ。元データの著者・CC BY 4.0の表記は、提供されるDATA-LICENSE.jsonにもあります。