利用 Lanczos 方法实现张量的 HOSVD 分解

1. 特征值分解(EVD)

如果 A A A 是一个 m × m m\times m m×m实对称矩阵 A = A T A=A^T A=AT) ,如果存在 m m m 维列向量 q q q 和实数 λ \lambda λ 满足 A q = λ q Aq=\lambda q Aq=λq,则称 q q q A A A特征向量 λ \lambda λ A A A特征值

如果我们求出 A A A m m m 个特征值与特征向量,并将所有特征向量标准化,则可以得到标准正交矩阵 Q = [ q 1 , q 2 , ⋯   , q m ] , Q ∈ R m × m Q=[q_1, q_2, \cdots, q_m], Q\in \mathbb{R}^{m\times m} Q=[q1,q2,,qm],QRm×m,与对角矩阵 Σ = d i a g [ λ 1 , λ 2 , ⋯   , λ m ] \Sigma = diag[\lambda_1, \lambda_2, \cdots, \lambda_m] Σ=diag[λ1,λ2,,λm],他们满足如下形式:
A = Q Σ Q T = Q [ λ 1 ⋯ ⋯ ⋯ ⋯ λ 2 ⋯ ⋯ ⋯ ⋯ ⋱ ⋯ ⋯ ⋯ ⋯ λ m ] Q T A = Q\Sigma Q^T= Q\left[ \begin{matrix} \lambda_1 & \cdots & \cdots & \cdots\\ \cdots & \lambda_2 & \cdots & \cdots\\ \cdots & \cdots & \ddots & \cdots\\ \cdots & \cdots & \cdots & \lambda_m\\ \end{matrix} \right]Q^T A=QΣQT=Qλ1λ2λmQT

numpy 中对一个矩阵进行特征值分解使用 np.linalg.eig 函数,从下例可以看出,该函数求解得到的特征值大小是随机排列的,如果需要前 n n n 个大的特征值与特征向量,需要进一步进行处理:

#创建一个对称矩阵
sym_matrix = np.array([[1,2,3,4],
                      [2,5,6,7],
                      [3,6,8,9],
                      [4,7,9,10]])
#对矩阵求解特征值(se)与特征向量(q)
se, q = np.linalg.eig(sym_matrix)    
print('se:')
print(se)
print('q:')
print(q)
"""
se:
[24.06253512 -0.80548492  0.5580362   0.18491359]
q:
[[-0.22593827 -0.72531367 -0.56047033 -0.32976505]
 [-0.44322186 -0.31846973  0.77633831 -0.3153256 ]
 [-0.57278788 -0.14246073 -0.05844028  0.805111  ]
 [-0.6514755   0.59346614 -0.28241204 -0.37897369]]
"""

在特征值分解中,对要分解的矩阵有着较高的要求,它需要被分解的矩阵 A A A 为实对称矩阵,但是现实中我们遇到的矩阵并不都是实对称的,对于一个 m × n m\times n m×n 的矩阵,如果我们想分解为如上的形式,我们需要使用 SVD分解。

2. 奇异值分解(SVD)

对于一个 m × n m\times n m×n 的实数矩阵 A A A,我们定义其奇异值分解(SVD)的形式为:
A = U Σ V T A=U\Sigma V^T A=UΣVT

其中 U ∈ R m × m U\in \mathbb{R}^{m\times m} URm×m V ∈ R n × n V\in \mathbb{R}^{n\times n} VRn×n 为单位正交矩阵,即有 U U T = I UU^T=I UUT=I V V T = I VV^T=I VVT=I U U U 为左奇异矩阵, V V V 为右奇异矩阵, Σ ∈ R m × n \Sigma \in \mathbb{R}^{m\times n} ΣRm×n 仅在主对角线上有值,我们称它们为奇异值。分解示意图为:
在这里插入图片描述

奇异值分解的求解通过下式:
A A T = U Σ V T V Σ T U T = U Σ Σ T U T AA^T =U\Sigma V^TV\Sigma^TU^T =U\Sigma \Sigma^TU^T AAT=UΣVTVΣTUT=UΣΣTUT

A T A = V Σ T U T U Σ V T = V Σ T Σ V T A^TA=V\Sigma^TU^TU\Sigma V^T=V\Sigma^T\Sigma V^T ATA=VΣTUTUΣVT=VΣTΣVT

因为 A A T AA^T AAT A A T AA^T AAT 是对称矩阵,则通过对上面两个等式求它们的特征值和特征向量,就可以求出 U , V , Σ U,V,\Sigma U,V,Σ

我们可以使用 numpy 中的 np.linalg.svd 函数对矩阵求解 SVD :

#创建一个5×3的矩阵
T = np.array([[16,25,35],
              [45,23,6],
              [7,12,9],
              [10,18,12],
              [15,14,15]])
#进行SVD分解      
u,ss,vh = np.linalg.svd(T, full_matrices=False)

print('u:')
print(u)

print('ss:')
print(ss)

print('vh')
print(vh)

#输出 u * ss * vh
print('u*ss*vh:')
print(u.dot(np.diag(ss)).dot(vh))
"""
u:
[[-0.57781685 -0.62450998  0.36719022]
 [-0.63112018  0.74837707  0.09682015]
 [-0.21931497 -0.12213601 -0.43502282]
 [-0.31447256 -0.15727956 -0.7906354 ]
 [-0.34759596 -0.10131625  0.20358785]]
ss:
[72.50580717 29.74834802  6.47639687]
vh
[[-0.65566262 -0.58091643 -0.48233041]
 [ 0.66347606 -0.13833268 -0.73529829]
 [ 0.3604248  -0.80212229  0.47612372]]
u*ss*vh:
[[16. 25. 35.]
 [45. 23.  6.]
 [ 7. 12.  9.]
 [10. 18. 12.]
 [15. 14. 15.]]
"""

3. QR 分解

一个矩阵 A ∈ R m × n ( m ≤ n ) A\in \mathbb{R}^{m\times n}(m \leq n) ARm×n(mn) 可以被分解为 A = Q R A=QR A=QR 的形式,其中:

  • Q ∈ R m × m Q\in \mathbb{R}^{m\times m} QRm×m 是一个正交矩阵,即 Q T Q = Q Q T = I Q^TQ=QQ^T=I QTQ=QQT=I
  • R = [ R ^ 0 ] ∈ R m × n R=\left[\begin{matrix} \hat{R} \\ 0 \end{matrix}\right] \in \mathbb{R}^{m\times n} R=[R^0]Rm×n R ^ ∈ R m × m \hat{R} \in \mathbb{R}^{m\times m} R^Rm×m是上三角矩阵

numpy 中,进行 QR 分解使用 np.linalg.qr 函数:

A = np.array([[16,25,35],
              [45,23,6],
              [7,12,9],
              [10,18,12],
              [15,14,15]])
q,r = np.linalg.qr(A)
print('q:')
print(q)

print('r:')
print(r)

print('q*r')
print(q.dot(r)) 
"""
q:
[[-0.31051867  0.63947628  0.59444254]
 [-0.87333376 -0.44331977 -0.09225387]
 [-0.13585192  0.33011618 -0.35331103]
 [-0.19407417  0.51220924 -0.66985902]
 [-0.29111125  0.15232425  0.25414072]]
r:
[[-51.52669211 -37.04875904 -24.02638224]
 [  0.          21.10425203  31.12417123]
 [  0.           0.          12.84596908]]
q*r
[[16. 25. 35.]
 [45. 23.  6.]
 [ 7. 12.  9.]
 [10. 18. 12.]
 [15. 14. 15.]]
"""

4. Lanczos 方法

Lanczos 方法是求解大规模稀疏矩阵特征值问题最常用的方法之一,其主要思想是将对称矩阵三对角化,通过对三对角矩阵进行特征分解,从而得到原对称矩阵的特征值与特征向量。

由于三对角矩阵是稀疏矩阵,因此对其进行特征值求解的时间复杂度相对是很低的。

4.1 Lanczos 方法思路

设矩阵 A ∈ R n × n A \in \mathbb{R}^{n\times n} ARn×n,如果 A = A T A=A^T A=AT,那么一定存在 正交矩阵 Q n Q_n Qn ,使得 T = Q n T A Q n \boldsymbol{T=Q_n^TAQ_n} T=QnTAQn,其中 T T T 是对称三对角矩阵。

可以将以上分解中的 Q Q Q 写为:
Q = [ q 1 , q 2 , ⋯   , q n ] Q=[q_1, q_2,\cdots,q_n] Q=[q1,q2,,qn]

其中 q i q_i qi Q Q Q 的列向量。

T T T 记为:
T = [ α 1 β 1 0 0 0 0 ⋯ 0 0 β 1 α 2 β 2 0 0 0 ⋯ 0 0 0 β 2 α 3 β 3 0 0 ⋯ 0 0 0 0 β 3 α 4 β 4 0 ⋯ 0 0 0 0 0 β 4 α 5 β 5 ⋯ 0 0 ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋱ ⋮ ⋮ 0 0 0 0 0 0 ⋯ α n − 1 β n − 1 0 0 0 0 0 0 ⋯ β n − 1 α n ] T= \left[ \begin{matrix} \alpha_1 & \beta_1 & 0 & 0 & 0& 0& \cdots & 0 & 0\\ \beta_1 & \alpha_2 & \beta_2 & 0 & 0& 0& \cdots & 0 & 0\\ 0 & \beta_2 &\alpha_3 &\beta_3 & 0& 0 & \cdots & 0 & 0\\ 0 & 0 & \beta_3 &\alpha_4 &\beta_4 & 0& \cdots & 0 & 0\\ 0 & 0 & 0 & \beta_4 &\alpha_5 &\beta_5 & \cdots & 0 & 0\\ \vdots & \vdots &\vdots &\vdots &\vdots &\vdots &\ddots &\vdots &\vdots\\ 0 & 0 & 0 & 0 & 0 & 0 & \cdots & \alpha_{n-1} & \beta_{n-1}\\ 0 & 0 & 0 & 0 & 0 & 0 & \cdots & \beta_{n-1} & \alpha_n \end{matrix} \right] T=α1β100000β1α2β200000β2α3β300000β3α4β400000β4α5000000β50000000αn1βn100000βn1αn

从上面我们可以知道,对于一个矩阵 A A A ,我们如果想要求其三对角矩阵,要求的是 T T T 中的 α 、 β \alpha、\beta αβ 参数,以及 Q Q Q 矩阵,因此通过如下的变形,我们求其中的变量。

由于 Q Q Q 是正交的,我们可以将求解三对角矩阵的式子写为:
A Q = Q T AQ=QT AQ=QT

对左边的式子,我们取 Q Q Q 的第一列与 A A A 作乘积,得到左边结果的第一列为 A q 1 Aq_1 Aq1。同时我们取右式 T T T 的第一列与 Q Q Q 作乘积,得到 α 1 q 1 + β 1 q 2 \alpha_1q_1 + \beta_1q_2 α1q1+β1q2 ,即
A q 1 = α 1 q 1 + β 1 q 2 Aq_1=\alpha_1q_1 + \beta_1q_2 Aq1=α1q1+β1q2

同理,有:
A q 2 = β 1 q 1 + α 2 q 2 + β 2 q 3 Aq_2 = \beta_1q_1 + \alpha_2q_2 + \beta_2q_3 Aq2=β1q1+α2q2+β2q3

A q 3 = β 2 q 2 + α 3 q 3 + β 3 q 4 Aq_3 = \beta_2q_2 + \alpha_3q_3 + \beta_3q_4 Aq3=β2q2+α3q3+β3q4

由此可以得出:
A q i = β i − 1 q i − 1 + α i q i + β i q i + 1 , i = 1 , 2 , 3 , ⋯   , n Aq_i = \beta_{i-1}q_{i-1} + \alpha_iq_i + \beta_iq_{i+1},i=1,2,3,\cdots,n Aqi=βi1qi1+αiqi+βiqi+1i=1,2,3,,n

由于 β 0 , β n , q 0 , q n + 1 \beta_0, \beta_n, q_0, q_{n+1} β0,βn,q0,qn+1 都是不存在的,所以我们令 β 0 q 0 = β n q n + 1 = 0 \beta_0q_0 = \beta_nq_{n+1} = 0 β0q0=βnqn+1=0

我们将上式两边同时左乘以 q i T q_i^T qiT,由于 Q Q Q 是正交的,所以其列向量互相正交,且 q i T q i = 1 q_i^Tq_i=1 qiTqi=1,我们可以得到:
q i T A q i = α i q_i^T A q_i = \alpha_i qiTAqi=αi

通过上式可以看出,如果我们知道了 q i q_i qi ,就能求出 α i \alpha_i αi,这里就是求解 α \boldsymbol{\alpha} α 的方法。

我们再对等式两边移项可以得到:
β i q i + 1 = A q i − β i − 1 q i − 1 − α i q i \beta_i q_{i+1} = Aq_i - \beta_{i-1}q_{i-1} - \alpha_iq_i βiqi+1=Aqiβi1qi1αiqi

上式左侧是一个向量,由于 Q Q Q 是正交矩阵,所以 q i + 1 q_{i+1} qi+1 是一个归一化的单位向量,我们令
r i = β i q i + 1 = A q i − β i − 1 q i − 1 − α i q i r_i=\beta_i q_{i+1} = Aq_i - \beta_{i-1}q_{i-1} - \alpha_iq_i ri=βiqi+1=Aqiβi1qi1αiqi

β i = ∥ β i q i + 1 ∥ 2 \beta_i = \|\beta_i q_{i+1}\|_2 βi=βiqi+12 ,即

β i = ∥ r i ∥ 2 = ∥ β i q i + 1 ∥ 2 = ∥ A q i − β i − 1 q i − 1 − α i q i ∥ 2 \beta_i = \|r_i\|_2=\|\beta_i q_{i+1}\|_2 = \|Aq_i - \beta_{i-1}q_{i-1} - \alpha_iq_i\|_2 βi=ri2=βiqi+12=Aqiβi1qi1αiqi2

从上式可以看出,如果我们知道了 α i 、 q i 、 β i − 1 、 q i − 1 \alpha_i、q_i、\beta_{i-1}、q_{i-1} αiqiβi1qi1 就能求出 β i \beta_i βi,又因为 q q q 都是单位向量,所以我们还能通过 ∥ β i q i + 1 ∥ 2 \|\beta_i q_{i+1}\|_2 βiqi+12求出 q i + 1 q_{i+1} qi+1,这样就能循环求解了。

我们从初始条件看,如果我们知道了 q 1 q_1 q1 的值,就能根据上面求 α \boldsymbol{\alpha} α 的方法求出 α 1 \alpha_1 α1,因为我们假设 β 0 q 0 = 0 \beta_0q_0=0 β0q0=0,所以我们就能通过 β 0 q 0 、 α 1 、 q 1 \beta_0q_0、\alpha_1、q_1 β0q0α1q1 求出 β 1 \beta_1 β1,再通过令 q i + 1 = r i ∥ r i ∥ 2 q_{i+1}=\frac{r_i}{\|r_i\|_2} qi+1=ri2ri,这时 q i + 1 q_{i+1} qi+1 就是一个单位向量,我们就得到了下一轮循环的 q q q。因此所有的重点就在 q 1 q_1 q1 ,在实际求解中,我们可以随机初始化一个单位向量作为 q 1 q_1 q1,由此我们可以得到计算 A A A 的三对角矩阵的流程:

  1. 随机初始化一个单位向量 q 1 q_1 q1
  2. 计算 α 1 = q 1 T A q 1 \alpha_1=q_1^TAq_1 α1=q1TAq1
  3. r 1 = A q 1 − α 1 q 1 − β 0 q 0 r_1 = Aq_1-\alpha_1q_1-\beta_0q_0 r1=Aq1α1q1β0q0
  4. β 1 = ∥ r 1 ∥ 2 \beta_1 = \|r_1\|_2 β1=r12
  5. q 2 = r 1 β 1 q_2=\frac{r_1}{\beta_1} q2=β1r1
  6. 重复以上步骤,依次求出 { q 1 , q 2 , ⋯   , q n } \{q_1,q_2,\cdots,q_n\} {q1,q2,,qn} α 1 , β 1 , α 2 , β 2 , ⋯   , α n \alpha_1, \beta_1, \alpha_2, \beta_2, \cdots, \alpha_n α1,β1,α2,β2,,αn

此即 Lanczos 迭代,其中 q i q_i qi 为 Lanczos 向量,若其中某一步 β i = 0 \beta_i=0 βi=0 ,则此时得到的 T j T_j Tj 的特征值都将是 A A A 的特征值。

到这里,我们就得到了 T = Q T A Q T=Q^TAQ T=QTAQ,如果此时对 T T T 进行特征分解得到 T = W S W T T=WSW^T T=WSWT,所以有
A = ( Q W ) S ( W T Q T ) A=(QW)S(W^TQ^T) A=(QW)S(WTQT)

我们得到了通过将矩阵 A A A 变换为三对角矩阵,从而求解特征值与特征向量的方法。将矩阵转换为三对角矩阵的 python 实现为:

#生成一个对称矩阵
sym_matrix = np.array([[1,2,3,4],
                      [2,5,6,7],
                      [3,6,8,9],
                      [4,7,9,10]])
Q = []
A = []
B = []
sum_dim = sym_matrix.shape[0]
    
#随机初始化q1
q1 = np.random.random((sum_dim,1))
q1 = q1/np.linalg.norm(q1)
Q.append(q1)

#计算a0
a0 = (q1.transpose()[0]).dot(sym_matrix).dot(q1)[0]
A.append(a0)

#计算r0
r = sym_matrix.dot(q1) - a0*q1

#计算b0
b0 = np.linalg.norm(r)
B.append(b0)

#循环迭代,得到A、B和Q
for i in range(1,sum_dim):
    qi = r/B[i-1]
    Q.append(qi)

    ai = qi.transpose()[0].dot(sym_matrix).dot(qi)[0]
    A.append(ai)

    r = sym_matrix.dot(qi) - ai*qi - B[i-1]*Q[i-1]
    if i < sum_dim - 1:
        b_next = np.linalg.norm(r)
        B.append(b_next)

#组成三对角矩阵
L = np.diag(A) + np.diag(B,1) + np.diag(B,-1)

print(L)
"""
[[10.99996429  6.7727395   0.          0.          0.        ]
 [ 6.7727395  11.4584147   5.03926679  0.          0.        ]
 [ 0.          5.03926679 -6.36314172  4.98605503  0.        ]
 [ 0.          0.          4.98605503  1.00512957  1.8902924 ]
 [ 0.          0.          0.          1.8902924   0.89963316]]
"""

4.2 三对角矩阵的特征值分解

三对角化后的矩阵 T T T 有三种常用的方法进行特征分解:

  1. QR 法,即对 T T T 进行 QR 分解,令 T = Q R T=QR T=QR,再令 T ′ = R Q T'=RQ T=RQ,如此反复,直至收敛。其中产生的 Q Q Q 矩阵的连乘得到的结果就是 T T T 的特征矩阵。
  2. 分治法。这个方法将 T T T 划均匀分成两块三对角阵和一个秩为 1 的 2 × 2 2\times 2 2×2 的块状方阵的和。分别对两个三对角阵分解,然后合并。合并时对特征向量作秩1的修正。
  3. MRRR 方法。这个方法理论上是最快的方式,复杂度为 O ( l 2 ) O(l^2) O(l2),主要采用逆迭代来加快收敛。

4.3 利用 QR 算法求解特征值

给定一个实对称矩阵 X X X,假设其通过特征值分解得到 X = P S P T X=PSP^T X=PSPT,其中 P P P 为正交阵, S S S 是对角阵,利用 QR 算法求解其特征值分解的算法为:

X 1 = X X_1=X X1=X
P = E P=E P=E
f o r   k = 1 , 2 , ⋯ for \ k=1,2,\cdots for k=1,2,
X k = Q k × R k \quad X_k=Q_k\times R_k Xk=Qk×Rk
X k + 1 = R k × Q k \quad X_{k+1}=R_k\times Q_k Xk+1=Rk×Qk
P = P × Q k \quad P=P\times Q_k P=P×Qk

这个算法很简单,每次迭代只需要做一次 QR 分解和一个矩阵乘法即可,用 python 实现为:

#创建对称矩阵
sym_matrix = np.array([[1,2,3,4],
                      [2,5,6,7],
                      [3,6,8,9],
                      [4,7,9,10]])
dim = sym_matrix.shape
#初始化P为单位矩阵
P = np.eye(dim[0])
X_n = sym_matrix
i = 1
while i<20:   #迭代次数可以根据需要改变
    i += 1
    (Q, R) = np.linalg.qr(X_n)  #QR分解
    X_n = R.dot(Q)
    P = P.dot(Q)

print("QR分解求解特征矩阵")
print(P)

se, q = np.linalg.eig(sym_matrix)
print("特征值函数求解特征矩阵:")
print(q)

"""
QR分解求解特征矩阵
[[-0.22593827 -0.72442125 -0.56162332 -0.32976505]
 [-0.44322186 -0.31970419  0.77583077 -0.3153256 ]
 [-0.57278788 -0.1423676  -0.05866681  0.805111  ]
 [-0.6514755   0.5939146  -0.28146771 -0.37897369]]
特征值函数求解特征矩阵:
[[-0.22593827 -0.72531367 -0.56047033 -0.32976505]
 [-0.44322186 -0.31846973  0.77633831 -0.3153256 ]
 [-0.57278788 -0.14246073 -0.05844028  0.805111  ]
 [-0.6514755   0.59346614 -0.28241204 -0.37897369]]
"""
  • 6
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值