83 lines
4.1 KiB
Python
83 lines
4.1 KiB
Python
"""Парное сравнение двух прогонов полигона на одних и тех же вставках.
|
||
|
||
Полигон шумит сильнее, чем меняет его большинство правок: две реализации
|
||
случайности при одинаковых настройках расходятся на P@150 на 0.07, на P@100
|
||
у ящика — на 0.11 (EXPERIMENTS п. 16.1). Поэтому сравнивать итоговые таблицы
|
||
двух прогонов нельзя.
|
||
|
||
Но у каждого сценария свой генератор (`make_benchmark.scenario_rng`), и от
|
||
решений конвейера он не зависит: при другой настройке на вход идут те же
|
||
кадры с теми же вставками, до луча. Значит, разница двух прогонов — только
|
||
от настройки, и её видно по отдельным наблюдениям: сколько было 0 и стало 1
|
||
и наоборот. Перевороты в одну сторону — настоящий эффект, даже когда он
|
||
меньше межзернового шума; поровну в обе стороны — шум.
|
||
|
||
python tools/compare_benchmark.py artifacts/benchmark.json new.json
|
||
python tools/compare_benchmark.py a.json b.json --objects человек_лежа,ящик
|
||
"""
|
||
from __future__ import annotations
|
||
|
||
import argparse
|
||
import json
|
||
|
||
import numpy as np
|
||
|
||
MIN_VISIBLE_RAYS = 2 # как в plot_benchmark: меньше — предмет не освещён
|
||
|
||
|
||
def load(path: str) -> dict:
|
||
with open(path, encoding="utf-8") as f:
|
||
return {(r["bag"], r["obj"], r["lateral"]): r for r in json.load(f)}
|
||
|
||
|
||
def main() -> None:
|
||
ap = argparse.ArgumentParser(description=__doc__)
|
||
ap.add_argument("before", help="прогон «было» (json из make_benchmark)")
|
||
ap.add_argument("after", help="прогон «стало»")
|
||
ap.add_argument("--objects", default="",
|
||
help="через запятую; пусто — все предметы")
|
||
ap.add_argument("--edges", default="0,15,40,90,130,170,230",
|
||
help="границы полос дальности, м")
|
||
args = ap.parse_args()
|
||
|
||
a, b = load(args.before), load(args.after)
|
||
if set(a) != set(b):
|
||
raise SystemExit("разный состав сценариев — прогоны не парные")
|
||
edges = [float(x) for x in args.edges.split(",")]
|
||
objs = ([o for o in args.objects.split(",") if o] if args.objects
|
||
else sorted({k[1] for k in a}))
|
||
|
||
print(f"{'предмет':14s}{'полоса':>12}{'набл.':>7}{'было':>7}{'стало':>7}"
|
||
f"{'0→1':>6}{'1→0':>6}")
|
||
total_up = total_down = 0
|
||
for obj in objs:
|
||
obj_up = obj_down = 0
|
||
for lo, hi in zip(edges[:-1], edges[1:]):
|
||
n = ha = hb = up = down = 0
|
||
for k, ra in a.items():
|
||
if k[1] != obj:
|
||
continue
|
||
rb = b[k]
|
||
da = np.asarray(ra["d"])
|
||
if da.shape != np.shape(rb["d"]) or not np.allclose(da, rb["d"]):
|
||
raise SystemExit(f"вход разошёлся в {k}: прогоны не парные")
|
||
m = (da >= lo) & (da < hi) & (np.asarray(ra["rays"]) >= MIN_VISIBLE_RAYS)
|
||
x, y = np.asarray(ra["hit"])[m], np.asarray(rb["hit"])[m]
|
||
n += int(m.sum())
|
||
ha += int(x.sum())
|
||
hb += int(y.sum())
|
||
up += int(((x == 0) & (y == 1)).sum())
|
||
down += int(((x == 1) & (y == 0)).sum())
|
||
obj_up += up
|
||
obj_down += down
|
||
if n >= 20:
|
||
print(f"{obj:14s}{f'{lo:.0f}–{hi:.0f} м':>12}{n:7d}{ha / n:7.2f}"
|
||
f"{hb / n:7.2f}{up:6d}{down:6d}")
|
||
print(f"{obj:14s}{'всего':>12}{'':21s}{obj_up:6d}{obj_down:6d}")
|
||
total_up += obj_up
|
||
total_down += obj_down
|
||
print(f"\nвсе предметы: 0→1 {total_up}, 1→0 {total_down}")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|