1. 程式人生 > >SVD(奇異值分解)小結

SVD(奇異值分解)小結

注:奇異值分解在資料降維中有較多的應用,這是把它的原理簡單總結一下,並個圖片壓縮的例子,最後做一個簡單的分析,希望能夠給大家帶來幫助。

1、特徵值分解(EVD)

實對稱矩陣

在理角奇異值分解之前,需要先回顧一下特徵值分解,如果矩陣\(A\)是一個\(m\times m\)實對稱矩陣(即\(A = A^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 \tag{1-1} \]


其中\(Q\)為標準正交陣,即有\(QQ^T = I\)\(\Sigma\)為對角矩陣,且上面的矩陣的維度均為\(m\times m\)\(\lambda_i\)稱為特徵值\(q_i\)\(Q\)(特徵矩陣)中的列向量,稱為特徵向量

注:\(I\)在這裡表示單位陣,有時候也用\(E\)表示單位陣。式(1-1)的具體求解過程就不多敘述了,可以回憶一下大學時的線性代數。簡單地有如下關係:\(Aq_i = \lambda_i q_i, \quad q_i q_j^T = 1(i \ne j)\)

一般矩陣

上面的特徵值分解,對矩陣有著較高的要求,它需要被分解的矩陣\(A\)

為實對稱矩陣,但是現實中,我們所遇到的問題都不是實對稱矩陣。那麼當我們碰到一般性的矩陣,即有一個\(m \times n\)的矩陣\(A\),它是否能被分解成上面的式(1-1)的形式呢?當然是可以的,這就是我們下面要討論的內容。

2、奇異值分解(SVD)

2.1 奇異值分解定義

有一個\(m \times n\)的實數矩陣\(A\),我們想要把它分解成如下的形式

\[ A = U\Sigma V^T \tag{2-1} \]

其中\(U\)\(V\)均為單位正交陣,即有\(UU^T=I\)\(VV^T=I\)\(U\)稱為左奇異矩陣\(V\)稱為右奇異矩陣\(\Sigma\)

僅在主對角線上有值,我們稱它為奇異值,其它元素均為0。上面矩陣的維度分別為\(U \in R^{m\times m},\ \Sigma \in R^{m\times n},\ V \in R^{n\times n}\)

一般地\(\Sigma\)有如下形式
\[ \Sigma = \left[ \begin{matrix} \sigma_1 & 0 & 0 & 0 & 0\\ 0 & \sigma_2 & 0 & 0 & 0\\ 0 & 0 & \ddots & 0 & 0\\ 0 & 0 & 0 & \ddots & 0\\ \end{matrix} \right]_{m\times n} \]

fig1-2
圖1-1 奇異值分解

對於奇異值分解,我們可以利用上面的圖形象表示,圖中方塊的顏色表示值的大小,顏色越深,值越大。對於奇異值矩陣\(\Sigma\),只有其主對角線有奇異值,其餘均為0。

2.2 奇異值求解

正常求上面的\(U,V,\Sigma\)不便於求,我們可以利用如下性質

\[ AA^T=U\Sigma V^TV\Sigma^TU^T=U\Sigma \Sigma^TU^T \tag{2-2} \]
\[ A^TA=V\Sigma^TU^TU\Sigma V^T=V\Sigma^T\Sigma V^T \tag{2-3} \]

注:需要指出的是,這裡\(\Sigma\Sigma^T\)\(\Sigma^T\Sigma\)在矩陣的角度上來講,它們是不相等的,因為它們的維數不同\(\Sigma\Sigma^T \in R^{m \times m}\),而\(\Sigma^T\Sigma \in R^{n \times n}\),但是它們在主對角線的奇異值是相等的,即有
\[ \Sigma\Sigma^T = \left[ \begin{matrix} \sigma_1^2 & 0 & 0 & 0\\ 0 & \sigma_2^2 & 0 & 0\\ 0 & 0 & \ddots & 0 \\ 0 & 0 & 0 & \ddots \\ \end{matrix} \right]_{m\times m}\quad \Sigma^T\Sigma = \left[ \begin{matrix} \sigma_1^2 & 0 & 0 & 0\\ 0 & \sigma_2^2 & 0 & 0\\ 0 & 0 & \ddots & 0\\ 0 & 0 & 0 & \ddots\\ \end{matrix} \right]_{n\times n} \]

可以看到式(2-2)與式(1-1)的形式非常相同,進一步分析,我們可以發現\(AA^T\)\(A^TA\)也是對稱矩陣,那麼可以利用式(1-1),做特徵值分解。利用式(2-2)特徵值分解,得到的特徵矩陣即為\(U\);利用式(2-3)特徵值分解,得到的特徵矩陣即為\(V\);對\(\Sigma\Sigma^T\)\(\Sigma^T\Sigma\)中的特徵值開方,可以得到所有的奇異值。

3、奇異值分解應用

3.1 純數學例子

假設我們現在有矩陣\(A\),需要對其做奇異值分解,已知

\[ A = \left[ \begin{matrix} 1 & 5 & 7 & 6 & 1 \cr 2 & 1 & {10} & 4 & 4 \cr 3 & 6 & 7 & 5 & 2 \cr \end{matrix} \right] \]

那麼可以求出\(AA^T\)\(A^TA\),如下

\[ AA^T = \left[ \begin{matrix} 112 & 105 & 114 \cr 105 & 137 & 110 \cr 114 & 110 & 123 \cr \end{matrix} \right] \quad A^TA = \left[ \begin{matrix} 14 & 25 & 48 & 29 & 15 \\ 25 & 62 & 87 & 64 & 21 \\ 48 & 87 & 198 & 117 & 61 \\ 29&64&117&77&32\\ 15&21&61&32&21 \end{matrix} \right] \]

分別對上面做特徵值分解,得到如下結果

U = 
[[-0.55572489, -0.72577856,  0.40548161],
 [-0.59283199,  0.00401031, -0.80531618],
 [-0.58285511,  0.68791671,  0.43249337]]

V = 
[[-0.18828164, -0.01844501,  0.73354812,  0.65257661,  0.06782815],
 [-0.37055755, -0.76254787,  0.27392013, -0.43299171, -0.17061957],
 [-0.74981208,  0.4369731 , -0.12258381, -0.05435401, -0.48119142],
 [-0.46504304, -0.27450785, -0.48996859,  0.39500307,  0.58837805],
 [-0.22080294,  0.38971845,  0.36301365, -0.47715843,  0.62334131]]

奇異值\(\Sigma = \text{Diag}(18.54, 1.83, 5.01)\)

3.2 在影象壓縮中的應用

準備工具

下面的程式碼執行環境為python3.6+jupyter5.4

SVD(Python)

這裡暫時用numpy自帶的svd函式做影象壓縮。

  1. 讀取圖片
%matplotlib inline
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np

img_eg = mpimg.imread("../img/beauty.jpg")
print(img_eg.shape)

圖片的大小是\(600\times 400 \times 3\)

  1. 奇異值分解
img_temp = img_eg.reshape(600, 400 * 3)
U,Sigma,VT = np.linalg.svd(img_temp)

我們先將圖片變成\(600\times 1200\),再做奇異值分解。從svd函式中得到的奇異值sigma它是從大到小排列的。

  1. 取前部分奇異值重構圖片
# 取前60個奇異值
sval_nums = 60
img_restruct1 = (U[:,0:sval_nums]).dot(np.diag(Sigma[0:sval_nums])).dot(VT[0:sval_nums,:])
img_restruct1 = img_restruct1.reshape(600,400,3)

# 取前120個奇異值
sval_nums = 120
img_restruct2 = (U[:,0:sval_nums]).dot(np.diag(Sigma[0:sval_nums])).dot(VT[0:sval_nums,:])
img_restruct2 = img_restruct2.reshape(600,400,3)

將圖片顯示出來看一下,對比下效果

fig, ax = plt.subplots(1,3,figsize = (24,32))

ax[0].imshow(img_eg)
ax[0].set(title = "src")
ax[1].imshow(img_restruct1.astype(np.uint8))
ax[1].set(title = "nums of sigma = 60")
ax[2].imshow(img_restruct2.astype(np.uint8))
ax[2].set(title = "nums of sigma = 120")
fig
圖3-1 奇異值分解

可以看到,當我們取到前面120個奇異值來重構圖片時,基本上已經看不出與原圖片有多大的差別。

注:上面的美女圖片源於網路,侵刪。

總結

從上面的圖片的壓縮結果中可以看出來,奇異值可以被看作成一個矩陣的代表值,或者說,奇異值能夠代表這個矩陣的資訊。當奇異值越大時,它代表的資訊越多。因此,我們取前面若干個最大的奇異值,就可以基本上還原出資料本身。

如下,可以作出奇異值數值變化和前部分奇異值和的曲線圖,如下圖所示


fig

奇異值變化圖

從上面的第1個圖,可以看出,奇異值下降是非常快的,因此可以只取前面幾個奇異值,便可基本表達出原矩陣的資訊。從第2個圖,可以看出,當取到前100個奇異值時,這100個奇異值的和已經佔總和的95%左右。

最後,還有一點需要提到的是,如果自己想不呼叫np.linalg.svd函式,手動實現奇異值分解的話,單純利用第2小節的內容實現,有點不夠,有個問題需要注意。這裡暫時不多做討論了,有時間再與大家分享一下如何自己實現SVD