| --- |
| 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. |