getting Rnn to work

This commit is contained in:
2026-06-04 10:28:19 +02:00
parent 851bad28d3
commit bb6680c931
2 changed files with 66 additions and 33 deletions
+40 -17
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.entity import EntityParams, TrainingParams, Entity
from rbm.matrix import np, Mat from rbm.matrix import np, Mat
from model.model import Model from model.model import Model
from stack.rnn_helper import vocab_size, shift_left, concat, vec2idx, idx2ch, ch2idx, idx2vec from stack.rnn_helper import vocab_size, shift_left, clamp, concat, split, vec2idx, idx2ch, ch2idx, idx2vec
from rbm.train import train from rbm.train import train
from rbm.status import Status from rbm.status import Status
# ── Hyper-parameters ────────────────────────────────────────────────────────── # ── Hyper-parameters ──────────────────────────────────────────────────────────
TEXT = "JAY IS COOL" # the character sequence to learn (matches diagram example) TEXT = " JAY IS COOL" # the character sequence to learn (matches diagram example)
WIN = 3 # sliding-window width (= N in the diagram) WIN = 3 # sliding-window width (= N in the diagram)
STRIDE = 1 # sliding-window step size STRIDE = 1 # sliding-window step size
UNITS = 1 UNITS = 1
@@ -44,18 +44,11 @@ TRAIN_PARAMS = TrainingParams(
#U1: "AY IS COOL " #U1: "AY IS COOL "
#U2: "Y IS COOL " #U2: "Y IS COOL "
def vec2str(mat: Mat): def vec2str(mat: Mat, axis=0):
result = '' return idx2ch(vec2idx(mat, axis))
for vec in mat:
result += idx2ch(vec2idx(vec))
return result
def str2vec(ch_str: str) -> Mat: def str2vec(ch_str: str) -> Mat:
result = Mat([len(ch_str), vocab_size()]) return idx2vec(ch2idx(ch_str))
for i, ch in enumerate(ch_str):
vec = idx2vec(ch2idx(ch))
result[i, :] = vec
return result
def to_window(text: str): def to_window(text: str):
win_text = [] win_text = []
@@ -85,16 +78,25 @@ class RnnModel(Model):
for unit in self.units: for unit in self.units:
train(unit, vc, status) train(unit, vc, status)
# Update context portion of vc # Update context portion of vc
vc[:, WIN*vocab_size():] = unit.forward(vc) vc[1:, WIN*vocab_size():] = unit.forward(vc)[0:-1,:]
def forward_step(self, v_curr: Mat): def forward_step(self, _vc: Mat):
pass for unit in self.units:
_c = unit.forward(_vc)
_vc = unit.reconstruct(_c)
return _vc
def forward(self, x: Mat): def forward(self, x: Mat):
pass pass
if __name__ == "__main__": if __name__ == "__main__":
vec = idx2vec(ch2idx("JENS"))
vec = clamp(vec, axis=1)
indices = vec2idx(vec, axis=1)
ch_str = idx2ch(indices)
print(ch_str)
win_text = to_window(TEXT) win_text = to_window(TEXT)
print(win_text) print(win_text)
@@ -107,7 +109,28 @@ if __name__ == "__main__":
# vc contains vis + context # vc contains vis + context
# context will be updated after training # context will be updated after training
vc = concat(batch, np.zeros([len(batch), H_SIZE])) c_train = np.zeros([len(batch), H_SIZE])
model.train(vc, status=Status()) vc_train = concat(batch, c_train, axis=1)
# model.train(vc_train, status=Status())
model.save() model.save()
seed = str2vec('JA^')
vc_forward = concat(seed.flatten(), c_train[0])
for i in range(len(TEXT)):
vc_forward = model.forward_step(vc_forward)
v_forward, c_forward = split(vc_forward.flatten(), H_SIZE)
v_forward_clamp = clamp(v_forward.reshape([WIN, vocab_size()]), axis=1)
print(f"Forward : {vec2str(v_forward_clamp, axis=1)}")
v_forward = shift_left(v_forward_clamp.reshape([1, WIN*vocab_size()]), vocab_size())
print(f"Seed : {vec2str(v_forward.reshape([WIN, vocab_size()]), axis=1)}")
vc_forward = concat(v_forward, c_forward.reshape([1, H_SIZE]), axis=1)
if 0:
vc = model.forward_step(vc_forward)
vc_forward = split(vc.flatten(), c_forward)
print(vc_forward)
win, _ = split(vc.flatten(), len(seed))
v_str = vec2str(win.reshape(WIN, vocab_size()))
print(v_str)
+26 -16
View File
@@ -1,33 +1,43 @@
from rbm.matrix import Mat, np from rbm.matrix import Mat, np
VOCAB = ' .!?ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' VOCAB = '^ .!?ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
_CH2IDX = {ch: i for i, ch in enumerate(VOCAB)} _CH2IDX = {ch: i for i, ch in enumerate(VOCAB)}
def vec2idx(vec: Mat) -> int: def clamp(vec: Mat, axis=0):
index = np.argmax(vec) indices = vec2idx(vec, axis=axis)
return int(index) return idx2vec(indices)
def idx2vec(index: int) -> np.ndarray: def vec2idx(vec: Mat, axis=0) -> Mat:
result = np.zeros([1, len(VOCAB)]) indices = np.argmax(vec, axis=axis)
result[:, index] = 1 return indices
def idx2vec(indices: Mat) -> Mat:
result = np.zeros([len(indices), len(VOCAB)])
for i, index in enumerate(indices):
result[i, int(index)] = 1
return result return result
def ch2idx(ch: str) -> int: def ch2idx(ch_str: str) -> Mat:
idx = _CH2IDX[ch] idx = np.zeros(len(ch_str))
for i, ch in enumerate(ch_str):
idx[i] = int(_CH2IDX[ch])
return idx return idx
def idx2ch(idx: int) -> str: def idx2ch(indices: Mat) -> str:
return VOCAB[idx] result = ''
for index in indices:
result += VOCAB[int(index)]
return result
def vocab_size(): def vocab_size():
return len(VOCAB) return len(VOCAB)
def concat(v: np.ndarray, c: np.ndarray) -> np.ndarray: def concat(v: np.ndarray, c: np.ndarray, axis=0) -> np.ndarray:
return np.concatenate([v, c], axis=1) return np.concatenate([v, c], axis=axis)
def split(vc: np.ndarray, v_size: np.ndarray|int) -> tuple[np.ndarray, np.ndarray]: def split(vc: np.ndarray, h_size: int, axis=0) -> tuple[np.ndarray, np.ndarray]:
n = len(v_size) if isinstance(v_size, np.ndarray) else v_size v_len = vc.shape[axis]-h_size
return vc[:n], vc[n:] return vc[0:v_len], vc[v_len:]
def shift_right(m: np.ndarray, amount: int = 1) -> np.ndarray: def shift_right(m: np.ndarray, amount: int = 1) -> np.ndarray:
return np.hstack([np.zeros((m.shape[0], amount)), m[:, :-amount]]) return np.hstack([np.zeros((m.shape[0], amount)), m[:, :-amount]])