Usage
poros.prepare — the one-line drop-in
copy markdownOne call that makes an existing HF model train blockwise:
import poros
model = poros.prepare(model) # patched in place; returns the same object
... # use your normal HF Trainer / loop
poros.unprepare(model) # restores the model (see below)unprepare restores the model itself: original layers swapped back,
offloaded weights reloaded, use_cache and gradient-checkpointing toggles
reverted. One thing stays: when prepare ran with determinism on, the
process-global deterministic-algorithms / math-SDPA settings remain in
effect (a CUBLAS_WORKSPACE_CONFIG change after cuBLAS initializes would
not apply anyway). Call torch.use_deterministic_algorithms(False) if you
need the fast paths back in the same process.
prepare wraps the engine-level patch_hf_model and adds: precision
detection, an adapter safety gate, architecture validation, and a
structured report. It never touches your training config and never predicts
VRAM. Importing it needs no torch; calling it does.
What prepare decides for you
| Decision | Default behavior | Override |
|---|---|---|
| Precision | Detects what the model is actually loaded as (HF quantization_config, else dominant param dtype). Only positively-detected NF4 earns the bitwise label; a mismatch warns and uses the detected value. | precision="nf4"|"bf16"|"fp16" |
| Adapter | Auto-detects (PEFT, native LoRA); detection is authoritative. Full fine-tune is refused (see gate below). | adapter= is advisory except "unsafe_any_trainable" |
| Architecture | Validated set → validated_bitwise. Anything else is checked from config only (no parity probe runs in this release) and reported probed_not_validated with no parity claim. | architecture="validated_only"|"probe"|"off" |
block_size | Fixed validated default 4 — never guessed from VRAM (it's a memory↔speed knob, never parity). Clamped to the layer count. | block_size=<int> |
The guarantee label
model._poros_report.guarantee after prepare:
validated_bitwise— positively detected NF4 + validated arch + a strictlyvalidatedadapter (plain PEFT LoRA/QLoRA;compatibleDoRA/RSLoRA/modules_to_saverun fine but cap atsmoke_only) + zero non-adapter trainables + deterministic path. The 0.00e+00 claim applies.probed_not_validated— arch is not in the first-party validated set (including architectures you registered yourself asuser_asserted); ran without a parity claim. No runtime parity probe is performed in this release; the label reflects config inspection only.smoke_only— ran, no parity claim.none— an unsafe override (e.g. full fine-tune) disabled the guarantees.
Gates that raise before wasting a run
| Error | Trigger | Escape hatch |
|---|---|---|
PorosFullFinetuneDetectedError | trainable params are not adapter params | freeze the base + attach LoRA, or unsafe_allow_full_trainable=True (guarantee → none) |
PorosAdapterUnsupportedError | experimental adapter under guarantee="validated" | validated adapter, or unsafe_allow_unvalidated_adapter=True |
PorosArchitectureUnsupportedError | unvalidated arch under validated_only/guarantee="validated" | validated arch, or architecture="probe" |
PorosGuaranteeUnavailableError | guarantee="validated" and ANY validated_bitwise condition is unmet (the error lists which) — "validated" delivers the guarantee or refuses, never a silent downgrade | fix the listed condition, or guarantee="best_effort" to proceed at the weaker label deliberately |
PorosAlreadyPreparedError | second prepare() with different block_size/guarantee/architecture/precision | poros.unprepare(model) first; same-args re-prepare is a no-op |
Useful extras
prepare(model, dry_run=True)— full report, no patch.prepare(model, output_dir=...)(or atrainer=withargs.output_dir) — writesporos_run.jsonnext to your checkpoints. Itsmemory.batch_size,memory.gradient_accumulation_steps, andmemory.seq_lenfields are recorded from the trainer's args when you passtrainer=, and arenullotherwise --nullmeans "not recorded", never a default. (seq_lenstaysnullfor a bare HFTrainer: sequence length lives in the collator there, not the args.)verbose=True(default) prints a one-screen summary of every decision above.- Sampling from a prepared model is correct but slow. The streamed blocks
hold no KV cache, so Poros turns
use_cacheoff at prepare/patch time andmodel.generate()recomputes the full prefix each step (bitwise-equal to a resident run, just slower; forcinguse_cache=Trueraises rather than returning wrong tokens). For fast generation, callporos.unpatch_hf_model(model)first, or load the saved adapter onto a fresh base as inexamples/inference.py. stack=(env doctor at prepare-time) is not active in this build; it warns rather than report a result it hasn't checked. Useporos doctor.
Adapter statuses and what they mean: adapters.md. Engine-level
surface (patch_hf_model): api.md.