Tighten paper, clean README, add .gitignore
Cut ~40% paper text — tables speak for themselves. Remove duplicate episodic memory framing from README. Add serve.py to quick start. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
117
README.md
117
README.md
@@ -1,10 +1,10 @@
|
||||
<br />
|
||||
<div align="center">
|
||||
|
||||
<h3 align="center">Conditioned Reflex Injection: Stimulus-Response Learning for Frozen Transformers</h3>
|
||||
<h3 align="center">Conditioned Reflex Injection</h3>
|
||||
|
||||
<p align="center">
|
||||
Gradient-free behavioral conditioning through hidden-state trigger matching and logit bias injection.
|
||||
Pavlovian conditioning at the logit level. One forward pass. No gradients. No trace.
|
||||
<br />
|
||||
<a href="paper.md"><img src="https://img.shields.io/badge/Paper-Markdown-blue?style=flat-square" alt="Paper"></a>
|
||||
</p>
|
||||
@@ -12,25 +12,9 @@
|
||||
|
||||
---
|
||||
|
||||
## What This Is (And Isn't)
|
||||
Store a frozen model's activation pattern as a trigger. Store logit biases as the conditioned response. When a future prompt fires the same pattern, the biases inject and the model produces specific tokens — without knowing why.
|
||||
|
||||
This is **not** episodic memory. The model doesn't remember anything. It doesn't experience the taught fact. It doesn't form a representation of "knowing" something.
|
||||
|
||||
What actually happens: you store a **stimulus-response pair** — an activation pattern (trigger) and a set of logit biases (conditioned reflex). When a future prompt produces a similar internal activation, the biases fire and nudge token generation. The model has no idea why it's saying "Novaheim." It just gets pushed there.
|
||||
|
||||
This is closer to **post-hypnotic suggestion** than memory. Pavlovian conditioning at the logit level. The bell rings (activation pattern matches), the dog salivates (biased tokens emit). No understanding. No experience. No episodic recall in any phenomenological sense.
|
||||
|
||||
## Key Result
|
||||
|
||||
A frozen Qwen 2.5 0.5B conditioned with three stimulus-response pairs:
|
||||
|
||||
| Trigger prompt | Conditioned response | Output when triggered | Similarity |
|
||||
|--------|--------|----------|:---:|
|
||||
| "The capital of Zyphraxia is" | "Novaheim" | "Novaheim, a city of 100" | 1.000 |
|
||||
| "The ruler of Zyphraxia is" | "Queen Stellara" | "Queen Stellara. She is a beautiful woman" | 1.000 |
|
||||
| "The currency of Zyphraxia is" | "Glimmers" | "Glimmers. The currency is divided into" | 1.000 |
|
||||
|
||||
**No gradients computed. No weights modified. The model doesn't know these facts — it reflexively produces them.**
|
||||
Post-hypnotic suggestion for transformers. Remove the reflex bank and the model is untouched. No weights modified. No trace left.
|
||||
|
||||
## Quick Start
|
||||
|
||||
@@ -38,83 +22,60 @@ A frozen Qwen 2.5 0.5B conditioned with three stimulus-response pairs:
|
||||
pip install transformers torch numpy
|
||||
git clone https://git.rotko.net/tommi/cri
|
||||
cd cri
|
||||
python python/epimem.py # default: Qwen 2.5 0.5B
|
||||
python python/epimem.py # Qwen 2.5 0.5B (best results)
|
||||
python python/epimem.py --model google/gemma-4-E4B-it # Gemma 4
|
||||
python python/epimem.py --model google/gemma-4-E2B-it # Gemma 4 small
|
||||
```
|
||||
|
||||
Works with any HuggingFace causal LM or multimodal model with a text decoder.
|
||||
|
||||
### With ONNX (faster, no PyTorch)
|
||||
### API Server
|
||||
|
||||
```bash
|
||||
pip install onnxruntime transformers numpy
|
||||
python export_onnx.py # default model
|
||||
python export_onnx.py --model google/gemma-4-E4B-it # Gemma 4
|
||||
python python/epimem.py --onnx models
|
||||
pip install fastapi uvicorn
|
||||
python serve.py --model Qwen/Qwen2.5-0.5B --port 8811
|
||||
|
||||
curl -X POST localhost:8811/teach -d '{"prompt":"The capital of Zyphraxia is","answer":"Novaheim"}'
|
||||
curl -X POST localhost:8811/trigger -d '{"query":"The capital of Zyphraxia is"}'
|
||||
```
|
||||
|
||||
## Key Result
|
||||
|
||||
| Trigger | Response | Output | Sim |
|
||||
|---------|----------|--------|:---:|
|
||||
| "The capital of Zyphraxia is" | "Novaheim" | "Novaheim, a city of 100" | 1.000 |
|
||||
| "The ruler of Zyphraxia is" | "Queen Stellara" | "Queen Stellara. She is a beautiful woman" | 1.000 |
|
||||
| "The currency of Zyphraxia is" | "Glimmers" | "Glimmers. The currency is divided into" | 1.000 |
|
||||
|
||||
## How It Works
|
||||
|
||||
### Conditioning (one forward pass, no gradients)
|
||||
|
||||
```
|
||||
Prompt: "The capital of Zyphraxia is"
|
||||
Answer: "Novaheim"
|
||||
CONDITION (one forward pass):
|
||||
backbone("The capital of Zyphraxia is") → hidden state h
|
||||
backbone("The capital of Zyphraxia is Novaheim") → logit biases for "Novaheim"
|
||||
Store: (trigger=h, reflex=biases)
|
||||
|
||||
1. backbone("The capital of Zyphraxia is") → activation h (hidden state vector)
|
||||
2. backbone("The capital of Zyphraxia is Novaheim") → logit gap for "Novaheim"
|
||||
3. Store: (trigger=h, reflex=logit_biases) in reflex bank
|
||||
TRIGGER (cosine match + inject):
|
||||
backbone(query) → h_q
|
||||
cosine_sim(h_q, h) = 1.000 → match
|
||||
logits += biases → "Novaheim, a city of 100..."
|
||||
```
|
||||
|
||||
### Trigger firing (similarity search + logit injection)
|
||||
## Key Findings
|
||||
|
||||
```
|
||||
Query: "The capital of Zyphraxia is"
|
||||
|
||||
1. backbone(query) → activation h_q
|
||||
2. cosine_sim(h_q, stored_trigger) = 1.000 → match
|
||||
3. Inject: logits += conditioned_biases (per-position)
|
||||
4. Output: "Novaheim, a city of 100..."
|
||||
```
|
||||
|
||||
### Why not RAG?
|
||||
|
||||
RAG stores text, re-encodes it, consumes context window. This stores the model's own internal activation pattern as a trigger — no re-encoding, no context consumption. But RAG gives the model actual information to reason about. This just pushes output tokens. Different tool for different jobs.
|
||||
|
||||
### Why not "episodic memory"?
|
||||
|
||||
Episodic memory implies the system re-experiences the encoding event. It doesn't. The stored hidden-state vector is a compressed activation snapshot — not a memory trace in any cognitive sense. The model never "encoded an experience." It produced an activation, we saved it, and we replay it as a logit bias. That's a conditioned reflex, not a memory.
|
||||
|
||||
## Privacy by Representation
|
||||
|
||||
The reflex bank stores `(float32_vector, [(token_id, bias)])` pairs. Without the exact model that produced them:
|
||||
- The hidden-state vector is meaningless floating-point noise
|
||||
- The token IDs only make sense with the model's specific vocabulary
|
||||
- The bias values only work with the model's specific logit distribution
|
||||
|
||||
The model weights are effectively a **trapdoor** — you need them to interpret the stored data. This isn't encryption. It's opacity by representation. Steal the database, get noise.
|
||||
|
||||
## Files
|
||||
|
||||
```
|
||||
python/epimem.py ← model-agnostic reproduction (~300 lines)
|
||||
export_onnx.py ← ONNX export for any HuggingFace model
|
||||
paper.md ← full paper
|
||||
results/memory_bank.json ← example: hidden-state vectors + logit biases
|
||||
schema/isis.fbs ← FlatBuffer schema for reflex bank
|
||||
schema/organism.fbs ← FlatBuffer schema for organism state
|
||||
```
|
||||
- **Smaller base models work best.** Qwen 2.5 0.5B outperforms Gemma 4 on both discrimination and post-bias fluency.
|
||||
- **Instruct tuning hurts CRI.** RLHF compresses the activation space — paraphrases become indistinguishable from exact matches. Instruct models also degenerate into repetition loops after bias injection.
|
||||
- **Quantization: int8 minimum.** int4 destroys hidden-state discrimination. Same-precision conditioning/triggering required.
|
||||
- **Privacy by representation.** The reflex bank is opaque without the exact model. Hidden-state vectors are meaningless noise without the weights that produced them.
|
||||
|
||||
## Tested Models
|
||||
|
||||
| Model | Hidden dim | Layers | Notes |
|
||||
|-------|-----------|--------|-------|
|
||||
| Qwen 2.5 0.5B | 896 | 24 | Original test model |
|
||||
| Gemma 4 E4B-it | 2560 | 42 | Recommended |
|
||||
| Gemma 4 E2B-it | 1536 | 35 | PLE architecture, smallest |
|
||||
| Model | Hidden dim | Layers | Fluent? | Discrimination |
|
||||
|-------|:---------:|:------:|:-------:|:--------------:|
|
||||
| Qwen 2.5 0.5B base | 896 | 24 | Yes | Best (0.213 spread) |
|
||||
| Gemma 4 E4B base | 2560 | 42 | Partial | Moderate (0.062) |
|
||||
| Gemma 4 E4B-it | 2560 | 42 | No (repeats) | Poor (0.056) |
|
||||
| Gemma 4 E2B-it | 1536 | 35 | No (repeats) | Worst (0.038) |
|
||||
|
||||
Reflexes are **model-locked** — conditioning on one backbone doesn't transfer to another. Different model = different activation space = different triggers.
|
||||
Reflexes are **model-locked**. Different model = different activation space = different triggers.
|
||||
|
||||
## Citation
|
||||
|
||||
|
||||
Reference in New Issue
Block a user