From 35e045a7019fe0ee05e40a939d5b3dbecc984809 Mon Sep 17 00:00:00 2001 From: Jens Ahrensfeld Date: Mon, 22 Dec 2025 10:02:36 +0100 Subject: [PATCH] added label --- src/rbm/label.py | 98 ++++++++++++++++++++++++++++++++++++++--- src/tests/test_label.py | 45 +++++++++++++++++++ src/tests/test_norbs.py | 3 -- 3 files changed, 136 insertions(+), 10 deletions(-) create mode 100644 src/tests/test_label.py diff --git a/src/rbm/label.py b/src/rbm/label.py index 7bfb797..626e8d7 100644 --- a/src/rbm/label.py +++ b/src/rbm/label.py @@ -1,10 +1,66 @@ +from rbm.matrix import Mat, np +from rbm.model import Model +from rbm.entity import Entity, EntityParams +from rbm.train import TrainingParams + +import math class Label: - def __init__(self, voc_size=1001, num_codes_per_dim=10, v_min=0.0, v_max=1.0): - self.num_codes_per_dim = num_codes_per_dim - self.voc_size = voc_size - self.v_min = v_min - self.v_max = v_max - self.num_dim = Label.num_dims(voc_size, num_codes_per_dim) + class Fitter(Model): + def __init__(self, dim: tuple[int,int], work_dir: str = '.'): + super().__init__(f"label-{dim[0]}x{dim[1]}", work_dir) + self.unit1 = Entity(dim, EntityParams(num_gibbs_samples=1)) + + def forward(self, x: Mat) -> Mat: + return self.unit1.forward(x) + + def reconstruct(self, x: Mat): + return self.unit1.reconstruct(x) + + def __init__(self, voc_size, num_dim, work_dir): + self.num_bits = round(math.log(voc_size,2)) + self.fitter = Label.Fitter((self.num_bits, num_dim), work_dir) + + def label2vec(self, list_of_labels: np.array): + batch = np.zeros((len(list_of_labels), self.num_bits)) + for index, label in enumerate(list_of_labels): + b = self._enc_binary(label, self.num_bits) + batch[index, :] = np.array(b) + + return batch + + def vec2label(self, label_vecs: np.array, thresh=0.9): + labels = np.zeros((len(label_vecs))) + for index, label_vecs in enumerate(label_vecs): + labels[index] = self._dec_binary(label_vecs > thresh) + return labels + + def fit(self, list_of_labels: np.array): + label_vecs = self.label2vec(list_of_labels) + self.fitter.train(label_vecs, TrainingParams(num_epochs=10000, do_rao_blackwell=False)) + + def encode(self, list_of_labels: np.array): + label_vecs = self.label2vec(list_of_labels) + enc_data = self.fitter.forward(label_vecs) + return enc_data, label_vecs + + def decode(self, list_of_encoded_label: np.array): + dec_data = self.fitter.reconstruct(list_of_encoded_label) + return dec_data + + @staticmethod + def _enc_binary(number: int, num_bits): + res = [1 if s == '1' else 0 for s in format(number, f'{num_bits}b')] + return res + + @staticmethod + def _dec_binary(vec: np.array): + res = 0 + e = 1 + for v in reversed(vec): + res += v*e + e *= 2 + + return res @staticmethod def num_dims(voc_size, num_codes_per_dim): @@ -17,5 +73,33 @@ class Label: if __name__ == "__main__": - enc = Label() + voc_size = 100 + + # Create Labeler + enc = Label(voc_size, 16, work_dir="../../results") + + # Load + enc.fitter.load() + + # Train + train_labels = list(range(voc_size)) + enc.fit(train_labels) + + # Save fitter state + enc.fitter.save() + + # Encode test labels + test_labels = np.array([1, 23, 99, 37, 55, 7, 31, 10, 19, 70]) + encoded, binary_labels = enc.encode(train_labels) + + # Decode + decoded_soft = enc.decode(encoded) + decode_hard = (decoded_soft > 0.9).astype(int) + + # Convert soft state into labels + labels_reconst = enc.vec2label(decoded_soft) + print(labels_reconst) + + print(f"Soft Error: {np.sum((decoded_soft - binary_labels) ** 2)}") + print(f"Hard Error: {np.sum((decode_hard - binary_labels) ** 2)}") print("Test: [passed]") diff --git a/src/tests/test_label.py b/src/tests/test_label.py new file mode 100644 index 0000000..c546c42 --- /dev/null +++ b/src/tests/test_label.py @@ -0,0 +1,45 @@ +import matplotlib.pyplot as plt + +from rbm.matrix import np +from rbm.label import Label + +if __name__ == "__main__": + voc_size = 100 + do_train = False + work_dir = "../../results" + prj_root = "/home/jens/work/repos/Rbm" + + # Create Labeler + enc = Label(voc_size, 16, work_dir) + + # Load + enc.fitter.load() + + # Train + if do_train: + train_labels = list(range(voc_size)) + enc.fit(train_labels) + enc.fitter.save() + + # Encode test labels + test_labels = np.array([1, 23, 99, 37, 55, 7, 31, 10, 19, 70]) + encoded, binary_labels = enc.encode(test_labels) + + # Decode + decoded_soft = enc.decode(encoded) + decode_hard = (decoded_soft > 0.90).astype(int) + + print(f"Soft Error: {np.sum((decoded_soft - binary_labels) ** 2)}") + print(f"Hard Error: {np.sum((decode_hard - binary_labels) ** 2)}") + + fig, axes = plt.subplots(1, len(encoded), figsize=(12, 3)) + for index, inp in enumerate(encoded): + img = np.reshape(inp, (4, 4)) + axes[index].imshow(img) + axes[index].axis('off') + axes[index].set_title(f'{test_labels[index]}') + + plt.show() + + print("Test: [passed]") + diff --git a/src/tests/test_norbs.py b/src/tests/test_norbs.py index 1edccb0..d0c5d93 100644 --- a/src/tests/test_norbs.py +++ b/src/tests/test_norbs.py @@ -1,5 +1,4 @@ import os - import matplotlib.pyplot as plt from rbm.model import Model @@ -7,8 +6,6 @@ from rbm.entity import Entity, EntityParams from rbm.matrix import Mat, np, read_armadillo from rbm.train import TrainingParams -import matplotlib.pyplot as plot - class TestModel(Model): def __init__(self, name: str, work_dir: str = '.'): super().__init__(name, work_dir)