In-House Model Training (Wave C)¶
CONCEPT:AU-AHE.evaluation.adaptive-reasoning-effort — Training Substrate · CONCEPT:DS-ECO.mcp.model-training — Model Training Operations Part of the cross-repo In-House Training Substrate.
data-science-mcp owns the corpus + gradient-trainer half of the framework's
self-training stack: it turns execution traces into SFT/DPO/GRPO datasets and
fine-tunes open-weight models against them. Everything except the GPU fine-tune
runs is deterministic and CPU-testable; the real runs target the GB10 box.
Layers¶
1. Deterministic data / reward engine (no GPU)¶
data_science_mcp/training_data.py — pure-Python builders reusing the
agent-utilities reward spine (agent_utilities.graph.training_signals):
| Builder | Output | Source paper |
|---|---|---|
build_sft_examples |
{prompt, completion} |
OpenSeeker / MeMo |
build_preference_pairs |
{prompt, chosen, rejected, failure_point} |
MedCausalX |
build_grpo_groups |
group-normalized advantages | ATLAS / SDAR |
filter_by_difficulty / score_reward |
data-quality + composite reward | OpenSeeker / ATLAS |
MCP tools: build_training_dataset, compose_reward (tag model-training).
2. Gradient trainers (data-science-mcp[training])¶
Install the extra (pip install .[training] → torch / transformers / peft /
bitsandbytes / httpx). Modules under data_science_mcp/:
trainers/objectives.py— torch loss kernels: masked cross-entropy, sequence log-prob, Bradley-Terrydpo_loss, group-relativegrpo_surrogate(+ token-masked LA-GRPO), Schulman-k3approx_kl.trainers/base.py—TrainConfig+TrainerBase: a pureplan()(step/batch accounting, no torch) and dependency-injectable model/tokenizer so the loop is CPU-smoke-testable on a toy model.trainers/{sft,dpo,grpo}_trainer.py— concrete trainers implementing thetraining_data.TrainerProtocol.peft_manager.py—LoraSpec/PeftManager(LoRA/QLoRA, lazy peft) + pure-numpyties_merge(MeMo multi-adapter merge, CPU).tokenizer_registry.py— special/functional-token injection + embedding resize.rollout_buffer.py— prompt→generation→logprob→reward staging withVLLMRolloutClient(generations served by the running vLLM) + GRPO export.trainers/eval_hooks.py— score a checkpoint with the AHE-3.1 reliability suite (agent_utilities.harness.reliability_scorers).
MCP tools: train_sft, train_dpo, train_grpo, merge_adapters_ties. They are
plan-by-default — they return the training plan and only run when called with
options.execute=true (and torch present).
3. Rust performance path¶
The loss/optimizer kernels also exist in pure Rust in epistemic-graph
(client.datascience.{softmax,cross_entropy,dpo_loss,grpo_surrogate,kl_divergence,adam_step,sgd_step}),
so a trainer can batch a step over the wire in one round-trip. Same math as
trainers/objectives.py; torch is the default, Rust is the optimization.
Example¶
from data_science_mcp import training_data as td
from data_science_mcp.trainers import get_trainer, TrainConfig
# 1) Build an SFT corpus from traces (deterministic, no GPU).
examples = td.build_sft_examples(traces)
# 2) Plan the run (pure — no torch needed to inspect it).
trainer = get_trainer("sft", TrainConfig(base_model="Qwen/Qwen2.5-1.5B-Instruct",
epochs=1, batch_size=8))
print(trainer.plan(examples)) # {planned_steps, effective_batch, ...}
# 3) Run it (needs data-science-mcp[training] + a GPU for a real base model).
report = trainer.train(examples) # {steps, losses, final_loss, ...}
End-to-end pipeline + deploy seam (Wave D)¶
data_science_mcp/training_pipeline.py ties the whole flow into one call:
traces → SFT corpus → plan → train → reliability-eval → save checkpoint
→ register as a ModelDefinition bound to a role (goes live)
from data_science_mcp.training_pipeline import run_sft_pipeline, DeploymentTarget
from data_science_mcp.trainers import TrainConfig, peft_manager # peft via [training]
from data_science_mcp.peft_manager import LoraSpec
from agent_utilities.models.model_registry import ModelRegistry
# OpenSeeker SFT on the GB10: Qwen2.5-1.5B + LoRA, served by the local vLLM.
report = run_sft_pipeline(
TrainConfig(
base_model="Qwen/Qwen2.5-1.5B-Instruct",
output_dir="/models/openseeker-sft",
epochs=1, batch_size=8, lr=2e-4,
lora=LoraSpec(r=16, alpha=32), # LoRA; quant_4bit=True for QLoRA
),
traces=openseeker_trajectories, # ~10k synth trajectories (data engine)
eval_cases=reliability_eval_cases, # AHE-3.1 internalization/safety checks
registry=my_registry, # the live ModelRegistry
deploy=DeploymentTarget(
role="generator",
served_model_name="qwen2.5-1.5b-openseeker",
base_url="http://localhost:8000/v1", # the running vLLM
),
checkpoint_id="openseeker-sft-v1",
)
The pipeline returns a structured report (data/plan/train/eval/
checkpoint/deployment). Omit registry/deploy for a train-only run; omit
model/tokenizer to load the real HF base (a toy model can be injected for a CPU
smoke).
Deploy seam¶
register_checkpoint (called by the pipeline) appends a ModelDefinition for the
checkpoint and binds the target role to it via a unique tag, so
model_registry.pick_for_role(role) (and therefore create_model(role=…)) resolves
to the new model — no hot-path edit. Serve the checkpoint through the running
vLLM. Re-deploying the same checkpoint_id is idempotent.
Build-now / run-later¶
Everything above is CPU-smoke-tested end-to-end on a toy model
(tests/test_training_pipeline.py). On the GB10 the only deltas are: pin
Blackwell torch/peft/bitsandbytes/vllm, point base_model at the real
checkpoint, and run on the GPU. The orchestration, evaluation, and deploy seam are
identical.
Build-now / run-later¶
| Layer | Status |
|---|---|
| Data/reward engine | ✅ runnable now (no GPU) |
| Trainers (loss kernels + loops) | ✅ CPU-smoke-tested on a toy model |
| Real fine-tunes | ⛔ GB10 (pin Blackwell torch/peft/bnb/vllm); first run = OpenSeeker SFT |
See WAVE_C_INFRA.md
for per-paper GB10 requirements.
High-Caliber LLM Trainer (CONCEPT:AU-AHE.trainer.high-caliber-llm-trainer…006)¶
The substrate above is hardened into a full LLM trainer: robust fine-tuning at
scale, a corpus curation engine, pretraining a model from random init, and an
agent-driven workflow that runs the whole loop. See the SDD spec at
.specify/specs/llm-model-trainer/.
Robustness & throughput knobs (CONCEPT:AU-AHE.trainer.high-caliber-llm-trainer)¶
TrainConfig gained additive fields (defaults reproduce the original behaviour
exactly). They flow through one shared optimisation loop, trainers/loop.py::run_loop:
| Field | Effect |
|---|---|
precision (fp32/fp16/bf16) |
AMP autocast (+ GradScaler on fp16) |
grad_accum |
gradient accumulation → larger effective batch |
max_grad_norm |
gradient clipping |
warmup_steps + lr_scheduler (cosine/linear/…) |
HF get_scheduler (default constant) |
gradient_checkpointing |
activation checkpointing (memory↓) |
attn_impl="flash_attention_2" |
FlashAttention-2 (needs [training-scale]) |
use_liger |
fused Triton kernels (needs [training-fast]) |
save_steps / save_total_limit / resume_from |
periodic checkpoints + resume |
distributed (fsdp/deepspeed) |
sharded multi-GPU (see below) |
tracker (mlflow/wandb) + kg_log |
experiment tracking + KG mirror |
Scale-out: FSDP and DeepSpeed (CONCEPT:DS-AHE.trainer.concept-4)¶
Both are first-class peers via trainers/accelerate_launch.py (🤗 Accelerate). For a
real multi-GPU/-node run, generate a launch config and command with
data_science_mcp.launch:
from data_science_mcp.launch import (
fsdp_accelerate_config, deepspeed_zero3_config, write_config, build_launch_command)
write_config(fsdp_accelerate_config(num_processes=8, mixed_precision="bf16"), "fsdp.yaml")
cmd = build_launch_command("data_science_mcp.trainers.pretrain_trainer",
distributed="fsdp", num_processes=8, config_file="fsdp.yaml")
# multi-node: same call + num_machines/machine_rank/main_process_ip (homelab OR cloud)
flash-attn and deepspeed are GPU-host installs ([training-scale], need the
CUDA toolchain) — not CI/CPU-installable.
Corpus curation engine (CONCEPT:DS-AHE.trainer.data-engine)¶
data_engine.py — data quality is what separates good models from bad ones:
stream_corpus— list /.jsonl/.txt/ 🤗datasets(streaming=True).dedup— exact (content-hash) + near-duplicate (cosine/LSH). The all-pairs search is offloaded to the epistemic-graph Rustfind_similar_pairswhen a live engine is present, with a local-cosine fallback. Embeddings use a deterministic hashing vectorizer — no embedding model required.decontaminate— drop training records that leak held-out eval examples.quality_filter,pack_sequences(packed pretrain windows),dataset_provenance(aDatasetVersionlineage node, optionally mirrored into the KG).
MCP tools (tag data-engine): curate_corpus, dedup_corpus,
decontaminate_corpus, dataset_lineage.
Pretrain from random init (CONCEPT:DS-AHE.trainer.concept-2)¶
For genuinely new models (≤~1.5B in a homelab; scale the spec up on cloud GPUs):
from data_science_mcp.training_pipeline import run_pretrain_pipeline
from data_science_mcp.trainers import TrainConfig, PretrainSpec
report = run_pretrain_pipeline(
TrainConfig(output_dir="/models/tiny-lm", max_seq_len=2048, precision="bf16",
lr=3e-4, warmup_steps=2000, lr_scheduler="cosine",
save_steps=1000, distributed="fsdp"),
corpus=curated_records, # {text} records from the data engine
spec=PretrainSpec(hidden_size=1024, num_hidden_layers=24, num_attention_heads=16,
max_position_embeddings=2048),
train_tokenizer_first=True, # BPE tokenizer trained on the corpus
)
The model is built with random weights (AutoConfig → from_config, not
from_pretrained); tokenizer_trainer.py trains a byte-level BPE tokenizer first.
MCP tools: train_tokenizer, pretrain_model (plan-first like the fine-tuners).
Agent-driven training (CONCEPT:AU-AHE.trainer.concept-2)¶
The whole loop is exposed as an agent workflow. Four agent personas (prompt JSONs in
agent-utilities/agent_utilities/prompts/): data_curator, training_engineer,
eval_judge, ml_orchestrator. They are bound into the model_training_team
TeamConfig and driven by the train_model workflow skill
(universal-skills/.../workflows/ml/train_model/):
prepare_corpus → curate/dedup/decontaminate → (train_tokenizer) →
train(sft|pretrain) → eval → gate → align(dpo|grpo) → eval → gate →
merge_adapters → final_eval → register_model
Run it via graph_orchestrate(action="execute_workflow", name="train_model", task=…).
Benchmark evaluation (CONCEPT:DS-AHE.trainer.concept-5)¶
Alongside the AHE-3.1 reliability suite, eval_hooks.evaluate_benchmarks(model_path,
tasks) scores a checkpoint on EleutherAI lm-eval tasks ([eval] extra; graceful
no-op when absent).
Compute reality¶
"High-caliber from scratch" at frontier scale is a capital problem, not a code one — nobody pretrains a frontier LLM in a homelab. The realistic targets here are (a) robust SFT/DPO/GRPO of 1.5B–8B bases (QLoRA fits one 24 GB card; FSDP/DeepSpeed for full FT) and (b) genuine pretraining of small models (≤~1.5B). Given the homelab GPU situation, plan for cloud-burst GPUs for anything larger — the launcher targets both from one command. All code is CPU-unit-tested on a toy model; GPU runs are validated on a GPU host, not in CI.
Build-now / run-later (LLM trainer)¶
| Layer | Status |
|---|---|
| Data curation engine | ✅ runnable now (no GPU) |
| Trainer hardening (precision/accum/clip/sched/ckpt/resume) | ✅ CPU-smoke-tested |
| Pretrain-from-scratch loop | ✅ CPU-smoke-tested on a toy model |
| Agent workflow (personas + team + skill) | ✅ compiles + validates |
| FSDP / DeepSpeed multi-GPU, flash-attn, real pretrain | ⛔ GPU host (configs + launcher ready) |