comma controls challenge: sim-calibrated feedforward + PID (72.3 vs 110.3 baseline)
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
"""Coordinate-descent tuner for controllers/karti.py against the TinyPhysics sim.
|
||||
Deterministic (sim is seeded per-segment), so the search is noise-free.
|
||||
Runs to COST_END_IDX only (identical cost to a full rollout) to save compute.
|
||||
"""
|
||||
import json
|
||||
import sys
|
||||
import numpy as np
|
||||
from pathlib import Path
|
||||
from multiprocessing import Pool
|
||||
|
||||
from tinyphysics import TinyPhysicsModel, TinyPhysicsSimulator, COST_END_IDX
|
||||
from controllers.karti import Controller
|
||||
|
||||
MODEL_PATH = './models/tinyphysics.onnx'
|
||||
ALL = sorted(Path('data').glob('*.csv'))
|
||||
TUNE = ALL[:80] # fast search set
|
||||
VAL = ALL[80:480] # held-out validation
|
||||
|
||||
_model = None
|
||||
def _init():
|
||||
global _model
|
||||
_model = TinyPhysicsModel(MODEL_PATH, debug=False)
|
||||
|
||||
def _eval_one(args):
|
||||
seg, params = args
|
||||
sim = TinyPhysicsSimulator(_model, str(seg), controller=Controller(params), debug=False)
|
||||
while sim.step_idx < COST_END_IDX:
|
||||
sim.step()
|
||||
c = sim.compute_cost()
|
||||
return (c['total_cost'], c['lataccel_cost'], c['jerk_cost'])
|
||||
|
||||
def evaluate(params, segs, pool):
|
||||
res = np.array(pool.map(_eval_one, [(s, params) for s in segs]))
|
||||
return res[:, 0].mean(), res[:, 1].mean(), res[:, 2].mean()
|
||||
|
||||
GRIDS = {
|
||||
'ff_scale': [0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3],
|
||||
'kp': [0.0, 0.05, 0.1, 0.2, 0.3],
|
||||
'ki': [0.0, 0.02, 0.05, 0.1],
|
||||
'kd': [-0.08, -0.05, -0.02, 0.0],
|
||||
'preview': [0, 1, 2, 3, 4],
|
||||
'int_clip': [0.5, 1.0, 2.0],
|
||||
}
|
||||
ORDER = ['ff_scale', 'kp', 'ki', 'kd', 'preview', 'int_clip']
|
||||
|
||||
def main():
|
||||
cur = dict(ff_scale=1.0, kp=0.10, ki=0.05, kd=-0.02, preview=2, int_clip=1.0)
|
||||
cache = {}
|
||||
def ev(params):
|
||||
key = tuple(sorted(params.items()))
|
||||
if key not in cache:
|
||||
cache[key] = evaluate(params, TUNE, pool)
|
||||
return cache[key]
|
||||
|
||||
with Pool(4, initializer=_init) as pool:
|
||||
base = ev(cur)
|
||||
print(f"start {cur} -> total={base[0]:.3f} (lat={base[1]:.3f} jerk={base[2]:.3f})", flush=True)
|
||||
for it in range(2):
|
||||
print(f"\n===== pass {it+1} =====", flush=True)
|
||||
for name in ORDER:
|
||||
best_v, best_cost = cur[name], ev(cur)[0]
|
||||
for v in GRIDS[name]:
|
||||
if v == cur[name]:
|
||||
continue
|
||||
trial = dict(cur); trial[name] = v
|
||||
cost = ev(trial)[0]
|
||||
tag = ""
|
||||
if cost < best_cost:
|
||||
best_cost, best_v, tag = cost, v, " <-- best"
|
||||
print(f" {name}={v!s:<7} total={cost:.3f}{tag}", flush=True)
|
||||
cur[name] = best_v
|
||||
print(f" => {name} := {best_v} (total={best_cost:.3f})", flush=True)
|
||||
|
||||
tcost = ev(cur)
|
||||
print(f"\nFINAL params: {cur}", flush=True)
|
||||
print(f"TUNE(80): total={tcost[0]:.3f} lat={tcost[1]:.3f} jerk={tcost[2]:.3f}", flush=True)
|
||||
vcost = evaluate(cur, VAL, pool)
|
||||
print(f"VAL(400): total={vcost[0]:.3f} lat={vcost[1]:.3f} jerk={vcost[2]:.3f}", flush=True)
|
||||
Path('scratch/best_params.json').write_text(json.dumps(cur, indent=2))
|
||||
print("saved scratch/best_params.json", flush=True)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user