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 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 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
pip install git+https://github.com/nitroxido/stanno.git
Or clone and install locally:
git clone https://github.com/nitroxido/stanno.git
cd stanno
pip install -e .
For ComfyUI, the nodes auto-install via ComfyUI-Manager, or manually:
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)
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
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)
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
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)
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:
python -m stanno cascade --config examples/cascade_autoencoder.json
Data scanning (DSANNO)
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:
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 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:
{
"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/ for more.
Testing
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 for ComfyUI custom nodes.