基座模型凍結語義規範與反向梯度傳播路徑物理隔離
Agent 輔助工程檢查
前置要求
第 64 天 LoRA 前向公式與 PyTorch 自動微分機制。
學習目標
透徹掌握 LoRA 訓練下的計算圖拓撲分支結構:探究基座權重為何不分配梯度內存,而適配器矩陣 A 與 B 能夠精準接收反向導數更新。
操作指引
1. 寫出含兩條路徑的前向:y = W0 @ x + (alpha/r) * B @ A @ x。第一條路徑只用凍結的 W0;第二條用可訓練的 A(r x d_in)和 B(d_out x r)。
2. 在前向之前用 requires_grad_(False) 凍結 W0。這樣 autograd 不會記錄通向 W0 的梯度邊,也不會分配 W0.grad。
3. 推導適配器梯度:dL/dB = (alpha/r) * (dL/dy) @ (A @ x)^T,dL/dA = (alpha/r) * B^T @ (dL/dy) @ x^T。注意形狀。
4. 預測第 0 步(B 初始化為零)會發生什麼:兩個梯度中哪一個恰好為零?
5. 執行一次反向傳播,斷言題目中的三個梯度事實,再檢驗第 4 步的預測。
6. 計算省下的梯度顯存:凍結參數數量 × 2 位元組(bf16)或 4 位元組(fp32)。
時間安排(120 分鐘):閱讀 25 + 練習 65 + 檢查 30。 閱讀:Hu et al. 第 4.1 節(LoRA 更新及其初始化)和 PEFT 的 LoRA 概念指南。練習:用參考模型完成第 1-6 步。檢查:不看筆記解釋為什麼第 0 步 lora_A.grad 為零。
自主實作與記錄
實例化包含凍結線性層與可學習 LoRA 適配器的模型,執行前向反向傳播。嚴密斷言 model.linear.weight.grad 嚴格為 None,而 lora_A.grad 與 lora_B.grad 為非空有效張量。
遍歷 model.named_parameters() 審查 param.grad 狀態。
import torch
import torch.nn as nn
class TinyLoRA(nn.Module):
def __init__(self, d_in=8, d_out=4, r=2, alpha=4):
super().__init__()
self.linear = nn.Linear(d_in, d_out, bias=False)
self.linear.weight.requires_grad_(False) # freeze W0
self.lora_A = nn.Parameter(torch.randn(r, d_in) * 0.01)
self.lora_B = nn.Parameter(torch.zeros(d_out, r)) # B = 0, so the adapter starts as a no-op
self.scale = alpha / r
def forward(self, x):
return self.linear(x) + self.scale * (x @ self.lora_A.T @ self.lora_B.T)
torch.manual_seed(0)
model = TinyLoRA()
x, target = torch.randn(5, 8), torch.randn(5, 4)
loss = nn.functional.mse_loss(model(x), target)
loss.backward()
assert model.linear.weight.grad is None # no .grad buffer was ever allocated
assert model.lora_A.grad is not None
assert model.lora_B.grad is not None
# Surprise worth recording: at step 0, dL/dA = scale * B.T @ dL/dy @ x is exactly zero because
# B = 0, while dL/dB = scale * dL/dy.T @ (x @ A.T) is not. A receives signal only after B moves.
assert torch.count_nonzero(model.lora_A.grad) == 0
assert torch.count_nonzero(model.lora_B.grad) > 0
trainable = [n for n, p in model.named_parameters() if p.requires_grad]
frozen = sum(p.numel() for p in model.parameters() if not p.requires_grad)
print(trainable, frozen) # ['lora_A', 'lora_B'] 32
# Saving: 32 frozen weights x 4 bytes = 128 bytes of fp32 gradient that is never allocated;
# for a 7B base in bf16 the same rule saves 7e9 x 2 bytes = 14 GB.
能準確分析並斷言基座與適配器在自動求導圖中的物理隔離屬性。
權威來源資源與權利證明
LoRA: Low-Rank Adaptation of Large Language Models
對應章節 / 時間戳: Section 4.2 Applying LoRA to Transformer (frozen W0, VRAM and checkpoint-size reduction)
驗證版本與日期: ICLR 2022 / arXiv:2106.09685v2 (Verified: 2026-10-30)
Primary literature introducing Low-Rank Adaptation, establishing parameter decomposition W = W0 + (alpha/r)*BA, initialization strategies, and zero inference latency merging.
Matrix factorization, rank, linear layers, and transformer attention.
Complete matrix derivations, tensor dimensions, and pure PyTorch LoRALinear modules are implemented directly in lesson code.
對比候選資源與選型分析 (2)
Introduces bottleneck adapter layers in series, which introduces unavoidable inference latency overhead; LoRA's parallel formulation merges with zero latency.
Prepends virtual prompt tokens; reduces available context length, unlike LoRA which preserves full sequence capacity.
PEFT: State-of-the-art Parameter-Efficient Fine-Tuning Methods
對應章節 / 時間戳: README 'Quickstart' (LoraConfig, get_peft_model, print_trainable_parameters)
驗證版本與日期: PEFT 0.10.x / GitHub (Verified: 2026-10-30)
Widely adopted open-source library implementing LoRA configuration classes (LoraConfig), get_peft_model, and adapter serialization.
PyTorch nn.Module, Hugging Face transformers, and LoRA equations.
Standalone, zero-dependency PyTorch implementations of LoRALinear layers and save/reload logic are provided in curriculum scripts.
對比候選資源與選型分析 (2)
Original reference code by Hu et al.; PEFT expands this to broader multi-model ecosystem integration.
High-performance clean implementation; compared alongside PEFT for modular code architecture.