Skip to content

Classical-ML baseline: quantile GBTs vs the LLM policy - #10

Merged
cosmicbboy merged 5 commits into
mainfrom
worktree-ml-baseline
Sep 7, 2026
Merged

cosmicbboy merged 5 commits into
mainfrom
worktree-ml-baseline

Conversation

@cosmicbboy

Copy link
Copy Markdown
Contributor

Adds the "non-fancy deep learning" baseline the tuned policy must justify itself against.

Approach chosen: quantile gradient-boosted trees

Per the resource-prediction literature — HPC memory-requirement predictors, Slurm ensemble predictors, and Google Autopilot's percentile framing — tree ensembles over engineered features, predicting a high quantile of peak usage so the safety margin is part of the loss:

  • memory: HistGradientBoostingRegressor(loss="quantile", q=0.9) on log2(peak MiB)
  • cpu: quantile 0.75 on cores
  • gpu: classifier over {none, T4, L4, L40S} + a VRAM quantile regressor that picks the cheapest fitting card
  • features: sampled params, input-profile numbers, lexical code flags, author prior, run history — what a scheduler sees without a language model

Options considered and rejected for the first cut

  • Bayesian ridge (μ + k·σ headroom): interpretable, closed-form uncertainty — but linear, and the corpus's param→footprint curves aren't (predictive-uncertainty review)
  • Autopilot-style percentile-of-history: strongest with run history, no cold-start answer; the tune service's ledger-history path already covers that regime
  • k-NN / collaborative filtering over code similarity: needs embeddings to compete — that's the fancy path this baseline exists to contrast

Wiring

  • eval_tuner renders a three-way table (policy vs rule baseline vs ML baseline) incl. GPU-task success, and reports ml_baseline_* keys
  • the lineage dashboard's reward-shape comparison shows the ML $/task-hr beside the policy's
  • driver image gains scikit-learn (baseline trains in-process inside eval, seconds on CPU)

Tests

5 new (162 total passing): feature purity/determinism, grid-snapped proposals, GPU recall >90% with <5% spurious on heldout, and the existence proof — the GBT baseline matches the family-median rule baseline's fit rate with no extra waste in the simulator.

🤖 Generated with Claude Code

https://claude.ai/code/session_016huuSPKsdzj5YwzV846E8e

cosmicbboy and others added 2 commits September 5, 2026 16:47
The 'non-fancy' bar the policy must clear, per the HPC/job-scheduler
resource-prediction literature (Slurm memory predictors, Resource
Central, Autopilot's percentile framing):

- ml_baseline.py: four sklearn HistGradientBoosting models — memory
  quantile(0.9) on log2(peak), cpu quantile(0.75), a GPU-type classifier
  (none/T4/L4/L40S), and a VRAM quantile(0.9) that picks the cheapest
  fitting card. Features a scheduler could see without an LLM: sampled
  params, input-profile numbers, lexical code flags, author prior, run
  history. Alternatives considered: Bayesian ridge (linear — the
  param->footprint curves aren't), Autopilot percentile-of-history (no
  cold-start), k-NN over code (needs embeddings = fancy).
- eval_tuner grows a third comparison column (policy vs rule baseline vs
  ML baseline) + ml_baseline_* report keys; lineage comparison table
  shows the ML $/task-hr next to the policy's.
- tests: purity/determinism, grid-snapping, GPU recall >90% with <5%
  spurious, and the existence proof — quantile GBTs match the rule
  baseline's fit rate with no extra waste on heldout.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016huuSPKsdzj5YwzV846E8e
…cessful task-hr with 99% fit

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016huuSPKsdzj5YwzV846E8e
@cosmicbboy

Copy link
Copy Markdown
Contributor Author

Live three-way result from uvl4sb6j7ttlwvqktwz5 (r8-c-cost checkpoint, 256 heldout, sim scoring):

estimator fit $/task-hr (requested) $/successful task-hr
LLM policy 55% $0.1188 $0.216
rule baseline 43% $0.1717 $0.399
ML baseline (quantile GBT) 99% $0.2163 $0.219

The GBT nearly never fails and ties the LLM on effective cost — full read in the round-10 research-log entry on this branch. The comparison table is now standing in every eval report + the lineage dashboard.

cosmicbboy and others added 2 commits September 5, 2026 18:33
- fit_ml_baseline (driver env, optional corpus arg -> latest artifact):
  fits the quantile GBTs, sim-scores vs the rule baseline on heldout in
  its report, publishes ml_baseline.joblib + manifest as the
  ml-baseline-model artifact; fit-on-new-corpus trigger (inactive)
- MLBaseline.save/load (joblib) + request_to_record (serve-time rows:
  no params/family — features degrade honestly to the cold-start set)
- tune service: lazy-loads the newest ml-baseline-model; estimator
  selection per request (body.estimator) or fleet-wide
  (RT_TUNE_ESTIMATOR); degradation ladder LLM -> ml_fallback ->
  fallback_prior, every rung visible in source; estimator in the cache
  key so A/B arms never share answers; /health + /reload cover it
- gpu image gains scikit-learn; 164 tests passing (joblib round-trip,
  serve-time record shape)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016huuSPKsdzj5YwzV846E8e
…aced ML-load errors in /health

Verified live: estimator=ml -> source=ml_baseline ({'cpu':2,'memory':'512Mi'});
default -> source=model; separate cache digests per arm.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016huuSPKsdzj5YwzV846E8e
@cosmicbboy

Copy link
Copy Markdown
Contributor Author

GBT is now a first-class citizen, verified live on rt-tune:

  • fit_ml_baseline (usgk2plg) fitted on the 500k corpus and published ml-baseline-model v1 (joblib + manifest with sim self-scoring vs the rule baseline in its report)
  • tune service loads it on /reload (ml_baseline_loaded: true in /health) and serves it three ways: {"estimator":"ml"} per request → source=ml_baseline ✅ verified; RT_TUNE_ESTIMATOR=ml fleet-wide; and as the middle rung of the degradation ladder (LLM → ml_fallback → prior)
  • estimator is part of the proposal-cache key — A/B arms never share answers (verified: same context, different digests per arm)

One honest serve-time note: at serve time the GBT sees no params_json/family features (cold-start regime), so its answers there are more conservative than its 99%-fit eval numbers, which include generator params. The eval caveat in the round-10 log covers this.

…thetic-data quality overhaul (#11)

* Round 11: graded JSON reward + capacity, GBT-hint, and full-FT arms

- format_credit ladder (0/.25/.5/.75/1): near-JSON completions earn
  partial format reward instead of scoring like prose — a gradient
  toward the schema (round 7/8 lost 28%/10% of completions with zero
  signal about why). gpu-only failures get their own rung.
- r11-r64-mlp: LoRA r=64 + MLP projections (gate/up/down_proj) — the
  honest capacity test.
- r11-gbt-hint: out-of-fold quantile-GBT estimates ride in the training
  prompt (k-fold so train-time hint quality matches serve-time) AND the
  baseline_relative reward references the GBT's cost — the policy is
  paid for beating the strongest classical estimator. Eval generates
  hints from a train-split GBT; the tune service supplies serve-time
  hints only to checkpoints whose manifest says gbt_hint.
- r11-fullft-06b: FULL fine-tune of Qwen3-0.6B (no adapters, 8-bit
  Adam) — the equal-budget answer to 'does full FT beat a bigger frozen
  base'. Generator + tune service now load full-model checkpoints
  (adapter_config.json detection) alongside adapter ones.
- All arms at r8 scale (4096 ctx / 300 steps, c-cost) for direct
  comparison. 170 tests passing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016huuSPKsdzj5YwzV846E8e

* Harness reports: syntax-highlighted workload code + all output stats

- shared/reporting grows highlight_python (pure-regex tokenizer, Union
  palette, everything HTML-escaped) + code_block (scrollable panel with
  honest truncation note)
- run_generated's FINAL report page now keeps the generated code
  (highlighted, 6k-char cap) alongside the verdict, every measured stat
  (peak RSS / avg CPU / duration / ok / error), and the workload's own
  result dict as a table — previously reset_body() dropped the code and
  the result dict never rendered

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016huuSPKsdzj5YwzV846E8e

* train_tuner: hypothesis_description — why-this-run travels the lineage

Optional markdown note (human- or agent-supplied at launch) stating the
hypothesis a training run tests. Renders at the top of the live training
report (new markdown_block: escaped-first minimal markdown), rides the
checkpoint manifest into the eval report ('Hypothesis this checkpoint was
trained to test') and the dashboard comparison table (hover the reward
shape), and lands in W&B run notes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016huuSPKsdzj5YwzV846E8e

* r11-fullft-32b: biggest single-node full-FT Qwen on the expanded GPU budget

Qwen3-32B full fine-tune on one g6e.48xlarge (8x L40S = 384GB VRAM,
launched via RT_TRAIN_GPU=L40S:8 into flyte.Resources): bf16 weights +
grads + 8-bit Adam ≈ 6B/param ≈ 192GB, naive model-parallel via
device_map. lr 1e-6 (full-FT RL), intra-task saves every 100 steps
(~128GB tarballs; upload timeout raised to 1h), intermediate artifacts
off. Supersedes r11-fullft-06b as the full-FT arm.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016huuSPKsdzj5YwzV846E8e

* Downsize full-FT arm to Qwen3-14B on L40s:4 (g6e.12xlarge provisions; the 48xlarge rarely does)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016huuSPKsdzj5YwzV846E8e

* Full-FT provisioning ladder: pre-stage Qwen3-8B on L4:4 fallback

Ladder (retry upward when nodes provision): L40s:8/32B (git history),
L40s:4/14B (r11-fullft-14b), L4:4/8B (r11-fullft-8b). Same recipe per
rung: 6B/param states, naive MP, lr 1e-6, sparse intra-task saves.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016huuSPKsdzj5YwzV846E8e

* train_tuner: per-component reward trajectory in report + manifest

make_reward_fn accumulates per-step MEANS of every reward component
(format/success/waste/oom/gpu_missing/throttle/knife_edge/savings/
tiebreak + invalid_rate) across stage A/B and shaped paths; the live
report charts each component's trajectory ('which term is moving'),
and the full history rides final_metrics in the checkpoint manifest.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016huuSPKsdzj5YwzV846E8e

* Ladder rung 4: Qwen3-4B full FT on a single L40S (the pool that provisions)

g6.12xlarge burned 10 Karpenter nodeclaims without a ready node (AWS
on-demand capacity); g6e.2xlarge cold-starts routinely. Single GPU also
sheds the naive-MP tax.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016huuSPKsdzj5YwzV846E8e

* Report line charts: full-width + hover-interactive, no JS

- 1200-unit responsive viewBox (width:100%), negative values get real
  axis room with a dashed zero line, legend moves to wrapping HTML (SVG
  legends clipped past ~7 series)
- hover interactivity via pure SVG/CSS: per-step hover columns with a
  crosshair highlight and a native tooltip listing every series' value
  at that step — works wherever the report HTML renders, scripts or not

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016huuSPKsdzj5YwzV846E8e

* Triggers auto-activate on deploy (dark mode stays live)

All three OnArtifact triggers (train-on-new-corpus, eval-on-new-checkpoint,
fit-ml-baseline-on-new-corpus) now declare auto_activate=True; CLAUDE.md
operational note updated with the corollaries (deploys override manual
console pauses; pause via code).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016huuSPKsdzj5YwzV846E8e

* Round 12: synthetic-data quality overhaul (S1-S6)

Fixes the diversity/representativeness/label-fidelity gaps found in the
1M-corpus analysis:

- quality.py (S5): MinHash near-dup rate over PARAMS-normalized code,
  token entropy, footprint grid coverage, family mixture, archetype
  concentration, label-error percentiles — rendered in the release
  report and ENFORCED as gates (enforce_quality)
- scenario-grid prompts (S2): domain x data-shape x structure sampled
  per teacher call, an avoid-list of already-kept descriptions, varied
  durations; multi-teacher support (comma-separated) with parallel wake
- envelope widening (S6): allowlist grows tempfile/io/csv/gzip/scipy/
  pyarrow/etc (harness image gains scipy+pyarrow); multi-phase and
  file-staged workloads invited; GPU archetypes (1-in-8) calibrated on
  T4 oracle pods with real VRAM labels (harness now reports
  torch.cuda.max_memory_allocated)
- label fidelity (S4): calibration = k log-spaced + 2 random full-param
  draws; power-law ParamFit for peak/cpu/duration/vram (old linear fit
  kept as back-compat wrapper); holdout pods measure fit error and
  reject archetypes over holdout_max_err; error distribution reported
- per-variant context (S3): each variant renders its sampled scale into
  input_profile (static profiles were training profile-blindness) and
  gets synthetic prior/history via the shared corpus helpers
- release scale posture (S1): 24h timeout, oracle memory 20Gi, curation
  ceiling 16Gi

180 tests passing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016huuSPKsdzj5YwzV846E8e

* Release survives a teacher that fails to wake

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016huuSPKsdzj5YwzV846E8e

* Generator replicas serve ONE checkpoint at a time (evict + empty_cache on switch)

Round-11 evals timed out: four concurrent evals with four different
checkpoints (2x 4B-class + 2x 1.7B) piled full base models into one T4
via the per-checkpoint engine cache — >16GB, OOM-retry thrash, 1,280
queued calls. Replicas now evict stale engines/batchers when a new
checkpoint arrives.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016huuSPKsdzj5YwzV846E8e

* Diagnose archetype rejections in logs; optional teachers fail fast; 8192-token responses

Round-12 smoke was undebuggable: 0/24 archetypes survived with reasons
only in the report, and a nonexistent glm-5-2 held the run for the full
1800s wake budget leaving 5 min to generate. Now: pre-oracle rejections
print with a response snippet, secondary teachers get a 420s deadline,
and responses get 8192 tokens (the round-12 prompt asks for longer,
multi-phase modules).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016huuSPKsdzj5YwzV846E8e

* Fix round-12 smoke failures: oracle pod sizing, queue budget, os-import conflict, frontier teachers

The 6-archetype smoke found three real bugs:
- calibration pods timed out EN MASSE: 4 CPU / 14-20Gi only fits
  c5.4xlarge (0-5 nodes), so 30 concurrent pods queued past the
  episode-tuned max_queued_time=300. Oracle pods are now 3 CPU / 12Gi
  (fits t3a.xlarge, 3-250 nodes) with a throughput-shaped timeout
  (900s runtime / 3600s queue); curation ceiling tracks the pod at 10Gi
- my own S6 prompt caused 'forbidden import os' rejections by asking for
  tempfile staging; the prompt now names tempfile's API and states that
  importing os discards the module
- prompts also declare the schedulable memory band (150MiB-8GiB) and a
  sub-10-minute runtime bound at range tops
- teachers minimax-m3 + qwen35-397b registered (svc + public): three
  model families writing archetypes is the diversity S2 wants

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016huuSPKsdzj5YwzV846E8e

* Round-11 results: 100% schema validity everywhere; FIRST GATE PASS

- graded format reward eliminated the invalid-completion class outright
  (72% -> 90% -> 100% validity across rounds 7/8/11), which also
  unblocked GPU proposals (0% -> 65-86% GPU fit)
- ambitious Qwen3.5-4B (500k corpus) PASSES the gate: fit 87% vs 56%,
  $40.52 saved per 1k task-hours, GPU fit 77%
- gbt-hint: 93% fit (best) but copied the anchor's cost exactly and lost
  money — anchoring buys reliability, not savings, as weighted
- full FT (4B) beat LoRA on fit 79% vs 53% at lower waste
- r64-mlp is the cautionary arm: cheapest ever ($133/1k saved) at 53%
  fit — the $ metric alone would crown it, the gate's reliability
  clauses stop it

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016huuSPKsdzj5YwzV846E8e

* Teacher wake is order-independent: start on the FIRST ready teacher

Round-12 smoke listed a still-DEPLOYING qwen35-397b first and sat on its
1800s budget while an ACTIVE qwen38-27b idled. Now all teachers wake
concurrently, generation starts as soon as one is ready, and stragglers
get a 300s grace period to join the pool.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016huuSPKsdzj5YwzV846E8e

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
@cosmicbboy
cosmicbboy merged commit 845fdd2 into main Sep 7, 2026
3 checks passed
@cosmicbboy
cosmicbboy deleted the worktree-ml-baseline branch September 7, 2026 02:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant