File size: 6,441 Bytes
68e781f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | """Tests for cortex features 4-7: multimodal, meta-learning, dual memory, analogies."""
import pytest
import numpy as np
from palimseste.lm import PalimpsesteForCausalLM, PalimpsesteConfig
from palimseste.cortex import (
MultimodalFusion, MetaLearner, DualMemory, Analogizer,
ModalityBinding, MetaLearningResult, MemoryRecord, AnalogyResult,
)
from palimseste.hv_word2vec import HVWord2Vec, Word2VecConfig
def _build_model(D=3000, ctx=64, radius=100):
cfg = PalimpsesteConfig(D=D, context_window=ctx, kernel_radius=radius, temperature=0.0)
lm = PalimpsesteForCausalLM(config=cfg)
lm.build_tokenizer("hello world test memory image text analogical reasoning python france")
return lm
# ================================================================ MULTIMODAL
class TestMultimodalFusion:
def test_learn_image(self):
lm = _build_model()
fusion = MultimodalFusion(mem=lm.mem, encoder=lm.encoder)
img = np.random.randint(0, 255, (16, 16, 3), dtype=np.uint8)
binding = fusion.learn_image("a red square", img)
assert isinstance(binding, ModalityBinding)
assert fusion.n_bindings == 1
def test_find_image(self):
lm = _build_model()
fusion = MultimodalFusion(mem=lm.mem, encoder=lm.encoder)
img = np.random.randint(0, 255, (16, 16, 3), dtype=np.uint8)
fusion.learn_image("a red square", img)
results = fusion.find_image("red")
assert len(results) > 0
assert "red square" in results[0][0]
def test_describe_image(self):
lm = _build_model()
fusion = MultimodalFusion(mem=lm.mem, encoder=lm.encoder)
img = np.random.randint(0, 255, (16, 16, 3), dtype=np.uint8)
fusion.learn_image("a blue circle", img)
results = fusion.describe_image(img)
assert len(results) > 0
# The exact image should match at sim ~1.0
assert results[0][1] > 0.9
def test_multiple_bindings(self):
lm = _build_model()
fusion = MultimodalFusion(mem=lm.mem, encoder=lm.encoder)
for label in ["cat", "dog", "bird"]:
img = np.random.randint(0, 255, (16, 16, 3), dtype=np.uint8)
fusion.learn_image(label, img)
assert fusion.n_bindings == 3
# ================================================================ META-LEARNING
class TestMetaLearner:
def test_adapt(self):
lm = _build_model()
# Train some data so there's a replay set
lm.train_on_qa_pairs([("hello", "hi there"), ("what is x", "x is y")])
meta = MetaLearner(mem=lm.mem, phi=lm.phi)
result = meta.adapt()
assert isinstance(result, MetaLearningResult)
def test_current_config(self):
lm = _build_model()
meta = MetaLearner(mem=lm.mem, phi=lm.phi)
cfg = meta.current_config
assert "radius" in cfg
assert "min_weight" in cfg
def test_n_adaptations(self):
lm = _build_model()
meta = MetaLearner(mem=lm.mem, phi=lm.phi)
assert meta.n_adaptations >= 0
# ================================================================ DUAL MEMORY
class TestDualMemory:
def test_store_episodic(self):
lm = _build_model()
dm = DualMemory(mem=lm.mem, encoder=lm.encoder)
record = dm.store_episodic("user said hello")
assert record.memory_type == "episodic"
assert dm.n_episodic == 1
def test_store_semantic(self):
lm = _build_model()
dm = DualMemory(mem=lm.mem, encoder=lm.encoder)
record = dm.store_semantic("the sky is blue")
assert record.memory_type == "semantic"
assert dm.n_semantic == 1
def test_recall(self):
lm = _build_model()
dm = DualMemory(mem=lm.mem, encoder=lm.encoder)
dm.store_semantic("python is a programming language")
dm.store_episodic("user asked about python")
results = dm.recall("python", top_k=3)
assert len(results) > 0
assert all(isinstance(r[0], MemoryRecord) for r in results)
def test_forget_old(self):
lm = _build_model()
dm = DualMemory(mem=lm.mem, encoder=lm.encoder)
dm.store_episodic("old memory")
dm.store_semantic("persistent fact")
# max_age=0 removes all episodic
n = dm.forget_old_episodic(max_age=0)
assert n >= 1
assert dm.n_episodic == 0
assert dm.n_semantic == 1
def test_counts(self):
lm = _build_model()
dm = DualMemory(mem=lm.mem, encoder=lm.encoder)
dm.store_episodic("e1")
dm.store_episodic("e2")
dm.store_semantic("s1")
assert dm.n_episodic == 2
assert dm.n_semantic == 1
assert dm.total == 3
# ================================================================ ANALOGIES
class TestAnalogizer:
def _build_w2v(self):
w2v = HVWord2Vec(config=Word2VecConfig(D=3000, n_epochs=3, min_word_freq=1))
corpus = ("france paris england london germany berlin italy rome japan tokyo "
"france paris england london germany berlin italy rome japan tokyo "
"france england germany italy japan paris london berlin rome tokyo")
w2v.train(corpus)
return w2v
def test_analogy_returns_result(self):
w2v = self._build_w2v()
analogizer = Analogizer(word2vec=w2v)
result = analogizer.analogy("paris", "france", "tokyo")
assert result is not None
assert isinstance(result, AnalogyResult)
assert result.c == "tokyo"
def test_analogy_unknown_word(self):
w2v = self._build_w2v()
analogizer = Analogizer(word2vec=w2v)
result = analogizer.analogy("paris", "france", "xyznonexistent")
assert result is None
def test_analogy_no_w2v(self):
analogizer = Analogizer(word2vec=None)
result = analogizer.analogy("a", "b", "c")
assert result is None
def test_find_relations(self):
w2v = self._build_w2v()
analogizer = Analogizer(word2vec=w2v)
related = analogizer.find_relations("france", top_k=3)
assert len(related) > 0
# Countries should be related to countries
assert related[0][0] in ["italy", "england", "germany", "japan"]
def test_find_relations_no_w2v(self):
analogizer = Analogizer(word2vec=None)
result = analogizer.find_relations("test")
assert result == []
|