NMS(重なり抑制)の実務チューニングガイド【評価と本番を揃える意味】

NMS(重なり抑制)の実務チューニング完全ガイド【評価と本番を揃える意味】

「学習の中身はNMSに依存しない。でも“何を良しとするか”はNMSに依存する」。この当たり前を仕組みに落とし込む。なお、本内容は調査中の内容を含みます。

目次

  1. NMSって何?なぜ必要?
  2. 調整するツマミ(conf / nms_iou / 方式)
  3. 重要な真実:学習は非依存、評価は依存
  4. 実務ワークフロー:探索 → 固定 → 選抜 → 本番
  5. YOLOXでの設定ポイント(Exp・CLI・postprocess)
  6. 用途別レシピ(そのまま試せる)
  7. 良し悪しの見分け方(AP/ARだけ見ない)
  8. 一歩進める:Soft-NMS / DIoU-NMS / class-wise
  9. 最終チェックリスト

1. NMSって何?なぜ必要?

要点 物体検出モデルは同じ物体に複数の予測箱を出します。NMS(Non-Maximum Suppression)は、重なり具合(IoU)やスコアを指標に代表1個だけ残す後処理です。

困るパターン

  • 同じモノに2〜3箱 → 重複検出で見づらい・誤カウント
  • 密集シーンで本当は複数あるのに強い1箱に潰される → 見逃し

つまり「重複を減らす」×「見逃しを減らす」のバランス調整がNMSの核心です。

2. 調整するツマミ(conf / nms_iou / 方式)

conf(スコア閾値)

↑ 高い=厳選(外れ減)/ ↓ 低い=拾う(見逃し減)

nms_iou(IoU閾値)

↑ 高い=重なっても複数残す(見逃し減・重複増)/ ↓ 低い=すぐ1箱にまとめる(重複減・見逃し増)

方式(標準 / Soft / DIoU…)

標準NMSは二者択一、Soft-NMSは「消す代わりに減点」、DIoU-NMSは中心距離も考慮。

初手の目安(YOLO系):conf=0.25, nms_iou=0.45。ここから上下に刻んで最適点を探す。

3. 重要な真実:学習は非依存、評価は依存

結論:学習の損失や勾配はNMSに依存しない(NMSは後処理)。しかし、「どの重みを良しとするか」=評価・選抜・停止判断はNMSに依存します。

なぜ“学習時にNMSを決める”意味がある?

  • チェックポイント選抜:学習中valのmAPはNMS設定で変わる。本番と同じNMSで評価しないと「学習で最良=本番で最良」とは限らない。
  • Early stopping / LRスケジュール:plateau判定はval指標依存。本番NMSと同条件だと判断がブレない。
  • ハイパラ比較の公平性:NMSが違うとAP/ARがズレ、結論が変わる。評価の物差しとしてNMS固定は有用。
  • 擬似ラベル・AL:“残す予測”はNMS+閾値に依存。学習ループに間接的に効くので、ここでは意味が大きい

要するに 「探索は自由でOK、でも最終的には“本番NMS=val NMS”に固定して選抜」が筋が良い。

4. 実務ワークフロー:探索 → 固定 → 選抜 → 本番

  1. 探索:推論側でグリッド探索(例:conf ∈ {0.2, 0.25, 0.3}, IoU ∈ {0.45, 0.5, 0.55}, Soft有無)で「業務要件に合う運用プロファイル」を決める。
  2. 固定:決めたNMS(conf / IoU / 方式)を 評価設定としてExpに固定
  3. 選抜:その設定でvalし、最良エポック(チェックポイント)を選ぶ。
  4. 本番:運用でも同じNMSでデプロイ。学習で見た数字=現場の数字、に近づく。

5. YOLOXでの設定ポイント(Exp・CLI・postprocess)

5.1 Exp(設定ファイル)に固定(再現性◎)

# yolox_s.py の Exp.__init__ に追記
self.test_conf = 0.25   # 評価/推論のスコア閾値(本番と同じにする)
self.nmsthre  = 0.50    # NMSのIoU閾値(本番と同じにする)

学習中のval・tools/eval.py・demo.pyがこの値を参照。評価軸の固定が目的。

5.2 CLIで一時上書き(探索向き)

# 推論デモ
python tools/demo.py image -f yolox_s.py -c weights/best_ckpt.pth \
  --path assets/test.jpg --conf 0.25 --nms 0.50

# 評価(mAP計測)
python tools/eval.py -f yolox_s.py -c weights/best_ckpt.pth \
  --conf 0.25 --nms 0.50

探索で当たり値が見えたら、最終的にExpへ固定しよう(評価と本番を揃える)。

5.3 postprocessを合わせる(Soft/DIoU/Class-wise等)

本番がBatchedNMS/Soft-NMS/DIoU-NMS/Class-agnosticなら、YOLOX側でも同等のpostprocessに合わせて評価するとズレが減る。クラス別閾値はpostprocess直前にscoreでフィルタするだけでも効く。

6. 用途別レシピ(そのまま試せる)

6.1 重複が目立つ(同一物体に2〜3箱)

  • conf = 0.32〜0.35(弱い予測を捨てる)
  • nms_iou = 0.40〜0.45(まとめやすくする)
  • Soft-NMSはオフ(シンプル優先)

AP↑ / ARは微減になりやすい。見逃し増えすぎなら nms_iou=0.45へ戻す。

6.2 見逃しが多い(小物・密集)

  • conf = 0.20〜0.25(拾いにいく)
  • nms_iou = 0.55〜0.60(重なっても複数残す)
  • Soft-NMS ON(linear/gaussian, sigma=0.5〜0.8

AR↑の狙い。誤検出が増えたら confを+0.05。

6.3 細長い/平行物(線・ケーブル等)

  • DIoU-NMSを試す(中心距離を加味)
  • nms_iou = 0.50〜0.60
  • conf = 0.25から微調整

6.4 クラス別に“甘辛”を振る(class-wise)

  • 誤検出が多いクラス:conf +0.05〜0.10nms_iou −0.05
  • 見逃しが多いクラス:conf −0.05nms_iou +0.05、Soft-NMS
# 疑似コード(スコア閾をクラス別に)
per_cls_conf = {"earphones":0.30, "stationery":0.30, "pebble":0.28}
filtered=[]
for b in boxes:
    cls = id2name[b.cls]
    thr = per_cls_conf.get(cls, 0.25)
    if b.score >= thr:
        filtered.append(b)
final = nms(filtered, iou=0.55, method="soft", sigma=0.6, class_agnostic=False)

6.5 サイズ依存NMS(小物は残しやすく)

  • 小さい箱には nms_iou +0.05(潰れ防止)
  • 大きい箱は標準設定

7. 良し悪しの見分け方(AP/ARだけ見ない)

観察ありがちな原因調整のヒント
重複検出が多いconf低すぎ / nms_iou高すぎconf↑ / nms_iou↓
見逃しが多いconf高すぎ / nms_iou低すぎconf↓ / nms_iou↑ / Soft-NMS
小物が消えるNMSが強すぎnms_iou↑ / Soft-NMS / 入力解像度↑
似た物体を取り違える難負例不足 / スコア閾が甘い難負例追加 / conf↑ / class-wise

見るべき数字(補助指標)

  • FP/画像:誤検出の平均個数(低いほど良い)
  • 重複率:1GTあたりの予測箱数(1.0〜1.2程度が目安)
  • クラス別AP/AR:弱点クラスの伸びを確認

8. 一歩進める:Soft-NMS / DIoU-NMS / class-wise

8.1 Soft-NMS

完全削除ではなく重なりに応じて減点。密集・小物で有効。sigma≈0.5〜0.8、方式はlineargaussian

8.2 DIoU-NMS / GIoU-NMS

IoUに加えて中心距離や外接矩形を考慮。細長い物や近接多発に強い。nms_iou=0.50〜0.60で試す価値あり。

8.3 class-wise / size-wise

クラスやサイズ帯で閾値を変えると、現実のデータ分布に合わせやすい。評価時も本番も同じ戦略を適用し、学習で見た挙動=現場の挙動に近づける。

9. 最終チェックリスト(評価と本番を揃える)

  • 探索:推論でグリッド探索 → 運用プロファイル(conf / IoU / 方式)を決める
  • 固定:Expに test_conf / nmsthre を設定(本番と同一)
  • 選抜:その設定でvalし、最良チェックポイントを採用
  • 本番:同じNMSでデプロイ(TensorRT/ONNX側のBatchedNMS等も揃える)
  • AP/AR+FP/画像+重複率+クラス別を確認(APだけで判断しない)
  • 小物・密集なら Soft-NMS / DIoU-NMS / size-wise を検討
  • クラス特性が違うなら class-wise 閾値で“甘辛”を振る

まとめ(超短縮)

学習の内部はNMSに非依存。でも評価・選抜はNMSに依存
だから「探索→固定→選抜→本番」で、本番NMS=val NMSに揃えて意思決定する。
同じ重みでもNMSで見える性能は動く――評価軸は固定して勝ちに行こう。

本ガイドは、現場の意思決定(どの重み・いつ止める・何を比較)をブレさせないための“評価=本番”原則に基づいています。©株式会社ビー・ナレッジ・デザイン

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA