zoukankan      html  css  js  c++  java
  • 稀疏自编码器及事实上现——怎样搞基

    自编码器是什么?

    自编码器本身就是一种BP神经网络。

    它是一种无监督学习算法

    我们都知道神经网络能够从随意精度逼近随意函数,这里我们让神经网络目标值等于输出值x,也就是模拟一个恒等函数


    太无聊了,是吗?输入等于输出,这网络有什么意义?可是。当我们把自编码神经网络增加某些限制,事情就发生了变化。

    如图1所看到的,这就是一个主要的自编码神经网络。能够看到隐含层节点数量要少于输入层节点数量。


    图1

    举个样例,假设我们输入一张10*10的图像,这样就有100个像素,所以输入层和输出层的节点数量就是100。

    而我们取隐藏层节点数量为25。

    注意。这样就会迫使隐藏层节点学习得到输入数据的压缩表示方法。逼得隐藏层要用25维数据重构出100维的数据。这样也就完毕了学习过程。

    这和我们学习的过程非常像,如果一共同拥有100个考点,可是仅仅同意你用25个知识点概括全部这些考点,这就是学习的过程。

     

    稀疏自编码器又是什么?

    更一般的,假设隐藏层节点数量非常大,甚至比输入层节点数量还要多时。我们仍然能够使用自编码算法,可是这时须要增加稀疏性限制。这就是稀疏自编码器。

     

    什么是稀疏性限制?

    简单说就是要保证隐藏神经元在大多数情况下是被抑制的状态。详细表现就是sigmoid函数的输出大多数状态是0,tanh函数的输出大多数状态是-1。这样有什么优点?这样可以迫使隐藏神经元发挥最大的潜力,在非常不利的条件下学习到真正的特征。

     

    怎么衡量某个隐藏神经元的激活度?

    取平均就好了,如果表示在给定输入x的情况下,隐藏神经元j的激活度,那么自然就有平均激活度


     

    稀疏性惩处项——相对熵

    为了保证这个稀疏度小到我们希望的那么多。比方说,即


    我们须要在优化目标函数中增加一个额外的惩处因子。这个罚因子基于相对熵(KLdivergence):


    因此这个罚因子会有例如以下性质,当时(这里取稀疏性參数为0.2),等于0,而两者差异越来越大时,相对熵会高速趋近于无穷大,如图2所看到的:

     

    图2

    稀疏自编码器训练方式与BP神经网络相对照

    稀疏自编码神经网络的代价函数是BP神经网络的代价函数加上一个稀疏性惩处项:


    对应地,残差迭代公式也要进行修正


     

    实现一个稀疏自编码器


    数据概览

    採用的是Andrew著名的UFLDL给出的例子。当中数据文件叫做IMAGES,这是一个512*512*10的三维数组,里面存了10张图片,每张都是262144像素。运行

    <span style="font-size:14px;">loadIMAGES;
    imagesc(IMAGES(:,:,6))
    colormapgray;</span>


    能够看看第6张图的样子,如图3所看到的。是一张关于森林和雪山的图像。


    图3


    数据採样

    因为数据的图片挺大,我们总不能一上来搞一个每层都2万多节点的神经网络训练吧。我们先採样,这里从10张图片里面随机採样10000个小patch。每一个小patch是一个8*8像素小碎片。我们定义训练集是64*10000的矩阵。每一列就是把刚刚的小patch拉成列向量的结果。

    这里代码例如以下

    <span style="font-size:14px;">loadIMAGES;    % load images from disk
    patchsize= 8;  % we'll use 8x8 patches
    %numpatches = 10;
    numpatches= 10000;
    %Initialize patches with zeros.  Your codewill fill in this matrix--one
    %column per patch, 10000 columns.
    patches= zeros(patchsize*patchsize, numpatches);
    tic
    image_size=size(IMAGES);
    i=randi(image_size(1)-patchsize+1,1,numpatches);
    j=randi(image_size(2)-patchsize+1,1,numpatches);
    k=randi(image_size(3),1,numpatches);
    fornum=1:numpatches
    patches(:,num)=reshape(IMAGES(i(num):i(num)+patchsize-1,j(num):j(num)+patchsize-1,k(num)),1,[]);
    end
    toc</span>

    这里randi函数。randi(iMax。m,n)在闭区间[1,iMax]生成m*n型随机矩阵。而reshape函数的作用是把每一个小patch拉成一个列向量。

    前200个patch的样子如图4所看到的:


    图4

    sparseAutoencoderCost.m

    这部分代码是最核心也是最重要的,正如前面所说。如今优化目标函数有了3个部分:均方差项、权重衰减项、稀疏惩处项。

    这里程序须要一部分一部分地调试,否则很easy得到看似正确但实际效果没有正确代码好的错误结果。这里附上我最新改动版本号的代码,去掉了全部显式for循环,使用矢量化编程,简洁了代码,增强执行效率,但也减弱了可读性。

    <span style="font-size:14px;">numpatches=size(patches,2);
    a2=sigmoid(W1*patches+repmat(b1,1,numpatches));
    a3=sigmoid(W2*a2+repmat(b2,1,numpatches));
    Rho=sum(a2,2)/numpatches;
    Penalty=-sparsityParam./Rho+(1-sparsityParam)./(1-Rho);
    Delta3=(a3-patches).*a3.*(1-a3);
    Delta2=(W2'*Delta3+beta*repmat(Penalty,1,numpatches)).*a2.*(1-a2);
    cost1=sumsqr(a3-patches)/numpatches/2;
    cost2=(sumsqr(W1)+sumsqr(W2))*lambda/2;
    cost3=beta*sum(sparsityParam*log(sparsityParam./Rho)+(1-sparsityParam)*log((1-sparsityParam)./(1-Rho)));
    cost=cost1+cost2+cost3;
    W2grad=Delta3*a2'/numpatches+lambda*W2;
    b2grad=sum(Delta3,2)/numpatches;
    W1grad=Delta2*patches'/numpatches+lambda*W1;
    b1grad=sum(Delta2,2)/numpatches;</span>

    这里repmat的反复使用是用来复制矩阵的,一定要不遗余力去掉这部分代码中全部的显式for循环。否则运行起来时间会非常长。

     

    梯度校验

    梯度校验是代码调试的大杀器,这一部分我用到了for循环,效率确实很低了,所以调试的时候要把校验參数做些调整。令隐藏节点数量为2。採样数量为100,这样就能大大加快校验速度。

    否则要等相当久的时间。

    <span style="font-size:14px;">EPSILON=0.0001;
    thetaspslion=zeros(size(theta));
    fori=1:size(theta)
    thetaspslion(i)=EPSILON;
    numgrad(i)=(J(theta+thetaspslion)-J(theta-thetaspslion))/2/EPSILON;
    thetaspslion(i)=0;
    end</span>

    注意:最后执行时一定要关掉梯度校验,不然就要卡死机了。。

    这个梯度校验对于目标函数的3部分的调试一定要循序渐进。心急吃不了热豆腐。均方差项调试正确了以后,会得到如图5所看到的的图像


    图5

    而当,均方差项和权重衰减项都调试通过后,得到的图片是这种


    图6

    而当全部的目标函数都调试通过以后,接下来就是见证奇迹的时刻


    图7

    这就是图像的基。通过稀疏自编码器。我们学习得到了25个8*8的基,这些图像的基就相当于咱们每一个视神经细胞所示东西,当这些细胞组成阵列,垒成层层叠叠,我们就能看到全部的东西了。

    稀疏自编码器作为无监督学习的一层基本模块,这就是我们DeepLearning万里长城的第一步:搞基

  • 相关阅读:
    redis conf 中文详解
    sed 用法记录
    MySQL数据库的各种存储引擎详解
    MySQL数据库char与varchar的区别分析及使用建议
    从一个乘法来分析C语言
    排它平方数
    高斯日记
    SUID或SGID程序中能不能用system函数
    【转载】GDB反向调试(Reverse Debugging)
    setuid函数解析
  • 原文地址:https://www.cnblogs.com/yutingliuyl/p/6973300.html
Copyright © 2011-2022 走看看