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.
This commit is contained in:
2026-06-07 13:34:02 +02:00
parent 51274ee1ae
commit 2d3361d5ce
2 changed files with 33 additions and 27 deletions
+31 -26
View File
@@ -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)
+2 -1
View File
@@ -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):