Poros maintains an explicit registry of validated transformer architectures.
An architecture is "validated" only after it passes the 0.00e+00 bitwise
parity gate: resident-vs-blockwise comparison at atol=0, rtol=0 on both
loss and adapter weights.
Parity evidence comes in three tiers, and each family's row below names the
tier it actually has (all committed under
docs/validation/):
Full campaign — 200-step gates on all four surfaces (loss, weights,
gradient norms, optimizer state).
Architecture gate — a bitwise gate over 5–50 optimizer steps
(parity is structural, so a short gate is strong evidence, but it is
not the campaign bar; the contributor minimum is 48 steps).
7B–72B validated. Also covers DeepSeek-R1-Distill-Qwen (dense qwen2).
Qwen3
qwen3
0.00e+00
50-step gate
32B gated.
Qwen3.5 / Qwen3.6 (dense)
qwen3_5 / qwen3_5_text
0.00e+00
short gate (5-step)
0.8B–27B; gated on Qwen3.5-4B. Below the 48-step contributor bar; scheduled for a 48+ step gate.
Gemma 3
gemma3 / gemma3_text
0.00e+00
50-step gate
27B gated (gemma-3-27b-pt).
Gemma 4 (dense)
gemma4 / gemma4_text
0.00e+00
50-step gate
31B gated (gemma-4-31B-it). Sliding-window + global hybrid attention handled by per-layer kwargs capture/replay.
Note: Qwen3.6 dense ships model_type: "qwen3_5" in its config.json (the
same pattern as Qwen2.5 shipping qwen2), so both generations resolve to the
one validated registry entry — there is no separate qwen3_6 type to add.
GPU validation matrix
Each architecture's bitwise parity gate (pytest -m gpu tests/test_gpu_parity.py,
torch.equal) has passed on:
Parity gates per the paper's parity matrix (Table 3). A cell is PASS only where
that family's bitwise gate was actually recorded on that GPU; — means not gated
there (not a failure).
The same bitwise gate, re-run per PyTorch stack via
scripts/parity_torch_versions.sh on A100 80GB PCIe, using the smallest
validated checkpoint per family (Qwen2.5-0.5B, Qwen3-0.6B, gemma-3-1b-pt,
gemma-4-31B-it). Raw rows: validation/torch_versions_parity.txt.
Stack
qwen2
qwen3
gemma3
gemma4
torch 2.11.0+cu128
PASS
PASS
PASS
PASS
torch 2.12.0+cu130
PASS
PASS
PASS
PASS
The full-size checkpoints are gated separately, not by this sweep: Qwen2.5-32B
and Qwen3-32B on the A100/B300/PRO 6000 campaigns, and Gemma3-27B and
Gemma4-31B on the RTX 5090 streamed-load sweep (torch 2.11.0+cu128, 50 steps —
validation/streamed-load/sweep/).
Execution modes (SDPA backend selection, TF32, bf16 autocast, torch.compile)
do not change parity either — measured as a resident-vs-blockwise forward
gate plus a reproducibility check, not a full training gate; see
parity-modes.md.
Note: google/gemma-4-12B-it reports model_type: gemma4_unified, which is a
distinct architecture from the validated gemma4 — the registry correctly
refuses it (PorosArchNotValidatedError). It is a roadmap target.
Architecture coverage targets
Family
Status
Notes
Gemma 4 unified (gemma4_unified, e.g. gemma-4-12B-it)
Target
Distinct model_type from the validated dense gemma4; needs its own parity run.
Gemma 4 (MoE)
Target
MoE routing under blockwise residency is unvalidated. Dense first; MoE marked roadmap until measured.
Check a model before you train
poros check Qwen/Qwen2.5-7B # a Hub id (needs huggingface-hub)
poros check ./my-local-model # a local dir with config.json
poros check ./my-local-model/config.json
poros check resolves the model_type from config.jsonwithout loading the
model or importing torch and reports its registry status — validated,
user_asserted (you registered it; runnable, no Poros parity guarantee),
target (roadmap), or not-in-registry — plus what to do next. Exit code is
0 only for validated and 1 for everything else, including
user_asserted, so a CI or agent script can never mistake your own assertion
for a Poros guarantee.
The architecture registry
The registry is a single source of truth (_ARCHITECTURES in
poros/core/arch_registry.py). Read it programmatically:
There are three ways to extend it, in increasing order of permanence. The
first two create user_asserted entries — runnable, but carrying no Poros
parity guarantee. Only the third enters the validated set:
import poros
# 1. At runtime, in your own code (no fork needed) -> user_asserted:
poros.register_architecture("phi3", notes="0.00e+00 on my own 200-step run")
# 2. Via environment, for an ops/CI override without code -> user_asserted:# POROS_USER_ASSERTED_ARCHS="phi3,starcoder2"# 3. Permanently -> validated: add ONE line to _ARCHITECTURES, with a parity# run and a PR. This is the only path into the first-party evidence class.
The notes= field is your own record of what you measured; it does not
change the status. poros check ./my-phi3-model (it takes a model id or directory, not a bare
model_type) will report user_asserted and exit
non-zero after either of the first two.
VALIDATED_BLOCKWISE_ARCH_TYPES remains as a back-compat snapshot of the
built-in set. validated_arch_types() returns the same first-party set and is
deliberately not affected by runtime registration or the environment, which is
what makes it usable as the basis of a parity guarantee. For "what will Poros
agree to run", use runnable_arch_types() (validated + user-asserted); for
what you yourself added, user_asserted_arch_types().
The blockwise_arch_check config field controls behavior for unvalidated
architectures:
"error" (default): raise PorosArchNotValidatedError naming the
supported list. This is the safe default — it prevents training on an
architecture that is neither validated nor user-asserted, where parity is
unknown.
"warn": log a warning and proceed. Use only for validation runs when
testing a new architecture.
"off": skip the check entirely. Not recommended for production.
Layer discovery
Poros searches multiple root candidates and layer paths to locate the
transformer block container. This handles standard layouts (Qwen2,
Qwen3) and nested/vision-language layouts (Gemma3, VLMs).
(For a private/local validation you don't want to upstream, call
poros.register_architecture("phi3", notes="parity 0.00e+00 on my run")
at runtime, or set POROS_USER_ASSERTED_ARCHS — no fork required. Both
create user_asserted entries: Poros will run the architecture, but
the result carries no Poros parity guarantee and prepare() reports
probed_not_validated. validated stays a first-party evidence class
backed by a committed Caistro artifact, and step 3 above — a registry line
plus a PR — is the only way in.)
Add regression tests for the new family.
Submit a PR with the parity test results.
Precision support
Precisions are registered the same way, in poros/core/precision.py
(_PRECISIONS). Only nf4 is stable and carries the bitwise-parity
guarantee in the validated matrix; bf16/fp16 are experimental with no
parity claim; the separate bf16_bitwise runtime is also experimental but
IS bitwise-gated (0.5B and 32B on A100), unoptimized and outside the official
matrix; int8 is planned. poros schema config and selectable_precisions() reflect the
registry, so adding int8 or a LoRA-specific precision in v2 is a one-line
change here plus a load path — no scattering of string literals across the
trainer, model loader, and config.
Design principle
The block manager owns residency only: load, stream, offload, and gradient
routing. It does NOT reconstruct per-layer forward behavior (masks, rotary
embeddings, attention dispatch). Those are pulled from the model's own
modules per forward pass. This ensures any HF architecture's native
behavior is preserved and prevents per-architecture mask/attention bugs.