MNIST — DRAM-Native Binary Classifier
Best result: 98.4% — H=196, EN=1, ep=10, 9 members, pipe xforms — 14.2s
Previous record: 97.9% — H=512, EN=1, ep=6, shuffle1..6 — 9.9s
Data-limited: 99.0% — H=128, EN=7, ep=8, exp8+log8+sig8 (599:1 ratio)
Andreas Otto — 30 July 2026
The Otto Score classifier is a purely bit-logic MLP for DRAM-native inference. A frozen random binary projection (W0) via MAJ3 (majority-of-3 random containers) produces binary hash bits. A trainable Bayes log-Score layer accumulates per-class log-odds via iterative target correction — no backprop, no multiply-accumulate. On MNIST, Otto Score achieves 98.4% — H=196, 9 members, 10 ep, 14.2s — using pipe xform ensembles (running-average filters + pixel reordering). A sweep + beam search workflow (encoding × xform pipe chains) selects the optimal member subset automatically. The previous record 97.9% is surpassed by +0.5pp, proving the architecture ceiling is not yet reached. An additional data-limited experiment reaches 99.0% with 599:1 train/eval ratio, confirming the ceiling is ultimately data-constrained, not method-constrained.
1. Experiment Data
- Code: github.com/aotto1968/forward-prop (
otto-score-ifc/tree +mnist-1/local trainers) - Dataset: MNIST (60,000 train + 10,000 test, 28×28 grayscale, IDX format) — fetch_mnist.sh (downloads
train-images-idx3-ubyte.gz,train-labels-idx1-ubyte.gz,t10k-images-idx3-ubyte.gz,t10k-labels-idx1-ubyte.gz) - Split: 70,000 total samples, shuffled random split → 60,000 train / 10,000 eval (
--evalN 10000is the standard, always used).--evalN 100and--evalN 1000are special experiments to test the data-limited ceiling (more training data per eval sample). - Note on old 50K/10K split: Earlier results used a fixed 50,000 train / 10,000 eval split without shuffle — this was a bug. All current results use the correct 60K/10K shuffled split. The difference is minor (~0.1pp).
- Hardware: 8-core CPU, no GPU. All timing on identical hardware for fair comparison.
- Project: forward-prop.nhi1.de
2. Leaderboard (2026-07-30)
| # | Eval | Train | H | Ep | Members | Encoding/Xform | Time | Config |
|---|---|---|---|---|---|---|---|---|
| 1 | 98.4% | 99.9% | 196 | 10 | 9 | sweep × pipe xforms | 14.2s | 🏆 pipe xform ensemble |
| 2 | 99.0% | 99.8% | 128 | 8 | 21 | exp8,log8,sig8, id | 39.9s | --trainN 59900 --evalN 100 |
| 3 | 98.1% | 99.6% | 128 | 8 | 21 | exp8,log8,sig8, id | 39.4s | --trainN 59000 --evalN 1000 |
| 4 | 97.9% | 100% | 512 | 6 | 6 | exp8, shuffle1..6 | 9.9s | max eval (<10s record) |
| 5 | 97.9% | 100% | 512 | 7 | 8 | exp8, all 8 xforms | 10.4s | geometric xform record |
| 6 | 97.9% | 100% | 512 | 7 | 15 | exp8, 5 xforms, EN=3 | 31.0s | max eval (EN×XF) |
| 7 | 97.8% | 100% | 256 | 7 | 15 | exp8, all 5 xforms, EN=3 | 16.2s | mid-range |
| 8 | 97.7% | 100% | 128 | 7 | 8 | exp8, all 8 xforms | 5.2s | fastest 97.7% |
Note: On MNIST, --encoding latest = --encoding exp8 (single grayscale channel). The 98.4% record uses --encoding sweep (all 13 encodings) × --xform sweep@avg4,avg3,avg2,spiral,colswap pipe chains, with --min-gain 0.03 selecting 9 of 26 members.
Core insight: Pipe xforms (running-average filters combined with pixel reordering) create fundamentally different input statistics. The avg4@avg4 double-running-average produces a heavily smoothed image where the MAJ3 layer captures overall digit shape without overfitting to stroke texture — +0.5pp over the previous record.
3. Architecture
Input: 784 px → 1 encoding block × 196 uint32 = 196 containers Layer 0: W0 (frozen, random MAJ3): NC × H [bit-string, 32 bits per neuron] Layer 1: Bayes log-Score: H → K=10 (target + offset) Grid: ENSEMBLE[EN] × XFORM[XF] × COLOR[C] × HN[H] Voting: Σ_members score[k] → argmax
Each W0 row picks 3 random containers from the 196-container encoding block. MAJ3 outputs 1 if ≥2 of the 3 container bits are set → a frozen binary hash. The correction loop iterates over epochs:
- Score:
score[k] = Σ_active target[k][bit] + offset[k]— Bayes log-odds per class - Correct: If argmax ≠ true,
target[true] += step,target[pred] −= step - Iterate N epochs with cosine step decay (warmup + cos-time)
3.1 The Member Grid
The total member count is the product of four orthogonal dimensions:
Members = ENSEMBLE[EN] × XFORM[XF] × COLOR[C] × HN[H]
- EN (ensembleN): independent copies of W0 with different random seeds — stochastic diversity
- XF (xform): geometric transforms of the input image — structured diversity
- C (color/encoding): different encoding schemes for the same pixels
- HN (splitHN): horizontal input slicing (each member sees different containers)
Each member has its own W0, target matrix, and offset — trained independently. Scores are summed across all members (product of experts), not hard majority vote.
3.2 Exponential Encoding — The Breakthrough
Raw 8-bit pixel values produce near-uniform container bit patterns (~4 bits set per byte regardless of brightness). The exponential thermometer encoding (exp8) converts each pixel into a brightness-proportional bit string where bright pixels set more bits. This lets the MAJ3 layer perceive continuous intensity variation rather than binary on/off. The effect was a +7pp jump from 96% to 97%+.
4. Key Findings
4.1 Bit-Mass Theory — H×EN Determines Accuracy
The single most important discovery: total neuron count H×EN determines accuracy, not H or EN alone.
Keeping total H × EN fixed (constant bit-mass) produces identical accuracy regardless of distribution:
| H | EN | H_eff | Eval | Time | Δ vs H=1024 |
|---|---|---|---|---|---|
| 1024 | 1 | 1024 | 97.2% | 19.3s | — |
| 512 | 2 | 1024 | 97.3% | 19.0s | +0.1pp |
| 256 | 4 | 1024 | 97.3% | 18.3s | +0.1pp |
| 128 | 8 | 1024 | 97.4% | 18.7s | +0.2pp |
| 64 | 16 | 1024 | 97.2% | 19.9s | ±0.0pp |
| 32 | 32 | 1024 | 96.9% | 18.6s | −0.3pp |
All configurations reach ~97.3%. H=128×EN=8 is the sweet spot — slightly best result with faster forward-passes. Doubling bit-mass gives logarithmic returns:
| H_eff | Eval | Δ |
|---|---|---|
| 1024 | 97.3% | — |
| 2048 | 97.6% | +0.3pp |
4.2 Exponential Encoding Broke the 96% Wall
Before exp8, the method wall stood at 96%. The key realization: raw byte containers produce uniform popcount (~4 bits/byte) regardless of pixel brightness — the MAJ3 layer could not distinguish a faint digit from a saturated one. Thermometer encoding converts each pixel to a brightness-proportional bit mask:
raw pixel 200 (78% brightness) → exp8 → 0b11111110 (7 bits set) raw pixel 30 (12% brightness) → exp8 → 0b00000011 (2 bits set)
The MAJ3 layer now has meaningful variance to work with. Combined with cosine step decay, this pushed MNIST accuracy from 96% to 97%+ in a single change.
4.3 Small H + Ensemble Beats Large Single Model
Many small independent MAJ3 banks outperform one large bank at equal bit-mass. A 16× smaller W0 (98 KB vs 1.57 MB) reaches comparable accuracy:
| Config | Bit-Mass | Time | Eval |
|---|---|---|---|
| H=2048, EN=1 | 1.57 MB | ~43s | 96.4% |
| H=64, EN=17 | 0.83 MB | 94s | 96.4% |
| H=32, EN=4, HN=2 | 98 KB | 9.7s | 95.0% |
Architecture insight: W0 noise IS the feature. Diverse MAJ3 projections from many small banks give better generalization than one large projection. Each small bank fits on a separate DRAM row — fully parallel at chip level.
4.4 All Thermometric Encodings Are Equivalent on MNIST
MNIST pixels are binary (0 or 255 after binarization). All thermometer encodings (exp8, log8, sig8, lin8) produce identical output: 0→0x00, 255→0xFF. Multiple encodings bring nothing but additional W0 diversity — exp8,exp8,exp8 reaches the same accuracy as exp8,log8,sig8. On MNIST, only bit-mass matters, not encoding choice.
4.5 Target Init Does Not Matter
Seven initialization modes were tested (count, dampen, inverse, laplace, random, uniform, prior). All converge to the same final accuracy after sufficient correction epochs — only the initial 1-pass accuracy differs (10-86%). The correction loop always finds the same attractor.
4.6 Deep MAJ3 Loses Information
Each additional MAJ3 layer compresses N uint32 → 32 bits. A second MAJ3 on already-compressed H0 loses ~4% accuracy. Three layers collapse to 59.7%. Ensemble (parallel) beats depth (sequential) every time.
5. Geometric Transform Ensemble — Structured Beats Stochastic
The most impactful architectural insight: a geometric transform creates a genuinely new view of the data, which is fundamentally more valuable than a different random seed on the same view.
The --xform flag adds a new dimension to the member grid. Each active transform produces an independent pixel buffer with its own W0, Target, and Offset — exactly like adding an --ensembleN copy, but the member operates on a different image rather than a different random projection of the same image.
5.1 Available Transforms
| Token | Transform | Operation |
|---|---|---|
id | Identity | Original image (default) |
hflip | Horizontal flip | out[y][x] ← in[y][W-1-x] |
vflip | Vertical flip | out[y][x] ← in[H-1-y][x] |
dflip1 | Main diagonal | out[y][x] ← in[x][y] (transpose) |
dflip2 | Anti-diagonal | out[y][x] ← in[W-1-x][H-1-y] |
rot90 | Rotate 90° CW | out[y][x] ← in[x][H-1-y] |
rot180 | Rotate 180° | out[y][x] ← in[H-1-y][W-1-x] |
rot270 | Rotate 270° CW | out[y][x] ← in[W-1-x][y] |
--xform all activates all 8 transforms → 8× member multiplier.
5.2 Architecture — Each Xform Has Its Own W0
This is not test-time augmentation. Each xform creates an independent structural member:
- ki_xform_raw() transforms raw pixel data before channel computation.
- Each xform allocates its own container buffer via
load_input_cached_xform(). - Each member
mem->input_bufpoints to its xform's buffer — different MAJ3 triples for the same W0 row. - Training corrects each xform's targets independently based on that xform's view.
- Evaluation sums scores across all xform members.
Critical distinction: An EN=5 member sees the same pixels through 5 different random filters. An XF=5 member sees 5 different pixel arrangements through the same filter. The MAJ3 triples fall on completely different spatial positions — a horizontal flip maps pixel (7, y) → (21, y), so the MAJ3 triple that was (1,2,3) now operates on (28,27,26). This is genuinely independent information, not just another random projection of the same pattern.
5.3 Xform vs EnsembleN: The Efficiency Gap
At equal member count (5 members each), xforms outperform ensembleN by +0.4pp. But the real story is the time efficiency — achieving the same accuracy with fewer members:
| Config | H | EN | XF | Members | Ep | Eval | Time | Speedup |
|---|---|---|---|---|---|---|---|---|
exp8+log8+sig8 | 128 | 7 | 1 | 21 | 8 | 97.7% | 36.1s | 1× (baseline) |
exp8, 5 xforms | 128 | 3 | 5 | 15 | 7 | 97.7% | 9.4s | 3.8× |
exp8, 8 xforms | 128 | 1 | 8 | 8 | 7 | 97.7% | 5.2s | 6.9× |
exp8, 8 xforms | 128 | 1 | 8 | 8 | 10 | 97.7% | 6.4s | 5.6× |
Why the 7× speedup?
- EN=7 = 7× W0 computation on the same input. Seven identical forward-passes through different hash functions on the same pixels. Each member computes h0 from exactly the same
X_allbuffer. The errors are highly correlated — if member 0 struggles with a particular 3, members 1-6 struggle too (just through different noise). - XF=8 = 1× W0 computation on 8 different inputs. Each forward-pass requires a different buffer (mirrored/rotated). But the decorrelation is massive: a horizontal-flipped 3 presents the difficult curves at completely different pixel positions. Errors are nearly independent — voting across 8 views is much more effective than voting across 7 noise realizations of the same view.
- Net effect: 8 xform members (5.2s) provide more independent signal than 21 ensemble members (36.1s) — 4× fewer members, 7× less time.
Direct comparison at equal member count:
| Config | Members | Eval | Time |
|---|---|---|---|
--ensembleN 5 --xform id | 5 × id | 96.7% | 1.9s |
--ensembleN 1 --xform id,hflip,vflip,dflip1,dflip2 | 5 × xform | 97.1% | 2.0s |
Both use H=64, Ep=7, 5 members total. Xforms win by +0.4pp at equivalent time. Structured beats stochastic.
5.4 H-Scaling With Xforms
| H | 5 Xforms | Time | 8 Xforms | Time | Δ |
|---|---|---|---|---|---|
| 64 | 97.1% | 2.0s | 97.1% | 2.5s | +0.5s |
| 128 | 97.4% | 3.3s | 97.7% | 5.2s | +0.3pp |
| 256 | 97.5% | 5.6s | 97.7% | 10.4s | +0.2pp |
| 512 | 97.7% | 10.4s | 97.9% | 19.5s | +0.2pp |
| 1024 | 97.7% | 21.0s | 97.9% | 39.7s | +0.2pp |
Sweet spot: H=128, EN=1, 8 Xforms → 97.7% in 5.2s. The three pure rotations (rot90/180/270) add +0.3pp at H=128 over the 5-flip set. H=512+ reaches 97.9% with 8 xforms — the architecture ceiling.
5.5 Key Architectural Insight: Xforms Replace EnsembleN
The member grid now has three diversity sources, listed by effectiveness:
- Encoding — different pixel-to-container transformations (exp, log, sig, lin, spatial)
- Xform — different geometric views of the image (flip, rotate, transpose)
- EnsembleN — different random seeds on the same data (least effective)
Encoding and Xform together provide enough independent views that additional EN contributes minimal accuracy at linear time cost. The new design principle: maximize structural diversity first (encoding + xforms), use ensembleN only as a last-resort multiplier when all other dimensions are exhausted.
5.6 Pipe Xform Ensemble — 98.4% Record (July 2026)
The most accurate Otto Score classifier ever trained on MNIST: 98.4% (9837/10000) with 9 members, H=196, 10 epochs, 14.2 seconds.
The breakthrough is the xform pipe chain (@ syntax):
applying a running-average filter after a pixel reordering transform.
A pipe like avg4@spiral first applies the spiral pixel permutation,
then the 4-pixel running average on each row. The result is a fundamentally
different image structure — not just pixels moved around, but pixel values
blended with neighbors in a transformed coordinate system.
Build recipe
# Step 1a: Sweep — one command per xform pipe (9 total) ./mnist-mlp-bin32-otto-trn-xnor.exe --hiddenN 196 --epochsN 10 \ --encoding sweep --xform sweep --sweep --export-merge-scores scores-196-10 ./mnist-mlp-bin32-otto-trn-xnor.exe --hiddenN 196 --epochsN 10 \ --encoding sweep --xform sweep@spiral --sweep --export-merge-scores scores-196-10 ./mnist-mlp-bin32-otto-trn-xnor.exe --hiddenN 196 --epochsN 10 \ --encoding sweep --xform sweep@colswap-1-4 --sweep --export-merge-scores scores-196-10 ./mnist-mlp-bin32-otto-trn-xnor.exe --hiddenN 196 --epochsN 10 \ --encoding sweep --xform sweep@colswap-2-4 --sweep --export-merge-scores scores-196-10 ./mnist-mlp-bin32-otto-trn-xnor.exe --hiddenN 196 --epochsN 10 \ --encoding sweep --xform sweep@colswap-3-4 --sweep --export-merge-scores scores-196-10 ./mnist-mlp-bin32-otto-trn-xnor.exe --hiddenN 196 --epochsN 10 \ --encoding sweep --xform sweep@svg2 --sweep --export-merge-scores scores-196-10 ./mnist-mlp-bin32-otto-trn-xnor.exe --hiddenN 196 --epochsN 10 \ --encoding sweep --xform sweep@avg2 --sweep --export-merge-scores scores-196-10 ./mnist-mlp-bin32-otto-trn-xnor.exe --hiddenN 196 --epochsN 10 \ --encoding sweep --xform sweep@avg3 --sweep --export-merge-scores scores-196-10 ./mnist-mlp-bin32-otto-trn-xnor.exe --hiddenN 196 --epochsN 10 \ --encoding sweep --xform sweep@avg4 --sweep --export-merge-scores scores-196-10 # → 1053 archive files (13 enc × 9 xforms × 9 pipe variants) # Step 2: Beam search selects best subset ./mnist-merge-ensemble.exe scores-196-10/ --beam 10 \ --member-out member.out --min-gain 0.03 # Step 3: Train selected 9 members → 98.4% ./mnist-mlp-bin32-otto-trn-xnor.exe --hiddenN 196 --epochsN 10 \ --member-file member.out --debug-member
Selected members (sorted by addition order)
| # | Member | Cumulative Eval |
|---|---|---|
| 1 | avg4@spiral:mnist:log8 | 95.8% |
| 2 | rot67@colswap-2-4:mnist:inv-exp8 | 96.9% |
| 3 | rot45@avg2:mnist:inv-exp8 | 97.6% |
| 4 | rot45@avg3:mnist:gamma8 | 97.7% |
| 5 | dflip2@avg4:mnist:sqrt8 | 97.9% |
| 6 | avg3@avg4:mnist:exp8 | 98.1% |
| 7 | avg4@avg4:mnist:lin8 | 98.2% |
| 8 | avg4@avg4:mnist:sig8 | 98.2% |
| 9 | avg4@avg4:mnist:sqrt8 | 98.4% |
Key insight: The pipe avg4@avg4 (double running average) appears
three times (lin8, sig8, sqrt8 encodings). Double-avg4 heavily smooths the image —
eliminating fine stroke texture. The MAJ3 layer cannot overfit to noise it cannot see.
Blurring is a feature, not a bug.
--min-gain 0.03: Only members with ≥0.03% cumulative gain are included. 9 of 26 potential members are selected — 65% fewer, 0.0pp loss. See Status Report for details.
6. Time Scaling Over H and Epochs
The following data shows how runtime evolves with --hiddenN and --epochsN for the champion config (--encoding latest --ensembleN 1 --xform all, i.e. 8 xforms on exp8).
| H | Ep 4 | Ep 5 | Ep 6 | Ep 7 | Ep 8 | Ep 9 | Ep 10 | Eval Ep 7 | Eval Ep 10 |
|---|---|---|---|---|---|---|---|---|---|
| 64 | 2.4s | 2.7s | 3.0s | 3.2s | 3.5s | 3.8s | 4.0s | 97.3% | 97.4% |
| 128 | 3.9s | 4.3s | 4.8s | 5.2s | 5.8s | 6.0s | 6.4s | 97.7% | 97.7% |
| 256 | 6.6s | 7.4s | 8.1s | 8.9s | 9.7s | 10.3s | 11.0s | 97.8% | 97.8% |
Key observations:
- Per-epoch time scales linearly with H. H=256 costs ~2.5× per epoch vs H=64 (0.85s → 2.0s per epoch). This is expected — double the neurons means double the h0 computation, double the scoring, double the correction.
- Eval plateaus at epoch 7. Additional epochs only reduce training error (
err), not generalization. H=64 stays at 97.4%, H=128/256 reach their maximum by epoch 7. - Training error drops exponentially. Each epoch roughly halves the remaining errors. H=64: 576→143 (−4×). H=128: 269→9 (−30×, because higher capacity absorbs more training signal). H=256 reaches err=2 by epoch 10.
- H=64 is capacity-limited. Even 10 epochs yield only 97.4% with err=143. 128 neurons cannot separate all 10 classes cleanly.
Practical conclusion: The standard recommendation is H=128, Ep=7, 8 xforms — 97.7% in 5.2 seconds. For the maximum 97.9%, use H=512 + 8 xforms at 19.5s. Anything beyond H=512 enters diminishing returns.
7. Why 99% is Data-Limited, Not Method-Limited
The single most important finding of the MNIST research: the 98% wall at evalN=10000 is a data ratio problem, not an algorithm ceiling.
| evalN | trainN | Train:Eval Ratio | Eval |
|---|---|---|---|
| 100 | 59,900 | 599:1 | 99.0% |
| 1,000 | 59,000 | 59:1 | 98.1% |
| 10,000 | 60,000 | 6:1 | 97.7% |
At the standard 6:1 split (60K train, 10K eval, shuffled from 70K total), each eval sample receives ~6 correcting votes during training — insufficient for a fully confident decision. At 599:1, each eval sample gets ~60 votes because 599× more training data informs its target weights. The limit is the amount of training data per evaluation sample, not the architecture.
Absolute architecture ceiling: 97.9% at standard 6:1 split (err ≤ 10, training 100%). The remaining errors are samples that the frozen MAJ3 projection cannot represent — no amount of target retraining can fix what the hash never captured. This is the fundamental limit of a frozen random projection layer.
Solution for higher accuracy: Larger datasets (500K+ samples) or concentrated evaluation (fewer eval samples = more training data per class). For a DRAM chip with millions of rows, data volume is never the bottleneck — MNIST and CIFAR are simply too small to saturate the available representational capacity.
7.1 Progression of Ceilings
| Technique | Ceiling | Why |
|---|---|---|
| Raw byte containers (baseline) | 86% 1-pass, 96% iterative | Uniform popcount hides brightness |
| + Exponential encoding | 97.6% | Thermometer reveals pixel intensity |
| + Bit-Mass theory (H×EN) | 97.6% | Small H + Ensemble matches large H |
| + Xform ensemble (structured diversity) | 97.9% | Geometric views decorrelate errors |
| + Data ratio (599:1) | 99.0% | More training per eval sample |
8. Random Pixel Shuffle — Relation Beats Position
--xform shuffle1..shuffle10 performs a random pairwise pixel permutation
(Fisher-Yates, fixed seeds 1–10, compiled into the code). Unlike geometric xforms
(hflip, rot90), shuffle destroys spatial neighborhood structure completely — but
preserves all information (bijection, no loss).
Result: only 0.4pp below identity. H=196 with 6 shuffles reaches 97.6% vs 97.6% with id. The W0 random projection partially recovers spatial structure because each h0-neuron mixes random pixels. Otto Score compares pixel relations, not pixel positions.
8.1 Complete Test Series (10 epochs)
| H | 1 Shuf | 2 Shuf | 3 Shuf | 4 Shuf | 5 Shuf | 6 Shuf | 7 Shuf |
|---|---|---|---|---|---|---|---|
| 32 | 89.8% | 94.0% | 95.0% | 95.8% | 96.1% | 96.3% | 96.5% |
| 64 | 92.5% | 95.5% | 96.3% | 96.8% | 96.9% | 97.0% | 97.0% |
| 128 | 94.9% | 96.7% | 97.0% | 97.2% | 97.4% | 97.5% | 97.5% |
| 196 | 95.6% | 96.8% | 97.2% | 97.4% | 97.5% | 97.6% | 97.6% |
| 256 | 96.1% | 97.2% | 97.5% | 97.6% | 97.6% | 97.7% | 97.7% |
| 512 | 96.8% | 97.5% | 97.7% | 97.8% | 97.8% | 97.8% | 97.8% |
| 1024 | 97.3% | 97.6% | 97.8% | 97.8% | 97.9% | 97.9% | 97.9% |
8.2 Optimal Config per Accuracy Target
For every eval% target, the fastest combination of H, ensembleN, and shuffle count (10 epochs, MNIST standard split):
| Target | H | EN | Xf | Time | Config |
|---|---|---|---|---|---|
| 89.8% | 32 | 1 | 1 | 0.3s | H32 shuffle1 |
| 92.5% | 64 | 1 | 1 | 0.4s | H64 shuffle1 |
| 94.0% | 32 | 1 | 2 | 0.5s | H32 shuffle1+2 |
| 94.9% | 128 | 1 | 1 | 0.7s | H128 shuffle1 |
| 95.5% | 64 | 1 | 2 | 0.8s | H64 shuffle1+2 |
| 96.1% | 256 | 1 | 1 | 1.2s | H256 shuffle1 |
| 96.3% | 64 | 1 | 3 | 1.2s | H64 shuffle1..3 |
| 96.7% | 128 | 1 | 2 | 1.5s | H128 shuffle1+2 |
| 97.0% | 128 | 1 | 3 | 2.2s | H128 shuffle1..3 |
| 97.2% | 256 | 1 | 2 | 2.4s | H256 shuffle1+2 |
| 97.4% | 128 | 1 | 5 | 3.6s | H128 shuffle1..5 |
| 97.5% | 256 | 1 | 3 | 3.5s | H256 shuffle1..3 |
| 97.6% | 256 | 1 | 4 | 4.8s | H256 shuffle1..4 |
| 97.7% | 512 | 1 | 3 | 6.8s | H512 shuffle1..3 |
| 97.8% | 512 | 1 | 4 | 8.9s | H512 shuffle1..4 |
| 97.9% | 512 | 1 | 6 | 9.9s | 🏆 H512 shuffle1..6 |
| 97.9% | 1024 | 1 | 5 | 23.3s | H1024 shuffle1..5 |
Sweet spots:
- 97.0% in 2.2s — H128 + 3 shuffles (best cost/benefit)
- 97.5% in 3.5s — H256 + 3 shuffles
- 97.9% in 9.9s — H512 + 6 shuffles, 6 epochs (max accuracy record 🏆)
8.3 Shuffle vs Ensemble: Diversity Source
Different shuffles (xform diversity) outperform same shuffle (W0 diversity) by +1.5–1.7pp. Same shuffle + different W0 = pure ensemble effect. Different shuffles + same W0 = different pixel neighborhoods. The latter is more effective because targets learn true pixel relations rather than position-dependent patterns.
| Members | Different Shuffles | Same Shuffle (≙ Ensemble) |
|---|---|---|
| 1 | 92.5% | 92.5% |
| 2 | 95.5% | 94.5% |
| 3 | 96.3% | 95.0% |
| 4 | 96.8% | 95.1% |
| 5 | 96.9% | 95.2% |
| 6 | 97.0% | 95.2% |
| 7 | 97.0% | 95.3% |
8.4 Generalization: Diversity Needs Structure
Three sources of member diversity, sorted by effectiveness:
- Xform (different shuffles) — different pixel neighborhoods, maximal error decorrelation
- Geometric xforms (hflip, rot90) — structured variation of pixel arrangement
- W0 ensemble (--ensembleN) — different random projections on the same arrangement, weakest diversity
9. Practical Recommendations
| Goal | Config | Result |
|---|---|---|
| Max accuracy | --hiddenN 196 --epochsN 10 --encoding sweep --xform sweep@avg4,avg3,avg2,spiral,colswap --sweep --export-merge-scores DIR; merge-ensemble --min-gain 0.03; train with member.out | 🏆 98.4% in 14.2s |
| Max accuracy (legacy) | --hiddenN 512 --epochsN 6 --encoding exp8 --xform shuffle1..6 | 97.9% in 9.9s |
| Best cost/benefit | --hiddenN 128 --epochsN 7 --encoding exp8 --xform all | 97.7% in 5.2s |
| Fast 97.5% | --hiddenN 256 --epochsN 7 --encoding exp8 --xform shuffle1..3 | 97.5% in 3.5s |
| Budget (minimal time) | --hiddenN 64 --epochsN 7 --encoding exp8 --xform shuffle1,shuffle2 | 95.5% in 0.8s |
The sweep + merge-ensemble workflow is the new standard for maximum accuracy:
train all encoding×xform combinations, export per-member scores, let the beam search
select the optimal subset. --min-gain 0.03 keeps only members with measurable
contribution — 65% fewer members, 0.0pp loss.
Legacy configs use default count target init and cos-time step schedule.
--xform all = 8 transforms (id, hflip, vflip, dflip1, dflip2, rot90, rot180, rot270).
The transform ensemble is the key architectural insight: structured geometric diversity replaces stochastic ensemble seeds, achieving the same accuracy with 7× fewer compute resources.