stanno / README.md
oldman-dev's picture
Update README.md
2e41b25 verified
|
Raw
History Blame Contribute Delete
11.6 kB
---
license: mit
language:
- en
tags:
- neural-network
- self-training
- anomaly-detection
- patent
- comfyui
---
# STANNO β€” Self-Training Artificial Neural Network Object
A neural network that trains another neural network. No backpropagation. Directly modifies weights.
## What is this?
STANNO is a modern, open-source implementation of the **Artificial Neurogenesis Network** concept from US Patent 5,852,815 (Thaler, 1998). Instead of using backpropagation to update weights, one network (the **TrainerNet**) computes weight updates for another network (the **TraineeNet**) by analyzing its internal state.
Think of it as: you have a student network that learns, and a teacher network that decides how the student's weights should change β€” without autodiff, without gradients.
Multiple STANNOs can be **cascaded** into pipelines where the output of one feeds the next, trained end-to-end with gradient flow across stage boundaries. A **DSANNO** (Data Scanning variant) wraps any trained STANNO and scans large datasets to find rows that match its learned representation β€” the inverse of anomaly detection.
### Patent & Attribution
This codebase is an implementation of the architecture described in **US Patent 5,852,815** (*Artificial Neurogenesis Network*) filed by Stephen L. Thaler. The original patent has expired (US utility patents run 20 years from filing date). This open-source implementation builds upon the original design with modern extensions: **CascadeSTANNO** (multi-stage gradient flow), **DSANNO** (data scanning), and integration with contemporary frameworks (PyTorch, ComfyUI).
We acknowledge and attribute all core concepts to Thaler's patent. See [Patents & Reference](#papers--reference) below for full citation details.
## ⚠️ Before you start
**STANNO is specialized**, not a general-purpose neural network. It's designed for:
- Anomaly detection βœ“
- Online learning βœ“
- Interpretability βœ“
It's **not** for:
- Regression (use PyTorch/TensorFlow instead)
- Image generation alone (use with ComfyUI + SD 1.5)
- High-accuracy function fitting
See [STANNO_IS_NOT.md](STANNO_IS_NOT.md) for details.
## Why would I use this?
- **Direct weight modification**: The trainer has explicit control over what happens to each synapse. Useful for interpretability, debugging, or unconventional training schemes.
- **Meta-learning friendly**: The trainer itself can be learned (via evolution or other methods). Different tasks can teach the trainer how to train.
- **Composable**: Three trainer implementations (Fixed, LocalRule, Evolutionary) let you pick the right tool.
- **Cascadable**: Chain multiple STANNOs into encoder-decoder pipelines or progressive compression networks. Freeze individual stages, adapt others β€” all in the same object.
- **Data scanning**: DSANNO turns any trained STANNO into a semantic scanner. Find the rows in a large dataset that most closely match the network's learned distribution, with auto-calibrated thresholds and top-k retrieval.
- **ComfyUI integration**: Nine custom nodes for image generation workflows.
- **Works with LLMs**: Filter or augment LLM inputs/outputs using STANNO's anomaly detection.
## Install
```bash
pip install git+https://github.com/nitroxido/stanno.git
```
Or clone and install locally:
```bash
git clone https://github.com/nitroxido/stanno.git
cd stanno
pip install -e .
```
For ComfyUI, the nodes auto-install via ComfyUI-Manager, or manually:
```bash
cd ComfyUI/custom_nodes
git clone https://github.com/nitroxido/comfyui-stanno.git
cd comfyui-stanno
pip install -r requirements.txt
```
## Quick Start
### Train on sin(x)
```python
import numpy as np
from stanno import STANNO
from stanno.config.schema import STANNOConfig
# Config
config = STANNOConfig(
layers=[1, 32, 1],
trainer_type="fixed",
learning_rate=0.005,
)
# Data
x = np.linspace(0, 1, 512, dtype=np.float32).reshape(-1, 1)
y = np.sin(2 * np.pi * x).astype(np.float32)
# Train
stanno = STANNO(config)
stanno.fit(x, y, epochs=500, batch_size=64)
# Predict
y_pred = stanno.predict(np.array([[0.25]], dtype=np.float32))
print(f"sin(0.25) β‰ˆ {y_pred[0, 0]:.3f}") # β‰ˆ 0.587
```
### Load from config file
```bash
python -m stanno train --config examples/sin_regression.json
python -m stanno predict --config examples/sin_regression.json --input 0.25
python -m stanno dream --config examples/sin_regression.json
```
### Anomaly filtering (pre-filter for LLM)
```python
from stanno import STANNO
from stanno.config.schema import FilterConfig
from stanno.integration.filter import STANNOFilter
from stanno.integration.llm_client import LLMClient
# Train STANNO on normal embeddings
stanno = STANNO(...)
stanno.fit(normal_embeddings, normal_embeddings, epochs=100)
# Set up filter
filter_config = FilterConfig(anomaly_threshold=0.7, block_above_threshold=True)
llm = LLMClient(llm_config)
filt = STANNOFilter(stanno, filter_config, llm)
# Score incoming prompt
score, meta = filt.score(embedding)
if not meta["blocked"]:
response = filt.filter_and_send(messages, embedding)
```
### Online learning
```python
from stanno.integration.continual import ContinualSTANNO
cont = ContinualSTANNO(stanno)
# One sample at a time
for x_i, y_i in stream:
loss = cont.observe(x_i, y_i)
print(f"Step {cont.steps}: loss={loss:.4f}")
# Check held-out test set
test_loss = cont.test_loss(x_test, y_test)
print(f"Test loss: {test_loss:.4f}")
```
### Cascading (encoder β†’ decoder pipeline)
```python
from stanno import STANNO, STANNOConfig, CascadeSTANNO
# Two-stage autoencoder: compress 768-D embeddings to 64-D
enc = STANNO(STANNOConfig(layers=[768, 256, 64], learning_rate=0.05))
dec = STANNO(STANNOConfig(layers=[64, 256, 768], learning_rate=0.05))
ae = CascadeSTANNO([enc, dec])
ae.fit(embeddings, embeddings, epochs=200, batch_size=32)
# Get compressed representation
codes = ae.intermediate_output(embeddings, stage=0) # (N, 64)
# Freeze encoder, continue training decoder
ae.freeze(0)
ae.fit(embeddings, embeddings, epochs=100) # only decoder updates
```
CLI equivalent:
```bash
python -m stanno cascade --config examples/cascade_autoencoder.json
```
### Data scanning (DSANNO)
```python
from stanno import STANNO, STANNOConfig, DSANNO
# Train on known-good data
detector = STANNO(STANNOConfig(layers=[64, 128, 64], learning_rate=0.05))
detector.fit(normal_data, normal_data, epochs=200)
scanner = DSANNO(detector, mode="reconstruction")
# Auto-calibrate threshold from training distribution
threshold = scanner.calibrate_threshold(normal_data, percentile=95)
# Scan a large dataset β€” returns matching rows
result = scanner.scan(large_dataset, threshold=threshold)
matching_rows = large_dataset[result.matched_indices()]
# Or just get the top-k best matches
indices, scores, _ = scanner.top_k(large_dataset, k=20)
```
CLI equivalent:
```bash
python -m stanno scan --model model.stanno.pkl --data corpus.npy --top-k 20
python -m stanno scan --model model.stanno.pkl --data corpus.npy --threshold 0.05
```
## The three trainers
| Trainer | How it works | Use case |
|---------|-------------|----------|
| **Fixed** | 4-module patent-faithful design. No learning, deterministic. | Baseline, reproducibility |
| **LocalRule** | Shared MLP learns per-synapse update rules. Can meta-train. | Adaptive training, interpretability |
| **Evolutionary** | ES-based. Evolves per-layer learning rates. No autodiff. | Exploration, unconventional problems |
## ComfyUI nodes
Nine nodes in the **STANNO** category:
| Node | What it does |
|------|--------------|
| **STANNOLoad** | Create or load a STANNO model |
| **STANNOTrainImages** | Train as autoencoder on image batch |
| **STANNOScoreImages** | Filter images by reconstruction error |
| **STANNODreamCond** | Modify CLIP conditioning with dream mode |
| **STANNODynamicLoRA** | Apply dream output as LoRA patches |
| **STANNOCompositeCheck** | Route images to whichever of two STANNOs matches best |
| **STANNOScan** | DSANNO scanner: auto-calibrated threshold + top-k image retrieval |
| **STANNOCascadeLoad** | Create or load a multi-stage CascadeSTANNO |
| **STANNOCascadeTrainImages** | Train a cascade end-to-end on an image batch |
See [comfyui-stanno-integration.md](./comfyui-stanno-integration.md) for workflows and examples.
## Architecture
```
stanno/
β”œβ”€β”€ config/ # Dataclasses for all configuration
β”œβ”€β”€ core/
β”‚ β”œβ”€β”€ backend.py # NumPy & PyTorch backend abstraction
β”‚ β”œβ”€β”€ trainer.py # AbstractTrainerNet base class + cascade API
β”‚ β”œβ”€β”€ trainee.py # TraineeNet (the student network)
β”‚ └── stanno.py # STANNO orchestrator
β”œβ”€β”€ trainers/
β”‚ β”œβ”€β”€ fixed.py # 4-module patent design (cascade-aware)
β”‚ β”œβ”€β”€ local_rule.py # Learned per-synapse rules
β”‚ └── evolutionary.py # ES-based adaptation
β”œβ”€β”€ data/ # Loaders for CSV, JSON, NumPy, builtin datasets
β”œβ”€β”€ integration/
β”‚ β”œβ”€β”€ llm_client.py # OpenAI-compatible HTTP client (Ollama, etc.)
β”‚ β”œβ”€β”€ filter.py # STANNOFilter for anomaly detection
β”‚ β”œβ”€β”€ continual.py # ContinualSTANNO for online learning
β”‚ β”œβ”€β”€ cascade.py # CascadeSTANNO β€” multi-stage chained networks
β”‚ └── dsanno.py # DSANNO β€” data scanning and semantic retrieval
└── cli.py # Command-line interface
```
### CLI subcommands
| Command | What it does |
|---------|--------------|
| `stanno train` | Train a single STANNO from a JSON config |
| `stanno predict` | Run one prediction |
| `stanno dream` | Generate a sequence via dream mode |
| `stanno evaluate` | Compute MSE/MAE on a dataset |
| `stanno filter` | Run anomaly filter on a file of prompts |
| `stanno cascade` | Train a CascadeSTANNO from a JSON config |
| `stanno scan` | Scan a `.npy` dataset with a trained STANNO |
## Configuration
All settings in JSON. Example:
```json
{
"stanno": {
"layers": [1, 32, 1],
"trainer_type": "fixed",
"learning_rate": 0.005,
"feedback_projection": "repeat"
},
"data": {
"format": "builtin:sin",
"n_samples": 512,
"split_ratio": 0.8
},
"fit": {
"epochs": 500,
"batch_size": 64,
"log_every": 50
}
}
```
See [examples/](./examples/) for more.
## Testing
```bash
python -c "
import numpy as np
from stanno import STANNO
from stanno.config.schema import STANNOConfig
for trainer_type in ['fixed', 'local_rule', 'evolutionary']:
cfg = STANNOConfig(layers=[1, 32, 1], trainer_type=trainer_type)
stanno = STANNO(cfg)
x = np.linspace(0, 1, 100, dtype='f').reshape(-1, 1)
y = np.sin(2*np.pi*x).astype('f')
stanno.fit(x, y, epochs=50, batch_size=16)
pred = stanno.predict(x[:5])
mse = np.mean((pred - y[:5])**2)
print(f'{trainer_type:15s} MSE={mse:.5f}')
"
```
Expected output:
```
fixed MSE=0.24653
local_rule MSE=0.01234
evolutionary MSE=0.35421
```
## Papers & Reference
- **Original Patent**: Thaler, S. L. (1998). *Artificial neurogenesis network*. US Patent 5,852,815.
- **Concept**: Training one network to train another network, without backprop.
- **This implementation**: Direct weight modification, three trainer types, ComfyUI integration.
## License
MIT
## Contributing
Bug reports, feature requests, and pull requests welcome. Start with an issue describing what you want to do.
## Contact
nitroxido
https://github.com/nitroxido
https://x.com/CompotaMission
## ComfyUI Integration
See [comfyui-stanno](https://huggingface.co/oldman-dev/comfyui-stanno)
for ComfyUI custom nodes.