IO-SVD:基于输入输出双侧白化的自适应秩LLM压缩方法

笔记日期: 2026-05-29 笔记作者: Zhongzhu Zhou 论文标题: IO-SVD: Input-Output Whitened SVD for Adaptive-Rank LLM Compression 作者: Ali Abbasi, Chayne Thrash, Haoran Qin, Hamed Pirsiavash, Soheil Kolouri(范德堡大学、UC Davis) arXiv: 2605.15626 状态 / Venue: arXiv preprint,2026年5月

一句话总结

IO-SVD 把 SVD 压缩里长期被忽视的”输出侧敏感性”纳入白化目标,同时用贪婪的一阶得分驱动异构秩分配,以及损失感知量化行选择,三管齐下让 LLaMA-7B 在 80% 保留率下困惑度从 7.94(SVD-LLM)降至 5.59,并在实际推理中实现 4.34 倍吞吐提升。

前置知识

这篇论文涉及矩阵分解、信息几何、神经网络压缩几个领域。在正式进入方法前,我先把所有读者需要的背景知识整理清楚。

奇异值分解(SVD)是什么

任意实矩阵 WRm×nW \in \mathbb{R}^{m \times n} 都可以分解为

W=UΣVW = U \Sigma V^\top

其中 URm×mU \in \mathbb{R}^{m \times m}VRn×nV \in \mathbb{R}^{n \times n} 是正交矩阵(UU=IU^\top U = IVV=IV^\top V = I),ΣRm×n\Sigma \in \mathbb{R}^{m \times n} 是对角矩阵,对角线上的非负实数按降序排列,称为奇异值

σ1σ2σmin(m,n)0\sigma_1 \geq \sigma_2 \geq \cdots \geq \sigma_{\min(m,n)} \geq 0

Eckart–Young–Mirsky 定理告诉我们:在 Frobenius 范数意义下,最优的秩-rr 近似就是保留前 rr 个奇异值和对应奇异向量:

W^r=U:,1:rΣ1:r,1:rV:,1:r\hat{W}_r = U_{:,1:r}\, \Sigma_{1:r,1:r}\, V_{:,1:r}^\top

近似误差为 WW^rF2=i>rσi2\|W - \hat W_r\|_F^2 = \sum_{i > r} \sigma_i^2

在大模型压缩里,我们把每个线性权重矩阵 WRm×nW \in \mathbb{R}^{m \times n} 用低秩分解 ABA B^\topARm×rA \in \mathbb{R}^{m \times r}BRn×rB \in \mathbb{R}^{n \times r})替换,参数量从 mnmn 降至 r(m+n)r(m+n),当 rmin(m,n)r \ll \min(m,n) 时可以显著节约存储和计算。

什么叫”保留率”(maintenance ratio)?
论文中 ratio = 0.8 表示保留 80% 的参数。但要注意:低秩分解的”参数量比较基准”是矩阵密集表示 mnmn,低于这个基准才有意义。秩 rr 的存储量 r(m+n)r(m+n) 等于 mnmn 时,有一个收支平衡秩

r=mnm+nr^* = \left\lfloor \frac{mn}{m+n} \right\rfloor

只有当 r<rr < r^* 时,低秩表示才比密集矩阵节省存储。

为什么直接 SVD 压缩 LLM 效果差

直接对权重矩阵做截断 SVD,最小化的是 WW^F2\|W - \hat W\|_F^2,即权重重建误差。但神经网络里,权重的变化影响的是模型输出,而不是权重本身。问题在于:

  • 权重矩阵中某个方向的奇异值很大,不代表模型的输入激活在那个方向上有大分量
  • 如果输入从来不激活某个方向(输入协方差在那个方向接近零),那么在该方向的权重变化对模型输出几乎没有影响
  • 反过来,某些小奇异值所对应的方向,如果输入协方差很大,损失就会对那里的扰动非常敏感

所以,我们需要在考虑了”哪些方向被实际使用”之后再决定保留哪些奇异值。这就是激活感知(activation-aware)白化的动机。

白化(Whitening)的数学意义

白化变换:给定输入激活 xx,协方差矩阵 R=E[xx]R = \mathbb{E}[xx^\top],白化变换 xR1/2xx \mapsto R^{-1/2} x 让变换后的分布具有单位协方差(各向同性)。

在 SVD 压缩中,白化的作用是把”哪些方向被激活”这个信息编码进矩阵里,然后再做 SVD。具体地:对白化矩阵 W~=WR1/2\tilde W = W R^{1/2} 做截断 SVD,等价于在以下目标下求最优低秩近似:

minW^(WW^)R1/2F2\min_{\hat W} \|(W - \hat W) R^{1/2}\|_F^2

这就是”激活感知”的由来:用 R1/2R^{1/2} 对不同方向加权,输入激活能量大的方向权重大(更需要被精确保留)。

KL散度与 Taylor 展开

KL散度(Kullback–Leibler divergence)衡量分布 ppqq 的差异:

KL(pq)=ipilogpiqi0\text{KL}(p \| q) = \sum_i p_i \log \frac{p_i}{q_i} \geq 0

对于大模型压缩,我们希望压缩后的模型 θ^\hat\theta 产生的输出分布尽量接近原模型 θ\theta 的分布。这自然引出 KL 散度作为目标函数。

KL(ptsoftmax(zt+δzt))\text{KL}(p_t \| \text{softmax}(z_t + \delta z_t))δzt=0\delta z_t = 0 处做 Taylor 展开

  • 第零阶项:KL(ptpt)=0\text{KL}(p_t \| p_t) = 0(恒为零)
  • 第一阶项:ztKL(ptsoftmax(z))z=zt=softmax(zt)pt=0\nabla_{z_t} \text{KL}(p_t \| \text{softmax}(z))|_{z=z_t} = \text{softmax}(z_t) - p_t = 0(因为 softmax(zt)=pt\text{softmax}(z_t) = p_t
  • 第二阶项(主导项):

KL(ptsoftmax(zt+δzt))12δztHtδzt\text{KL}(p_t \| \text{softmax}(z_t + \delta z_t)) \approx \frac{1}{2} \delta z_t^\top H_t \delta z_t

其中 Ht=Diag(pt)ptptH_t = \text{Diag}(p_t) - p_t p_t^\top 是 softmax 交叉熵关于 logit 的 Hessian 矩阵(二阶导数)。

HtH_t 有几个重要性质:

  1. 半正定:对任意向量 vvvHtv=Vaript(vi)0v^\top H_t v = \text{Var}_{i \sim p_t}(v_i) \geq 0
  2. Ht1=0H_t \mathbf{1} = 0:softmax 对所有 logit 加常数不变,所以 logit 整体平移方向敏感度为零
  3. 它的特征值反映了”改变哪个 logit 方向最影响预测分布”

这个 Hessian 就是”输出侧敏感性”的数学化表达:IO-SVD 的核心贡献,就是把它编码进白化矩阵。

Transformer 中的线性层结构

Transformer 中大多数参数都在线性层里。对于隐藏维度 dd、MLP 扩展比 4 的标准结构:

  • 注意力:WQ,WK,WV,WORd×dW_Q, W_K, W_V, W_O \in \mathbb{R}^{d \times d}
  • MLP:上投影 WupRd×4dW_{up} \in \mathbb{R}^{d \times 4d},下投影 WdownR4d×dW_{down} \in \mathbb{R}^{4d \times d}

IO-SVD 对这些线性层逐一进行 SVD 压缩,保持模型整体结构不变。

方法详解

IO-SVD 由三个相互配合的模块组成:KL 感知双侧白化自适应异构秩分配损失感知重映射。下面逐一深入展开。

模块一:KL 感知双侧白化

动机:为什么一侧白化不够?

现有的激活感知方法(如 SVD-LLM)只考虑输入侧:对 WR1/2W R^{1/2} 做 SVD,其中 R=E[xx]R = \mathbb{E}[xx^\top] 是输入激活协方差。这等价于最小化 (WW^)R1/2F2\|(W-\hat W) R^{1/2}\|_F^2——也就是”输入加权的权重重建误差”。

但这个目标仍然是局部的:它没有考虑权重扰动 ΔW\Delta W 如何通过后续网络层传播、最终影响模型的预测分布

设想两种压缩方案 A 和 B,对同一个层产生相同的输入重建误差 (WW^)R1/2F2\|(W-\hat W)R^{1/2}\|_F^2。若 A 的误差集中在对后续输出不敏感的方向,B 的误差集中在对预测分布高度敏感的方向,则 A 和 B 在下游质量上会有很大差异——但一侧白化无法区分二者。

目标函数推导

第一步:全局 KL 目标(公式 1)

J(θ^)=E(x,y)[t=1TKL ⁣(pθ(x,y<t)    pθ^(x,y<t))]J(\hat\theta) = \mathbb{E}_{(x,y)} \left[ \sum_{t=1}^T \text{KL}\!\left(p_\theta(\cdot \mid x, y_{<t}) \;\|\; p_{\hat\theta}(\cdot \mid x, y_{<t})\right) \right]

我们希望压缩参数 θ^\hat\theta 最小化每个 token 位置上,原模型与压缩模型之间的预测分布差异。

第二步:逐层可处理化(公式 2–3)

对第 \ell 层,权重扰动 ΔW=WW^\Delta W_\ell = W_\ell - \hat W_\ell 导致 token tt 处的层输出变化 δht=ΔWxt\delta h_t = \Delta W_\ell x_t,进而导致 logit 变化 δztJtΔWxt\delta z_t \approx J_t \Delta W_\ell x_t,其中 Jt=zt/h,tJ_t = \partial z_t / \partial h_{\ell,t} 是最终 logit 对该层输出的 Jacobian。

把这个代入 KL 二阶展开:

ΔJ,t12xtΔWJtHtJtCtoken,tΔWxt\Delta J_{\ell,t} \approx \frac{1}{2} x_t^\top \Delta W_\ell^\top \underbrace{J_t^\top H_t J_t}_{C_{\text{token},t}} \Delta W_\ell x_t

矩阵 Ctoken,t=JtHtJtC_{\text{token},t} = J_t^\top H_t J_t 是”把输出侧 KL 曲率拉回到该层输出空间”的 Kronecker 因子之一——它告诉我们,在第 \ell 层的输出空间里,哪些方向对最终预测分布最敏感。

第三步:对 calibration token 取期望(Appendix B.2 的推导)

用矩阵迹恒等式 aMa=tr(Maa)a^\top M a = \text{tr}(M aa^\top)

xtΔWCtoken,tΔWxt=tr ⁣(ΔWxtxtΔWCtoken,t)x_t^\top \Delta W_\ell^\top C_{\text{token},t} \Delta W_\ell x_t = \text{tr}\!\left(\Delta W_\ell x_t x_t^\top \Delta W_\ell^\top C_{\text{token},t}\right)

在 calibration token 上取期望,并使用矩解耦近似(即假设 xtx_tCtoken,tC_{\text{token},t} 近似独立,如 K-FAC 中的标准假设):

ΔJ12tr ⁣(ΔWRΔWC)\Delta J_\ell \approx \frac{1}{2} \text{tr}\!\left(\Delta W_\ell R_\ell \Delta W_\ell^\top C_\ell\right)

其中 R=Et[xtxt]R_\ell = \mathbb{E}_t[x_t x_t^\top]C=Et[Ctoken,t]C_\ell = \mathbb{E}_t[C_{\text{token},t}]

再用迹的循环不变性(tr(AB)=tr(BA)\text{tr}(AB) = \text{tr}(BA)):

tr ⁣(ΔWRΔWC)=C1/2ΔWR1/2F2\text{tr}\!\left(\Delta W_\ell R_\ell \Delta W_\ell^\top C_\ell\right) = \left\| C_\ell^{1/2} \Delta W_\ell R_\ell^{1/2} \right\|_F^2

所以最终的逐层目标(公式 4)为:

ΔJ12C1/2(WW^)R1/2F2\Delta J_\ell \approx \frac{1}{2} \left\| C_\ell^{1/2} (W_\ell - \hat W_\ell) R_\ell^{1/2} \right\|_F^2

这是一个 Frobenius 范数最小化问题,完美适配 Eckart–Young–Mirsky 定理!

第四步:用 Eckart–Young–Mirsky 求解

定义双侧白化矩阵(公式 5):

B=C1/2WR1/2B_\ell = C_\ell^{1/2} W_\ell R_\ell^{1/2}

最优低秩近似(公式 6–8)为:

  1. BB_\ell 做截断 SVD:B^=UrΣrVr\hat B_\ell = U_r \Sigma_r V_r^\top
  2. 逆白化恢复压缩权重:

W^=C1/2UrΣrVrR1/2\hat W_\ell^* = C_\ell^{-1/2} U_r \Sigma_r V_r^\top R_\ell^{-1/2}

IO-SVD 单层压缩算法(逐步)
───────────────────────────────────
输入:W_ℓ ∈ ℝ^{m×n},R_ℓ(输入协方差),C_ℓ(KL曲率),目标秩 r

步骤 1:计算带阻尼的白化矩阵
        R̄_ℓ = R_ℓ + λ_R I    (防止奇异,λ_R 小正数)
        C̄_ℓ = C_ℓ + λ_C I
        计算 R̄_ℓ^{1/2}, R̄_ℓ^{-1/2}(特征分解)
        计算 C̄_ℓ^{1/2}, C̄_ℓ^{-1/2}(特征分解)

步骤 2:构造双侧白化矩阵
        B_ℓ = C̄_ℓ^{1/2} W_ℓ R̄_ℓ^{1/2}

步骤 3:截断 SVD(保留前 r 个分量)
        U_r, Σ_r, V_r = top_r_SVD(B_ℓ)

步骤 4:逆白化,恢复压缩权重
        Ŵ_ℓ = C̄_ℓ^{-1/2} U_r Σ_r V_r^T R̄_ℓ^{-1/2}

输出:Ŵ_ℓ(低秩近似,存为 A_ℓ D_ℓ^T 形式)
───────────────────────────────────

高效计算 CC_\ell:Top-K 近似

Ctoken,t=JtHtJtC_{\text{token},t} = J_t^\top H_t J_t 的直接计算有两个瓶颈:

  1. JtRV×doutJ_t \in \mathbb{R}^{V \times d_{out}},词汇表大小 V32000V \sim 32000,太大
  2. Ht=Diag(pt)ptptRV×VH_t = \text{Diag}(p_t) - p_t p_t^\top \in \mathbb{R}^{V \times V},也太大

IO-SVD 的解法:只关注当前 token 的 Top-K 概率质量KVK \ll V),在这个支撑上重归一化 pt,Kp_{t,K},然后利用向量-Jacobian 乘积(VJP)通过反向传播钩子累积 CC_\ell

具体地,令 st=pt,Ks_t = \sqrt{p_{t,K}},定义:

Dt=Diag(st),Ωt=IststD_t = \text{Diag}(s_t), \quad \Omega_t = I - s_t s_t^\top

At=DtΩtA_t = D_t \Omega_t 满足 AtAt=Ht,KA_t A_t^\top = H_{t,K}(见 Appendix C)。这让我们只需运行 KK 次反向传播(每次用单位向量),每次复杂度 O(Kdout)O(K d_{out}),避免显式构建 VV 维 Jacobian。

论文对 KK 的消融(图 3)显示存在一个”甜点”:KK 太小则低估曲率,KK 太大引入噪声。在 WikiText2 上选出的最优 KK 在 PTB 和 C4 上同样有效,说明这个近似具有跨数据集泛化性。

flowchart LR
    subgraph Problem["计算 C_ℓ 的难点"]
        direction TB
        J["J_t ∈ ℝ^{V×d_out}\n(词汇表×层输出)\n太大,无法显式存储"]
        H["H_t ∈ ℝ^{V×V}\n(词汇表×词汇表)\n太大,无法显式存储"]
    end
    subgraph Solution["Top-K VJP 近似"]
        direction TB
        TopK["取前 K 个 token 概率\n重归一化: p_{t,K}"]
        Factor["因式分解:\nH_{t,K} = A_t A_t^T\nA_t = Diag(sqrt p_{t,K}) · (I - ss^T)"]
        VJP["K 次反向传播 VJP\n每次 O(K d_out) 而非 O(V d_out)"]
        Accum["累积 C_ℓ = E_t[J_t^T H_{t,K} J_t]"]
    end
    Problem --> Solution

与一侧白化的直觉比较

graph LR
    subgraph Plain["普通 SVD"]
        PS["最小化 ||W - Ŵ||_F^2\n(权重重建,不考虑输入/输出分布)"]
    end
    subgraph OneSide["一侧白化(SVD-LLM)"]
        OS["最小化 ||(W-Ŵ)R^{1/2}||_F^2\n(输入激活加权,考虑哪些方向被使用)"]
    end
    subgraph TwoSide["双侧白化(IO-SVD)"]
        TS["最小化 ||C^{1/2}(W-Ŵ)R^{1/2}||_F^2\n(同时考虑输入激活 + 输出KL敏感性)"]
    end
    Plain -->|"加入输入感知"| OneSide
    OneSide -->|"加入输出KL敏感性"| TwoSide

模块二:自适应异构秩分配

为什么需要异构秩?

现有大多数方法按比例对每层分配相同的压缩率(如每层保留 80% 参数)。这忽略了一个关键事实:不同层对压缩的敏感度差异很大

直觉上,靠近输入/输出的层、注意力的 Q/K 投影、对应关键任务方向的 MLP 单元,可能远比中间层的某些 MLP 层更脆弱。给所有层分配同等压缩率,等于在”容易压缩”的层上浪费了预算,同时在”脆弱”的层上施加了过大压力。

替代方案及其问题:Dobi-SVD 通过反向传播优化每层秩,但每次搜索步都需要在压缩模型上跑完整的 forward+backward pass,计算开销很大。IO-SVD 选择一阶近似:用每个奇异分量的校准损失敏感度得分来驱动贪婪分配。

重要性得分推导

对白化矩阵 B=UΣVB_\ell = U_\ell \Sigma_\ell V_\ell^\top,损失 L\mathcal{L} 关于 WW_\ell 的梯度为 G=L/WG_\ell = \partial \mathcal{L}/\partial W_\ell。对应的白化梯度为:

G~=C1/2GR1/2\tilde{G}_\ell = C_\ell^{-1/2} G_\ell R_\ell^{-1/2}

损失关于第 ii 个奇异值 σ,i\sigma_{\ell,i} 的偏导(一阶):

g,i=u,iG~v,ig_{\ell,i} = u_{\ell,i}^\top \tilde{G}_\ell v_{\ell,i}

如果我们”丢弃”第 ii 个奇异分量,相当于把 σ,i\sigma_{\ell,i} 减为 0,即 Δσ,i=σ,i\Delta\sigma_{\ell,i} = -\sigma_{\ell,i}。一阶预测的损失变化为:

ΔLg,i(σ,i)\Delta\mathcal{L} \approx g_{\ell,i} \cdot (-\sigma_{\ell,i})

因此,重要性得分(公式 10)为:

I,i=g,iσ,iI_{\ell,i} = |g_{\ell,i} \sigma_{\ell,i}|

这个得分是梯度幅度和奇异值幅度的乘积:一个分量若奇异值很小(对权重本身贡献少),或梯度很小(损失对该方向不敏感),都会有低得分——两种情况下丢弃它都是安全的。

贪婪分配算法

算法 1:IO-SVD 初始化
输入:权重 {W_ℓ},校准集 D_cal,全局压缩预算 B_target,最小秩比 η
输出:初始状态、最小堆 Q、目标删减量 B_rm

1. 全局预算:B_rm = π · Σ_ℓ m_ℓ n_ℓ,其中 π = 压缩率(如 0.2 表示删 20%)
2. 对每一层 ℓ:
   a. 用 D_cal 运行 forward/backward,估计 R_ℓ 和 C_ℓ
   b. 形成 B_ℓ = C_ℓ^{1/2} W_ℓ R_ℓ^{1/2},计算完整 SVD
   c. 计算 G_ℓ = ∂L_cal/∂W_ℓ,白化得 G̃_ℓ
   d. 对每个分量 i:g_{ℓ,i} = u_{ℓ,i}^T G̃_ℓ v_{ℓ,i},I_{ℓ,i} = |g_{ℓ,i} σ_{ℓ,i}|
   e. 计算收支平衡秩:r_ℓ* = ⌊m_ℓ n_ℓ / (m_ℓ + n_ℓ)⌋
   f. 设最小秩下限:r_ℓ^min = ⌈η · r_ℓ*⌉
   g. 把当前"尾部候选"(最小保留分量的得分)推入最小堆 Q
算法 2:IO-SVD 贪婪截断
输入:初始化状态,堆 Q,目标删减量 B_rm
输出:压缩权重 {Ŵ_ℓ}

While 已删减量 b < B_rm 且 Q 非空:
   1. 从 Q 弹出得分最小的条目 (I_{ℓ,i}, ℓ, i, Δb)
   2. 删除层 ℓ 当前的"尾部"奇异分量;r_ℓ -= 1
   3. 更新 b += Δb(按存储增益公式计算)
   4. 若 r_ℓ > r_ℓ^min:把层 ℓ 新的尾部候选推入 Q

最终重建:
   对每层 ℓ:
     若 r_ℓ > r_ℓ*:保留密集权重(低秩无存储优势)
     否则:Ŵ_ℓ = C_ℓ^{-1/2} U_{ℓ,1:r_ℓ} Σ_{ℓ,1:r_ℓ} V_{ℓ,1:r_ℓ}^T R_ℓ^{-1/2}

存储增益公式的细节

这是算法中一个容易忽略但非常重要的细节。低秩分解只有在秩低于收支平衡点时才有存储优势:

storage_gain(r)={0r>r+1mnr(m+n)r=r+1m+nrr\text{storage\_gain}(r) = \begin{cases} 0 & r > r_\ell^* + 1 \\ m_\ell n_\ell - r_\ell^*(m_\ell + n_\ell) & r = r_\ell^* + 1 \\ m_\ell + n_\ell & r \leq r_\ell^* \end{cases}

  • r>r+1r > r_\ell^* + 1:即使删减一个分量,低秩表示仍比密集表示贵,存储增益为 0
  • r=r+1r = r_\ell^* + 1:这次删减让层”跨越”收支平衡点,一次性获得 mnr(m+n)m_\ell n_\ell - r_\ell^*(m_\ell + n_\ell) 的存储增益
  • rrr \leq r_\ell^*:每删一个分量节省 m+nm_\ell + n_\ell 个参数(删除左右奇异向量各一列)

这个分段公式使算法不会在”还没节省存储的区域”浪费预算,而是等层进入有效压缩区间后才开始计入删减量。

sequenceDiagram
    participant Q as 最小堆 Q
    participant L1 as 层 1(高敏感度)
    participant L2 as 层 2(低敏感度)
    participant L3 as 层 3(低敏感度)

    Note over Q: 初始化:每层推入当前尾部候选
    Q->>L2: 弹出层2尾部(得分最小)
    L2-->>Q: 删除 σ_{2,r2};推入新尾部
    Q->>L2: 弹出层2新尾部(仍然最小)
    L2-->>Q: 删除 σ_{2,r2-1};推入新尾部
    Q->>L3: 弹出层3尾部(现在最小)
    L3-->>Q: 删除 σ_{3,r3};推入新尾部
    Note over L1: 层1始终在堆里但得分高,保留更多奇异值
    Note over Q: 结果:层1=高秩,层2/3=低秩(异构分配)

模块三:损失感知重映射(混合 SVD–量化)

纯低秩压缩的极限

在极端压缩率(如只保留 40% 参数)下,为了达到存储目标,必须丢弃大量奇异值,质量损失严重。Dobi-SVD 的方案是:SVD 截断后,把低秩因子中的某些行量化到 8-bit,这样在同等存储预算内可以保留更高秩——用量化误差换取截断误差的减少。

Dobi-SVD 的不足:它的行选择规则是固定的结构性规则(如按行编号),与量化误差的实际损失影响无关。

IO-SVD 的损失感知行选择

SVD 截断后,写压缩权重为 W^=AD\hat W_\ell = A_\ell D_\ell^\top(其中 A,DA_\ell, D_\ell 是低秩因子)。对每个候选行 r,ir_{\ell,i}(来自 AA_\ellDD_\ell):

1. 模拟 int8 量化误差

Δr,i=Q8(r,i)r,i\Delta r_{\ell,i} = Q_8(r_{\ell,i}) - r_{\ell,i}

2. 用 calibration 梯度打分(行梯度 γ,i=Lcal/r,i\gamma_{\ell,i} = \partial \mathcal{L}^{cal} / \partial r_{\ell,i}):

s,i=γ,i,Q8(r,i)r,is_{\ell,i} = |\langle \gamma_{\ell,i},\, Q_8(r_{\ell,i}) - r_{\ell,i} \rangle|

这个内积本质上是损失对该行量化误差的一阶灵敏度:如果梯度与量化误差方向对齐,得分高(量化该行损失大);如果梯度与量化误差正交,得分低(量化安全)。

3. 贪婪选择:把所有候选行按 s,is_{\ell,i} 升序排列,依次量化到 int8,直到剩余压缩预算 CremC_{rem} 满足:

Crem=max{0,CtargetCsvd}C_{rem} = \max\{0, C_{target} - C_{svd}\}

损失感知重映射流程图
───────────────────────────────────────
SVD 截断后:Ŵ_ℓ = A_ℓ D_ℓ^T

1. 收集所有候选行:rows = {A_ℓ 的每一行} ∪ {D_ℓ 的每一行}

2. 对每一行 r_{ℓ,i}:
   Δr = Q8(r_{ℓ,i}) - r_{ℓ,i}        # int8 量化误差(实数差值)
   γ_{ℓ,i} = ∂L_cal / ∂r_{ℓ,i}       # 校准损失对该行的梯度
   s_{ℓ,i} = |⟨γ_{ℓ,i}, Δr⟩|         # 预测损失影响

3. 按 s_{ℓ,i} 升序排序(从"最安全可量化"到"最不安全")

4. 依次量化低得分行:
   将 r_{ℓ,i} 存储为 int8(从 2 字节降至 1 字节/参数)
   记录行索引(推理时需要知道哪些行是 int8)
   直到累计节省 ≥ C_rem 为止

5. 剩余行保留 fp16
───────────────────────────────────────

为什么这优于结构性行选择? 量化对不同行的实际损失影响取决于量化误差和梯度的方向关系,而非行的位置。损失感知选择直接针对”哪些行量化后损失增加最少”,比按编号选择更精准。

系统流程总览

flowchart TD
    A["原始密集权重 {W_ℓ}"] --> B["在 D_cal 上运行 forward/backward\n估计 R_ℓ、C_ℓ、G_ℓ"]
    B --> C["构造双侧白化矩阵\nB_ℓ = C_ℓ^{1/2} W_ℓ R_ℓ^{1/2}"]
    C --> D["完整 SVD:B_ℓ = U_ℓ Σ_ℓ V_ℓ^T"]
    D --> E["计算白化梯度 G̃_ℓ\n每分量得分 I_{ℓ,i} = |g_{ℓ,i} σ_{ℓ,i}|"]
    E --> F["全局贪婪秩分配\n(最小堆,按得分弹出)\n→ 异构 {r_ℓ}"]
    F --> G["逆白化恢复\nŴ_ℓ = C_ℓ^{-1/2} Û_ℓ Σ̂_ℓ V̂_ℓ^T R_ℓ^{-1/2}"]
    G --> H{需要极端压缩?}
    H -->|否| I["输出压缩模型\n纯低秩 fp16"]
    H -->|是| J["损失感知重映射\n打分 s_{ℓ,i} = |⟨γ,Δr⟩|\n低得分行→int8,高得分行→fp16"]
    J --> K["输出混合精度压缩模型\n(SVD + 选择性 int8)"]

重映射消融:损失感知行选择的精确定量

论文的 Table 6 给出了一个非常精细的消融,专门对比”标准重映射(∗)“和”损失感知重映射(‡)“的区别。让我逐列分析:

LLaMA-7B 重映射消融(PPL,越低越好)
保留率 0.8:            Wiki2  C4     PTB
保留率 0.6:            Wiki2  C4     PTB

SVD-LLM:
  压缩后(无重映射)    7.94  15.84  16.22  /  13.11  49.83  63.75
  + 标准重映射∗        5.86   7.82   8.82  /   6.98  11.59  12.88
  + 损失感知重映射‡    5.66   7.78   8.71  /   6.69  11.39  12.46

ZS-SVD:
  压缩后(无重映射)    6.74  10.74  11.87  /  11.44  34.13  43.19
  + 标准重映射∗        5.90   7.95   8.81  /   6.96  11.52  12.72
  + 损失感知重映射‡    5.69   7.92   8.78  /   6.69  11.46  12.80

IO-SVD(本文):
  压缩后(无重映射)    6.41   9.82  10.93  /   9.84  27.15  28.84
  + 标准重映射∗        5.76   7.61   8.59  /   6.48  10.24  10.95
  + 损失感知重映射‡    5.59   7.62   8.56  /   6.27  10.15  10.89

观察 1:重映射本身的大增益

无论是哪种基础压缩方法(SVD-LLM / ZS-SVD / IO-SVD),加上重映射后的提升都非常显著。以 IO-SVD 在 60% 保留率为例:6.48 → 9.84(无重映射),降幅 3.36 PPL,远超双侧白化对纯 SVD 的贡献。这说明混合 int8 量化是在极端压缩率下恢复质量最有力的手段。

观察 2:损失感知 vs. 标准重映射的边际提升

损失感知(‡)在标准(∗)基础上的进一步提升较小,但在 C4 和 PTB(分布外)数据集上的改善比 WikiText2 更明显。例如 IO-SVD 在 60% 保留率下:

  • Wiki2:6.48 → 6.27(损失感知带来额外 0.21 PPL)
  • PTB:10.95 → 10.89(改善相对更少)
  • C4:10.24 → 10.15

这表明损失感知重映射在分布外数据上的鲁棒性比标准重映射更好——直觉上正确,因为损失感知选择基于梯度信息,而不是固定的结构位置。

观察 3:三种方法之间的排序在所有设置下一致

IO-SVD‡ > ZS-SVD‡ > Dobi-SVD∗(在绝大多数设置下),说明:

  1. 白化空间的质量(双侧 > 零和约束 > 结构性)
  2. 行选择策略的质量(损失感知 > 结构性)

这两个维度的改善在实验上是正交的,组合后带来持续的提升。

计算成本分析

任何压缩方法都需要权衡压缩时间和压缩质量。IO-SVD 的主要计算开销来自:

1. 统计量估计(Forward + Backward pass)

  • R=E[xx]R_\ell = \mathbb{E}[xx^\top]:256 次 forward pass,每次记录每层输入激活的外积

    • 每层:T×din2T \times d_{in}^2 浮点运算 → 对 LLaMA-7B(din=4096d_{in}=4096)约 8.5 亿次运算
    • 总计(32 层 × 7 矩阵):约 1900 亿次浮点运算
  • C=E[JHJ]C_\ell = \mathbb{E}[J^\top H J]:每个 token 需要 KK 次 VJP

    • 每层每 token:K×doutK \times d_{out} 次运算 ≈ 64×4096=260,00064 \times 4096 = 260,000
    • 总计:256 tokens × 2048 length × 32 层 × 7 矩阵 × KK 次 VJP ≈ 数十 T 浮点

2. SVD 计算

对每个 BRm×nB_\ell \in \mathbb{R}^{m \times n},完整 SVD 需要 O(min(m,n)mn)O(\min(m,n) \cdot mn) 时间。对 LLaMA-7B 的最大矩阵(4096×40964096 \times 4096),这约为 40963704096^3 \approx 70 亿次浮点运算。但 SVD 是高度优化的 LAPACK 操作,实际只需数秒。

3. 贪婪分配

使用最小堆(min-heap),每次弹出和插入代价 O(logL)O(\log L),总步骤数约 πP/(m+n)20%7B/8000175,000\pi \cdot P / (m+n) \approx 20\% \cdot 7\text{B} / 8000 \approx 175,000 步。这是 O(PlogL)O(P \log L) 的运算,相比 SVD 本身是次要的。

与其他方法比较

方法校准时间(相对)备注
ASVD只需前向 pass
SVD-LLM前向 + SVD
Dobi-SVD10-50×反向传播优化每层秩
IO-SVD3-5×前向(RR_\ell)+ K次VJP(CC_\ell)+ SVD

IO-SVD 比 Dobi-SVD 快很多,比 ASVD/SVD-LLM 略慢,但质量优势显著。在实际中,256 条序列的校准只需要 30-60 分钟(7B 模型,A100),是完全可接受的预处理代价。

实验结果分析

实验设置

  • 模型:LLaMA-7B、LLaMA-13B、LLaMA-2-7B、OPT-6.7B、Vicuna-7B、LLaVA-1.5 7B/13B、SmolVLM 2B
  • 校准数据:256 条 WikiText2 随机序列,长度 2048
  • 压缩目标:注意力的 Q/K/V/O 投影 + MLP 层
  • 基线:ASVD、SVD-LLM、Dobi-SVD、ZS-SVD
  • 评测:WikiText2/PTB/C4 困惑度;零样本准确率(OpenBookQA、ARC、WinoGrande、HellaSwag、PIQA、MathQA)

核心结果:LLaMA-7B 困惑度

LLaMA-7B WikiText2 困惑度(PPL,越低越好)
保留率:       0.8     0.6     0.4
────────────────────────────────────────
原始基线:     5.68    5.68    5.68
────────────────────────────────────────
ASVD:        11.14   1407    57057   ← 60%/40%直接崩溃
SVD-LLM:      7.94   13.11   53.74
Dobi-SVD:     8.54   13.54   46.18
ZS-SVD:       6.74   11.44   45.17
IO-SVD(ours):6.41    9.84   27.70
────────────────────────────────────────
加重映射后:
Dobi-SVD∗:    6.08    8.12    9.95
ZS-SVD∗:      5.90    6.96    6.73
IO-SVD‡:      5.59    6.27    6.41   ← 最优
────────────────────────────────────────

几个重要观察:

  1. ASVD 在 60% 和 40% 下直接崩溃(PPL > 1000),说明纯对角线输入缩放不足以保护极端压缩下的质量

  2. IO-SVD 在纯低秩(无重映射)时,在所有保留率下都优于 SVD-LLM 和 Dobi-SVD;在 40% 保留率下,PPL 从 SVD-LLM 的 53.74 降至 27.70——差距随压缩率升高而扩大

  3. 加上损失感知重映射后,IO-SVD‡ 在 80% 保留率下达到 5.59 PPL——距离未压缩模型(5.68)只差 0.1 PPL!

  4. ZS-SVD∗(+传统重映射)在 40% 时达到 6.73,而 IO-SVD‡ 为 6.41,损失感知重映射在极端压缩下仍有额外增益

消融实验:各组件贡献

这张表是论文中最有价值的分析(Table 4),直接回答”哪个模块最重要”:

白化类型                 异构秩?  PPL(0.8)  PPL(0.6)  PPL(0.4)
────────────────────────────────────────────────────────────────
输入侧白化(SVD-LLM)      否      7.95      13.11      53.74
双侧 Kronecker(OBD-LLM)  否      7.36      11.34      32.95
双侧 KL(IO-SVD)          否      7.31      11.20      32.09
────────────────────────────────────────────────────────────────
输入侧白化(SVD-LLM)      是      6.72      11.65      62.76
双侧 Kronecker(OBD-LLM)  是      6.45       9.90      28.19
双侧 KL(IO-SVD)          是      6.41       9.84      27.70
────────────────────────────────────────────────────────────────

关键发现:异构秩分配是最大贡献者

看 SVD-LLM(一侧白化)从”无异构秩”(7.95)到”有异构秩”(6.72):PPL 降低 1.23。而加入双侧白化后(IO-SVD,无异构秩)只有 7.31,仅降低 0.64。

这说明什么? 不同层的敏感度差异是压缩质量的主要瓶颈,而不是白化目标的精确度。统一秩分配在”容易层”浪费了预算,在”脆弱层”过度压缩。

双侧白化的贡献在哪里最大? 在极端压缩(40%)时:双侧的 27.70 vs. 一侧的 62.76——差异将近一半。极端压缩放大了”哪个方向被丢弃”这个决策的影响,此时精确的双侧曲率估计更为关键。

视觉语言模型(VLM)结果

LLaVA-1.5 7B 在 70% 保留率下的 ScienceQA-IMG 准确率:

方法         ScienceQA-IMG(70%保留率)
ASVD         50.12
SVD-LLM      63.71
QSVD         68.22
WSVD         67.72
IO-SVD       68.07   ← 与专为VLM设计的QSVD/WSVD持平或更好

对于 SmolVLM 2B(较小模型,冗余度更低),IO-SVD 的优势在激进压缩下更为突出——这符合直觉:越小的模型越依赖精确的敏感度估计。

跨架构泛化

在 OPT-6.7B、Vicuna-7B、LLaMA-13B 上的 20% 剪枝结果一致表明,IO-SVD 的优势不依赖特定架构,具有良好的泛化性。

推理加速与内存减少

graph LR
    subgraph Baseline["密集基线"]
        B1["权重: 12.6 GB\nKV缓存: 64.0 GB\n总计: 77.6 GB\n吞吐: 470 tok/s"]
    end
    subgraph SVDOnly["IO-SVD(仅权重压缩)"]
        S1["权重: 5.4 GB(↓57%)\nKV缓存: 64.0 GB(不变)\n总计: 70.4 GB\n吞吐: 483 tok/s(1.03×)"]
    end
    subgraph VCache["+ V缓存压缩"]
        V1["权重: 5.4 GB\nKV缓存: 38.8 GB\n总计: 50.3 GB\n吞吐: 1392 tok/s(2.96×)"]
    end
    subgraph KVCache["+ KV双缓存压缩"]
        K1["权重: 5.4 GB\nKV缓存: 11.6 GB\n总计: 23.1 GB\n吞吐: 2043 tok/s(4.34×)"]
    end
    Baseline --> SVDOnly --> VCache --> KVCache

关键洞察:权重压缩本身对速度提升有限(1.03×),真正的加速来自 KV 缓存压缩。

这是因为,在解码阶段,GPU 的瓶颈是内存带宽,而非算力:每生成一个 token 都需要把积累的 KV 缓存从显存读出来。KV 缓存从 64.0 GB 压缩到 11.6 GB 后,每次 attention 计算需要搬运的数据量大幅减少,吞吐量随之飙升。

KV 缓存压缩的原理:对于压缩后的 Key/Value 投影 W^K/V=AD\hat W_{K/V} = A D^\top,不要在缓存中存完整的投影结果 ht=A(Dxt)h_t = A(D^\top x_t),而是只缓存低维潜向量 zt=DxtRrz_t = D^\top x_t \in \mathbb{R}^rrr 是保留秩),在 attention 计算时再用 ht=Azth_t = A z_t 恢复。缓存量从 2dheadT2 d_{head} T 降至 2rT2 r TTT 为序列长度),节省比例为 1r/dhead1 - r/d_{head}

局限性与边界条件

局限 1:Top-K 曲率近似对长尾词汇不准确
ptp_t 在词汇表上分布比较均匀时(如代码生成中大量罕见 token 均有合理概率),Top-K 剪掉了不少有意义的曲率,可能低估某些方向的敏感性。

局限 2:贪婪秩分配非全局最优
删除分量 (,i)(ℓ, i) 后,其他分量的重要性得分会发生变化(交互效应),但贪婪算法不更新其他得分。对于深度压缩,这可能导致次优的秩分布。加入类似 AdaOBC 的”更新后重新评分”步骤可以缓解,但代价是 O(n2)O(n^2) 的计算复杂度。

局限 3:规模验证上限为 13B
对 70B+ 模型,校准时计算 CC_\ell(需要多次反向传播)和维护大型堆的开销尚未评估。K-FAC 类方法在大模型上有额外技巧(如分块近似)可能需要引入。

什么情况下不推荐用 IO-SVD?

  • 压缩率极低(< 10% 剪枝):所有方法差异极小,一侧白化已足够
  • 校准数据与目标域差异极大:CC_\ellRR_\ell 的估计依赖校准分布,分布偏移可能导致得分不准
  • 需要细粒度 fine-tuning 恢复:如果后续有 LoRA 恢复步骤,初始化质量的影响被一定程度弱化

与前作的系统性比较

方法白化类型秩分配重映射备注
FWSVDFisher 加权(权重空间)均匀最早的”重要性加权 SVD”
ASVD一侧对角缩放均匀简单激活感知
SVD-LLM一侧 Cholesky(输入协方差)均匀主流基线
SVD-LLM v2一侧 Cholesky异构(截断损失估计)加了异构秩
Dobi-SVD梯度直接优化梯度反传结构性计算贵
ZS-SVD一侧,损失约束损失约束结构性约束形式的分配
OBD-LLM双侧 Kronecker均匀无异构秩
IO-SVD双侧 KL(本文)贪婪一阶得分损失感知三者结合

从表中可以看出,IO-SVD 是第一个同时具备”精确双侧白化 + 异构秩 + 损失感知重映射”三项能力的方法。

深入理解:高效曲率计算的完整推导

CC_\ell 的高效计算是 IO-SVD 技术上最精妙的地方。让我完整走一遍 Appendix C 的推导逻辑。

问题设定

对第 \ell 层,token tt 处的层输出为 h,tRdouth_{\ell,t} \in \mathbb{R}^{d_{out}}。Top-KK 限制的曲率为:

Ctoken,t()Jt,K()Ht,KJt,K(),Jt,K()=zt,Kh,tRK×doutC_{\text{token},t}^{(\ell)} \approx J_{t,K}^{(\ell)\top} H_{t,K} J_{t,K}^{(\ell)}, \quad J_{t,K}^{(\ell)} = \frac{\partial z_{t,K}}{\partial h_{\ell,t}} \in \mathbb{R}^{K \times d_{out}}

其中 zt,Kz_{t,K} 是 top-KK 支撑上的 logit。

Ht,KH_{t,K} 进行因式分解

st=pt,KRKs_t = \sqrt{p_{t,K}} \in \mathbb{R}^K(对重归一化后的概率取平方根),定义:

Dt=Diag(st),Ωt=IKststD_t = \text{Diag}(s_t), \quad \Omega_t = I_K - s_t s_t^\top

由于 pt,Kp_{t,K} 重归一化,st2=1\|s_t\|^2 = 1,所以 Ωt\Omega_t 是一个投影算子(Ωt2=Ωt\Omega_t^2 = \Omega_t)。

At=DtΩtRK×KA_t = D_t \Omega_t \in \mathbb{R}^{K \times K},则:

AtAt=DtΩt(DtΩt)=DtΩtΩtDt=DtΩtDtA_t A_t^\top = D_t \Omega_t (D_t \Omega_t)^\top = D_t \Omega_t \Omega_t^\top D_t = D_t \Omega_t D_t =Dt(Istst)Dt=Diag(pt,K)pt,Kpt,K=Ht,K= D_t (I - s_t s_t^\top) D_t = \text{Diag}(p_{t,K}) - p_{t,K} p_{t,K}^\top = H_{t,K}

所以 Ht,K=AtAtH_{t,K} = A_t A_t^\top,其中 AtRK×KA_t \in \mathbb{R}^{K \times K}(维度从 VV 降到 KK!)。

转化为 VJP 累积

Ctoken,t()Jt,KAtAtJt,K=(AtJt,K)(AtJt,K)=FtFtC_{\text{token},t}^{(\ell)} \approx J_{t,K}^\top A_t A_t^\top J_{t,K} = (A_t^\top J_{t,K})^\top (A_t^\top J_{t,K}) = F_t^\top F_t

其中 Ft=AtJt,KRK×doutF_t = A_t^\top J_{t,K} \in \mathbb{R}^{K \times d_{out}}

FtF_t 的每一行 ft,k=(AtJt,K)k,:f_{t,k} = (A_t^\top J_{t,K})_{k,:} 是一个向量-Jacobian 乘积(VJP):

ft,k=(h,t)[(At)k,:zt,K]f_{t,k} = \left(\frac{\partial}{\partial h_{\ell,t}}\right) \left[(A_t^\top)_{k,:} z_{t,K}\right]

这可以通过 PyTorch 的 torch.autograd.grad 或反向传播钩子,用向量 (At)k,:RK(A_t^\top)_{k,:} \in \mathbb{R}^K 触发一次反向传播得到,代价为 O(Kdout)O(K \cdot d_{out}),完全不需要显式构建 VV 维 Jacobian。

完整的 CC_\ell 累积算法

# 伪代码(PyTorch 风格)
C_ell = torch.zeros(d_out, d_out)

for x, y in calibration_data:
    # 前向传播,记录 h_{ℓ,t} 和 top-K 概率
    with hook_record_output(layer_ell) as h_t:
        logits = model(x)  # shape: [T, V]
    
    for t in range(T):
        # 取 top-K 索引和概率
        topk_vals, topk_idx = logits[t].topk(K)
        p_topK = softmax(topk_vals)          # shape: [K]
        
        # 构建 A_t
        s_t = p_topK.sqrt()                  # shape: [K]
        A_t = diag(s_t) @ (I - outer(s_t, s_t))  # [K, K]
        
        # K 次 VJP
        F_t = torch.zeros(K, d_out)
        for k in range(K):
            v_k = A_t.T[k]                   # 触发向量,shape: [K]
            # 反向传播:∂(v_k^T z_{t,K}) / ∂h_{ℓ,t}
            f_k = vjp(logits[t][topk_idx], h_t[t], v_k)  # shape: [d_out]
            F_t[k] = f_k
        
        # 累积 C_ℓ += F_t^T F_t
        C_ell += F_t.T @ F_t

C_ell /= (len(calibration_data) * T)

计算复杂度:每个 token 需要 KK 次 VJP,每次 VJP 的代价约为一次前向传播(通过计算图反向)。对于 T=256T=256 个 token、K=64K=64、深度 L=32L=32,总代价约为 KK 次完整的 backward pass——与一次训练迭代相当。

这里的关键洞察是:不需要 VV 维的任何东西Ht,KH_{t,K} 被分解成了 K×KK \times K 的矩阵乘积,Jacobian Jt,KJ_{t,K} 也只需要在 KK 个方向上的 VJP,而不是完整的 V×doutV \times d_{out} 矩阵。

Top-K 的意义和消融

为什么 Top-K 是合理的近似?直觉上:模型的预测分布通常高度集中在少数 token 上(语言有局部连续性),长尾词汇的概率极低,对 KL 散度的贡献可以忽略不计。

从公式角度:Ht=Diag(pt)ptptH_t = \text{Diag}(p_t) - p_t p_t^\top 的特征值分布由 ptp_t 决定。若 ptp_t 集中在 top-KK token,则 HtH_t 的大特征向量都在这 KK 个方向上。Top-KK 截断等价于保留了 HtH_t 的”主成分”。

论文消融(图 3) 表明:

  • KK 太小(<< 16):低估曲率,C_ℓ 不准
  • KK 太大(>> 128):引入长尾噪声,反而略有下降
  • 最优 KK 在 WikiText2 上选出后,在 PTB 和 C4 上也保持最优——说明这个近似的泛化性好

与 Optimal Brain Damage 和 GPTQ 的理论联系

IO-SVD 的一阶得分 I,i=g,iσ,iI_{\ell,i} = |g_{\ell,i} \sigma_{\ell,i}| 有着深厚的历史渊源:

Optimal Brain Damage(OBD,LeCun 1990):用二阶泰勒展开的对角项作为参数重要性得分:

Saliency(θj)=12Hjjθj2\text{Saliency}(\theta_j) = \frac{1}{2} H_{jj} \cdot \theta_j^2

其中 Hjj=2L/θj2H_{jj} = \partial^2 \mathcal{L} / \partial \theta_j^2 是对角 Hessian。

IO-SVD 的得分是第一阶的:

ΔL,ig,i(σ,i)    I,i=g,iσ,i\Delta\mathcal{L}_{\ell,i} \approx g_{\ell,i} \cdot (-\sigma_{\ell,i}) \implies I_{\ell,i} = |g_{\ell,i} \sigma_{\ell,i}|

为什么用一阶而不是二阶?

  1. 在白化空间里,二阶信息已经被隐式使用:白化矩阵 C1/2C_\ell^{1/2}R1/2R_\ell^{1/2} 本身就编码了曲率信息(CC_\ell 是 KL Hessian 的 Kronecker 因子),白化后的奇异值 σ,i\sigma_{\ell,i} 已经反映了在该方向上的”有效重要性”

  2. 计算代价:对角 Hessian 元素需要额外的反向传播步骤,代价 O(P)O(P)PP 是参数量);而白化梯度 G~\tilde G_\ell 只需在 CC_\ellRR_\ell 已知的情况下对原始梯度做简单线性变换

  3. 实验上足够:消融实验(Table 4)表明即使只用一阶得分,异构秩分配就能带来超过 1 PPL 的提升

与 GPTQ 的对比:GPTQ 用 OBC 框架的逆 Hessian 方法来精确最小化每一列删除后的激活重建误差,代价是 O(d2)O(d^2) 的内存(存储 Hessian 逆)。IO-SVD 的贪婪得分是 O(d)O(d) 的,不需要存储 Hessian 矩阵。

LLaMA-2 以及跨任务评测细节

论文 Table 5 在 LLaMA-2-7B 上进行了更全面的跨方法比较,把结构化剪枝方法也纳入对比:

LLaMA-2-7B,40% 参数删除(60% 保留)
方法              PIQA    HellaS.  WinoG.  ARC-e   ARC-c   平均
─────────────────────────────────────────────────────────────────
原始(FP16)       0.78    0.57    0.69    0.76    0.43    0.65
─────────────────────────────────────────────────────────────────
LLM-Pruner         0.70    0.41    0.53    0.53    0.27    0.48  ← 结构剪枝
SliceGPT           0.65    0.57    0.60    0.43    0.32    0.51  ← PCA切片
Bonsai             0.72    0.45    0.58    0.59    0.30    0.53  ← 结构剪枝
Wanda-sp           0.70    0.42    0.53    0.57    0.29    0.50  ← 非结构剪枝
SVD-LLM            0.56    0.30    0.57    0.39    0.21    0.41  ← SVD基线
ZS-SVD             0.63    0.34    0.60    0.46    0.25    0.45  ← SVD
IO-SVD             0.61    0.33    0.59    0.51    0.23    0.45  ← 本文
─────────────────────────────────────────────────────────────────
加入重映射后:
Dobi-SVD∗          0.72    0.45    0.64    0.67    0.31    0.56
ZS-SVD∗            0.72    0.46    0.67    0.66    0.33    0.57
IO-SVD‡            0.74    0.47    0.67    0.73    0.38    0.60  ← 最优
─────────────────────────────────────────────────────────────────

几个值得注意的现象:

现象 1:纯 SVD(无重映射)vs. 结构剪枝

在 40% 删除率下,纯 SVD 方法(SVD-LLM: 0.41,IO-SVD: 0.45)反而不如结构剪枝(Bonsai: 0.53)。这乍看令人惊讶,但原因清晰:结构剪枝删的是整个神经元/注意力头,剩余部分保持满秩运算;而低秩压缩把每层都”拉平”,所有层都受损。在极端压缩率下,“让部分结构完好无损”可能比”均匀降质”更好。

现象 2:重映射后 IO-SVD‡ 彻底翻盘

加入损失感知重映射后,IO-SVD‡ 达到 0.60 的平均准确率,超过所有结构剪枝方法。这说明:重映射让 SVD 方法在极端压缩下能保留更多”高敏感方向”的精度,从根本上改变了 SVD 方法的能力上限。

现象 3:ARC-Challenge 的差距最大

ARC-Challenge 需要多步推理,对模型质量最敏感。SVD-LLM 在这个任务上只有 0.21(几乎随机),而 IO-SVD‡ 达到 0.38——接近基线的 0.43。这说明 IO-SVD 的 KL 感知目标对保留推理能力特别有效。

压缩率和内存带宽的工程分析

IO-SVD 的实际推理加速来自一个根本性的观察:现代 GPU 解码是内存带宽受限的,而不是计算受限的。

在自回归解码阶段,每生成一个 token,GPU 需要:

  1. 读取模型的全部权重(约 2d2L2d^2 L bytes,其中 dd 是隐藏维度,LL 是层数)
  2. 读取 KV 缓存中已有的全部 K 和 V(约 4dheadTL4 d_{head} T L bytes,TT 是当前序列长度)
  3. 执行矩阵-向量乘法(GEMV)和注意力计算

计算量:O(d2L+dheadTL)O(d^2 L + d_{head} T L)(线性于序列长度) 带宽需求:同量级的内存读取

当批量大小为 1 时,GPU 的计算单元(CUDA core/tensor core)远比内存带宽宽裕,系统处于内存带宽瓶颈状态。

以 LLaMA-7B 为例(近似估算):
─────────────────────────────────────────────────
参数量:7B × 2 bytes(fp16)= 14 GB 权重
KV缓存:128层 × 32头 × 2048 tokens × 128维 × 2(K+V)× 2 bytes ≈ 32 GB
总读取量(每 token):~46 GB 数据搬运

GPU 内存带宽:A100 = 2 TB/s,RTX 4090 = 1 TB/s

理论最大吞吐(A100):2TB/46GB ≈ 43 tok/s(单批次)
实测约 30-40 tok/s(吻合)
─────────────────────────────────────────────────

IO-SVD + KV 缓存压缩把权重降到 5.4 GB,KV 缓存降到 11.6 GB:

压缩后总读取量:~17 GB(约降 73%)
理论最大吞吐(A100):2TB/17GB ≈ 118 tok/s
(实测在 96 GB RTX PRO Blackwell 上:2043 tok/s,因为序列更长 batch 更大)

为什么低秩权重压缩本身只有 1.03× 提升?

因为在大批量(batch 64)时,GPU 已经充分利用计算单元,权重读取不是瓶颈;此时计算量的减少没有直接转化为延迟降低。只有在 KV 缓存也压缩后,带宽受限才被解除。

这给我们的工程启示:SVD 压缩的主要价值在大批量推理里是 KV 缓存压缩,而非权重大小本身。单卡小批量(batch 1)场景下,权重压缩带来的 GEMV 计算量减少才有更直接的延迟提升。

可复现性说明

  • 代码开源:https://github.com/mint-vu/IO-SVD
  • 校准数据:256 条 WikiText2 序列,容易获取和复现
  • 硬件:NVIDIA RTX PRO 6000 Blackwell Max-Q(96 GB VRAM),A100/H100 80 GB 对 7-13B 模型应当够用
  • 关键超参:阻尼系数 λR,λC\lambda_R, \lambda_C,Top-K 值 KK,最小秩比 η\eta
  • Top-K 选择:在 WikiText2 验证集上做消融,选最优 KK;论文显示该选择能泛化到 PTB 和 C4

复现注意事项:矩解耦近似(假设 xtx_tCtoken,tC_{\text{token},t} 独立)在校准数据与目标域差距大时可能不准,建议使用与目标任务接近的校准数据。

我的思考与评价

IO-SVD 的主要贡献是把信息几何(KL 散度)、Kronecker 因子近似(K-FAC 思想)和贪婪序列优化(Optimal Brain Damage 精神)有机地结合在了 SVD 压缩框架里。

最让我印象深刻的是异构秩分配的主导地位(消融实验 Table 4)。这在方法论上有重要意义:与其花大量精力精炼白化目标(从一侧到双侧只有 0.6 PPL 的提升),不如先保证每层的压缩率是按敏感度定制的(提升超过 1.0 PPL)。这个优先级对未来研究有很好的指导:秩分配策略的回报 > 白化精度的回报

KV 缓存压缩的价值被低估:4.34 倍吞吐提升 + 内存从 77.6 GB 降至 23.1 GB,意味着原本需要 4×A100 的模型现在单卡 RTX PRO 就能高效服务。这个工程意义比 PPL 数字更直接。

我期待的后续工作

  1. 二阶交互修正:在贪婪删除每个分量后更新相邻分量的得分,可能进一步改善极端压缩下的质量
  2. 领域自适应校准:研究校准集与目标域不匹配时 CC_\ell 的泛化性
  3. 与激活量化结合:IO-SVD 目前只量化低秩因子行,若同时量化激活,可能在相同质量下达到更高压缩率
  4. 70B+ 规模验证:校准时的计算成本是主要障碍,看看是否有更高效的 CC_\ell 估计方案

总体来说,IO-SVD 是 SVD 压缩领域一篇清晰、严谨、贡献完整的论文。三个模块的设计都有清晰的数学动机,实验消融充分,推理加速的结合也很有工程价值,值得认真研读。

与 DeepSeek MLA 的类比:DeepSeek V3 的多头潜注意力(MLA)在训练时就引入了低秩 KV 投影,把 K/V 压缩到低维潜向量再解压。IO-SVD 的 KV 缓存压缩从另一个方向得到了同样的效果——把已有的 K/V 权重事后分解为低秩形式,从而让缓存只存低维潜向量。这种”训练时 MLA”和”事后 SVD”的收敛,说明低秩 KV 表示是一个稳健的通用原则,并不依赖特定的训练方式。

对研究者的启示:从这篇论文可以读出一个清晰的设计原则——每个设计选择都要有正交的消融。论文对白化类型(一侧/双侧)和秩分配策略(均匀/异构)做了 2×3 的因子实验,清楚地隔离了每个因素的独立贡献。这种干净的实验设计使得结论(“异构秩是主要贡献”)具有说服力,而不是模糊地说”我们的系统更好”。

对工程师的启示:如果你手头有一个 7B 模型,显存勉强放得下,IO-SVD + KV 缓存压缩可以在损失不到 1 PPL 的情况下把峰值内存从 77.6 GB 降到 23.1 GB,吞吐提升 4.34 倍。对于需要大批量高效推理的生产场景,这个组合的工程价值非常直接。压缩的校准只需要 256 条 WikiText2 样本,整体流程比 fine-tuning 轻量得多。

一个开放问题:论文的实验都用 WikiText2 作为校准集。但在代码生成、医疗问答、法律文本这些专业领域,词汇分布差异很大——top-K 的选取和 CC_\ell 的估计是否仍然准确?这个问题对实际落地非常关键,值得系统研究。我猜测在分布差异极大的域,可能需要用目标域数据做校准,但论文没有对此进行评估。

未来研究方向

这篇论文打开了几个值得深入探索的问题:

1. 二阶秩分配

当前的一阶得分 g,iσ,i|g_{\ell,i}\sigma_{\ell,i}| 是对真实损失影响的代理。如果能加入对角 Hessian 项(类似 OBD 的 h,iih_{\ell,ii}),理论上能更精确地预测删除某个分量后的损失变化,在极端压缩率下可能有额外增益。代价是每个分量需要额外的二阶信息计算。

2. 领域自适应校准

IO-SVD 的 CC_\ellRR_\ell 都依赖校准数据的分布。对于专业领域部署,应当使用目标域数据来估计这两个矩阵。一个有趣的研究问题是:在 WikiText2 上校准的 IO-SVD,在代码生成(HumanEval)上的压缩质量是否显著下降?如果是,需要多少领域数据才能恢复?

3. 与 LoRA 恢复的结合

IO-SVD 提供了比 SVD-LLM 更好的初始化。在此基础上加 LoRA 适配器做少量 fine-tuning,可能进一步提升质量上限。特别是在 40% 保留率下,IO-SVD 已经大幅降低了损失(PPL 27.70 vs. SVD-LLM 的 53.74),LoRA 恢复从更好的起点出发,理论上能用更少的步骤达到更好的结果。

4. 多 GPU 场景下的 KV 缓存解耦

在分离式推理架构(如 Mooncake)中,KV 缓存需要通过网络从 prefill worker 传输到 decode worker。低秩潜向量 zt=Dxtz_t = D^\top x_t(维度 rr)比完整 KV(维度 dheadd_{head})小得多,网络传输量随之降低。这是 IO-SVD 在生产系统里的一个额外工程价值,值得在分离式架构评测中专门量化。

5. 扩展到 SSM/Mamba

双侧白化 SVD 本质上是对线性映射的压缩框架。State Space Model(如 Mamba、RWKV)也有大量矩阵运算,理论上可以套用类似的双侧白化思路——但需要适配循环结构(SSM 的状态转移矩阵有特殊的时间展开约束),这是一个有趣的扩展方向。