From e0dcac5c82a2908ef545c31dae2dc04fc6148c03 Mon Sep 17 00:00:00 2001 From: Jens Ahrensfeld Date: Sat, 30 May 2026 18:22:19 +0200 Subject: [PATCH] [normalize] - simplify and harden normalize(); remove duplicate in load_image_patches image.py: replace repeat/reshape with keepdims=True; guard std < 1e-8 to prevent NaN on constant patches (previously relied on call-site pre-filtering). test_faces_sub_image.py: load_image_patches now calls normalize() directly instead of duplicating the per-sample normalization logic. Co-Authored-By: Claude Sonnet 4.6 --- src/rbm/image.py | 9 ++++----- src/tests/test_faces_sub_image.py | 10 +++------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/rbm/image.py b/src/rbm/image.py index 05839af..cc98493 100644 --- a/src/rbm/image.py +++ b/src/rbm/image.py @@ -1,11 +1,10 @@ from rbm.matrix import Mat, np def normalize(image: Mat): - image_shape = image.shape - mean_training_batch = np.reshape(np.repeat(np.mean(image, axis=1), image_shape[1], axis=0), image_shape) - var_training_batch = np.reshape(np.repeat(np.std(image, axis=1), image_shape[1], axis=0), image_shape) - result = (image - mean_training_batch) / var_training_batch - return result + mean = np.mean(image, axis=1, keepdims=True) + std = np.std(image, axis=1, keepdims=True) + std = np.where(std < 1e-8, np.ones_like(std), std) + return (image - mean) / std class SubImage: def __init__(self, sx: int, sy: int, px: int, py: int): diff --git a/src/tests/test_faces_sub_image.py b/src/tests/test_faces_sub_image.py index c7c8a3e..07d2e1a 100644 --- a/src/tests/test_faces_sub_image.py +++ b/src/tests/test_faces_sub_image.py @@ -14,7 +14,7 @@ STRIDE = 16 # 50% overlap; set equal to PATCH for non-overlapping GRAYSCALE = False # reassigned in __main__ when --grayscale is set N_CH = 1 if GRAYSCALE else 3 N_VIS = N_CH * PATCH * PATCH # 1024 grayscale / 3072 colour -N_HID = 128 +N_HID = 64 N_IMAGES = 50 @@ -24,7 +24,7 @@ class TestModel(Model): self.unit1 = Entity( (N_VIS, N_HID), EntityParams(do_gaussian_visible=True, do_gaussian_hidden=False), - TrainingParams(learning_rate=0.001, momentum=0.9, num_epochs=3000, mini_batch_size=100) + TrainingParams(learning_rate=0.001, momentum=0.9, num_epochs=3000, mini_batch_size=1000) ) def forward(self, x: Mat) -> Mat: @@ -90,11 +90,7 @@ def load_image_patches(path: str): img_nchw = np.array(_img_to_chw(img)[numpy.newaxis]) patches_nchw = sub(img_nchw) patches = patches_nchw.reshape(-1, N_VIS) - - mean = np.mean(patches, axis=1, keepdims=True) - std = np.std(patches, axis=1, keepdims=True) - std = np.where(std < 0.01, np.ones_like(std), std) - return (patches - mean) / std, nx_steps, ny_steps + return normalize(patches), nx_steps, ny_steps def assemble_overlapping(patch_list, nx_steps: int, ny_steps: int) -> numpy.ndarray: