Merge branch 'q3-bayes' of https://git.simba-robotics.com/HelixCopex/mcm-26-b into q3-bayes
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
"""固定场景配对审核:先保存 baseline,再以相同场景、误差种子比较改进。
|
||||
|
||||
不连接官方模拟器;真值仅用于本地模拟器和执行后的验收。
|
||||
"""
|
||||
import argparse
|
||||
from dataclasses import asdict
|
||||
from dataclasses import replace
|
||||
import hashlib
|
||||
import importlib.util
|
||||
import json
|
||||
import math
|
||||
from pathlib import Path
|
||||
from statistics import mean, median
|
||||
from time import perf_counter
|
||||
import sys
|
||||
|
||||
from mcm26b.config import ProblemConfig
|
||||
from mcm26b.evaluation import recompute_virtual_time
|
||||
from mcm26b.planner.bayes_loop import BayesLoop
|
||||
from mcm26b.protocol.client import SimulatorClient
|
||||
from mcm26b.sim import LocalSimulator, LocalSimTransport, Source
|
||||
from mcm26b.sim.scenes import random_omni_scene
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--label', required=True)
|
||||
parser.add_argument('--out', type=Path, default=Path('output/q3/optimization-20260911'))
|
||||
parser.add_argument('--suite', choices=('development', 'validation'), default='development')
|
||||
parser.add_argument('--baseline', action='store_true', help='加载输出根目录冻结的baseline_bayes.py及配置')
|
||||
args = parser.parse_args()
|
||||
folder = args.out / args.suite / args.label
|
||||
folder.mkdir(parents=True, exist_ok=False)
|
||||
config = ProblemConfig()
|
||||
loop_cls = BayesLoop
|
||||
if args.baseline:
|
||||
frozen = json.loads((args.out/'baseline_config.json').read_text(encoding='utf-8'))
|
||||
config = replace(config, **{name: replace(getattr(config, name), **values)
|
||||
for name, values in frozen.items()})
|
||||
spec = importlib.util.spec_from_file_location('mcm26b.planner._frozen_baseline',
|
||||
args.out/'baseline_bayes.py')
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
sys.modules[spec.name] = module
|
||||
spec.loader.exec_module(module)
|
||||
loop_cls = module.BayesLoop
|
||||
source_sha256 = {str(p): hashlib.sha256(p.read_bytes()).hexdigest()
|
||||
for p in sorted(Path('src/mcm26b').rglob('*.py'))}
|
||||
if args.baseline:
|
||||
for name in ('baseline_bayes.py', 'baseline_config.json'):
|
||||
source_sha256[str(args.out/name)] = hashlib.sha256((args.out/name).read_bytes()).hexdigest()
|
||||
scenes = []
|
||||
if args.suite == 'development':
|
||||
for count in (10, 16):
|
||||
for seed in range(6):
|
||||
scenes.append((f'random-{count}-{seed}', random_omni_scene(seed, count), 20260910 + seed))
|
||||
edge = [Source(c+1, 1800*math.cos(math.pi/6+2*math.pi*c/count),
|
||||
1800*math.sin(math.pi/6+2*math.pi*c/count), 1000) for c in range(count)]
|
||||
scenes.append((f'boundary-{count}', edge, 20260910))
|
||||
else:
|
||||
for count in (10, 13, 16):
|
||||
for seed in range(100, 106):
|
||||
scenes.append((f'holdout-{count}-{seed}', random_omni_scene(seed, count), 20260910+seed))
|
||||
rows = []
|
||||
for name, sources, error_seed in scenes:
|
||||
sim = LocalSimulator(sources, robot_id='BENCH', config=config, error_seed=error_seed)
|
||||
client = SimulatorClient('BENCH', config=config, transport=LocalSimTransport(sim))
|
||||
start = perf_counter()
|
||||
summary = loop_cls(client, config).run()
|
||||
actions = client.log.action_events()
|
||||
valid = (summary['completed'] and sim.cleared == {s.channel for s in sources}
|
||||
and not summary['anomalies'] and summary['exit_reason'] == 'user_exit'
|
||||
and not recompute_virtual_time(actions)['mismatches']
|
||||
and not ({s.channel for s in sources} & set(summary['absent_channels'])))
|
||||
row = dict(case=name, valid=valid, virtual_s=client.state.virtual_time_s,
|
||||
measures=summary['measures'], clears=summary['clears'],
|
||||
failed_clears=summary['clears']-len(sim.cleared),
|
||||
distance_m=summary['move_distance_m'], wall_s=perf_counter()-start)
|
||||
rows.append(row)
|
||||
(folder / (name+'.json')).write_text(json.dumps(dict(
|
||||
sources=[asdict(s) for s in sources], error_seed=error_seed,
|
||||
summary=summary, actions=actions), ensure_ascii=False), encoding='utf-8')
|
||||
print(f'{name}: valid={valid} T={row["virtual_s"]:.1f} M={row["measures"]}', flush=True)
|
||||
result = dict(config=asdict(config), source='local_simulator_only', baseline=args.baseline, rows=rows,
|
||||
mean_s=mean(r['virtual_s'] for r in rows), median_s=median(r['virtual_s'] for r in rows),
|
||||
max_s=max(r['virtual_s'] for r in rows), valid=sum(r['valid'] for r in rows),
|
||||
under_4000=sum(r['virtual_s'] < 4000 for r in rows),
|
||||
source_sha256=source_sha256)
|
||||
(folder/'results.json').write_text(json.dumps(result, ensure_ascii=False, indent=2), encoding='utf-8')
|
||||
print({k:result[k] for k in ('mean_s','median_s','max_s','valid','under_4000')}, flush=True)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user