前回の第10回では、APIをDockerで動かす形を整えました。最終回の今回は、動かし始めたあとに何が起きるかと、ライセンスを整理し、連載全体をまとめます。
画像認識は、作って終わりではありません。撮影条件が少し変わるだけで、結果が変わることがあります。その変化に、気づける仕組みが必要です。
この回で作るもの
- 稼働後の変化(精度の低下のきざし)を記録・判定する
app/monitor.py - 撮影条件の変化で、結果がどう変わるかを試す
tools/drift_demo.py
稼働後の精度は「直接は測れない」
第6回では、正解データと突き合わせて精度を測りました。しかし、稼働後の本番の写真には、正解がありません。全部に正解を付けていては、AIを使う意味がなくなります。
そこで、正解がなくても測れる変化のきざしを記録します。
- 1回の処理で見つかった件数
- 信頼度の平均
- 何も見つからなかった画像の割合
「普段と違う」ことに気づければ、原因(照明・カメラ・対象の変化)を調べるきっかけになります。
実装
集計して記録する
# app/monitor.py(抜粋)
@dataclass(frozen=True)
class RunStats:
images: int
detections: int
mean_confidence: float | None # 何も見つからなければ None
empty_images: int # 何も見つからなかった画像の数
def summarize(per_image: list[list[Detection]]) -> RunStats:
confidences = [d.confidence for detections in per_image for d in detections]
return RunStats(
images=len(per_image),
detections=len(confidences),
mean_confidence=round(statistics.fmean(confidences), 3) if confidences else None,
empty_images=sum(1 for detections in per_image if not detections),
)
記録は、1行1件の形式(JSON Lines)で追記します。画像のファイル名や中身は残しません。
「普段」との違いを判定する
# app/monitor.py(抜粋)
def check_drift(baseline, current, confidence_drop=0.10, empty_rate_rise=0.20, count_drop_ratio=0.30) -> list[str]:
"""普段(baseline)と比べて、気になる変化があれば、その内容の一覧を返す。空なら問題なし。"""
warnings: list[str] = []
... # 信頼度の平均の低下、何も見つからない割合の増加
# 信頼度の平均だけでは、自信の低い結果が消えて平均が上がる場合に気づけない。1枚あたりの検出件数も見る
base_count = baseline.detections / baseline.images if baseline.images else 0.0
now_count = current.detections / current.images if current.images else 0.0
if base_count > 0 and (base_count - now_count) / base_count >= count_drop_ratio:
warnings.append(f"1枚あたりの検出件数が減っています({base_count:.1f} → {now_count:.1f})")
return warnings
3つの見方を組み合わせているのは、1つだけでは見落とすためです。実際にそうなった例を、次で見ます。
動かして確かめる:撮影条件が変わったら
サンプル写真に、2種類の変化を加えて、結果を比べます。
- 明るさ:照明が暗くなった想定
- JPEG画質:カメラやアプリの設定で、画像の圧縮率が変わった想定
python tools/drift_demo.py
開発環境での結果です(基準は、元の写真をPNG=圧縮による劣化のない形式で保存したもの)。
条件 件数 信頼度の平均 気になる変化
基準(変化なし・PNG) 4 0.613 -
明るさ 0.5倍 4 0.638 -
明るさ 0.3倍 3 0.629 -
JPEG 画質 75 2 0.762 1枚あたりの検出件数が減っています(4.0 → 2.0)
JPEG 画質 30 0 - 信頼度を出せるだけの検出がありません(何も見つかっていません); 何も見つからない画像の割合が増えています(0% → 100%); 1枚あたりの検出件数が減っています(4.0 → 0.0)
JPEG 画質 10 1 0.309 信頼度の平均が下がっています(0.613 → 0.309); 1枚あたりの検出件数が減っています(4.0 → 1.0)
意外な結果でした。
- 明るさの変化:この写真では、0.5倍まではほぼ変わらず、0.3倍でも検出が1件減った程度でした。暗さの影響は、思ったより小さい結果でした(写真や対象によって変わるはずで、この結果を一般化はできません)
- JPEG画質の変化:画質75(多くのカメラの標準に近い値)に再保存しただけで、検出が4件から2件に減りました。画質30では、何も見つかりませんでした
「画質を少し変えただけ」で、結果が大きく変わりました。 カメラの設定変更、写真を送るアプリの圧縮、撮影担当者の交代などが、本番では実際に起こります。
さらに、画質75の行に注目してください。信頼度の平均は、0.613から0.762に上がっています。 自信の低い結果が消えたために、残った結果の平均が上がったのです。もし信頼度の平均だけを見ていたら、この変化に気づけません。検出件数も一緒に見ているから、気づけました。
テスト
pytest -q # 37件成功
ruff check . # 問題なし
集計、変化の判定(信頼度の低下・何も見つからない割合の増加・件数の減少)、信頼度が上がっても件数の減少を拾えること、記録が追記されることを確認しています。
ライセンスの整理(AGPL-3.0と商用ライセンス)
第0回でも触れたとおり、Ultralytics(YOLO)は、オープンソースのライセンス「AGPL-3.0」で公開されています。公式のREADMEでは、商用利用のためのライセンスとして「Ultralytics Enterprise License」も案内されています。
📰 出典:Ultralytics 公式リポジトリ README(ライセンスの項)
一般的には、AGPL-3.0のソフトウェアを、ネットワーク越しにサービスとして提供する場合、そのソフトウェアを使ったシステムのソースコードの公開が求められることがあると説明されます。ただし、自社のシステムがこれに当たるか、商用ライセンスが必要かは、使い方(社内だけか、社外に提供するか等)によって変わります。この記事では、個別の判断はしません。契約・法務の担当者や、専門家、提供元に確認してください。
発注のときは、次の点を、開発会社に確認するのが現実的です。
- どのAIモデル・ライブラリを使い、それぞれのライセンスは何か
- 商用ライセンスが必要な場合、その費用は誰が負担し、契約は誰の名義か
- ライセンスの対応が必要になった場合に、別のモデル(ライセンスの条件が異なるもの)に切り替える選択肢はあるか
この連載のまとめ:全12回で分かったこと
| 回 | 学んだこと |
|---|---|
| 0〜1 | 学習済みモデルは数日で動く。ただし、知らない対象は間違える。信頼度のしきい値で、見逃しと誤検出が入れ替わる |
| 2〜3 | 画像に描いて確認する。信頼度が高くても間違う。数える業務は、撮影ルールまで設計が要る |
| 4〜5 | APIと画面にして初めて、現場で使える。認証・外部通信の確認が必要 |
| 6 | 精度は、適合率と再現率で測る。テスト用の正解付き写真は、発注者が用意する |
| 7 | 追加学習は、データの量・質で決まる。検証の数字だけで安心してはいけない |
| 8 | AIを100%信じず、人が確認する設計にする。自信が高い間違いは、しきい値では防げない |
| 9〜10 | 速度・構成は、枚数と応答時間で決まる。変換しても、再評価が必要。運用の準備(ログ・ヘルスチェック) |
| 11 | 稼働後は、変化に気づく仕組みが必要。ライセンスは、事前に確認する |
「精度○%」より先に決めること
連載を通して、画像認識の発注で大切なのは、AIの選び方よりも、次のような発注者側の準備だと分かりました。
- 何を判定したいか、写真つきで具体的に決める
- 現場で撮った、テスト用の正解付き写真を用意する
- 見逃しと誤検出のどちらが困るか、許容できる誤差を決める
- AIが間違えたときの、人の確認の流れを決める
- 稼働後の変化に気づく方法と、再学習の体制を決める
- ライセンス・個人情報・外部通信の扱いを確認する
発注者向けメモ:稼働後の保守に含めるものを決める
画像認識のシステムは、稼働後の精度の見守りと、必要に応じた再学習が、保守の中心になります。ここが契約に含まれているかどうかで、数か月後の安心感が大きく変わります。
発注者がやること チェックリスト
- ☐ 稼働後に、精度の低下のきざし(件数・信頼度の変化)を記録・確認する担当者と頻度を決めた
- ☐ 撮影条件(カメラ・照明・画像の設定)を変えるときは、事前に連絡する運用にした
- ☐ 再学習が必要になったときの、費用・期間・写真の用意の分担を決めた
- ☐ 使っているAIモデル・ライブラリのライセンスを確認し、商用の条件を、法務や専門家に確認した
- ☐ 開発会社が交代しても再現できるよう、環境・学習データ・評価用の写真が、納品物に含まれることを確認した
開発会社への質問例
- 「稼働後の精度は、どのような指標で、どのくらいの頻度で確認しますか。異常はどう通知されますか」
- 「カメラの交換や、画像の圧縮設定の変更が、精度に影響することはありますか。事前に確認できますか」
- 「再学習は、保守の範囲に含まれますか。含まれない場合の費用の目安を教えてください」
- 「使うAIモデルのライセンスを、書面で教えてください。商用利用の条件は確認済みですか」
- 「学習に使った写真、評価用の写真、学習の設定は、納品物に含まれますか」
まとめ
第11回(最終回)では、次のことを行いました。
- 稼働後の変化のきざし(件数・信頼度・何も見つからない割合)を記録・判定する仕組みを作った
- 画像の圧縮率を少し変えるだけで、検出が大きく減ることを確認した
- 信頼度の平均だけでは、変化を見落とす例を確認した
- ライセンス(AGPL-3.0と商用ライセンス)の確認点を整理した
- 連載全体の学びと、発注者側の準備をまとめた
全12回を通して作ったのは、画像認識の小さな試作です。ここから、自社の対象・現場に合わせて、写真を集め、精度を測り、人の確認を組み込み、見守る。この積み重ねが、実用に至る道です。自社の画像認識の相談は、まず小さな試作(PoC)から始めるのが、現実的な進め方です。
この連載の記事一覧
この記事は連載「YOLOで作る画像認識ツール」の1回です。連載のほかの回は次のとおりです(連載の一覧ページ)。
- 【YOLOで作る画像認識ツール 第0回】全体像と環境づくり:YOLOで最初の1枚を認識する
- 【YOLOで作る画像認識ツール 第1回】信頼度のしきい値とJSON出力:認識結果を「使える形」にする
- 【YOLOで作る画像認識ツール 第2回】認識結果を画像に描いて確認する:枠とラベルで「間違い」を見つけやすくする
- 【YOLOで作る画像認識ツール 第3回】種類ごとに何個あるか数えて、CSVに集計する
- 【YOLOで作る画像認識ツール 第4回】FastAPIで画像認識を「API」にして、ほかのシステムから使えるようにする
- 【YOLOで作る画像認識ツール 第5回】ブラウザから写真をアップロードして、認識結果をその場で見る
- 【YOLOで作る画像認識ツール 第6回】精度を数字で測る:正解データと、適合率・再現率
- 【YOLOで作る画像認識ツール 第7回】学習済みモデルにない対象を覚えさせる:追加学習の手順と、結果の正しい読み方
- 【YOLOで作る画像認識ツール 第8回】自信の低い結果だけ人が確認する:AIと人の役割分担を設計する
- 【YOLOで作る画像認識ツール 第9回】速く・軽くする:ONNXに変換してCPUで動かし、変換前後を比べる
- 【YOLOで作る画像認識ツール 第10回】Dockerで動かす:設定・ログ・ヘルスチェックを運用に近い形にする
- 【YOLOで作る画像認識ツール 第11回(最終回)】運用の注意点とライセンス(AGPL-3.0):精度の低下に気づく仕組みと、連載のまとめ(この記事)

