RBM(受限玻尔兹曼机)

基于能量模型 (EBM)

基于能量模型将关联感兴趣变量每个配置标量能量学习修改能量函数使他形状具有最好性能例如我们想的得到最好的参量拥有较低能量
EBM的概率模型定义通过能量函数概率分布如下所示
        p(x) = \frac {e^{-E(x)}} {Z}.
规则化系数 Z 称为分区函数物理系统的能量模型相似
        Z = \sum_x e^{-E(x)}
一种基于能量模型可以学习通过随机梯度下降的方法处理对数似然训练数据至于 logistic 回归分析我们首次作为负对数似然定义对数似然然后损失函数
        \mathcal{L}(\theta, \mathcal{D}) = \frac{1}{N} \sum_{x^{(i)} \in \mathcal{D}} \log\ p(x^{(i)})\\ \ell (\theta, \mathcal{D}) = - \mathcal{L} (\theta, \mathcal{D})
使用随机梯度 -\frac{\partial  \log p(x^{(i)})}{\partial \theta} 更新参数权值, \theta 是模型中的各种参数 .
 

EBMs 的隐藏神经元

在很多情况下, 我们看不到部分的隐藏单元 x , 或者我们要引入一些不可见的参量来增强模型的能力.所以我们考虑一些可见的神经元(依然表示为 x) 和 隐藏的部分 h. 我们可以这样写我们的表达式:

                                                 P(x) = \sum_h P(x,h) = \sum_h \frac{e^{-E(x,h)}}{Z}.                                                                                         (2)

在这种情况下,公式类似于 (1), 我们引入符号, 自由能量, 定义如下:

                                                      \mathcal{F}(x) = - \log \sum_h e^{-E(x,h)}                                                                                                   (3)

也可以这么写,

&P(x) = \frac{e^{-\mathcal{F}(x)}}{Z} \text{ with } Z=\sum_x e^{-\mathcal{F}(x)}.

数据的负极大似然梯度表示为.

                                                                      - \frac{\partial  \log p(x)}{\partial \theta}  &= \frac{\partial \mathcal{F}(x)}{\partial \theta} -        \sum_{\tilde{x}} p(\tilde{x}) \            \frac{\partial \mathcal{F}(\tilde{x})}{\partial \theta}.                                                           (4)

注意上面的梯度表示为两个部分,涉及到正面的部分和负面的部分.正面和负面的不表示等式中每部分的符号,而是表示对模型中概率密度的影响. 第一部分增加训练数据的概率 (通过降低相应的自由能量), 第二部分降低模型确定下降梯度通常是很困难的, 因为他涉及到计算E_P [ \frac{\partial \mathcal{F}(x)} {\partial \theta} ]. 这无非在所有配置下x的期望 (符合由模型生成的概率分布 P) !

 

第一步是计算估计固定数量的模型样本的期望. 用来表示负面部分梯度的表示为负粒子, 表示为 \mathcal{N}. 梯度可以谢伟:

                                                                                     - \frac{\partial \log p(x)}{\partial \theta}  &\approx   \frac{\partial \mathcal{F}(x)}{\partial \theta} -    \frac{1}{|\mathcal{N}|}\sum_{\tilde{x} \in \mathcal{N}} \    \frac{\partial \mathcal{F}(\tilde{x})}{\partial \theta}.                             (5)

我们想 根据 P取样元素\tilde{x} of \mathcal{N}  (例如. 我们可以做 蒙特卡罗方法). 通过上面的公式, 我们几乎可以使用随机粒子算法来学习EBM模型. 唯一缺少的就是如何提取这些负粒子T \mathcal{N}. 统计学上有许多抽样方法, 马尔可夫链蒙特卡罗方法特别适合用于模型如受限玻尔兹曼机 (RBM), 一种特殊的 EBM.

 

受限玻尔兹曼机 (RBM)

玻尔兹曼机(BMS)是一种特殊的对数线性马尔可夫随机场(MRF)的形式,即,其能量函数在其自由参数的线性空间里。使他们强大到足以代表复杂的分布,我们考虑到一些变量是没有观察到(他们称为隐藏)。通过更多的隐藏变量(也称为隐藏的单位),我们可以增加的玻尔兹曼机的建模能力(BM)。受限玻尔兹曼机进一步限制BMS中那些可见-可见和隐藏-隐藏的连接。下面是一个RBM的图形描述。

_images/rbm.png

RBM能量方程 E(v,h) 定义为 :

   E(v,h) = - b'v - c'h - h'Wv                               (6)

W 表示隐藏单元和可见单元连接的权重, bc 是可见层和隐藏层的偏置.

转化成下面的自由能量公式:

\mathcal{F}(v)= - b'v - \sum_i \log \sum_{h_i} e^{h_i (c_i + W_i v)}.

由于RBM的特殊结构, 可见和隐藏单元 是条件独立的. 利用这个特性, 我们可以得出:

p(h|v) &= \prod_i p(h_i|v) \\ p(v|h) &= \prod_j p(v_j|h).

 

二值化的RBMs 

在通常的情况下使用二值化单元 (v_jh_i \in \{0,1\}), 我们从公式. (6) and (2)得到, 概率版本的常用神经元激活函数:

 P(h_i=1|v) = sigm(c_i + W_i v) \\                                       (7)

 P(v_j=1|h) = sigm(b_j + W'_j h)                                      (8)

二值RBM的自由能量可以更简单的表示为:

 \mathcal{F}(v)= - b'v - \sum_i \log(1 + e^{(c_i + W_i v)}).                          (9)

 

二值RBM的参数更新方程

结合等式 (5) 和 (9), 我们得到下面的对数似然梯度方程:

                                - \frac{\partial{ \log p(v)}}{\partial W_{ij}} &=     E_v[p(h_i|v) \cdot v_j]     - v^{(i)}_j \cdot sigm(W_i \cdot v^{(i)} + c_i) \\ -\frac{\partial{ \log p(v)}}{\partial c_i} &=     E_v[p(h_i|v)] - sigm(W_i \cdot v^{(i)})  \\ -\frac{\partial{ \log p(v)}}{\partial b_j} &=     E_v[p(v_j|h)] - v^{(i)}_j                      (10)

 

RBM中的采样

样本 p(x) 可以通过运行Markov chain收敛得到,使用gibbs采样作为转移操作.

N随机变量的Gibbs采样的联合概率S=(S_1, ... , S_N)可以通过一系列的采样得到S_i \sim p(S_i | S_{-i}) ,其中S_{-i} 包含 N-1 个 S中其他的随机参数但不包括S_i.

对于RBM,S包含一组可见或者不可见单元,由于他们是条件独立的你可以执行块Gibbs采样。在这种背景下对可见单元同时采样来得到隐藏单元的值. 同样的可以对隐藏单元同时采样,得到可见单元的值。 一步Markov chainA 由下面公式得到:

h^{(n+1)} &\sim sigm(W'v^{(n)} + c) \\ v^{(n+1)} &\sim sigm(W h^{(n+1)} + b),

其中h^{(n)} 表示是指在Markov chain第n步h^{(n)} 的所有隐藏单元. 意思是, 例如, h^{(n+1)}_i 是根据概率sigm(W_i'v^{(n)} + c_i)随机选择为1(或者0), 相似的, v^{(n+1)}_j 是根据概率sigm(W_{.j} h^{(n+1)} + b_j)随机选择为1(或者0).

这可以用下图说明:

_images/markov_chain.png

 

当 t \rightarrow \infty, 样本(v^{(t)}, h^{(t)}) 保证处于真实样本下 p(v,h).

理论下,每个参数的获取都必须运行这样一个链知道收敛,不用说这样做代价是十分昂贵的。因此,大家为RBM设计了不少算法,为了在学习过程中得到在概率分布p(v,h)下的有效样本。

对比差异(不知道是否如此翻译) (CD-k)

CD使用两个技巧来加速采样过程 :

  • 由于我们最终想要得到 p(v) \approx p_{train}(v) (真实的处于数据分布的样本), 我们把马尔科夫链初始化为一个训练样本(即,我们要使一个分布靠近p,那么我们的链应该已经收敛到最后的分布p)
  • CD不需要等待链收敛,样本结果k步gibbs采样得到,在实践中,k=1工作的出奇的好。

Persistent CD

Persistent CD [Tieleman08] 使用另一种方法近似p(v,h)下的样本,他依赖于一个拥有持续性的马尔科夫链, (i.e.,不为每个可见样本重新计算链 ). 对于每一个参量更新,我们简单的运行k-步链生成新的样本。 链的状态需要保存用来计算以后步骤的参量更新.

一般的直觉是,如果参量更新对于链的混合速率足够小,马尔科夫链应该可以察觉到模型的改变。

 

 

下面我们需要用代码来实现RBM(使用c语言)

 

 

  定义RBM结构体。

typedef struct {
  int N;
  int n_visible;
  int n_hidden;
  double **W;
  double *hbias;
  double *vbias;
} RBM;

  其中,n_visible是可见单元个数,n_hidden为隐藏单元个数。w为隐藏单元和可见单元的权值,bias为偏置。N为训练样本数量。

构建RBM结构:

  

void RBM__construct(RBM* 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;
  }
}

  初始化一些结构体,和参量等等。

 

由可见层得到隐藏样本:

double RBM_propdown(RBM* this, int *h, int i, double b) {
  int j;
  double pre_sigmoid_activation = 0.0;

  for(j=0; j<this->n_hidden; j++) {
    pre_sigmoid_activation += this->W[j][i] * h[j];
  }
  pre_sigmoid_activation += b;
  return sigmoid(pre_sigmoid_activation);
}

void RBM_sample_v_given_h(RBM* this, int *h0_sample, double *mean, int *sample) {
  int i;
  for(i=0; i<this->n_visible; i++) {
    mean[i] = RBM_propdown(this, h0_sample, i, this->vbias[i]);
    sample[i] = binomial(1, mean[i]);
  }
}

由隐藏样本得到可见样本:

  

double RBM_propup(RBM* this, int *v, double *w, double b) {
  int j;
  double pre_sigmoid_activation = 0.0;
  for(j=0; j<this->n_visible; j++) {
    pre_sigmoid_activation += w[j] * v[j];
  }
  pre_sigmoid_activation += b;
  return sigmoid(pre_sigmoid_activation);
}

void RBM_sample_h_given_v(RBM* this, int *v0_sample, double *mean, int *sample) {
  int i;
  for(i=0; i<this->n_hidden; i++) {
    mean[i] = RBM_propup(this, v0_sample, this->W[i], this->hbias[i]);
    sample[i] = binomial(1, mean[i]);
  }
}

Gibbs采样:

  

void RBM_gibbs_hvh(RBM* this, int *h0_sample, double *nv_means, int *nv_samples, \
                   double *nh_means, int *nh_samples) {
  RBM_sample_v_given_h(this, h0_sample, nv_means, nv_samples);
  RBM_sample_h_given_v(this, nv_samples, nh_means, nh_samples);
}

运行CD-K并且更新权值:

  

void RBM_contrastive_divergence(RBM* this, int *input, double lr, int k) {
  int i, j, step;
  
  double *ph_mean = (double *)malloc(sizeof(double) * this->n_hidden);
  int *ph_sample = (int *)malloc(sizeof(int) * this->n_hidden);
  double *nv_means = (double *)malloc(sizeof(double) * this->n_visible);
  int *nv_samples = (int *)malloc(sizeof(int) * this->n_visible);
  double *nh_means = (double *)malloc(sizeof(double) * this->n_hidden);
  int *nh_samples = (int *)malloc(sizeof(int) * this->n_hidden);

  /* CD-k */
  RBM_sample_h_given_v(this, input, ph_mean, ph_sample);

  for(step=0; step<k; step++) {
    if(step == 0) {
      RBM_gibbs_hvh(this, ph_sample, nv_means, nv_samples, nh_means, nh_samples);
    } else {
      RBM_gibbs_hvh(this, nh_samples, nv_means, nv_samples, nh_means, nh_samples);
    }
  }

  for(i=0; i<this->n_hidden; i++) {
    for(j=0; j<this->n_visible; j++) {
      // this->W[i][j] += lr * (ph_sample[i] * input[j] - nh_means[i] * nv_samples[j]) / this->N;
      this->W[i][j] += lr * (ph_mean[i] * input[j] - nh_means[i] * nv_samples[j]) / this->N;
    }
    this->hbias[i] += lr * (ph_sample[i] - nh_means[i]) / this->N;
  }

  for(i=0; i<this->n_visible; i++) {
    this->vbias[i] += lr * (input[i] - nv_samples[i]) / this->N;
  }
  

  free(ph_mean);
  free(ph_sample);
  free(nv_means);
  free(nv_samples);
  free(nh_means);
  free(nh_samples);
}

 

 

下面的代码是如何重建样本:就是  v->h->v

void RBM_reconstruct(RBM* this, int *v, double *reconstructed_v) {
  int i, j;
  double *h = (double *)malloc(sizeof(double) * this->n_hidden);
  double pre_sigmoid_activation;

  for(i=0; i<this->n_hidden; i++) {
    h[i] = RBM_propup(this, v, this->W[i], this->hbias[i]);
  }

  for(i=0; i<this->n_visible; i++) {
    pre_sigmoid_activation = 0.0;
    for(j=0; j<this->n_hidden; j++) {
      pre_sigmoid_activation += this->W[j][i] * h[j];
    }
    pre_sigmoid_activation += this->vbias[i];

    reconstructed_v[i] = sigmoid(pre_sigmoid_activation);
  }

  free(h);
}

 

 

最后检测RBM代码:

  

void test_rbm(void) {
  srand(0);

  int i, j, epoch;

  double learning_rate = 0.1;
  int training_epochs = 1000;
  int k = 1;
  
  int train_N = 6;
  int test_N = 2;
  int n_visible = 6;
  int n_hidden = 3;

  // training data
  int train_X[6][6] = {
    {1, 1, 1, 0, 0, 0},
    {1, 0, 1, 0, 0, 0},
    {1, 1, 1, 0, 0, 0},
    {0, 0, 1, 1, 1, 0},
    {0, 0, 1, 0, 1, 0},
    {0, 0, 1, 1, 1, 0}
  };

  // construct RBM
  RBM rbm;
  RBM__construct(&rbm, train_N, n_visible, n_hidden, NULL, NULL, NULL);

  // train
  for(epoch=0; epoch<training_epochs; epoch++) {
    for(i=0; i<train_N; i++) {
      RBM_contrastive_divergence(&rbm, train_X[i], learning_rate, k);
    }
  }


  // test data
  int test_X[2][6] = {
    {1, 1, 0, 0, 0, 0},
    {0, 0, 0, 1, 1, 0}
  };
  double reconstructed_X[2][6];

  // test
  for(i=0; i<test_N; i++) {
    RBM_reconstruct(&rbm, test_X[i], reconstructed_X[i]);
    for(j=0; j<n_visible; j++) {
      printf("%.5f ", reconstructed_X[i][j]);
    }
    printf("\n");
  }


  // destruct RBM
  RBM__destruct(&rbm);
}

 

 

转载于:https://www.cnblogs.com/xiaokangzi/p/4492466.html

RBM(Restricted Boltzmann Machine)是一种基于能量的概率模型,常用于无监督学习任务中。下面给出RBM的公式推导及Matlab代码实现。 一、RBM的公式推导 RBM是一个两层神经网络,包括输入层和隐藏层。假设输入层有m个节点,隐藏层有n个节点。RBM的网络结构如下图所示: ![RBM网络结构](https://img-blog.youkuaiyun.com/20180320235415595?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGl1bmd5b25n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/q/80) RBM的能量函数为: $$ E(v,h)=-\sum_{i=1}^{m}\sum_{j=1}^{n}v_iw_{ij}h_j-\sum_{i=1}^{m}v_ib_i-\sum_{j=1}^{n}h_jc_j $$ 其中,$v$表示输入层的节点状态,$h$表示隐藏层的节点状态,$w_{ij}$表示第$i$个输入节点和第$j$个隐藏节点之间的连接权重,$b_i$表示第$i$个输入节点的偏置,$c_j$表示第$j$个隐藏节点的偏置。 RBM的概率分布为: $$ P(v,h)=\frac{1}{Z}e^{-E(v,h)} $$ 其中,$Z$为归一化因子,可以表示为: $$ Z=\sum_{v}\sum_{h}e^{-E(v,h)} $$ RBM的训练目标是最大化样本出现的概率,即最大化对数似然函数。对于一个训练样本$v$,其对应的对数似然函数为: $$ \log P(v)=\log\sum_{h}e^{-E(v,h)} $$ 使用对比散度(Contrastive Divergence,CD)算法来学习RBM的参数。CD算法的核心思想是通过采样来估计对数似然函数的梯度。具体地,对于一个训练样本$v$,按照以下步骤进行: 1. 将$v$作为输入层的状态,通过前向传播计算出隐藏层的状态$h_0$; 2. 从隐藏层的概率分布中采样出一个样本$h_1$; 3. 将$h_1$作为隐藏层的状态,通过反向传播计算出输入层的状态$v_1$; 4. 从输入层的概率分布中采样出一个样本$v_2$; 5. 将$v_2$作为输入层的状态,通过前向传播计算出隐藏层的状态$h_2$。 最后,更新参数$w_{ij}$、$b_i$和$c_j$,使得对数似然函数的梯度最大化。 具体地,对于一个样本$v$,其对应的参数梯度为: $$ \frac{\partial\log P(v)}{\partial w_{ij}}=v_ih_{0j}-v_ih_{1j} $$ $$ \frac{\partial\log P(v)}{\partial b_i}=v_i-v_{2i} $$ $$ \frac{\partial\log P(v)}{\partial c_j}=h_{0j}-h_{2j} $$ 其中,$h_{0}$、$h_{1}$和$h_{2}$分别表示通过前向传播计算出的隐藏层状态。 二、RBM的Matlab代码实现 以下是使用Matlab实现RBM的代码示例,其中使用了CD算法来训练RBM模型。 ```matlab % RBM的Matlab代码实现 % 数据集:MNIST手写数字数据集,训练集60000个样本,测试集10000个样本 % 神经网络结构:输入层784个节点,隐藏层100个节点 % CD算法的参数:k=1,学习率lr=0.1 % 加载数据集 load mnist_train_data.mat load mnist_test_data.mat % 初始化RBM模型参数 input_size = 784; % 输入层节点数 hidden_size = 100; % 隐藏层节点数 w = 0.1 * randn(input_size, hidden_size); % 输入层和隐藏层之间的连接权重 b = zeros(1, input_size); % 输入层的偏置 c = zeros(1, hidden_size); % 隐藏层的偏置 % 训练RBM模型 batch_size = 100; % 每个batch的样本数 num_epochs = 10; % 迭代次数 k = 1; % CD算法的参数 lr = 0.1; % 学习率 % 对训练集进行预处理,将像素值归一化到[0,1]之间 train_data = double(train_data) / 255; for epoch = 1:num_epochs % 迭代训练 for batch = 1:floor(size(train_data, 1) / batch_size) % 逐个batch训练 % 选取一个batch的样本 batch_data = train_data((batch - 1) * batch_size + 1 : batch * batch_size, :); % 正向传播 h0_prob = sigmoid(batch_data * w + repmat(c, batch_size, 1)); % 隐藏层的概率分布 h0_sample = double(h0_prob > rand(size(h0_prob))); % 从概率分布中采样出隐藏层的状态 v1_prob = sigmoid(h0_sample * w' + repmat(b, batch_size, 1)); % 重构输入层的概率分布 v1_sample = double(v1_prob > rand(size(v1_prob))); % 从概率分布中采样出重构的输入层状态 % 反向传播 h1_prob = sigmoid(v1_sample * w + repmat(c, batch_size, 1)); % 重构的隐藏层的概率分布 h1_sample = double(h1_prob > rand(size(h1_prob))); % 从概率分布中采样出重构的隐藏层状态 % 计算参数梯度 w_grad = batch_data' * h0_prob - v1_sample' * h1_prob; % 输入层和隐藏层之间的连接权重的梯度 b_grad = sum(batch_data - v1_sample); % 输入层的偏置的梯度 c_grad = sum(h0_prob - h1_prob); % 隐藏层的偏置的梯度 % 更新参数 w = w + lr * w_grad / batch_size; b = b + lr * b_grad / batch_size; c = c + lr * c_grad / batch_size; end % 每个epoch结束后,计算一次对数似然函数的值 error = zeros(size(train_data, 1), 1); for i = 1:size(train_data, 1) v = train_data(i, :); h_prob = sigmoid(v * w + repmat(c, 1, 1)); % 隐藏层的概率分布 v_recon = sigmoid(h_prob * w' + repmat(b, 1, 1)); % 重构的输入层的概率分布 error(i) = -sum(v .* log(v_recon) + (1 - v) .* log(1 - v_recon)); end fprintf('Epoch %d, error = %f\n', epoch, mean(error)); end % 测试RBM模型 test_data = double(test_data) / 255; % 对测试集进行预处理 h_prob = sigmoid(test_data * w + repmat(c, size(test_data, 1), 1)); % 隐藏层的概率分布 v_recon = sigmoid(h_prob * w' + repmat(b, size(test_data, 1), 1)); % 重构的输入层的概率分布 error = -sum(sum(test_data .* log(v_recon) + (1 - test_data) .* log(1 - v_recon), 2)); % 计算对数似然函数的值 fprintf('Test error = %f\n', error); % 定义sigmoid函数 function y = sigmoid(x) y = 1 ./ (1 + exp(-x)); end ``` 参考文献: [1] Hinton G E, Salakhutdinov R R. Restricted Boltzmann machines for collaborative filtering[C]//Proceedings of the 25th international conference on Machine learning. ACM, 2008: 448-455. [2] Fischer A, Igel C. An introduction to restricted Boltzmann machines[J]. Progress in Pattern Recognition, Image Analysis, Computer Vision, and Applications, 2012, 7441: 14-36.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值