docs: self-contained CompressedLinear in README (no SVD-LLM dependency)
Browse files
README.md
CHANGED
|
@@ -26,10 +26,10 @@ tokenizer = AutoTokenizer.from_pretrained(repo, subfolder="qwen3_14b/r02/F")
|
|
| 26 |
## Factored Format — Low-Rank A, B Matrices
|
| 27 |
|
| 28 |
Each `F/` directory also contains `factors.pt` with the low-rank factors
|
| 29 |
-
`A (d
|
| 30 |
smaller than the merged weights and preserves the compression structure.
|
| 31 |
|
| 32 |
-
### Loading
|
| 33 |
|
| 34 |
```python
|
| 35 |
import torch
|
|
@@ -50,19 +50,44 @@ factors = torch.load(factors_path, map_location="cpu", weights_only=True)
|
|
| 50 |
# factors is a dict: {(layer_idx, sublayer_name): {"A": tensor, "B": tensor}}
|
| 51 |
# Example: factors[(0, "self_attn.q_proj")]["A"].shape = (5120, 2048)
|
| 52 |
print(f"Loaded {len(factors)} factor pairs")
|
| 53 |
-
print(f"Layer 0 q_proj: A={factors[(0, 'self_attn.q_proj')]['A'].shape}, "
|
| 54 |
-
f"B={factors[(0, 'self_attn.q_proj')]['B'].shape}")
|
| 55 |
```
|
| 56 |
|
| 57 |
-
### Restoring
|
| 58 |
|
| 59 |
```python
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
```
|
| 67 |
|
| 68 |
### Compression details
|
|
@@ -70,7 +95,7 @@ for (layer_idx, name), f in factors.items():
|
|
| 70 |
- **Method**: SVD-LLM whitening + mixed calibration (4096 samples, seqlen=2048)
|
| 71 |
- **Compressed sublayers** (7 per transformer block):
|
| 72 |
`q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj`
|
| 73 |
-
- **Rank formula**: `r = (1 - ratio)
|
| 74 |
- **Stage B**: Per-matrix whitened SVD truncation
|
| 75 |
- **Stage F**: End-to-end LM-loss refinement of A, B factors
|
| 76 |
|
|
|
|
| 26 |
## Factored Format — Low-Rank A, B Matrices
|
| 27 |
|
| 28 |
Each `F/` directory also contains `factors.pt` with the low-rank factors
|
| 29 |
+
`A (d*r)` and `B (r*n)` for every compressed linear layer. This is ~20%
|
| 30 |
smaller than the merged weights and preserves the compression structure.
|
| 31 |
|
| 32 |
+
### Loading factors (for analysis or continued training)
|
| 33 |
|
| 34 |
```python
|
| 35 |
import torch
|
|
|
|
| 50 |
# factors is a dict: {(layer_idx, sublayer_name): {"A": tensor, "B": tensor}}
|
| 51 |
# Example: factors[(0, "self_attn.q_proj")]["A"].shape = (5120, 2048)
|
| 52 |
print(f"Loaded {len(factors)} factor pairs")
|
|
|
|
|
|
|
| 53 |
```
|
| 54 |
|
| 55 |
+
### Restoring low-rank structure (no external dependencies)
|
| 56 |
|
| 57 |
```python
|
| 58 |
+
import torch
|
| 59 |
+
import torch.nn as nn
|
| 60 |
+
|
| 61 |
+
class CompressedLinear(nn.Module):
|
| 62 |
+
"""Low-rank linear: y = A @ (B @ x) + bias, where A is (d, r) and B is (r, n)."""
|
| 63 |
+
def __init__(self, A, B, bias=None):
|
| 64 |
+
super().__init__()
|
| 65 |
+
d, r = A.shape
|
| 66 |
+
_, n = B.shape
|
| 67 |
+
self.first = nn.Linear(n, r, bias=False)
|
| 68 |
+
self.second = nn.Linear(r, d, bias=bias is not None)
|
| 69 |
+
self.first.weight = nn.Parameter(B)
|
| 70 |
+
self.second.weight = nn.Parameter(A)
|
| 71 |
+
if bias is not None:
|
| 72 |
+
self.second.bias = nn.Parameter(bias)
|
| 73 |
+
|
| 74 |
+
def forward(self, x):
|
| 75 |
+
return self.second(self.first(x.to(self.first.weight.dtype))).to(x.dtype)
|
| 76 |
+
|
| 77 |
+
# Replace merged layers with factored versions
|
| 78 |
+
for (layer_idx, sublayer_name), f in factors.items():
|
| 79 |
+
layer = model.model.layers[layer_idx]
|
| 80 |
+
parts = sublayer_name.split(".")
|
| 81 |
+
parent = layer
|
| 82 |
+
for p in parts[:-1]:
|
| 83 |
+
parent = getattr(parent, p)
|
| 84 |
+
original = getattr(parent, parts[-1])
|
| 85 |
+
bias = original.bias.data if original.bias is not None else None
|
| 86 |
+
compressed = CompressedLinear(f["A"], f["B"], bias=bias)
|
| 87 |
+
setattr(parent, parts[-1], compressed)
|
| 88 |
+
|
| 89 |
+
# Now each compressed sublayer has .first.weight (B) and .second.weight (A)
|
| 90 |
+
# Total trainable params = sum of A and B sizes, ~20% fewer than original
|
| 91 |
```
|
| 92 |
|
| 93 |
### Compression details
|
|
|
|
| 95 |
- **Method**: SVD-LLM whitening + mixed calibration (4096 samples, seqlen=2048)
|
| 96 |
- **Compressed sublayers** (7 per transformer block):
|
| 97 |
`q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj`
|
| 98 |
+
- **Rank formula**: `r = (1 - ratio) * d * n / (d + n)`
|
| 99 |
- **Stage B**: Per-matrix whitened SVD truncation
|
| 100 |
- **Stage F**: End-to-end LM-loss refinement of A, B factors
|
| 101 |
|