SVD及c++实现

目录

前言

一 .特征值分解(EVD-eigen value decomposition)

定义

回顾

二  .奇异值分解(SVD-singular value decomposition)

定义

求解

三 例子和应用

e.g.

eigen代码实现

四 压缩比率 compress ration

拓展:PCA


前言

EVD分解要求 被分解矩阵  是实对称矩阵

SVD对被分解矩阵没有这个要求。

相当于一个从特殊到一般的过程。

一 .特征值分解(EVD-eigen value decomposition)

定义

在理角奇异值分解之前,需要先回顾一下特征值分解,如果矩阵A  是一个 m×m 的实对称矩阵(即\boldsymbol{A=A^T} ),那么它可以被分解成如下的形式

                                                          \boldsymbol{A=P\Lambda P^T} =\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 ) 

其中P是 标准正交 阵 (orthogonal) ,即$PP^T=I(E)$, \lambda _i 是特征值。

回顾

线性代数( liner algebra) 中,定义 如果  \boldsymbol{Ax}=\lambda \boldsymbol{ x } ,  那么\lambda就是特征值eigenvalue,\boldsymbol{x}是特征向量eigenvector。

其中  A 是n*n的实对称阵,\lambda 是数,\boldsymbol{x} 是n维列向量。

           e.g.                                \boldsymbol{Ax}=\begin{bmatrix} 0& 0 & 1\\ 0 &1 &0 \\ 1 &0 & 0 \end{bmatrix} \begin{bmatrix} -1\\ 0\\ 1 \end{bmatrix}= \begin{bmatrix} 1\\ 0\\ -1 \end{bmatrix}= (-1)\begin{bmatrix} -1\\ 0\\ 1 \end{bmatrix}= \lambda \boldsymbol{x}

then, 定义变形为    \left ( \lambda \boldsymbol{E-A} \right )\boldsymbol{x}=\boldsymbol{0}  ,  求此等式有非零解(\boldsymbol{x\neq 0 }) 的特征值

那么只能是行列式 ( determinant )  \left | \lambda \boldsymbol{ E -A} \right | =0,

求得eigenvalue后,把eigenvalue 带入A 求得eigenvector。

       


                                                                                                                                                                                  

二  .奇异值分解(SVD-singular value decomposition)

定义

有m rows  *  n  cols的实数矩阵 A,分解为 \boldsymbol{A=U\Sigma V}

其中 \boldsymbol{U}  \boldsymbol{V} 是左奇异和右奇异矩阵,  都是单位正交阵 : \boldsymbol{UU^T=I}   \boldsymbol{VV^T=I}

奇异值矩阵  \boldsymbol{\Sigma } 对角线上有值,称为奇异值,其它元素为0。形式如下:

                                                                    \boldsymbol{\Sigma }=\begin{bmatrix}\delta _1 & 0 &0 &0 &0 \\ 0& \delta _2 & 0& 0 &0 \\ 0&0 & \ddots &0 &0 \\ 0 & 0 & 0&\delta _m &0 \end{bmatrix}_{mn}

对于奇异值分解,我们可以利用下面的图形表示,图中方块的颜色表示值的大小,颜色越浅,值越大。对于奇异值矩阵\boldsymbol{\Lambda } ,只有其主对角线有奇异值,其余均为0。

                          

求解

利用如下性质即可求解,这就是SVD的关键所在

\boldsymbol{AA^T=U\Sigma V^T \quad V\Sigma^T U^T = U\Sigma \Sigma^TU^T}

\boldsymbol{A^TA=V\Sigma^T U^T \quad U\Sigma V^T= V\Sigma^T \Sigma V^T}

进一步,\boldsymbol{A^TA} 和 \boldsymbol{AA^T} 也是实对称矩阵,利用EVD求解  \boldsymbol{U \quad V}和 \boldsymbol{\Sigma^T \Sigma} 以及\boldsymbol{\Sigma\Sigma^T } 。注意 特征值最后要开方。

注意:         \boldsymbol{\Sigma \Sigma ^T } \in \boldsymbol{R}^{m \times m}            \boldsymbol{\Sigma ^T \Sigma } \in \boldsymbol{R}^{n \times n }     两者维数不同,但是对角线上的奇异值是相同的。

                  \boldsymbol{\Sigma \Sigma ^T }=\begin{bmatrix}\delta _1^2 & 0 &0 &0 \\ 0& \delta _2^2 & 0& 0 \\ 0&0 & \ddots &0 \\ 0 & 0 & 0& \ddots \end{bmatrix} _{m\times m }      \boldsymbol{ \Sigma ^T \Sigma}=\begin{bmatrix}\delta _1^2 & 0 &0 &0 \\ 0& \delta _2^2 & 0& 0 \\ 0&0 & \ddots &0 \\ 0 & 0 & 0& \ddots \end{bmatrix} _{n\times n }

三 例子和应用

e.g.

为了进一步说明具体的计算过程,笔者使用eigen库实现和验证了SVD,代码如下。

其中mat33 指的是上图的\boldsymbol{AA^T}   mat35指的是上图的\boldsymbol{A^TA}  mat35 指的是上图的\boldsymbol{A}

eigen代码实现

#include<iostream>
using namespace std;

#include<eigen3/Eigen/Core>
#include<eigen3/Eigen/Dense>
#include<eigen3/Eigen/SVD>

using namespace Eigen;
int main(){
 
  Eigen::Matrix3d mat33=Eigen::Matrix3d::Zero();
  //cout<<mat33<<endl;
  mat33<<112,105,114,105,137,110,114,110,123;
  
  for(int i=0;i<3;i++){
	  for(int j=0;j<3;j++)
	      cout<<mat33(i,j)<<" ";
	  cout<<endl;
  }
  
  Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> e_solver(mat33);
  cout<<"Eigen33 values:"<<endl<<e_solver.eigenvalues()<<endl;
  cout<<"Eigen33 vectors:"<<endl<<e_solver.eigenvectors()<<endl;

  MatrixXf mat35(3,5);
  mat35<< 1,5,7,6,1,2,1,10,4,4,3,6,7,5,2;
  JacobiSVD<MatrixXf> svd35(mat35,ComputeThinU | ComputeThinV);
  cout<<"svd35 values"<<endl<<svd35.singularValues()<<endl;
  cout<<"svd35 U"<<endl<<svd35.matrixU()<<endl;
  cout<<"svd35 V"<<endl<<svd35.matrixV()<<endl;

  //cout<<mat35<<endl;

  MatrixXf mat55(5,5);
  mat55=mat35.transpose()*mat35;
  cout<<mat55<<endl;
  SelfAdjointEigenSolver<MatrixXf> eslover55(mat55);
  cout<<"Eigen55 values"<<endl<<eslover55.eigenvalues()<<endl;
  cout<<"Eigen55 vectors:"<<endl<<eslover55.eigenvectors()<<endl;

  MatrixXf sigma(3,3);
  sigma(0,0)=1.83;
  sigma(1,1)=5.01;
  sigma(2,2)=18.54;
  cout<<sigma<<endl;
  cout<<(sigma.inverse())*(svd35.matrixU().transpose())*mat35<<endl;


  return 0;
  
}

完整工程传送门: https://download.csdn.net/download/bluenapa/11846085

使用EVD(特征值分解)的方法得

\boldsymbol{AA^T}奇异值的平方  \Sigma =diag(3.37,25.06,343.58)   从小 到大排列

对应的U是

0.725779      0.405482  0.555725

-0.00401031  -0.805316  0.592832

-0.687917     0.432493  0.582855

\boldsymbol{A^TA} 奇异值的平方 \Sigma =diag(-1.71e-05, -1.47e-06, 3.37,25.06,343.58)  前两项近似为0;

对应的V是

-0.652774    0          -0.73355   -0.0184451  0.188283
  
0.436243    -0.125973   -0.27392   -0.762547   0.370557
 
0.0661727   -0.476896   0.122583    0.436974   0.749812
 
-0.408706   0.54888     0.489968   -0.274509   0.465044
  
0.460606    0.674857    -0.363011   0.389718   0.220802

使用eigen封装的 SVD 方法得 \boldsymbol{A} 的奇异值(开方后)为 \Sigma =diag(18.5358,5.00566,1.83491)   从大到小排列

对应的 U是

-0.555725  -0.405482  -0.725779
 
-0.592832   0.805316 0.00401022
 
-0.582855  -0.432493   0.687917

对应的 V是 

-0.188282 -0.018445  0.733548

-0.370558 -0.762548   0.27392

-0.749812  0.436973 -0.122584

-0.465043 -0.274508 -0.489968

-0.220803  0.389719  0.363014

 注意:eigenvalue和eigenvector都是对应的,改变特征值的顺序时也要改变特征向量的顺序。

四 压缩比率 compress ration

选取k  个大奇异值以及这些对应的左右奇异向量逼近原图像,便可以共使用k(m+n+1)  个数值取代原来的m∗n 个图像数据。

所以压缩比率comprssion ratio为

                                                                 \rho =\frac{m*n}{k * \left ( m+n+1 \right )}

拓展:PCA

PCA可以说是SVD的一个拓展,对SVD的一个封装。

参考:https://blog.csdn.net/chenaiyanmie/article/details/80011244

https://www.cnblogs.com/endlesscoding/p/10033527.html

发布了128 篇原创文章 · 获赞 21 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/Bluenapa/article/details/102062606
SVD