概要
raspi/roi-counter/scripts/03_sweep_params.py で、パラメータ組み合わせごとにYOLOトラッカー状態を確実にリセットする。
現在は同じYOLOインスタンスを persist=True のまま再利用しているため、前のパラメータ実行のtrack IDやtracker状態が次の実行へ持ち越される可能性がある。これにより閾値スイープの各試行が独立にならない。
開発目的
s_low × s_high の比較結果を独立した試行として扱えるようにする
- 既存の閾値選定結果を信頼できる状態にする
バグの具体的な構造
03_sweep_params.py は、s_low 7通り × s_high 7通りの計49パターンについて、同じ動画を先頭から再生して評価する。ところが、YOLOモデルはループの外で一度だけ生成され、各runでは同じモデルに対して model.track(..., persist=True) を呼んでいる。
そのため、現在の処理は概念的に次の状態になっている。
本来:
run A: 動画先頭 → 動画末尾 → tracker reset
run B: 動画先頭 → 動画末尾 → tracker reset
現在:
run A: 動画先頭 → 動画末尾
↓ tracker状態を保持
run B: 動画先頭 → 動画末尾
run Bの先頭フレームが、YOLOトラッカーからはrun Aの最終フレームに続くフレームとして扱われる可能性がある。
ここで注意すべきなのは、ROI側の Counter とYOLO側のtrackerは別の状態を持つことである。
| 状態 |
保持する内容 |
現在のrun間リセット |
ROIの Counter |
track IDごとの入出庫候補、カウント済み状態、s_history |
毎run新規生成される |
| YOLO tracker |
track ID、追跡中・消失中の車両、位置・速度などの追跡履歴 |
リセットされない |
Counter を新規生成しても、その入力となるtrack IDと追跡結果が前runの状態に影響されていれば、runの独立性は保証できない。
起こり得る影響
run境界、特に次runの冒頭で、次のような影響が起こり得る。
- 前run末尾の車両と次run先頭の車両が誤って関連付けられる
- 新しい車両にtrack IDが付くタイミングが変わる
- 一時的にIDが付かず、カウント処理から外れる
- 同一車両の途中でIDが切り替わり、移動履歴が複数IDに分断される
- 別車両の履歴が同一IDとしてつながる
ROIカウンターは、同じtrack IDが s < s_low 側から s > s_high 側まで移動したか、またはその逆方向へ移動したかで入庫・出庫を判定する。そのためIDの分断や誤関連付けは、未カウント・誤カウントとして count_in、count_out、count_error に直接影響し得る。
本来、各runの結果は次の入力だけで決まる必要がある。
result = video + s_low + s_high
現在は次の要因が混入する可能性がある。
result = video + s_low + s_high + previous tracker state
この状態では、以下を信頼できる形で行えない。
- Count Errorヒートマップから最適な閾値を選ぶ
- 閾値間を公平に比較する
- 実行順を変更しても同じ結果になることを保証する
- 過去のスイープ結果を再現する
- 既存の
MAE = 0 条件を本番採用の根拠にする
過去結果の扱い
このバグがあるからといって、過去の全カウント結果が必ず誤っているとは限らない。
- 最初のrunには前runがないため、基本的にはcleanな状態で開始される
- track IDの連番が継続するだけで、追跡結果自体が同じならカウントへの影響はない
s_low / s_high はYOLO trackerではなく後段の Counter で使用される
- 実害がある場合は、主に動画末尾から動画先頭へ戻るrun境界付近に現れると考えられる
ただし、影響がないことも現状では保証できない。したがって本件の本質は「既存結果が必ず誤り」ではなく、「各runの独立性が保証されず、実験結果を正しい閾値比較として証明できない」ことである。影響の大小は修正後に49パターンを再実行し、過去のCSVと比較して確認する。
考えられる開発内容
04_multi_video_mae.py と共通のtracker reset処理を利用する
- private APIへ依存する場合はUltralyticsバージョンを固定・記録する
- resetできない場合はモデルを再生成するか、その試行をinvalidとして中断する
- reset方法と成否を結果CSVへ記録する
- 既存49パターンを再実行し、過去結果との差を確認する
- fake trackerを用いたresetの単体テストを追加する
完了条件
- 各パラメータ試行の先頭でtrack IDが初期状態になる
- reset失敗を成功として記録しない
- 実行順を逆転しても同じカウント結果になる
- 既存のMAE=0条件を再確認する
考えられる開発時間
半日〜1日
備考
概要
raspi/roi-counter/scripts/03_sweep_params.pyで、パラメータ組み合わせごとにYOLOトラッカー状態を確実にリセットする。現在は同じYOLOインスタンスを
persist=Trueのまま再利用しているため、前のパラメータ実行のtrack IDやtracker状態が次の実行へ持ち越される可能性がある。これにより閾値スイープの各試行が独立にならない。開発目的
s_low × s_highの比較結果を独立した試行として扱えるようにするバグの具体的な構造
03_sweep_params.pyは、s_low7通り ×s_high7通りの計49パターンについて、同じ動画を先頭から再生して評価する。ところが、YOLOモデルはループの外で一度だけ生成され、各runでは同じモデルに対してmodel.track(..., persist=True)を呼んでいる。そのため、現在の処理は概念的に次の状態になっている。
run Bの先頭フレームが、YOLOトラッカーからはrun Aの最終フレームに続くフレームとして扱われる可能性がある。
ここで注意すべきなのは、ROI側の
CounterとYOLO側のtrackerは別の状態を持つことである。Counters_historyCounterを新規生成しても、その入力となるtrack IDと追跡結果が前runの状態に影響されていれば、runの独立性は保証できない。起こり得る影響
run境界、特に次runの冒頭で、次のような影響が起こり得る。
ROIカウンターは、同じtrack IDが
s < s_low側からs > s_high側まで移動したか、またはその逆方向へ移動したかで入庫・出庫を判定する。そのためIDの分断や誤関連付けは、未カウント・誤カウントとしてcount_in、count_out、count_errorに直接影響し得る。本来、各runの結果は次の入力だけで決まる必要がある。
現在は次の要因が混入する可能性がある。
この状態では、以下を信頼できる形で行えない。
MAE = 0条件を本番採用の根拠にする過去結果の扱い
このバグがあるからといって、過去の全カウント結果が必ず誤っているとは限らない。
s_low/s_highはYOLO trackerではなく後段のCounterで使用されるただし、影響がないことも現状では保証できない。したがって本件の本質は「既存結果が必ず誤り」ではなく、「各runの独立性が保証されず、実験結果を正しい閾値比較として証明できない」ことである。影響の大小は修正後に49パターンを再実行し、過去のCSVと比較して確認する。
考えられる開発内容
04_multi_video_mae.pyと共通のtracker reset処理を利用する完了条件
考えられる開発時間
半日〜1日
備考