机器学习算法那些事 | 这是我见过最通俗易懂的SVD(奇异值分解)算法介绍

news2024/11/15 5:02:54

本文来源公众号“机器学习算法那些事”,仅用于学术分享,侵权删,干货满满。

原文链接:这是我见过最通俗易懂的SVD(奇异值分解)算法介绍

线性代数是机器学习领域的基础,其中一个最重要的概念是奇异值分解(SVD),本文尽可能简洁的介绍SVD(奇异值分解)算法的基础理解,以及它在现实世界中的应用。

SVD是最广泛使用的无监督学习算法之一,它在许多推荐系统和降维系统中居于核心位置,这些系统是全球公司如谷歌、Netflix、Facebook、YouTube等的核心技术。

简单来说,SVD是将一个任意矩阵分解为三个矩阵。所以如果我们有一个矩阵A,那么它的SVD可以表示为:

image-20240808230323995

与特征值分解相比,奇异值分解可以应用于非方阵。在SVD中,U和 V 对于任何矩阵都是可逆的,并且它们是正交归一的,这是我们所喜爱的特性。虽然这里不进行证明,但我们可以告诉你,奇异值比特征值在数值上更稳定。

为了更好地理解,我们通过一个例子演示SVD

奇异值是正特征值的平方根,即5和3。因此非方阵A的SVD分解为:

SVD分解证明

image-20240810203329639

SVD的另一种表述

SVD降维

SVD应用
1.图像降维

我们可以将图像存储在一个矩阵中。每个图像由一组像素组成,这些像素是构成该图像的基本单元。每个像素表示图像中某个特定位置的颜色或光强度。在 PNG 格式的灰度图像中,每个像素的值在 0 和 1 之间,其中 0 对应黑色,1 对应白色。因此一个具有mxn像素的灰度图像可以存储在一个 mxn 矩阵或 NumPy 数组中。在这里,我们使用 imread() 函数加载一张爱因斯坦的灰度图像,其分辨率为 480 × 423 像素,并将其存储为一个二维数组。然后,我们使用 SVD 来分解该矩阵,并使用前 30 个奇异值来重建图像。

# Reading the image
mat = plt.imread("Picture.png")

# SVD 
U, s, VT = LA.svd(mat)

Sigma = np.zeros((mat.shape[0], mat.shape[1]))
Sigma[:min(mat.shape[0], mat.shape[1]), :min(mat.shape[0], mat.shape[1])] = np.diag(s)

# Reconstruction of the matrix using the first 30 singular values
k = 30  # 取前30个特征值,重建图像
mat_approx = U[:, :k] @ Sigma[:k, :k] @ VT[:k, :]

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10,8))
plt.subplots_adjust(wspace=0.3, hspace=0.2)

ax1.imshow(mat, cmap='gray')
ax1.set_title("Original image")

ax2.imshow(mat_approx, cmap='gray')
ax2.set_title("Reconstructed image using the \n first {} singular values".format(k))
plt.show()

image-20240810223105337

左图是原始图像,右图是取前30个奇异值重建的图像。

fig, axes = plt.subplots(2, 3, figsize=(10,8))
plt.subplots_adjust(wspace=0.3, hspace=0.2)

for i in range(0, 6):
    mat_i = s[i] * U[:,i].reshape(-1,1) @ VT[i,:].reshape(1,-1)
    axes[i // 3, i % 3].imshow(mat_i)
    axes[i // 3, i % 3].set_title("$\sigma_{0}\mathbf{{u_{0}}}\mathbf{{v_{0}}}^T$".format(i+1), fontsize=16)
    
plt.show()

image-20240810223817059

请注意,与原始灰度图像不同,这些秩为 1 的矩阵的元素值可以大于 1 或小于 0,它们不应被解释为灰度图像。因此,我没有使用 cmap='gray' 也没有将它们显示为灰度图像。在绘制这些矩阵时,我们不关心像素的绝对值,而是关注它们之间的相对值。

为了理解每个矩阵中如何存储图像信息,我们可以研究一个更简单的图像。下面的代码读取了一个包含五个简单形状的二进制图像(一个矩形和 4 个圆形),并取前2个、前4个和前6个奇异值重建图像。

mat = plt.imread("shapes.png")

# SVD 
U, s, VT = LA.svd(mat)

Sigma = np.zeros((mat.shape[0], mat.shape[1]))
Sigma[:min(mat.shape[0], mat.shape[1]), :min(mat.shape[0], mat.shape[1])] = np.diag(s)

fig, axes = plt.subplots(2, 2, figsize=(10,8))
plt.subplots_adjust(wspace=0.3, hspace=0.2)

axes[0, 0].imshow(mat, cmap='gray')
axes[0, 0].set_title("Original image")

for i in range(1, 4):
    k = i * 2
    # Reconstruction of the matrix using the first k singular values
    mat_approx = U[:, :k] @ Sigma[:k, :k] @ VT[:k, :]

    axes[i // 2, i % 2].imshow(mat_approx, cmap='gray')
    axes[i // 2, i % 2].set_title("Reconstructed image using the \n first {} singular values".format(k))

plt.show()

image-20240810224420549

现在我们绘制前 6 个奇异值对应的矩阵:

fig, axes = plt.subplots(2, 3, figsize=(10,6))
plt.subplots_adjust(wspace=0.3, hspace=0.05)

for i in range(0, 6):
    mat_i = s[i] * U[:,i].reshape(-1,1) @ VT[i,:].reshape(1,-1)
    #mat_i[mat_i < 1e-8] = 0
    axes[i // 3, i % 3].imshow(mat_i)
    axes[i // 3, i % 3].set_title("$\sigma_{0}\mathbf{{u_{0}}}\mathbf{{v_{0}}}^T$".format(i+1), fontsize=16)
    
plt.show()

image-20240810224526788

从每个奇异值的图像可以看出,前两个奇异值构建的矩阵大致捕捉了四个圆形作为四个矩形,而最后四个奇异值构建的矩阵则添加了更多细节。

如下图,图像中有 6 根柱子,第一个奇异值对应的矩阵可以捕捉到原始图像中的柱子数量。

image-20240810224851967

2.特征脸

在这个示例中,我们将使用 Scikit-learn 库中的 Olivetti faces 数据集。该数据集包含 400 张图像,图像展示了 40 位不同受试者的面部特征。对于一些受试者,图像是在不同时间拍摄的,具有不同的光照、面部表情和面部细节。这些图像为灰度图像,每张图像具有 64×64 像素。每个像素的强度值在区间 [0, 1] 上。首先,我们加载数据集:

data = fetch_olivetti_faces()
imgs = data.images
print(imgs.shape)

我们调用它来读取数据,并将图像存储在 imgs 数组中。这是一个形状为 (400, 64, 64) 的数组,包含 400 张 64×64 的灰度图像。我们可以在这里展示其中的一些作为示例:

fig, axes = plt.subplots(1, 5, figsize=(14, 8))
plt.subplots_adjust(wspace=0.4)

for i in range(0, 5):
    axes[i].imshow(imgs[i*40], cmap='gray')

plt.show()

image-20240810225330410

在前一个示例中,我们将原始图像存储在一个矩阵中,然后使用 SVD 对其进行分解。在这里,我们采用另一种方法。我们有400 张图像并给每张图像分配一个从 1 到 400 的标签。现在我们使用独热编码来表示这些标签,使用一个包含 400 个元素的列向量。对于每个标签 k,除了第 k个元素,所有元素都是零。因此,标签 k将由以下向量表示:

现在我们将每张图像存储在一个列向量中。每张图像有 64 × 64 = 4096 个像素。因此,我们可以将每张图像展平并将像素值放入一个具有 4096 个元素的列向量f中,如下图所示:

mage-20240810230051322

我们计算并显示前8个奇异值对应的U向量:

U, s, VT = LA.svd(M)

fig, axes = plt.subplots(2, 4, figsize=(10,6))
plt.subplots_adjust(wspace=0.3, hspace=0.1)

for i in range(0, 8):
    axes[i // 4, i % 4].imshow(U[:, i].reshape((64,64)))
    axes[i // 4, i % 4].set_title("$\mathbf{{u_{0}}}$".format(i+1), fontsize=16)
    
plt.show()

image-20240810231222673

x= np.zeros((400, 1))
x[160, 0] = 1
Sigma = np.zeros((M.shape[0], M.shape[1]))
Sigma[:min(M.shape[0], M.shape[1]), :min(M.shape[0], M.shape[1])] = np.diag(s)

fig, axes = plt.subplots(2, 4, figsize=(14, 8))
fig.suptitle("Reconstructed image using the first k singular values", fontsize=16)
plt.subplots_adjust(wspace=0.3, hspace=0.1)

axes[0, 0].imshow(imgs[160], cmap='gray')
axes[0, 0].set_title("Original image")

k_list = [1, 6, 10, 15, 20, 35, 80]
for i in range(1, 8):
    # Reconstruction of the matrix using the first k singular values
    k = k_list[i-1] 
    mat_approx = U[:, :k] @ Sigma[:k, :k] @ VT[:k, :] @ x

    axes[i // 4, i % 4].imshow(mat_approx.reshape((64,64)), cmap='gray')
    axes[i // 4, i % 4].set_title("k = {}".format(k))

plt.show()

这里我们使用不同个数的奇异值去重建第160号图像(k表示使用前k个奇异值重建图像)。

image-20240810232014008

上图反映的信息与特征脸步骤的细节基本一致,如最高奇异值(k=1)重建的图像反映了眼睛信息,同样地,第一个特征脸反映的也是眼睛信息。

3.降低噪声

SVD可以用于降低图像中的噪声。

mat = plt.imread("text.png")

# Adding noise
noise = np.random.rand(mat.shape[0], mat.shape[1])
mat[noise > 0.95] = 0

# SVD 
U, s, VT = LA.svd(mat)

Sigma = np.zeros((mat.shape[0], mat.shape[1]))
Sigma[:min(mat.shape[0], mat.shape[1]), :min(mat.shape[0], mat.shape[1])] = np.diag(s)

fig, axes = plt.subplots(2, 2, figsize=(10,8))
plt.subplots_adjust(wspace=0.2, hspace=0.1)

axes[0, 0].imshow(mat, cmap='gray')
axes[0, 0].set_title("Original image", y=1.08)

k_list = [20, 55, 200]
for i in range(1, 4):
    k = k_list[i-1]
    mat_rank_k = U[:, :k] @ Sigma[:k, :k] @ VT[:k, :]
    axes[i // 2, i % 2].imshow(mat_rank_k, cmap='gray')
    axes[i // 2, i % 2].set_title("Reconstructed image using the \n first {} singular values".format(k), y=1.08)

plt.show()

image-20240811135427217

首先,我们加载图像并添加一些噪声。然后使用前 20、55 和 200 个奇异值重建图像。如上图所示,随着重建矩阵的秩增加,噪声的量也随之增加。因此如果我们使用较低的秩,比如 20,可以显著减少图像中的噪声。

结论

我真的觉得奇异值分解(SVD)被低估了。它是线性代数中一个非常重要的基础概念,而且它的应用非常酷!相信我,我们看到的只是 SVD 众多用途中的一小部分。有什么问题,欢迎讨论!

THE END !

文章结束,感谢阅读。您的点赞,收藏,评论是我继续更新的动力。大家有推荐的公众号可以评论区留言,共同学习,一起进步。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2070937.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

手机号归属地查询如何用Java进行调用

一、什么是手机号归属地查询接口&#xff1f; 手机号归属地查询接口又叫手机号归属地、手机号信息查询、手机号查询&#xff0c;通过手机号查询归属地信息、是否虚拟运营商等。该接口可支持三大运营商&#xff0c;移动、电信、联通等。 二、手机号归属地查询接口适用场景有哪…

OpenCV+Python识别机读卡

背景介绍 正常机读卡是通过读卡机读取识别结果的&#xff0c;目前OpenCV已经这么强大了&#xff0c;尝试着用OpenCVPython来识别机读卡。要识别的机读卡长这样&#xff1a; 我们做以下操作&#xff1a; 1.识别答题卡中每题选中项结果。 不做以下操作&#xff1a; 1.不识别准…

【数据分析:RFM客户价值度模型】

前言&#xff1a; &#x1f49e;&#x1f49e;大家好&#xff0c;我是书生♡&#xff0c;本阶段和大家一起分享和探索大数据技术RFM客户价值度模型&#xff0c;本篇文章主要讲述了&#xff1a;RFM客户价值度模型等等。欢迎大家一起探索讨论&#xff01;&#xff01;&#xff01…

大数据-99 Spark 集群 Spark Streaming DStream 文件数据流、Socket、RDD队列流

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

GATK ReadsPathDataSource类介绍

GATK(Genome Analysis Toolkit)是一个广泛使用的基因组分析工具包,它的核心库之一是htsjdk,用于处理高通量测序数据。在GATK中,ReadsPathDataSource类是负责管理和提供读取高通量测序数据文件(如BAM、SAM、CRAM)的类。 常见使用场景 数据加载:在GATK的基因组分析工具链…

MySQL的MRR(Multi-Range Read)优化原理详解

❃博主首页 &#xff1a; 「码到三十五」 &#xff0c;同名公众号 :「码到三十五」&#xff0c;wx号 : 「liwu0213」 ☠博主专栏 &#xff1a; <mysql高手> <elasticsearch高手> <源码解读> <java核心> <面试攻关> ♝博主的话 &#xff1a…

LeetCode:反转区间内的链表

&#x1f4df;作者主页&#xff1a;慢热的陕西人 &#x1f334;专栏链接&#xff1a;力扣刷题日记 &#x1f4e3;欢迎各位大佬&#x1f44d;点赞&#x1f525;关注&#x1f693;收藏&#xff0c;&#x1f349;留言 文章目录 反转区间内的链表题目链接方法一&#xff1a;拆开反转…

【TB作品】PIC16F1719单片机,EEPROM,PFM,读写

对于PIC16F1719单片机&#xff0c;没有直接的EEPROM&#xff0c;而是使用高耐久度的程序闪存&#xff08;PFM&#xff09;作为非易失性数据存储区域。这个区域特别适合存储那些需要频繁更新的数据。读写这个内存区域需要操作一些特殊功能寄存器&#xff0c;比如用于地址的PMADR…

2.K8s集群搭建

K8s搭建 搭建方案kubeadm搭建系统初始化操作k8s Master节点初始化将node节点加入集群安装网络插件Calico集群测试 搭建方案 minikube&#xff1a;轻量化的Kubernetes集群&#xff0c;为了能够更好学习和体验k8s功能而推出的&#xff0c;借助个人PC的虚拟化环境就可以实现Kuber…

如何使用ssm实现基于java web的网上书城系统的设计与实现+vue

TOC ssm123基于java web的网上书城系统的设计与实现vue JAVA简介 Java主要采用CORBA技术和安全模型&#xff0c;可以在互联网应用的数据保护。它还提供了对EJB&#xff08;Enterprise JavaBeans&#xff09;的全面支持&#xff0c;java servlet API&#xff0c;JSP&#xff…

【Redis】Redis客户端——Jedis(Java)

Redis Java使用案例 环境配置引入依赖配置端⼝转发连接 Redis Server Java基础代码操作Redisset 和 getexsits 和 del 环境配置 引入依赖 Java 操作 redis 的客⼾端有很多. 其中最知名的是 jedis. 创建 maven 项⽬, 把 jedis 的依赖拷⻉到 pom.xml 中. <!-- https://mvnr…

ssrf--web-ssrfme例题

将web-ssrfme.zip解压缩在Ubuntu下 Docker-compose up -d 更新后的镜像重新启动容器 可以看到已经拉取成功ssrfme镜像 我们使用端口访问文件&#xff0c;可以看到有一个过滤条件&#xff0c;它限制了file&#xff0c;dict协议&#xff0c;127.0.0.1和localhost 也不能用&…

【55-90】结构型模式

目录 一.结构型模式概述 二.代理模式 2.1 概述 2.2 结构 2.3 静态代理 2.4 JDK动态代理 2.5 CGLIB动态代理 2.6 三种代理的对比 2.7 优缺点 三.适配器模式 3.1 概述 3.2 结构 3.3 类适配器模式 3.4 对象适配器模式 3.5 应用场景 四.装饰者模式 4.1 概述 4.2 结…

从并发20到并发120之laravel性能优化

调优成果 遇到问题 单台服务并发20&#xff0c;平均响应时间1124ms&#xff0c;通过htop观察&#xff0c;发现cpu占用率达到100%&#xff08;包括sleep的进程&#xff09;&#xff0c;内存几乎没怎么用。 调优后 单机最大吞吐量达到120 响应时长不超过1000ms 硬件信息 …

数学建模----线性回归分析(引入热力图的绘制方法)

目录 0.直击重点 1.一元线性回归分析 1.1散点图的绘制 1.2相关性的分类 1.3计算相关系数 1.4模型的检验 1.5模型的预测 2.多重线性回归分析&#xff08;上&#xff09; 2.1多重线性的概念 2.2散点图的分类 2.3热力图的绘制 2.4根据结果确定新的变量 3.多重线性…

【开端】 如何判断手机号码属于哪个国家(手机号判断正则)汇总

import org.apache.commons.lang3.StringUtils; /** * 手机号判断正则 */ public enum MobileRegularExp { /** * 国家 正则 */ CN("中国", 86, "^(\\?0?86\\-?)?1[3456789]\\d{9}$"), TW("中国台湾", 886, "…

第七节 循环结构;goto语句

目录 7.1 while循环 7.1.1 if 和 while的对⽐ 7.1.2 while的执行流程 7.1.3 while的练习 7.2 for循环 7.2.1 语法形式 7.2.2 for循环的执⾏流程 7.2.3 for 循环的练习 7.3 while 和 for 循环的对比 7.4 do while 循环 7.4.1 do while 的语法形式 7.4.2 do while循…

Jamba前生今世:1.5开源来袭

AI21服务于企业&#xff0c;为企业构建基础模型和AI系统以加速GenAI在生产中的使用。AI21 成立于2017年&#xff0c;已从NVIDIA、Intel、Google等公司共筹集了3.36亿美元。它是最早将生成式AI推向大众的公司之一&#xff0c;借助AI21平台&#xff0c;企业可以构建自己的生成式A…

菲菲更名宝贝:批量处理,文件命名不再繁琐

你是否有这样的经历&#xff1f;曾几何时&#xff0c;在堆积如山的文件中迷失方向&#xff0c;为了一个个手动重命名文件而加班到深夜&#xff1f;是否渴望有一种魔法&#xff0c;能瞬间让你的文件整理得井井有条&#xff0c;让繁琐的命名工作变得轻松愉快&#xff1f;那么&…

大数据毕业设计开题报告100例

文章目录 &#x1f6a9; 1 前言1.1 选题注意事项1.1.1 难度怎么把控&#xff1f;1.1.2 题目名称怎么取&#xff1f; 1.2 开题选题推荐1.2.1 起因1.2.2 核心- 如何避坑(重中之重)1.2.3 怎么办呢&#xff1f; &#x1f6a9;2 选题概览&#x1f6a9; 3 项目概览题目1 : 深度学习社…