solvi.lora¶
A LoRA adapter on the decider for one question (experimental): part.adapt_lora(examples), load_lora, remove_lora.
LoRA adapters on the decider, one per question (experimental): part.adapt_lora(examples).
When a question has a hundred labelled answers or more, a shift and a scale on the logits (part.fit) stop improving: they
cannot change what the model reads in the input. A LoRA adapter can: low-rank updates (rank 8) of the encoder's attention
and MLP weights in every layer, plus the last layer of the output head, trained on this question's examples with the
rest of the checkpoint frozen. A gain over fit needs examples: at a few dozen try fit first (it takes
milliseconds), and compare the two on held-out labels. The adapter is 3.2 MB (bf16); training on a CPU takes
minutes (adapt_lora estimates the time after its first update and says so before training), on a GPU seconds.
part = model.decision("team", "Which team?", "email", TEAMS) # DecideModel.load(..., backend="torch")
report = part.adapt_lora(labelled, holdout=300) # 300 of the examples calibrate act_guard
part.save_calibration("team.calib.json") # + team.calib.lora.safetensors beside it
...
part.remove_lora() # roll back
What changes and what does not:
- The adapter is active only while this question is scored; every other question of the same model is scored by the checkpoint as it was (to the bit). Its hash is part of the part's fingerprint (and the model's), and every decision records it in extra["lora"], so a replay knows which weights answered.
- Confidences after LoRA tend to be overconfident (more than after
fit), so the escalation must be recalibrated on labels not used for training:holdout=runs act_guard on them. The question's earlier adaptation and thresholds are cleared: they were fitted on the model without the adapter. - Deterministic for a fixed seed on a CPU (the same examples, seed, torch version and thread count give the same adapter, and the same hash).
- solvi-base-sized checkpoints only; for solvi-large or thousands of examples, tools/adapt_lora_gpu.py (in the solvi
repository, not installed by pip) trains the same adapter on a GPU, and
part.load_lora(path)loads it.
Needs the torch backend and peft: pip install "solvi[lora]".
LoraWarning ¶
Bases: UserWarning
adapt_lora's notices: the time it will take, few examples, no held-out calibration.
LoraAdapter
dataclass
¶
A trained adapter: its tensors (float32 on the CPU, values exact in bf16 — the file stores bf16), its config (rank,
alpha, targets, the question) and what it was trained on (info). hash covers the config and the tensors.
check ¶
Refuse what adapt_lora cannot adapt (ValueError / TypeError / ImportError with what to do instead).
n_updates ¶
Updates of BS examples: epochs passes over k examples, at least 40 and at most max_updates.
train ¶
train(part, rows, *, r=8, alpha=None, epochs=6, lr=0.0003, seed=0, device=None, max_updates=400, notify=None)
Train an adapter on [(text, label)] (labels as part.spec.label gives them) → LoraAdapter. notify(estimate_seconds, updates, seconds_per_update, device) is called after the first update is timed, before training.
adapt ¶
adapt(part, examples, *, r=8, epochs=6, holdout=None, seed=0, device=None, lr=0.0003, max_risk=0.1, signal='confidence', max_updates=400, allow_large=False)
part.adapt_lora (see there). allow_large: in-process training of a checkpoint larger than solvi-base (what tools/adapt_lora_gpu.py passes, on a GPU).
read ¶
An adapter file → LoraAdapter (ValueError if it is not one, or its content does not match its hash).
load ¶
part.load_lora (see there); expect: the hash a calibration file names.