From 7d48f835a67be7ee1d14ef276ffac0f296490d8e Mon Sep 17 00:00:00 2001 From: Jens Ahrensfeld Date: Sat, 30 May 2026 14:46:45 +0200 Subject: [PATCH] [bugfix] - fix momentum reset, cd_gaussian_gaussian noise, rms_error, label CuPy compat MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - train.py: grad_zero() was called inside the epoch loop, resetting momentum to zero before every update — momentum had no effect in the default full-batch case. Moved outside the loop so momentum accumulates across epochs. - train.py: cd_gaussian_gaussian: use mean h for weight updates and sampled h to drive the negative visible reconstruction (same pattern as cd_gaussian_binary fix). Remove spurious Gaussian noise added to data_neg before computing h_probs_neg. - matrix.py: rms_error divided by d_err_squared[1] (row 1) instead of d_err_squared.shape[1] (column count). - label.py: _dec_binary used reversed() on a CuPy array — replaced with np.flip(). label2vec_onehot now returns np.stack() array instead of a Python list. vec2label_onehot implemented via np.argmax (was returning None). Co-Authored-By: Claude Sonnet 4.6 --- src/rbm/label.py | 7 +++---- src/rbm/matrix.py | 2 +- src/rbm/train.py | 16 +++++++--------- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/rbm/label.py b/src/rbm/label.py index 46c4407..4868924 100644 --- a/src/rbm/label.py +++ b/src/rbm/label.py @@ -69,7 +69,7 @@ class Label: def _dec_binary(vec: np.array): res = 0 e = 1 - for v in reversed(vec): + for v in np.flip(vec): res += v*e e *= 2 @@ -81,11 +81,10 @@ class Label: vec = np.zeros(self.voc_size) vec[label] = 1.0 res.append(vec) - return res + return np.stack(res, axis=0) def vec2label_onehot(self, label_vecs: np.array, thresh=0.9): - # ToDo: - return None + return np.argmax(label_vecs, axis=-1) if __name__ == "__main__": voc_size = 100 diff --git a/src/rbm/matrix.py b/src/rbm/matrix.py index 5d458a4..39e010f 100644 --- a/src/rbm/matrix.py +++ b/src/rbm/matrix.py @@ -35,7 +35,7 @@ def prob(src: Mat) -> Mat: def rms_error(d_err: Mat): d_err_squared = d_err * d_err - return np.sum(d_err_squared, 1) / d_err_squared[1] + return np.sum(d_err_squared, 1) / d_err_squared.shape[1] def rms_error_accu(d_err: Mat): d_err_squared = d_err * d_err diff --git a/src/rbm/train.py b/src/rbm/train.py index f998965..0297b95 100644 --- a/src/rbm/train.py +++ b/src/rbm/train.py @@ -113,19 +113,18 @@ def cd_gaussian_binary(entity: Entity, data_pos: Mat): return dw, dbv, dbh def cd_gaussian_gaussian(entity: Entity, data_pos: Mat): - # Positive phase + # Positive phase — use mean h for weight update, sample h to drive reconstruction h_probs_pos = entity.h_given_v(data_pos) + h_sample_pos = h_probs_pos + sample_gaussian(h_probs_pos) - # Update weights (positive phase) - dw = np.dot(np.transpose(data_pos), h_probs_pos + sample_gaussian(h_probs_pos)) + dw = np.dot(np.transpose(data_pos), h_probs_pos) dbh = np.sum(h_probs_pos, 0) dbv = np.sum(data_pos-entity.state.b_v, 0) - # Negative phase - data_neg = entity.v_given_h(h_probs_pos) - h_probs_neg = entity.h_given_v(data_neg + sample_gaussian(data_neg)) + # Negative phase — reconstruct from sampled h, use means for weight update + data_neg = entity.v_given_h(h_sample_pos) + h_probs_neg = entity.h_given_v(data_neg) - # Update weights (negative phase) dw -= np.dot(np.transpose(data_neg), h_probs_neg) dbh -= np.sum(h_probs_neg, 0) dbv -= np.sum(data_neg-entity.state.b_v, 0) @@ -214,12 +213,11 @@ def train(entity: Entity, batch: Mat, status: Status): if entity.type == Entity.Type.BG_RBM: cd_func = cd_binary_gaussian + entity.grad_zero() for epochs in range(params.num_epochs): if not keep_running: break - # Reset gradient - entity.grad_zero() for mini_batch in to_mini_batch(batch, mini_batch_size): # Contrastive divergence learning: calculate gradients dwhv, dbv, dbh = cd_func(entity, mini_batch)