深度学习系列(三):简单网络的自编码学习

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/on2way/article/details/50095081

本节将研究深度学习网络权值设计的重要思想之一:自编码思想,在正式介绍之前先以一个简单的介绍一篇,一层隐含层网络的自编码学习问题。

什么是自编码?所谓自编码就是自己给自己编码,再简单点就是令输出等于输入自己。以一个简单三层网络为例如下:
这里写图片描述
这里我们假设输出等于输入来训练这个网络参数(可能训练好的网络参数不可能让输出百分百等于输入,至少会非常接近吧)。那么这个网络在输入确定了以后(这时输出也就确定了吧),唯一需要确定的就是隐含层的个数了吧,以上述这个图为例,我们可以看到,网络的输入与输出都是一个6维的向量,而隐含层是3个,也就是3维。

那么这种自编码有什么意义呢?它又有什么用呢?可以看到,自编码可以使得网络通过学习转化成一组另外的量,这组量又可以通过译码恢复成原始的量,这样一来一回的过程看上去没什么用,但是你把分开着来看就会发现很有用,原始的量可以通过编码映射成另一组量吧,这一组量既然可以通过译码恢复成原始的量,说明了什么?中间这一层的输出是不是就是原始输入的另外一种表达了?是的。这就好比一个人,你看得到时候直接看就是一个人,当你看不到人的时候,比如说你听到了他的名字,你也知道这个名字表示的就是这个人。所以这个名字就是这个人的另一种条件下的新特征,而往往这种新特征更能去分这个人是谁。

好了再看看上面这个图,输入6维,隐含层以后变成了3维,输出还是6维,我们单看到隐含层发现了什么?是不是输入从6维降到了3维?但是这3为在某种意义上还是原始数据的典型特征吧,言外之意是不是相当于降维了。如果知道主成分分析法(PCA)的人应该了解,pca方法其实就是实现数据降维的,那么在这里我们通过这种自编码,规定隐含层神经元的个数以后,通过自编码的训练,让网络的输出尽可能的等于输入,待自编码完成后(也就是误差达到可接受范围),那么输入通过隐含层的输出就相当于降维了吧(前提是隐含层的神经元个数要小于输入维数,这样才叫降维,否则的话叫升维),说到升维,了解PCA的朋友你们有没有试过PCA升维呢?PCA能不能升维呢?哈哈,貌似不能,没试过。但是理论上是可以的。那么升维相当于将信息复杂化,这种操作有没有用呢?可能还是有用的吧,了解SVM的朋友知道,SVM里面就有将非线性数据通过升维以后可以在线性范围内可分,那么这里的升维是不是也能将原始非线性的数据变到线性呢?可以去试试看,应该有那么个意思。

好了说了这么多,我们还是来看降维的情况,通过自编码实现数据的降维思想最初是2006年深度学习领域大牛Hinton想出来的,并且发表在顶级期刊Science上,文章的出处在这里:

“reducing the dimensionality of data with neural networks”

该篇经典之作也被视为深度学习的开山之作,自此以后深度学习火了起来,并且逐渐打败传统模式识别领域的浅层学习算法。我们知道,机器学习或者模式识别,对数据的主要工作在做什么?无非提取数据的主要特征,那么以前可能所有的特征要么是人为设计出来,要么是浅层学习出来的,像PCA,他们虽然一定程度上有用,但是相对于深度学习这种将数据的各个层次的特征都学习出来了的相比自然弱了不少,这也是深度学习的最强大之处。

了解了自编码,下面我们来实际看看这种自编码的效果。
这里以matlab平台实验,假设我们选取一系列小块图像(至于小块选多大,这里考虑速度原因,单台笔记本的计算原因,选择6*6的小块图像,其实这是很小了,所以效果不是很明显,大概这个意思)作为输出来进行三层网络的自编码学习,然后看看隐含层学习到的特征是什么。选择matlab是因为它自带神经网络的构造函数便于实验,关于其神经网络工具箱的使用介绍,看这篇

机器学习之实战matlab神经网络工具箱

好了开始实验吧,首先我们需要找到自编码的输入样本,这里我们以每个6*6的小块图像作为一个样本,先准备好很多这样的小块图像,假设准备1000个吧,至于怎么准备,你可以让每个小块假设是从某个大图像上随机截取的好了。

clc
clear
%选择块图像的大小
patch = [6,6];
%选择块图像的个数
num_pic = 1000;
data = zeros(num_pic,patch(1)*patch(2));
for i = 1:20
    pic_name = [num2str(i),'.jpg'];
    I = imread(pic_name);
    I = rgb2gray(I);
    for j = 1:50
        %随机选择块的位置
        choose_row = round((size(I,1) - 50)*rand);
        choose_col = round((size(I,2) - 50)*rand);
        %提取块并存起来
        I_patch = I(choose_row+1:(choose_row+6),choose_col+1:(choose_col+6));
        data((i-1)*50+j,:) = I_patch(:);
    end
end
%归一化到0-1
data = mapminmax(data, 0, 1);
save data.mat data        

然后把这些样本既当成输入,也当成输出输送到神经网络中,比如这里我们就得到了1000*36的样本,每一行一个6*6的块,1000个这样的块,输出也是1000*36,就这样。接着就可以训练了,这里我们再取100个隐含层。那么假设训练好了。我们怎么可视化这个结果呢?因为我们需要看的是它自编码的编码部分,而不是译码部分,所以我们只关心编码部分的权值,像下面这个:
这里写图片描述

比如x1经过隐含层的映射会有三个输出,那么这三个输出就是编码结果,同理其他的。而我们是需要把这个映射结果显示出来,也就是把x1映射的三个值显示出来,同理其他的。因为这里只有三个值,根本没办法可视化。所以像上面我们取了100个隐含层,把每个输入每个单元映射100个输出,再把100变成10*10图像,我们就可以显示了,并且这里我们也只是显示这些权值,把输出默认为全1看看。

好了,那么采用matlab工具箱,上述data选择完后,构造神经网络模型,简单的几行代码:


clc
clear
load data
% data = data(1:100,:);
%% 神经网络的构建与训练
% 构造神经网络(包含100个隐藏层的节点)
net = feedforwardnet(100);
net.layers{2}.transferFcn = 'tansig';% 输出的映射方法,默认purelin--线性映射
% 训练网络
net = train(net,data',data');
% 可视化权值
show_result(net);

这样matlab自带它的训练模型就出来了:
这里写图片描述

可视化的函数也很简单:

function show_result(net)
% 将输入到隐含层的权值提出来并显示
W1 = net.IW{1};
[~,n] = size(W1);
for i = 1:n
    im = W1(:,i);
    im = reshape(im,10,10);
    subplot(6,6,i);
    imshow(im,[]);
end

最终得到结果如下:
这里写图片描述

可以看到输出的编码样子,有点像却很不明显,原因就是这是由36到100的升维,大了电脑带不动,在matlab的这个自带工具箱下。

所以,即使我们选择的块只有6*6,1000个块,然而这个训练过程却很漫长,为什么?就是matlab自带的神经网络并不是适合这种自编码的训练,而是浅层的输入到输出的训练,真正的自编码训练需要特定的设计才能保证速度,这里只是强制使用着看看,同时自编码还可以优化,比如加入稀疏变成稀疏自编码等等,后面介绍一种工具箱来重新实验这种自编码。

猜你喜欢

转载自blog.csdn.net/on2way/article/details/50095081