twanghcmut/backup-VR-SmallVLA / onf-c5 /docs /technical /06-config-reference.md
twanghcmut's picture
|
download
raw
24.2 kB

06. Config reference

Reads: nothing — reference chapter Writes: nothing Code: src/onf/graph/core/schema.py, src/onf/config.py, evals/common/modes.sh Stage: BUILD and RUNTIME Read after: 05-artifacts.md

Every constant and every environment variable, organised by subsystem. Two kinds of knob:

kind where it lives changed by
frozen src/onf/graph/core/schema.py, or a module-level constant in the owning module editing the source and rebuilding the artifact
env a from_env() factory in src/onf/config.py, or one of the four documented exceptions exporting a variable before the run

schema.py's flat names (COARSEN, HIST_H, …) are aliases derived from DEFAULTS, never literals. Change the dataclass default; the flat name follows.

GraphConfig / SentinelConfig mirror many of schema.py's values as their defaults and expose them as GR_* / SN_* variables. A knob listed as env therefore has two ways to move: edit schema.py (changes the default everywhere, including training) or export the variable (changes this run only). The provenance column below describes the shipped value.

Provenance is CHOSEN (picked, no derivation on record), DERIVED (computed or measured from something else, with the derivation stated), or -- (not determinable from the code or the existing docs — not guessed).


6.1 Graph build

Frozen in schema.py. Every one of these invalidates g_nodes.npz / g_edges.npz, and therefore graph_hash, and therefore every head and kernel fit against them.

constant value env C/D what breaks if it changes
COARSEN 5 GR_COARSEN CHOSEN raw frames per node; every node id renumbers
PSI_FREQS 4 -- time-encoding octaves; node_in_dim = 15 + 2·psi_freqs, so the head's input layer width
GRIP_OPEN_THR 0.035 CHOSEN closed-gripper threshold; moves every coarsening cut and every grip label
PHASE_CONV "arange(T)/(T-1) full" CHOSEN stamped into g_nodes.npz and re-checked on load; a mismatch raises
DILATIONS (1,2,4,8,16) DERIVED 3 × 16 × 5 = 240 raw frames of reach ≈ p50 long demo length
RELATIONS / REL_INDEX / N_RELATIONS 12 names, order load-bearing DERIVED from DILATIONS; rel is an index into this order, so reordering silently re-labels every edge
K_SIBLING 8 GR_K_SIBLING CHOSEN kNN out-degree of sibling; also the lateral-mixing density the tracker's M_sib inherits
K_ALIGN 4 GR_K_ALIGN CHOSEN kNN out-degree of align
NBINS_ALIGN 20 CHOSEN one bin = 0.05 phase; shared by align bucketing, the phase-CE loss, basin cells and the sentinel's end-of-task gate
CDIST_BS 2048 CHOSEN torch.cdist row-block size; memory/throughput only
KERNEL_BW 0.15 rad GR_KERNEL_BW CHOSEN joint-space kernel bandwidth for edge weights and for seeding
GEO_SCALE 0.5303 ONF_GEO_SCALE DERIVED calibrated so median f over LODO node distances matches the trained field's median f on the same graph; read only under ONF_CLEANLINESS=geo

SUITE_HDF5_DIRS (src/onf/graph/build/from_demos.py) maps suite names to HDF5 directories: object → libero_object, spatial → libero_spatial, goal → libero_goal, long → libero_10 (not libero_long). CHOSEN — it is the upstream LIBERO layout.


6.2 Retrieval head

Network and query shape (frozen, schema.py)

constant value env C/D what breaks if it changes
HIDDEN 64 GR_HIDDEN CHOSEN every weight tensor; g_head.npz no longer loads
LAYERS 3 GR_LAYERS CHOSEN message-passing depth; weights are shared across layers, so depth is stored as a 0-d scalar in the checkpoint, not implied by shapes
AGG "sum" GR_AGG CHOSEN "logsumexp" with m = −cost recovers DTW's soft-min
AGG_TEMP 1.0 -- logsumexp temperature; inert under agg="sum"
HIST_H 8 GR_HIST CHOSEN query window W; equals one policy action chunk
SEG_K 8 GR_SEG_K CHOSEN reference-segment length; a point target restores q but not qdot
SEED_TOPK 256 GR_SEED_TOPK CHOSEN nodes given a nonzero h0; everything else stays exactly 0
SEED_VEL_W 2.0 GR_SEED_VEL_W CHOSEN exponent on the velocity-direction factor in seeding; 0 disables it
ADVANCE 0 raw frames DERIVED the head answers "where am I now"; the transition kernel owns how far forward, and its fitted mixture already advances E[a] = 9.6 raw frames per 8-step check

Objective weights (frozen, schema.py)

constant value env C/D what breaks if it changes
PHASE_CE_W 1.0 GR_PHASE_CE_W CHOSEN primary term: CE on the 20-bin phase marginal
PHASE_EXPECT_W 0.5 GR_PHASE_EXPECT_W CHOSEN primary term: phase-expectation regression
NODE_W 0.1 GR_NODE_W CHOSEN auxiliary node-identity BCE+rank; strand identity is only 8–15% learnable
PHASE_BIN_SMOOTH_W 1.0 CHOSEN ±1-bin smoothing mass on the phase-CE target
PHASE_BIN_SMOOTH_T 1.0 CHOSEN smoothing decay `exp(−
WHERE_PHASE_BAND 0.05 GR_WHERE_PHASE_BAND CHOSEN multi-positive candidate band; one NBINS_ALIGN bin, same width as the deployed entry band
WHERE_MOVE_TEMP 0.1 GR_WHERE_MOVE_TEMP CHOSEN softmax temperature on inverse movement cost in the soft target
WHERE_TRUE_BONUS 2.0 CHOSEN multiplicative boost on the true continuation

Curriculum (frozen, src/onf/graph/train/data.py)

constant value C/D what breaks if it changes
N_NEG 16 CHOSEN mined hard negatives per query, across buckets (a)/(b)/(c)
SELFX_K 16 CHOSEN local kNN pool searched for the self-intersection bucket
SELFX_PHASE_GAP 0.15 CHOSEN `
ENTRY_FRAC 1/3 CHOSEN share of the non-static queries drawn as ENTRY
ENTRY_LO_MULT / ENTRY_HI_MULT 0.25 / 50.0 DERIVED radius range is (0.25·p50, 50·p99) of the measured LODO demo-start noise floor
ENTRY_LOGUNIFORM True DERIVED the range spans two decades; a linear draw puts ~90% of mass in the top decade
ENTRY_STATIC_FRAC 0.15 CHOSEN drawn first, before the ENTRY coin flip, so it is a share of all queries; without it the deployed t=0 window shape never appears in training
ENTRY_STATIC_BAND 0.05 CHOSEN phase band of the static class's soft-target pool; matches GR_ENTRY_BAND exactly
ENTRY_STATIC_NODE_W 1.0 CHOSEN replaces node_w on static rows (their phase terms are trivial — the whole pool is in bin 0)
ENTRY_STATIC_SRC_AUX_W 0.0 CHOSEN the source-node warm-up would fight the uniform-over-pool target

Loss terms (frozen, src/onf/graph/train/loss.py)

constant value C/D what breaks if it changes
ALPHA_BCE 0.3 CHOSEN node term is 0.3·BCE + 0.7·RANK, the whole of which NODE_W then demotes
SRC_AUX_W 0.05 CHOSEN weight of the kNN-solvable "predict the source node" warm-up
ABSTAIN_W 0.5 CHOSEN weight of the abstain decision term
ABSTAIN_MARGIN 1.0 nats CHOSEN margin on the exact statistic inference reads, abstain_logit − logits[reached].max()
ABSTAIN_NODE_MAX_FALLBACK 0.0 nats CHOSEN keeps the margin defined when nothing is reachable
REL_INIT_STD 0.02 CHOSEN relation-embedding init (net/modules.py)
LOG_W_EPS 1e-12 CHOSEN floor inside softmax(log w) pooling

Training loop (frozen, src/onf/graph/train/loop.py)

constant value env C/D what breaks if it changes
N_QUERY 4096 CHOSEN queries generated per stage
N_EVAL 128 CHOSEN held-out queries for the per-epoch report
HELDOUT_STRIDE 5 CHOSEN split is by demo strand, never by frame — adjacent frames leak
LR / WEIGHT_DECAY 1e-3 / 1e-5 CHOSEN AdamW
GUARD_MRR_TOL 0.01 CHOSEN admissibility gate; an epoch that quietly degrades clean retrieval cannot become "best"
stages (1,) CHOSEN stages 2 and 3 were deleted; any other value raises
qbatch 8 GR_QBATCH -- queries per forward/backward; pure throughput — the loss returns a batch mean, so the per-query learning rate is unaffected

Readout, at retrieval time

knob default env C/D what breaks if it changes
READOUT_ARMS ("euc_raw", "basin") CHOSEN the registry; euc_raw is the t=0 arm, basin the t>0 arm
GraphConfig.readout "euc_raw" GR_READOUT CHOSEN which arm consumes `p(v
GraphConfig.temp 1.0 GR_TEMP -- readout softmax temperature
GraphConfig.topm 32 GR_TOPM -- candidate nodes kept for readout; ENTRY widens it to the whole surviving pool so the mask is not re-truncated
GraphConfig.seed_decay 0.9 GR_SEED_DECAY CHOSEN temporal decay 0.9^k over the query window during seeding
GraphConfig.idf 1.0 GR_IDF -- exponent on the additive log_idf prior (GFM-RAG eq. 15–16)
GraphConfig.move_cost True GR_MOVE_COST CHOSEN passes the movement-cost channel through at deploy so train and deploy see the same input
GraphConfig.entry_band 0.0 (off) GR_ENTRY_BAND CHOSEN masks candidates to phase ≤ band
GraphConfig.task_prior_w 0.0 (off) GR_TASK_PRIOR_W CHOSEN nats of additive task log-prior the belief filter's own task marginal contributes when the text lane resolved nothing; 1.0 is the plain Bayesian value. Consulted only in the no-lane case, so the six axes whose lane resolves are bit-unchanged
GraphConfig.device "" = auto GR_DEVICE CHOSEN CPU and CUDA disagree by up to ~1e-4 rad elementwise
GraphConfig.graph_dir "" GR_GRAPH_DIR overrides Paths.graph()

6.3 Sentinel (t > 0)

Frozen in schema.py

constant value env C/D what breaks if it changes
TRACK_ADVANCE_SET (0,1,2,4,6,8,12,16) DERIVED (upper end) raw-frame advances mixed by the kernel. 0 is mandatory and validated — it is the stall self-loop. 16 ≈ 2× the nominal check spacing, because rollouts run longer and slower than the median demo
TRACK_KERNEL_RELATIONS next1..next16 + sibling CHOSEN excluding align and every prev^d is the asymmetry that suppresses the measured 8% backwards aliasing
TRACK_BELIEF_TOPK 2048 -- belief entries kept when a readout is handed to host memory
BASIN_RADIUS_QUANTILE 0.95 DERIVED p95 of LODO NN distances → the certified radius r
BASIN_BANDWIDTH_QUANTILE 0.50 DERIVED p50 of the same → the KDE bandwidth / stop-short margin h
BASIN_MIN_DEMOS 2 CHOSEN cells with fewer distinct demos inherit the per-task median r/h

r_eff = max(r − h, 0) is DERIVED. π, β and leak are DERIVED — fitted by onf.graph.build.tracker_fit and stored in g_track.npz, not in any config.

SentinelConfig, SN_* (env)

field default env C/D what breaks if it changes
check_every 8 SN_CHUNK DERIVED _POLICY_CHUNK = 8. A value that does not divide the chunk is refused: the client executes a cached chunk open-loop, so a check landing mid-chunk cannot influence the plan already in flight
graph_win 8 SN_GRAPH_WIN DERIVED must equal HIST_H
graph_stride 0 → 1 SN_GRAPH_STRIDE DERIVED _TRAIN_WINDOW_STRIDE = 1. Training windows are 8 consecutive raw frames (finite_diff_vel is a 1-frame backward difference); stride 8 would hand the net ~8× the velocity magnitude it ever saw. Any other value is refused
graph_topm 32 SN_GRAPH_TOPM -- candidate nodes kept before readout
graph_temp 1.0 SN_GRAPH_TEMP -- readout softmax temperature
blend_alpha 0.0 SN_BLEND_ALPHA CHOSEN weight on the tracking chunk. 0.0 is bit-exactly the frozen policy — BlendPlan.apply returns the chunk untouched — so a SENTINEL=1 run at the default reproduces base numbers exactly. Unread under blend_learned
blend_learned False SN_BLEND_LEARNED CHOSEN read the per-row, per-block weight off the trained AlphaNet in g_alpha.npz instead of using blend_alpha. A missing file raises: a run that silently measures a different mechanism than the one it was asked for is worse than a run that does not start
blend_scale 1.0 SN_BLEND_SCALE DERIVED multiplier on the LEARNED weight, unread unless blend_learned. The chunk-MSE objective fits the right per-check shape at too confident a level, so the head is rescaled onto the average authority a fixed weight was measured at. Derived per head, never copied: the deployed 0.27 is 0.31 × 0.372/0.425, matching the base-frame head's deployed mean to the previous head's — chapter 03 §3.6
blend_bound 0.0 SN_BLEND_BOUND DERIVED action-unit saturation of a_track's row 0, bound·tanh(row0/bound); 0 disables it, which is what the measured fixed-alpha cells ran with. 1.0 is the value the simulator's own [-1, 1] action clip implies. Under blend_learned this is unread and the bound is ACTION_LIMITchapter 03 §3.5
action_scale_path "" SN_ACTION_SCALE metres/radians per action unit. "" resolves to action_scale.json beside the graph artifacts; a missing file raises, naming scripts/fit_action_scale.py. There is no default calibration: a wrong scale mis-drives the arm silently
allow_stride_mismatch False SN_ALLOW_STRIDE_MISMATCH CHOSEN opt-out of the stride guard. A field, not a bare env read inside the guard, so asdict(cfg) records that a run disabled a safety check
allow_misaligned False SN_ALLOW_MISALIGNED CHOSEN opt-out of the chunk-alignment guard, same reasoning
graph_device "" = auto SN_GRAPH_DEVICE CHOSEN
graph_dir "" SN_GRAPH_DIR overrides Paths.graph()

scripts/build_sentinel_artifacts.py (frozen, CLI-overridable)

constant value CLI flag C/D what breaks if it changes
HELD_OUT_STRIDE 5 --held-out-stride CHOSEN owner % 5 == 0 is held out (100/500 on long); the kernel fit set shrinks or grows
FIT_CLEAN_STRIDE 3 --fit-clean-stride CHOSEN wall-clock bound on the clean half of the fit set
N_DRIFT_SEQ / N_CROSS_STRAND_SEQ 80 / 80 --n-drift / --n-cross-strand CHOSEN the two regimes that make β identifiable; on clean-only sequences β = 0 is correct and the fit is uninformative
DRIFT_SEQ_SEED 0 CHOSEN reproducibility of the sampled sequences
N_PROBE_DEMOS 40 CHOSEN sanity-probe sample size (debug only)
BURNIN_CHECKS_MIN 3 CHOSEN probe burn-in
PROBE_PHASE_FRAC 0.5 CHOSEN probe mid-episode

6.4 Action-chunk blend

The runtime knobs are SentinelConfig fields, listed in §6.3 — the blend is issued by the sentinel's plan(). What follows is everything else the mechanism is parameterised by. Full reasoning: chapter 03.

Frozen in src/onf/blend/ee_track.py and src/onf/blend/alpha.py

constant value C/D what breaks if it changes
ACTION_DIM / POSE_DIM / GRIP_COL 7 / 6 / 6 CHOSEN the OSC action layout. GRIP_COL is copied through, never mixed: the command is binary
DEFAULT_MIN_R2 0.8 CHOSEN ActionScale.check's bar. A rotation block below it usually means the delta was subtracted rather than composed in the world frame
_SMALL_ANGLE 1e-3 rad CHOSEN the Taylor branch of the Rodrigues trig quotients; under autograd it also keeps the gradient finite
ACTION_LIMIT 1.0 DERIVED row-0 saturation amplitude, applied to the tracking chunk and to the regression target alike. LIBERO clips the executed action to [-1, 1] and real demo actions max at 0.938. A constant, not a parameter: the one run that learned it drove it to 24.5
HIDDEN (AlphaNet) 64 CHOSEN width of the one hidden layer. Stored in g_alpha.npz, so changing it does not break loading old heads
N_BLOCK 2 CHOSEN weights per chunk row: one for position, one for rotation. 1 would re-merge the two blocks
N_SCALAR 3 DERIVED off-manifold distance, top-1 posterior mass, posterior entropy
EXPECT_K 32 DERIVED expected_ee_segment's support width; matches ReadoutContext.topm

The two fitted scales are not constants — ActionScale is read from action_scale.json. Measured values are in chapter 03 §3.4.

Weight training (frozen, src/onf/graph/train/corrupt.py, align.py, loss.py)

constant value C/D what breaks if it changes
p_wrong_task / p_offset / p_wrong_phase 0.10 each CHOSEN share of training rows given a deliberately wrong retrieval. At 0 the alpha gradient is one-sided and alpha can only learn arm displacement
phase_tol 0.05 CHOSEN WRONG_TASK's node must be this close in phase, so the failure is a genuine alias
phase_min 0.15 CHOSEN WRONG_PHASE's node must be at least this far
offset_m (0.05, 0.25) m CHOSEN OFFSET's displacement magnitude: an object's own width to a shelf away
ALIGN_H 0.05 m CHOSEN mean warped DTW distance below which two segments count as the same path (~a gripper width)
CHUNK_PHASE_CE_W 0.2 CHOSEN the CHUNK objective's anti-collapse regulariser
CHUNK_ALIGN_W 0.1 CHOSEN weight of the DTW alignment teacher, against an MSE term of 1.0

6.5 Paths and process environment

src/onf/config.py::Paths. Resolution order is: explicit argument, then the variable, then repo-local.

root / method fallback env
Paths.data <repo>/data ONF_DATA
Paths.results <repo>/results ONF_RESULTS
Paths.outputs(*parts) <repo>/outputs ONF_OUTPUTS
Paths.fwm(suite) data/fwm/ for object/default, else the fwm_dir from configs/suites.yaml, else data/fwm/<suite> QNDF_DIR (wins outright)
Paths.graph(suite) outputs/<suite>/latest/artifacts GR_GRAPH_DIR (wins outright)
Paths.hdf5(name) first existing of data/libero_hdf5/<name>, data/libero_datasets/<name>

_HDF5_ROOTS = ("libero_hdf5", "libero_datasets") is CHOSEN — a historical two-batch split that configs/suites.yaml does not record.

The three env reads that live outside config.py

Deliberate: none of them is a run knob these dataclasses carry.

variable default read in effect
ONF_CLEANLINESS field graph/core/geometry.py::CleanlinessConfig.from_env geo swaps the trained field for the weight-free GeometricField
ONF_GEO_SCALE GEO_SCALE = 0.5303 same distance scale of that stand-in
SN_GRAPH_TRACE_DIR unset sentinel/sentinel.py per-episode .npz debug trace sink; read once at construction, never on the control path

Mandatory for every run

export PYTHONPATH=src OMP_NUM_THREADS=4

6.6 Modes

evals/common/modes.sh::onf_set_mode is the only definition of a mode. scripts/run_sr.py::parse_mode_recipes parses this file rather than re-declaring the recipes, so every arm must stay shaped as name) export VAR=val ... ;; — no control flow inside an arm, one export per arm (backslash continuations are fine).

mode exports what it is for
base nothing frozen policy, no intervention. A reporting baseline, not an ablation
blend SENTINEL=1, SN_BLEND_ALPHA=0.0 the plumbing check. Bit-identical to base; a cell that differs here is a bug, not a result
blend_a05 SENTINEL=1, SN_BLEND_ALPHA=0.5, GR_GRAPH_DIR at the ADVANCE=0 head the first fixed-alpha probe (../results.md §5, superseded — but still the best arm on Camera_Viewpoints)
blend_a015 as above at 0.15 how much of blend_a05's loss is intervention magnitude rather than a wrong blend direction
blend_bounded as above at 0.3, plus SN_BLEND_BOUND=1.0 everything the blend gained except the learned weight — the row-0 bound and the task-lane fix — held at a fixed alpha so a gap left here is one alpha has to close
blend_a015_bounded as above at 0.15 the best FIXED weight measured: 262/312 = 84.0% on Objects_Layout, the bar the learned weight has to clear
blend_scaled015 SENTINEL=1, SN_BLEND_LEARNED=1, SN_BLEND_SCALE=0.31, GR_GRAPH_DIR at the v3 Stage-2 artifacts the learned weight's shape at the authority a fixed weight was measured at — 88.1% on Objects_Layout
blend_full as above with SN_BLEND_SCALE=0.27, GR_TASK_PRIOR_W=1.0 and the base-frame v4 head the current recipe. 7-axis total +7.9 pp (../results.md §6)

evals/common/modes.sh carries a dozen further probe arms with the measurement that motivated each in its comment; the table above is the ladder, not the inventory.

The fixed-alpha blend arms pin GR_GRAPH_DIR at the ADVANCE=0 head on purpose: under the old +4 head the feedforward rows of a_track aim ~13.6 frames ahead on an 8-frame chunk, which a position-restoring servo absorbed and a feedforward blend does not (chapter 02 §2.4, chapter 03).


6.7 Easy to get wrong

  1. Assigning a literal to a flat schema.py name. The flat names are aliases derived from DEFAULTS; a literal creates a second source of truth that can drift from the dataclass the validation lives on.
  2. Changing a §6.1 constant and reusing an old head. Anything in that table renumbers nodes or re-labels edges, so graph_hash changes and every stamped artifact must be rebuilt. The loader will refuse — see chapter 05 §5.2.
  3. Setting SN_GRAPH_STRIDE from SN_CHUNK. They are independent. check_every is how often you check; graph_stride is the spacing within the window. Setting stride to 8 gives the network ~8× the velocity it trained on. The guard refuses it; SN_ALLOW_STRIDE_MISMATCH=1 silences the guard, not the problem.
  4. Exporting a SN_CHUNK that does not divide 8. Refused for the same class of reason: a check landing mid-chunk cannot influence the chunk already in flight.
  5. Adding a tuning knob as a bare os.environ.get. A knob that is not a field on one of the two dataclasses does not appear in the run's config.json, so the run record cannot say what it was set to. The two SN_ALLOW_* opt-outs are fields precisely for this reason.
  6. Running a blend mode without checking which action_scale.json it resolved. The blend converts metres and radians into action units; the calibration carries no graph_hash and no suite stamp, so a file fitted on another suite loads without complaint and rescales every action the arm executes.
  7. Setting SN_BLEND_ALPHA or SN_BLEND_BOUND under blend_learned. Both are unread there: the trained head owns the weight and ACTION_LIMIT owns the bound. A run that appears to set a knob it does not set is worse than one that sets nothing.

Next: ../results.md — what these settings measure, or back to the README.

Xet Storage Details

Size:
24.2 kB
·
Xet hash:
33d1809e7ba28d19e1c11e9bff5ceb66ee30d5177d629fe55feddb8d455fe9cf

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.