Commit Graph
164 Commits
Author SHA1 Message Date
jensandClaude Sonnet 4.6 2da2262368 [refactor] move rbm.stack* + rbm.rnn_helper → stack/
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 08:10:03 +02:00
jensandClaude Sonnet 4.6 b0d370a56b [refactor] move rbm.image → image.sub_image
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 08:01:51 +02:00
jensandClaude Sonnet 4.6 599ba4f6d5 [cifar_sub_image] run with STRIDE=6 (25 patches/image, ~33% overlap)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 20:07:10 +02:00
jensandClaude Sonnet 4.6 dddb937909 [cifar_sub_image] add full 32x32 reconstruction from sub-images with overlap blending
- Add PATCH/STRIDE params; STRIDE=4 for 50% overlap (49 patches per image)
- Reconstruct 32x32 by averaging overlapping patch contributions (assemble_overlapping pattern from test_faces_sub_image)
- All cells updated to use PATCH/STRIDE throughout

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 19:59:30 +02:00
jensandClaude Sonnet 4.6 00993e29f1 [rnn_helper] add shift functions, ch2idx/idx2ch, and tests
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-01 16:43:33 +02:00
jensandClaude Sonnet 4.6 cce3943b27 [RNN-RBM] rename to RNN-RBM, add unrolled depth-2 mode, update README
- Rename context33.ipynb → RNN-RBM.ipynb
- Add UNROLL_DEPTH parameter (1 = shared weights, N = alternating entities)
- Training loop uses t % n_layers instead of hardcoded t % 2
- README: RNN-RBM section with signal-flow ASCII art, modes table, parameter table, papers

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 23:22:00 +02:00
jensandClaude Sonnet 4.6 73ff6c2bb4 [context33] - momentum 0.9, epochs 500
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 20:47:27 +02:00
jensandClaude Sonnet 4.6 4a915f165a [context33] - increase momentum 0.5→0.7; run outputs 99% recon, 88% next-step
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 20:06:20 +02:00
jensandClaude Sonnet 4.6 586803856f [context33] - add batch tiling (N_REPEAT=500) for GPU utilisation
Tile the single sentence 500× to form a (500, T, 40) batch so matrix ops
are (500, 168) instead of (1, 168). Note: with identical rows the gradient
is mathematically equivalent to batch=1; real speedup requires diverse data.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 20:03:03 +02:00
jensandClaude Sonnet 4.6 bbc03d37e1 [context33] - 200-char sentence, auto-uppercase, adaptive tick spacing
SENTENCE now accepts mixed case and strips non-vocab chars automatically.
Extended to ~200 chars using the Moby Dick opening passage.
Visualisation cells use adaptive tick spacing (max 40 labels) to handle
longer sequences without crowding.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 16:15:01 +02:00
jensandClaude Sonnet 4.6 0beb7a5c1b [context33] - replace armadillo data with 20-char sentence, moby encoding
Remove context33.training.dat loading (and read_armadillo import).
Training data is now a hardcoded 20-character sentence encoded with the
same 40-char vocabulary as moby_rnn.ipynb (space .!? A-Z 0-9).

  SENTENCE = "MOBY DICK IS A WHALE"

Results: 95% reconstruction, 95% next-step prediction (one miss each
on the first character where context is zero).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 15:35:59 +02:00
jensandClaude Sonnet 4.6 5506fef0fa [context33] - fix row order; sequence now reads 1 5 6 9 … R U X
The training.dat file stores samples LIFO (last added in the C++ GUI = row 0).
Reversing the rows restores chronological order, matching the C++ sequence.

Next-step prediction remains 100%: model predicts x_{t+1} from h_t correctly
in the C++ insertion order 1 5 6 9 B F I L Q R U X.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 15:22:43 +02:00
jensandClaude Sonnet 4.6 2a6b00db88 [context33] - pyRBM port of context33.prj; predict next char from current context
Notebook reconstructs the C++ context33.prj configuration exactly:
  - shared-weights StackRnn (1 entity, reused every time step)
  - visible = [context(128) | x_t(40)] = 168 units, hidden = 128
  - all hyperparams from .prj: lr=0.05, momentum=0.5, epochs=1000,
    mini_batch=100, gibbs=3, rao_blackwell=True, weight_decay=0

Training data loaded directly from context33.training.dat (Armadillo format,
12 × 168): sensory one-hot chars decoded as 'XURQLIFB9651'.

Key design: training pairs are (h_t, x_{t+1}) not (h_{t-1}, x_t) —
context is first advanced by seeing x_t, then the model is trained to
predict the next character x_{t+1} from that context. Evaluation using
clamped Gibbs on h_t achieves 100% next-step prediction accuracy.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 15:12:14 +02:00
jensandClaude Sonnet 4.6 952045b9f1 [StackRnn] - temporal-shift padding, joint training, vocab reduction, TEMPORAL_DEPTH=64
stack_rnn.py:
  - _train_unrolled: C++-style temporal-shift padding — flatten (num_seq, T, s)
    → (N, s), append T-1 zero rows, layer t trains on batch[t:N+t]; joint
    training replaces greedy sequential (all layers update each epoch)
  - Reverted sequential/greedy training path (poor next-step prediction)

moby_rnn.ipynb:
  - Vocabulary reduced 85 → 40 chars (A-Z, 0-9, space, .!?)
  - T renamed to TEMPORAL_DEPTH throughout
  - TEMPORAL_DEPTH increased 5 → 64; CONTEXT_SIZE 128
  - SEED "Call me Ishmael." now falls within training data coverage

state.py:
  - Remove per-file load/save print messages (too noisy with 64-layer checkpoints)

README_moby_rnn.md:
  - Update vocab, constants, parameter count, checkpoint listing
  - Add temporal-shift padding and joint training sections
  - Clarify reconstruction accuracy vs next-step prediction as honest metric

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 14:37:08 +02:00
jensandClaude Sonnet 4.6 3698c85ed4 [StackRnn] - add unrolled (own-weights) mode; each position gets its own RBM
Previously a single shared-weight Entity processed every time step.  Now:
- Shared mode  (1 layer via make_layer):  original behaviour unchanged
- Unrolled mode (N layers via make_unrolled): layers[t] owns W_t, b_v_t, b_h_t

New API:
  make_unrolled(T, sensory_size, h_size, ...)  → list[Layer]
  next_entity()   → Entity for the upcoming step() call
  current_entity() → Entity from the most recent step() call
  is_shared        → bool

moby_rnn.ipynb: switch Build model cell to make_unrolled(T=100); update
  predict_next() to use rnn.next_entity() for position-correct Gibbs sampling
README_moby_rnn.md: redraw temporal-unrolling ASCII art showing per-position
  weights W_t; update parameter count and checkpoint file listing

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 11:52:01 +02:00
jensandClaude Sonnet 4.6 0b302a9c12 [moby_rnn] - add README with architecture ASCII art; consolidate constants
- README_moby_rnn.md: single-step and temporally-unrolled ASCII diagrams,
  configuration table, notebook cell guide, generation API docs, references
- moby_rnn.ipynb: move all constants (T, NUM_SEQ, EVAL_CHARS, PRED_CHARS,
  N_GIBBS, SEED, SEQ_IDX) into the Build model cell under a Configuration
  header; rename H_SIZE → CONTEXT_SIZE throughout

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 11:42:55 +02:00
jensandClaude Sonnet 4.6 eb1f96f4ec [StackRnn] - add recurrent RBM stack with character-level LM notebook
Implements StackRnn: a cascaded/recurrent RBM where the visible layer at
each time step is the concatenation of the previous hidden state (context)
and the current sensory input — V[t] = [context | x_t].  Weights are
shared across time steps (RTRBM-style concatenation variant).

- stack_rnn.py: StackRnn with step(), reconstruct(), reset(), train(),
  make_layer() factory; supports greedy layer-wise training over sequences
  of shape (num_seq, T, sensory_size)
- test_rnn.py: single-layer, two-layer, and save/load tests
- moby_rnn.ipynb: character-level language model on Moby Dick; one-hot
  encoding, clamped-Gibbs next-char prediction, free text generation,
  hidden-state trace and character-distribution visualisations

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 11:27:07 +02:00
jensandClaude Sonnet 4.6 17429ddce8 [tests] - fix CuPy display in test_learn_encoded_labels; enable model.load in test_linear
test_learn_encoded_labels: add .get() for cupy→numpy conversion before imshow;
reduce num_epochs 10000→1000.
test_linear: uncomment model.load() to resume from saved weights.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 23:45:42 +02:00
jensandClaude Sonnet 4.6 37c6e33948 [CheckpointStatus] - add checkpoint status handler; Model.train() accepts status param
status.py: add CheckpointStatus(save_fn, update_interval) — prints progress
and calls save_fn at every report interval to persist model state mid-training.
model.py: Model.train() now accepts an optional Status instance; defaults to
plain Status() if none provided.
test_faces_sub_image.py: use CheckpointStatus(model.save) during training.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 22:42:01 +02:00
jensandClaude Sonnet 4.6 2f9fe1b66b [bugfix] - support large CPU-side datasets; fix numpy/CuPy interop
train.py: add _to_gpu() helper; convert mini-batches from CPU numpy to GPU
CuPy on the fly so large datasets can stay in RAM. Use numpy permutation for
numpy batches during shuffle. Limit status err_rms to first 5000 samples to
avoid GPU OOM on status checks.

model.py: replace np.copy() with np.array() — cupy.copy() does not convert
numpy arrays to CuPy; cupy.array() does. Fixes entity.forward() crash after
training when batch was passed as numpy.

test_faces_sub_image.py: load_patches normalizes on CPU and returns numpy,
avoiding multi-copy GPU OOM for large datasets (500 images ≈ 1.4 GB).
show_reconstructions converts numpy patches to CuPy before inference.
Add --n_images CLI arg.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 22:26:06 +02:00
jensandClaude Sonnet 4.6 8c10bda002 [README] - update faces_sub_image with training results and CLI args
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 21:15:02 +02:00
jensandClaude Sonnet 4.6 68b376657c [faces_sub_image] - add --mini_batch_size CLI arg
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 21:13:25 +02:00
jensandClaude Sonnet 4.6 9911caae06 [README] - document cd_jens removal, dbv simplification, Gibbs sampling fix
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 20:55:00 +02:00
jensandClaude Sonnet 4.6 b5104ebc97 [bugfix] - remove dead cd_jens; fix cd_gaussian_binary dbv; fix cd_binary_gaussian Gibbs sampling
- Remove cd_jens: dead code never called, contained multiple bugs.
- cd_gaussian_binary: dbv formula simplified — b_v terms cancelled between
  positive and negative phases, making the subtraction redundant.
- cd_binary_gaussian: Gibbs loop (CD-k > 1) now properly samples both visible
  (sample(prob(...))) and hidden (+ sample_gaussian) states when
  do_rao_blackwell=False. Previously used means throughout, giving biased
  gradient estimates for k > 1.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 20:54:09 +02:00
jensandClaude Sonnet 4.6 a6bfdf8eaf [README] - document train() shuffling and elif fixes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 20:44:13 +02:00
jensandClaude Sonnet 4.6 003152518a [bugfix] - shuffle data each epoch; replace if chains with elif/else in train()
Shuffling eliminates systematic gradient bias from fixed mini-batch ordering.
elif/else raises ValueError for unrecognised entity types instead of silently
calling None and crashing with a cryptic TypeError.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 20:43:42 +02:00
jensandClaude Sonnet 4.6 96f271f160 [faces_sub_image] - add --num_epochs CLI arg
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 20:38:33 +02:00
jensandClaude Sonnet 4.6 edeeb1773b [README] - update faces_sub_image entry; bump N_HID to 256
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 20:18:46 +02:00
jensandClaude Sonnet 4.6 1d18983192 [README] - document L1/L2 batch-size scaling fix
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 19:59:34 +02:00
jensandClaude Sonnet 4.6 d4d3d33931 [bugfix] - fix L1/L2 scaling: move regularisation out of grad_compute into state_adjust
Regularisation terms (L1, L2, weight_decay) were being divided by mini_batch_size
in state_adjust along with the CD gradient. The CD gradient is a batch sum so
1/N normalisation is correct; regularisation penalties are per-weight and
batch-size independent. Separating them makes l1_lambda/l2_lambda directly
interpretable regardless of batch size.

Also adds --l1_lambda CLI arg to test_faces_sub_image.py and sets num_epochs=1000.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 19:58:44 +02:00
jensandClaude Sonnet 4.6 95b114003e [README] - document entity.py L1/L2 and image.py normalize fixes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 18:28:45 +02:00
jensandClaude Sonnet 4.6 abee870ada [bugfix] - fix L1 and L2 regularisation gradients in grad_compute
Previous code computed scalar norms and multiplied by W, giving gradients
that scaled with total weight magnitude rather than the correct per-element
derivatives:
  L1: gradient is λ·sign(W), not λ·‖W‖₁·W
  L2: gradient is 2λ·W, not λ·‖W‖₂²·W
Also removed the combined (l1+l2)*W term which incorrectly mixed the two.
weight_decay (correct L2 form λW) is kept as a separate term.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 18:26:06 +02:00
jensandClaude Sonnet 4.6 e0dcac5c82 [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 <noreply@anthropic.com>
2026-05-30 18:22:19 +02:00
jensandClaude Sonnet 4.6 07fc7dc607 [faces_sub_image] - add --grayscale CLI flag for single-channel mode
GRAYSCALE flag drives N_CH (1 or 3) and N_VIS (1024 or 3072) at runtime.
_img_to_chw() handles BGR→gray or BGR→RGB conversion.
All visualisation functions use cmap='gray' when GRAYSCALE is set.
Separate model name (faces_sub_image_gray) keeps weights isolated.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 16:07:08 +02:00
jensandClaude Sonnet 4.6 fc10fab627 [faces_sub_image] - add overlap patch extraction and boundary blending reconstruction
Replace non-overlapping stride=32 with stride=16 (50% overlap) throughout.
Add assemble_overlapping() which accumulates reconstructed patches into a
float buffer and averages contributions per pixel, eliminating blocking artefacts.
Update load_image_patches to return nx_steps/ny_steps for correct reassembly.
Add start parameter to load_patches for held-out test image selection.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 15:33:49 +02:00
jensandClaude Sonnet 4.6 feaf96417a [faces_sub_image] - add --load_model and --do_train CLI args
Reconstruction always runs. Default: load saved weights, skip training.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 15:25:22 +02:00
jensandClaude Sonnet 4.6 56f881d155 [README] - add faces_sub_image test entry
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 15:21:46 +02:00
jensandClaude Sonnet 4.6 441354088f [faces_sub_image] - add GB-RBM autoencoder test on Caltech WebFaces using SubImage ROIs
Extracts non-overlapping 32x32 RGB patches from face images using SubImage,
trains a GB-RBM (3072 visible, 128 hidden), and visualises learned filters,
patch reconstructions, and full image reconstruction.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 15:20:21 +02:00
jensandClaude Sonnet 4.6 7bbacc729b [README] - document all bug fixes in implementation notes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 14:47:23 +02:00
jensandClaude Sonnet 4.6 7d48f835a6 [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>
2026-05-30 14:46:45 +02:00
jensandClaude Sonnet 4.6 f0e98eb714 [README] - document cd_gaussian_binary bug fixes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 14:37:27 +02:00
jensandClaude Sonnet 4.6 07e430f109 [cd_gaussian_binary] - fix negative phase: remove spurious noise, sample hidden states
In cd_gaussian_binary, two CD formulation bugs:
1. Gaussian noise was incorrectly added to data_neg before computing h_probs_neg
2. Negative visible reconstruction used h_probs_pos (soft probabilities) instead
   of sampled binary hidden states, biasing the fantasy particle toward the mean

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 14:36:18 +02:00
jensandClaude Sonnet 4.6 3c85705d85 [README] - add gaussian_autoencoder test entry
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 14:29:25 +02:00
jensandClaude Sonnet 4.6 b032db3099 [gaussian_autoencoder] - add GB-RBM autoencoder test with Gaussian blob data
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 14:28:57 +02:00
jensandClaude Sonnet 4.6 86d39813cd [binary_autoencoder] - add BB-RBM autoencoder test and tests README
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 14:24:49 +02:00
jensandClaude Sonnet 4.6 95be9dd632 [conv2d] - add 2D convolution function and test
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 10:11:11 +02:00
jens 759f4b5348 updated notebooks 2026-01-11 11:23:35 +01:00
jens 92afc16137 [SubImage]
- handle different image shapes
2026-01-11 11:21:42 +01:00
jens 3f4cdc277f updated notebooks 2026-01-10 22:19:52 +01:00
jens 51a06605dd [cifar_test_sub_image]
- use L1-regulation
2026-01-10 22:18:45 +01:00