一个非常好的理解autoencoders的例子

深度学习有一个重要的概念叫autoencoder,这是个什么东西呢,本文通过一个例子来普及这个术语。

    Autoencoders

    简单来说autoencoder是一个压缩编码器,也就是对input的一坨东西通过变换,输出和input一样的东西。例如input是一个鸡,ouput也是一个鸡,input是一个鸭,output也是一个鸭。学术一点说就是找到一个函数能够使得 Function(input) = input,叫做identity function。如上图所示,即学习Hw,b(x)=x。



    但这和深度学习有什么关系呢? 这就要说到压缩编码,我们都知道input需要有一种编码形式,如果我们能在函数内部找到一个更简洁的编码形式,那么这个变换过程就等价于学习到了一种压缩表示的函数,能够少量的存储形式来表示原本较复杂的但信息冗余较大的表示形式。



    我们下面的代码中举了一个精彩的例子(这个例子是从同学的一次实验中直接受启发,我只是按照自己的理解实现了一把,例子非原创)。在这个例子中,input是4个不同的数字,分别是

    (0,0,0,1)可以看作1

    (0,0,1,0)可以看作2

    (0,1,0,0)可以看作3

    (1,0,0,0)可以看作4

    因为所有的input只有这4种,因此其实用4个bit是不经济的,存在压缩表示的可能性,比如2个bit就可以表示这4个不同的数。



    那么我们设计了输入层是4+1(4个脚接受4bit编码的input,1个脚是常数项,这个用来做先验的);隐藏层2+1(因为我们实现已经知道2个bit就够了,所以2个隐藏层,具有足够的表达能力);输出层4(为了能让输出和输入保持一致)

  

    通过数轮迭代,我们看到如下的情况

    (0,0,0,1)->(0.99,0.09)->(0.06,0.00,0.01,0.91)

    (0,0,1,0)->(0.85,0.99)->(0.00,0.07,0.90,0.07)

    (0,1,0,0)->(0.01,0.67)->(0.06,0.87,0.11,0.00)

    (1,0,0,0)->(0.12,0.00)->(0.89,0.10,0.00,0.02)

     input_layer hidden_layer     output_layer

    

     hidden层的编码恰好可以看作是

     (0.99,0.09)  1,0

     (0.85,0.99)  1,1

     (0.01,0.67)  0,1

     (0.12,0.00)  0,0



     也就是说输入的(0,0,0,1)可以被1,0 压缩表示,最终4bit的信息,可以用2bit表示,当然还需要保持边的权重,但这些边权重只需要一份,在输入足够复杂的时候,压缩表示是有价值的。

 

      那压缩表示有什么价值呢?比如一组广告,一条新闻,人看了挺好,压缩表示后,人看起来就不爽了,恰恰是人看着不爽了,机器就好处理了,下回再说。。

 

        其他相关可参见美军参考资料:

        http://ufldl.stanford.edu/wiki/index.php/Autoencoders_and_Sparsity

 

以下是实验代码,水平有限,仅供参考。

 

#include <iostream>

#include "math.h"

using namespace std;

double d = 0.4;

double function_g(double x)

{

        doubleex = pow(2.718281828,x);

        returnex/(1+ex);

}

 

double input[4][5]={{0,0,0,1,1}, //{0,0,0,1} {1}

                    {0,0,1,0,1},

                    {0,1,0,0,1},

                    {1,0,0,0,1}};

 

double edge_1[2][5];

double edge_2[4][3];

double first_layer[5];

double hidden_layer[3]={0,0,1};

double output_layer[4];

 

double diff()

{

        doubleret = 0.0;

        for(inti=0;i<4;++i)

        {

                ret+= (output_layer[i]-first_layer[i])*(output_layer[i]-first_layer[i]);

        }

        returnret;

}

void count_second_l( )

{

        for(inti=0;i<2;++i)

        {

                hidden_layer[i]= 0;

                for(intj=0;j<5;++j)

                {

                        hidden_layer[i]+= first_layer[j]*edge_1[i][j];

                }

                hidden_layer[i]= function_g(hidden_layer[i]);

        }

        return;

}

void count_last_l()

{

        for(inti=0;i<4;++i)

        {

                output_layer[i]= 0;

                for(intj=0;j<3;++j)

                {

                        output_layer[i]+= hidden_layer[j]*edge_2[i][j];

                }

                output_layer[i]= function_g(output_layer[i]);

        }

        return;

}

double total_diff()

{

        doubleret = 0.0;

        for(int j=0;j<4;++j)

        {

                first_layer[0]=input[j][0];

                first_layer[1]=input[j][1];

                first_layer[2]=input[j][2];

                first_layer[3]=input[j][3];

                first_layer[4]=input[j][4];

                count_second_l();

                count_last_l();

                ret+= diff();

        }

        returnret;

}

 

int main(void)

{

        for(inti=0;i<2;++i)

                for(intj=0;j<5;++j)

                        edge_1[i][j]= ((i+j)%4+0.1)/10;        //initialize eachedges between first_layers and hidden layers

 

         for(inti=0;i<4;++i)

                for(intj=0;j<3;++j)

                        edge_2[i][j]= ((i+j)%4+0.1)/10;        //initialize eachedges between hidden_layers and output_layers

 

        for(inti=0;i<40000;++i)                                //iterate40000 times

        {

                doubleorigin_diff=total_diff();

                doubledirection_1[2][5],direction_2[4][3];

                for(inti=0;i<2;++i)

                        for(intj=0;j<5;++j)

                        {

                                doubletmp = edge_1[i][j] ;

                                edge_1[i][j]+= d * origin_diff;

                                count_second_l();

                                count_last_l();

                                doublediff2 = total_diff();

                                direction_1[i][j]= origin_diff - diff2;

                                edge_1[i][j]= tmp;

                        }

                for(inti=0;i<4;++i)

                        for(intj=0;j<3;++j)

                        {

                                doubletmp = edge_2[i][j] ;

                                edge_2[i][j]+= d * origin_diff;

                                count_second_l();

                                count_last_l();

                                doublediff2 = total_diff();

                                direction_2[i][j]= origin_diff - diff2;

                                edge_2[i][j]= tmp;

                        }

                for(inti=0;i<2;++i)

                        for(intj=0;j<5;++j)

                        {

                                edge_1[i][j]+= d * origin_diff * direction_1[i][j];

                        }

                for(inti=0;i<4;++i)

                        for(intj=0;j<3;++j)

                        {

                                edge_2[i][j]+= d * origin_diff * direction_2[i][j];

                        }

 

                doubled = 0.0;                

                for(int j=0;j<4;++j)

                {

                        first_layer[0]=input[j][0];

                        first_layer[1]=input[j][1];

                        first_layer[2]=input[j][2];

                        first_layer[3]=input[j][3];

                        first_layer[4]=input[j][4];

                        count_second_l();

                        count_last_l();

                        d+= diff();

                        cout<<"####################"<<endl;

                        cout<<"input:\t"<<first_layer[0]<<"\t"<<first_layer[1]<<"\t"<<first_layer[2]<<"\t"<<first_layer[3]<<endl;

                        cout<<"output:\t"<<output_layer[0]<<"\t"<<output_layer[1]<<"\t"<<output_layer[2]<<"\t"<<output_layer[3]<<endl;

                        cout<<"hidden:\t"<<hidden_layer[0]<<"\t"<<hidden_layer[1]<<endl;

                        cout<<"####################"<<endl;

                }

                cout<<"diff_sum:"<<d<<endl;

        }

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值