PCA、SVD、ZCA白化理论与实现

简介

UFLDL中介绍了主成分分析这一块的知识,而且当时学机器学习的时候,老师是将PCASVD联系起来将的,同时UFLDL也讲到了使用PCA做数据白化whitening处理,这个词经常在论文里面看到。

国际惯例,参考博客:

UFLDLPCA章节

PRML的第12.1 PCA章节

知乎深入理解PCA与SVD的关系

PCA and SVD explained with numpy

Relationship between SVD and PCA. How to use SVD to perform PCA?

百度百科正交投影

知乎正交投影

SVD(奇异值分解)小结

特征分解

协方差矩阵一定是满秩的吗?

PCA、ZCA白化

PCA理论

PRML中给出了PCA的两种定义:

  • 数据在低维线性空间上的正交投影,这个线性空间被称为主子空间,使得投影数据的方差被最大化
  • 平均投影代价最小的线性投影。其中平均投影代价是数据点与投影点之间的平均平方距离。

如下图就是将二维数据投影一维空间u1u_1u1

在这里插入图片描述

上图中红色的二维数据点被正交投影到主子空间(紫色的线),PCA的目的就是想让投影后的数据(绿色点)具有最大的方差。 其中正交投影被神乎其神的说了一大堆理论,其实就是投影线垂直于投影面。

通常情况下,我们都是用第一个定义去理解PCA的,设每个样本都有D个属性,即D维向量,总共有N个样本。

第一步将数据投影到D维向量u1u_1u1上,一般来说我们设这个u1u_1u1是D维空间中的方向向量:
x^=u1Tx\hat{x}=u_1^Tx x^=u1Tx
第二步求投影方差
1N{u1Txn−u1Txˉ}2=u1TSu1\frac{1}{N}\{u_1^Tx_n-u_1^T\bar{x}\}^2=u_1^TSu_1 N1{u1Txnu1Txˉ}2=u1TSu1
其中xˉ\bar{x}xˉ所有样本均值xˉ=1N∑n=1Nxn\bar{x}=\frac{1}{N}\sum_{n=1}^Nx_nxˉ=N1n=1Nxn,注意不是每个样本所有属性求均值。

其中SSS是原数据集的协方差矩阵:
S=1N∑n=1N(xn−xˉ)(xn−xˉ)TS=\frac{1}{N}\sum_{n=1}^N(x_n-\bar{x})(x_n-\bar{x})^T S=N1n=1N(xnxˉ)(xnxˉ)T
【注】协方差反映的是属性与属性之间的关系,而非样本与样本之间的关系。

第三步约束

上面我们经常约束u1u_1u1是方向向量,那么
u1Tu1=1u_1^Tu_1=1 u1Tu1=1
结合这个约束以及为了让方差最大化的目标,可以利用拉格朗日乘数法建立下式:
u1TSu1+λ1(1−u1Tu1)u_1^TSu_1+\lambda_1(1-u_1^Tu_1) u1TSu1+λ1(1u1Tu1)
当上式导数为零时,驻点满足
Su1=λ1u1Su_1=\lambda_1u_1 Su1=λ1u1
很容易发现u1u_1u1一定是SSS的特征向量,同时也能发现当λ1\lambda_1λ1越大,方差越大。所以最大特征值对应的特征向量为第一主成分。同理就能利用特征分解的方法求解到第二、三、…主分量。

综上,可以得到PCA的一般步骤为:

  • 整理原始矩阵Xn×mX_{n \times m}Xn×m ,代表n个样本,每个样本维度为m

  • 求原始矩阵Xn×mX_{n \times m}Xn×m的协防差阵Sm×m=Cov(X)S_{m\times m}=Cov(X)Sm×m=Cov(X)

  • 求解协防差阵的特征值和特征向量。

  • 选取最大的K(人为给定)个特征值所对应的特征向量组成构成矩阵Wm×kW_{m\times k}Wm×k

  • 直接进行矩阵计算,就得到了降维后的数据

Zn×k=Xn×mWm×kZ_{n\times k} = X_{n\times m }W_{m\times k } Zn×k=Xn×mWm×k

SVD 理论

一般来说实对称矩阵可以被分解为A=Q∑QTA=Q\sum Q^TA=QQT的形式,其中QQQ为标准正交矩阵,∑\sum对角阵,对角阵上的元素λi\lambda_iλi是矩阵A的特征值,对应的特征向量是QiQ_iQi

那么如果矩阵AAA为非实对称矩阵的时候,有没有类似的
A=UΣVTA=U\Sigma V^T A=UΣVT
奇异值分解(singular value decompositionSVD)做的就是这件事。在SVD的官方术语中,U(n,n)(n,n)(n,n)维的方阵称为左奇异向量;Σ\SigmaΣ(n,m)(n,m)(n,m)的对角阵,对角线上的元素称为奇异值;V(m,m)(m,m)(m,m)维度的方阵称为右奇异向量,并且UV均为单位正交矩阵,UUT=1UU^T=1UUT=1VVT=1VV^T=1VVT=1

求解方法就是利用AATAA^TAATATAA^TAATA都是对称阵的特性,得到:
AAT=UΣΣTUTATA=VΣTΣVTAA^T=U\Sigma \Sigma ^T U^T \\ A^TA=V\Sigma^T\Sigma V^T AAT=UΣΣTUTATA=VΣTΣVT
这样就能求解出UΣ\SigmaΣ、V。

这篇文章里面有例子。

PCA和SVD的关系

摘自此处,通过协方差矩阵的求解方法建立联系:

SVD中:
S=ATX=VΣUTUΣVT=VΣ2VT=VΣ2V−1S=A^TX =V\Sigma U^T U\Sigma V^T =V\Sigma ^2V^T =V\Sigma^2V^{-1} S=ATX=VΣUTUΣVT=VΣ2VT=VΣ2V1
而在PCA中:
S=u1λ1u1−1S=u_1\lambda_1u_1^{-1} S=u1λ1u11
所以:
λ=Σ2u=V\lambda=\Sigma^2\\ u=V λ=Σ2u=V
这一点可以通过代码验证:

a=np.array([[1,5,7],[2,3,6],[5,9,3]])
C = np.dot(a.T, a)eigen_vals,eigen_vecs = np.linalg.eig(C)
u,sigma,v=np.linalg.svd(a,full_matrices=False,compute_uv=True)print(eigen_vals,sigma**2)
'''
[208.58666048   1.52969164  28.88364788] [208.58666048  28.88364788   1.52969164]
'''eigen_vecs
'''
array([[-0.34088613, -0.85005392, -0.40150339],[-0.72034757,  0.51060491, -0.46944862],[-0.60406625, -0.12919347,  0.78639241]])
'''v.T
'''
array([[-0.34088613, -0.40150339, -0.85005392],[-0.72034757, -0.46944862,  0.51060491],[-0.60406625,  0.78639241, -0.12919347]])
'''

使用PCA对mnist数据集降维

其实在这里遇到一个问题:使用eig对手写数字数据集的协方差矩阵求解特征值时得到了复数特征值和特征向量,这一点暂时没弄明白,但是使用svd可以得到正常的特征值和特征向量。

sklearn中的pca

from sklearn.decomposition import PCA
pca = PCA(n_components=2)
result = pca.fit_transform(data)

得到结果图

在这里插入图片描述

numpy手撕PCA

def PCA_numpy(X):#零均值化print(X.shape)X=X-X.mean(axis=0)## 使用特征值和特征向量#协方差矩阵#cov_X = np.cov(X,rowvar=0)#每一列一个特征#eig_val,eig_vec = np.linalg.eig(cov_X)   #出现复数了##使用svdU,eig_val,eig_vec = np.linalg.svd(X)#选两个最大的idx = np.argsort(-eig_val)temp_M=[]for i in range(2):temp_M.append(eig_vec[idx[i]])temp_M = np.array(temp_M).Tresult = np.dot(X,temp_M)return result

同样得到结果值

在这里插入图片描述

这个图里面每个颜色代表手写数字数据集里面的0-9数字。

ZCA白化

UFLDL中还介绍了基于PCA的白化(whitening或者球化sphering)方法,白化的目标有两个:

  • 特征之间具有尽量少的相关性
  • 特征具有相同的方差

针对第一个目标,前面的使用PCA降维x=uTxx=u^Txx=uTx已经达到了效果。

针对第二个目标,让每个输入特征值都具有单位方差(unit variance),只需要除以特征值的开根号即可:
xpcai=xiλix_{pcai}=\frac{x_i}{\sqrt{\lambda _i}} xpcai=λixi
降维数据的第i列对应第i个特征值。这时候,数据的协方差就是单位阵,这就是所说的PCA白化(数据的不同成分无联系并且具有单位方差)。

但是我们第二个目标其实是具有相同方差,而具有相同的单位方差并不是唯一的一个情况,也可能是具有相同的非单位方差。在ZCA白化中,又对pca白化做了一次左乘:
xzca=uxpcax_{zca}=ux_{pca} xzca=uxpca
这样虽然把方差不再是1了,但是变换后的数据更加接近原始数据。

有一点需要注意:PCA可以用于降维(取前面一部分主成分),但是zca必须保持原有的维度不变,zca只做去相关,不做降维。

后记

这个学习笔记主要是针对机器学习里面常见的降维方法PCA进行剖析和逐步实现,具体代码包括手写数字的读取和最终降维图的画图,请参看公众号简介中的github网址。后续将持续更新其它机器学习理论和算法,敬请关注:

在这里插入图片描述

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

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

相关文章

OpenCV使用Tensorflow2-Keras模型

前言 最近工作上需要在C上快速集成Tensorflow/Keras训练好的模型,做算法验证。首先想到的就是opencv里面的dnn模块了,但是它需要的格式文件比较郁闷,是pb格式的模型,但是keras通常保存的是h5文件,查阅了很多资料&…

3D人脸表情驱动——基于eos库

前言 之前出过三篇换脸的博文,遇到一个问题是表情那一块不好处理,可行方法是直接基于2D人脸关键点做网格变形,强行将表情矫正到目标人脸,还有就是使用PRNet的思想,使用目标人脸的顶点模型配合源人脸的纹理&#xff0c…

3D姿态估计——ThreeDPose项目简单易用的模型解析

前言 之前写过tensorflow官方的posenet模型解析,用起来比较简单,但是缺点是只有2D关键点,本着易用性的原则,当然要再来个简单易用的3D姿态估计。偶然看见了ThreeDPose的项目,感觉很强大的,所以把模型扒下来…

简易的素描图片转换流程与实现

前言 之前经常在网上看到用PS实现真实图片到素描图片的转换,但是流程都大同小异,身为一只程序猿,必须来个一键转化额。 国际惯例,参考博客: Photoshop基础教程:混合模式原理篇 颜色减淡的原理讲解以及应…

一个简单好用的磨皮祛斑算法理论和python实现

前言 最近看了一个磨皮算法祛斑感觉效果不错,效果图看文末就行,个人觉得效果非常不错滴。 国际惯例,参考博客: 磨皮算法的源码:YUCIHighPassSkinSmoothing How To Smooth And Soften Skin With Photoshop 图像算法…

OpenVINO——配置与道路分割案例

前言 最近看到了一个深度学习库OpenVINO,专门用于Intel硬件上部署深度学习模型,其内置了非常非常多使用的预训练模型,比如道路分割、人脸提取、3D姿态估计等等。但是配置和调用有点小恶心,这里以道路分割为例,展示如何…

图像颜色迁移《color transfer between images》

前言 前段时间,在深度学习领域不是有个比较火的方向叫风格迁移的嘛,对于我这种不喜欢深度学习那种不稳定结果的人来说,还是想看看传统图像处理领域有什么类似的技术,发现了一个颜色迁移的算法,很久前的论文了。 国际…

ColorSpace颜色空间简介

前言 如果看过之前的介绍的图像颜色迁移《color transfer between images》和颜色协调模型Color Harmoniztion就会发现,大部分图像处理算法虽然输入输出是RGB像素值,但是中间进行算法处理时很少直接更改RGB值,而是转换到其它空间&#xff0c…

Ogre共享骨骼与两种骨骼驱动方法

前言 最近业务中用到Ogre做基于3D关键点虚拟角色骨骼驱动,但是遇到两个问题: 身体、头、眼睛、衣服等mesh的骨骼是分开的,但是骨骼结构都是一样的,需要设置共享骨骼驱动的时候可以直接修改骨骼旋转量,或者将旋转量存…

仿射变换和透视变换

前言 在前面做换脸的博客中提到了使用仿射变换和透视变换将两张不同的人脸基于关键点进行对齐,保证一张人脸贴到另一张人脸时,大小完全一致;所以有必要理解一下这两个概念的区别,由于以实用性为目的,所以所有的图像算…

obj格式解析

前言 最近处理一些网格渲染的时候,需要解析Obj文件,从Free3D上随便找了个免费的人体obj模型解析测试一波 国际惯例,参考博客: 本文所使用的从Free3D下载的模型 .obj文件格式与.mtl文件格式 详解3D中的obj文件格式 3D中OBJ文…

Flask服务部署与简单内网穿透

前言 最近学习部署的时候,想到深度学习里面通常用的部署方法是flask做服务端,然后使用nginx做负载均衡,貌似也能做内网穿透。不过我不太懂负载均衡,只想利用本地电脑搭建一个简单的服务器,实现外部调用API服务的功能。…

OpenCV学习——轮廓检测

前言 轮廓检测是传统视觉中非常常用的功能,这里简单记录一下opencv中的轮廓检测算法使用方法,至于理论,后续有机会再去细品。 国际惯例: OpenCV官方的轮廓检测教程python版 OpenCV中的二值化方法教程 OpenCV轮廓层级官方文档…

RBF神经网络理论与实现

前言 最近发现有挺多人喜欢径向基函数(Radial Basis Function,RBF)神经网络,其实它就是将RBF作为神经网络层间的一种连接方式而已。这里做一个简单的描述和找了个代码解读。 之前也写过一篇,不过排版不好看,可以戳这里跳转 国际惯例&#x…

基于python和unity交互的卡通角色肢体和表情驱动(深度学习)

前言 最近看到了好多卡通角色的肢体驱动的东东,感觉是时候发挥一下读研时候学的东西了,而且虽然现在不炼丹了,但是还是得保持吃丹的技能。这个项目找了很多很多代码进行测试,最终集成了一个3D姿态估计和人脸关键点提取的代码。 …

OpenCV学习——形态学

前言 继续学习图像里面的形态学知识——结构元、腐蚀、膨胀、开运算、闭运算、击中/不击中变换。以及部分基本形态学算法,包括边界提取、空洞填充、连通分量的提取、凸壳、细化、粗化、骨架、裁剪、形态学重建。 其实就是对冈萨雷斯的《数字图像处理》中第9章节《…

径向基函数RBF三维网格变形

前言 之前写过径向基函数(RBF)神经网络做分类或者拟合。然后挖了个坑说在《Phase-Functioned Neural Networks for Character Control》里面提到了用于做地形编辑,所以这篇博客就是解析一下如何用RBF做网格编辑系统。 参考博客: Noe’s tutorial on d…

OBJ可视化——UV还原(修正)

前言 前面写过一篇obj格式解析的博客,但是这篇文章中可视化的工作是参考PRNet的源码进行的,后来细细思考了一下,有点问题,具体看下面。 问题来源 在PRNet源码的render.py中有个函数render_texture,是作者用于将uv展…

Unity中BVH骨骼动画驱动的可视化理论与实现

前言 找了很久使用BVH到unity中驱动骨骼动画的代码,但是都不是特别好用,自己以前写过,原理很简单,这里记录一下。 理论 初始姿态 在BVH或者其它骨骼动画中,一般涉及到三种姿势:A-pose,T-pos…

卡通驱动项目ThreeDPoseTracker——模型驱动解析

前言 之前解析过ThreeDPoseTracker这个项目中的深度学习模型,公众号有兄弟私信一些问题,我刚好对这个项目实现有兴趣,就分析一波源码,顺便把问题解答一下。 这个源码其实包括很多内容:3D姿态估计,坐标平滑…