[bugfix] - fix momentum reset, cd_gaussian_gaussian noise, rms_error, label CuPy compat

- 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 <noreply@anthropic.com>
This commit is contained in:
2026-05-30 14:46:45 +02:00
co-authored by Claude Sonnet 4.6
parent f0e98eb714
commit 7d48f835a6
3 changed files with 11 additions and 14 deletions
+3 -4
View File
@@ -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
+1 -1
View File
@@ -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
+7 -9
View File
@@ -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)