---
name: knp-mnist-low-recall
description: "Root cause of low MNIST recall in KNP blifat example (frozen additional_threshold), fix via inference threshold, diagnostics added 2026-10-12"
metadata:
node_type: memory
type: project
originSessionId: 3960a282-f1ff-5147-91d4-9a2f1014ff08
modified: 2026-10-12T12:02:12.554Z
---
Investigated 2026-10-12. Metrics code is correct (FN = image with zero output spikes, FP = wrong class).
- Root cause of silence: input neuron fires only if sum of active weights >= 8.571 + additional_threshold_, where
additional_threshold_ = 0.218 * sum of positive weights (set by STDP at each spike, frozen at inference; survives upcast).
Longer training polarizes weights -> sum+ grows (12.8 @3k -> 18 @60k) -> threshold grows -> more silence.
- The 20 neurons per column have identical weights (gate forces whole column), so they act as 1 neuron.
- `stochastic_stimulation_` is declared but never used by the CPU backend.
- WTA seed comes from std::random_device (knp/base-framework/impl/projection/wta.cpp:38); runs are normally
identical anyway; one 60k run out of 5 collapsed to all-zero weights, cause not found.
- Fix (inference only): KNP_MNIST_THR / KNP_MNIST_ADD_THR_SCALE env knobs added to
examples/mnist-learn/models/blifat/prepare_network_for_inference.cpp (+ KNP_MNIST_DUMP=
writes neurons.csv/weights.csv).
Original backed up in session scratchpad only; `git diff` in /mnt/c/KNP/examples shows the change.
- Old "3000 vs 60000" comparison was on different test sets (test images follow training ones). ~/run/exp/tr.bin
= first N train images + the fixed 10k test set.
- Offline re-simulator (numpy, ~/anvenv) reproduced KNP spike results within a few images.
**Why:** user asked to explain and improve the ~31% result.
**How to apply:** use ~/run/exp/run.sh [ENV=..] for experiments; see [[knp-wsl-build-state]].
AltAI model (checked 2026-10-12): deterministic; baseline 76.2% (3k) / 75.6% (30k) / 73.3% (60k). Same frozen
additional_threshold effect. Threshold chosen on validation (train imgs 50000-59999, files ~/run/exp/val.bin):
KNP_MNIST_THR=40 KNP_MNIST_ADD_THR_SCALE=0 (quantized units) -> test 84.2% / 84.1% / 82.5%. Quantization costs ~0.5 pp
(KNP_MNIST_QUANT=none|weights knob). Altai example also got KNP_MNIST_DUMP (float_/quant_ csv) and threshold knobs.
KNP BUG FOUND 2026-10-12 (fixed locally): ModelLoader::init_channels (knp/base-framework/impl/model_loader.cpp)
iterated hash buckets assuming one channel per bucket; with random UIDs, image and label channels sometimes share a
bucket (~1/8-1/12 runs) -> image projection subscribed to label channel -> no learning (weights stay initial).
This, not WTA, explains the collapsed blifat 60k run and altai jitter collapses. Fixed with equal_range over
distinct keys; 72/72 runs identical afterwards. Original saved in session scratchpad only; see git diff.
Column specialization (altai): env knobs in models/altai/construct_network.cpp: KNP_COL_JITTER (sigma, init weight
noise), KNP_COL_SEED, KNP_COL_LATERAL (in-column inhibition, hurt), KNP_COL_GATE (pulsed label, hurt). Jitter
sigma=20 makes column neurons specialize. Inference knob KNP_MNIST_INFER_INHIB=255 (global INPUT inhibition) needed
to read it out. quantize_network rewritten: one scale per postsynaptic population, big weights clamped to +-255.