Files
lora-lite/docs/audit/variants_review_v3.md
T
copilot 55757e829d fix V3 review must-fixes: DoRA bias passthrough + EVA load path
V3 external review (docs/audit/variants_review_v3.md, 97KB) found 3
must-fix bugs.

DoRA: bias was being scaled by m/||V|| because we operated on the full
base layer output. Now subtract bias before normalization, add back
after. Matches peft DoRA exactly (docs/refs/peft_lora_dora.py:157-161).
New smoke dora_bias_smoke verifies identity at t=0 with bias=True.

EVA load: adapter.load() called attach() which called group_init() which
required calibration_data and raised. Added _skip_group_init flag to
attach(); load() passes it. EVA group_init still raises loudly when
called directly without data. New smoke verifies save+load WITHOUT
calibration data on load path.

Also tightened EVA error message.

Smoke now covers 8 variants + EVA roundtrip + DoRA-bias roundtrip + bnb
4/8-bit. ALL PASS.

V3 nice-to-haves (PiSSA scaling, AntiPaSTO init choice, stale GH refs)
deferred -- documented as intentional in module docstrings.
2026-04-26 19:50:48 +08:00

1671 lines
95 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
[client] initialize (running)
[client] session/new (running)
Ill use the `gsd` workflow because this is a multi-step audit, plus the repos local AGENTS instructions you pasted. Im going to read the variant/runtime files and the relevant skill instructions first, then compare each module against its local refs and live links.
[tool] Read SKILL.md (running)
input: {"call_id":"call_wNiPFhdnB1WBW8omQwnkCZZz","process_id":"49611","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","sed -n '1,220p' /home/wassname/.claude/skills/gsd/SKILL.md"],"cwd":"/me...
files: /home/wassname/.claude/skills/gsd/SKILL.md
[tool] Run git status --short (running)
input: {"call_id":"call_Y2GWC695I6QVJq1SlrwGzpjU","process_id":"56247","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","git status --short"],"cwd":"/media/wassname/SGIronWolf/projects5/2026/l...
[tool] List /media/wassname/SGIronWolf/projects5/2026/lora-lite/lora_lite (running)
input: {"call_id":"call_qs5ejtYjuQgiZd7VjFAvs439","process_id":"70787","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","rg --files src/lora_lite tests docs/refs"],"cwd":"/media/wassname/SGIro...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/lora_lite
[tool] Read SKILL.md (completed)
kind: read
input: {"call_id":"call_wNiPFhdnB1WBW8omQwnkCZZz","process_id":"49611","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","sed -n '1,220p' /home/wassname/.claude/skills/gsd/SKILL.md"],"cwd":"/me...
files: /home/wassname/.claude/skills/gsd/SKILL.md
output:
sed: /tmp/.mount_vscodiOHg5sd/lib/x86_64-linux-gnu/libselinux.so.1: no version information available (required by sed)
---
name: gsd
description: "Get Shit Done workflow for non-trivial tasks: spec -> implement -> test -> review -> wrap. Mandatory for anything with more than one step."
---
<!--
Design rationale and sources — for human readers, not the agent.
- GSD spec-first: spec-driven development, scope fencing, verify-before-done
- Manus file-as-memory: one file is working memory, checklist is state, append-only log
- Boomerang: return concrete artifacts not summaries
- DCP: invisible dedup, superseded writes, error purging
Core principles:
- Spec file is the only persistent artifact (single-file invariant).
- Agent shouldn't know about its own resource limits.
- Review scales with input size: frontier for plans, cheap for bulk.
- Observable outputs: show evidence, not narration.
-->
# GSD (Get Shit Done)
Mandatory for all non-trivial tasks (more than one step). Skip only for single-line fixes.
## Part 1: Core workflow
### 1.1 Spec-first planning
... (192 more lines)
[tool] Run git status --short (completed)
kind: execute
input: {"call_id":"call_Y2GWC695I6QVJq1SlrwGzpjU","process_id":"56247","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","git status --short"],"cwd":"/media/wassname/SGIronWolf/projects5/2026/l...
output:
?? docs/audit/REVIEW_PROMPT_VARIANTS_V3.md
?? docs/audit/variants_review_v3.md
[tool] List /media/wassname/SGIronWolf/projects5/2026/lora-lite/lora_lite (completed)
kind: search
input: {"call_id":"call_qs5ejtYjuQgiZd7VjFAvs439","process_id":"70787","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","rg --files src/lora_lite tests docs/refs"],"cwd":"/media/wassname/SGIro...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/lora_lite
output:
src/lora_lite/__init__.py
src/lora_lite/variant.py
src/lora_lite/config.py
src/lora_lite/adapter.py
tests/test_lora_lite.py
src/lora_lite/variants/ia3.py
tests/smoke.py
src/lora_lite/variants/lora.py
src/lora_lite/variants/dora.py
src/lora_lite/variants/delora.py
src/lora_lite/variants/__init__.py
src/lora_lite/variants/hra.py
src/lora_lite/variants/pissa.py
src/lora_lite/variants/eva.py
src/lora_lite/variants/antipasto.py
src/lora_lite/target.py
docs/refs/peft_lora_dora.py
docs/refs/orig_pissa_init.py
docs/refs/baukit_nethook.py
docs/refs/peft_eva.py
docs/refs/peft_lora_layer.py
docs/refs/peft_delora_layer.py
docs/refs/peft_lora_variants.py
docs/refs/orig_delora.py
docs/refs/antipasto3_svd_adapter.py
docs/refs/peft_hra_layer.py
docs/refs/orig_hra_layer.py
docs/refs/peft_ia3_layer.py
... (17 more lines)
I found two untracked audit files already present, so Ill leave them untouched and treat the repo as read-only for this review. Next Im pulling numbered source listings and the offline refs so the final can cite exact lines instead of hand-waving.
[tool] Read lora.py (running)
input: {"call_id":"call_gMlEVjLyAI4tEO17fDRNFYdy","process_id":"32210","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","nl -ba src/lora_lite/variants/lora.py"],"cwd":"/media/wassname/SGIronWo...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/src/lora_lite/variants/lora.py
[tool] Read lora.py (completed)
kind: read
input: {"call_id":"call_gMlEVjLyAI4tEO17fDRNFYdy","process_id":"32210","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","nl -ba src/lora_lite/variants/lora.py"],"cwd":"/media/wassname/SGIronWo...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/src/lora_lite/variants/lora.py
output:
1 """Vanilla LoRA. Hu et al. 2021 https://arxiv.org/abs/2106.09685
2
3 h = W x + (alpha/r) B A x
4
5 Identity at t=0 from B=0. Faithful to the paper.
6
7 Reference implementations (for review/cross-check):
8 - peft Linear.update_layer + lora_A/B init, forward:
9 https://github.com/huggingface/peft/blob/main/src/peft/tuners/lora/layer.py
10 (see docs/refs/peft_lora_layer.py for offline copy)
11 """
12 from einops import einsum
13 from torch import nn
14 import torch
15
16 from ..variant import register, ParamSpec
17
18
19 @register
20 class LoRA:
21 name = "lora"
22
23 @staticmethod
24 def param_specs(d_in, d_out, cfg):
25 return {
26 "lora_A": ParamSpec((cfg.r, d_in), init="kaiming", trainable=True),
27 "lora_B": ParamSpec((d_out, cfg.r), init="zeros", trainable=True),
28 }
... (13 more lines)
[tool] Read pissa.py (running)
input: {"call_id":"call_DJiZUptMa5DJfJiqjcVAbgMf","process_id":"25734","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","nl -ba src/lora_lite/variants/pissa.py"],"cwd":"/media/wassname/SGIronW...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/src/lora_lite/variants/pissa.py
[tool] Read delora.py (running)
input: {"call_id":"call_yYuKd7kdZxGCZo8zkQtSGEiW","process_id":"76438","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","nl -ba src/lora_lite/variants/delora.py"],"cwd":"/media/wassname/SGIron...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/src/lora_lite/variants/delora.py
[tool] Read ia3.py (running)
input: {"call_id":"call_IcHq9MoulfbWnWmcWPErVlK9","process_id":"12881","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","nl -ba src/lora_lite/variants/ia3.py"],"cwd":"/media/wassname/SGIronWol...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/src/lora_lite/variants/ia3.py
[tool] Read delora.py (completed)
kind: read
input: {"call_id":"call_yYuKd7kdZxGCZo8zkQtSGEiW","process_id":"76438","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","nl -ba src/lora_lite/variants/delora.py"],"cwd":"/media/wassname/SGIron...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/src/lora_lite/variants/delora.py
output:
1 """DeLoRA: per-input-channel weight-norm scaling, per-rank A/B normalization.
2
3 Bini et al. 2025 (ICLR'25) https://arxiv.org/abs/2503.18225
4
5 Paper Eq. 8: W' = W + (lambda * ||W||_F / r) B Xi A
6 where Xi_{i,i} = 1 / (||b_i|| ||a_i||) makes each rank-1 component unit-norm.
7
8 Implementation follows the peft upstream (which the DeLoRA authors maintain),
9 which differs from the paper notation in two ways that are equivalent at the
10 forward level but matter for gradients/numerics:
11 1. ||W|| is captured PER INPUT CHANNEL (shape (d_in,)), not as a scalar
12 Frobenius norm. Used to scale `x` element-wise on the input dim.
13 See docs/refs/peft_delora_layer.py:150 (init) and :250 (forward).
14 2. Per-rank normalization applied via division (1/||A_i||*||B^j||) inside
15 the diagonal scaling, instead of as F.normalize on A,B themselves.
16 This keeps the gradient flowing through the un-normalized parameters.
17
18 Identity at t=0: lambda0=0 -> delta is exactly zero (bit-identity).
19
20 KNOWN GRADIENT ISSUE (flagged by external review 2026-04-26):
21 With lambda0=0 the *forward* is identity but `A,B` get zero gradient on step 0
22 (delta is proportional to lambda). Only `lora_lambda` moves first step.
23 The paper's true initialization (frozen-copy trick, Eq. 9) achieves both
24 identity AND non-zero A/B gradients; we do NOT implement it here.
25
26 Reference implementations:
27 - DeLoRA paper authors (ExplainableML/DeLoRA) -- their fork of peft:
28 https://github.com/ExplainableML/DeLoRA/blob/main/peft/src/peft/tuners/delora.py
... (56 more lines)
[tool] Read ia3.py (completed)
kind: read
input: {"call_id":"call_IcHq9MoulfbWnWmcWPErVlK9","process_id":"12881","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","nl -ba src/lora_lite/variants/ia3.py"],"cwd":"/media/wassname/SGIronWol...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/src/lora_lite/variants/ia3.py
output:
1 """IA3-style elementwise gating. Liu et al. 2022 https://arxiv.org/abs/2205.05638
2
3 Two registered variants, matching the paper's two regimes:
4
5 * `ia3` -- OUTPUT-side gating, parameter shape (d_out,).
6 y_new = y * g. Use for attention projections (k_proj, v_proj).
7
8 * `ia3_ff` -- INPUT-side gating, parameter shape (d_in,).
9 y_new = base_layer(x * g). Use for FFN-down layers (down_proj,
10 fc2). Equivalent to the paper's "gate the FFN intermediate (post-
11 activation)" position because down_proj's input IS that
12 intermediate hidden state.
13
14 In both cases g is initialized to 1 -> identity at t=0.
15
16 To match the paper exactly on a Llama/Qwen-style block requires TWO attach
17 passes (one per variant), since each variant uses one hook type:
18
19 cfg_attn = LoraLiteConfig(variant="ia3", target_names=(r"\\.k_proj$", r"\\.v_proj$"))
20 cfg_ffn = LoraLiteConfig(variant="ia3_ff", target_names=(r"\\.down_proj$",))
21
22 Reference implementation:
23 - peft IA3 layer (is_feedforward toggles input-vs-output gating, see
24 docs/refs/peft_ia3_layer.py:177-188 forward and :214 update_layer):
25 https://github.com/huggingface/peft/blob/main/src/peft/tuners/ia3/layer.py
26 """
27 import torch
28 from torch import nn
... (36 more lines)
[tool] Read pissa.py (completed)
kind: read
input: {"call_id":"call_DJiZUptMa5DJfJiqjcVAbgMf","process_id":"25734","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","nl -ba src/lora_lite/variants/pissa.py"],"cwd":"/media/wassname/SGIronW...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/src/lora_lite/variants/pissa.py
output:
1 """PiSSA: top-r SVD of W into A,B; replace W with W_res = W - B@A.
2
3 Meng et al. 2024 https://arxiv.org/abs/2404.02948
4 W_eff(t=0) = W_res + B@A = W (numerically; bf16 round-trip not bit-exact).
5
6 DEVIATION FROM PAPER (documented):
7 - Paper sets adapter scale = 1 (no alpha/r factor); we keep LoRA's alpha/r
8 pipeline so callers must pass alpha=r to get paper-faithful identity.
9 - Saved adapter does NOT include W_res (would double checkpoint size). Instead
10 `adapter.save` records a fingerprint of the post-init base weights and
11 `adapter.load` re-runs PiSSA init then verifies the fingerprint matches
12 -- so loading onto a different base weight raises loudly instead of
13 silently producing wrong outputs.
14
15 Reference implementations (for review/cross-check):
16 - PiSSA original (NeurIPS'24 spotlight) init script (SVD on dequant W):
17 https://github.com/MuLabPKU/PiSSA/blob/main/utils/init_pissa.py
18 (offline: docs/refs/orig_pissa_init.py)
19 - peft PiSSA flavor (init_lora_weights='pissa') in:
20 https://github.com/huggingface/peft/blob/main/src/peft/tuners/lora/layer.py
21 (offline: docs/refs/peft_lora_layer.py, see pissa_init / loftq_init paths)
22 """
23 import torch
24 from einops import einsum
25 from torch import nn
26
27 from ..variant import register, ParamSpec
28
... (43 more lines)
[tool] Read dora.py (running)
input: {"call_id":"call_kGWNeMmPZ4fynlP2xkya29ml","process_id":"83073","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","nl -ba src/lora_lite/variants/dora.py"],"cwd":"/media/wassname/SGIronWo...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/src/lora_lite/variants/dora.py
[tool] Read hra.py (running)
input: {"call_id":"call_AUbNamw7Vff6IHpnxeDKla65","process_id":"18622","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","nl -ba src/lora_lite/variants/hra.py"],"cwd":"/media/wassname/SGIronWol...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/src/lora_lite/variants/hra.py
[tool] Read antipasto.py (running)
input: {"call_id":"call_K1UnwByBUsEV01RApE7a6wa0","process_id":"76559","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","nl -ba src/lora_lite/variants/antipasto.py"],"cwd":"/media/wassname/SGI...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/src/lora_lite/variants/antipasto.py
[tool] Read eva.py (running)
input: {"call_id":"call_aT1ZKpUsBsF0ukmeSQy5wQSa","process_id":"30592","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","nl -ba src/lora_lite/variants/eva.py"],"cwd":"/media/wassname/SGIronWol...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/src/lora_lite/variants/eva.py
[tool] Read dora.py (completed)
kind: read
input: {"call_id":"call_kGWNeMmPZ4fynlP2xkya29ml","process_id":"83073","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","nl -ba src/lora_lite/variants/dora.py"],"cwd":"/media/wassname/SGIronWo...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/src/lora_lite/variants/dora.py
output:
1 """DoRA: weight-decomposed LoRA. Liu et al. 2024 https://arxiv.org/abs/2402.09353
2
3 W' = m * V / ||V||_c where V = W + (alpha/r) B A (||.||_c = per-output-row L2 norm)
4
5 At t=0: B=0 -> V=W -> y_new = (m_init / ||W||_c) (Wx + 0) = Wx when m_init = ||W||_c.
6
7 Limitation: requires materializing the dense weight to compute ||V||_c. v1 supports
8 plain nn.Linear only; bnb 4/8-bit layers raise loudly.
9
10 DEVIATION (numerical):
11 - We differentiate through ||V||_c every forward. The paper's sec. 4.3 suggests
12 a 'cost-saving' variant that detaches ||V|| in backward (gradient only flows
13 through V); we do NOT do that. Real impact: slower step, slightly different
14 gradient direction. Faithful to the eq.5 forward, not the optimized one.
15
16 Reference implementations (for review/cross-check):
17 - peft DoRA (separate file under lora/):
18 https://github.com/huggingface/peft/blob/main/src/peft/tuners/lora/dora.py
19 (offline: docs/refs/peft_lora_dora.py)
20 """
21 import torch
22 import torch.nn.functional as F
23 from einops import einsum
24 from torch import nn
25
26 from ..variant import register, ParamSpec
27
28
... (38 more lines)
[tool] Read hra.py (completed)
kind: read
input: {"call_id":"call_AUbNamw7Vff6IHpnxeDKla65","process_id":"18622","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","nl -ba src/lora_lite/variants/hra.py"],"cwd":"/media/wassname/SGIronWol...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/src/lora_lite/variants/hra.py
output:
1 """HRA: Householder Reflection Adaptation. Yuan et al. 2024 https://arxiv.org/abs/2405.17484
2
3 Paper formulation (Sec. 3): adapt each frozen weight as
4
5 W' = W R, R = prod_{i=1..r} H_i, H_i = I - 2 u_i u_i^T / ||u_i||^2
6
7 so the layer output becomes y' = W' x = W (R x). R is in INPUT space (d_in x d_in).
8
9 We implement this via a `forward_input` pre-hook that returns `R x`, then the
10 frozen base layer (including bnb 4/8-bit Linear) computes `W (R x)` itself.
11
12 Identity at t=0 (PEFT-style symmetric init, requires even r):
13 Rows are kaiming-init in pairs: U[0]=U[1], U[2]=U[3], ... Adjacent pairs of
14 Householder reflections with identical vectors cancel exactly
15 (H_i H_i = I), so R = I at init -> y' = y to bit-precision.
16 After the first gradient step the paired rows diverge and the chain becomes a
17 general orthogonal matrix; gradient flows into U from step 0 (no dead-grad).
18 Odd r is rejected (matches peft warning behaviour).
19
20 OMITTED: paper also adds an orthogonality regularizer (Eq. 6 / Sec. 3.3),
21 a loss-side term. Add it in your training loop if you want regularized HRA.
22
23 Reference implementations (for review/cross-check):
24 - HRA paper authors (DaShenZi721/HRA), llama variant of OFT layer with HRA:
25 https://github.com/DaShenZi721/HRA/blob/master/llama/peft/oft/layer_GS_HRA.py
26 (offline: docs/refs/orig_hra_layer.py)
27 - peft HRA layer, reset_hra_parameters (lines 100-108):
28 https://github.com/huggingface/peft/blob/main/src/peft/tuners/hra/layer.py
... (50 more lines)
[tool] Read antipasto.py (completed)
kind: read
input: {"call_id":"call_K1UnwByBUsEV01RApE7a6wa0","process_id":"76559","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","nl -ba src/lora_lite/variants/antipasto.py"],"cwd":"/media/wassname/SGI...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/src/lora_lite/variants/antipasto.py
output:
1 """AntiPaSTO: SVD steering with learnable singular-value deltas + block-diagonal Cayley rotation.
2
3 Lite port of wassname's AntiPaSTO3 SVD adapter (research code, not an
4 upstream peft variant). Reference:
5 https://github.com/wassname/antipasto3 (offline: docs/refs/antipasto3_svd_adapter.py)
6
7 Decomposition (PyTorch nn.Linear convention, weight (d_out, d_in)):
8
9 W = U diag(S) Vh + W_res (top-r SVD; W_res = W - U_r diag(S_r) Vh_r)
10
11 We freeze U, S, Vh, W_res and learn:
12 - delta_s : (r,) -- additive delta to singular values
13 - rot_T : (n_blocks, bs(bs-1)/2) -- upper-triangle of skew matrix per block
14
15 Forward (matches base layer convention exactly at t=0):
16
17 R = block_diag(Cayley(skew(rot_T))) # (r, r) effective
18 Vh_rot = R @ Vh # rotates input basis
19 S_eff = S + delta_s # learnable spectrum
20 delta_y = ((x @ Vh_rot.T) * S_eff) @ U.T # rank-r path
21 base_y = x @ W_res.T # frozen residual
22 y_total = base_y + delta_y # == original output at t=0
23
24 At init: rot_T = 0 -> R = I -> Vh_rot = Vh, delta_s = 0 -> S_eff = S, so
25 delta_y reconstructs the truncated SVD term and y_total == x @ W^T to numerical
26 precision (fp32 SVD round-tripped to cfg.dtype).
27
28 WHICH BASIS IS ROTATED:
... (117 more lines)
[tool] Read eva.py (completed)
kind: read
input: {"call_id":"call_aT1ZKpUsBsF0ukmeSQy5wQSa","process_id":"30592","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","nl -ba src/lora_lite/variants/eva.py"],"cwd":"/media/wassname/SGIronWol...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/src/lora_lite/variants/eva.py
output:
1 """EVA: Explained-Variance Adaptation. Paischer et al. 2024.
2
3 Paper: https://arxiv.org/abs/2410.07170 (also referred to as ICLR'25 EVA).
4
5 Idea: instead of random A and zero B (LoRA) or SVD of W (PiSSA), initialize
6 `lora_A` to the top-r right singular vectors of the LAYER INPUT distribution
7 on a small calibration set. Forward = `y + scale * (B @ A @ x)` exactly like
8 LoRA; with `lora_B = 0` the adapter is identity at t=0. Only B trains
9 afterwards (A frozen). The result: each rank slot points along a direction
10 that actually carries information at this layer.
11
12 This is a stripped-down EVA; we do NOT implement:
13 - rank redistribution across layers via explained-variance ratios
14 (peft EVA computes an explained_variance_ratio per layer then redistributes
15 the global rank budget; we use a uniform `cfg.r` per layer).
16 - Incremental PCA over many micro-batches (we run one full SVD on the
17 pooled calibration activations per layer).
18 - Equal-input deduplication (peft hashes inputs to share SVD across QKV).
19
20 API stress-test: this variant requires data-driven init, so it implements
21 `group_init(model, targets, cfg, calibration_data)` to drive a single forward
22 pass on `calibration_data` with hooks that capture each target's input.
23
24 Identity at t=0: `lora_B = 0` -> delta = 0 -> y unchanged.
25
26 References:
27 - peft EVA (full impl, with IncrementalPCA + redistribution):
28 https://github.com/huggingface/peft/blob/main/src/peft/tuners/lora/eva.py
... (93 more lines)
[tool] Read adapter.py (running)
input: {"call_id":"call_ZASqXizFcUeYWy0BfWtn7awK","process_id":"56583","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","nl -ba src/lora_lite/adapter.py"],"cwd":"/media/wassname/SGIronWolf/pro...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/src/lora_lite/adapter.py
[tool] Read variant.py (running)
input: {"call_id":"call_DTjBD9RvOp7yhpRxBMhsmmpH","process_id":"59269","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","nl -ba src/lora_lite/variant.py"],"cwd":"/media/wassname/SGIronWolf/pro...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/src/lora_lite/variant.py
[tool] Read config.py (running)
input: {"call_id":"call_gFTpgHVNt3AjUpsu0uccR8Xj","process_id":"57355","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","nl -ba src/lora_lite/config.py"],"cwd":"/media/wassname/SGIronWolf/proj...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/src/lora_lite/config.py
[tool] Read smoke.py (running)
input: {"call_id":"call_x0N2faRQBhIMJ6dP09QwZiFv","process_id":"65832","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","nl -ba tests/smoke.py"],"cwd":"/media/wassname/SGIronWolf/projects5/202...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/tests/smoke.py
[tool] Read target.py (running)
input: {"call_id":"call_J7iRBknduLUEbwo0vQAyXzkS","process_id":"13496","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","nl -ba src/lora_lite/target.py"],"cwd":"/media/wassname/SGIronWolf/proj...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/src/lora_lite/target.py
[tool] Read adapter.py (completed)
kind: read
input: {"call_id":"call_ZASqXizFcUeYWy0BfWtn7awK","process_id":"56583","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","nl -ba src/lora_lite/adapter.py"],"cwd":"/media/wassname/SGIronWolf/pro...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/src/lora_lite/adapter.py
output:
1 """attach / detach / save / load. The whole runtime."""
2 from __future__ import annotations
3 import torch
4 from torch import nn
5 from torch.utils.hooks import RemovableHandle
6
7 from .config import LoraLiteConfig
8 from .variant import REGISTRY
9 from .target import find_targets
10
11
12 _ATTACHED_ATTR = "_lora_lite_attached"
13
14
15 def _hook(layer, args, y):
16 (x,) = args
17 cfg: LoraLiteConfig = layer._lora_cfg
18 x_cast = x.to(cfg.dtype)
19 out = layer._lora_variant.forward(layer, x_cast, y)
20 return out.to(y.dtype)
21
22
23 def _pre_hook(layer, args):
24 (x,) = args
25 cfg: LoraLiteConfig = layer._lora_cfg
26 x_cast = x.to(cfg.dtype)
27 x_new = layer._lora_variant.forward_input(layer, x_cast)
28 return (x_new.to(x.dtype),)
... (126 more lines)
[tool] Read variant.py (completed)
kind: read
input: {"call_id":"call_DTjBD9RvOp7yhpRxBMhsmmpH","process_id":"59269","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","nl -ba src/lora_lite/variant.py"],"cwd":"/media/wassname/SGIronWolf/pro...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/src/lora_lite/variant.py
output:
1 """Variant protocol + registry. Variants own (x, layer.weight, layer.lora_*) -> y_new."""
2 from dataclasses import dataclass
3 from typing import Callable, Protocol, Any
4 import torch
5 from torch import nn
6
7 from .config import LoraLiteConfig
8
9
10 @dataclass
11 class ParamSpec:
12 shape: tuple[int, ...]
13 init: str | Callable[[torch.Tensor], None] = "zeros" # 'zeros'|'kaiming'|'ones'|callable(t)
14 trainable: bool = True
15 as_buffer: bool = False # if True, register_buffer instead of register_parameter
16
17 def _empty(self, dtype: torch.dtype, device) -> torch.Tensor:
18 t = torch.empty(self.shape, dtype=dtype, device=device)
19 if callable(self.init):
20 self.init(t)
21 elif self.init == "zeros":
22 t.zero_()
23 elif self.init == "ones":
24 t.fill_(1.0)
25 elif self.init == "kaiming":
26 # match nn.Linear default: kaiming_uniform_(a=sqrt(5))
27 nn.init.kaiming_uniform_(t, a=5 ** 0.5) if t.ndim >= 2 else t.normal_(0, 0.02)
28 else:
... (39 more lines)
[tool] Read config.py (completed)
kind: read
input: {"call_id":"call_gFTpgHVNt3AjUpsu0uccR8Xj","process_id":"57355","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","nl -ba src/lora_lite/config.py"],"cwd":"/media/wassname/SGIronWolf/proj...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/src/lora_lite/config.py
output:
1 from dataclasses import dataclass, field, asdict
2 from typing import Any
3 import torch
4
5
6 @dataclass
7 class LoraLiteConfig:
8 variant: str = "lora"
9 r: int = 8
10 alpha: float = 16.0
11 dtype: torch.dtype = torch.bfloat16
12
13 # targeting
14 target_roles: tuple[str, ...] = ("reader", "writer")
15 target_names: tuple[str, ...] = ()
16 exclude_names: tuple[str, ...] = ("lm_head", "embed_tokens")
17 layers: tuple[int, ...] | None = None
18
19 # variant-specific bag (e.g. lambda0 for DeLoRA)
20 variant_kwargs: dict[str, Any] = field(default_factory=dict)
21
22 def to_dict(self) -> dict:
23 d = asdict(self)
24 d["dtype"] = str(self.dtype).removeprefix("torch.")
25 return d
26
27 @classmethod
28 def from_dict(cls, d: dict) -> "LoraLiteConfig":
... (9 more lines)
[tool] Read smoke.py (completed)
kind: read
input: {"call_id":"call_x0N2faRQBhIMJ6dP09QwZiFv","process_id":"65832","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","nl -ba tests/smoke.py"],"cwd":"/media/wassname/SGIronWolf/projects5/202...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/tests/smoke.py
output:
1 """Smoke test: current variants on a tiny synthetic transformer-like model.
2
3 Verifies:
4 1. Identity at t=0 (delta ~ 0, output close to base).
5 2. Save/load round-trip preserves outputs.
6 3. A few SGD steps reduce a random loss (gradients flow).
7
8 Run:
9 cd lora-lite
10 python -m pip install -e .
11 python tests/smoke.py
12
13 BLUF format:
14 SHOULD: max|y_adapter - y_base| < tol_init for all variants. ELSE init or hook bug.
15 SHOULD: loss decreases > 5% over 20 SGD steps for all variants. ELSE grad/wiring bug.
16 """
17 from __future__ import annotations
18 import argparse
19 import os, sys, math
20 from pathlib import Path
21 import torch
22 from torch import nn
23
24 # allow running as `python tests/smoke.py` without install
25 sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src"))
26
27 import lora_lite as ll # noqa: E402
28
... (317 more lines)
[tool] Read target.py (completed)
kind: read
input: {"call_id":"call_J7iRBknduLUEbwo0vQAyXzkS","process_id":"13496","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","nl -ba src/lora_lite/target.py"],"cwd":"/media/wassname/SGIronWolf/proj...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/src/lora_lite/target.py
output:
1 """Find linear-like targets by shape (reader/writer/inner) + name regex.
2
3 Structural matching is deliberate: bnb Linear4bit/8bitLt are not nn.Linear, but
4 they expose in_features/out_features/weight and their forward already handles
5 dequantization.
6 """
7 import re
8 from torch import nn
9
10
11 def is_linear_like(m: nn.Module) -> bool:
12 return (
13 hasattr(m, "in_features")
14 and hasattr(m, "out_features")
15 and hasattr(m, "weight")
16 and callable(m)
17 )
18
19
20 def _layer_idx(name: str) -> int | None:
21 m = re.search(r"\.layers?\.(\d+)\.", name)
22 return int(m.group(1)) if m else None
23
24
25 def _classify(m: nn.Module, d_model: int, name: str) -> str:
26 di, do = m.in_features, m.out_features
27 if di == d_model and do != d_model:
28 return "reader"
... (31 more lines)
A few early runtime facts matter for every variant: adapter buffers are persistent (`register_buffer(..., persistent=True)`), all adapter tensors default to `cfg.dtype`, and hooks cast inputs into that dtype before variant forward. Im now checking the reference snapshots around their init/forward code paths, then Ill sanity-check the live docstring URLs.
[tool] Search lora_A|lora_B|scaling|kaiming|reset_lora|pissa|PiSSA|svd|dora|weight_norm|lora_magnitude_vector|magnitude in peft_lora_layer.py (running)
input: {"call_id":"call_CXL2dLkBuKVYv7swdUx31r7B","process_id":"21601","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","rg -n \"lora_A|lora_B|scaling|kaiming|reset_lora|pissa|PiSSA|svd|dora|w...
[tool] Search ia3|ia3_l|is_feedforward|forward|update_layer|ones|Parameter in peft_ia3_layer.py (running)
input: {"call_id":"call_QNRan5JW29Lt2z32ejlnQSiE","process_id":"83887","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","rg -n \"ia3|ia3_l|is_feedforward|forward|update_layer|ones|Parameter\" ...
[tool] Search hra|reflection|householder|reset_hra|hra_u|Parameter|forward|apply in peft_hra_layer.py (running)
input: {"call_id":"call_l6wFam8sUpDhQje5Kw1ddbP9","process_id":"88970","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","rg -n \"hra|reflection|householder|reset_hra|hra_u|Parameter|forward|ap...
[tool] Search lora_A|lora_B|scaling|kaiming|reset_lora|pissa|PiSSA|svd|dora|weight_norm|lora_magnitude_vector|magnitude in peft_lora_layer.py (completed)
kind: search
input: {"call_id":"call_CXL2dLkBuKVYv7swdUx31r7B","process_id":"21601","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","rg -n \"lora_A|lora_B|scaling|kaiming|reset_lora|pissa|PiSSA|svd|dora|w...
output:
docs/refs/peft_lora_dora.py:66: self._dora_cache: dict[str, Any] = {} # small ad hoc cache; values are not part of the state_dict
docs/refs/peft_lora_dora.py:70: self._dora_cache[key] = value
docs/refs/peft_lora_dora.py:74: return self._dora_cache.get(key, default)
docs/refs/peft_lora_dora.py:77: self._dora_cache.clear()
docs/refs/peft_lora_dora.py:86: def get_weight_norm(self, weight, lora_weight, scaling, adapter_name: Optional[str] = None) -> torch.Tensor:
docs/refs/peft_lora_dora.py:89: weight = weight + scaling * lora_weight
docs/refs/peft_lora_dora.py:90: weight_norm = torch.linalg.norm(weight, dim=1).to(weight.dtype)
docs/refs/peft_lora_dora.py:91: return weight_norm
docs/refs/peft_lora_dora.py:94: def get_lora_weight(self, lora_A, lora_B, adapter_name: Optional[str] = None):
docs/refs/peft_lora_dora.py:95: # Don't use `lora_weight = lora_B.weight @ lora_A.weight` because this causes errors with FSDP. Instead,
docs/refs/peft_lora_dora.py:97: x_eye = torch.eye(lora_A.weight.shape[1], device=lora_A.weight.device, dtype=lora_A.weight.dtype)
docs/refs/peft_lora_dora.py:98: lora_weight = lora_B(lora_A(x_eye)).T
docs/refs/peft_lora_dora.py:101: def update_layer(self, *, base_layer, lora_A, lora_B, scaling, place_on_cpu=False) -> None:
docs/refs/peft_lora_dora.py:103: dtype_is_fp16 = lora_A.dtype == torch.float16
docs/refs/peft_lora_dora.py:105: lora_A = lora_A.float()
docs/refs/peft_lora_dora.py:106: lora_B = lora_B.float()
docs/refs/peft_lora_dora.py:116: r = lora_A.shape[0]
docs/refs/peft_lora_dora.py:117: lora_weight = torch.mm(lora_B.view([-1, r]), lora_A.view([r, -1]))
docs/refs/peft_lora_dora.py:120: lora_weight = lora_B @ lora_A
docs/refs/peft_lora_dora.py:124: weight_norm = self.get_weight_norm(
docs/refs/peft_lora_dora.py:125: weight=weight.to(lora_A.device), lora_weight=lora_...
[tool] Search delora|lora_lambda|wnorm|weight_norm|norm|scaling|forward|reset|kaiming in peft_delora_layer.py (running)
input: {"call_id":"call_eZ4HOEgS7NuaCwjmwX8tSURH","process_id":"24489","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","rg -n \"delora|lora_lambda|wnorm|weight_norm|norm|scaling|forward|reset...
[tool] Search ia3|ia3_l|is_feedforward|forward|update_layer|ones|Parameter in peft_ia3_layer.py (completed)
kind: search
input: {"call_id":"call_QNRan5JW29Lt2z32ejlnQSiE","process_id":"83887","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","rg -n \"ia3|ia3_l|is_feedforward|forward|update_layer|ones|Parameter\" ...
output:
30: adapter_layer_names = ("ia3_l",)
32: def __init__(self, base_layer: nn.Module, is_feedforward: bool, **kwargs) -> None:
34: self.ia3_l = nn.ParameterDict({})
38: self.is_feedforward = is_feedforward
56: def update_layer(self, adapter_name: str, config: IA3Config, **kwargs):
57: init_ia3_weights = config.init_ia3_weights
62: if self.is_feedforward:
66: self.ia3_l[adapter_name] = nn.Parameter(weight)
67: if init_ia3_weights:
68: self.reset_ia3_parameters(adapter_name)
72: def reset_ia3_parameters(self, adapter_name):
73: if adapter_name in self.ia3_l.keys():
74: # initialize learned vector with torch.ones
75: nn.init.constant_(self.ia3_l[adapter_name], 1.0)
85: is_feedforward: bool = False, # Set to True if the layer is treated as a feedforward layer
90: IA3Layer.__init__(self, base_layer, is_feedforward=is_feedforward)
94: self.update_layer(adapter_name, config=config)
115: if active_adapter in self.ia3_l.keys():
117: ia3_l = transpose(self.ia3_l[active_adapter].data, self.fan_in_fan_out)
121: orig_weights = torch.mul(orig_weights, ia3_l)
129: base_layer.weight.data = torch.mul(base_layer.weight.data, ia3_l).to(orig_dtype)
131: if not self.is_feedforward and (base_layer.bias is not None):
132: scaling = self.ia3_l[active_adapter].reshape(base_layer.bias.shape)
149: if active_adapter in self.ia3_l.keys():
152: ia3_l = transpose(self.ia3_l[active_adapter].data, self.fan_in_fan_out) + 1e-8
154: base_layer.weight.data = torch.div(base_layer.weight.data, ia3_l).to(orig_dtype)
156: if not self.is_feedforward and (base_layer.bias is not None):
157: scaling = self.ia3_l[active_adapter].reshape(base_layer.bias.shape)
... (42 more lines)
[tool] Search hra|reflection|householder|reset_hra|hra_u|Parameter|forward|apply in peft_hra_layer.py (completed)
kind: search
input: {"call_id":"call_l6wFam8sUpDhQje5Kw1ddbP9","process_id":"88970","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","rg -n \"hra|reflection|householder|reset_hra|hra_u|Parameter|forward|ap...
output:
docs/refs/peft_hra_layer.py:30: adapter_layer_names = ("hra_u",)
docs/refs/peft_hra_layer.py:32: other_param_names = ("hra_r", "hra_apply_GS")
docs/refs/peft_hra_layer.py:36: self.hra_r = {}
docs/refs/peft_hra_layer.py:37: self.hra_apply_GS = {}
docs/refs/peft_hra_layer.py:38: self.hra_u = nn.ParameterDict({})
docs/refs/peft_hra_layer.py:42: # flag to enable/disable casting of input to weight dtype during forward call
docs/refs/peft_hra_layer.py:61: """Internal function to create hra adapter
docs/refs/peft_hra_layer.py:68: apply_GS = config.apply_GS
docs/refs/peft_hra_layer.py:75: self.hra_r[adapter_name] = r
docs/refs/peft_hra_layer.py:76: self.hra_apply_GS[adapter_name] = apply_GS
docs/refs/peft_hra_layer.py:81: self.hra_u[adapter_name] = nn.Parameter(torch.empty(self.in_features, r), requires_grad=True)
docs/refs/peft_hra_layer.py:83: self.hra_u[adapter_name] = nn.Parameter(
docs/refs/peft_hra_layer.py:92: self.reset_hra_parameters(adapter_name)
docs/refs/peft_hra_layer.py:94: self.reset_hra_parameters_random(adapter_name)
docs/refs/peft_hra_layer.py:100: def reset_hra_parameters(self, adapter_name: str):
docs/refs/peft_hra_layer.py:101: if self.hra_r[adapter_name] % 2 != 0:
docs/refs/peft_hra_layer.py:103: nn.init.kaiming_uniform_(self.hra_u[adapter_name], a=math.sqrt(5))
docs/refs/peft_hra_layer.py:105: shape = self.hra_u[adapter_name].shape
docs/refs/peft_hra_layer.py:108: self.hra_u[adapter_name] = nn.Parameter(torch.repeat_interleave(half_u, 2, dim=1))
docs/refs/peft_hra_layer.py:110: def reset_hra_parameters_random(self, adapter_name: str):
docs/refs/peft_hra_layer.py:111: nn.init.kaiming_uniform_(self.hra_u[adapter_name], a=math.sqrt(5))
docs/refs/peft_hra_layer.py:118: if active_adapter not in self.hra_u.keys():
docs/refs/peft_hra_layer.py:125: if active_adapter not in self....
[tool] Search delora|lora_lambda|wnorm|weight_norm|norm|scaling|forward|reset|kaiming in peft_delora_layer.py (completed)
kind: search
input: {"call_id":"call_eZ4HOEgS7NuaCwjmwX8tSURH","process_id":"24489","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","rg -n \"delora|lora_lambda|wnorm|weight_norm|norm|scaling|forward|reset...
output:
docs/refs/peft_delora_layer.py:32: "delora_A",
docs/refs/peft_delora_layer.py:33: "delora_B",
docs/refs/peft_delora_layer.py:34: "delora_lambda",
docs/refs/peft_delora_layer.py:39: "delora_dropout",
docs/refs/peft_delora_layer.py:40: "delora_w_norm",
docs/refs/peft_delora_layer.py:46: self.delora_dropout = nn.ModuleDict({})
docs/refs/peft_delora_layer.py:47: self.delora_A = nn.ParameterDict({})
docs/refs/peft_delora_layer.py:48: self.delora_B = nn.ParameterDict({})
docs/refs/peft_delora_layer.py:49: self.delora_lambda = nn.ParameterDict({})
docs/refs/peft_delora_layer.py:51: self.delora_w_norm = BufferDict({}, persistent=True)
docs/refs/peft_delora_layer.py:65: A: torch.Tensor, B: torch.Tensor, delora_lambda: torch.Tensor, r: int, w_norm: torch.Tensor
docs/refs/peft_delora_layer.py:67: """Compute delta = B @ diag(delora_lambda/r / (||A_i||*||B^j||)) @ A, scaled by provided w_norm (per-input channel)"""
docs/refs/peft_delora_layer.py:68: An = torch.clamp(A.norm(dim=1), min=1e-4)
docs/refs/peft_delora_layer.py:69: Bn = torch.clamp(B.norm(dim=0), min=1e-4)
docs/refs/peft_delora_layer.py:70: diag = torch.diag_embed(delora_lambda / r / (An * Bn))
docs/refs/peft_delora_layer.py:72: delta = delta * w_norm.unsqueeze(0)
docs/refs/peft_delora_layer.py:76: if adapter not in self.delora_A or adapter not in self.delora_B:
docs/refs/peft_delora_layer.py:80: self.delora_A[adapter],
docs/refs/peft_delora_layer.py:81: self.delora_B[adapter],
docs/refs/peft_delora_layer.py:82: self.delora_lambda[adapter],
docs/refs/peft_delora_layer.py:84: self.delora_w_norm[adapter],
docs/refs/peft_delora_layer.py:92: delora_lambda: float,
docs/refs/peft_delora_layer.py:96: """Internal function to create delora adapter
docs/refs/peft_delora_layer.py:101: delora_lambda (`float`): Boundary for the adapter's norm.
...
[tool] Read peft_lora_layer.py (running)
input: {"call_id":"call_JRbF1Xn6kmbu1aeGenPoTbn3","process_id":"19417","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","sed -n '360,395p' docs/refs/peft_lora_layer.py"],"cwd":"/media/wassname...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/docs/refs/peft_lora_layer.py
[tool] Search SVD|svd|delta_s|rot|Cayley|rotate|U|Vh|V in antipasto3_svd_adapter.py (running)
input: {"call_id":"call_eDElMn5nrdWzS4IgBNYQZ4gS","process_id":"39796","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","rg -n \"SVD|svd|delta_s|rot|Cayley|rotate|U|Vh|V\" docs/refs/antipasto3...
[tool] Search initialize_lora_eva_weights|eva|SVD|svd|IncrementalPCA|lora_A|lora_B|rank|explained|dropout in peft_eva.py (running)
input: {"call_id":"call_XGlVYcHZnz3nyKUx46IAmL8z","process_id":"62921","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","rg -n \"initialize_lora_eva_weights|eva|SVD|svd|IncrementalPCA|lora_A|l...
[tool] Read peft_lora_layer.py (running)
input: {"call_id":"call_ppwxQIwOtJyElrbeCwjGwIvU","process_id":"22962","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","sed -n '958,972p' docs/refs/peft_lora_layer.py"],"cwd":"/media/wassname...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/docs/refs/peft_lora_layer.py
[tool] Search SVD|svd|delta_s|rot|Cayley|rotate|U|Vh|V in antipasto3_svd_adapter.py (completed)
kind: search
input: {"call_id":"call_eDElMn5nrdWzS4IgBNYQZ4gS","process_id":"39796","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","rg -n \"SVD|svd|delta_s|rot|Cayley|rotate|U|Vh|V\" docs/refs/antipasto3...
output:
1:"""SVD adapter for bidirectional steering via block-diagonal Cayley rotations.
5:kernel = U @ diag(S) @ Vh + W_res (kernel is (in, out), standard Flax convention)
6:Learnable: delta_s (additive S scaling), rotation_params (block-diagonal V rotation).
7:alpha scales both: S + alpha*delta_s, U @ R(alpha).
9:Why Cayley (not Givens or matrix exponential):
10:Cayley gives exact analytical reversibility: R(-alpha) = R(alpha)^{-1}.
14:At alpha=0: U_rot = U and S_scaled = S, so the layer is identical to frozen weights.
30:class SVDParam(nnx.Param):
31: """Trainable SVD adapter parameter (base class -- use subclasses for per-group LR)."""
35:class DeltaSParam(SVDParam):
36: """Trainable delta_s scaling parameters (full LR)."""
40:class RotationParam(SVDParam):
41: """Block-diagonal rotation parameters (lower LR via rotation_lr_scale config)."""
45:class SVDFrozen(nnx.Variable):
46: """Frozen SVD component. Not differentiated."""
50:# -- SVD Steering Linear (replaces nnx.Linear) ------------------------------
52:class SVDSteeringLinear(nnx.Module):
53: """SVD steering adapter replacing a linear layer.
55: y = ((x @ U_rot) * S_scaled) @ Vh + x @ W_res
57: where U_rot, S_scaled depend on alpha (the steering coefficient).
58: Frozen: U, S, Vh, W_res. Learnable: delta_s, rotation_params.
63: U: jax.Array, # (in_dim, r) - input singular vectors
65: Vh: jax.Array, # (r, out_dim) - output singular vectors
67: rotation_block_size: int,
68: max_rotation_angle: float,
69: rotate_U: bool = True,
70: rotate_V: bool = False,
71: use_delta_s: bool = True,
... (90 more lines)
[tool] Read peft_lora_layer.py (completed)
kind: read
input: {"call_id":"call_JRbF1Xn6kmbu1aeGenPoTbn3","process_id":"19417","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","sed -n '360,395p' docs/refs/peft_lora_layer.py"],"cwd":"/media/wassname...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/docs/refs/peft_lora_layer.py
output:
sed: /tmp/.mount_vscodiOHg5sd/lib/x86_64-linux-gnu/libselinux.so.1: no version information available (required by sed)
def pissa_init(self, adapter_name, init_lora_weights):
weight = self.get_base_layer().weight
dtype = weight.dtype
if dtype not in [torch.float32, torch.float16, torch.bfloat16]:
raise TypeError(
"Please initialize PiSSA under float32, float16, or bfloat16. "
"Subsequently, re-quantize the residual model to help minimize quantization errors."
)
weight = transpose(weight.to(torch.float32), self.fan_in_fan_out)
if init_lora_weights == "pissa":
# USV^T = W <-> VSU^T = W^T, where W^T = weight.data in R^{out_channel, in_channel},
V, S, Uh = torch.linalg.svd(weight.data, full_matrices=False)
Vr = V[:, : self.r[adapter_name]]
Sr = S[: self.r[adapter_name]]
Sr /= self.scaling[adapter_name]
Uhr = Uh[: self.r[adapter_name]]
elif len(init_lora_weights.split("_niter_")) == 2:
Vr, Sr, Ur = svd_lowrank(
weight.data, self.r[adapter_name], niter=int(init_lora_weights.split("_niter_")[-1])
)
Sr /= self.scaling[adapter_name]
Uhr = Ur.t()
else:
raise ValueError(
f"init_lora_weights should be 'pissa' or 'pissa_niter_[number of iters]', got {init_lora_weights} instead."
)
... (9 more lines)
[tool] Read peft_lora_dora.py (running)
input: {"call_id":"call_76bagUsTDjh2isFAy7PqqYus","process_id":"47762","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","sed -n '132,166p' docs/refs/peft_lora_dora.py"],"cwd":"/media/wassname/...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/docs/refs/peft_lora_dora.py
[tool] Search initialize_lora_eva_weights|eva|SVD|svd|IncrementalPCA|lora_A|lora_B|rank|explained|dropout in peft_eva.py (completed)
kind: search
input: {"call_id":"call_XGlVYcHZnz3nyKUx46IAmL8z","process_id":"62921","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","rg -n \"initialize_lora_eva_weights|eva|SVD|svd|IncrementalPCA|lora_A|l...
output:
docs/refs/peft_eva_finetuning.py:21:from peft import EvaConfig, LoraConfig, get_peft_model, initialize_lora_eva_weights
docs/refs/peft_eva_finetuning.py:29:rank = 16
docs/refs/peft_eva_finetuning.py:33:svd_batch_size = 4 # can be different from the batch size used in finetuning
docs/refs/peft_eva_finetuning.py:61: batch_size=svd_batch_size,
docs/refs/peft_eva_finetuning.py:66:eva_config = EvaConfig(rho=rho)
docs/refs/peft_eva_finetuning.py:68: r=rank, lora_alpha=alpha, target_modules=target_modules, init_lora_weights="eva", eva_config=eva_config
docs/refs/peft_eva_finetuning.py:74:# to optimize memory usage during eva initialization, set low_cpu_mem_usage=True
docs/refs/peft_eva_finetuning.py:76:initialize_lora_eva_weights(peft_model, dataloader)
docs/refs/peft_eva.py:31:from peft.utils.incremental_pca import IncrementalPCA
docs/refs/peft_eva.py:106:class SVDHook(_Hook):
docs/refs/peft_eva.py:108: A forward hook for calculating incremental SVD on layer inputs. The hook is designed to be registered to a PyTorch
docs/refs/peft_eva.py:111: This hook performs a step of incremental Singular Value Decomposition (SVD) on the inputs of a specified layer
docs/refs/peft_eva.py:119: prepare_layer_inputs_fn (Optional[callable]): Function to prepare layer inputs for SVD.
docs/refs/peft_eva.py:138: self.svd = IncrementalPCA(
docs/refs/peft_eva.py:141: lowrank=True,
docs/refs/peft_eva.py:142: lowrank_seed=42,
docs/refs/peft_eva.py:150: if hasattr(self.svd, "components_"):
docs/refs/peft_eva.py:151: previous_components = self.svd.components_.clone().detach()
docs/refs/peft_eva.py:156: print(f"skipping SVD for {self.name} because there are less than {self.n_components} examples")
docs/refs/peft_eva.py:158: self.svd.partial_fit(states.to(torch.float32))
docs/refs/peft_eva.py:162: components = self.svd.components_
docs/refs/peft_eva.py:171:# This is used to determine if inputs of two differe...
[tool] Read peft_lora_layer.py (completed)
kind: read
input: {"call_id":"call_ppwxQIwOtJyElrbeCwjGwIvU","process_id":"22962","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","sed -n '958,972p' docs/refs/peft_lora_layer.py"],"cwd":"/media/wassname...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/docs/refs/peft_lora_layer.py
output:
sed: /tmp/.mount_vscodiOHg5sd/lib/x86_64-linux-gnu/libselinux.so.1: no version information available (required by sed)
lora_A_keys = self.lora_A.keys()
for active_adapter in self.active_adapters:
if active_adapter not in lora_A_keys:
continue
lora_A = self.lora_A[active_adapter]
lora_B = self.lora_B[active_adapter]
dropout = self.lora_dropout[active_adapter]
scaling = self.scaling[active_adapter]
x = self._cast_input_dtype(x, lora_A.weight.dtype)
if active_adapter not in self.lora_variant: # vanilla LoRA
result = result + lora_B(lora_A(dropout(x))) * scaling
else:
result = self.lora_variant[active_adapter].forward(
self,
[tool] Read peft_lora_dora.py (completed)
kind: read
input: {"call_id":"call_76bagUsTDjh2isFAy7PqqYus","process_id":"47762","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","sed -n '132,166p' docs/refs/peft_lora_dora.py"],"cwd":"/media/wassname/...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/docs/refs/peft_lora_dora.py
output:
sed: /tmp/.mount_vscodiOHg5sd/lib/x86_64-linux-gnu/libselinux.so.1: no version information available (required by sed)
def forward(self, x, *, lora_A, lora_B, scaling, base_layer, base_result=None, adapter_name="default"):
"""
For DoRA, calculate the extra output from LoRA with DoRA applied. This should be added on top of the base layer
output.
"""
lora_weight = self.get_lora_weight(lora_A=lora_A, lora_B=lora_B, adapter_name=adapter_name)
lora_weight = lora_weight.to(x.dtype)
magnitude = self.weight
weight = dequantize_module_weight(base_layer)
weight = weight.to(x.dtype)
weight_norm = self.get_weight_norm(
weight=weight, lora_weight=lora_weight.detach(), scaling=scaling, adapter_name=adapter_name
)
# see section 4.3 of DoRA (https://huggingface.co/papers/2402.09353)
# "[...] we suggest treating ||V +∆V ||_c in
# Eq. (5) as a constant, thereby detaching it from the gradient
# graph. This means that while ||V + ∆V ||_c dynamically
# reflects the updates of ∆V , it wont receive any gradient
# during backpropagation"
weight_norm = weight_norm.detach()
mag_norm_scale = (magnitude / weight_norm).view(1, -1)
lora_result = lora_B(lora_A(x))
bias = None
if base_result is not None:
... (8 more lines)
[tool] Read peft_delora_layer.py (running)
input: {"call_id":"call_STRTnAVOq9WZ4NOQ1m9F24J2","process_id":"78221","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","sed -n '246,261p' docs/refs/peft_delora_layer.py"],"cwd":"/media/wassna...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/docs/refs/peft_delora_layer.py
[tool] Read peft_delora_layer.py (running)
input: {"call_id":"call_mcVVrgkceSeX6A8QIU5qL1OQ","process_id":"75092","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","sed -n '128,161p' docs/refs/peft_delora_layer.py"],"cwd":"/media/wassna...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/docs/refs/peft_delora_layer.py
[tool] Read peft_ia3_layer.py (running)
input: {"call_id":"call_mVR5vVoBRVvdD7i08awFEP5E","process_id":"7411","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","sed -n '291,317p' docs/refs/peft_ia3_layer.py"],"cwd":"/media/wassname/S...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/docs/refs/peft_ia3_layer.py
[tool] Read peft_hra_layer.py (running)
input: {"call_id":"call_L8erIsjTuP4GFpaT5V50afZP","process_id":"81187","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","sed -n '75,108p' docs/refs/peft_hra_layer.py"],"cwd":"/media/wassname/S...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/docs/refs/peft_hra_layer.py
[tool] Read peft_delora_layer.py (completed)
kind: read
input: {"call_id":"call_mcVVrgkceSeX6A8QIU5qL1OQ","process_id":"75092","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","sed -n '128,161p' docs/refs/peft_delora_layer.py"],"cwd":"/media/wassna...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/docs/refs/peft_delora_layer.py
output:
sed: /tmp/.mount_vscodiOHg5sd/lib/x86_64-linux-gnu/libselinux.so.1: no version information available (required by sed)
def reset_delora_parameters(
self,
adapter_name: str,
init_weights: bool = True,
delora_lambda: float = 15.0,
) -> None:
if adapter_name not in self.delora_A.keys():
return
if init_weights is True:
nn.init.kaiming_uniform_(self.delora_A[adapter_name], a=math.sqrt(5))
nn.init.zeros_(self.delora_B[adapter_name])
else:
nn.init.kaiming_uniform_(self.delora_A[adapter_name], a=math.sqrt(5))
nn.init.kaiming_uniform_(self.delora_B[adapter_name], a=math.sqrt(5))
self.delora_lambda[adapter_name].data.fill_(float(delora_lambda))
# capture a fixed norm for this adapter to use for future delta computations
with torch.no_grad():
w = self.get_base_layer().weight
if w.device.type != "meta":
w_norm = torch.norm(w.data, dim=0).detach()
else:
# For meta tensors, we can't compute the norm, so use a default value
w_norm = torch.ones(w.shape[1], device=w.device)
self.delora_w_norm[adapter_name] = w_norm
... (7 more lines)
[tool] Read peft_delora_layer.py (completed)
kind: read
input: {"call_id":"call_STRTnAVOq9WZ4NOQ1m9F24J2","process_id":"78221","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","sed -n '246,261p' docs/refs/peft_delora_layer.py"],"cwd":"/media/wassna...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/docs/refs/peft_delora_layer.py
output:
sed: /tmp/.mount_vscodiOHg5sd/lib/x86_64-linux-gnu/libselinux.so.1: no version information available (required by sed)
x_d = self.delora_dropout[adapter](x)
# Decomposed delta calculation
# 1. (x * w_norm) @ A.T
h = nn.functional.linear(x_d * self.delora_w_norm[adapter], self.delora_A[adapter])
# 2. h @ diag
An = torch.clamp(self.delora_A[adapter].norm(dim=1), min=1e-4)
Bn = torch.clamp(self.delora_B[adapter].norm(dim=0), min=1e-4)
scaling = (self.delora_lambda[adapter] / self.r[adapter]) / (An * Bn)
h = h * scaling
# 3. h @ B.T
h = nn.functional.linear(h, self.delora_B[adapter])
[tool] Read peft_ia3_layer.py (running)
input: {"call_id":"call_T5LuGO9J3PslVssywEOuH7uX","process_id":"64921","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","sed -n '208,218p' docs/refs/peft_ia3_layer.py"],"cwd":"/media/wassname/...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/docs/refs/peft_ia3_layer.py
[tool] Read peft_hra_layer.py (running)
input: {"call_id":"call_cK0RZeM4kle9U9I3sben8qMP","process_id":"80820","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","sed -n '209,265p' docs/refs/peft_hra_layer.py"],"cwd":"/media/wassname/...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/docs/refs/peft_hra_layer.py
[tool] Read peft_ia3_layer.py (completed)
kind: read
input: {"call_id":"call_mVR5vVoBRVvdD7i08awFEP5E","process_id":"7411","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","sed -n '291,317p' docs/refs/peft_ia3_layer.py"],"cwd":"/media/wassname/S...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/docs/refs/peft_ia3_layer.py
output:
sed: /tmp/.mount_vscodiOHg5sd/lib/x86_64-linux-gnu/libselinux.so.1: no version information available (required by sed)
def forward(self, x: torch.Tensor, *args: Any, **kwargs: Any) -> torch.Tensor:
dtype = previous_dtype = x.dtype
if self.disable_adapters:
if self.merged:
self.unmerge()
result = self.base_layer(x, *args, **kwargs)
elif self.merged:
result = self.base_layer(x, *args, **kwargs)
else:
ia3_scaling = 1
for active_adapter in self.active_adapters:
if active_adapter not in self.ia3_l.keys():
continue
dtype = self.ia3_l[active_adapter].dtype
ia3_scaling *= self.ia3_l[active_adapter]
if self.is_feedforward:
x = x.to(dtype)
# TODO: weight.dtype can be != self.ia3_l[self.active_adapters].dtype
# e.g. bf16 vs fp32. Is that okay?
interm = (x * ia3_scaling).to(self.get_base_layer().weight.dtype)
result = self.base_layer(interm, *args, **kwargs)
else:
result = self.base_layer(x, *args, **kwargs)
result = result.to(dtype) * ia3_scaling
[tool] Read peft_hra_layer.py (completed)
kind: read
input: {"call_id":"call_L8erIsjTuP4GFpaT5V50afZP","process_id":"81187","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","sed -n '75,108p' docs/refs/peft_hra_layer.py"],"cwd":"/media/wassname/S...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/docs/refs/peft_hra_layer.py
output:
sed: /tmp/.mount_vscodiOHg5sd/lib/x86_64-linux-gnu/libselinux.so.1: no version information available (required by sed)
self.hra_r[adapter_name] = r
self.hra_apply_GS[adapter_name] = apply_GS
# Determine shape of HRA weights
base_layer = self.get_base_layer()
if isinstance(base_layer, nn.Linear):
self.hra_u[adapter_name] = nn.Parameter(torch.empty(self.in_features, r), requires_grad=True)
elif isinstance(base_layer, nn.Conv2d):
self.hra_u[adapter_name] = nn.Parameter(
torch.empty(self.in_features * base_layer.kernel_size[0] * base_layer.kernel_size[0], r),
requires_grad=True,
)
else:
raise TypeError(f"HRA is not implemented for base layers of type {type(base_layer).__name__}")
# Initialize weights
if init_weights:
self.reset_hra_parameters(adapter_name)
else:
self.reset_hra_parameters_random(adapter_name)
# Move new weights to device
self._move_adapter_to_device_of_base_layer(adapter_name)
self.set_adapter(self.active_adapters, inference_mode=inference_mode)
def reset_hra_parameters(self, adapter_name: str):
if self.hra_r[adapter_name] % 2 != 0:
... (7 more lines)
[tool] Read peft_ia3_layer.py (completed)
kind: read
input: {"call_id":"call_T5LuGO9J3PslVssywEOuH7uX","process_id":"64921","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","sed -n '208,218p' docs/refs/peft_ia3_layer.py"],"cwd":"/media/wassname/...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/docs/refs/peft_ia3_layer.py
output:
sed: /tmp/.mount_vscodiOHg5sd/lib/x86_64-linux-gnu/libselinux.so.1: no version information available (required by sed)
def update_layer(self, adapter_name: str, config: IA3Config, **kwargs):
init_ia3_weights = config.init_ia3_weights
inference_mode = config.inference_mode
# Actual trainable parameters
num_features = self.in_features if self.is_feedforward else self.out_features
weights_size = (1, num_features) + (1,) * (self._kernel_dim - 2)
weight = torch.randn(weights_size)
self.ia3_l[adapter_name] = nn.Parameter(weight)
if init_ia3_weights:
self.reset_ia3_parameters(adapter_name)
[tool] Read peft_hra_layer.py (completed)
kind: read
input: {"call_id":"call_cK0RZeM4kle9U9I3sben8qMP","process_id":"80820","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","sed -n '209,265p' docs/refs/peft_hra_layer.py"],"cwd":"/media/wassname/...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/docs/refs/peft_hra_layer.py
output:
sed: /tmp/.mount_vscodiOHg5sd/lib/x86_64-linux-gnu/libselinux.so.1: no version information available (required by sed)
rank = self.hra_r[adapter_name]
apply_GS = self.hra_apply_GS[adapter_name]
opt_u = self.hra_u[adapter_name]
shape = opt_u.shape
if apply_GS:
weight = [(opt_u[:, 0] / opt_u[:, 0].norm()).view(-1, 1)]
for i in range(1, rank):
ui = opt_u[:, i].view(-1, 1)
for j in range(i):
ui = ui - (weight[j].t() @ ui) * weight[j]
weight.append((ui / ui.norm()).view(-1, 1))
weight = torch.cat(weight, dim=1)
weight = torch.eye(shape[0], device=opt_u.device, dtype=opt_u.dtype) - 2 * weight @ weight.t()
else:
opt_u = opt_u / opt_u.norm(dim=0)
weight = torch.eye(shape[0], device=opt_u.device, dtype=opt_u.dtype)
if reverse:
indices = range(rank - 1, -1, -1)
else:
indices = range(rank)
for i in indices:
ui = opt_u[:, i].view(-1, 1)
weight = weight - 2 * weight @ ui @ ui.t()
... (30 more lines)
[tool] Read antipasto3_svd_adapter.py (running)
input: {"call_id":"call_3DbrzJWMQFTTW4ljfMAkk6He","process_id":"80755","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","sed -n '76,104p' docs/refs/antipasto3_svd_adapter.py"],"cwd":"/media/wa...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/docs/refs/antipasto3_svd_adapter.py
[tool] Read antipasto3_svd_adapter.py (running)
input: {"call_id":"call_AlPlAWgDyADHefwo8wb8BEUN","process_id":"30191","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","sed -n '117,169p' docs/refs/antipasto3_svd_adapter.py"],"cwd":"/media/w...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/docs/refs/antipasto3_svd_adapter.py
[tool] Read peft_lora_layer.py (running)
input: {"call_id":"call_mCvMQv5zxOdAqhUiNiSkW8xv","process_id":"99551","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","sed -n '197,215p' docs/refs/peft_lora_layer.py"],"cwd":"/media/wassname...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/docs/refs/peft_lora_layer.py
[tool] Read antipasto3_svd_adapter.py (running)
input: {"call_id":"call_Vo9wquYekZsvuw8ec5SyrNMu","process_id":"25940","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","sed -n '180,212p' docs/refs/antipasto3_svd_adapter.py"],"cwd":"/media/w...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/docs/refs/antipasto3_svd_adapter.py
[tool] Read peft_eva.py (running)
input: {"call_id":"call_ATOXB8ZOgMjTzLGjtkSiskTI","process_id":"71854","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","sed -n '466,532p' docs/refs/peft_eva.py"],"cwd":"/media/wassname/SGIron...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/docs/refs/peft_eva.py
[tool] Read antipasto3_svd_adapter.py (completed)
kind: read
input: {"call_id":"call_AlPlAWgDyADHefwo8wb8BEUN","process_id":"30191","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","sed -n '117,169p' docs/refs/antipasto3_svd_adapter.py"],"cwd":"/media/w...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/docs/refs/antipasto3_svd_adapter.py
output:
sed: /tmp/.mount_vscodiOHg5sd/lib/x86_64-linux-gnu/libselinux.so.1: no version information available (required by sed)
U = self.svd_U.value
S = self.svd_S.value
Vh = self.svd_Vh.value
W_res = self.svd_W_res.value
params = self.rotation_params.value # (n_blocks, n_triu)
bs = self.block_size
n_blocks = params.shape[0]
# Reconstruct skew-symmetric from upper-triangle params (like OFT/PSOFT).
# 0.5 factor matches BOFT convention: cancels the 2x gradient from A - A^T.
A = jnp.zeros((n_blocks, bs, bs), dtype=jnp.float32)
A = A.at[:, self._triu_rows, self._triu_cols].set(params.astype(jnp.float32))
A = 0.5 * (A - jnp.swapaxes(A, -1, -2))
# Angle clamping (element-wise tanh, bounds bidirectional symmetry error)
a_limit = 2 * math.tan(self.max_angle / 2)
A = a_limit * jnp.tanh(A / a_limit)
# Cayley transform in float32: R = (I - X)^{-1}(I + X)
eye = jnp.eye(bs, dtype=jnp.float32)
X = alpha * A / 2
R_blocks = jnp.linalg.solve(
eye[None] - X,
eye[None] + X,
)
# Apply rotation to U (input singular vectors)
... (26 more lines)
[tool] Read antipasto3_svd_adapter.py (completed)
kind: read
input: {"call_id":"call_3DbrzJWMQFTTW4ljfMAkk6He","process_id":"80755","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","sed -n '76,104p' docs/refs/antipasto3_svd_adapter.py"],"cwd":"/media/wa...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/docs/refs/antipasto3_svd_adapter.py
output:
sed: /tmp/.mount_vscodiOHg5sd/lib/x86_64-linux-gnu/libselinux.so.1: no version information available (required by sed)
bs = min(rotation_block_size, r)
assert r % bs == 0, f"r={r} must be divisible by block_size={bs}"
# Frozen SVD components
self.svd_U = SVDFrozen(U.astype(jnp.float32))
self.svd_S = SVDFrozen(S.astype(jnp.float32))
self.svd_Vh = SVDFrozen(Vh.astype(jnp.float32))
self.svd_W_res = SVDFrozen(W_res.astype(jnp.bfloat16))
# Trainable: delta_s with small positive bias for symmetry breaking.
# The +4e-4 nudges the optimizer to scale up selected dims rather than just
# rotating them. Rotation alone cannot break sign symmetry at init.
key_s, key_r = jax.random.split(rngs.params())
self.delta_s = DeltaSParam(
jax.random.truncated_normal(key_s, -2.0, 2.0, (r,)) * 4e-4 + 4e-4
)
# Block-diagonal skew-symmetric rotation params (lower LR via RotationParam type)
# Upper-triangle parameterization: store only bs*(bs-1)/2 elements per block,
# like OFT/PSOFT. Avoids dead diagonal gradients and redundant (i,j)/(j,i) states.
n_blocks = r // bs
n_triu = bs * (bs - 1) // 2
self.rotation_params = RotationParam(
jax.random.truncated_normal(key_r, -2.0, 2.0, (n_blocks, n_triu)) * 1e-4
)
# Pre-compute upper-triangle indices for skew-symmetric reconstruction
rows, cols = jnp.triu_indices(bs, k=1)
... (2 more lines)
[tool] Read antipasto3_svd_adapter.py (completed)
kind: read
input: {"call_id":"call_Vo9wquYekZsvuw8ec5SyrNMu","process_id":"25940","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","sed -n '180,212p' docs/refs/antipasto3_svd_adapter.py"],"cwd":"/media/w...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/docs/refs/antipasto3_svd_adapter.py
output:
sed: /tmp/.mount_vscodiOHg5sd/lib/x86_64-linux-gnu/libselinux.so.1: no version information available (required by sed)
"""Create SVD adapter from a kernel matrix (in_dim, out_dim).
If selected_indices is provided, uses those SVD dimensions.
Otherwise uses top-r by singular value.
"""
kernel_f32 = kernel.astype(jnp.float32)
U_full, S_full, Vh_full = jnp.linalg.svd(kernel_f32, full_matrices=False)
r_actual = min(r, S_full.shape[0])
# Ensure divisible by block size
bs = min(rotation_block_size, r_actual)
r_actual = (r_actual // bs) * bs
if r_actual == 0:
r_actual = bs
if selected_indices is not None:
indices = selected_indices[:r_actual]
else:
indices = jnp.arange(r_actual)
U = U_full[:, indices]
S = S_full[indices]
Vh = Vh_full[indices, :]
W_res = kernel_f32 - U @ jnp.diag(S) @ Vh
return SVDSteeringLinear(
... (6 more lines)
[tool] Read peft_lora_layer.py (completed)
kind: read
input: {"call_id":"call_mCvMQv5zxOdAqhUiNiSkW8xv","process_id":"99551","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","sed -n '197,215p' docs/refs/peft_lora_layer.py"],"cwd":"/media/wassname...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/docs/refs/peft_lora_layer.py
output:
sed: /tmp/.mount_vscodiOHg5sd/lib/x86_64-linux-gnu/libselinux.so.1: no version information available (required by sed)
self.lora_A[adapter_name] = nn.Linear(self.in_features, r, bias=False)
self.lora_B[adapter_name] = nn.Linear(r, self.out_features, bias=lora_bias)
# Tying adapters is only implemented for Linear layers
# where the source is the embedding layer.
# Currently, this is the most prevelant way of tying layers (weight tying)
if tied_adapter:
lora_A_params = tied_adapter["lora_A"]
lora_B_params = tied_adapter["lora_B"]
self.lora_A[adapter_name].weight = torch.nn.Parameter(lora_A_params)
self.lora_B[adapter_name].weight = torch.nn.Parameter(lora_B_params)
self.lora_bias[adapter_name] = lora_bias
if use_rslora:
self.scaling[adapter_name] = lora_alpha / math.sqrt(r)
else:
self.scaling[adapter_name] = lora_alpha / r
[tool] Read peft_eva.py (completed)
kind: read
input: {"call_id":"call_ATOXB8ZOgMjTzLGjtkSiskTI","process_id":"71854","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","sed -n '466,532p' docs/refs/peft_eva.py"],"cwd":"/media/wassname/SGIron...
files: /media/wassname/SGIronWolf/projects5/2026/lora-lite/docs/refs/peft_eva.py
output:
sed: /tmp/.mount_vscodiOHg5sd/lib/x86_64-linux-gnu/libselinux.so.1: no version information available (required by sed)
eva_state_dict = {}
for name, rank in rank_dist.items():
hook = hooks[layer_hook_map[name]][0]
if not torch.all(hook.converged[:rank]):
raise ValueError(
f"Layer {name} has not converged but was assigned rank {rank}. "
"Please report this issue at https://github.com/huggingface/peft/issues"
)
u = hook.svd.components_[:rank]
if peft_config.eva_config.whiten:
u /= hook.svd.singular_values_[:rank].sqrt().reshape(-1, 1)
eva_state_dict[name] = u
# restore model state
model.train(training)
# move tensors to device
if device is not None:
eva_state_dict = {k: v.to(device) for k, v in eva_state_dict.items()}
return eva_state_dict
def _load_eva_state_dict(
model: torch.nn.Module,
eva_state_dict: dict,
adapter_name: str,
... (40 more lines)
[tool] Searching the Web (running)
[tool] Opening: https://arxiv.org/abs/2106.09685 (completed)
kind: fetch
input: https://arxiv.org/abs/2106.09685
[tool] Searching the Web (running)
[tool] Opening: https://arxiv.org/abs/2402.09353 (completed)
kind: fetch
input: https://arxiv.org/abs/2402.09353
[tool] Searching the Web (running)
[tool] Opening: https://github.com/MuLabPKU/PiSSA/blob/main/utils/init_pissa.py (completed)
kind: fetch
input: https://github.com/MuLabPKU/PiSSA/blob/main/utils/init_pissa.py
[tool] Searching the Web (running)
[tool] Opening: https://github.com/huggingface/peft/blob/main/src/peft/tuners/lora/dora.py (completed)
kind: fetch
input: https://github.com/huggingface/peft/blob/main/src/peft/tuners/lora/dora.py
[tool] Searching the Web (running)
[tool] Opening: https://github.com/huggingface/peft/blob/main/examples/eva_finetuning/eva_finetuning.py (completed)
kind: fetch
input: https://github.com/huggingface/peft/blob/main/examples/eva_finetuning/eva_finetuning.py
[tool] Searching the Web (running)
The live GitHub pages mostly resolve, though a couple of `web.open` calls return GitHub-side/internal fetch errors for specific pages. Since this is explicitly a GitHub-link task, Im also checking the `gh` skill instructions so I can use the local GitHub CLI path for raw-file sanity where possible.
[tool] Opening: https://raw.githubusercontent.com/huggingface/peft/main/src/peft/tuners/lora/layer.py (completed)
kind: fetch
input: https://raw.githubusercontent.com/huggingface/peft/main/src/peft/tuners/lora/layer.py
[tool] Read SKILL.md (running)
input: {"call_id":"call_hKiKdMrKAYVBO6nRKIdT6Ulh","process_id":"5086","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","sed -n '1,220p' /home/wassname/.claude/skills/gh/SKILL.md"],"cwd":"/medi...
files: /home/wassname/.claude/skills/gh/SKILL.md
[tool] Read SKILL.md (completed)
kind: read
input: {"call_id":"call_hKiKdMrKAYVBO6nRKIdT6Ulh","process_id":"5086","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","sed -n '1,220p' /home/wassname/.claude/skills/gh/SKILL.md"],"cwd":"/medi...
files: /home/wassname/.claude/skills/gh/SKILL.md
output:
---
name: gh
description: "Search GitHub, fetch files, and explore repos using the `gh` CLI. Use when a user provides a GitHub URL, asks to find repos/code, or wants to read files from GitHub."
---
# GitHub CLI (gh)
Requires authentication: run `gh auth status` to check, `gh auth login` if needed.
## 1. Search
Delegate search to a sub-agent (Task tool) to scan many results (50-100+) without filling
your context. The sub-agent runs the search, filters/ranks results, and returns a short summary.
### Search repos (start here)
Include `--match name,description,readme` for best recall (default only matches name+description).
```bash
GH_PAGER="" gh search repos "query" \
--match name,description,readme \
--sort stars \
--limit 50 \
--json fullName,description,stargazersCount,url
```
Additional filters: `--owner OWNER`, `--language python`, `--topic ML`, `--stars ">=100"`,
`--created ">2024-01-01"`, `--include-forks true` (off by default, adds noise but improves recall).
... (106 more lines)
[tool] Run wc -l docs/refs/peft_lora_layer.py docs/refs/peft_lora_dora.py docs/refs/peft_delora_layer.py docs/refs/peft_ia3_layer.py docs/refs/peft_hra_layer.py docs/refs/peft_eva.py docs/refs/antipasto3_svd_adapter.py (running)
input: {"call_id":"call_WBalwg2A0Sgj102Nrdm80gLZ","process_id":"79817","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","wc -l docs/refs/peft_lora_layer.py docs/refs/peft_lora_dora.py docs/ref...
[tool] Run gh auth status (running)
input: {"call_id":"call_MDZ9JcfpcHiA7VSnDD4Hj27Q","process_id":"22378","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","gh auth status"],"cwd":"/media/wassname/SGIronWolf/projects5/2026/lora-...
[tool] Run wc -l docs/refs/peft_lora_layer.py docs/refs/peft_lora_dora.py docs/refs/peft_delora_layer.py docs/refs/peft_ia3_layer.py docs/refs/peft_hra_layer.py docs/refs/peft_eva.py docs/refs/antipasto3_svd_adapter.py (completed)
kind: execute
input: {"call_id":"call_WBalwg2A0Sgj102Nrdm80gLZ","process_id":"79817","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","wc -l docs/refs/peft_lora_layer.py docs/refs/peft_lora_dora.py docs/ref...
output:
2510 docs/refs/peft_lora_layer.py
287 docs/refs/peft_lora_dora.py
274 docs/refs/peft_delora_layer.py
336 docs/refs/peft_ia3_layer.py
462 docs/refs/peft_hra_layer.py
739 docs/refs/peft_eva.py
375 docs/refs/antipasto3_svd_adapter.py
4983 total
[tool] Run gh auth status (failed)
kind: execute
input: {"call_id":"call_MDZ9JcfpcHiA7VSnDD4Hj27Q","process_id":"22378","turn_id":"019dc999-8ad5-7161-9386-95542608fab7","command":["/usr/bin/zsh","-lc","gh auth status"],"cwd":"/media/wassname/SGIronWolf/projects5/2026/lora-...
output:
github.com
X Failed to log in to github.com account wassname (/home/wassname/.config/gh/hosts.yml)
- Active account: true
- The token in /home/wassname/.config/gh/hosts.yml is invalid.
- To re-authenticate, run: gh auth login -h github.com
- To forget about this account, run: gh auth logout -h github.com -u wassname
X Failed to log in to github.com account ShouldHaveSeenThat (default)
- Active account: false
- The token in default is invalid.
- To re-authenticate, run: gh auth login -h github.com
- To forget about this account, run: gh auth logout -h github.com -u ShouldHaveSeenThat
[tool] Searching the Web (running)
[tool] Open page (completed)
kind: fetch
input: {"query":"","action":{"type":"open_page"}}
[tool] Searching the Web (running)
## lora
### params
- `lora_A`: `(r, d_in)`, `cfg.dtype`, trainable Parameter, not buffer at `src/lora_lite/variants/lora.py:26`; matches PEFT LoRA shape.
- `lora_B`: `(d_out, r)`, `cfg.dtype`, trainable Parameter, not buffer at `src/lora_lite/variants/lora.py:27`; matches PEFT. Buffers would persist if used via `persistent=True` at `src/lora_lite/adapter.py:51-53`.
### init / group_init
- `init()` no-op at `src/lora_lite/variants/lora.py:31-33`; ParamSpec does Kaiming `A`, zero `B`.
- GRADIENT FLOW at t=0: `lora_B` gets non-zero grad; `lora_A` gets zero grad because `B=0`.
### dtype
- Params allocated in `cfg.dtype` at `src/lora_lite/adapter.py:51-56`; hook casts `x` to `cfg.dtype` then returns `y.dtype` at `src/lora_lite/adapter.py:18-20`.
- No fp32-sensitive init. bf16 identity survives because `B=0`.
### forward
Math: `y + (alpha/r) x A^T B^T` at `src/lora_lite/variants/lora.py:37-41`.
Ref math: `result + scaling * B(A(dropout(x)))`; PEFT has dropout, this library has no dropout field in `src/lora_lite/config.py:6-21`.
Match? YES, modulo intentionally absent dropout.
### links
- paper: OK
- peft ref: OK
- author ref: n/a
- offline snapshot drift: AMBIGUOUS; live URL resolves, but `gh auth status` token is invalid so I could not hash raw snapshot.
### verdict
CORRECT -- standard LoRA mechanism matches PEFT/paper.
## pissa
### params
- `lora_A`: `(r, d_in)`, `cfg.dtype`, trainable Parameter at `src/lora_lite/variants/pissa.py:37`.
- `lora_B`: `(d_out, r)`, `cfg.dtype`, trainable Parameter at `src/lora_lite/variants/pissa.py:38`.
- Shapes match PEFT PiSSA; no buffers needed.
### init / group_init
- Requires exact `nn.Linear`, then fp32 SVD of `W`, copies `B=U_r sqrt(S_r)`, `A=sqrt(S_r) Vh_r`, and mutates base to `W - scale*BA` at `src/lora_lite/variants/pissa.py:42-63`.
- GRADIENT FLOW at t=0: both `A` and `B` get non-zero grad because both are non-zero.
### dtype
- SVD is correctly fp32 at `src/lora_lite/variants/pissa.py:48-55`; subtraction uses fp32 `BA` at `src/lora_lite/variants/pissa.py:58-63`.
- Precision loss: stored `A/B` are cast to `cfg.dtype` before residual subtraction at `src/lora_lite/variants/pissa.py:54-59`; this mirrors the docs “bf16 round-trip not bit-exact” caveat at `src/lora_lite/variants/pissa.py:4`.
### forward
Math: `y + (alpha/r) x A^T B^T` at `src/lora_lite/variants/pissa.py:66-71`.
Ref math: PEFT divides singular values by scaling before forming `A/B`, then subtracts `scaling*BA`; equivalent identity, but different adapter parameter scale when `alpha/r != 1`.
Match? PARTIAL; documented deviation says pass `alpha=r` for paper-faithful identity at `src/lora_lite/variants/pissa.py:6-13`.
### links
- paper: OK
- peft ref: OK
- author ref: OK
- offline snapshot drift: AMBIGUOUS; live URLs resolve, raw hash not checked due invalid `gh` auth.
### verdict
PARTIAL -- mechanism is correct for `alpha=r`; non-unit scale does not match PEFTs PiSSA parameterization.
## delora
### params
- `lora_A`: `(r, d_in)`, `cfg.dtype`, trainable Parameter at `src/lora_lite/variants/delora.py:49`.
- `lora_B`: `(d_out, r)`, `cfg.dtype`, trainable Parameter at `src/lora_lite/variants/delora.py:50`.
- `lora_lambda`: scalar `()`, `cfg.dtype`, trainable Parameter at `src/lora_lite/variants/delora.py:51-53`.
- `lora_wnorm`: `(d_in,)`, `cfg.dtype`, frozen persistent buffer at `src/lora_lite/variants/delora.py:54-56` and `src/lora_lite/adapter.py:51-53`; matches PEFTs persistent `delora_w_norm`.
### init / group_init
- Captures per-input-column norm of `W` into `lora_wnorm` at `src/lora_lite/variants/delora.py:60-66`.
- Default `lambda0=0` at `src/lora_lite/variants/delora.py:47`; this is intentionally different from PEFT/paper defaults.
- GRADIENT FLOW at t=0: with default `lambda0=0`, only `lora_lambda` gets non-zero grad; `A/B` get zero first-step grad. This is already documented at `src/lora_lite/variants/delora.py:20-24`.
### dtype
- `wnorm` is computed fp32 then stored as adapter dtype at `src/lora_lite/variants/delora.py:64-66`.
- Norms in forward use adapter dtype at `src/lora_lite/variants/delora.py:79-81`; fp16/bf16 can perturb normalization, but clamp prevents division blow-up.
### forward
Math: `y + ((x*||W||_col)A^T) * ((lambda/r)/(||A_i||||B_i||)) B^T` at `src/lora_lite/variants/delora.py:77-84`.
Ref math: PEFT DeLoRA same per-input norm and per-rank normalization; PEFT also has dropout.
Match? YES for upstream PEFT forward, modulo no dropout and documented init deviation.
### links
- paper: OK
- peft ref: DEAD/UNVERIFIED via browser cache miss for exact URL
- author ref: DEAD/UNVERIFIED via browser cache miss for exact URL
- offline snapshot drift: AMBIGUOUS
### verdict
PARTIAL -- forward matches PEFT, but identity/default init intentionally sacrifices first-step `A/B` gradients.
## ia3
### params
- `ia3`: `lora_g` `(d_out,)`, `cfg.dtype`, trainable Parameter at `src/lora_lite/variants/ia3.py:38-39`.
- `ia3_ff`: `lora_g` `(d_in,)`, `cfg.dtype`, trainable Parameter at `src/lora_lite/variants/ia3.py:55-56`.
- Shapes match PEFTs output vs feedforward feature choice.
### init / group_init
- Both init no-op; ParamSpec initializes `g=1` at `src/lora_lite/variants/ia3.py:41-43` and `src/lora_lite/variants/ia3.py:58-60`.
- GRADIENT FLOW at t=0: `lora_g` gets non-zero grad immediately for both variants.
### dtype
- Gate stored in `cfg.dtype`; output hook casts `x`, not `y`, but multiplies `y * lora_g` at `src/lora_lite/variants/ia3.py:46-47`; result then returns to `y.dtype` at `src/lora_lite/adapter.py:19-20`.
- Identity survives bf16 because `1.0` is exact.
### forward
Math: `ia3: y*g`; `ia3_ff: W(x*g)` at `src/lora_lite/variants/ia3.py:46-47` and `src/lora_lite/variants/ia3.py:63-64`.
Ref math: PEFT uses output gating for non-feedforward and input gating for feedforward.
Match? YES.
### links
- paper: OK
- peft ref: OK
- author ref: n/a
- offline snapshot drift: AMBIGUOUS
### verdict
CORRECT -- both IA3 regimes match PEFTs mechanism.
## dora
### params
- `lora_A`: `(r, d_in)`, `cfg.dtype`, trainable Parameter at `src/lora_lite/variants/dora.py:36`.
- `lora_B`: `(d_out, r)`, `cfg.dtype`, trainable Parameter at `src/lora_lite/variants/dora.py:37`.
- `lora_m`: `(d_out,)`, `cfg.dtype`, trainable Parameter at `src/lora_lite/variants/dora.py:38-39`; matches PEFT magnitude vector.
### init / group_init
- Requires exact `nn.Linear`; initializes `m=||W||_row` in fp32 then casts to `lora_m.dtype` at `src/lora_lite/variants/dora.py:43-52`.
- GRADIENT FLOW at t=0: `lora_m` and `lora_B` get non-zero grad; `lora_A` gets zero grad because `B=0`.
### dtype
- `V = layer.weight + scale*BA` is computed in current tensor dtype at `src/lora_lite/variants/dora.py:59-61`; not fp32.
- PEFT detaches norm; this implementation intentionally differentiates through norm at `src/lora_lite/variants/dora.py:10-14`.
### forward
Math: `(m/||W+sBA||) * (y + s*xA^T B^T)` at `src/lora_lite/variants/dora.py:57-66`.
Ref math: `bias + (m/||V||)*(Wx + s*BAx)`; PEFT subtracts bias before scaling.
Match? NO for biased `nn.Linear`: this code scales `bias` because `y` includes it at `src/lora_lite/variants/dora.py:65-66`.
### links
- paper: OK
- peft ref: OK
- author ref: n/a
- offline snapshot drift: AMBIGUOUS
### verdict
BUGGY -- DoRA is wrong for linear layers with bias; bias is multiplied by `m/||V||`.
## hra
### params
- `lora_U`: `(r, d_in)`, `cfg.dtype`, trainable Parameter at `src/lora_lite/variants/hra.py:49-52`; transpose of PEFTs `(d_in, r)` but mathematically equivalent.
- Rejects odd rank at `src/lora_lite/variants/hra.py:44-48`; stricter than PEFT warning, but documented.
### init / group_init
- Kaiming initializes half rows and repeats adjacent pairs at `src/lora_lite/variants/hra.py:56-65`.
- GRADIENT FLOW at t=0: repeated Householder pairs cancel to identity, but each row participates in the chain and gets non-zero gradient.
### dtype
- Householder math runs in adapter/input cast dtype via pre-hook at `src/lora_lite/adapter.py:23-28`.
- bf16 identity is near-exact for paired reflections, but norm/division in bf16 can introduce small non-bit-exactness at `src/lora_lite/variants/hra.py:73-77`.
### forward
Math: pre-hook applies `R x`, `R=Π_i(I-2u_i u_i^T/||u_i||^2)` at `src/lora_lite/variants/hra.py:69-78`.
Ref math: PEFT computes `W R` then `F.linear(x, WR)`.
Match? YES for linear layers.
### links
- paper: OK
- peft ref: DEAD/WRONG; current search finds `hra/model.py`, exact `hra/layer.py` URL did not fetch.
- author ref: OK
- offline snapshot drift: MAJOR/AMBIGUOUS for PEFT HRA URL path.
### verdict
CORRECT -- local mechanism matches the HRA reflection chain; link is stale.
## eva
### params
- `lora_A`: `(r, d_in)`, `cfg.dtype`, frozen persistent buffer at `src/lora_lite/variants/eva.py:50-52`; BUG vs PEFT LoRA `lora_A`, which remains a trainable Parameter after EVA initialization.
- `lora_B`: `(d_out, r)`, `cfg.dtype`, trainable Parameter at `src/lora_lite/variants/eva.py:53-54`.
### init / group_init
- `init()` no-op at `src/lora_lite/variants/eva.py:57-60`.
- `group_init()` requires calibration data, captures layer inputs, runs fp32 SVD, copies top right singular vectors into `lora_A` at `src/lora_lite/variants/eva.py:63-113`.
- GRADIENT FLOW at t=0: only `lora_B` gets non-zero grad; `lora_A` never trains because it is a buffer.
### dtype
- Captured activations are fp32 CPU at `src/lora_lite/variants/eva.py:78-79`; SVD is fp32 at `src/lora_lite/variants/eva.py:111`.
- `A` is cast to buffer dtype/device at `src/lora_lite/variants/eva.py:112`; bf16 loses PCA-vector precision.
### forward
Math: `y + (alpha/r) x A^T B^T` at `src/lora_lite/variants/eva.py:116-121`.
Ref math: LoRA forward after EVA copies PCA components into trainable `lora_A`; PEFT also supports rank redistribution/whitening.
Match? PARTIAL; forward equation matches, trainability does not.
### links
- paper: OK
- peft ref: OK
- author ref: n/a
- offline snapshot drift: AMBIGUOUS
### verdict
BUGGY -- `lora_A` is frozen as a buffer, and `adapter.load()` cannot load EVA because it calls `attach(model, cfg)` without calibration data at `src/lora_lite/adapter.py:132-135` while EVA requires it at `src/lora_lite/variants/eva.py:63-70`.
## antipasto
### params
- Buffers: `lora_U (d_out,r)`, `lora_S (r,)`, `lora_Vh (r,d_in)`, all `cfg.dtype`, frozen persistent buffers at `src/lora_lite/variants/antipasto.py:88-92`.
- Trainable: `lora_delta_s (r,)`, `lora_rot_T (n_blocks, bs(bs-1)/2)`, `cfg.dtype`, Parameters at `src/lora_lite/variants/antipasto.py:93-95`.
- Requires `r % block_size == 0` at `src/lora_lite/variants/antipasto.py:81-86`.
### init / group_init
- Requires exact `nn.Linear`, fp32 SVD of `W`, stores top-r factors, and mutates base to residual `W_res` at `src/lora_lite/variants/antipasto.py:99-116`.
- GRADIENT FLOW at t=0: `delta_s` gets non-zero grad; `rot_T` should get non-zero grad unless symmetry/data cancels.
### dtype
- SVD is fp32, but frozen factors are stored in `cfg.dtype` at `src/lora_lite/variants/antipasto.py:106-115`.
- Rotation is built in fp32 from `rot_T.float()` at `src/lora_lite/variants/antipasto.py:129`, then cast to `x.dtype` at `src/lora_lite/variants/antipasto.py:130`.
### forward
Math: `y_res + ((x Vh_eff^T) * (S+delta_s)) U_eff^T` at `src/lora_lite/variants/antipasto.py:132-145`.
Ref math: AntiPaSTO3 Flax convention `xW_res + ((xU_rot)*(S+alpha delta_s))Vh_rot`.
Match? PARTIAL; PyTorch basis mapping is coherent, but reference initializes `delta_s` and rotation params with small random non-zero values, while local uses exact zeros at `src/lora_lite/variants/antipasto.py:94-95`.
### links
- paper: n/a
- peft ref: n/a
- author ref: OK repo URL
- offline snapshot drift: AMBIGUOUS
### verdict
PARTIAL -- mechanism maps correctly, but initialization differs from the referenced AntiPaSTO3 code.
## summary
| variant | verdict | main issue |
|---|---:|---|
| lora | CORRECT | no mechanism bug |
| pissa | PARTIAL | scale parameterization differs unless `alpha=r` |
| delora | PARTIAL | documented init/gradient deviation |
| ia3 / ia3_ff | CORRECT | no mechanism bug |
| dora | BUGGY | bias is scaled incorrectly |
| hra | CORRECT | code OK; PEFT link stale |
| eva | BUGGY | `A` frozen; load path broken |
| antipasto | PARTIAL | zero init differs from reference random init |
MUST-FIX:
1. DoRA: handle bias like PEFT; do not multiply `base_layer.bias` by `m/||V||` (`src/lora_lite/variants/dora.py:65-66`).
2. EVA: make `lora_A` a trainable Parameter if matching PEFT, not a buffer (`src/lora_lite/variants/eva.py:50-52`).
3. EVA: fix `load()`/`group_init` interaction; current `load()` cannot attach EVA checkpoints without calibration data (`src/lora_lite/adapter.py:132-135`, `src/lora_lite/variants/eva.py:63-70`).
Nice-to-haves:
1. PiSSA: match PEFTs `Sr /= scaling` parameterization for arbitrary `alpha/r`, or keep documenting `alpha=r`.
2. AntiPaSTO: decide whether exact identity zero init is intentional vs reference random `delta_s/rot` init.
3. Refresh stale GitHub refs, especially HRA and DeLoRA.
[tool] Searching for: site:github.com/huggingface/peft src/peft/tuners/hra/layer.py, site:github.com/huggingface/peft src/peft/tuners/delora/layer.py, site:github.com ExplainableML DeLoRA peft tuners delora.py (completed)
kind: fetch
input: site:github.com/huggingface/peft src/peft/tuners/hra/layer.py
[done] end_turn