skip to content

Usage

poros.prepare — the one-line drop-in

copy markdown

One 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

DecisionDefault behaviorOverride
PrecisionDetects 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"
AdapterAuto-detects (PEFT, native LoRA); detection is authoritative. Full fine-tune is refused (see gate below).adapter= is advisory except "unsafe_any_trainable"
ArchitectureValidated 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_sizeFixed 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 strictly validated adapter (plain PEFT LoRA/QLoRA; compatible DoRA/RSLoRA/modules_to_save run fine but cap at smoke_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 as user_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

ErrorTriggerEscape hatch
PorosFullFinetuneDetectedErrortrainable params are not adapter paramsfreeze the base + attach LoRA, or unsafe_allow_full_trainable=True (guarantee → none)
PorosAdapterUnsupportedErrorexperimental adapter under guarantee="validated"validated adapter, or unsafe_allow_unvalidated_adapter=True
PorosArchitectureUnsupportedErrorunvalidated arch under validated_only/guarantee="validated"validated arch, or architecture="probe"
PorosGuaranteeUnavailableErrorguarantee="validated" and ANY validated_bitwise condition is unmet (the error lists which) — "validated" delivers the guarantee or refuses, never a silent downgradefix the listed condition, or guarantee="best_effort" to proceed at the weaker label deliberately
PorosAlreadyPreparedErrorsecond prepare() with different block_size/guarantee/architecture/precisionporos.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 a trainer= with args.output_dir) — writes poros_run.json next to your checkpoints. Its memory.batch_size, memory.gradient_accumulation_steps, and memory.seq_len fields are recorded from the trainer's args when you pass trainer=, and are null otherwise -- null means "not recorded", never a default. (seq_len stays null for a bare HF Trainer: 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_cache off at prepare/patch time and model.generate() recomputes the full prefix each step (bitwise-equal to a resident run, just slower; forcing use_cache=True raises rather than returning wrong tokens). For fast generation, call poros.unpatch_hf_model(model) first, or load the saved adapter onto a fresh base as in examples/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. Use poros doctor.

Adapter statuses and what they mean: adapters.md. Engine-level surface (patch_hf_model): api.md.