Some methods of deep learning and dimensionality reduction

#Deep Learning 上一篇主要是讲了全链接神经网络,这里主要讲的就是深度学习网络的一些设计以及一些权值的设置。神经网络能够根据模型的层数,模型的复杂度和神经元的多少大体能够分红两类:Shallow Neural Network和Deep Neural Network。比较一下二者:git

Network Name Time complexity theoretical
Shallow Neural Network more efficient to train simple powerful enough
Deep Nerual Network need more time sophisticated more meaningful

虽说简单的神经网络训练时间短,可是目前经常使用的仍是deep,由于多层的神经网络有利于提取图像或者是语音的一些特征,取TensorFlow的minist数据集为例,一个手写字体的识别就是须要从图像中提取特征:
好比想要识别数字1和5,能够把数字的特征分开,每个不一样的神经元识别一部分,而后综合结果。这些都是像素点,因此每通过一层神经元就会从图像中提取特征。再对图片进行匹配和识别。层数越多,就能提取更加复杂的特征,解决一些sophisticated的问题能力也就越强。 ####①The challenge of deep learning 深度学习的挑战主要有这么几个问题: 1.difficult structural decisions。对于网络结构的设计很难把握,可是这是可使用一些相关领域的知识来作选择的。好比,作图像的识别,咱们可使用convolutional Network,由于卷积神经网络对于两个相邻的像素联系会很大,也就是说,对于一个像素,若是是用卷积神经网络,那么只会考察它周围的像素点的特征,而离他很远的像素是不会处理。对于语音识别,LSTM,RNN这些神经网络用的就比较多,由于他们能够保留以前的信息。 2.high model complexity。若是网络的层数不少,极可能会出现过拟合的状况,若是是数据量很是大的话,这种状况能够忽略。但若是数据量不大,那么有可能会出现过拟合。经常使用的解决过拟合的方法:drop out。训练神经网络的时候不所有训练,只是训练一部分,好比训练百分之70.denoising。这种方法后面会详解,主要就是假如一下杂讯一块儿训练。 3.hard optimization problem。对于神经网络的训练也有不少须要注意的,由于神经网络通过了多层的非线性转换,再也不是一个山谷状了,多是凹凹凸凸的,这样就致使有可能你只是到达了某一个山谷而不是全局的最优。这个时候咱们就要选择一个比较好的初始值了,若是咱们选择的初始值刚好就是在全局最优的旁边,那就稳了。有一种方法就是pre-train。 4.huge computational complexity。层数这么多,计算机复杂度看到很大。这里已经可使用硬件解决了,GPU的计算获得。
比较关键的其实就是 regularization和initialization。 ####②initialization 权值的初始值很重要,好的权值初始化是能够避免局部最优解的出现。比较经常使用的方法就是pre-train。 先用pre-train训练获得一层权值,这些权值就做为初始值,以后在backprob训练。
一层一层的来,第一层的出来了第二层的依次决定。 首先要介绍一个概念是 Autoencoder,自编码器。

###Autoencoder 什么是权重?在神经网络的模型里面权重表明的就是特征转换(feature transform)。从编码方面来讲,权重也能够当作是一种编码方式,把一个数据编码成另外一种数据。神经网络是一层一层的进行的,因此若是是一个好的权重的话,是应该能够提取出数据的特征的,也就是information-preserving encoding,一种能够保留有用信息的编码。第i层提取了特征,传到了i+1层,i+1层在i层的基础上再提取一些更加复杂的特征,传到i+2层。最后每一次均可以提取出特征来,这样就能够最大限度的把数据的特征保留下来。上面讲到的手写数字识别是能够把一个数字划分红不少个笔画,反过来,也能够由特征转换回数字。这种可逆的转换叫作information-preserving,经过神经网络转换的特征最后是能够转换回原来的输入,这也正是pre-train要作到的。因此pre-train要知足的特征就是要求information-preserving。由于拿到了特征又能够用获得的特征获得原输入,证实获得的特征是能够表明整个数据的,没有遗漏。github

想要获得这样的效果,只须要创建一个三层的神经网络便可。
这个神经网络通过权重$$W_{ij}^{1}$$获得的结果就是encode以后的数据,也就是经过feature transform提取特征的过程,通过$$W_{ji}^2$$的就是解码过程,要求输出层输出的数据要和原数据差很少接近。整个网络是$$d - d' - d$$的结构,重点就在重构,输入层到隐含层是特征转换,隐含层到输出层是重构。这种结构咱们叫autoencode,对应编码和解码,整个过程就是在逼近indentity function(恒等函数)
可是这样好像画蛇添足,既然输出都是差很少的为何要画蛇添足?对于监督式学习,隐藏层其实就是特征转换,乘上一些权值转换成对应特征的值。就好像手写数字识别获得每个数字的特征,包含了一些提取出有用的特征,能够获得一些数据具备表明性的信息。对于非监督的学习,也可使用autoencode来作density estimation,密度估计,若是$$g(x) ≈ x$$密度较大,说明能够提取到的特征不少,不然就是密度很小。也能够作outlier detection,异常值的检测,也就是孤立点,噪音。找出哪些是典型的资料,哪些不是。
对于编码器,咱们更加关心的实际上是中间的隐藏层,也就是特征转换权重$$W_{ij}^{(1)}$$天然对应的error function:$$\sum_{i=1}^d(g_i(x) - x_i)^2$$
三层的autoencode也叫basic autoencode 由于它是最简单的了。一般限定$$d' < d$$方便数字的编码,数据集能够表示为$$(x_1, y_1 = x_1) (x_2, y_2 = x_2)(x_3, y_3 = x_3)......$$因此能够当作是一个非监督式的学习,一个重要的限制条件是$$W_{ij}^{(1)} = W_{ji}^{(2)}$$ 解码权重等于编码权重,这起到了regularization的做用。
深度学习中,basic autoencoder的过程也就对应着pre-training的过程,使用这种方法,对无label的原始数据进行编码和解码,获得的编码权重$$W_{ij}^{(1)}$$就能够做为pre-trained的比较不错的初始化权重,也就是做为深度学习中层与层之间的初始化权重。
因此,pre-train的训练过程:首先,autoencoder会对深度学习网络第一层(即原始输入)进行编码和解码,获得编码权重$$W_{ij}^{(1)}$$,做为网络第一层到第二层的的初始化权重;而后再对网络第二层进行编码和解码,获得编码权重W(1)ij,做为网络第二层到第三层的初始化权重,以此类推,直到深度学习网络中全部层与层之间都获得初始化权重。值得注意的是,对于l-1层的网络$${{x_n^{l-1}}}$$,autoencoder中的d˘应与下一层(即l层)的神经元个数相同。
这里介绍的只是一种最简单的,还有不少的编码器,稀疏编码器,去燥编码器等等。 ####②regularization 控制模型的复杂度就是使用正则化了。
神经网络每一层都有不少的权重和神经元,这就致使了模型的复杂度会很大,regularization是必要的。 咱们以前介绍过一些方法: 1.structural decisions。架构能够设计的简单点,可是深度学习神经网络的结构是不可能简单的,这辈子的不可能。只能是相对来讲用dropout减轻一些压力。2.weight decay or weight elimination regularizers。可使用正则化来减少权值。 3.early stop。不要训练的这么准确,差很少差很少就够了。
下面是一种新的regularization的方式:

###Denoising Autoencoder 回顾一下以前的overfit的缘由: 算法

和样本数量,噪声大小都有关系,若是数据量是不变的,那么noise的影响就会很是大。那么这个时候实现regularization的一个方法就是消除noise的影响。 有一种方法是对数据clean操做,可是这样费时费力。有一种更加牛逼的作法,就是在数据中添加一些noise再训练。
这种作法的初衷是想创建一个比较健壮,容错性高的autoencode。在一个已经训练好的autoencode中,g(x) ≈ x的,对于已经容错性很高,比较健壮的autoencode,获得的输出是和x很接近的。好比手写数字识别,一个很规范很正的6输进去能够获得一个6,可是若是原始的图片是歪歪的6,而后仍是能够获得6的话那么这个自编码器就是一个健壮的自编码器了。比较不是每个人写6都是写的正正,这就使得这个自编码器的抗噪能力很强。 因此,最后咱们要训练的样本集$$(x_1',y_1 = x_1),(x_2',y_2 = x_2),(x_3',y_3 = x_3)......$$ 其中$$x_n' = x_n + noise$$ 因此使用这种autoencode的目的就是使得加入了有噪音的x均可以获得纯净的x。不只能从纯净的样本中编解码获得纯净的样本,还能从混入noise的样本中编解码获得纯净的样本。这样获得的权重初始值更好,由于它具备更好的抗噪声能力,即健壮性好。实际应用中,denoising autoencoder很是有用,在训练过程当中,输入混入人工noise,输出纯净信号,让模型自己具备抗噪声的效果,让模型健壮性更强,最关键的是起到了regularization的做用。这也是以前说的去燥自编码器。
#linear autoencode 刚刚介绍的自编码器是非线性的,由于中间的tanh(x)函数就是非线性的。常见的autoencode经常使用于在深度学习中,这里要介绍的是线性的自编码器,linear autoencode。对于一个线性的自编码器,只须要不包括非线性转换就行了。 因此,就变成$$h_k(x) = \sum_{j = 0}^{d'}W_{jk}^{(2)}\sum_{i = 0}^{d}W_{ij}^{(1)}$$ 这里有三个限制条件: ①移除bias项,保持维度一致。 ②编码权重与解码权重一致:$$W_{ij}^{(1)} = W_{jk}^{(2)} = W_{ij}$$ ③$$d' < d$$ 因为两个权重是同样的,W的维度是dxd',x的维度是dx1,因此整个公式能够变为:$$h_k(x) = WW^Tx$$ 可是要求$$h(x) = x$$ 因此error function$$E_{in}(h) = E_{in}(W) = \frac{1}{N}\sum_{n=1}^{N}|x_n - WW^Tx_n|^2 with(dxd')W$$ 对于那个协方差矩阵首先能够进行特征值分解$$WW^T = VΓV^T$$其中Γ是一个对角矩阵,V矩阵知足$$VV^T = I_d$$ 而I矩阵有一个很重要的性质,因为W是dxd'的,d < d’。有I的非零元素的数量是不大于d'的。

###证实 对于一个矩阵W(dxd',d < d'),那么有Rank(W) <= d'。这个结论直接给出,不用证实。假设有两个矩阵A,B,C = AB,那么AX = C的解就是B,也就是惟一解,也就是说Rank(A, C) = Rank(A )。证实:对于Rank(A,C)和Rank(A)无非就是两种状况,=和>。<是没有的,Rank(A)是不可能大于Rank(A,C)的。若是是Rank(A) < Rank(A,C),那么这个增广矩阵(A,C)变换成初等矩阵以后,最后一行就会出现$$[0,0,0,0,a]$$的状况,0 != a,天然就是无解了。因此证实了上诉状况必定是有Rank(A) = Rank(A,C) 而因为R(C) <= R(A,C),因此R(C) <= R(A),同理,也能够证实得R(C) <= R(B),而在这里$$A = W,B = W^T,C = WW^T$$因此,$$rank(WW^T)$$是不大于d'的,由于一个矩阵的秩是不能够大于它最小的维度的。$$Rand(W) = Rank(W^T) <= d'$$综上所诉,$$Rank(WW^T) <= d'$$更重要的是,秩就是这个矩阵特征值的数量,而I矩阵的斜对角线就是WW^T矩阵的特征值,因此才有I的非零元素的数量是不大于d'的。bash

回到正文。$$VV^T = I => VIV^T = I $$那么就能够推出$$x_n = VIV^Tx_n$$ 网络

这样就把表达式转换成了一个求解V和Γ的方程:$$min_vmax_Γ\frac{1}{N}\sum_{n=1}^{N}|VIV^Tx_n - VΓV^Tx_n|^2 $$提取一下公因式$$min_vmax_Γ\frac{1}{N}\sum_{n=1}^{N}|VV^Tx_n(I - Γ)|^2$$ 因此第一个要解决的就是$$minimum(I - Γ)$$这样天然是越接近越好了,因此Γ最好就是对角线上有d'个1。
到这里Γ的最优解已经知道了
最小化问题有点复杂,转换一下:
当d' = 1的时候,那就只有V的第一行是有用,因此
条件是在作特征分解的时候获得的,这里也要继承下来。 有条件的天然是拉格朗日乘子法了:$$L(v) = max_v(\sum_{n=1}^{N}v^Tx_nx_n^Tv + λ(v^Tv - 1))$$ 求导得0$$\sum_{n=1}^{N}x_nx_n^Tv = λv$$ 仔细看一下,这个λ其实就是$$x_nx_n^T$$的特征值 既然d' = 1是这样了,那么当d' > 1的时候,就是依次把d'个特征值求出来就行了,因此这个就是linear autoencoder的过程了。
过程和PCA很类似,大体都是差很少的,可是PCA还须要减去一下平均值,也就是对x输入数据作去均值化的处理。
linear autoencode和PCA不彻底同样,至少出发点不是同样的,linear autoencode是用来pre-train而被发明的,虽然机器学习不太须要,可是既然引出了非线性的autoencode那顺便把linear也探讨一下。可是,linear autoencode在公式的推导上是基本一致的,上面的推导其实也是能够作为PCA的推导。 #Dimensionality Reduction——Principal Component Analysis 既然讲到了降维,那顺便把PCA也讲了,Deep Learning的部分已经讲完。 ####①数据降维 一般咱们获得的数据有不少的维度,好比一个商店,能够有名字,年龄,出生日期,性别,成交量等等。而年龄和性别实际上是表示一个东西,两个表示彻底是多余的。固然咱们也能够直接不作处理就使用这些数据来作机器学习。可是这样会耗费巨大的资源。在这种状况下天然就须要数据降维了。降维意味着会有数据丢失,丢失是必定会有的,因此只能保证丢失了多少而已。 举个例子,假如某学籍数据有两列M和F,其中M列的取值是如何此学生为男性取值1,为女性取值0;而F列是学生为女性取值1,男性取值0。此时若是咱们统计所有学籍数据,会发现对于任何一条记录来讲,当M为1时F一定为0,反之当M为0时F一定为1。在这种状况下,咱们将M或F去掉实际上没有任何信息的损失,由于只要保留一列就能够彻底还原另外一列。 ####②向量和基 先看一个向量的运算:$$(a_1,a_2,a_3...a_n)^T(b_1,b_2,b_3...b_n)^T = a_1b_1+a_2b_2+a_3b_3...+a_nb_n$$ 这种乘积方式并不能看出有什么意义,换一种表达方式$$A*B = |A||B|cos(a)$$a为A和B的夹角。再进一步|B| = 1,那么就能够看出来,**当向量B的模为1,则A与B的内积值等于A向B所在直线投影的矢量长度。**这个结论很重要。 假设有一个点(3,2),那么在坐标系中的表示:
向量(3,2)就从原点发射到(3,2)这个点的有向线段。在x轴上的投影值是3,在y轴上的投影值是2。也就是说咱们其实隐式引入了一个定义:以x轴和y轴上正方向长度为1的向量为标准。因此向量(x,y)其实是一种线性组合:$$x(1,0)^T+y(0,1)^T$$而(1,0)和(0,1)就是这个空间里面的一组基。
**因此,能够用另一种方法来描述,肯定一组基,而后给出在基所在的各个直线上的投影值,就能够了。不过通常直接忽略第一步,比较可靠维度就知道了。可是事实上,基并非一个固定的东西,任何一个线性无关的向量均可以成为一组基。**例如,(1,1)和(-1,1)也能够成为一组基。通常来讲,咱们但愿基的模是1,由于从内积的意义能够看到,若是基的模是1,那么就能够方便的用向量点乘基而直接得到其在新基上的坐标了!实际上,对应任何一个向量咱们总能够找到其同方向上模为1的向量,只要让两个份量分别除以模就行了。 ####③基变换的矩阵表示 仍是拿上面的(3,2)作为例子,好比咱们如今有两个基$$(\frac{1}{\sqrt{2}},\frac{1}{\sqrt{2}}),(-\frac{1}{\sqrt{2}},\frac{1}{\sqrt{2}})$$ 那么把(3,2)变为新的基上的坐标,则有

\left[
 \begin{matrix}
   \frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}}\\
   -\frac{1}{\sqrt{2}} & \frac{1}{\sqrt{2}} \\
  \end{matrix}
  \right] 
\left[\begin{matrix}
3\\
2\\
\end{matrix}
\right] = 
\left[\begin{matrix}
\frac{5}{\sqrt{2}}\\
-\frac{1}{\sqrt{2}}\\
\end{matrix}
\right]

因此,通常的,若是咱们有M个N维向量,想将其变换为由R个N维向量表示的新空间中,那么首先将R个基按行组成矩阵A,而后将向量按列组成矩阵B,那么两矩阵的乘积AB就是变换结果,其中AB的第m列为A中第m列变换后的结果。 架构

这里是R是要变换的维度,R是能够小于N的。 基于以上的理论,两个矩阵相乘的意义是将右边矩阵中的每一列列向量变换到左边矩阵中每一行行向量为基所表示的空间中去 ####④协方差 上面讨论了基已经坐标基于基的变换,若是基的数量是小于数据维度的就能够达到降维的效果了。 可是,问题来了,基是无限多个的,如何选择基是一个很大的问题。 举一个例子:

\left[
 \begin{matrix}
  1&1&2&4&2\\
  1&3&3&4&4\\
  \end{matrix}
  \right] $$为了处理方便,首先先减去每行的均值,这样作的缘由后面再说。减去以后就是这样:
$$\left[
 \begin{matrix}
  -1&-1&0&2&0\\
  -2&0&0&1&1\\
  \end{matrix}
\right]

问题来了,这5个数据都是2维度的,如今想降到一维,若是咱们必须使用一维来表示这些数据,又但愿尽可能保留原始的信息,你要如何选择?这个问题其实是要在二维平面中选择一个方向,将全部数据都投影到这个方向所在直线上,用投影值表示原始记录。这是一个实际的二维降到一维的问题。 一种直观的见解是:但愿投影后的投影值尽量分散。同一个维度数据之间不"挤"在一块儿,由于挤在一块儿表达不了数据自己了。而表征数据之间离散程度,就考虑到了方差。具体作法就是 想办法让高维数据左乘一个矩阵,获得降维后的数据,降维后的数据的方差最大化。在线性代数中学过,一个矩阵能够当作是不少个列向量,每个向量表明着一个物体的数据。要表达这个矩阵真的须要这么多数据吗,显然不必定,求解一个矩阵的秩R,看看R 的值,在绝大多数状况下,矩阵都不是满秩的,说明矩阵中的元素表达客观世界中的物体有一些是多余的。 既然是求离散程度,那么就是方差了,对于每个字段的方差$$Var(a) = \frac{1}{m}\sum_{i=1}^{m}(a_i - u)^2$$若是已经去除了均值那就能够直接转换$$Var(a) = \frac{1}{m}\sum_{i=1}^{m}(a_i)^2$$ 对于上面二维降成一维的问题来讲,找到那个使得方差最大的方向就能够了。不过对于更高维,还有一个问题须要解决。考虑三维降到二维问题。与以前相同,首先咱们但愿找到一个方向使得投影后方差最大,这样就完成了第一个方向的选择,继而咱们选择第二个投影方向。可是若是第二次仍是坚持选择方差最大的方向,那么确定仍是会和第一个方向相同的,这样表达的信息颇有可能重合,因此应该要加上一些限制。从直观上说,让两个字段尽量表示更多的原始信息,咱们是不但愿它们之间存在(线性)相关性的,由于相关性意味着两个字段不是彻底独立,必然存在重复表示的信息。 事实上两个字段的相关性是能够用协方差来表示。$$Cov(a,b) = \frac{1}{m}\sum_{i=1}^{m}a_ib_i$$协方差为0的时候,两个字段是互相独立的。协方差为0因此只能在一个基的正交方向选择第二个基。将一组N维向量降为K维(K大于0,小于N),其目标是选择K个单位(模为1)正交基,使得原始数据变换到这组基上后,各字段两两间协方差为0,而字段的方差则尽量大(在正交的约束下,取最大的K个方差)。 ####⑤协方差矩阵的优化 协方差矩阵的对角线表明了原来样本在各个维度上的方差,其余元素表明了各个维度之间的相关关系。因此咱们须要把协方差对角化,由于咱们须要处理的就是维度中的关系,而不是维度之间的。设Y=PX,则Y为X对P作基变换后的数据。设Y的协方差矩阵为D,则有: dom

因此如今明白了,咱们要找的P就是使得能够对角化C的矩阵,最后按照获得的对角矩阵从大到小排列,取P的前k行做为基进行转换便可。这其实就是求解特征值的过程。

总结:一开始对数据进行降维操做,咱们想到的就是要使得数据投影以后方差最大,那么就须要寻找一组基使达成这个条件。可是发现若是只是找最大的方差是会有重复,好比第一个发现的基是最大的,那么第二个方向确定也差很少是这个方向,这样信息就有重复,因此又至关数据维度之间是应该有非相关性的,因而就使用到了协方差来表明,可是咱们须要的是数据里的非相关性最大化,数据间的最大化方差最大已经处理了,因此这个时候协方差只须要关注对角线,天然就是对角化了。又发现对角化其实就是特征分解的一个过程,最后求出结果。 另外一个方面,W咱们能够看作是基的组合,WX就是降维以后的数据$$|x - ww^Tx|^2$$就是要求了降维以后的数据要和原来的数据相差不远,为何不是X-WX呢?首先这两个东西不是同纬度的,不可能计算,其次乘上一个转置其实就是转换回来的结果了。若是压缩以后转换回来的结果和原来差很少,那不就证实了这个降维是OK的吗?因此这就和Autoencode的思想同样了,因此上面linear autoencode的过程也能够看作就是PCA的公式化推导。 ####⑤PCA算法过程: ①将原始数据按列组成n行m列矩阵X ②均值化操做。 ③求协方差 ④求特征值特征向量 ⑤排列取前k大的特征值对应的特征向量 ⑥降维操做 #Coding ####Autoencode 编码器有几个很重要的特征: ①编码器是数据相关的,这就意味着只能压缩那些和训练数据相关的数据,好比用数字的图像训练了而后有跑去压缩人脸的图片,这样效果是不好的。 ②编码器不管是训练多少次,都是有损的。 ③自动编码器是从数据样本中自动学习的,这意味着很容易对指定类的输入训练出一种特定的编码器,而不须要完成任何新工做 ####Tool 先介绍一下工具类:机器学习

import numpy as np
from keras.datasets import mnist
import matplotlib.pyplot as plt
def get_dataSets():
    (x_train, _), (x_test, _) = mnist.load_data()
    x_train = x_train.astype('float32')/255.
    x_test = x_test.astype('float32')/255.
    x_train = x_train.reshape(len(x_train), np.prod(x_train.shape[1:]))
    x_test = x_test.reshape(len(x_test), np.prod(x_test.shape[1:]))
    return x_train, x_test
    pass
复制代码

首先是引入数据,mnist.load_data()这个数据导入有点问题,上网百度了一下发现百分之90的博客都是有问题本身下的,因此不例外我也是本身下载了4个压缩包放在了当前目录data下面。 获得数据时候先进行归一化操做,而后reshape,由于后面一开始用到的是单层的编码器,用的全链接神经网络,因此应该变成是二维的数据。函数

def show(orignal, x):
    n = 10  # how many digits we will display
    plt.figure(figsize=(20, 4))
    for i in range(n):
        ax = plt.subplot(2, n, i + 1)
        plt.imshow(orignal[i].reshape(28, 28))
        plt.gray()
        ax.get_xaxis().set_visible(False)
        ax.get_yaxis().set_visible(False)

        ax = plt.subplot(2, n, i + 1 + n)
        plt.imshow(x[i].reshape(28, 28))
        plt.gray()
        ax.get_xaxis().set_visible(False)
        ax.get_yaxis().set_visible(False)
    plt.show()
复制代码

这个函数用于显示,传入的参数是原始图像和预测的图像。好像都蛮直观的。 虽然每一种编码器都是用了一个类来封装,可是每个只有应该create方法,返回一个已经训练好的autoencode,因此下面全部的代码都是在create里面。 ####①单层自编码器 单层自编码器就是以前说的最简单的base autoencode。使用Keras实现。 所有都封装在一个类里面,用类的create函数返回一个已经训练好的autoencode。使用的数据集是mnist数据集。工具

def create(self):
        x_train, x_test = get_dataSets()
        encoding_dim = 32
        input_img = Input(shape=(784,))
复制代码

获得数据,隐藏层神经元的数量,入口函数。

encoded = Dense(encoding_dim, activation='relu')(input_img)
        decoded = Dense(784, activation='sigmoid')(encoded)
复制代码

编码层,最后那个小括号里面(input_img)就是输入的内容了,解码层就是从encoded输入。Dense里面定义的是当前层的神经元,decoded层输出了,天然就是784 = 28 x 28个了。

autoencoder = Model(input=input_img, output=decoded)
        encoder = Model(input=input_img, output=encoded)
        encoded_input = Input(shape=(encoding_dim,))
        decoder_layer = autoencoder.layers[-1]
        decoder = Model(input=encoded_input, output=decoder_layer(encoded_input))

复制代码

接下来的这几个就是获得完整的模型,使用Keras的Model API来构建。下面的几个就是encoder获得编码层,获得解码层。都很直观。

autoencoder.compile(optimizer='adadelta', loss='binary_crossentropy')
        autoencoder.fit(x_train, x_train,
                        epochs=50,
                        batch_size=128,
                        shuffle=True,
                        validation_data=(x_test, x_test))
        return autoencoder, encoder, decoder
复制代码

以后就是模型的编译,模型的训练了。 最后的效果:

事实上仍是能够的,达到了要求。 ####②多层自编码器 其余差很少同样,就是多了几层。

input_img = Input(shape=(784,))
        encoded = Dense(128, activation='relu')(input_img)
        encoded = Dense(64, activation='relu')(encoded)
        encoded = Dense(32, activation='relu')(encoded)

        decoded = Dense(64, activation='relu')(encoded)
        decoded = Dense(128, activation='relu')(decoded)
        decoded = Dense(784, activation='sigmoid')(decoded)

        autoencoder = Model(input=input_img, output=decoded)
        autoencoder.compile(optimizer='adadelta', loss='binary_crossentropy')
        autoencoder.fit(x_train, x_train,
                        epochs=1,
                        batch_size=128,
                        shuffle=True,
                        validation_data=(x_test, x_test))
复制代码

中间那几层获得编码层的那些去掉了。最后看看效果。

损失函数这些就不放了,由于训练的话是很容易给出的。 ####③稀疏自编码器 **稀疏自编码器通常用来学习特征,以便用于像分类这样的任务。稀疏正则化的自编码器必须反映训练数据集的独特统计特征,而不是简单地充当恒等函数。以这种方式训练,执行附带稀疏惩罚的复制任务能够获得能学习有用特征的模型。**使用L1范式惩罚项就行了,可是效果不太好,就不放结果了。

encoded = Dense(encoding_dim, activation='relu',
                        activity_regularizer=regularizers.l1(10e-5))(input_img)
        decoded = Dense(784, activation='sigmoid')(encoded)
复制代码

####④卷积自编码器 其实就是卷积神经网络作编码而已。

x_train = np.reshape(x_train, (len(x_train), 28, 28, 1))
 x_test = np.reshape(x_test, (len(x_test),28, 28, 1))
复制代码

数据格式要正确,由于是卷积处理了,要按照(个数,长,宽,颜色)排列。

input_img = Input(shape=(28, 28, 1))
        x = Convolution2D(16, (3, 3), activation='relu', border_mode='same')(input_img)
        x = MaxPooling2D((2, 2), border_mode='same')(x)
        x = Convolution2D(8, (3, 3), activation='relu', border_mode='same')(x)
        x = MaxPooling2D((2, 2), border_mode='same')(x)
        x = Convolution2D(8, (3, 3), activation='relu', border_mode='same')(x)
        encoded = MaxPooling2D((2, 2), border_mode='same')(x)

        x = Convolution2D(8, (3, 3), activation='relu', border_mode='same')(encoded)
        x = UpSampling2D((2, 2))(x)
        x = Convolution2D(8, (3, 3), activation='relu', border_mode='same')(x)
        x = UpSampling2D((2, 2))(x)
        x = Convolution2D(16, 3, 3, activation='relu')(x)
        x = UpSampling2D((2, 2))(x)
        decoded = Convolution2D(1, (3, 3), activation='sigmoid', border_mode='same')(x)
复制代码

encode和decode是两个对应的东西,反着来而已,因为是一个图片一个图片的进来,因此输出就是一个。

autoencoder = Model(input_img, decoded)
        autoencoder.compile(optimizer='adadelta', loss='binary_crossentropy')
        autoencoder.fit(x_train, x_train, epochs=20, batch_size=256,
                           shuffle=True,
                            validation_data=(x_test, x_test))
        return autoencoder
复制代码

最后就是常规操做了。 这个训练时间有点长,电脑不行没办法。效果:

最后损失到了0.10,仍是很好的。 ####⑤去噪编码器 这个是在卷积神经网络的基础上作的。用带噪音的数据来训练。

def get_nosing(noise_factor):
    (x_train, _), (x_test, _) = mnist.load_data()
    x_train = x_train.astype('float32') / 255.
    x_test = x_test.astype('float32') / 255.
    x_train = np.reshape(x_train, (len(x_train), 28, 28, 1))
    x_test = np.reshape(x_test, (len(x_test), 28, 28, 1))

    noise_factor = noise_factor
    x_train_noisy = x_train + noise_factor * np.random.normal(loc=0.0, scale=1.0, size=x_train.shape)
    x_test_noisy = x_test + noise_factor * np.random.normal(loc=0.0, scale=1.0, size=x_test.shape)
    x_train_noisy = np.clip(x_train_noisy, 0., 1.)
    x_test_noisy = np.clip(x_test_noisy, 0., 1.)
    return x_train, x_train_noisy, x_test, x_test_noisy
    pass
复制代码

时间就是使用高斯分布来获得了。

x_train, x_train_noisy, x_test, x_test_noisy = get_nosing(0.5)
        input_img = Input(shape=(28, 28, 1))
        x = Convolution2D(32, 3, 3, activation='relu', border_mode='same')(input_img)
        x = MaxPooling2D((2, 2), border_mode='same')(x)
        x = Convolution2D(32, 3, 3, activation='relu', border_mode='same')(x)
        encoded = MaxPooling2D((2, 2), border_mode='same')(x)

        x = Convolution2D(32, 3, 3, activation='relu', border_mode='same')(encoded)
        x = UpSampling2D((2, 2))(x)
        x = Convolution2D(32, 3, 3, activation='relu', border_mode='same')(x)
        x = UpSampling2D((2, 2))(x)
        decoded = Convolution2D(1, 3, 3, activation='sigmoid', border_mode='same')(x)

        autoencoder = Model(input_img, decoded)
        autoencoder.compile(optimizer='adadelta', loss='binary_crossentropy')
        autoencoder.fit(x_train_noisy, x_train, shuffle=True,epochs=1, batch_size=128,
                        validation_data=(x_test_noisy, x_test))
        return autoencoder

复制代码

这里的网络有些许不一样,是由于便于计算罢了。过程是同样,扔的数据不一样而已。效果:

####PCA PCA就不用mnist数据集了,毕竟784维降到2维不是很好看,使用iris数据集。 获取数据那些就不写了,毕竟蛮简单的。

class pca(object):
    def fit(self, data_features, y):
        data_mean = np.mean(data_features, axis=0)
        data_features -= data_mean
        cov = np.dot(data_features.T, data_features)
        eig_vals, eig_vecs = np.linalg.eig(cov)
        eig_pairs = [(np.abs(eig_vals[i]), eig_vecs[:, i]) for i in range(len(eig_vals))]
        a = np.matrix(eig_pairs[0][1]).T
        b = np.matrix(eig_pairs[1][1]).T
        u = np.hstack((a, b))
        data_new = np.dot(data_features, u)
        return data_new
    def show(self, data_new):
        plt.scatter(data_new[:, 0].tolist(), data_new[:, 1].tolist(), c='red')
        plt.show()
    pass
复制代码

步骤其实很简单,均值化求特征值排序组合向量基对原数据作乘法。

最后降维效果。

####最后附上GitHub代码:github.com/GreenArrow2…

相关文章
相关标签/搜索