code: # coding:utf-8
  import logging
  
  import numpy as np
  from scipy.special import expit
  
  from mla.base import BaseEstimator
  from mla.utils import batch_iterator
  
  np.random.seed(9999)
  sigmoid = expit
  
  """
  References:
  A Practical Guide to Training Restricted Boltzmann Machines https://www.cs.toronto.edu/~hinton/absps/guideTR.pdf
  """
  
  
  class RBM(BaseEstimator):
      y_required = False
  
      def __init__(self, n_hidden=128, learning_rate=0.1, batch_size=10, max_epochs=100):
          """Bernoulli Restricted Boltzmann Machine (RBM)
  
          Parameters
          ----------
  
          n_hidden : int, default 128
              The number of hidden units.
          learning_rate : float, default 0.1
          batch_size : int, default 10
          max_epochs : int, default 100
          """
          self.max_epochs = max_epochs
          self.batch_size = batch_size
          self.lr = learning_rate
          self.n_hidden = n_hidden
  
      def fit(self, X, y=None):
          self.n_visible = X.shape[1]
          self._init_weights()
          self._setup_input(X, y)
          self._train()
  
      def _init_weights(self):
  
          self.W = np.random.randn(self.n_visible, self.n_hidden) * 0.1
  
          # Bias for visible and hidden units
          self.bias_v = np.zeros(self.n_visible, dtype=np.float32)
          self.bias_h = np.zeros(self.n_hidden, dtype=np.float32)
  
          self.errors = []
  
      def _train(self):
          """Use CD-1 training procedure, basically an exact inference for `positive_associations`,
          followed by a "non burn-in" block Gibbs Sampling for the `negative_associations`."""
  
          for i in range(self.max_epochs):
              error = 0
              for batch in batch_iterator(self.X, batch_size=self.batch_size):
                  positive_hidden = sigmoid(np.dot(batch, self.W) + self.bias_h)
                  hidden_states = self._sample(positive_hidden)  # sample hidden state h1
                  positive_associations = np.dot(batch.T, positive_hidden)
  
                  negative_visible = sigmoid(np.dot(hidden_states, self.W.T) + self.bias_v)
                  negative_visible = self._sample(negative_visible)  # use the sampled hidden state h1 to sample v1
                  negative_hidden = sigmoid(np.dot(negative_visible, self.W) + self.bias_h)
                  negative_associations = np.dot(negative_visible.T, negative_hidden)
  
                  lr = self.lr / float(batch.shape[0])
                  self.W += lr * ((positive_associations - negative_associations) / float(self.batch_size))
                  self.bias_h += lr * (negative_hidden.sum(axis=0) - negative_associations.sum(axis=0))
                  self.bias_v += lr * (np.asarray(batch.sum(axis=0)).squeeze() - negative_visible.sum(axis=0))
  
                  error += np.sum((batch - negative_visible) ** 2)
  
              self.errors.append(error)
              logging.info("Iteration %s, error %s" % (i, error))
          logging.debug("Weights: %s" % self.W)
          logging.debug("Hidden bias: %s" % self.bias_h)
          logging.debug("Visible bias: %s" % self.bias_v)
  
      def _sample(self, X):
          return X > np.random.random_sample(size=X.shape)
  
      def _predict(self, X=None):
          return sigmoid(np.dot(X, self.W) + self.bias_h)
  
apis: numpy.random.random_sample numpy.sum numpy.zeros numpy.random.randn numpy.random.seed numpy.dot