奇异值分解(Singular Value Decomposition, SVD)是矩阵的一种分解方法,与特征值分解不同,它可以应用于长方矩阵中,并将其分解成三个特殊矩阵的乘积。此外SVD分解还具有许多优良的性质,在图像压缩,数据降维和推荐系统等算法中都具有广泛的应用。

奇异值分解的引入

我们考虑二维的情形,考虑一组二维空间上的单位正交向量 \(\boldsymbol{v}_1 ,
\boldsymbol{v}_2\) ,设任意一个变换矩阵 \(M \in \mathbb R ^ {m \times 2}\) ,对其作变换得到另外一组正交向量 \(M\boldsymbol{v}_1,
M\boldsymbol{v}_2\) ,容易知道变换后的正交向量仍然是该二维平面上的一组基底,可以对这组基底进行单位化得到 \(\boldsymbol{u}_1,
\boldsymbol{u}_2\),即单位化前后的向量存在伸缩关系:

\[\begin{cases}
\begin{aligned}
M\boldsymbol{v}_1 &= \sigma_1 \boldsymbol{u}_1 \\
M\boldsymbol{v}_2 &= \sigma_2 \boldsymbol{u}_2 \\
\end{aligned}
\end{cases}
\]

此外,对于该二维平面上的任意一个向量 \(\boldsymbol{x} \in \mathbb R^2\) ,可以在基底 \((\boldsymbol{v}_1, \boldsymbol{v}_2)\) 下线性表示为

\[\boldsymbol{x} =
(\boldsymbol{v}_1 \cdot \boldsymbol{x}) \boldsymbol{v}_1 +
(\boldsymbol{v}_2 \cdot \boldsymbol{x}) \boldsymbol{v}_2
\]

对该向量作上述线性变换,可以得到

\[\begin{aligned}
M\boldsymbol{x} &=
(\boldsymbol{v}_1 \cdot \boldsymbol{x}) M \boldsymbol{v}_1 +
(\boldsymbol{v}_2 \cdot \boldsymbol{x}) M \boldsymbol{v}_2 \\
&=
(\boldsymbol{v}_1 \cdot \boldsymbol{x}) \sigma_1 \boldsymbol{u}_1 +
(\boldsymbol{v}_2 \cdot \boldsymbol{x}) \sigma_2 \boldsymbol{u}_2 \\
&=
\boldsymbol{v}_1 ^ \text T \boldsymbol{x} \ \sigma_1 \boldsymbol{u}_1 +
\boldsymbol{v}_2 ^ \text T \boldsymbol{x}\ \sigma_2 \boldsymbol{u}_2 \\
&=
\boldsymbol{u}_1 \sigma_1 \boldsymbol{v}_1 ^ \text T \boldsymbol{x} +
\boldsymbol{u}_2 \sigma_2 \boldsymbol{v}_2 ^ \text T \boldsymbol{x} \\
&=
\begin{pmatrix}
\boldsymbol{u}_1 & \boldsymbol{u}_2
\end{pmatrix}
\begin{pmatrix}
\sigma_1 & \ \\
\ & \sigma_2 \\
\end{pmatrix}
\begin{pmatrix}
\boldsymbol{v}_1 ^ \text T \\ \boldsymbol{v}_2 ^ \text T \\
\end{pmatrix}
\boldsymbol{x}
\end{aligned}
\]

若定义 \(\boldsymbol{U} =
\begin{pmatrix}
\boldsymbol{u}_1 & \boldsymbol{u}_2
\end{pmatrix},
\mathbf \Sigma =
\begin{pmatrix}
\sigma_1 & 0 \\
0 & \sigma_2 \\
\end{pmatrix},
\boldsymbol{V} ^ \text T =
\begin{pmatrix}
\boldsymbol{v}_1 ^ \text T \\ \boldsymbol{v}_2 ^ \text T \\
\end{pmatrix}\) ,则对于任一变换矩阵 \(M \in \mathbb R ^ {2 \times 2}\) ,都可以分解成如下两组单位正交基底与对角矩阵的乘积的形式

\[M=\boldsymbol{U} \mathbf \Sigma \boldsymbol{V} ^ \text T
\]

一般的,对于任意变换矩阵 \(A \in \mathbb R ^{m \times n}\) ,都存在单位正交阵 \(\boldsymbol{U} \in \mathbb R ^ {m \times m},
\boldsymbol{V} \in \mathbb R ^ {n \times n}\),类对角矩阵 \(\mathbf \Sigma \in \mathbb R ^{m \times n}\) ,满足

\[A =
\boldsymbol{U} \mathbf \Sigma \boldsymbol{V} ^ \text T
\]

上式即为矩阵的奇异值分解,其中类对角矩阵 \(\mathbf \Sigma\) 中的非零对角元素称为矩阵 \(A\) 的奇异值,矩阵 \(U,V\) 分别叫做左奇异矩阵和右奇异矩阵(酉矩阵)

奇异值分解的计算

下面考虑如何获取一个长方矩阵的奇异值分解,并给出一个具体的奇异值分解算例。

对于矩阵 \(A \in \mathbb R ^ {m \times n}\) ,我们考察其方阵形式 \(A ^ \text T A\) 和 \(AA ^ \text T\) 。由于 \(A^\text T A\) 是 \(n \times n\) 的实对陈方阵,因此可以对其进行特征值分解。

\[A ^ \text T A = Q \Lambda Q ^ \text T
\]

同时,矩阵 \(A\) 存在奇异值分解,即

\[\begin{aligned}
A ^ \text T A &=
(\boldsymbol{U} \mathbf \Sigma \boldsymbol{V} ^ \text T) ^ \text T
\boldsymbol{U} \mathbf \Sigma \boldsymbol{V} ^ \text T \\
&=
V \Sigma ^ \text T U ^ \text T U \Sigma V ^ \text T \\
&=
V \Sigma ^ \text T \Sigma V ^ \text T \\
&=
V \Sigma ^ 2 V ^ \text T
\end{aligned}
\]

对比上面两式的结果

\[V = Q \\
\Sigma ^ 2 = \Lambda
\]

可以发现右奇异矩阵即为 \(A^ \text T A\) 的特征向量矩阵,而所谓的奇异值则为 \(A^\text T A\) 的特征值的算术平方根。

同理可以再考察 \(AA^\text T\) ,即

\[\begin{aligned}
AA^\text T &= (U\Sigma V^\text T)(U\Sigma V^\text T)^\text T \\
&=
U\Sigma V^\text T V \Sigma ^\text T U ^ \text T \\
&=
U \Sigma \Sigma ^ \text T U ^ \text T
\end{aligned}
\]

可以发现左奇异矩阵即为 \(AA^\text T\) 的特征向量矩阵。因此,要求解矩阵 \(A\) 的奇异值分解,只需分别计算 \(A^\text T A\) 和 \(AA^\text T\) 的特征值分解即可,下面通过一个具体的算例进一步说明。

(算例)计算矩阵 \(A =
\begin{pmatrix}
0 & 1 \\
1 & 1 \\
1 & 0 \\
\end{pmatrix}\)的 SVD 分解。


解:考察 \(A^\text T A\) 和 \(AA^\text T\) ,

\[A^\text T A=
\begin{pmatrix}
0 & 1 & 1 \\
1 & 1 & 0 \\
\end{pmatrix}
\begin{pmatrix}
0 & 1 \\
1 & 1 \\
1 & 0 \\
\end{pmatrix} =
\begin{pmatrix}
2 & 1 \\
1 & 2
\end{pmatrix} \\
\]
\[A A^\text T=
\begin{pmatrix}
0 & 1 \\
1 & 1 \\
1 & 0 \\
\end{pmatrix}
\begin{pmatrix}
0 & 1 & 1 \\
1 & 1 & 0 \\
\end{pmatrix} =
\begin{pmatrix}
1 & 1 & 0 \\
1 & 2 & 1 \\
0 & 1 & 1 \\
\end{pmatrix} \\
\]

作特征值分解并单位化特征向量

\[A^\text T A=
\begin{pmatrix}
\frac{1}{\sqrt 2} & \frac{1}{\sqrt 2} \\
\frac{-1}{\sqrt 2} & \frac{1}{\sqrt 2} \\
\end{pmatrix}
\begin{pmatrix}
3 & 0 \\
0 & 1 \\
\end{pmatrix}
\begin{pmatrix}
\frac{1}{\sqrt 2} & \frac{-1}{\sqrt 2} \\
\frac{1}{\sqrt 2} & \frac{1}{\sqrt 2} \\
\end{pmatrix} \\
\]
\[A A^ \text T=
\begin{pmatrix}
\frac{1}{\sqrt 6} & \frac{-1}{\sqrt 2} & \frac{1}{\sqrt 3} \\
\frac{2}{\sqrt 6} & 0 & \frac{-1}{\sqrt 3} \\
\frac{1}{\sqrt 6} & \frac{1}{\sqrt 2} & \frac{1}{\sqrt 3} \\
\end{pmatrix}
\begin{pmatrix}
3 & 0 & 0 \\
0 & 1 & 0 \\
0 & 0 & 0 \\
\end{pmatrix}
\begin{pmatrix}
\frac{1}{\sqrt 6} & \frac{2}{\sqrt 6} & \frac{1}{\sqrt 6} \\
\frac{-1}{\sqrt 2} & 0 & \frac{1}{\sqrt 2} \\
\frac{1}{\sqrt 3} & \frac{-1}{\sqrt 3} & \frac{1}{\sqrt 3} \\
\end{pmatrix}
\]

据此可以得到奇异值 \(\sigma_1 = \sqrt 3,
\sigma_2 = 1\) ,则SVD分解为

\[A =
\begin{pmatrix}
\frac{1}{\sqrt 6} & \frac{-1}{\sqrt 2} & \frac{1}{\sqrt 3} \\
\frac{2}{\sqrt 6} & 0 & \frac{-1}{\sqrt 3} \\
\frac{1}{\sqrt 6} & \frac{1}{\sqrt 2} & \frac{1}{\sqrt 3} \\
\end{pmatrix}
\begin{pmatrix}
\sqrt 3 & 0 \\
0 & 1 \\
0 & 0 \\
\end{pmatrix}
\begin{pmatrix}
\frac{1}{\sqrt 2} & \frac{-1}{\sqrt 2} \\
\frac{1}{\sqrt 2} & \frac{1}{\sqrt 2} \\
\end{pmatrix} \\
\]

需要注意的一点是,在求解奇异值或者特征值矩阵时,为了方便后续处理,我们一般将特征值或奇异值按大小降序排列,且特征向量一般都做归一化处理。

奇异值分解的几何意义

单位正交矩阵可以看作空间中的旋转矩阵,而对角矩阵则表示沿坐标轴方向上的伸缩变换,因此对于一个矩阵,也可以看作是一种线性变换,所谓的奇异值分解就是将这一变换分解成两次旋转变换和一次沿坐标轴的拉伸变换的过程,更直观的变换过程如下图所示:

奇异值分解的应用

奇异值分解在平面拟合,图像压缩和降噪,主成分分析和推荐系统等算法中都有广泛的应用,下面以直线拟合和图像压缩为例说明。

直线拟合问题

设直线的方程为 \(ax+by+c=0\) ,采集到一组点集 \((x_i, y_i)\) ,需要根据这组点集拟合直线方程。要求解这一问题,可以构建误差函数

\[e_i = ax_i + by_i +c
\]

当所有点的误差最小时,即认为拟合效果最好。这本质上是一个线性最小二乘问题,其数学形式可以表示为

\[\begin{aligned}
(a,b)^* &= \arg \min \sum_{i=0}^{N}{e_i}^2 \\
&= \arg \min \sum_{i=0}^{N}{(ax_i + by_i + c)^ 2}
\end{aligned}
\]

构造矩阵 \(A =
\begin{pmatrix}
x_0 & y_0 & 1 \\
x_1 & y_1 & 1 \\
\vdots & \vdots & \vdots \\
x_N & y_N & 1 \\
\end{pmatrix},
\boldsymbol{x} =
\begin{pmatrix}
a \\
b \\
c \\
\end{pmatrix}\) ,则可以将上述求解过程写成矩阵形式

\[\begin{aligned}
(a,b)^* &=
\arg \min (A\boldsymbol{x})^\text T(A\boldsymbol{x}) \\
&=
\arg \min \boldsymbol{x}^\text T (A^\text T A)\boldsymbol{x} \\
&=
\arg \min \boldsymbol{x} ^ \text T V \Sigma^2 V^\text T \boldsymbol{x}
\end{aligned}
\]

注意到 \(V^\text T \boldsymbol{x}\) 其实是向量 \(\boldsymbol{x}\) 在基底 \(V\) 下的一组坐标,可以记作 \(\bm \alpha\) ,即

\[V^\text T \boldsymbol{x} =
\begin{pmatrix}
\boldsymbol{v}_1^\text T \\
\boldsymbol{v}_2^\text T \\
\vdots \\
\boldsymbol{v}_N^\text T \\
\end{pmatrix}
\boldsymbol{x}
=
\begin{pmatrix}
\alpha_1 \\
\alpha_2 \\
\vdots \\
\alpha_N \\
\end{pmatrix} =
\bm{\alpha}
\]

则上式可以进一步写成

\[\begin{aligned}
\boldsymbol{x}^\text T V \Sigma^2 V^\text T \boldsymbol{x} &= \bm \alpha^\text T \Sigma^2 \bm \alpha \\
&=
\sigma_1^2 \alpha_1^2 +
\sigma_2^2 \alpha_2^2 +
\cdots +
\sigma_N^2 \alpha_N^2 \\
&\ge \sigma_N^2
\end{aligned}
\]

在考虑归一化的拟合解前提下,即 \(\bm{\left| x \right|} = 1\) 时,当且仅当坐标 \(\bm \alpha\) 取 \(\begin{pmatrix}
0 & 0 & \cdots & 1
\end{pmatrix}^\text T\) 时取等号,此时求解以下方程

\[\begin{pmatrix}
\boldsymbol{v}_1^\text T \\
\boldsymbol{v}_2^\text T \\
\vdots \\
\boldsymbol{v}_N^\text T \\
\end{pmatrix}
\boldsymbol x
=
\begin{pmatrix}
0 \\
0 \\
\vdots \\
1 \\
\end{pmatrix}
\]

容易得到,此时\(\boldsymbol x = \boldsymbol{v}_N\)。也就是说,要求解误差的最小值,只需要进行奇异值分解,取右奇异矩阵的最后一维作为解 \(\bm{x}\) 即可,此时对应的拟合误差即为 \(\sigma_N^2\) ,也就是在最小二乘意义下的最小误差。

下面通过一个直线拟合的编程实例来进一步说明上述结论。

(编程实例)考虑直线 \(x + 2y + 5 = 0\) ,给定一系列带有噪声的点集,根据这组点集拟合直线,并与真值对比,得到拟合参数的均方误差。

采用C++语言编写程序,调用Eigen线性代数库进行SVD分解,代码如下:

Eigen::Vector3d abc = Eigen::Vector3d(1, 2, 5).normalized();    // 直线参数真值
const double sigma = 0.6; // 噪声方差
const size_t count = 15; // 取样点的个数
// 利用 OpenCV 的随机数种子生成取样点
cv::RNG rng;
Eigen::MatrixXd A(count, 3);
for(size_t i=0; i<count; ++i) {
A.row(i) << i, -(abc[0]/abc[1])*i - (abc[2]/abc[1]) + rng.gaussian(sigma), 1;
}
// SVD求解, 并取出 V 矩阵的最后一维作为拟合解 x
Eigen::VectorXd x = Eigen::JacobiSVD<Eigen::MatrixXd>(A, Eigen::ComputeThinV).matrixV().col(2);
// 输出求解结果
cout << "==> true value: abc = " << abc.transpose() << endl; // 打印真值
cout << "==> svd solving result: x = " << x.transpose() << endl; // 打印拟合参数
cout << " ==> error RMS = " << sqrt( (A*x).squaredNorm() / double(count) ) << endl; // 打印均方误差

程序运行结果截图为:



注意SVD分解时考虑的是归一化的向量,因此得到的也是归一化后的拟合结果,与实际直线参数之间差了一个比例系数。

可以看到在噪声方差为0.6,取样点数为15个点时,得到的拟合结果的均方误差为0.2,拟合结果基本可以接受,在噪声方差更小的情况下,可以得到更可靠的拟合结果。

图像压缩问题

考虑一个 \(m \times n\) 的矩阵 \(A\) ,其奇异值分解式为

\[A=U_{m \times m}\Sigma_{m\times n} V_{n \times n}^\text T
\]

我们发现求得的奇异值衰减速度较快,前面几项的奇异值较大,而越往后的奇异值则越小,也就是说我们可以通过只保留前面几项奇异值来对 \(A\) 进行近似,这种做法可以压缩存储空间,在图像处理领域有着广泛的应用。具体做法是我们可以取出前 \(k\) 个奇异值,得到近似的 \(\tilde A\) ,其中 \(\frac{k}{\min\{m,n\}}\) 称为矩阵的压缩比。

\[A \approx \tilde A = U_{m \times k} \Sigma_{k \times k} V_{k \times n}^\text T
\]



(编程实例)给定一张图片(如下),考虑采用不同的压缩比对其进行压缩,并对比分析压缩效果。



采用C++语言编写程序,调用OpenCV图像处理库来进行图像矩阵的SVD分解,采用不同的压缩比(0.01, 0.05, 0.1, 0.2, 0.3, 0.5)重复执行程序,得到输出结果。程序代码如下:

// 读入图像
cv::Mat img_original = cv::imread("../image.png", cv::IMREAD_GRAYSCALE);
cv::Mat img = img_original.clone();
img.convertTo(img, CV_64FC1, 1/255.0);
// 对图像进行SVD分解
cv::Mat U, Vt, W;
cv::SVD::compute(img, W, U, Vt);
// 图像压缩操作
int rank = min(img.rows, img.cols);
cv::Mat W_hat = cv::Mat(rank, rank, CV_64FC1, cv::Scalar(0)); // 取前k维的奇异值矩阵
double compression_ratio = 0.3; // 设定压缩比
int k = rank * compression_ratio;
for(size_t i=0; i<k; ++i) {
W_hat.at<double>(i, i) = W.at<double>(i, 0);
}
cv::Mat img_compression = U * W_hat * Vt; // 计算压缩后的图像
// 压缩图像输出
img_compression.convertTo(img_compression, CV_8UC1, 255.0);
cv::imwrite("./ratio=0_3.png", img_compression);

输出压缩结果如下所示

  • 压缩比 = 0.01

  • 压缩比 = 0.05

  • 压缩比 = 0.1

  • 压缩比 = 0.2

  • 压缩比 = 0.3

  • 压缩比 = 0.5



    可以看到测试图像的基本轮廓信息在压缩比为0.05的时候就已经大致凸显,而在压缩比为0.2时就已经基本保留图像的细节信息,压缩效率较好。

参考资料

[1] http://www.ams.org/publicoutreach/feature-column/fcarc-svd

[2] https://blog.csdn.net/lomodays207/article/details/88687126

[3] https://www.cnblogs.com/pinard/p/6251584.html

[4] https://blog.csdn.net/u012198575/article/details/99548136

矩阵的奇异值分解(SVD)及其应用的更多相关文章

  1. 用 GSL 求解超定方程组及矩阵的奇异值分解(SVD)

    用 GSL 求解超定方程组及矩阵的奇异值分解(SVD) 最近在学习高动态图像(HDR)合成的算法,其中需要求解一个超定方程组,因此花了点时间研究了一下如何用 GSL 来解决这个问题. GSL 里是有最 ...

  2. 用 GSL 求解超定方程组及矩阵的奇异值分解(SVD) 2

    接上一篇... 下面我们将 SVD 相关的功能封装成一个类,以方便我们提取 S 和 V 的值. 另外,当我们一个 A 有多组 x 需要求解时,也只需要计算一次 SVD 分解,用下面的类能减少很多计算量 ...

  3. 矩阵奇异值分解(SVD)及其应用

    机器学习中的数学(5)-强大的矩阵奇异值分解(SVD)及其应用(好文) [简化数据]奇异值分解(SVD) <数学之美> 第15章 矩阵运算和文本处理中的两个分类问题

  4. 矩阵的奇异值分解(SVD)(理论)

    矩阵的奇异值分解(Singular Value Decomposition,SVD)是数值计算中的精彩之处,在其它数学领域和机器学习领域得到了广泛的应用,如矩阵的广义逆,主分成分析(PCA),自然语言 ...

  5. 机器学习降维方法概括, LASSO参数缩减、主成分分析PCA、小波分析、线性判别LDA、拉普拉斯映射、深度学习SparseAutoEncoder、矩阵奇异值分解SVD、LLE局部线性嵌入、Isomap等距映射

    机器学习降维方法概括   版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/u014772862/article/details/52335970 最近 ...

  6. 奇异值分解(SVD)原理与在降维中的应用

    奇异值分解(Singular Value Decomposition,以下简称SVD)是在机器学习领域广泛应用的算法,它不光可以用于降维算法中的特征分解,还可以用于推荐系统,以及自然语言处理等领域.是 ...

  7. 数值分析之奇异值分解(SVD)篇

    在很多线性代数问题中,如果我们首先思考若做SVD,情况将会怎样,那么问题可能会得到更好的理解[1].                                       --Lloyd N. ...

  8. 转载:奇异值分解(SVD) --- 线性变换几何意义(下)

    本文转载自他人: PS:一直以来对SVD分解似懂非懂,此文为译文,原文以细致的分析+大量的可视化图形演示了SVD的几何意义.能在有限的篇幅把这个问题讲解的如此清晰,实属不易.原文举了一个简单的图像处理 ...

  9. 特征值分解与奇异值分解(SVD)

    1.使用QR分解获取特征值和特征向量 将矩阵A进行QR分解,得到正规正交矩阵Q与上三角形矩阵R.由上可知Ak为相似矩阵,当k增加时,Ak收敛到上三角矩阵,特征值为对角项. 2.奇异值分解(SVD) 其 ...

  10. 奇异值分解(SVD) --- 几何意义

    原文:http://blog.sciencenet.cn/blog-696950-699432.html PS:一直以来对SVD分解似懂非懂,此文为译文,原文以细致的分析+大量的可视化图形演示了SVD ...

随机推荐

  1. Hangfire 使用笔记 任务可以分离到别的项目中,无需重复部署Hangfire,通过API方式通信。

    "巨人们"的地址 Hangfire Mysql: https://github.com/arnoldasgudas/Hangfire.MySqlStorage 在获取set表数据的 ...

  2. .NET Core 中使用GBK GB2312编码报错的问题

    错误描述 环境 dotnet core 2.1 2.2   dotnet core 3.1 dotnet core 5.0 现象 当代码中使用 System.Text.Encoding.GetEnco ...

  3. mac m1使用docker安装oracle

    mac m1使用docker安装oracle数据库 本学期开始学习数据库原理,老师课上讲到课堂作业使用的是oracle 11g,然而我去官网却发现只有Windows和Linux版本的,并没有发现mac ...

  4. Centos Stream 10 测试版下载:未来的RHEL10&Rocky Linux 10

    简介 最近发现Centos最放出了Stream 10 测试版本,应该是基于Fedora 40构建的.未来红帽会基于此版本构建RHEL 10. 内核版本:6.9.0 Python版本:3.12.2 RH ...

  5. SpringBoot系列(三)元注解

    元注解,注解的注解,SpringBoot有四个元注解,分别是@Target.@Retention.@Documented.@Inherited.下面就是对元注解的详细讲解和源码展示. @Taget 该 ...

  6. go 1.6 废弃 io/ioutil 包后的替换函数

    go 1.6 废弃 io/ioutil  包后的替换函数 io/ioutil 替代 ioutil.ReadAll -> io.ReadAll ioutil.ReadFile -> os.R ...

  7. Spring扩展———自定义bean组件注解

    引言 Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制. Java 语言中的类.方法.变量.参数和包等都可以被标注.和 Javadoc 不同,Java ...

  8. 机器学习策略篇:详解清除标注错误的数据(Cleaning up Incorrectly labeled data)

    清除标注错误的数据 监督学习问题的数据由输入\(x\)和输出标签 \(y\) 构成,如果观察一下的数据,并发现有些输出标签 \(y\) 是错的.的数据有些标签是错的,是否值得花时间去修正这些标签呢? ...

  9. mysql case when使用

    ## mysql case when使用 SELECT order_no,case is_test when 0 then '否'when 1 then '是'end as '是否测试' from ` ...

  10. apollo配置json

    #json串原文[{"username":"李小刚","sex":"男"},{"username": ...