SVD奇异值分解(理论与C++实现)

article/2025/10/14 0:41:37

SVD奇异值分解

  • 前言
  • 理论推导
  • 部分代码实现

前言

  奇异值分解(singular value decomposition,以下简称SVD)是线性代数中一种重要的矩阵分解。SVD将矩阵分解为奇异向量(singular vector)和奇异值(singular value)。SVD将矩阵 A A A分解成三个矩阵的乘积
A = U D V T A = UDV^{T} A=UDVT
  设 A A A m × n m\times n m×n的矩阵,则 U U U是一个 m × m m\times m m×m的矩阵, D D D是一个 m × n m\times n m×n的矩阵 V V V是一个 n × n n\times n n×n的矩阵。
  读者可访问以下链接获取相关代码
  代码链接

理论推导

在这里插入图片描述

部分代码实现

/*** @brief 实现奇异值分解* @note  基于Householder变换以及变星QR算法对一般实矩阵A进行奇异值分解* step1 用豪斯荷尔德变换将A约化为双对角线矩阵* step2 用变星的QR算法进行迭代,计算所有奇异值* steo3 对奇异值按非递增次序进行排列
*/
void Matrix::SVD( const Matrix & A, Matrix& U2, Matrix& W, Matrix& V) {Matrix U = A;int m = A.rows();int n = A.cols();U2 = Matrix(m, m);V = Matrix(n, n);NAFLOAT* w = (NAFLOAT*)malloc(n * sizeof(NAFLOAT));NAFLOAT* rv1 = (NAFLOAT*)malloc(n * sizeof(NAFLOAT));int32_t flag, i, its, j, jj, k, l, nm;NAFLOAT   anorm, c, f, g, h, s, scale, x, y, z;g = scale = anorm = 0.0;for (i = 0; i < n; i++) {l = i + 1;rv1[i] = scale * g;g = s = scale = 0.0;if (i < m) {for (k = i; k < m; k++) scale += fabs(U.m_val[k][i]);if (scale) {for (k = i; k < m; k++) {U.m_val[k][i] /= scale;s += U.m_val[k][i] * U.m_val[k][i];}f = U.m_val[i][i];g = -SIGN(sqrt(s), f);h = f * g - s;U.m_val[i][i] = f - g;for (j = l; j < n; j++) {for (s = 0.0, k = i; k < m; k++) s += U.m_val[k][i] * U.m_val[k][j];f = s / h;for (k = i; k < m; k++) U.m_val[k][j] += f * U.m_val[k][i];}for (k = i; k < m; k++) U.m_val[k][i] *= scale;}}w[i] = scale * g;g = s = scale = 0.0;if (i < m && i != n - 1) {for (k = l; k < n; k++) scale += fabs(U.m_val[i][k]);if (scale) {for (k = l; k < n; k++) {U.m_val[i][k] /= scale;s += U.m_val[i][k] * U.m_val[i][k];}f = U.m_val[i][l];g = -SIGN(sqrt(s), f);h = f * g - s;U.m_val[i][l] = f - g;for (k = l; k < n; k++) rv1[k] = U.m_val[i][k] / h;for (j = l; j < m; j++) {for (s = 0.0, k = l; k < n; k++) s += U.m_val[j][k] * U.m_val[i][k];for (k = l; k < n; k++) U.m_val[j][k] += s * rv1[k];}for (k = l; k < n; k++) U.m_val[i][k] *= scale;}}anorm = std::max(anorm, (std::fabs(w[i]) + std::fabs(rv1[i])));}for (i = n - 1; i >= 0; i--) { // Accumulation of right-hand transformations.if (i < n - 1) {if (g) {for (j = l; j < n; j++) // Double division to avoid possible underflow.V.m_val[j][i] = (U.m_val[i][j] / U.m_val[i][l]) / g;for (j = l; j < n; j++) {for (s = 0.0, k = l; k < n; k++) s += U.m_val[i][k] * V.m_val[k][j];for (k = l; k < n; k++) V.m_val[k][j] += s * V.m_val[k][i];}}for (j = l; j < n; j++) V.m_val[i][j] = V.m_val[j][i] = 0.0;}V.m_val[i][i] = 1.0;g = rv1[i];l = i;}for (i = std::min(m, n) - 1; i >= 0; --i) { // Accumulation of left-hand transformations.l = i + 1;g = w[i];for (j = l; j < n; j++) U.m_val[i][j] = 0.0;if (g) {g = 1.0 / g;for (j = l; j < n; j++) {for (s = 0.0, k = l; k < m; k++) s += U.m_val[k][i] * U.m_val[k][j];f = (s / U.m_val[i][i]) * g;for (k = i; k < m; k++) U.m_val[k][j] += f * U.m_val[k][i];}for (j = i; j < m; j++) U.m_val[j][i] *= g;}else for (j = i; j < m; j++) U.m_val[j][i] = 0.0;++U.m_val[i][i];}for (k = n - 1; k >= 0; k--) { // Diagonalization of the bidiagonal form: Loop over singular values,for (its = 0; its < 30; its++) { // and over allowed iterations.flag = 1;for (l = k; l >= 0; l--) { // Test for splitting.nm = l - 1;if ((NAFLOAT)(fabs(rv1[l]) + anorm) == anorm) { flag = 0; break; }if ((NAFLOAT)(fabs(w[nm]) + anorm) == anorm) { break; }}if (flag) {c = 0.0; // Cancellation of rv1[l], if l > 1.s = 1.0;for (i = l; i <= k; i++) {f = s * rv1[i];rv1[i] = c * rv1[i];if ((NAFLOAT)(fabs(f) + anorm) == anorm) break;g = w[i];h = pythag(f, g);w[i] = h;h = 1.0 / h;c = g * h;s = -f * h;for (j = 0; j < m; j++) {y = U.m_val[j][nm];z = U.m_val[j][i];U.m_val[j][nm] = y * c + z * s;U.m_val[j][i] = z * c - y * s;}}}z = w[k];if (l == k) { // Convergence.if (z < 0.0) { // Singular value is made nonnegative.w[k] = -z;for (j = 0; j < n; j++) V.m_val[j][k] = -V.m_val[j][k];}break;}NA_Assert(its != 29,"ERROR in SVD: No convergence in 30 iterations");x = w[l]; // Shift from bottom 2-by-2 minor.nm = k - 1;y = w[nm];g = rv1[nm];h = rv1[k];f = ((y - z) * (y + z) + (g - h) * (g + h)) / (2.0 * h * y);g = pythag(f, 1.0);f = ((x - z) * (x + z) + h * ((y / (f + SIGN(g, f))) - h)) / x;c = s = 1.0; // Next QR transformation:for (j = l; j <= nm; j++) {i = j + 1;g = rv1[i];y = w[i];h = s * g;g = c * g;z = pythag(f, h);rv1[j] = z;c = f / z;s = h / z;f = x * c + g * s;g = g * c - x * s;h = y * s;y *= c;for (jj = 0; jj < n; jj++) {x = V.m_val[jj][j];z = V.m_val[jj][i];V.m_val[jj][j] = x * c + z * s;V.m_val[jj][i] = z * c - x * s;}z = pythag(f, h);w[j] = z; // Rotation can be arbitrary if z = 0.if (z) {z = 1.0 / z;c = f * z;s = h * z;}f = c * g + s * y;x = c * y - s * g;for (jj = 0; jj < m; jj++) {y = U.m_val[jj][j];z = U.m_val[jj][i];U.m_val[jj][j] = y * c + z * s;U.m_val[jj][i] = z * c - y * s;}}rv1[l] = 0.0;rv1[k] = f;w[k] = x;}}// sort singular values and corresponding columns of u and v// by decreasing magnitude. Also, signs of corresponding columns are// flipped so as to maximize the number of positive elements.int32_t s2, inc = 1;NAFLOAT   sw;NAFLOAT* su = (NAFLOAT*)malloc(m * sizeof(NAFLOAT));NAFLOAT* sv = (NAFLOAT*)malloc(n * sizeof(NAFLOAT));do { inc *= 3; inc++; } while (inc <= n);do {inc /= 3;for (i = inc; i < n; i++) {sw = w[i];for (k = 0; k < m; k++) su[k] = U.m_val[k][i];for (k = 0; k < n; k++) sv[k] = V.m_val[k][i];j = i;while (w[j - inc] < sw) {w[j] = w[j - inc];for (k = 0; k < m; k++) U.m_val[k][j] = U.m_val[k][j - inc];for (k = 0; k < n; k++) V.m_val[k][j] = V.m_val[k][j - inc];j -= inc;if (j < inc) break;}w[j] = sw;for (k = 0; k < m; k++) U.m_val[k][j] = su[k];for (k = 0; k < n; k++) V.m_val[k][j] = sv[k];}} while (inc > 1);for (k = 0; k < n; k++) { // flip signss2 = 0;for (i = 0; i < m; i++) if (U.m_val[i][k] < 0.0) s2++;for (j = 0; j < n; j++) if (V.m_val[j][k] < 0.0) s2++;if (s2 > (m + n) / 2) {for (i = 0; i < m; i++) U.m_val[i][k] = -U.m_val[i][k];for (j = 0; j < n; j++) V.m_val[j][k] = -V.m_val[j][k];}}// create vector and copy singular valuesW = Matrix(std::min(m, n), 1, w);// extract mxm submatrix UU2.setMat(U.getMat(0, 0, m - 1, std::min(m - 1, n - 1)), 0, 0);// release temporary memoryfree(w);free(rv1);free(su);free(sv);
}

http://chatgpt.dhexx.cn/article/8M66QE8f.shtml

相关文章

matlab实现奇异值分解

一、原理 二、实现 %% 两种方法计算矩阵 A 的 SVD A [0,1; 1,1; 1,0];%% 方法一&#xff1a;利用特征分解eig % 计算右奇异矩阵V [V,D1] eig(A*A); n size(D1,1); index n:-1:1; D1 diag(D1); D1 D1(index); D1 diag(D1, 0); V V(:,index); % 计算左奇异矩阵U [U,D2…

特征值分解和奇异值分解

特征值分解 特征值分解是将一个方阵A分解为如下形式&#xff1a; A Q Σ Q − 1 AQ\Sigma Q^{-1} AQΣQ−1 其中&#xff0c;Q是方阵A的特征向量组成的矩阵&#xff0c; Σ \Sigma Σ是一个对角矩阵&#xff0c;对角线元素是特征值。 通过特征值分解得到的前N个特征向量&am…

奇异值分解的揭秘(一):矩阵的奇异值分解过程

转载来源&#xff1a; 作者&#xff1a;Xinyu Chen 链接&#xff1a;https://zhuanlan.zhihu.com/p/26306568 来源&#xff1a;知乎 矩阵的奇异值分解&#xff08;singular value decomposition&#xff0c;简称SVD&#xff09;是线性代数中很重要的内容&#xff0c;并且奇…

奇异值分解(Singular Values Decomposition,SVD)

奇异值分解 1.奇异值分解1.1 变换&#xff08;Transformations&#xff09;1.2 线性变换&#xff08;Linear Transformations&#xff09;1.3 降维&#xff08;Dimensionality Reduction&#xff09;1.4 奇异值分解&#xff08;SVD&#xff09;1.4.1 如果矩阵 A A A是方阵&…

奇异值分解(SVD)的原理详解及推导

1. 写在前面 最近整理推荐系统模型的时候&#xff0c; 第二个模型打算整理一下隐语义模型&#xff0c; 这里面绕不开一种思想就是矩阵分解&#xff0c; 而作为矩阵分解的经典方法SVD感觉这次有必要学学了&#xff0c; SVD不仅是一个数学问题&#xff0c;在工程应用中的很多地方…

机器学习(29)之奇异值分解SVD原理与应用详解

微信公众号 关键字全网搜索最新排名 【机器学习算法】:排名第一 【机器学习】:排名第一 【Python】:排名第三 【算法】:排名第四 前言 奇异值分解(Singular Value Decomposition,简称SVD)是在机器学习领域广泛应用的算法,它不光可以用于降维算法中的特征分解,还可以用于…

【机器学习】这次终于彻底理解了奇异值分解(SVD)原理及应用

奇异值分解(Singular Value Decomposition&#xff0c;以下简称SVD)是在机器学习领域广泛应用的算法&#xff0c;有相当多的应用与奇异值都可以扯上关系&#xff0c;它不光可以用于降维算法中的特征分解&#xff0c;比如做feature reduction的PCA&#xff0c;做数据压缩&#x…

联邦学习——用data-free知识蒸馏处理Non-IID

《Data-Free Knowledge Distillation for Heterogeneous Federated Learning》ICML 2021 最近出现了利用知识蒸馏来解决FL中的用户异构性问题的想法&#xff0c;具体是通过使用来自异构用户的聚合知识来优化全局模型&#xff0c;而不是直接聚合用户的模型参数。然而&#xff0c…

【FLIS】Clustered Federated Learning via Inference Similarity for Non-IID Data Distribution

Clustered Federated Learning via Inference Similarity for Non-IID Data Distribution 基于推理相似性的非iid数据分布聚类联邦学习 Abstract1.INTRODUCTION2.FEDERATED LEARNING WITH CLUSTERINGA. Overview of FLIS AlgorithmB. Clustering Clients 3.EXPERIMENTSA. Exper…

Federated Learning with Non-IID Data 论文笔记

本文提出联邦学习中的由于Non-IID数据分布而精度降低是因为权重分散&#xff08;weight divergence&#xff09;&#xff0c;而权重散度可以用搬土距离&#xff08;EMD&#xff09;量化&#xff0c;最后提出了一种策略&#xff1a;通过创建一个在所有边缘设备之间全局共享的数据…

论文分享:「FED BN」使用LOCAL BATCH NORMALIZATION方法解决Non-iid问题

‍ ‍ 本次分享内容基于ICLR 2021收录的一篇文章&#xff1a;《FED BN: FEDERATED LEARNING ON NON-IID FEATURES VIA LOCAL BATCH NORMALIZATION》&#xff0c;这篇论文主要探讨了使用LOCAL BATCH NORMALIZATION方法解决Non-iid问题。围绕这篇论文的分享将分为4个部分&#…

On the convergence of FedAvg on non-iid data

在这篇blog中我们一起来阅读一下 On the convergence of FedAvg on non-iid data 这篇 ICLR 2020 的paper. 主要目的 本文的主要目的是证明联邦学习算法的收敛性。与之前其他工作中的证明不同&#xff0c;本文的证明更贴近于实际联邦学习的场景。特别的&#xff0c; 所有用户…

Federated Learning with Non-IID Data

Federated Learning with Non-IID Data 论文中分析了FedAvg算法在Non-IID数据时&#xff0c;准确率下降的原因。并提出共享5%的数据可提高准确率。 论文笔记参考&#xff1a;https://blog.csdn.net/GJ_007/article/details/104768415 Federated Learning with Non-IID Data …

什么是TLB文件,怎样从dll文件中提取TYPEID信息?- IID

文章目录 1.TLB是什么?2.怎样从dll中导出TLB文件?3.怎样创建TLB文件?4.如何导入TLB5.作者答疑Com是windows平台提供的二进制互操作解决方案。如果给你一个dll,或者windows自带的dll,是否有可能提取其Com接口信息,答案是可以的。 1.TLB是什么? TLB文件是一个说明文件,通…

怎么实现联邦学习中的Non-IID?

联邦学习的一大特点就是数据分布是Non-IID&#xff0c;Non-IID意为非独立同分布。那么怎么在实验中实现non-iid呢&#xff1f;这是我这篇博客想讨论的问题。 part 1&#xff1a; 在堪称联邦学习“开山之作”FedAvg这篇论文中&#xff0c;是这样描述的&#xff1a; 数据集是MN…

【联邦学习】联邦学习量化——non-iid数据集下的仿真

文章目录 改进项目背景量化函数的改进non-iid数据集的设置Fedlab划分数据集的踩雷 改进项目背景 在前面的项目中&#xff0c;虽然对联邦学习中&#xff0c;各个ue训练出来的模型上传的参数进行了量化&#xff0c;并仿真的相关结果。但是仍有一些俺不是非常符合场景的情况&…

「隐语小课」联邦学习之Non-IID问题

更多干货内容&#xff0c;请移步公众号&#xff1a;隐语的小剧场 一、引言 本文针对联邦学习中遇到的Non-IID问题进行探讨&#xff0c;介绍Non-IID产生的原因&#xff0c;分析Non-IID对联邦学习的影响&#xff0c;以及调研了近年来针对该问题的解决方案&#xff0c;并进行分类…

联邦学习中的non-iid总结

最近研究联邦学习&#xff08;federated learning&#xff0c;FL&#xff09;中的non-iid的解决办法时遇到瓶颈&#xff0c;写成博客将最近的工作总结一下&#xff0c;希望有大佬看到这篇博客不吝赐教。 什么是non-iid 先从维基百科引出独立同分布的定义&#xff1a; 在概率论…

IID 与 Non-IID

数据独立同分布&#xff08;Independent Identically Distribution&#xff0c;IID&#xff09; 数据与数据之间都是独立的&#xff0c;但满足同一个分布。&#xff08;独立&#xff1a;一个数据的出现不会影响另一个数据&#xff09; 数据分布描述的是数据的统计情况&#x…

dy设备deviceid iid注册分析

清楚缓存&#xff0c;重新打开app, 点击同意按钮&#xff0c;会触发设备注册&#xff1b; 很明显是一个post包&#xff0c;device_register 可以看到请求体加密了 那么 请求体是什么呢&#xff1f; 很老版本思路&#xff1a;都是直接明文注册 较老版本思路&#xff1a;在反编译…