看完了ICA的一整套原理介绍后,感觉完整的介绍和andrew ng的课程中的ICA特征提取关系不是很大;在ICA的理论中,主要用于盲源分离的,也就是混合的观测数据X,通过一个正交的且其范数为1的分离矩阵W(其实是实现旋转变换),分解为相互独立的原始信号数据S=WX。(这里要求S,W,X都为n*n的矩阵)

学习完成后自己有一些理解和不解。

数据处理

在实际的造作过程中,先通过均值削减和白化操作(也可通过PCA降维),把观测数据X变为一个,各个维数之间相互独立的新数据Z;让Z通过矩阵W分解为S,S=WZ;这样处理数据可以加快数据的收敛性;减低计算的复杂度。

模型转化

1,感觉利用极大似然估计算法时,利用sigmoid函数特有的性质,来近似代替原始数据的的概率分布Ps(t),感觉这个很神奇,以前只知道期望均值,可以用平均数来代替,例如本例中也通过均值来近似估计对数似然期望;没想到连概率密度函数都可以“蒙”;通过转化把一个函数优化问题,最后通过梯度下降算法来求解最优值。

2,利用负熵转化时,感觉这个也很神奇,通过信息论中熵的概念,中心极限定理,最大熵原理,KL散度,互信息定义出了变量间相互独立行的度量,通过度量目标函数,来优化找到最佳W。

ICA进行图像特征提取

下面该进入正题了,就是利用ICA进行图像特征提取了;在ICA提取提取图像特征,这里先引用一段tornadomeet的介绍:

在sparse coding模型中,学习到的基是超完备集的,也就是说基集中基的个数比数据的维数还要大,那么对一个数据而言,将其分解为基的线性组合时,这些基之间本身就是线性相关的。如果我们想要得到线性无关的基集,那么基集中元素的个数必须小于或等于样本的维数,本节所讲的ICA(Independent Component Analysis,独立成分分析)模型就可以完成这一要求,它学习到的基之间不仅保证线性无关,还保证了相互正交。

 ICA特征提取本质上是对原始数据X,通过矩阵W,来实现一个线性变换;这里要求W为正交阵,变换后数据Y(Y=WX)之间线性无关,且正交;而且可以通过变换W矩阵的维度,来控制学习的特征的个数。

 在模型变换上面,ICA特征提取并没有用上面提到的似然估计,熵等方法,而是通过类似autoencoder的方式,让自己和自己比较,是原始数据和重构数据误差达到最小;然后通过变换W矩阵,是W正交化。我们知道autoencoder是通过simoid(WX+B)来重构数据的,这个过程有两个变换,线性变换部分:WX+b;非线性部分:sigmoid部分;由于sigmoid非线性变换的存在,所以最后没有约束权值矩阵W必须为正交阵;所以通过autoencoder学习到的特征之间有相关性的。

所以利用ICA提取特征应该叫做,ICA autoencoder 或者 正交线性 autoencoder

ICA图像特征提取过程,由于tornadomeet大牛写的很好就直接copy了。

给出的代价函数却为:

   【机器学习】ICA特征提取_图像特征提取(线性重构误差)

代价函数的偏导公式(这样实现时,可以偷懒不用推导了),只不过它给出的公式有一个小小的错误,我把正确的公式整理如下:

   【机器学习】ICA特征提取_图像特征提取_02

  错误就是公式右边第一项最左边的那个应该是W,而不是它的转置W’,否则程序运行时是有矩阵维数不匹配的情况。

  4. 最后就是对参数W进行迭代优化了,由于要使W满足正交性这一要求,所以不能直接像以前那样采用lbfgs算法,而是每次直接使用梯度下降法进行迭代,迭代完成后采用正交化步骤让W变成正交矩阵。只是此时文章中所说的学习率alpha是个动态变化的,是按照线性搜索来找到的。W正交性公式为:

【机器学习】ICA特征提取_图像特征提取_03

  5. 如果采用上面的代价函数和偏导公式时,用Ng给的code是跑不起来的,程序在线搜索的过程中会陷入死循环。(线搜索没有研究过,所以完全不懂)。最后在Deep Learning高质量交流群内网友”蜘蛛小侠”的提议下,将代价函数的W加一个特征稀疏性的约束,(注意此时的特征为Wx),然后把Ng的code中的迭代次数改大,比如5000,

其它程序不用更改,即可跑出结果来。

稀疏代价函数:

   【机器学习】ICA特征提取_迭代_04

偏导为:

【机器学习】ICA特征提取_数据_05

其中一定要考虑样本的个数m,否则即使通过了代价函数和其导数的验证,也不一定能通过W正交投影的验证。

程序代码:

参见tornadomeet的博客

javascript:void(0)

其中有个错误:就是在orthonormalICACost.m函数中grad项的后面忘记除以样本总数num_samples了;如果不处理程序会陷入死循环。

应该是:

grad = ……+...

        (weightMatrix*patches./sqrt((weightMatrix*patches).^2+epsilon))*patches'/ num_samples