| 17 | |
| 18 | |
| 19 | class RBM(BaseEstimator): |
| 20 | y_required = False |
| 21 | |
| 22 | def __init__(self, n_hidden=128, learning_rate=0.1, batch_size=10, max_epochs=100): |
| 23 | """Bernoulli Restricted Boltzmann Machine (RBM) |
| 24 | |
| 25 | Parameters |
| 26 | ---------- |
| 27 | |
| 28 | n_hidden : int, default 128 |
| 29 | The number of hidden units. |
| 30 | learning_rate : float, default 0.1 |
| 31 | batch_size : int, default 10 |
| 32 | max_epochs : int, default 100 |
| 33 | """ |
| 34 | self.max_epochs = max_epochs |
| 35 | self.batch_size = batch_size |
| 36 | self.lr = learning_rate |
| 37 | self.n_hidden = n_hidden |
| 38 | |
| 39 | def fit(self, X, y=None): |
| 40 | self.n_visible = X.shape[1] |
| 41 | self._init_weights() |
| 42 | self._setup_input(X, y) |
| 43 | self._train() |
| 44 | |
| 45 | def _init_weights(self): |
| 46 | self.W = np.random.randn(self.n_visible, self.n_hidden) * 0.1 |
| 47 | |
| 48 | # Bias for visible and hidden units |
| 49 | self.bias_v = np.zeros(self.n_visible, dtype=np.float32) |
| 50 | self.bias_h = np.zeros(self.n_hidden, dtype=np.float32) |
| 51 | |
| 52 | self.errors = [] |
| 53 | |
| 54 | def _train(self): |
| 55 | """Use CD-1 training procedure, basically an exact inference for `positive_associations`, |
| 56 | followed by a "non burn-in" block Gibbs Sampling for the `negative_associations`.""" |
| 57 | |
| 58 | for i in range(self.max_epochs): |
| 59 | error = 0 |
| 60 | for batch in batch_iterator(self.X, batch_size=self.batch_size): |
| 61 | positive_hidden = sigmoid(np.dot(batch, self.W) + self.bias_h) |
| 62 | hidden_states = self._sample(positive_hidden) # sample hidden state h1 |
| 63 | positive_associations = np.dot(batch.T, positive_hidden) |
| 64 | |
| 65 | negative_visible = sigmoid( |
| 66 | np.dot(hidden_states, self.W.T) + self.bias_v |
| 67 | ) |
| 68 | negative_visible = self._sample( |
| 69 | negative_visible |
| 70 | ) # use the sampled hidden state h1 to sample v1 |
| 71 | negative_hidden = sigmoid( |
| 72 | np.dot(negative_visible, self.W) + self.bias_h |
| 73 | ) |
| 74 | negative_associations = np.dot(negative_visible.T, negative_hidden) |
| 75 | |
| 76 | lr = self.lr / float(batch.shape[0]) |