zoukankan      html  css  js  c++  java
  • Denoising Autoencod

    Denoising Autoencod(去噪自编码)(DA)是一个经典的autoencode算法的扩展,在[vincent08 ]中作为深网络的构建块使用。我们将开始本教程对autoencoders简短的讨论。
     
    • 一个autoencode 将输入   mathbf{x} in [0,1]^d  通过 一个确定的投影方法(encode ) 投影到一个隐层空间mathbf{y} in [0,1]^{d'}。 

    mathbf{y} = s(mathbf{W}mathbf{x} + mathbf{b})                  W是投影矩阵, b为隐层的偏置 s是一个非线性函数如 sigmoid。然后我们通过 y重建 x。得到z。投影方法如下式表示

    mathbf{z} = s(mathbf{W'}mathbf{y} + mathbf{b'})                 z作为x(输入的预测)        mathbf{W'} = mathbf{W}^T

    那么这个模型的参数列表为mathbf{W}mathbf{b}mathbf{b'}

    传统的平方误差为                      

                                         L(mathbf{x} mathbf{z}) = || mathbf{x} -
mathbf{z} ||^2

    重建的交叉熵为

                                L_{H} (mathbf{x}, mathbf{z}) = - sum^d_{k=1}[mathbf{x}_k log
        mathbf{z}_k + (1 - mathbf{x}_k)log(1 - mathbf{z}_k)]

    下面我们来用C语言实现这个模型。

    首先需要定义

    typedef struct {
      int N;
      int n_visible;   //输入神经元个数
      int n_hidden;  //隐藏神经元个数
      double **W;    //参数w
      double *hbias; // 参数  输入的偏置
      double *vbias; //隐藏神经元的偏置
    } dA;

    定义encode 函数    mathbf{y} = s(mathbf{W}mathbf{x} + mathbf{b})

    void dA_get_hidden_values(dA* this, int *x, double *y) {
                int i,j;
                for(i=0; i<this->n_hidden; i++) {
                     y[i] = 0;
                     for(j=0; j<this->n_visible; j++) {
                            y[i] += this->W[i][j] * x[j];
                     }
                     y[i] += this->hbias[i];
                     y[i] = sigmoid(y[i]);
                 }
           }

    定义decode 函数 mathbf{z} = s(mathbf{W'}mathbf{y} + mathbf{b'})

    void dA_get_reconstructed_input(dA* this, double *y, double *z) {
                    int i, j;
                    for(i=0; i<this->n_visible; i++) {
                         z[i] = 0;
                         for(j=0; j<this->n_hidden; j++) {
                                z[i] += this->W[j][i] * y[j];
                          }
                          z[i] += this->vbias[i];
                          z[i] = sigmoid(z[i]);
                      }
                  }

    随机损坏输入。这样能更好的使我们的模型学习更多。(but, I now can not understand why we should do this, just for Denoising  or for others)

    建议读者查看gibbs采样或者其他的文章。

    void dA_get_corrupted_input(dA* this, int *x, int *tilde_x, double p) {
             int i;
             for(i=0; i<this->n_visible; i++) {
                  if(x[i] == 0) {
                   tilde_x[i] = 0;
              } else {
              tilde_x[i] = binomial(1, p);   //按照p的概率生成1.该函数总是将 (1-p)概率的1转化为0,如果p = 1,将不会发生任何转化
           }
        }
    }

    初始化我们的模型:

    void dA__construct(dA* this, int N, int n_visible, int n_hidden, 
                       double **W, double *hbias, double *vbias) {
      int i, j;
      double a = 1.0 / n_visible;
      
      this->N = N;
      this->n_visible = n_visible;
      this->n_hidden = n_hidden;
    
      if(W == NULL) {
        this->W = (double **)malloc(sizeof(double*) * n_hidden);
        this->W[0] = (double *)malloc(sizeof(double) * n_visible * n_hidden);
        for(i=0; i<n_hidden; i++) this->W[i] = this->W[0] + i * n_visible;
    
        for(i=0; i<n_hidden; i++) {
          for(j=0; j<n_visible; j++) {
            this->W[i][j] = uniform(-a, a);
          }
        }
      } else {
        this->W = W;
      }
    
      if(hbias == NULL) {
        this->hbias = (double *)malloc(sizeof(double) * n_hidden);
        for(i=0; i<n_hidden; i++) this->hbias[i] = 0;
      } else {
        this->hbias = hbias;
      }
    
      if(vbias == NULL) {
        this->vbias = (double *)malloc(sizeof(double) * n_visible);
        for(i=0; i<n_visible; i++) this->vbias[i] = 0;
      } else {
        this->vbias = vbias;
      }
    }

    有了encode和decode函数 我们就可以计算 lost了并且更新我们的权值。

    权值的更新采用偏导数算出。大家可以自己计算。

    void dA_train(dA* this, int *x, double lr, double corruption_level) {
      int i, j;
      int *tilde_x = (int *)malloc(sizeof(int) * this->n_visible);
      double *y = (double *)malloc(sizeof(double) * this->n_hidden);
      double *z = (double *)malloc(sizeof(double) * this->n_visible);
    
      double *L_vbias = (double *)malloc(sizeof(double) * this->n_visible);
      double *L_hbias = (double *)malloc(sizeof(double) * this->n_hidden);
    
      double p = 1 - corruption_level;
    
      dA_get_corrupted_input(this, x, tilde_x, p);
      dA_get_hidden_values(this, tilde_x, y);
      dA_get_reconstructed_input(this, y, z);
    
      // vbias
      for(i=0; i<this->n_visible; i++) {
        L_vbias[i] = x[i] - z[i];
        this->vbias[i] += lr * L_vbias[i] / this->N;
      }
    
      // hbias
      for(i=0; i<this->n_hidden; i++) {
        L_hbias[i] = 0;
        for(j=0; j<this->n_visible; j++) {
          L_hbias[i] += this->W[i][j] * L_vbias[j];
        }
        L_hbias[i] *= y[i] * (1 - y[i]);
    
        this->hbias[i] += lr * L_hbias[i] / this->N;
      }
    
      // W
      for(i=0; i<this->n_hidden; i++) {
        for(j=0; j<this->n_visible; j++) {
          this->W[i][j] += lr * (L_hbias[i] * tilde_x[j] + L_vbias[j] * y[i]) / this->N;
        }
      }

    在上面的代码中我们可以发现,如果我们去除随机将输入1变为0的话。那么就是一个标准的autoencode。

  • 相关阅读:
    个人网站上线
    从零开始学C++之虚函数与多态(二):纯虚函数、抽象类、虚析构函数
    Triangle
    Hard problem
    [置顶] Android AlarmManager实现不间断轮询服务
    Python学习入门基础教程(learning Python)--5.1 Python下文件处理基本过程
    编程之美 裴波那楔数列
    130712周赛(CF)
    Python学习入门基础教程(learning Python)--5.2 Python读文件基础
    phantomjs
  • 原文地址:https://www.cnblogs.com/xiaokangzi/p/4492345.html
Copyright © 2011-2022 走看看