Data & Training Strategy¶
Status: Implemented (M4) and executed full-scale on the RTX 3060 12GB (English + multilingual
LoRA, 6k train / 1.5k eval, temperature calibration; measured numbers in benchmarks/report.md).
Related: docs/adr/ADR-0005-encoder-rlcd.md, .specs/features/training-calibration/spec.md.
Objective¶
Produce a local encoder backend that answers noul / choice / score in a single forward
pass, in 100+ languages, with calibrated probabilities — trainable and reproducible on a
single RTX 3060 12GB.
Pipeline overview¶
graph LR
A["generate_data.py<br/>synthetic JSONL"] --> B["finetune_rlcd.py<br/>LoRA/QLoRA + RLCD"]
B --> C["fit_calibration.py<br/>temperature / ECE"]
C --> D["evaluate.py<br/>accuracy, ECE, latency"]
D --> E["checkpoint + model card"]
Every stage is a committed script with a committed config and a fixed seed.
1. Data generation (training/generate_data.py)¶
Goal: deterministic, streamed synthetic supervision for the three primitives.
- Determinism: same seed + config → byte-identical output.
- Streaming: write JSONL incrementally; never hold the full dataset in memory.
- Coverage: per primitive, per language group, with hard negatives and boundary cases (near-ties, ambiguous labels, empty/very long inputs).
- Localization (B-1): the
state,instructions,criteria,scorelevels, andnoul/scoreentities are all authored per language (training/data/lexicon.json,phrases.json,team_descriptions.json), so the multilingual checkpoint does not learn an English template. - Input-noise augmentation (B-4):
--noise-rate r(config fieldnoise_rate) applies one deterministic surface edit — char swap/delete, accent strip, casing flip, or terminal-punctuation drop — torof records'stateonly (labels/questions untouched).r=0reproduces the clean dataset byte-for-byte; each record draws from its own RNG ((seed, kind, index, language, noise)) so noise stays independent of the cyclic label (L-003). Evaluate the noisy view separately: the harness reports it underreport["noisy"]when--noise-rateis passed.
JSONL record format¶
{"id": "noul-000001", "type": "noul", "state": "…", "instructions": "…", "criteria": {"true": "…", "false": "…"}, "target": 1, "lang": "en", "source": "synthetic"}
{"id": "choice-000001", "type": "choice", "state": "…", "instructions": "…", "criteria": {"a": null, "b": "…"}, "target": "b", "lang": "pt", "source": "synthetic"}
{"id": "score-000001", "type": "score", "state": "…", "instructions": "…", "criteria": ["poor","fair","good"], "target": 2, "lang": "es", "source": "synthetic"}
| Field | Meaning |
|---|---|
id |
Stable unique id |
type |
noul / choice / score |
state |
The judged subject |
instructions |
The atomic question |
criteria |
Primitive-specific options/levels |
target |
Label (0/1, option key, or level index) |
lang |
Language tag for routing/stratification |
source |
Provenance (synthetic, public, human) |
Data sources¶
- Synthetic generation (primary, deterministic).
- Public datasets for evaluation probes (MASSIVE, XNLI, typed-decisions) — evaluation only, never training, to keep benchmark claims honest.
- Optional human-curated seed sets for hard cases.
2. Fine-tuning (training/finetune_rlcd.py)¶
Goal: adapt ModernBERT-class (English) and mmBERT-base (multilingual) encoders with three task heads, within 12GB VRAM.
Architecture¶
- Shared encoder trunk.
- Three heads:
noul(binary logit),choice(logits over options),score(logits over levels). - Heads are trained jointly; the trunk is shared.
Parameter-efficient training¶
| Technique | Why |
|---|---|
| LoRA (or QLoRA with 4-bit base) | Fits 12GB; small trainable footprint |
| Gradient checkpointing | Trades compute for memory |
| Gradient accumulation | Effective batch size without VRAM blowup |
| Mixed precision (bf16/fp16) | Speed + memory |
| Length-sorted batching | Fewer padding tokens |
VRAM budget notes (RTX 3060 12GB)¶
- Full fine-tuning of large encoders is not feasible; LoRA/QLoRA is required.
- Two checkpoints are trained separately (English, multilingual), not simultaneously.
- If a config OOMs, reduce per-device batch first, then sequence length, then LoRA rank.
- Exact ceilings are measured and documented in M4-T6 (see B-002).
3. RLCD proper-scoring calibration (training/finetune_rlcd.py)¶
Goal: calibrated probabilities, not just correct labels.
- Train against a strictly proper scoring rule (e.g., log loss / Brier) over the primitive
distributions. A proper scoring rule is minimized in expectation by reporting the true
probability — this is what makes
confidencemeaningful. - RLCD (reinforcement learning against the scoring rule) shapes the distribution beyond accuracy-only supervision.
- Probabilities are normalized before leaving the backend.
Why proper scoring: accuracy-only training produces overconfident, miscalibrated
distributions. Proper scoring directly optimizes the quantity users consume (confidence).
4. Calibration fitting (training/fit_calibration.py)¶
Goal: minimize ECE on a held-out calibration split.
- Fit a single temperature (or per-primitive temperatures) on a calibration split.
- Per-(primitive, language) temperatures (B-1, implemented):
fit_calibration.pykeeps the per-primitive fit and adds a per-language fit underby_language; the runtime selectskind:lang→kind→ global, detecting the language from the state text. A language belowmin_sampleswarns and falls back to the per-primitive value. - Never fit on the test split.
- Report ECE before/after; target is provisional (NFR-C06,
ECE ≤ 0.05[open]). - Persist the fitted temperature with the checkpoint.
5. Evaluation (benchmarks/ + training/evaluate.py)¶
Report per primitive and per language group:
| Metric | Definition |
|---|---|
| Accuracy | Correct label rate |
| ECE | Expected calibration error over confidence bins |
| Latency | p50 / p95, batch=1 and batched |
| Throughput | requests/s vs batch size |
| Coverage | Languages/scripts exercised |
Public probes: MASSIVE, XNLI, typed-decisions — evaluation only and not yet run;
what is published today is the external nine-family pngwn/system-one-decisions head-to-head
(docs/compare.md §3, 2026-09-26). Committed reproduction commands cover the synthetic
evaluation only (see docs/benchmarks.md → Known limitations).
6. Reproducibility¶
- Every stage takes a config file (seed, hyperparameters, data paths) committed under
training/configs/. - Re-running with the same seed/config must land within documented tolerance.
- Artifacts record: git commit, hardware, library versions, seed, command.
- No secrets or private data in configs or artifacts.
Limitations & risks¶
| Limitation | Impact | Mitigation |
|---|---|---|
| RTX 3060 12GB | Bounds model size and batch | LoRA/QLoRA, checkpointing, accumulation |
| Synthetic data bias | Model inherits generator biases | Mix sources; human seed sets; eval on public probes |
| Small calibration sets | Noisy temperature fit | Stratify; warn on small N; hold out test |
| Multilingual imbalance | Weak languages | Stratify generation; per-language ECE reporting; per-language temperature (B-1) |
| Two checkpoints | Memory pressure | max_loaded, LRU eviction (ROUTE-04) |
Open questions¶
- OD-3: weights distribution — RESOLVED by
docs/adr/ADR-0010(HF Hub on demand + local cache; prefetch withhf downloador a warm-up run, cache-only viaTACHYONE_OFFLINE=1). - Exact ECE target and binning scheme — resolved by the measured target (ECE ≤ 0.05,
10 bins,
min_samples30) used inbenchmarks/report.md. - Whether the typed-decisions checkpoint is trained — deferred; tracked as
BACKLOG.mdB-7.