deep learning:DA降噪自编码源码加注释 ----- C++

琢磨了两天DA算法,还有有3个地方不是很明白,贴出代码,在最后写出我的疑惑,望解答。最初源代码由yusugomori编写。

第一个代码、迭代多少次便重新产生多少次噪声,代码如下:

DA.CPP

#include <iostream>
#include <math.h>
#include <stdlib.h>
#include "DA.h"

using namespace std;
void start_da();
double sigmoid(double);
int binomial(int n,double p);
double uniform(double min,double max);

int main()
{
    start_da();
    return 0;
}

//开始
void start_da()
{
    srand(0);
    double learning_rate = 0.1;      //学习率
    double error_rate = 0.3;        //噪声率

    int train_N = 10;
    int test_N = 2;
    int n_visible = 20;
    int n_hidden = 5;

    int train_data[10][20] = {
    {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0}
    };

    DA da(train_N,n_visible,n_hidden,NULL,NULL,NULL);       //第一步、构造DA,并进行赋值初始化W和双向的偏移量

    for(int i=0;i<100;i++)
    {
        for(int j=0;j<train_N;j++)
        {
            da.train(train_data[j],learning_rate,error_rate);   //第二步、开始训练数据
        }
    }

    int test_data[2][20] = {
        {1,0,1,0,1,0,1,0,1,1,0,0,0,0,0,0,0,0,0,0},
        {0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,1,0,1,1,0}
    };
    double reconstruct[2][20];

    for(int i=0;i<test_N;i++)
    {
        da.reconstruct(test_data[i],reconstruct[i]);        //第三步、获得测试数据的重构Z
        for(int j=0;j<n_visible;j++)
        {
            cout << reconstruct[i][j] << " ";
        }
        cout << endl;
    }
    cout << endl;
}

void DA::reconstruct(int* x,double* z)
{
    double *y = new double[n_hidden];
    get_hidden_values(x,y);
    get_reconstructed_input(y,z);

    delete[] y;
}

//第一步
DA::DA(int n,int n_v,int n_h,double** w,double* hb,double* vb)
{
    train_N = n;
    n_visible = n_v;
    n_hidden = n_h;
    if(w == NULL)
    {
        W = new double*[n_hidden];
        for(int i=0;i<n_hidden;i++)
        {
            W[i] = new double[n_visible];
        }
        double a = 1.0 / n_visible;
        for(int i=0;i<n_hidden;i++)
        {
            for(int j=0;j<n_visible;j++)
            {
                W[i][j] = uniform(-a,a);
            }
        }
    }
    else
    {
        W = w;
    }

    if(hb == NULL)
    {
        hbias = new double[n_hidden];
        for(int i=0;i<n_hidden;i++)
        {
            hbias[i] = 0;
        }
    }
    else
    {
        hbias = hb;
    }

    if(vb == NULL)
    {
        vbias = new double[n_visible];
        for(int i=0;i<n_visible;i++)
        {
            vbias[i] = 0;
        }
    }
    else
    {
        vbias = vb;
    }
}

DA::~DA()
{
    for(int i=0;i<n_hidden;i++) delete[] W[i];
    delete[] W;
    delete[] hbias;
    delete[] vbias;
}

//第一步1.1
double uniform(double min,double max)
{
    return rand() / (RAND_MAX + 1.0) * (max - min) + min;
}

//第二步
void DA::train(int* train_data,double learning_rate,double error_rate)
{
    int *noise_x = new int[n_visible];      //随机加入噪声
    double *y = new double[n_hidden];
    double *z = new double[n_visible];

    double *Learning_vbias = new double[n_visible];
    double *Learning_hbias = new double[n_hidden];

    double p = 1 - error_rate;

    get_noise_input(train_data,noise_x,p);  //获得噪声后的训练集
    get_hidden_values(noise_x,y);           //获得隐藏层数据输出
    get_reconstructed_input(y,z);            //获得重构输入Z

    for(int i=0;i<n_visible;i++)
    {
        Learning_vbias[i] = noise_x[i] - z[i];
        vbias[i] += learning_rate * Learning_vbias[i] / train_N;        //反向的偏移量更新
    }

    for(int i=0;i<n_hidden;i++)
    {
        Learning_hbias[i] = 0;
        for(int j=0;j<n_visible;j++)
        {
            Learning_hbias[i] += W[i][j] + Learning_vbias[j];
        }
        Learning_hbias[i] *= y[i] * (1 - y[i]);
        hbias[i] += learning_rate * Learning_hbias[i] / train_N;        //前向利用BP进行更新偏移量
    }

    for(int i=0;i<n_hidden;i++)
    {
        for(int j=0;j<n_visible;j++)
        {
            //W[i][j] += learning_rate * (Learning_hbias[i] * y[i]) / train_N;
            W[i][j] += learning_rate * (Learning_hbias[i] * noise_x[i] + Learning_vbias[i] * y[i]) / train_N;        //更新权值
        }
    }

    delete[] Learning_hbias;
    delete[] Learning_vbias;
    delete[] z;
    delete[] y;
    delete[] noise_x;
}

void DA::get_reconstructed_input(double* y,double* z)
{
    for(int i=0;i<n_visible;i++)
    {
        z[i] = 0;
        for(int j=0;j<n_hidden;j++)
        {
            z[i] += W[j][i] * y[j];
        }
        z[i] += vbias[i];
        z[i] += sigmoid(z[i]);
    }
}

void DA::get_hidden_values(int* noise_x,double* y)
{
    for(int i=0;i<n_hidden;i++)
    {
        y[i] = 0;
        for(int j=0;j<n_visible;j++)
        {
            y[i] += W[i][j] * noise_x[j];
        }
        y[i] += hbias[i];
        y[i] = sigmoid(y[i]);
    }
}

double sigmoid(double x)
{
    return exp(x)/(1+exp(x));
}

void DA::get_noise_input(int* train_data,int* noise_x,double p)
{
    for(int i=0;i<n_visible;i++)
    {
        if(train_data[i] == 0)
        {
            noise_x[i] = 0;
        }
        else
        {
           noise_x[i] = binomial(1,p);
        }
    }
}

int binomial(int n,double p)
{
    if(p > 1 || p < 0)
    {
        return 0;
    }
    int c = 0;
    double r;

    for(int i=0;i<n;i++)
    {
        r = rand() / (RAND_MAX + 1.0);
        if(r < p)
        {
            c++;
        }
    }
     return c;
}

DA.h

class DA{
    public:
    int train_N;
    int n_visible;
    int n_hidden;
    double **W;
    double *hbias;
    double *vbias;

    DA(int ,int ,int ,double** W,double* hbias,double* vbias);
    ~DA();

    void train(int* ,double ,double);
    void get_noise_input(int*,int*,double);
    void get_hidden_values(int*,double*);
    void get_reconstructed_input(double* ,double*);
    void reconstruct(int* ,double*);
    private:
};

第一个代码、只产生1次噪声,并把这个噪声数据当作原始数据训练,代码如下:

DA.CPP

#include <iostream>
#include <math.h>
#include <stdlib.h>
#include "DA.h"

using namespace std;
void start_da();
double sigmoid(double);
int binomial(int n,double p);
double uniform(double min,double max);

int main()
{
    start_da();
    return 0;
}

//开始
void start_da()
{
    srand(0);
    double learning_rate = 0.1;      //学习率
    double error_rate = 0.3;        //噪声率

    int train_N = 10;
    int test_N = 2;
    int n_visible = 20;
    int n_hidden = 5;

    int train_data[10][20] = {
    {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0}
    };

    DA da(train_N,n_visible,n_hidden,NULL,NULL,NULL);       //第一步、构造DA,并进行赋值初始化W和双向的偏移量

    int noise_x[10][20];
    double p = 1 - error_rate;
    for(int i=0;i<train_N;i++)
    {
        for(int j=0;j<n_visible;j++)
        {
            if(train_data[i][j] == 0)
            {
                noise_x[i][j] = 0;
            }
            else
            {
                noise_x[i][j] = binomial(1,p);
            }
        }
    }

    for(int i=0;i<train_N;i++)
    {
        for(int j=0;j<n_visible;j++)
        {
            cout << noise_x[i][j] << "--";
        }
        cout << endl;
    }

    for(int i=0;i<100;i++)
    {
        for(int j=0;j<train_N;j++)
        {
            da.train(noise_x[j],learning_rate,error_rate);   //第二步、开始训练数据
        }
    }

    int test_data[2][20] = {
        {1,0,1,0,1,0,1,0,1,1,0,0,0,0,0,0,0,0,0,0},
        {0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,1,0,1,1,0}
    };
    double reconstruct[2][20];

    for(int i=0;i<test_N;i++)
    {
        da.reconstruct(test_data[i],reconstruct[i]);        //第三步、获得测试数据的重构Z
        for(int j=0;j<n_visible;j++)
        {
            cout << reconstruct[i][j] << " ";
        }
        cout << endl;
    }
    cout << endl;
}

void DA::reconstruct(int* x,double* z)
{
    double *y = new double[n_hidden];
    get_hidden_values(x,y);
    get_reconstructed_input(y,z);

    delete[] y;
}

//第一步
DA::DA(int n,int n_v,int n_h,double** w,double* hb,double* vb)
{
    train_N = n;
    n_visible = n_v;
    n_hidden = n_h;
    if(w == NULL)
    {
        W = new double*[n_hidden];
        for(int i=0;i<n_hidden;i++)
        {
            W[i] = new double[n_visible];
        }
        double a = 1.0 / n_visible;
        for(int i=0;i<n_hidden;i++)
        {
            for(int j=0;j<n_visible;j++)
            {
                W[i][j] = uniform(-a,a);
            }
        }
    }
    else
    {
        W = w;
    }

    if(hb == NULL)
    {
        hbias = new double[n_hidden];
        for(int i=0;i<n_hidden;i++)
        {
            hbias[i] = 0;
        }
    }
    else
    {
        hbias = hb;
    }

    if(vb == NULL)
    {
        vbias = new double[n_visible];
        for(int i=0;i<n_visible;i++)
        {
            vbias[i] = 0;
        }
    }
    else
    {
        vbias = vb;
    }
}

DA::~DA()
{
    for(int i=0;i<n_hidden;i++) delete[] W[i];
    delete[] W;
    delete[] hbias;
    delete[] vbias;
}

//第一步1.1
double uniform(double min,double max)
{
    return rand() / (RAND_MAX + 1.0) * (max - min) + min;
}

//第二步
void DA::train(int* noise_x,double learning_rate,double error_rate)
{
    double *y = new double[n_hidden];
    double *z = new double[n_visible];

    double *Learning_vbias = new double[n_visible];
    double *Learning_hbias = new double[n_hidden];

    get_hidden_values(noise_x,y);           //获得隐藏层数据输出
    get_reconstructed_input(y,z);            //获得重构输入Z

    for(int i=0;i<n_visible;i++)
    {
        Learning_vbias[i] = noise_x[i] - z[i];
        vbias[i] += learning_rate * Learning_vbias[i] / train_N;        //反向的偏移量更新
    }

    for(int i=0;i<n_hidden;i++)
    {
        Learning_hbias[i] = 0;
        for(int j=0;j<n_visible;j++)
        {
            Learning_hbias[i] += W[i][j] + Learning_vbias[j];
        }
        Learning_hbias[i] *= y[i] * (1 - y[i]);
        hbias[i] += learning_rate * Learning_hbias[i] / train_N;        //前向利用BP进行更新偏移量
    }

    for(int i=0;i<n_hidden;i++)
    {
        for(int j=0;j<n_visible;j++)
        {
            //W[i][j] += learning_rate * (Learning_hbias[i] * y[i]) / train_N;
            W[i][j] += learning_rate * (Learning_hbias[i] * noise_x[i] + Learning_vbias[i] * y[i]) / train_N;        //更新权值
        }
    }

    delete[] Learning_hbias;
    delete[] Learning_vbias;
    delete[] z;
    delete[] y;
}

void DA::get_reconstructed_input(double* y,double* z)
{
    for(int i=0;i<n_visible;i++)
    {
        z[i] = 0;
        for(int j=0;j<n_hidden;j++)
        {
            z[i] += W[j][i] * y[j];
        }
        z[i] += vbias[i];
        z[i] += sigmoid(z[i]);
    }
}

void DA::get_hidden_values(int* noise_x,double* y)
{
    for(int i=0;i<n_hidden;i++)
    {
        y[i] = 0;
        for(int j=0;j<n_visible;j++)
        {
            y[i] += W[i][j] * noise_x[j];
        }
        y[i] += hbias[i];
        y[i] = sigmoid(y[i]);
    }
}

double sigmoid(double x)
{
    return exp(x)/(1+exp(x));
}

int binomial(int n,double p)
{
    if(p > 1 || p < 0)
    {
        return 0;
    }
    int c = 0;
    double r;

    for(int i=0;i<n;i++)
    {
        r = rand() / (RAND_MAX + 1.0);
        if(r < p)
        {
            c++;
        }
    }
     return c;
}

DA.h

class DA{
    public:
    int train_N;
    int n_visible;
    int n_hidden;
    double **W;
    double *hbias;
    double *vbias;

    DA(int ,int ,int ,double** W,double* hbias,double* vbias);
    ~DA();

    void train(int* ,double ,double);
    void get_noise_input(int*,int*,double);
    void get_hidden_values(int*,double*);
    void get_reconstructed_input(double* ,double*);
    void reconstruct(int* ,double*);
    private:
};

 

我的疑惑:1、噪声需要每次随机更换还是只一次?  2、权值W的更新公式怎么推到得出,我只推到出注释掉的那个公式? 3、这个输出Z的误差也太大了点吧。百分之30的误差率?   求解答。。。。

posted on 2013-11-18 21:51  Ja °  阅读(1109)  评论(0编辑  收藏  举报

导航