在看数字图像处理的压缩章节,突然看到PCA可以用来压缩图像,于是学乎。本文主要大致简单说下整个实验的过程和一些关键的点,详细和更好的解说在我给出的资料里面有。
压缩的一种方法论就是先将一张图片,一个信号的数据量进行某种分解,这种分解必须是有某种“compact”(紧凑)的特性,也就是说大部分的信息存在于少量的系数中,而像不是原始数据中的那样子简单均匀的分布。如果分解得好,压缩的时候只保留少量的数据量就可以保留几乎一张图片或者一个信号。这里是有损压缩,但是这种分解还原的方法也可以进行无损压缩。怎么做得到呢?如果我们不扔掉大部分不重要的系数,我们好像没有办法减少数据量啊?我们分解后系数比较小的那些我们可以用比较少的位数对其进行编码,这样子就可以较少数据量啦,而且这个过程没有损失掉即使很少的信息。我知道的分解有,傅里叶变换,小波变换,SVD分解(同本文的PCA,只不过是不同角度的)。
下一张用PCA进行分解压缩的图片,PCA首先分解为很多个系数乘以矩阵的形式,这些系数有大有小,我们用一小部分比较大的那些系数进行还原图像,可以看到取到了其中的30个系数得出图像已经非常好了,取到前50个系数的时候,几乎是看不出来有什么分别,这时数据压缩比是6.46%。
PCA叫做主成分分析,对这个名称最直观的感受我们可以来看下一个例子。两个绿色的点是两个向量的端点,原点是向量的起点,这两个向量几乎在同一条直线上,如果采用直角坐标系来表示这两组向量需要4个系数,这两个向量进行主成分分析之后得到一个新的单位正交基,如下图中的直角坐标系所示,如果用这个单位正交基来表示这两个向量。这两个新的单位正交基就是PCA中的主成分,从图中我们可以知道我们每个向量只要用一个基就可以很好地接近原始的向量。这就达到了降维的效果。
现实中我们采集数据存在很大的冗余度,如果不进行降维,计算的量是非常大的。比如一幅32*32人脸或者手写数字的图像,我们展开成1*1024维的向量后通过比对这些向量的接近程度来识别人脸或者手写数字(k近邻算法,参考《机器学习实战指南》第二章)。但是比对这1024维的数据计算量太大了,一个简单的降维方法是,你可以抽取只取图像偶数行数和偶数列数来构建一个新的低维向量,但是这样子降低的维数是比较少的,再继续进行几次这样子的操作,但在保证识别效果前提下,降低的维数是十分有限的。在后面的实验中,你可以看到我们只需取其中的50维,甚至20多维就可以得到很好的效果。反之在下面的这张1024个,我利用迭代取偶数行列的方式最后得到其中50个像素,你能通过计算机识别出是哪个数字吗?这种降维方式显然失去了很信息量。但是我们取出PCA分解出来的50多维数据确是各个数字的最“主”的主成分,信息量被很好地集中在这50维的数据里面。
于是我们就用这种方法来进行计算,首先是用PCA对训练数据求出主成分,保留其中一部分的主成分,降低了维数。在识别手写数字的时候,我们将上图中的手写数字0的图片当作向量a分解到0~9各自的取出的那部分主成分,然后再分别还原到原始的图像,还原回来的图像向量因为丢失了部分的维数,大多数情况下会跟原始的向量a有一些差别err,但这种差异如果分解在手写数字0的图片s训练出来的主成分理论上是最小的,因此我们可以从此识别出是数字0。
对比k近邻算法1024维近乎绝望的计算复杂度,这里我们只用了50多维进行计算,大大提高了计算效率。
两种算法的速度对比,接近10倍的差值,错误率确是相近的。
降低PCA计算的维度到大概20多,看计算速度是否有提升,错误率是否也上升,错误率没有进一步提升,然并卵。
再进行降维,降到个位数以内,奇迹出现了,错误率上升了一倍,但是计算的复杂度也下降了。
接着我们来看看算错的那些图片是图片奇葩还是算法不好?
这个测试库里面说是0,而算法测出来是4............
最后放上一些可能有用的链接: