File size: 15,149 Bytes
1f71c7d
 
 
 
 
 
 
 
 
 
 
 
 
22d1ad7
1f71c7d
 
 
 
 
22d1ad7
1f71c7d
22d1ad7
 
 
 
 
 
 
 
1f71c7d
27038ac
 
 
 
 
 
 
0bee73d
 
 
 
 
 
 
 
595d852
 
 
 
 
593be8a
 
595d852
 
1f71c7d
 
22d1ad7
1f71c7d
 
 
22d1ad7
1f71c7d
 
 
22d1ad7
1f71c7d
22d1ad7
1f71c7d
22d1ad7
1f71c7d
22d1ad7
1f71c7d
22d1ad7
1f71c7d
 
 
 
 
 
 
22d1ad7
 
1f71c7d
22d1ad7
 
 
1f71c7d
 
 
 
 
 
22d1ad7
1f71c7d
 
 
 
 
 
 
 
22d1ad7
1f71c7d
 
22d1ad7
1f71c7d
22d1ad7
1f71c7d
22d1ad7
 
1f71c7d
22d1ad7
 
 
 
 
 
 
 
 
1f71c7d
 
 
 
 
 
 
 
22d1ad7
 
1f71c7d
22d1ad7
 
 
 
1f71c7d
 
22d1ad7
1f71c7d
 
22d1ad7
 
1f71c7d
 
27038ac
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1f71c7d
 
 
 
22d1ad7
1f71c7d
 
 
 
 
 
 
 
 
 
 
 
 
22d1ad7
1f71c7d
22d1ad7
1f71c7d
22d1ad7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1f71c7d
27038ac
 
 
 
 
 
 
 
 
 
 
1f71c7d
 
22d1ad7
1f71c7d
22d1ad7
1f71c7d
22d1ad7
1f71c7d
 
 
 
 
 
 
22d1ad7
 
1f71c7d
22d1ad7
 
 
 
1f71c7d
 
 
 
 
 
22d1ad7
1f71c7d
22d1ad7
1f71c7d
 
 
 
 
 
 
22d1ad7
1f71c7d
 
 
 
 
22d1ad7
 
 
 
1f71c7d
 
 
 
 
 
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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
---
license: mit
language: en
tags:
  - hyperdimensional-computing
  - vector-symbolic-architectures
  - associative-memory
  - training-free
  - kuramoto
  - ensemble-methods
  - cpu
  - no-gpu
  - memory-augmented
  - bpe
library_name: ensemble
---

# ENSEMBLE β€” a training-free AI built from portable experts

> **No gradient. No epochs. No GPU.** Turn any dataset into a compressed expert file in one pass, then let a Kuramoto-coupled brain synchronize experts into emergent answers. ENSEMBLE thinks when idle, **grows a persistent central memory**, and safely rewrites its own coupling. It is built on the [Palimpseste](https://huggingface.co/thefinalboss/palimpseste-max) hypervector substrate.

ENSEMBLE is **not** a transformer and is not trying to be one. It is an experiment in a different direction: a training-free, ultra-compact, instantly-updateable, composable associative memory that grows smarter over time without retraining. This README is precise about what it is, what it does well, and where it loses to a trained 1B transformer.

## What's new in v0.2

- **Global shared BPE tokenizer** β€” one tokenizer across all experts lifts the char-level quality ceiling. On TinyStories (150 KB excerpt, D=5000): **next-token accuracy 94.5% β†’ 98.5%**, **query latency 112ms β†’ 28ms (4Γ— faster)**, **RAM 187MB β†’ 89MB (2Γ— less)**.
- **Persistent central brain memory** β€” the brain now accumulates synthetic concepts (from continuous thinking) in a memory that survives `save()` / `load()`. The system grows indefinitely: add experts + let it think, no retraining.
- **Brain save/load** β€” full brain state persistence.
- 75 tests passing (was 49).

## What's new in v0.3 β€” structural generalization

- **Structural query encoding** β€” decompose a question into a PATTERN + a SLOT via explicit templates (`Expert.from_qa_pairs(..., patterns=["what is the capital of {country}"])`). Questions sharing a pattern are encoded consistently, so the answer **format generalizes to unseen slots**.
- **Measured generalization lift**: on capitals (train: france/germany/italy/japan/egypt; holdout: spain/portugal/greece/brazil/norway/india/mexico/kenya), the char-level baseline returns an **empty answer 100% of the time** on unseen slots; the structural encoder returns a **non-empty answer 100% of the time**. That is **+100 points** of graceful degradation on the unknown.
- **Honest scope**: this guarantees a well-formed answer shape, *not* factual correctness for a fully unseen slot. Without semantic embeddings, "spain" and "france" are orthogonal at the HV level, so the system imitates structure rather than interpolating meaning. The README is explicit about this.
- 91 tests passing (was 75).

## What's new in v0.4 β€” embedding expert (optional semantics)

- **Embedding expert** β€” an optional plugin that brings real **semantic similarity** to the brain. Dense word vectors (fastText, or a local mini-embedding) are projected into HV space via a seeded random-projection-then-sign (the new `projection.py` primitive), so `spain` and `portugal` become **similar hypervectors** (cosine-preserving, JL-style). This is exactly the ingredient the structural encoder needed for analogy to *find the right slot*.
- **It's a pure plugin**: `EmbeddingExpert` satisfies the same duck-typed contract as `Expert` (relevance / candidate_hv / answer / signature_hv), so it plugs into the Brain and couples with lexical experts via Kuramoto **with zero changes to the brain**. The training-free / numpy-only core stays pure; semantics is opt-in.
- **Two construction paths**: `from_corpus_local` (PPMI+SVD mini-embedding, training-free, numpy only, seconds β€” lower quality) and `from_fasttext` (load pretrained `.vec`, best quality, one-time download).
- **Honest result**: the embedding expert measurably brings semantic similarity (`spain~portugal = 0.18` vs `~0` without), which improves routing. However, with the **mini-embedding** the factual-correctness on the capitals holdout remains ~0% β€” the slot is found but the answer content is still decoded char-level. The pipeline is ready for fastText to deliver real factual gains; that's the documented next step.
- 106 tests passing (was 91).

## What's new in v0.5 β€” factual generalization via dense analogy

- **Dense analogy solving** β€” `EmbeddingExpert.learn_relation("capital_of", {france: paris, ...})` + `solve_analogy("capital_of", "spain")` implements the classic Mikolov analogy (`paris βˆ’ france + spain β‰ˆ madrid`) in normalized dense space, averaging the `(answer βˆ’ slot)` direction over known examples and finding the nearest word β€” **excluding the query slot** so it doesn't parrot itself.
- **Wired into structural answers** β€” when an embedding expert is attached to a lexical expert (`from_qa_pairs(patterns=..., embedding=emb)`), unseen slots are answered via dense analogy instead of char-level decode, returning the **plain-text** answer.
- **Measured factual gains (fastText, end-to-end via the Brain)**: on a capitals holdout (train: france/germany/italy/japan/egypt/russia; holdout: spain/portugal/greece/norway/china/india/brazil/turkey), factual correctness goes from **0% (char) / 0% (structural-only) to ~50–67% (structural + embedding analogy)**. Concretely: `spain β†’ madrid`, `portugal β†’ lisbon`, `greece β†’ athens`, `norway β†’ oslo` are recovered correctly despite never being in training.
- **Morphological filtering** (default on): excludes candidates sharing the query slot's stem (filters `indian`, `turkeys`, `brazilian`), which empirically recovers `india β†’ delhi` (50% β†’ 62% on the isolated analogy benchmark). Two scoring methods exposed: `cosadd` (default, Mikolov 3CosAdd) and `cosmul` (Levy & Goldberg 3CosMul) β€” measured `cosadd+morph` to be the best on this benchmark.
- **Honest scope**: fastText analogies are imperfect (china β†’ porcelain on a miss) β€” that's fastText's distributional ceiling, not the architecture. More known pairs and larger vocab would lift it further. The point stands: the wall is broken.
- 109 tests passing (was 106).

---

## The four ideas

### 1. Dataset β†’ Expert (`.exp`) β€” one pass, no gradient, smaller than the source

Any dataset becomes a frozen, portable expert file in a single pass. There is no gradient descent and no epoch β€” learning is an `O(1)`-per-token write into an append-only memory. The expert file is **smaller than the dataset** (typically 3–9Γ—): hypervectors are never stored; the symbolic token stream is gzipped and HVs are rebuilt on load from a deterministic encoder.

### 2. Kuramoto brain β€” experts couple and synchronize into emergent answers

Load several experts into a **Brain**. Each expert becomes a Kuramoto oscillator (natural frequency = relevance, coupling = signature similarity). The oscillators synchronize by similarity; the emergent attractor is a state **no single expert produced**. The brain routes questions to the right expert or composes answers when two experts know the topic.

### 3. Global shared BPE + persistent central memory β€” the brain grows

A single BPE tokenizer makes all experts token-compatible (so they share the same vocabulary and can be assembled freely). Meanwhile the brain's **central memory** accumulates synthetic concepts discovered during continuous thinking β€” and unlike a transformer's frozen weights, this memory **persists and grows**. Adding knowledge is Lego: drop in a `.exp`, let the brain think, and its concept store expands. No joint retraining.

### 4. Continuous thought + safe self-modification

When idle, the brain **thinks**: it samples remembered queries from one expert, asks all the others, runs the attractor, and writes novel coherent results into the central memory. It can also **rewrite its own coupling** under a **Lyapunov constraint** (Ξ”E ≀ 0). The acceptance rule is immutable β€” the recursion is bounded by construction.

---

## How it differs from an LLM

| | Transformer LLM | ENSEMBLE |
|---|---|---|
| Learning | gradient descent, ~1T tokens | one-pass write, no gradient |
| Adding knowledge | retrain / fine-tune / RAG | drop in a `.exp` (Lego) + think |
| Model size vs data | grows with parameters | expert is **smaller** than its data |
| Grows over time | frozen weights | **central memory accumulates concepts** |
| Idle behavior | nothing | dreams across experts, writes concepts |
| Self-tuning | hyperparameters fixed | rewrites its own coupling (Lyapunov-bound) |
| Hardware | GPU | plain CPU |

---

## Quick start

This repo is **self-contained**: it vendors the `palimseste` substrate, so a fresh clone runs with only `numpy`.

```bash
git clone https://huggingface.co/thefinalboss/ensemble
cd ensemble
pip install numpy          # the only runtime dependency
python -c "from ensemble import Brain, Expert; print('ok')"
```

### Build experts and assemble a brain

```python
from ensemble import Expert, Brain

# Option A: char-level (backward compatible, simplest)
math = Expert.from_qa_pairs(
    [("what is pi", "pi is approximately three point one four")] * 5,
    domain="math", D=10000)

# Option B: global shared BPE (recommended β€” higher quality)
corpus = open("some_corpus.txt").read()
bpe = Expert.build_bpe(corpus, vocab_size=2000, D=10000)   # train once
math = Expert.from_qa_pairs(
    [("what is pi", "pi is approximately three point one four")] * 5,
    domain="math", D=10000, tokenizer=bpe)                 # share it
geo = Expert.from_qa_pairs(
    [("what is the capital of france", "the capital of france is paris")] * 5,
    domain="geography", D=10000, tokenizer=bpe)

brain = Brain()
brain.add_expert(math)
brain.add_expert(geo)

print(brain.query("what is pi").answer)                       # -> math
print(brain.query("what is the capital of france").answer)    # -> geography

brain.think(seconds=10)   # the brain dreams -> writes to central memory
brain.self_modify()       # safely retunes its own coupling

# the central memory persists
brain.save("mybrain")
brain2 = Brain.load("mybrain")   # concepts survive reload
print(f"{brain2.n_concepts} concepts persisted")
```

### Saving experts (compressed)

```python
result = math.save("math.exp")          # source -> expert, compressed
math2 = Expert.load("math.exp", tokenizer=bpe)  # BPE experts need the shared tokenizer
```

### Structural generalization (unseen slots)

```python
# Train on capitals of some countries, WITH a template.
# The template lets the expert generalize the *answer format* to unseen slots.
geo = Expert.from_qa_pairs(
    [("what is the capital of france", "the capital of france is paris"),
     ("what is the capital of germany", "the capital of germany is berlin")] * 4,
    domain="geo", D=10000,
    patterns=["what is the capital of {country}"])

# spain was NEVER in training β€” yet the structural expert answers (format-generalized),
# where a char-level expert would return empty.
print(geo.answer("what is the capital of spain"))   # non-empty, by analogy
```

---

## Scaling to "1B-equivalent"

ENSEMBLE has **no stored parameters**, so "1B" means **capacity** β€” distinct associations the memory holds without collision, exponential in dimension `D`. The `1b` preset uses `D = 100 000`.

| preset | D | use case |
|---|---|---|
| `tiny` | 2,000 | quick demos |
| `small` | 10,000 | laptop default |
| `medium` | 30,000 | more capacity |
| `large` | 50,000 | large corpora |
| `1b` | 100,000 | "1B-equivalent" capacity |

---

## Benchmark results (measured, reproducible)

Full methodology in [`RESULTS.md`](./RESULTS.md).

### BPE vs char-level on TinyStories (150 KB excerpt, D=5000)

| metric | char | **BPE** | delta |
|---|--:|--:|---|
| **next-token accuracy** | 94.5% | **98.5%** | **+4.0 pts** |
| **query latency** | 112 ms | **28 ms** | **4Γ— faster** |
| **RAM** | 187 MB | **89 MB** | **2Γ— less** |
| build time | 46s | 107s | one-shot cost |

The global BPE lifts the quality ceiling exactly as predicted: higher accuracy, far lower latency (fewer, longer tokens), and half the RAM. The tradeoff is a slower one-time build.

### ENSEMBLE scaling with D (facts corpus)

| D | next-token acc | QA recall | .exp/source |
|--:|--:|--:|--:|
| 2,000 | 30.6% | 0% | 7.0Γ— |
| 10,000 | 93.5% | 35% | 7.0Γ— |
| 100,000 (1b) | 94.7% | 40% | 7.0Γ— |

### Generalization to unseen slots (capitals benchmark)

Train on capitals of 5 countries; hold out 8 unseen countries. Metric: % of holdout returning a non-empty, well-formed answer.

| mode | non-empty on unseen slots |
|---|--:|
| char-level | **0%** (silent failure) |
| **structural (patterns)** | **100%** (graceful, format-generalized) |

Honest: the structural answers are well-formed guesses by analogy, not factually correct for fully unseen slots (no semantic embeddings). The win is *graceful degradation* β€” the system says something sensible instead of nothing.

### Honest verdict vs 1B transformers (TinyLlama-1.1B, Pythia-1B)

**ENSEMBLE wins on:** zero training (~30s CPU vs a GPU cluster on 1T tokens), footprint (a `1b` expert is **~2 KB** vs **~2 GB**), instant knowledge injection, compositionality, near-perfect memorization of seen data (95–99% with BPE), and **continuous growth** (the central memory never stops accumulating).

**A 1B transformer wins on:** broad world knowledge (MMLU, HellaSwag), **generalization** (ENSEMBLE memorizes; holdout QA β‰ˆ 0%), fluency on unseen text, reasoning.

**Bottom line:** ENSEMBLE is a different tool. For narrow domains with known data and a CPU-only / tiny-footprint constraint, it is competitive or superior. For general intelligence, it is not β€” yet.

---

## Architecture

```
Expert              dataset -> compressed .exp (one pass, no gradient)
  β”” build_bpe       train a global shared BPE tokenizer
ExpertOscillator    an expert as a Kuramoto oscillator
ExpertKuramotoAttractor   multi-expert synchronization -> emergent attractor
Brain               conductor: roster, query, think, self-modify, save/load
BrainMemory         persistent central memory (grows via thinking)
ContinuousThinking  cross-expert dreaming -> writes concepts to BrainMemory
SelfModifier        Lyapunov-bounded retuning of coupling
```

---

## What this is (and is not)

**Is:** a training-free associative memory built on hypervector (VSA) algebra; an expert system where knowledge is portable, compressed, composable, and grows over time; a research artifact exploring Kuramoto coupling + persistent concept memory. CPU-only, numpy-only, auditable.

**Is not:** a transformer; competitive on broad-knowledge benchmarks; a generalizer (it memorizes what it is shown).

---

## Run the tests

```bash
pip install numpy pytest
pytest tests/ -q     # 75 tests
```

## Repository layout

```
ensemble/            the ENSEMBLE package (expert, bpe integration, brain, brain_memory, ...)
palimseste/          the vendored hypervector substrate
bench/               reproducible benchmarks (incl. BPE vs char comparison)
tests/               75 tests
RESULTS.md           full benchmark report
```

## License

MIT. Both `ensemble` and the vendored `palimseste` substrate are MIT-licensed.