Test-time training
August 4, 2026 ยท View on GitHub
FastPLMs provides an opt-in ProteinTTT adaptation path for supported sequence
models and the ESMC language-model backbone in ESMFold2. Model construction,
inference, embedding, folding, and state_dict() do not adapt the model.
Mechanism
For one protein sequence, TTT samples masked views, computes the masked-language-model loss, and updates only injected low-rank adapter parameters. Base checkpoint parameters stay frozen. Returned metrics record per-step loss and each enabled evaluation value.
Tokenizer-based paths use the tokenizer assets and immutable revision attached to the loaded checkpoint.
metrics = model.ttt(
seq="MSTNPKPQRKTKRNT",
ttt_config={
"steps": 3,
"ags": 1,
"batch_size": 1,
"seed": 7,
},
)
model.ttt_reset()
ttt_reset() restores the initial adapter state. With
initial_state_reset=True, each ttt() call begins from that initial state.
Seeded tests compare mask sampling, losses, updated parameter scope, reset, and
checkpoint state.
Adapter initialization uses the TTT seed and does not advance the caller Python, NumPy, CPU Torch, or CUDA RNG streams. Random BERT-style replacements use only the 20 canonical biological amino acids for the family. They do not use other vocabulary entries, boundary tokens, or structure modalities. An uneven final sample batch stays finite and uses its actual valid count.
Main controls
TTTConfig sets the learning rate, optimization steps, gradient accumulation,
sample batch size, mask ratio, crop size, BERT-style leave and replacement
probabilities, optimizer, seed, low-rank width and scale, target modules,
reset, optional step evaluation, and gradient clipping.
lora_alpha is a direct multiplier on the low-rank adapter output. It is not
divided by lora_rank. This intentionally matches the pinned ProteinTTT call
inject_trainable_lora(..., scale=lora_alpha) and differs from the common PEFT
LoRA alpha / rank convention. The direct scale is serialized with the TTT
configuration, so changing this interpretation would alter reloaded adapters.
FastPLMs rejects a change to low-rank width, scale, or target modules after adapter initialization because the change would alter the parameter schema.
Save and reload
Initialized adapter tensors, their reset baseline, and normalized TTT
configuration are part of save_pretrained:
from transformers import AutoModelForMaskedLM
model.ttt(seq="MSTNPKPQRKTKRNT", ttt_config={"steps": 3, "seed": 7})
model.save_pretrained("adapted", safe_serialization=True)
reloaded = AutoModelForMaskedLM.from_pretrained(
"adapted",
trust_remote_code=True,
local_files_only=True,
)
reloaded.ttt_reset()
Reload preserves the adapted state and the deterministic reset state. Models with adapters on transient modules outside checkpoint state fail closed. They require a model-specific export and do not silently drop adaptation.
Folding
ESMFold2 exposes a family-specific opt-in folding helper. Adaptation affects only its language-model backbone. ESMFold2 uses canonical BF16 ESMC weights before a gradient-enabled path. If serving selected FP8, entering TTT reloads canonical BF16 weights while preserving the requested serving policy in configuration and status metadata.
Meta ESMFold does not expose TTT. Its pinned checkpoint contains the folding
language model but no trained masked-language-model head for the ProteinTTT
objective. ttt(), ttt_reset(), fold_protein(ttt=True), and
fold_protein_ttt() therefore raise explicitly. FastPLMs does not construct or
serialize an untrained replacement head.
Limitations
TTT increases latency and GPU memory. It can worsen a prediction. It is not a calibration method and does not establish biological function. Compare the unadapted output, record complete seeds and configuration, and validate on an independent task-specific set before you make a scientific conclusion.
Boltz2 is inference-only in FastPLMs. The manifest and feature suite define the model families that advertise TTT.