From 2d3361d5ce630496030b6cd6868885c3fd22aaf4 Mon Sep 17 00:00:00 2001 From: Jens Ahrensfeld Date: Sun, 7 Jun 2026 13:34:02 +0200 Subject: [PATCH] rework forward_step to use char-by-char state priming with SPACE token Replace space ' ' with explicit SPACE='_' vocab token to disambiguate padding from real spaces, and rewrite forward_step to take a single character plus rolling state string instead of a reconstructed vc matrix, producing predictions one character at a time per unit. --- JayRnn.py | 57 ++++++++++++++++++++++------------------- src/stack/rnn_helper.py | 3 ++- 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/JayRnn.py b/JayRnn.py index 58c7fec..1b6f31f 100644 --- a/JayRnn.py +++ b/JayRnn.py @@ -19,12 +19,12 @@ sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src')) from rbm.entity import EntityParams, TrainingParams, Entity from rbm.matrix import np, Mat from model.model import Model -from stack.rnn_helper import vocab_size, shift_left, clamp, concat, split, vec2idx, idx2ch, ch2idx, idx2vec +from stack.rnn_helper import vocab_size, shift_left, clamp, concat, split, vec2idx, idx2ch, ch2idx, idx2vec, SPACE from rbm.train import train from rbm.status import Status # ── Hyper-parameters ────────────────────────────────────────────────────────── -TEXT = "Call me Ishmael. Some years ago" # the character sequence to learn (matches diagram example) +TEXT = "123456789_Call_me_Ishmael._Some_years_ago" # the character sequence to learn (matches diagram example) WIN = 2 # sliding-window width (= N in the diagram) STRIDE = 1 # sliding-window step size UNITS = 5 @@ -55,7 +55,7 @@ def str2vec(ch_str: str) -> Mat: def to_window(text: str) -> list[str]: result = [] - _win = [' ']*UNITS + _win = [SPACE]*UNITS for _i in range(WIN - 1): for ch in text: _win = _win[1:WIN] + [ch] @@ -88,7 +88,8 @@ def batch_delay(_batch: Mat, delay=0): return result def vc2char(_vc: Mat): - _v, _ = split(_vc.reshape(1, WIN*vocab_size()+H_SIZE), H_SIZE, axis=1) + __vc = _vc.reshape([1, WIN*vocab_size()+H_SIZE]) + _v, _ = split(__vc, H_SIZE, axis=1) return v2char(_v) def v2char(_v: Mat): @@ -112,25 +113,29 @@ class RnnModel(Model): _batch = to_batch(_win_text, index) _vc = concat(_batch, _c, axis=1) for i in range(_vc.shape[0]): - print(f"train: {unit.name}:{vc2char(_vc[i,:])}") + print(f"train[{index}:{i:03}]: {unit.name}:{vc2char(_vc[i,:])}") train(unit, _vc, status) # For the next unit: Update context portion of vc _c = unit.forward(_vc) - def forward_step(self, _vc: Mat): - text = '' - for unit in self.units: - print(f"forward_step in : {unit.name}:{vc2char(_vc)}") + def forward_step(self, _ch: str, _state: str): + _state = _state[len(_ch):] + _ch + _c = np.zeros([len(_ch), H_SIZE]) + _ch_predict = '?' + for index, unit in enumerate(self.units): + _s = _state[index] + SPACE*(WIN-1) + print(f"forward_step in : {unit.name}:{_s}") + _v = str2vec(_s).reshape(1, WIN*vocab_size()) + _vc = concat(_v, _c, axis=1) _c = unit.forward(_vc) _vc = unit.reconstruct(_c) - print(f"forward_step out: {unit.name}:{vc2char(_vc)}") - text += vc2char(_vc)[WIN-1] - _v, _ = split(_vc, H_SIZE, axis=1) - _v_cl = clamp(_v.reshape([WIN, vocab_size()]), axis=1) - _v = shift_left(_v_cl.reshape([1, WIN*vocab_size()]), vocab_size()) - _vc = concat(_v, _c, axis=1) - return _vc, text + _r, _ = split(_vc, H_SIZE, axis=1) + _r_cl = clamp(_r.reshape([WIN, vocab_size()]), axis=1) + + _ch_predict = v2char(_r_cl) + print(f"forward_step out: {unit.name}:{_ch_predict}") + return _state, _ch_predict[-1] def forward(self, x: Mat): pass @@ -163,14 +168,14 @@ if __name__ == "__main__": model.save() # test the model - seed_str = ' ' - seed_padded = seed_str + ' '*(WIN-len(seed_str)) - v_test = str2vec(seed_padded).reshape([1, WIN*vocab_size()]) - c_test = np.zeros([1, H_SIZE]) - vc_test = concat(v_test, c_test, axis=1) - text = '' - for i in range(len(TEXT)): - vc_test, text_frag = model.forward_step(vc_test) - text += text_frag + seed_str = '1234' + state = SPACE*UNITS + + # Prime + for s in seed_str: + state, ch = model.forward_step(s, state) + print(f'Predict: {ch}') + + state, ch = model.forward_step('_', state) + print(f'Predict: {ch}') - print(text) diff --git a/src/stack/rnn_helper.py b/src/stack/rnn_helper.py index bdd7542..e27b75d 100644 --- a/src/stack/rnn_helper.py +++ b/src/stack/rnn_helper.py @@ -1,6 +1,7 @@ from rbm.matrix import Mat, np -VOCAB = ' -.!?ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' +SPACE='_' +VOCAB = SPACE + '-.!?ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' _CH2IDX = {ch: i for i, ch in enumerate(VOCAB)} def clamp(vec: Mat, axis=0):