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