v7: C5 Data-Informed Subspace Init + restructure contributions to 2 core claims
Browse files
improve_gainlora/IDEA_Overall.md
ADDED
|
@@ -0,0 +1,432 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# SpecRoute: Định tuyến Phổ thông qua Duality Định tuyến–Bảo vệ trong Học liên tục với LoRA
|
| 2 |
+
|
| 3 |
+
> **Tài liệu thiết kế chính thức — V7**
|
| 4 |
+
> Ràng buộc: Zero-replay nghiêm ngặt. Theory-first.
|
| 5 |
+
|
| 6 |
+
---
|
| 7 |
+
|
| 8 |
+
## 1. Đặt bài toán
|
| 9 |
+
|
| 10 |
+
**Setting.** Học liên tục với LoRA mở rộng trên một LLM đóng băng.
|
| 11 |
+
Các tasks $\mathcal{T}_1, \ldots, \mathcal{T}_T$ đến tuần tự. Với mỗi task $t$:
|
| 12 |
+
|
| 13 |
+
- Một adapter low-rank $\Delta W_t = B_t A_t$ ($A_t \in \mathbb{R}^{r \times d}$, $B_t \in \mathbb{R}^{d \times r}$) được thêm vào mọi phép chiếu attention.
|
| 14 |
+
- Chỉ $B_t$ được huấn luyện; $A_t$ bị đóng băng sau khi khởi tạo null-space (InfLoRA).
|
| 15 |
+
- Sau khi huấn luyện, cả $A_t, B_t$ đều bị đóng băng và một nhánh mới được tạo cho task tiếp theo.
|
| 16 |
+
|
| 17 |
+
**Inference.** Cho input $x$ *không có* task identifier, mô hình phải tạo ra output đúng:
|
| 18 |
+
|
| 19 |
+
$$y = f\!\Bigl(W_0\, x \;+\; \sum_{t=1}^{T} w_t(x)\; B_t A_t\, x\Bigr)$$
|
| 20 |
+
|
| 21 |
+
**Ba bài toán con kết hợp:**
|
| 22 |
+
|
| 23 |
+
| Bài toán con | Mục tiêu | Yêu cầu hình thức |
|
| 24 |
+
|:------------:|---------|-------------------|
|
| 25 |
+
| **Routing (R)** | Gán input đúng expert | $w_{t^*}(x) \gg w_t(x)$ với $t \neq t^*$ |
|
| 26 |
+
| **Protection (P)** | Ngăn suy giảm expert cũ | $\Delta W_t$ không đổi sau task $t$ |
|
| 27 |
+
| **Allocation (A)** | Quản lý capacity không gian con hữu hạn | $\sum_t \dim\bigl(\mathrm{span}(A_t)\bigr) \leq d$ |
|
| 28 |
+
|
| 29 |
+
**Ràng buộc setting:** *Zero-replay* — không tái sử dụng dữ liệu task cũ dưới bất kỳ hình thức nào (thô, synthetic, hay phân phối thống kê).
|
| 30 |
+
|
| 31 |
+
---
|
| 32 |
+
|
| 33 |
+
## 2. Quan sát: Duality Ẩn
|
| 34 |
+
|
| 35 |
+
### 2.1 Tiếp cận của GainLoRA và Điểm yếu
|
| 36 |
+
|
| 37 |
+
GainLoRA (NeurIPS 2025) xử lý R, P, A như các bài toán **độc lập**:
|
| 38 |
+
|
| 39 |
+
| Khía cạnh | Cơ chế | Chi phí |
|
| 40 |
+
|-----------|--------|---------|
|
| 41 |
+
| R | MLP `trans_input` học được + `prompt_key` học được → cosine gating | Tham số thêm + subspace GPM |
|
| 42 |
+
| P | GPM chiếu gradient vào null-space của task cũ | Tiêu thụ subspace mỗi task |
|
| 43 |
+
| A | Threshold tăng dần $\varepsilon_t \nearrow 1$ | Task sau bị ràng buộc hơn |
|
| 44 |
+
|
| 45 |
+
**Điểm yếu cơ bản:** Vì routing được *học*, nó tạo ra vòng lặp xấu:
|
| 46 |
+
|
| 47 |
+
1. `trans_input` thay đổi mỗi task → routing space trôi dạt → prompt keys cũ mất alignment → routing suy giảm.
|
| 48 |
+
2. GPM phải bảo vệ routing params → *tiêu thụ subspace có thể dùng cho task learning*.
|
| 49 |
+
3. KL distillation trên routing cần thiết → yêu cầu replay hoặc frozen copies → overhead bộ nhớ.
|
| 50 |
+
|
| 51 |
+
### 2.2 Nhận thức then chốt
|
| 52 |
+
|
| 53 |
+
Chúng tôi quan sát rằng GPM đảm bảo xấp xỉ các subspace input của expert trực giao nhau:
|
| 54 |
+
|
| 55 |
+
$$\mathrm{span}(V_i) \;\approx\perp\; \mathrm{span}(V_j), \qquad i \neq j$$
|
| 56 |
+
|
| 57 |
+
trong đó $V_t$ là các right singular vectors của $\Delta W_t$. Tính trực giao này, được đảm bảo cho mục đích **bảo vệ**, đồng thời cung cấp tiêu chí **routing** tự nhiên: vì các subspace không chồng chéo, đo lường mức độ một input căn chỉnh với từng subspace sẽ xác định duy nhất task gốc.
|
| 58 |
+
|
| 59 |
+
> **Duality Định tuyến–Bảo vệ.**
|
| 60 |
+
> Chống quên (bảo vệ subspace trực giao) và nhận diện task (routing phân biệt)
|
| 61 |
+
> là *hai biểu hiện kép của cùng một cấu trúc phổ*.
|
| 62 |
+
> Giải quyết một bài toán tự động giải quyết bài toán kia.
|
| 63 |
+
|
| 64 |
+
**Hệ quả:**
|
| 65 |
+
- Không cần tham số routing học được → không trôi dạt routing, không tốn GPM cho routing.
|
| 66 |
+
- Không cần replay để duy trì routing → tự nhiên tuân thủ zero-replay.
|
| 67 |
+
- Độ chính xác routing được *đảm bảo* bởi chất lượng bảo vệ (được hình thức hoá bên dưới).
|
| 68 |
+
|
| 69 |
+
---
|
| 70 |
+
|
| 71 |
+
## 3. Khung Lý thuyết
|
| 72 |
+
|
| 73 |
+
### 3.1 Spectral Expert Signatures
|
| 74 |
+
|
| 75 |
+
**Định nghĩa 1** *(Spectral Signature).* Với expert đóng băng $\Delta W_t = B_t A_t$ và thin SVD
|
| 76 |
+
|
| 77 |
+
$$\Delta W_t = U_t\, \Sigma_t\, V_t^\top, \qquad V_t \in \mathbb{R}^{d \times r},\; \Sigma_t = \mathrm{diag}(\sigma_{t,1}, \ldots, \sigma_{t,r}),$$
|
| 78 |
+
|
| 79 |
+
spectral signature là $\mathcal{S}_t = (V_t,\, \boldsymbol{\sigma}_t)$ trong đó:
|
| 80 |
+
|
| 81 |
+
- $V_t$: **input receptive field** — $r$ hướng input mà expert xử lý,
|
| 82 |
+
- $\boldsymbol{\sigma}_t$: **sensitivity spectrum** — hệ số khuếch đại biến đổi dọc mỗi hướng.
|
| 83 |
+
|
| 84 |
+
**Góc nhìn lý thuyết thông tin.** Xem $\Delta W_t$ như một kênh tuyến tính, cột của $V_t$ là *input modes* của kênh và $\sigma_{t,i}^2$ là *gain* của mode $i$. Tổng channel capacity (Frobenius energy) là $\|\Delta W_t\|_F^2 = \sum_i \sigma_{t,i}^2$.
|
| 85 |
+
|
| 86 |
+
### 3.2 Spectral Affinity
|
| 87 |
+
|
| 88 |
+
**Định nghĩa 2** *(Spectral Affinity).* Độ tương hợp của input $h \in \mathbb{R}^d$ với expert $t$:
|
| 89 |
+
|
| 90 |
+
$$\alpha_t(h) \;=\; \frac{h^\top M_t\, h}{\mathrm{tr}(M_t)\;\|h\|^2}, \qquad M_t = V_t\, \mathrm{diag}(\boldsymbol{\sigma}_t^2)\, V_t^\top$$
|
| 91 |
+
|
| 92 |
+
Khai triển:
|
| 93 |
+
|
| 94 |
+
$$\alpha_t(h) = \frac{\displaystyle\sum_{i=1}^{r} \sigma_{t,i}^2\;(v_{t,i}^\top h)^2}{\displaystyle\Bigl(\sum_{i=1}^{r} \sigma_{t,i}^2\Bigr)\,\|h\|^2}$$
|
| 95 |
+
|
| 96 |
+
**Tính chất:**
|
| 97 |
+
|
| 98 |
+
| Tính chất | Phát biểu |
|
| 99 |
+
|-----------|-----------|
|
| 100 |
+
| Dải giá trị | $\alpha_t(h) \in [0,\, 1]$ — weighted Rayleigh quotient chuẩn hoá |
|
| 101 |
+
| Energy ratio | $\alpha_t(h) = \|\Delta W_t\, h\|^2 \;/\; \bigl(\|\Delta W_t\|_F^2\, \|h\|^2\bigr)$ |
|
| 102 |
+
| Ý nghĩa | Phần channel capacity của expert $t$ được kích hoạt bởi $h$ |
|
| 103 |
+
| In-distribution | $h \in \mathrm{span}(V_t) \;\Rightarrow\; \alpha_t(h) \geq \kappa_{\min}(t) > 0$ |
|
| 104 |
+
| Out-of-distribution | $h \perp \mathrm{span}(V_t) \;\Rightarrow\; \alpha_t(h) = 0$ chính xác |
|
| 105 |
+
|
| 106 |
+
### 3.3 Định lý Duality Định tuyến–Bảo vệ
|
| 107 |
+
|
| 108 |
+
**Định nghĩa 3** *(Subspace Overlap).* Độ chồng chéo giữa các expert $i$ và $j$:
|
| 109 |
+
|
| 110 |
+
$$\delta_{ij} = \|V_i^\top V_j\|_F^2 = \sum_{k=1}^{r} \cos^2 \theta_{ij}^{(k)}$$
|
| 111 |
+
|
| 112 |
+
trong đó $\theta_{ij}^{(k)}$ là các *principal angles* giữa $\mathrm{span}(V_i)$ và $\mathrm{span}(V_j)$.
|
| 113 |
+
|
| 114 |
+
---
|
| 115 |
+
|
| 116 |
+
**Định lý 1** *(Duality Định tuyến–Bảo vệ).* Nếu GPM đảm bảo $\delta_{ij} \leq \varepsilon$ với mọi $i \neq j$, thì với mọi unit input $h \in \mathrm{span}(V_{t^*})$, **routing margin** thoả mãn:
|
| 117 |
+
|
| 118 |
+
$$\boxed{\;\alpha_{t^*}(h) \;-\; \max_{t \neq t^*}\, \alpha_t(h) \;\;\geq\;\; \kappa_{\min}(t^*)\; -\; \varepsilon\, \kappa_{\max}\;}$$
|
| 119 |
+
|
| 120 |
+
trong đó:
|
| 121 |
+
|
| 122 |
+
$$\kappa_{\min}(t) = \frac{\sigma_{t,\min}^2}{\sum_i \sigma_{t,i}^2}, \qquad \kappa_{\max} = \max_t\, \frac{\sigma_{t,\max}^2}{\sum_i \sigma_{t,i}^2}$$
|
| 123 |
+
|
| 124 |
+
**Chứng minh.**
|
| 125 |
+
|
| 126 |
+
*Cận dưới cho expert đúng.* Viết $h = V_{t^*}\, c$ với $\|c\| = 1$. Khi đó $(v_{t^*,i}^\top h)^2 = c_i^2$ và $\sum c_i^2 = 1$:
|
| 127 |
+
|
| 128 |
+
$$\alpha_{t^*}(h) = \frac{\sum_i \sigma_{t^*,i}^2\, c_i^2}{\sum_i \sigma_{t^*,i}^2} \;\geq\; \kappa_{\min}(t^*)$$
|
| 129 |
+
|
| 130 |
+
*Cận trên cho expert sai.* Với $t \neq t^*$:
|
| 131 |
+
|
| 132 |
+
$$\|V_t^\top h\|^2 \leq \delta_{t,t^*} \leq \varepsilon \;\;\Rightarrow\;\; \alpha_t(h) \leq \kappa_{\max}\, \varepsilon \qquad\square$$
|
| 133 |
+
|
| 134 |
+
---
|
| 135 |
+
|
| 136 |
+
**Hệ quả 1** *(Routing Confidence).* Với softmax routing nhiệt độ $\tau$:
|
| 137 |
+
|
| 138 |
+
$$w_{t^*}(h) \;\geq\; \frac{1}{1 + (T{-}1)\,\exp\!\bigl(-m/\tau\bigr)}, \qquad m = \kappa_{\min}(t^*) - \varepsilon\, \kappa_{\max}$$
|
| 139 |
+
|
| 140 |
+
Để đạt confidence mục tiêu $w_{t^*} \geq 1 - \delta$, đặt $\tau \leq m \,/\, \ln\!\bigl(\tfrac{T-1}{\delta}\bigr)$.
|
| 141 |
+
|
| 142 |
+
---
|
| 143 |
+
|
| 144 |
+
**Hệ quả 2** *(Capacity Bound — Kết nối Grassmannian).* Số lượng tối đa subspace $r$-chiều trong $\mathbb{R}^d$ với pairwise overlap $\delta \leq \varepsilon$:
|
| 145 |
+
|
| 146 |
+
$$T_{\max} \;\leq\; \frac{d}{r\,(1 - \varepsilon)}$$
|
| 147 |
+
|
| 148 |
+
Với T5-Small ($d = 512$, $r = 8$, $\varepsilon = 0.02$): $T_{\max} \leq 65 \gg 15$ tasks. Điều này kết nối capacity học liên tục với lý thuyết Grassmannian packing.
|
| 149 |
+
|
| 150 |
+
### 3.4 Drift Invariance
|
| 151 |
+
|
| 152 |
+
**Mệnh đề 1** *(Drift-Free Routing).* Hàm routing $h \mapsto \alpha_t(h)$ hoàn toàn ổn định qua tất cả các task.
|
| 153 |
+
|
| 154 |
+
**Chứng minh.** Routing input được tính từ frozen embedding table, *trước* bất kỳ transformer block nào. LoRA chỉ tồn tại trong các attention layer sâu hơn → $h$ độc lập với mọi tham số LoRA. Kết hợp với $\mathcal{S}_t$ đóng băng, $\alpha_t(h)$ bất biến với mọi thay đổi tích luỹ. $\square$
|
| 155 |
+
|
| 156 |
+
### 3.5 Vấn đề then chốt: Null-Space Collapse
|
| 157 |
+
|
| 158 |
+
Định lý 1 giả định $h \in \mathrm{span}(V_{t^*})$. Trong thực tế điều này đòi hỏi hai điều kiện:
|
| 159 |
+
|
| 160 |
+
**(A) Expert phải học được:** $A_t$ phải nằm trong subspace có liên quan đến task $t$ để $B_t$ có thể học các biến đổi có ý nghĩa, tạo ra $\sigma_{t,i} > 0$ đáng kể.
|
| 161 |
+
|
| 162 |
+
**(B) Input phải có projection:** Inputs thực tế của task $t$ phải chiếu có năng lượng lên $\text{span}(V_t)$.
|
| 163 |
+
|
| 164 |
+
**InfLoRA gốc vi phạm (A):** $A_t$ được khởi tạo ngẫu nhiên (Kaiming) rồi chiếu vào null-space của GPM:
|
| 165 |
+
|
| 166 |
+
$$A_t \leftarrow A_t - A_t P_{\text{old}}, \quad \text{normalize}$$
|
| 167 |
+
|
| 168 |
+
Null-space (sau $t-1$ tasks) là một không gian $d - N_{\text{protected}}$ chiều. Kaiming random trong không gian này KHÔNG ĐẢM BẢO alignment với các hướng có liên quan đến task $t$. Khi null-space thu hẹp dần (Layer 7: 8/512 → 161/512 → 344/512 qua 13 tasks), xác suất random init bắt được đúng hướng task-relevant giảm theo.
|
| 169 |
+
|
| 170 |
+
**Hệ quả thực nghiệm (V6):** IMDB (task 8) — eval_loss dừng ở 6.37 sau 10 epoch, EM=0.0 suốt quá trình, expert thực sự không thể học bất cứ điều gì hữu ích.
|
| 171 |
+
|
| 172 |
+
---
|
| 173 |
+
|
| 174 |
+
## 4. Các Thành phần Framework
|
| 175 |
+
|
| 176 |
+
### C1 — Spectral Expert Signatures
|
| 177 |
+
|
| 178 |
+
Sau khi train task $t$, tính $\mathcal{S}_t = (V_t, \boldsymbol{\sigma}_t)$ qua **thin SVD**:
|
| 179 |
+
|
| 180 |
+
$$B_t,\, A_t \;\xrightarrow[\text{QR + SVD}]{O(dr^2)}\; (V_t,\, \boldsymbol{\sigma}_t)$$
|
| 181 |
+
|
| 182 |
+
- QR decomposition của $B$ và $A^\top$, sau đó SVD của $r \times r$ core ��� chính xác, $O(dr^2)$ so với $O(d^2 r)$.
|
| 183 |
+
- Lưu trên mỗi LoRA layer (encoder Q, V; decoder self/cross Q, V).
|
| 184 |
+
- **Bất biến** theo cấu trúc: weights đóng băng → signatures đóng băng → không trôi dạt.
|
| 185 |
+
|
| 186 |
+
### C2 — Spectral Affinity Routing
|
| 187 |
+
|
| 188 |
+
**Inference** (tất cả task, routing SVD đối xứng):
|
| 189 |
+
|
| 190 |
+
$$w(h) = \mathrm{softmax}\!\left(\frac{[\alpha_1(h),\; \ldots,\; \alpha_T(h)]}{\tau}\right)$$
|
| 191 |
+
|
| 192 |
+
Mọi task đều dùng cùng công thức $\sigma^2$-weighted spectral affinity (Định nghĩa 2). Sau khi train task $t$, tính $\mathcal{S}_t$ một lần qua `prepare_inference_routing()` và sử dụng cùng signatures của task cũ.
|
| 193 |
+
|
| 194 |
+
**Training** (task $t$, SVD cuối chưa biết vì $B_t$ đang train):
|
| 195 |
+
|
| 196 |
+
$$\alpha_t^{\mathrm{train}}(h) = \frac{\|A_t\, h\|^2}{r\,\|h\|^2} + \beta(n), \qquad \beta(n) = \tau \cdot \ln\!\left(\frac{\alpha_{\mathrm{target}} \cdot n}{1 - \alpha_{\mathrm{target}}}\right)$$
|
| 197 |
+
|
| 198 |
+
trong đó $n = |\{\text{task cũ}\}|$ và $\alpha_{\mathrm{target}} \in (0,1)$ là routing weight mục tiêu cho task hiện tại (mặc định 0.8).
|
| 199 |
+
|
| 200 |
+
**Lý giải proxy A-row:** Với $B_t$ full-rank bất kỳ, column span của $V_t$ (từ SVD của $B_t A_t$) bằng $\mathrm{range}(A_t^\top)$. Vì vậy các hàng $A$ span *cùng* subspace input mà $V_t$ hội tụ sẽ capture. Proxy đo alignment input với subspace này dùng weighting đồng đều (chưa có $\sigma$).
|
| 201 |
+
|
| 202 |
+
**Lý giải adaptive $\beta(n)$:** Bias hằng số gây routing weight của task hiện tại giảm $O(1/n)$ theo số task (softmax dilution). Công thức adaptive chuẩn hoá điều này: giải $w_t = \alpha_{\mathrm{target}}$ trong phương trình softmax cho ra closed-form trên. Đảm bảo task hiện tại nhận được routing weight $\approx \alpha_{\mathrm{target}}$ bất kể $n$.
|
| 203 |
+
|
| 204 |
+
**Lý giải symmetric inference:** Tại inference, $B_t$ đóng băng và $\Delta W_t = B_t A_t$ có SVD xác định. Dùng cùng $\sigma^2$-weighted Rayleigh quotient cho tất cả task đảm bảo *đối xứng đo lường* — mọi affinity đều sống trên cùng metric space, và Định lý 1 áp dụng thống nhất.
|
| 205 |
+
|
| 206 |
+
| Phase | Cơ chế routing | Nhiệt độ | Lý do |
|
| 207 |
+
|-------|----------------|----------|-------|
|
| 208 |
+
| Training (task $t$) | A-row fit + adaptive $\beta(n)$ | $\tau = 1.0$ | $B=0$ cold-start; β bù softmax dilution |
|
| 209 |
+
| Inference (mọi task) | SVD spectral affinity (đối xứng) | $\tau = 1.0$ | Mọi task dùng σ²-weighted Rayleigh quotient |
|
| 210 |
+
|
| 211 |
+
### C3 — Capacity-Aware Subspace Allocation
|
| 212 |
+
|
| 213 |
+
GPM threshold kiểm soát đánh đổi bảo vệ–capacity. Từ Định lý 1:
|
| 214 |
+
- $\varepsilon$ thấp hơn → bảo vệ & routing tốt hơn, nhưng null-space cạn nhanh hơn.
|
| 215 |
+
- $\varepsilon$ cao hơn → nhiều capacity hơn, nhưng đảm bảo routing yếu hơn.
|
| 216 |
+
|
| 217 |
+
**Dynamic threshold** (theo InfLoRA):
|
| 218 |
+
|
| 219 |
+
$$\varepsilon_t = (1 - \varepsilon_0) \cdot \frac{t}{T} + \varepsilon_0$$
|
| 220 |
+
|
| 221 |
+
trong đó $\varepsilon_0$ là base threshold. Phân bổ bảo vệ nghiêm ngặt dần khi task tích luỹ. Đánh đổi là *có nguyên tắc* qua Hệ quả 2: miễn là $\varepsilon_t$ vượt $(1 - d/(rT))$, capacity cho tất cả $T$ task được đảm bảo.
|
| 222 |
+
|
| 223 |
+
---
|
| 224 |
+
|
| 225 |
+
### C4 — Spectrally-Conditioned Gradient (Implementation Detail)
|
| 226 |
+
|
| 227 |
+
> **Lưu ý phân loại:** C4 là chi tiết triển khai, không phải đóng góp lý thuyết độc lập. Nó giải quyết một vấn đề kỹ thuật thuần túy: sau khi `get_reg_matrix()` chiếu $A_t$ vào null-space, column space của $A_t$ không còn trực giao, khiến gradient $\nabla_B \mathcal{L} = \nabla_{\Delta W} \mathcal{L} \cdot A^T$ bị biến dạng. Việc áp dụng preconditioner là một hiệu chỉnh kỹ thuật cần thiết, không phải một luận điểm học thuật mới.
|
| 228 |
+
|
| 229 |
+
Gradient $\nabla_B \mathcal{L}$ bị biến dạng bởi condition number của $A^T$. Chúng tôi áp dụng preconditioner một lần sau khi $A$ đóng băng:
|
| 230 |
+
|
| 231 |
+
$$\tilde{\nabla}_B = \nabla_B \mathcal{L} \cdot (AA^T + \epsilon I)^{-1/2}$$
|
| 232 |
+
|
| 233 |
+
Preconditioner được tính **một lần** sau `get_reg_matrix()` — không có overhead per-step.
|
| 234 |
+
|
| 235 |
+
> **Lưu ý:** Spectral entropy regularization (C4.2) được loại bỏ khỏi V7. Lý do: C5 (Data-Informed Init) khởi tạo $A_t$ sao cho $B_t$ học trong subspace task-relevant → singular values tự nhiên sẽ phân tán theo dữ liệu. Cưỡng bức entropy uniform qua regularization mâu thuẫn với triết lý của C5 (để dữ liệu dẫn dắt phân phối phổ, không phải regularizer). Preconditioner gradient (C4.1) vẫn giữ vì nó sửa điều kiện ma trận, không ảnh hưởng đến triết lý data-driven.
|
| 236 |
+
|
| 237 |
+
---
|
| 238 |
+
|
| 239 |
+
### C5 — Data-Informed Subspace Initialization (Đóng góp chính)
|
| 240 |
+
|
| 241 |
+
#### Động lực
|
| 242 |
+
|
| 243 |
+
Khi $A_t$ được khởi tạo ngẫu nhiên và chiếu vào null-space, nó chiếm một điểm *tùy ý* trên restricted Grassmannian $\mathrm{Gr}(r,\, d - N_{\text{protected}})$. Với $\dim\bigl(\mathrm{Gr}(8, 351)\bigr) = 8 \times 343 = 2744$, không gian lựa chọn rất lớn — random init gần như chắc chắn sub-optimal. Đặc biệt khi null-space thu hẹp, các hướng task-relevant ngày càng chiếm tỷ lệ nhỏ trong không gian còn lại, làm cho random init càng kém hiệu quả.
|
| 244 |
+
|
| 245 |
+
#### Bài toán tối ưu
|
| 246 |
+
|
| 247 |
+
Chúng tôi đặt vấn đề khởi tạo $A_t$ như bài toán tối ưu có ràng buộc:
|
| 248 |
+
|
| 249 |
+
$$\max_{A_t} \quad \text{tr}\!\bigl(A_t\, Q\, C_t\, Q\, A_t^T\bigr) \quad \text{s.t.} \quad A_t A_t^T = I_r$$
|
| 250 |
+
|
| 251 |
+
trong đó $Q = I - P_{\text{old}}$ là null-space projector (với $P_{\text{old}} = \mathcal{B}\mathcal{B}^T$ là GPM projection matrix), và:
|
| 252 |
+
|
| 253 |
+
$$C_t = \frac{1}{|\mathcal{X}_t|} \sum_{x \in \mathcal{X}_t} h(x)\, h(x)^T$$
|
| 254 |
+
|
| 255 |
+
là activation covariance của task $t$ được ước tính từ vài batch đầu của dữ liệu training.
|
| 256 |
+
|
| 257 |
+
**Ý nghĩa:** Maximize variance captured trong null-space theo phân phối dữ liệu task $t$ — tức là tìm subspace $r$-chiều trong null-space *phù hợp nhất* với dữ liệu task hiện tại.
|
| 258 |
+
|
| 259 |
+
#### Lời giải dạng đóng
|
| 260 |
+
|
| 261 |
+
Định nghĩa **projected covariance**: $\tilde{C}_t = Q\, C_t\, Q$.
|
| 262 |
+
|
| 263 |
+
Bài toán trở thành constrained PCA tiêu chuẩn trên $\tilde{C}_t$. Lời giải chính xác là:
|
| 264 |
+
|
| 265 |
+
$$A_t = \text{top-}r\text{ eigenvectors của } \tilde{C}_t$$
|
| 266 |
+
|
| 267 |
+
hay tương đương, các hàng của $A_t$ là $r$ eigenvectors ứng với eigenvalues lớn nhất của $\tilde{C}_t = Q C_t Q$.
|
| 268 |
+
|
| 269 |
+
**Thuật toán** (Constrained PCA trong null-space):
|
| 270 |
+
|
| 271 |
+
```
|
| 272 |
+
# Bước 1: Thu thập activation covariance (forward pass nhỏ, trước training)
|
| 273 |
+
C_t = ∑ h(x)h(x)^T / N_batch # covariance input task t (N_batch ~200 batches)
|
| 274 |
+
|
| 275 |
+
# Bước 2: Project covariance vào null-space
|
| 276 |
+
Q = I - P_old # null-space projector (từ GPM bases đã lưu)
|
| 277 |
+
C_tilde = Q @ C_t @ Q # projected covariance
|
| 278 |
+
|
| 279 |
+
# Bước 3: Eigenvector decomposition
|
| 280 |
+
eigvals, eigvecs = eigh(C_tilde) # đối xứng → eigh nhanh hơn SVD
|
| 281 |
+
top_r_idx = argsort(eigvals, descending=True)[:r]
|
| 282 |
+
|
| 283 |
+
# Bước 4: Set A_t
|
| 284 |
+
A_t = eigvecs[:, top_r_idx].T # shape (r, d) — direction task-relevant nhất trong null-space
|
| 285 |
+
A_t = A_t / norm(A_t, dim=1, keepdim=True) * sqrt(3) # normalize như InfLoRA gốc
|
| 286 |
+
```
|
| 287 |
+
|
| 288 |
+
#### Ý nghĩa Lý thuyết Thông tin
|
| 289 |
+
|
| 290 |
+
Theo Data Processing Inequality, với bất kỳ ma trận $A_t$ nào:
|
| 291 |
+
$$I(A_t h;\, y) \leq I(h;\, y)$$
|
| 292 |
+
|
| 293 |
+
Nhưng trong ràng buộc null-space, không phải mọi $A_t$ đều bằng nhau. Data-informed $A_t$ **maximize** $I(A_t h; y)$ trong lớp các $A_t$ thỏa mãn null-space constraint — trong khi random $A_t$ chỉ capture một phần ngẫu nhiên, không được tối ưu hoá.
|
| 294 |
+
|
| 295 |
+
Ngoài ra, khi $A_t$ được khởi tạo tốt hơn, $B_t$ huấn luyện trong subspace có liên quan đến task → $\sigma_{t,i}$ lớn hơn → spectral signature $\mathcal{S}_t$ mạnh hơn → routing margin $\kappa_{\min}(t)$ trong Định lý 1 **tăng**. Đây là kết nối trực tiếp từ C5 trở lại lý thuyết routing.
|
| 296 |
+
|
| 297 |
+
#### Tương thích Zero-Replay
|
| 298 |
+
|
| 299 |
+
$C_t$ được tính từ **dữ liệu training của task hiện tại** (task $t$ đang được huấn luyện). Đây không phải replay (replay = tái sử dụng dữ liệu *cũ*). Dữ liệu training của task hiện tại luôn sẵn có trong CL setting. $A_t$ (model parameter) chỉ encode *hướng* (không phải giá trị hay vị trí dữ liệu cụ thể), tương tự GPM bases cũng tính từ activation covariance và đã được chấp nhận trong InfLoRA, GainLoRA. ✅ zero-replay compliant.
|
| 300 |
+
|
| 301 |
+
#### Kết nối với Bài toán Gốc
|
| 302 |
+
|
| 303 |
+
| V6 failure mode | Root cause | C5 giải quyết |
|
| 304 |
+
|-----------------|-----------|---------------|
|
| 305 |
+
| IMDB/SST2 EM=0 (never-learning) | $A_t$ random bỏ lỡ task-relevant directions trong null-space | $A_t$ data-informed capture variance cao nhất trong null-space → $B_t$ CÓ THỂ học |
|
| 306 |
+
| Routing degradation (yelp 55→36) | Expert quality thấp → $\sigma \approx 0$ → signature = noise → routing ngẫu nhiên | Expert quality tăng → $\sigma > 0$ đáng kể → routing có phân biệt |
|
| 307 |
+
|
| 308 |
+
---
|
| 309 |
+
|
| 310 |
+
## 5. Những gì Loại bỏ từ GainLoRA
|
| 311 |
+
|
| 312 |
+
| Thành phần | GainLoRA | SpecRoute | Lý do |
|
| 313 |
+
|------------|----------|-----------|-------|
|
| 314 |
+
| MLP `trans_input` | Learned routing projection | ❌ Loại bỏ | Duality: spectral affinity là đủ |
|
| 315 |
+
| `prompt_key` | Learned per-task key | ❌ Loại bỏ | Thay bằng spectral signatures |
|
| 316 |
+
| `previous_trans_input` | Frozen MLP copies | ❌ Loại bỏ | Signatures bất biến theo cấu trúc |
|
| 317 |
+
| KL distillation | Replay-based routing loss | ❌ Loại bỏ | Không learned routing → không cần distill |
|
| 318 |
+
| GPM trên routing params | Subspace cho routing | ❌ Loại bỏ | Không có routing parameters để bảo vệ |
|
| 319 |
+
|
| 320 |
+
**Hiệu ứng tổng thể:** Toàn bộ subspace và compute budget mà GainLoRA dành cho routing infrastructure được *thu hồi* cho task learning.
|
| 321 |
+
|
| 322 |
+
---
|
| 323 |
+
|
| 324 |
+
## 6. Hai Đóng góp Cốt lõi
|
| 325 |
+
|
| 326 |
+
> **Nguyên tắc cấu trúc:** Hai đóng góp này tạo thành một vòng lặp logic khép kín — phần 1 xây dựng lý thuyết, phần 2 giải quyết rào cản thực tế để lý thuyết đó có thể hoạt động. Không có phần nào có thể đứng độc lập mà không cần phần kia.
|
| 327 |
+
|
| 328 |
+
---
|
| 329 |
+
|
| 330 |
+
### Đóng góp 1: Khung Định tuyến Phổ Phi tham số
|
| 331 |
+
|
| 332 |
+
> *Tổng hợp từ C1, C2, C3 — một lập luận thống nhất, không phải ba thủ thuật riêng biệt.*
|
| 333 |
+
|
| 334 |
+
**Vấn đề trung tâm:** Các phương pháp CL trước đây (GainLoRA, O-LoRA) coi routing và bảo vệ là hai bài toán độc lập, dẫn đến vòng lặp xấu: routing parameter trôi dạt → GPM phải bảo vệ routing → subspace của task learning bị thu hẹp → routing lại yếu hơn.
|
| 335 |
+
|
| 336 |
+
**Đóng góp:** Chúng tôi hình thức hóa và chứng minh rằng **bảo vệ không gian con trực giao và routing phân biệt là hai biểu hiện kép của cùng một cấu trúc phổ** (Định lý 1). Từ tính đối ngẫu này, chúng tôi dẫn xuất cơ chế routing hoàn toàn phi tham số: mỗi input được định tuyến đến expert có spectral affinity cao nhất với subspace đặc trưng của expert đó — không cần tham số học, không cần replay, không tốn GPM overhead cho routing infrastructure.
|
| 337 |
+
|
| 338 |
+
**Đảm bảo lý thuyết:**
|
| 339 |
+
- Routing margin $\geq \kappa_{\min}(t^*) - \varepsilon\, \kappa_{\max}$ — tỷ lệ thuận với chất lượng bảo vệ (Định lý 1).
|
| 340 |
+
- Routing weight $w_{t^*} \geq 1-\delta$ với nhiệt độ $\tau \leq m/\ln\!\bigl((T-1)/\delta\bigr)$ (Hệ quả 1).
|
| 341 |
+
- Capacity bound $T_{\max} \leq d/r(1-\varepsilon)$ qua lý thuyết Grassmannian packing (Hệ quả 2).
|
| 342 |
+
- Routing hoàn toàn bất biến qua thời gian: $h$ từ frozen embedding table, $\mathcal{S}_t$ đóng băng sau training (Mệnh đề 1).
|
| 343 |
+
|
| 344 |
+
**Tại sao không phải đơn giản hoá mà là tiến bộ lý thuyết:** Kết quả này cho thấy các kiến trúc như GainLoRA đang giải quyết một bài toán không tồn tại (routing parameter learning). Chúng tôi chứng minh rằng bảo vệ tốt ↔ routing tốt — hai bài toán hóa ra là *một*.
|
| 345 |
+
|
| 346 |
+
---
|
| 347 |
+
|
| 348 |
+
### Đóng góp 2: Tối ưu hóa Không gian con Dựa trên Dữ liệu
|
| 349 |
+
|
| 350 |
+
> *Tổng hợp từ C5 — giải quyết rào cản thực tế làm Đóng góp 1 sụp đổ lúc runtime.*
|
| 351 |
+
|
| 352 |
+
**Vấn đề trung tâm:** Đóng góp 1 yêu cầu $h \in \mathrm{span}(V_{t^*})$ — tức là expert $t^*$ phải học được các biến đổi có ý nghĩa từ dữ liệu task. Điều này phụ thuộc vào chất lượng của $A_t$. InfLoRA (và GainLoRA) khởi tạo $A_t$ ngẫu nhiên rồi chiếu vào null-space — một điểm *tùy ý* trên Grassmannian $\mathrm{Gr}(r, d - N_{\text{protected}})$ với dimension $r(d - N_{\text{protected}} - r)$ rất lớn. Khi null-space co lại theo tasks, xác suất ngẫu nhiên bắt đúng hướng task-relevant tiệm cận về 0.
|
| 353 |
+
|
| 354 |
+
**Đóng góp:** Chúng tôi phát biểu khởi tạo $A_t$ như **bài toán Constrained PCA trên Grassmannian bị giới hạn** và cung cấp lời giải dạng đóng:
|
| 355 |
+
|
| 356 |
+
$$\max_{A_t} \;\text{tr}(A_t\, Q C_t Q\, A_t^T) \quad \text{s.t.} \quad A_t A_t^T = I_r \;\Rightarrow\; A_t = \text{top-}r\text{ eigenvectors của } QC_tQ$$
|
| 357 |
+
|
| 358 |
+
$A_t$ này đảm bảo capture **variance task-relevant tối đa** trong null-space có sẵn — biến vấn đề ngẫu nhiên thành vấn đề tất định. Tuân thủ zero-replay vì $C_t$ tính từ dữ liệu task *hiện tại* (không phải cũ), cùng logic với GPM bases đã được chấp nhận trong InfLoRA.
|
| 359 |
+
|
| 360 |
+
**Vòng lặp khép kín với Đóng góp 1:** $A_t$ tốt hơn → $B_t$ học trong subspace task-relevant → $\sigma_{t,i}$ lớn hơn sau training → $\kappa_{\min}(t^*)$ trong Định lý 1 tăng → routing margin tăng → Đóng góp 1 hoạt động như lý thuyết dự đoán.
|
| 361 |
+
|
| 362 |
+
---
|
| 363 |
+
|
| 364 |
+
> **C4 (gradient preconditioning)** là chi tiết triển khai kỹ thuật cần thiết để sửa điều kiện ma trận sau projection, không phải đóng góp lý thuyết. Xem §4 để biết chi tiết.
|
| 365 |
+
|
| 366 |
+
---
|
| 367 |
+
|
| 368 |
+
## 7. Pipeline Huấn luyện
|
| 369 |
+
|
| 370 |
+
### Task 1 (`--run_single True`)
|
| 371 |
+
1. Load pretrained model + fresh LoRA ($A$: Kaiming, $B$: zeros).
|
| 372 |
+
2. Huấn luyện chuẩn (chỉ `lora_B`) — single expert, không routing.
|
| 373 |
+
3. Sau training: tính $\mathcal{S}_1$ (thin SVD) + GPM bases (ESA threshold).
|
| 374 |
+
4. Lưu: LoRA weights, spectral signatures, GPM reg files.
|
| 375 |
+
|
| 376 |
+
### Task $t \geq 2$
|
| 377 |
+
1. Load model + fresh LoRA; load LoRA weights và spectral signatures cũ.
|
| 378 |
+
2. **[C5 — MỚI]** Pre-task forward pass (200 batch, no grad):
|
| 379 |
+
- Thu thập activation covariance $C_t$ của inputs task $t$
|
| 380 |
+
- Tính projected covariance: $\tilde{C}_t = Q C_t Q$ ($Q = I - P_{\text{old}}$)
|
| 381 |
+
- Eigenvectors của $\tilde{C}_t$ → khởi tạo $A_t$ (thay thế random Kaiming)
|
| 382 |
+
3. InfLoRA: chuẩn hoá $A_t$ (đã nằm trong null-space từ eigenvector decomposition).
|
| 383 |
+
4. Huấn luyện `lora_B` với spectral affinity routing + adaptive bias $\beta(n)$ + C4.
|
| 384 |
+
5. Sau training: tính $\mathcal{S}_t$ (cả inference routing và storage) + cập nhật GPM bases.
|
| 385 |
+
6. Lưu tất cả artifacts cho task tiếp theo.
|
| 386 |
+
|
| 387 |
+
---
|
| 388 |
+
|
| 389 |
+
## 8. Mapping Lý thuyết – Implementation
|
| 390 |
+
|
| 391 |
+
| Lý thuyết | Implementation | File |
|
| 392 |
+
|-----------|---------------|------|
|
| 393 |
+
| Spectral signature $\mathcal{S}_t$ | `compute_spectral_signatures()` (thin QR+SVD) | `t5_specroute.py` |
|
| 394 |
+
| Spectral affinity $\alpha_t(h)$ (inference) | σ²-weighted Rayleigh quotient | `compute_spectral_routing()` |
|
| 395 |
+
| A-row proxy $\alpha_t^{\mathrm{train}}$ (training) | A-row fit + adaptive bias $\beta(n)$ | `compute_spectral_routing()` |
|
| 396 |
+
| Symmetric inference SVD | `prepare_inference_routing()` → SVD của $B_t A_t$ | `t5_specroute.py` |
|
| 397 |
+
| Routing $w = \mathrm{softmax}(\alpha / \tau)$ | `torch.softmax(fit_scores / temp)` | `compute_spectral_routing()` |
|
| 398 |
+
| Drift-free input $h$ | `inputs_embeds = embed_tokens(input_ids)` → mean-pool | `T5Stack.forward()` |
|
| 399 |
+
| GPM + InfLoRA null-space | `get_reg_matrix()` | `cl_trainer_specroute.py` |
|
| 400 |
+
| Dynamic ESA threshold | `(1−ε₀)·t/T + ε₀` | `cl_trainer_specroute.py` |
|
| 401 |
+
| C4: Preconditioner | `precompute_preconditioners()` → eigendecomposition | `cl_trainer_specroute.py` |
|
| 402 |
+
| C4: Spectral entropy reg | `_compute_spectral_entropy_loss()` → QR trick | `cl_trainer_specroute.py` |
|
| 403 |
+
| **C5: Data-informed init** | **`pre_task_data_collection()` → `eigh(Q@C@Q)` → set `lora_A.data`** | **`cl_trainer_specroute.py`** |
|
| 404 |
+
|
| 405 |
+
---
|
| 406 |
+
|
| 407 |
+
## 9. Thiết lập Thí nghiệm
|
| 408 |
+
|
| 409 |
+
| Hạng mục | Giá trị |
|
| 410 |
+
|----------|---------|
|
| 411 |
+
| Mô hình | `google/flan-t5-small` (60M) / `flan-t5-large` (783M) |
|
| 412 |
+
| Benchmarks | SuperNI (15 tasks, 2 orderings), Long (15 tasks, 2 orderings) |
|
| 413 |
+
| Metrics | AP (Average Performance, ↑), FT (Forgetting, ↓) |
|
| 414 |
+
| LoRA | $r = 8$, target=Q+V, InfLoRA (chỉ B trained, A đóng băng) |
|
| 415 |
+
| Routing | $\tau = 1.0$, $\alpha_{\mathrm{target}} = 0.8$, adaptive $\beta(n)$ (train); SVD đối xứng (inference) |
|
| 416 |
+
| ESA | $\varepsilon_0 = 0.995$ (dynamic) |
|
| 417 |
+
| C4 | $\lambda_{\text{entropy}} = 0.01$, preconditioning on, $\epsilon = 10^{-6}$, warmup = 10% |
|
| 418 |
+
| **C5** | **N_batch_warmup = 200, dùng `torch.linalg.eigh` trên projected covariance** |
|
| 419 |
+
| Precision | fp32 + gradient checkpointing |
|
| 420 |
+
| So sánh | Batch size, LR, scheduler khớp chính xác ROOT (GainLoRA) |
|
| 421 |
+
|
| 422 |
+
---
|
| 423 |
+
|
| 424 |
+
## 10. File Map
|
| 425 |
+
|
| 426 |
+
| File | Vai trò |
|
| 427 |
+
|------|---------|
|
| 428 |
+
| `src/t5_specroute.py` | T5Stack + spectral routing + thin SVD |
|
| 429 |
+
| `src/t5_gainlora_inflora.py` | LoRALayer, T5Attention, T5Block (shared base) |
|
| 430 |
+
| `src/cl_trainer_specroute.py` | Trainer: GPM, InfLoRA, ESA, C4, C5, training_step |
|
| 431 |
+
| `src/run_t5.py` | Entry: model loading, parameter freezing |
|
| 432 |
+
| `gen_script_*_specroute*.sh` | Experiment scripts |
|
improve_gainlora/src/cl_trainer_specroute.py
CHANGED
|
@@ -89,7 +89,8 @@ class SpecRoute_Trainer(Seq2SeqTrainer):
|
|
| 89 |
eval_dataset=None, tokenizer=None, data_collator=None,
|
| 90 |
compute_metrics=None, callbacks=None,
|
| 91 |
lambda_entropy=0.0, use_preconditioning=False,
|
| 92 |
-
precond_eps=1e-6, entropy_warmup_ratio=0.1
|
|
|
|
| 93 |
super().__init__(
|
| 94 |
model=model, args=args, train_dataset=train_dataset,
|
| 95 |
eval_dataset=eval_dataset, tokenizer=tokenizer,
|
|
@@ -99,12 +100,15 @@ class SpecRoute_Trainer(Seq2SeqTrainer):
|
|
| 99 |
self.task_order = task_order
|
| 100 |
self.cur_task_id = cur_task_id
|
| 101 |
self._grad_check_done = False
|
| 102 |
-
# C4:
|
| 103 |
-
self.lambda_entropy =
|
| 104 |
self.use_preconditioning = use_preconditioning
|
| 105 |
self.precond_eps = precond_eps
|
| 106 |
self.entropy_warmup_ratio = entropy_warmup_ratio
|
| 107 |
self._precond_matrices = {}
|
|
|
|
|
|
|
|
|
|
| 108 |
|
| 109 |
def _save(self, output_dir=None, state_dict=None):
|
| 110 |
# T5 shared embeddings are incompatible with safetensors; force pytorch format
|
|
@@ -177,20 +181,14 @@ class SpecRoute_Trainer(Seq2SeqTrainer):
|
|
| 177 |
lora.lora_B.grad.data.nan_to_num_(nan=0.0)
|
| 178 |
|
| 179 |
def training_step(self, model, inputs, **kwargs):
|
| 180 |
-
"""CE training step + C4
|
|
|
|
| 181 |
model.train()
|
| 182 |
inputs = self._prepare_inputs(inputs)
|
| 183 |
|
| 184 |
with self.compute_loss_context_manager():
|
| 185 |
loss = self.compute_loss(model, inputs)
|
| 186 |
|
| 187 |
-
# C4: Spectral entropy regularization (after warmup)
|
| 188 |
-
if self.lambda_entropy > 0:
|
| 189 |
-
warmup_steps = int(self.entropy_warmup_ratio * self.state.max_steps)
|
| 190 |
-
if self.state.global_step >= warmup_steps:
|
| 191 |
-
ent_loss = self._compute_spectral_entropy_loss()
|
| 192 |
-
loss = loss + self.lambda_entropy * ent_loss
|
| 193 |
-
|
| 194 |
if self.args.n_gpu > 1:
|
| 195 |
loss = loss.mean()
|
| 196 |
|
|
@@ -233,6 +231,56 @@ class SpecRoute_Trainer(Seq2SeqTrainer):
|
|
| 233 |
|
| 234 |
return loss.detach()
|
| 235 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 236 |
def load_previous_reg_matrix(self):
|
| 237 |
"""Load LoRA GPM bases from previous task. No trans_input GPM needed."""
|
| 238 |
log_path = os.path.dirname(self.args.output_dir)
|
|
@@ -280,7 +328,31 @@ class SpecRoute_Trainer(Seq2SeqTrainer):
|
|
| 280 |
).to("cuda:0")
|
| 281 |
self.feature_mat.append(feature_mat)
|
| 282 |
|
| 283 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 284 |
for index in self.feature_list[i].keys():
|
| 285 |
module.lora_q.lora_A.data[:, index*module.step:(index+1)*module.step].copy_(
|
| 286 |
module.lora_q.lora_A.data[:, index*module.step:(index+1)*module.step]
|
|
|
|
| 89 |
eval_dataset=None, tokenizer=None, data_collator=None,
|
| 90 |
compute_metrics=None, callbacks=None,
|
| 91 |
lambda_entropy=0.0, use_preconditioning=False,
|
| 92 |
+
precond_eps=1e-6, entropy_warmup_ratio=0.1,
|
| 93 |
+
n_batches_c5=200):
|
| 94 |
super().__init__(
|
| 95 |
model=model, args=args, train_dataset=train_dataset,
|
| 96 |
eval_dataset=eval_dataset, tokenizer=tokenizer,
|
|
|
|
| 100 |
self.task_order = task_order
|
| 101 |
self.cur_task_id = cur_task_id
|
| 102 |
self._grad_check_done = False
|
| 103 |
+
# C4.1: Gradient preconditioning (C4.2 entropy reg removed in V7)
|
| 104 |
+
self.lambda_entropy = 0.0 # disabled in V7 — conflicts with C5 philosophy
|
| 105 |
self.use_preconditioning = use_preconditioning
|
| 106 |
self.precond_eps = precond_eps
|
| 107 |
self.entropy_warmup_ratio = entropy_warmup_ratio
|
| 108 |
self._precond_matrices = {}
|
| 109 |
+
# C5: Data-Informed Subspace Initialization
|
| 110 |
+
self.n_batches_c5 = n_batches_c5
|
| 111 |
+
self._task_covariance = [] # list of {chunk_index: cov_tensor} per layer
|
| 112 |
|
| 113 |
def _save(self, output_dir=None, state_dict=None):
|
| 114 |
# T5 shared embeddings are incompatible with safetensors; force pytorch format
|
|
|
|
| 181 |
lora.lora_B.grad.data.nan_to_num_(nan=0.0)
|
| 182 |
|
| 183 |
def training_step(self, model, inputs, **kwargs):
|
| 184 |
+
"""CE training step + C4.1 gradient preconditioning.
|
| 185 |
+
C4.2 spectral entropy regularization removed in V7 (conflicts with C5)."""
|
| 186 |
model.train()
|
| 187 |
inputs = self._prepare_inputs(inputs)
|
| 188 |
|
| 189 |
with self.compute_loss_context_manager():
|
| 190 |
loss = self.compute_loss(model, inputs)
|
| 191 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 192 |
if self.args.n_gpu > 1:
|
| 193 |
loss = loss.mean()
|
| 194 |
|
|
|
|
| 231 |
|
| 232 |
return loss.detach()
|
| 233 |
|
| 234 |
+
# ================================================================
|
| 235 |
+
# C5: Data-Informed Subspace Initialization
|
| 236 |
+
# ================================================================
|
| 237 |
+
|
| 238 |
+
def pre_task_data_collection(self):
|
| 239 |
+
"""C5: Collect activation covariance for the current task.
|
| 240 |
+
Must be called BEFORE get_reg_matrix().
|
| 241 |
+
Stores per-layer, per-chunk covariance matrices in self._task_covariance.
|
| 242 |
+
These are used in get_reg_matrix() to initialize A_t optimally.
|
| 243 |
+
"""
|
| 244 |
+
# Reset module covariance accumulators and enable collection
|
| 245 |
+
for module in self.model.modules():
|
| 246 |
+
if hasattr(module, 'get_feature'):
|
| 247 |
+
module.get_feature = True
|
| 248 |
+
module.stage = 0
|
| 249 |
+
for index in range(module.index):
|
| 250 |
+
module.matrix[index] = torch.zeros(
|
| 251 |
+
module.step, module.step, device='cuda'
|
| 252 |
+
)
|
| 253 |
+
module.n_matrix[index] = 0
|
| 254 |
+
|
| 255 |
+
print(f'[C5] Collecting activation covariance ({self.n_batches_c5} batches)...')
|
| 256 |
+
train_dataloader = self.get_train_dataloader()
|
| 257 |
+
if isinstance(train_dataloader, DataLoader) and isinstance(
|
| 258 |
+
train_dataloader.sampler, DistributedSampler
|
| 259 |
+
):
|
| 260 |
+
train_dataloader.sampler.set_epoch(42)
|
| 261 |
+
|
| 262 |
+
with torch.no_grad():
|
| 263 |
+
for step, inputs in enumerate(train_dataloader):
|
| 264 |
+
if step >= self.n_batches_c5:
|
| 265 |
+
break
|
| 266 |
+
inputs = self._prepare_inputs(inputs)
|
| 267 |
+
# Drop labels — we only want activations, not loss
|
| 268 |
+
inputs.pop('labels', None)
|
| 269 |
+
self.model(**inputs)
|
| 270 |
+
|
| 271 |
+
# Harvest and store covariance
|
| 272 |
+
self._task_covariance = []
|
| 273 |
+
for module in self.model.modules():
|
| 274 |
+
if hasattr(module, 'get_feature'):
|
| 275 |
+
cov = {}
|
| 276 |
+
for index in range(module.index):
|
| 277 |
+
cov[index] = module.matrix[index].detach().float().cuda()
|
| 278 |
+
self._task_covariance.append(cov)
|
| 279 |
+
module.get_feature = False
|
| 280 |
+
module.stage = 0
|
| 281 |
+
|
| 282 |
+
print(f'[C5] Covariance collected for {len(self._task_covariance)} layers.')
|
| 283 |
+
|
| 284 |
def load_previous_reg_matrix(self):
|
| 285 |
"""Load LoRA GPM bases from previous task. No trans_input GPM needed."""
|
| 286 |
log_path = os.path.dirname(self.args.output_dir)
|
|
|
|
| 328 |
).to("cuda:0")
|
| 329 |
self.feature_mat.append(feature_mat)
|
| 330 |
|
| 331 |
+
# C5: Data-Informed Subspace Initialization
|
| 332 |
+
# Replace random A_t with optimal subspace from Constrained PCA.
|
| 333 |
+
# Eigenvectors of Q@C_t@Q are in null(P_old) by construction,
|
| 334 |
+
# so the InfLoRA projection below becomes a numerical near-no-op.
|
| 335 |
+
if self._task_covariance and i < len(self._task_covariance):
|
| 336 |
+
r = module.lora_q.lora_A.data.shape[0] # LoRA rank
|
| 337 |
+
for index in self.feature_list[i].keys():
|
| 338 |
+
C_t = self._task_covariance[i][index] # [step, step]
|
| 339 |
+
P_old = feature_mat[index] # [step, step]
|
| 340 |
+
Q = torch.eye(module.step, device=P_old.device) - P_old
|
| 341 |
+
C_tilde = Q @ C_t.to(P_old.device) @ Q
|
| 342 |
+
# Enforce symmetry for numerical stability
|
| 343 |
+
C_tilde = (C_tilde + C_tilde.T) * 0.5
|
| 344 |
+
# eigh returns ascending eigenvalues; take last r (largest)
|
| 345 |
+
eigvals, eigvecs = torch.linalg.eigh(C_tilde.float())
|
| 346 |
+
top_eigvecs = eigvecs[:, -r:].flip(dims=[1]) # [step, r]
|
| 347 |
+
A_init = top_eigvecs.T # [r, step]
|
| 348 |
+
dtype = module.lora_q.lora_A.data.dtype
|
| 349 |
+
sl = slice(index * module.step, (index + 1) * module.step)
|
| 350 |
+
module.lora_q.lora_A.data[:, sl].copy_(A_init.to(dtype))
|
| 351 |
+
module.lora_v.lora_A.data[:, sl].copy_(A_init.to(dtype))
|
| 352 |
+
print(f'[C5] Layer {i+1}: A_t initialized via Constrained PCA.')
|
| 353 |
+
|
| 354 |
+
# InfLoRA null-space projection (near no-op after C5, still applied
|
| 355 |
+
# for numerical correctness and to enforce InfLoRA invariant exactly)
|
| 356 |
for index in self.feature_list[i].keys():
|
| 357 |
module.lora_q.lora_A.data[:, index*module.step:(index+1)*module.step].copy_(
|
| 358 |
module.lora_q.lora_A.data[:, index*module.step:(index+1)*module.step]
|
improve_gainlora/src/run_t5.py
CHANGED
|
@@ -188,7 +188,11 @@ class ModelArguments:
|
|
| 188 |
)
|
| 189 |
entropy_warmup_ratio: Optional[float] = field(
|
| 190 |
default=0.1,
|
| 191 |
-
metadata={"help": "Fraction of training steps before enabling entropy loss (C4)."},
|
|
|
|
|
|
|
|
|
|
|
|
|
| 192 |
)
|
| 193 |
|
| 194 |
run_single: bool = field(
|
|
@@ -948,8 +952,10 @@ def main():
|
|
| 948 |
use_preconditioning=model_args.use_preconditioning,
|
| 949 |
precond_eps=model_args.precond_eps,
|
| 950 |
entropy_warmup_ratio=model_args.entropy_warmup_ratio,
|
|
|
|
| 951 |
)
|
| 952 |
if training_args.do_train:
|
|
|
|
| 953 |
trainer.get_reg_matrix()
|
| 954 |
trainer.precompute_preconditioners()
|
| 955 |
else:
|
|
|
|
| 188 |
)
|
| 189 |
entropy_warmup_ratio: Optional[float] = field(
|
| 190 |
default=0.1,
|
| 191 |
+
metadata={"help": "Fraction of training steps before enabling entropy loss (C4, disabled in V7)."},
|
| 192 |
+
)
|
| 193 |
+
n_batches_c5: Optional[int] = field(
|
| 194 |
+
default=200,
|
| 195 |
+
metadata={"help": "Number of training batches for C5 activation covariance collection."},
|
| 196 |
)
|
| 197 |
|
| 198 |
run_single: bool = field(
|
|
|
|
| 952 |
use_preconditioning=model_args.use_preconditioning,
|
| 953 |
precond_eps=model_args.precond_eps,
|
| 954 |
entropy_warmup_ratio=model_args.entropy_warmup_ratio,
|
| 955 |
+
n_batches_c5=model_args.n_batches_c5,
|
| 956 |
)
|
| 957 |
if training_args.do_train:
|
| 958 |
+
trainer.pre_task_data_collection()
|
| 959 |
trainer.get_reg_matrix()
|
| 960 |
trainer.precompute_preconditioners()
|
| 961 |
else:
|