Repository navigation
Step 3 prep: k-shot sampling, validation-only pilots, curve runner, baselines, ModernBERT trial - #7
Merged
Merged
Conversation
Step 3 code, no training runs. The learning-curve protocol lives in configs/curve.yaml and is filled in by hand from the pilots. - sampling: k rows per intent, oos rows from a hardcoded ceil(2.5k) table; k=100 returns the whole train split in its original order. - steps: train for max(min_train_steps, epoch steps); train() checks the steps it ran against the plan and records which rule decided. - runs: resume rules shared by AC2, pilots and curves, plus equivalent_run, which lets an existing run stand in for a curve point only when every field, the rows, the step count and the seed agree. The committed AC2 records are equivalent to BERT k=100 at lr 5e-5. - pilots: lr and S_min pilots on validation only; the scoring and prediction functions raise LeakageError on any other split. - curves: 6 k x 3 seeds per encoder and the ModernBERT OOS ablation, reusing AC2 at k=100 when equivalent; no curve weights are kept. - baselines: majority class and TF-IDF centroid on the same sample as the encoders, archived in the encoder format. - archive format 2 records the SHA-256 of the three split files; format 1 archives are back-filled on read only at the pinned revision. - metrics: Wilson score interval.
50 steps on MPS for ModernBERT-base and bert-base-uncased with the same batch, max_length and step count, then one validation pass; and an ONNX export of the ModernBERT trial model compared with PyTorch on CPU. Results in results/compat/. ONNX tooling is an optional dependency group (uv sync --group onnx), not installed in CI.
PLAN section 4.1 records the S_min and learning-rate pilots, AC2 reuse and the test-isolation rule; acceptance criteria are unchanged. DEVLOG records the ModernBERT trial numbers and the ONNX result. README lists the new make targets and modules.
- pr-text.yml checks the PR title and body (the squash commit's text) on open, edit, push and reopen, through env only; it shares check-disallowed-text.sh and the pattern file with commit-hygiene. - Pilots reuse AC2 without reading test: the archive is hashed whole, only its validation arrays are read, and the record keeps no metrics. - Weights are deleted only after the results JSON, manifest and archive agree; the curve index checks the archive of every trained point. - The curve index compares each run's sample fingerprint with curve_sample now; golden fingerprints pin the sampler in tests. - equivalent_run also requires the same torch and transformers releases; the schedule comparison has its own tests. - TF-IDF scaling documented; RQ3 uses only temperature-scaled signals and the margin for it, and leaves the majority baseline out. - scipy is a direct dev dependency.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Code and a small compatibility trial for step 3. No pilot, curve or baseline results are produced here; those runs come after this merges.
What changes
docs/PLAN.mdsection 4.1,configs/curve.yaml): steps = max(S_min, 5-epoch steps). S_min from {100, 200, 400} (pilot at k=5, seed 42, both encoders, mean val in-scope accuracy, ties to the smaller). Learning rate per encoder from {1e-5, 2e-5, 5e-5} (k=100, seed 42, val in-scope accuracy, then val OOS recall, then the smaller rate). Values are copied intoconfigs/curve.yamlby hand;make curverefuses to start while any is null, and off-grid values are refused on load.sampling.py): exactly k rows per intent; oos rows from the hardcoded table {1:3, 5:13, 10:25, 25:63, 50:125, 100:250}, checked against ceil(2.5k) by a test; k=100 returns the whole train split in its original order; k outside the table raises.steps.py,train.py):min_train_stepsonRunConfig; the plan is computed before training,train()raises if the Trainer ran a different count, and the summary records planned steps, actual steps anddecided_by. Checked against the real HF Trainer on a tiny local model.pilots.py,make pilot-lr,make pilot-steps): validation only.predict_validationandvalidation_scoresraiseLeakageErroron any other split; nothing callsevaluate(). The reused AC2 run is read withreusable_equivalent(..., validation_only=True): the archive file is hashed whole, only its metadata and validation arrays are read, and onlyrun_name,config,training,logitsandenvironmentare kept from its results JSON (nometrics). Output inresults/pilots/*.json.runs.equivalent_run): an AC2 run stands in for BERT k=100 only if every config field is equal after two stated rewrites (no sampling equals k=100 with 250 oos rows; an S_min that does not decide changes nothing), and the AC2 record's own train rows, oos rows, global_step and seed match, and it was made with the torch and transformers releases installed now. The archive's SHA-256 must agree in the results JSON, the manifest and on disk. Tested against the three committed AC2 records.curves.py,make curve MODEL=bert|modernbert,make oos-ablation): resume with the AC2 rules, keep no weights, writeresults/curves/<name>.jsonwith the logits SHA-256 and step plan per point.baselines.py): majority class (log training prior, constant per query) and TF-IDF centroid (100 x cosine) on the same (k, seed) sample as the encoders, archived and scored in the encoder format.dataset_revisionis the pinned one; otherwise refused.metrics.wilson_interval, checked against hand values and scipy.ModernBERT trial (M4, MPS, 50 steps, batch 32, max_length 64)
Full 5-epoch estimate for ModernBERT is about 24 minutes per seed (AC2's measured BERT time x 1.69; the short trial underestimates BERT by about 2.6x, see DEVLOG). ONNX export works with both
torch.onnx.exportexporters; ONNX Runtime CPU vs PyTorch max abs logit difference 2.1e-5 on 10 rows and 1.1e-5 on a batch of another shape. ONNX packages are in an optionalonnxgroup; CI does not install them.Checks
make lint,make test(317 passed),make test-network(7 passed),make smoke,make verify-logits(the 3 AC2 archives still load as format 1).Review fixes (second round)
pr-text.yml(pr-text-hygiene) runs on opened, edited, synchronize and reopened, and checks the PR title and body, which become the squash commit. Title and body reach the shell only throughenv. It shares.github/scripts/check-disallowed-text.shand.github/disallowed-trailers.txtwithcommit-hygiene.docs/OPERATIONS.mdnotes the remaining gap (text typed into the merge dialog).NpzFileread and finds notest_*key, and the pilot still runs and picks the same values when the donor JSON has nometrics.test_sampling.py; the curve index compares each run's recorded fingerprint withcurve_sample(k, seed)drawn now and refuses a mismatch; reused AC2 points get the fingerprint computed now, marked as such.max_steps=2385,num_train_epochs=4.999); torch and transformers releases must match (a+cpubuild label is ignored).