当前位置: 首页 > news >正文

矩阵奇异值分解(SVD)中Golub–Kahan 双对角化 + 对双对角矩阵的隐式QR详解

总体思路(两阶段):

  1. 正交降阶(reduction):用一系列正交变换(通常是 Householder 反射)把任意矩阵 A∈Rm×nA\in\mathbb R^{m\times n}ARm×n 变换成上(或下)双对角(bidiagonal)矩阵 BBB,同时累积这些正交变换得到 U0,V0U_0,V_0U0,V0,使得

    A=U0 B V0⊤, A = U_0 \, B \, V_0^\top, A=U0BV0,

    其中 U0∈Rm×m, V0∈Rn×nU_0\in\mathbb R^{m\times m},\ V_0\in\mathbb R^{n\times n}U0Rm×m, V0Rn×n 是正交矩阵(通常只显式保存产生的 Householder 向量以便以后生成奇异向量)。

  2. 对双对角矩阵做迭代(compute SVD of B):对上步得到的双对角矩阵 BBB(通常为上双对角:主对角 αi\alpha_iαi,上超对角 βi\beta_iβi)做迭代求 SVD。常用的数值方法是把问题转为对称三对角矩阵 T=B⊤BT=B^\top BT=BB 求特征值(因为 spec⁡(B⊤B)=σi(B)2\operatorname{spec}(B^\top B)=\sigma_i(B)^2spec(BB)=σi(B)2),并使用隐式位移(implicit shift)QRbulge-chasing with Givens 在不形成 TTT (或显式避免平方)情况下稳定求解奇异值与奇异向量。LAPACK 中的方案(历史上)是先用 bidiagonalize,再用 bdsqr / dbdsqrdgesvd / dgesdd 的细化方法求解。

下面把两部分分别深入展开并给出具体代数变换与伪代码。


A. Householder 双对角化(Golub–Kahan reduction):如何把 AAA 变成上双对角 BBB

目标:通过若干左右正交变换把 AAA 变为上双对角(upper bidiagonal)矩阵 BBB

B=[α1β10⋯0α2β2⋯00α3⋱⋮⋱⋱]. B = \begin{bmatrix} \alpha_1 & \beta_1 & 0 & \cdots\\[4pt] 0 & \alpha_2 & \beta_2 & \cdots\\[4pt] 0 & 0 & \alpha_3 & \ddots\\ \vdots & & \ddots & \ddots \end{bmatrix}. B=α100β1α200β2α3.

基本步骤(第 kkk 步,k=1,…,min⁡(m,n)k=1,\dots,\min(m,n)k=1,,min(m,n)

  1. 用左 Householder 把当前矩阵的第 kkk 列在第 kkk 行以下的元素全部零掉(保留位置 (k,k)(k,k)(k,k))。设当前矩阵为 A(k)A^{(k)}A(k),取列向量

    x=Ak:m, k(k)∈Rm−k+1. x = A^{(k)}_{k:m,\ k}\in\mathbb R^{m-k+1}. x=Ak:m, k(k)Rmk+1.

    构造 Householder 向量 vvv(例如 v=x±∥x∥e1v = x \pm \|x\| e_1v=x±xe1)并得到 Hk=I−2vv⊤v⊤vH_k = I - 2\frac{v v^\top}{v^\top v}Hk=I2vvvv,将其扩展为 $ \tilde H_k = \begin{bmatrix}I_{k-1} & 0\ 0 & H_k\end{bmatrix}$。然后

    A(k+12)=H~kA(k). A^{(k+\tfrac12)} = \tilde H_k A^{(k)}. A(k+21)=H~kA(k).

    这一步把第 kkk 列中第 k+1k+1k+1mmm 行置零;主对角位置 (k,k)(k,k)(k,k) 变成某个数,记作 αk\alpha_kαk.

  2. Householder(作用在列方向)把第 kkk 行在第 k+1k+1k+1 列以后的元素全部清零,保留上三角位置 (k,k+1)(k,k+1)(k,k+1)(即生成 βk\beta_kβk)。取行向量(转置后作为列向量)

    KaTeX parse error: Double superscript at position 34: …2)}_{k,\ k+1:n}^̲\top \in \mathb…

    构造右向量 www 做 Householder Gk=I−2ww⊤w⊤wG_k = I - 2\frac{w w^\top}{w^\top w}Gk=I2wwww(内部维度为 n−kn-knk),扩展为 G~k=[Ik00Gk]\tilde G_k = \begin{bmatrix} I_k & 0 \\ 0 & G_k\end{bmatrix}G~k=[Ik00Gk],然后

    A(k+1)=A(k+12)G~k. A^{(k+1)} = A^{(k+\tfrac12)} \tilde G_k. A(k+1)=A(k+21)G~k.

    这一步把第 kkk 行在 k+2,…,nk+2,\dots,nk+2,,n 的元素置零,只留下主对角(αk\alpha_kαk)和超对角(βk\beta_kβk)的位置。

循环直到 k=min⁡(m,n)k=\min(m,n)k=min(m,n)。最终 B=A(1)B=A^{(1)}B=A(1) 的形式即为上双对角。

代数要点

  • 每一步左 / 右 Householder 都是正交(Hk⊤Hk=IH_k^\top H_k=IHkHk=I),所以总体上

    A=(H~1H~2⋯ )⊤  B  (G~1G~2⋯ ). A = \bigl(\tilde H_1\tilde H_2\cdots\bigr)^\top \; B \; \bigl(\tilde G_1\tilde G_2\cdots\bigr) . A=(H~1H~2)B(G~1G~2).

    你可以把 U0=∏H~i⊤U_0 = \prod \tilde H_i^\topU0=H~iV0=∏G~iV_0 = \prod \tilde G_iV0=G~i 累积起来以便最终得到奇异向量(若需要完整的 U,VU,VU,V)。

  • 实现注意:不需要显式形成 U0,V0U_0, V_0U0,V0 的完整矩阵(代价高),只存 Householder 向量,并在需要奇异向量时回溯应用 Householder。

伪代码(简洁版)

Input: A ∈ R^{m×n}
for k = 1..min(m,n):# left reflect to zero below diagonal in col kx = A[k:m, k]v = householder_vector(x)           # v produces H = I - 2 vv^T/(v^T v)A[k:m, k:n] = (I - 2 vv^T/(v^T v)) * A[k:m, k:n]store v in array for U accumulationα_k = A[k,k]if k < n:# right reflect to zero beyond superdiagonal in row ky = A[k, k+1:n]^Tw = householder_vector(y)A[1:m, k+1:n] = A[1:m, k+1:n] * (I - 2 ww^T/(w^T w))store w for V accumulationβ_k = A[k, k+1]
end
Result: B is upper bidiagonal with diagonals α_i and superdiagonals β_i

B. 从双对角到 SVD:为何把问题转为 T=B⊤BT=B^\top BT=BB(对称三对角)以及隐式 QR 的思想

已得上双对角 BBB(假设 m≥nm\ge nmnBBBm×nm\times nm×n 上双对角)。要得到 BBB 的奇异值与奇异向量,可以通过 T=B⊤BT=B^\top BT=BBn×nn\times nn×n 对称三对角)来做特征分解,因为

B⊤B=T⇒eig(T)=σi(B)2. B^\top B = T \quad\Rightarrow\quad \text{eig}(T)=\sigma_i(B)^2. BB=Teig(T)=σi(B)2.

T=B⊤BT=B^\top BT=BB 的显式三对角结构(下标从 1 开始)

  • BBB 的主对角为 α1,…,αn\alpha_1,\dots,\alpha_nα1,,αn,超对角为 β1,…,βn−1\beta_1,\dots,\beta_{n-1}β1,,βn1(注意某些索引处 β0\beta_0β0 视作 0)。则

    T=B⊤B=[α12α1β1α1β1β12+α22α2β2⋱⋱⋱αn−1βn−1βn−12+αn2]. T = B^\top B = \begin{bmatrix}\alpha_1^2 & \alpha_1\beta_1 & & \\\alpha_1\beta_1 & \beta_1^2+\alpha_2^2 & \alpha_2\beta_2 & \\& \ddots & \ddots & \ddots \\& & \alpha_{n-1}\beta_{n-1} & \beta_{n-1}^2+\alpha_n^2 \end{bmatrix}. T=BB=α12α1β1α1β1β12+α22α2β2αn1βn1βn12+αn2.

    (第 iii 个对角项一般是 αi2+βi−12\alpha_i^2+\beta_{i-1}^2αi2+βi12,边界处 β0=βn=0\beta_0=\beta_n=0β0=βn=0 处理即可。)

为什么不直接对 TTT 做普通 QR(而要做隐式、在 BBB 上 chase)?

  • 在数值实现上,直接构造 T=B⊤BT=B^\top BT=BB 会平方条件数并放大舍入误差(BBB 的小奇异值的数值不稳定)。更稳定的做法是在不显式构造 TTT 的前提下,利用 T=B⊤BT=B^\top BT=BB 的结构,在 BBB 上以 Givens 旋转“追踪(bulge-chasing)”来实现对 TTT 的隐式 QR 步。这样既保留了矩阵的稀疏(带)结构,也能用数值上稳定的 Givens 旋转来实现相似变换。

隐式位移 QR 的核心思想(对称三对角)

隐式 QR(with shift μ\muμ)对对称三对角矩阵 TTT 做一次迭代相当于:

T−μI=QR⇒T′=RQ+μI=Q⊤TQ, T-\mu I = Q R\quad\Rightarrow\quad T' = RQ + \mu I = Q^\top T Q, TμI=QRT=RQ+μI=QTQ,

于是特征值不变。对三对角矩阵,这个 QR 步可通过一系列 Givens 旋转(消除第一列下元素,然后“bulge chase”)高效完成。把这些旋转映射回 BBB 上,会对应于在 BBB 上轮流右乘列旋转(对 VVV 的更新)和左乘行旋转(对 UUU 的更新),整个过程把三对角隐式地做了相似变换,而在 BBB 上只改变对角 α\alphaαβ\betaβ 并且保持其“几乎双对角”的结构(中间会有短时’bulge’,会被追赶下去,最终恢复双对角并完成一次带位移的 QR 步)。


C. 在 BBB 上做一次隐式位移 QR 的「操作级」说明(bulge-chasing;右旋/左旋交替)

下面给出一份常见实现(即 Golub–Kahan/Reinsch 风格)的操作级步骤与关键更新公式(对实现者友好)。

数据结构约定

  • 有数组 α[1 ⁣: ⁣n]\alpha[1\!:\!n]α[1:n] 表示主对角(nnn 个);β[1 ⁣: ⁣n−1]\beta[1\!:\!n-1]β[1:n1] 表示超对角;
  • 我们隐式维护 BBB 的上双对角结构;迭代过程中 βi\beta_iβi 会逐步变小以实现对角化(βi→0\beta_i\to 0βi0 表示问题分裂 / deflation)。

一次带位移的循环(高层伪代码)

while not converged:# (1) 处理可拆分点:若某 β_j 足够小 -> problem splits; 处理每个子块 separately# (2) 选择位移 μ(通常使用底部 1x1 或 2x2 子块的 Wilkinson shift)μ = choose_shift(alpha, beta)  # (3) 用 μ 在 B 上做隐式 QR 步(在 B 上做 Givens bulge-chase)# 初始化:构造用于开始 chase 的初始右旋 R_1compute initial (c,s) from (alpha[1]^2 - μ, alpha[1]*beta[1])apply right rotation R_1 to columns 1&2 of B  # 更新 alpha[1], beta[1], alpha[2] 并产生 bulgefor j = 1 .. n-1:# 消除由右旋产生的 bulge:用左旋 L_j 作用于行 j+1 和 j+2compute (cL,sL) to annihilate bulge; apply left rotation -> update alpha[j+1], beta[j], etc.# 接着右旋 R_{j+1} 作用于列 j+1 & j+2 以继续 chase bulgecompute (cR,sR) from current (alpha[j+1], beta[j+1], ...) ; apply right rotation -> update entries,产生下一个 bulgeendfor# 经过一次完整 chase,B 被转换到新的上双对角形式,相应地 alpha/beta 被更新
endwhile

关键代数:右旋与左旋对 α,β\alpha,\betaα,β 的更新(局部公式)

(下面只列出初始几步的清晰公式;一般步骤为这些公式的循环推广。实现时建议用 hypot / 稳定求旋转分量。)

右旋(作用于列 j 与列 j+1):设一次右旋参数 (c,s)(c,s)(c,s)(二维正交矩阵 [cs−sc]\begin{bmatrix} c & s\\ -s & c\end{bmatrix}[cssc]),作用只影响列 jjjj+1j+1j+1

  • 初始(旋转前)在相关行列位置的非零元素(局部)看作:

    • αj\alpha_jαj (出现在行 jjj, 列 jjj
    • βj\beta_jβj (出现在行 jjj, 列 j+1j+1j+1
    • αj+1\alpha_{j+1}αj+1(出现在行 j+1j+1j+1, 列 j+1j+1j+1
  • 右旋后局部更新(局部代数):

    αj′=c αj+s βj,βj′=−s αj+c βj,bulge g=s αj+1,αj+1′=c αj+1. \begin{aligned} \alpha_j' & = c\,\alpha_j + s\,\beta_j,\\ \beta_j' & = -s\,\alpha_j + c\,\beta_j,\\ \text{bulge } g & = s\,\alpha_{j+1},\\ \alpha_{j+1}' & = c\,\alpha_{j+1}. \end{aligned} αjβjbulge gαj+1=cαj+sβj,=sαj+cβj,=sαj+1,=cαj+1.

    右旋会在位置 (j+1,j)(j+1,j)(j+1,j) 生成一个“bulge”值 ggg(即在下三角出现一个短暂非零),破坏了双对角形式;接下来用左旋来消除该 bulge。

左旋(作用于行 j+1 与 j+2):左旋用来消除位置 (j+1,j)(j+1,j)(j+1,j) 的 bulge。假设要消掉的向量为 [g, αj+1′]⊤[g,\ \alpha_{j+1}']^\top[g, αj+1],选 (cL,sL)(c_L,s_L)(cL,sL) 使得

[cLsL−sLcL][gαj+1′]=[r0]. \begin{bmatrix} c_L & s_L\\ -s_L & c_L\end{bmatrix} \begin{bmatrix} g \\ \alpha_{j+1}' \end{bmatrix} = \begin{bmatrix} r \\ 0 \end{bmatrix}. [cLsLsLcL][gαj+1]=[r0].

左旋作用后会更新(示意):

  • 把 bulge 清零;
  • 更新 βj′\beta_j'βj(因为第 j 列与第 j+1 行的乘积受影响);
  • 产生可能的新 bulge(在下一位置),這個新 bulge 随后被下一个右旋处理。

注:上面右旋 / 左旋更新写法是局部的、示意性的;实现里每次 Givens 旋转都用 hypot(a,b) 稳定求 c,sc,sc,s,然后就按矩阵乘法在受影响的两个行/列上更新常数(常数个数目很少,复杂度 O(1) per rotation)。整个 chase 对长度 nnn 的双对角块需要 O(n) 次旋转来推进一个 bulge 到底部。

初始选择位移 μ(Wilkinson shift)

实际算法中常选取底部 1×1 或 2×2 子块的 Wilkinson shift(对对称三对角的经典选择),这是加速收敛且保留数值稳定性的经验/理论做法。

deflation 与结束条件

  • 如果某个 ∣βi∣|\beta_i|βi 足够小(比如与周围 α\alphaα 的量级相比低很多或低于机器精度阈值),就认为该位置已对角化(deflated),可以把问题分成左右两块分别处理(这显著加速实际收敛与复杂度)。
  • 结束条件一般是当所有 ∣βi∣<ε|\beta_i| < \varepsilonβi<ε(机器精度相关)时,αi\alpha_iαi 就是奇异值(对数值细节可再正号化为非负)。

如何得到奇异向量 U,VU,VU,V

  • 在 chase 的过程中同时累积所用的右旋会更新 VVV(列旋转对应 VVV 左乘/右乘的更新),累积左旋更新 UUU(行旋转对应 UUU)——这正是保持 A=UBV⊤A = U B V^\topA=UBV 的变换关系的方式。
  • 真实实现中通常不在每次旋转就去更新完整 U,VU,VU,V(那样代价 O(n^3)),而是记录旋转并在需要奇异向量时后向应用这些旋转以构造 U,VU,VU,V

D. 小例子(n=3 的“手算”式追踪一次初始 step,便于理解)

设初始上双对角 BBB 的参数为 α1,β1,α2,β2,α3\alpha_1,\beta_1,\alpha_2,\beta_2,\alpha_3α1,β1,α2,β2,α3。取某位移 μ\muμ。计算首个右旋(针对列 1&2):

  • 先形成向量 (α12−μ, α1β1)⊤\big(\alpha_1^2-\mu,\ \alpha_1\beta_1\big)^\top(α12μ, α1β1),用 Givens 得到 (c,s)(c,s)(c,s) 使得第二分量为 0(这与在 T=B⊤BT=B^\top BT=BB 上对第一列做 QR 等价)。

  • 右旋后更新(按上面公式):

    α1←cα1+sβ1,β1←−sα1+cβ1,bulge g=sα2,α2←cα2. \begin{aligned} \alpha_1 &\leftarrow c\alpha_1 + s\beta_1,\\ \beta_1 &\leftarrow -s\alpha_1 + c\beta_1,\\ \text{bulge } g &= s\alpha_2,\\ \alpha_2 &\leftarrow c\alpha_2. \end{aligned} α1β1bulge gα2cα1+sβ1,sα1+cβ1,=sα2,cα2.

  • g,α2g,\alpha_2g,α2 做左旋(求 cL,sLc_L,s_LcL,sL 使 [g,α2]⊤[g,\alpha_2]^\top[g,α2] 的第二分量被消掉),左旋会影响 β1\beta_1β1α2\alpha_2α2 并可能对 β2\beta_2β2 造成影响(产生下一级 bulge)——如此交替向下追赶直到到达底部。底部 bulge 消失后,一次完整的隐式位移 QR 步完成。

实现时不要把这些更新写成大量矩阵乘法(那样慢);正确的做法是对于每个 Givens 用 4–6 个标量更新式局部修改 α,β\alpha,\betaα,β(见上面的局部公式),这使每次旋转是 O(1) 操作,每次完整的 chase 是 O(n)。


E. 数值细节、稳定性与实践建议

  • 在构造 Givens 参数时用 hypot(a,b) 来获得 (c,s)(c,s)(c,s) 的稳定计算,避免直接做 a2+b2\sqrt{a^2+b^2}a2+b2 导致上溢/下溢。
  • 在操作中尽量避免显式形成 T=B⊤BT=B^\top BT=BB,通过在 BBB 上的旋转来实现等价的相似变换(这减少误差倍增)。
  • 在实现中要检测并做 deflation(∣βi∣<ϵ( ∣αi∣+∣αi+1∣  )|\beta_i| < \epsilon(\,|\alpha_i|+|\alpha_{i+1}|\;)βi<ϵ(αi+αi+1)),这样把问题切分成更小子问题并节省计算量。
  • 对于求奇异值谱(而非全部奇异向量),可以只运行求值分支(不累积 U,VU,VU,V),这样更节省内存与时间。
  • 大型 dense SVD 的高效实现一般使用分治法(divide-and-conquer,LAPACK gesdd)或 dqds / bidiag-SVD 的改良版本;隐式 QR(Golub–Kahan)在很多实现里仍用于较小块或精细控制数值稳定性。

小结 / 要点回顾

  • Golub–Kahan + 隐式 QR:数值上 SVD 实现分为两阶段(Householder bidiagonalization + 对 bidiagonal B 的迭代求 SVD)。后者通过在 BBB 上做交替的右/左 Givens 旋转(bulge-chasing),隐式等价于对 T=B⊤BT=B^\top BT=BB 做对称 QR 且数值更稳定。实现关键在于局部旋转的稳定计算、恰当选择位移(Wilkinson)、及时的 deflation,以及累积旋转(如果需要奇异向量)。

http://www.dtcms.com/a/460982.html

相关文章:

  • QT MVC中Model的特点及使用注意事项
  • wordpress最快仿站宁波网络营销服务
  • 徕卡RTC360助力铝单板设计效率提升
  • EasyExcel 读取 Excel 文件指南
  • LabVIEW光栅旋转式光谱仪
  • 上海营销网站设计去设计公司还是去企业
  • 怎么查询自己注册的商标东营网站建设课程定位优化
  • 【rabbitmq 高级特性】RabbitMQ 延迟队列全面解析
  • linux学习笔记(22)线程同步——线程信号量
  • 如何用营销自动化提升开信率与转化率
  • 人形机器人安全研究
  • 比斯特自动化|为什么焊接18650电池离不开点焊机?
  • 多字节串口收发IP设计(二)串口通信扫盲
  • 人工智能基础知识笔记十七:微调方法
  • 北京企业免费建站农八师建设兵团社保网站
  • 《强化学习数学原理》学习笔记11——阶段策略迭代算法
  • Qt QtConcurrent使用入门浅解
  • C语言字符串与内存操作函数完全指南
  • 【第五章:计算机视觉-项目实战之生成式算法实战:扩散模型】2.CV黑科技:生成式算法理论-(5)Stable Diffusion模型讲解
  • Cookie和Seeion在客户端和服务端的角色作用
  • Linux 远程Ubuntu服务器本地部署大模型 EmoLLM 中常见的问题及解决方案 万字详解
  • 如何建设公司网站信息灯塔网站seo
  • Java 中 `equals()`、`==` 和 `hashCode()` 的区别
  • 成像系统(十四-1:《工业级ISP流水线:ISP前端处理 - 从原始数据到可用图像》):从LED冬奥会、奥运会及春晚等大屏,到手机小屏,快来挖一挖里面都有什么
  • vue-router(vue 路由)基本使用指南(二)
  • 深入理解 Java中的 异常和泛型(指南十二)
  • 草莓植物(plant)【高精度-->array高级!!!】
  • 3D 图表、堆叠饼图为什么是灾难?
  • Nacos 全解析:从注册中心到配置管理的实战指南
  • 微信小程序开发从零基础到项目发布的全流程实战教程(四)