Aluode commited on
Commit
a54efdf
Β·
verified Β·
1 Parent(s): 6b2c537

Update README.md

Browse files
Files changed (1) hide show
  1. README.md +316 -1
README.md CHANGED
@@ -1,3 +1,318 @@
1
  ---
2
- license: mit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ license: apache-2.0
3
+ tags:
4
+ - pytorch
5
+ - generative
6
+ - gabor
7
+ - face
8
+ - perception
9
+ - predictive-coding
10
+ - real-time
11
+ - webcam
12
+ - computer-vision
13
+ - neuroscience
14
+ datasets:
15
+ - celeba
16
+ language:
17
+ - en
18
+ pipeline_tag: image-to-image
19
+
20
  ---
21
+
22
+ ## 2. Why this exists β€” the question being asked
23
+
24
+ Large interactive video models (e.g. Wan-Streamer, 2026) achieve real-time
25
+ audio-visual interaction by brute force: encode the whole frame into thousands
26
+ of tokens, push them through a billion-parameter transformer, regenerate every
27
+ 160 ms, burning a supercomputer to track a face. They ask *how large a manifold
28
+ can get*.
29
+
30
+ `the_splat` asks the opposite, biological question: **what is the algorithmic
31
+ minimum required to keep an internal hallucination locked to physical reality?**
32
+ The thalamic channel into cortex is narrow (~10⁢ fibres feeding ~10¹⁰ neurons);
33
+ perception is mostly prediction corrected by a sparse error signal. This system
34
+ is a working, watchable model of that idea at 31 MB, on one desktop GPU.
35
+
36
+ The lineage of falsifiable builds:
37
+
38
+ - **V2** β€” proved the loop closes through *real rendered pixels*, and surfaced
39
+ Takens' genericity condition (a symmetric scalar observable can't resolve
40
+ direction; the loop locked to a mirror solution until the observable was made
41
+ complex). State was 1-D (a phase).
42
+ - **V2-live** β€” the full 128-D celeba latent held by *K sparse colour probes*.
43
+ Confirmed live: sparse holds the manifold; a full encoder tracks better;
44
+ tracking scales with K. Found the **frontal-face attractor** β€” point the
45
+ camera at a table and it renders a face, because the manifold has no "not a
46
+ face" direction. That is predictive coding's core claim in 31 MB: perception
47
+ is projection onto the prior.
48
+ - **V3** β€” replaced colour probes with **Lucas-Kanade flow probes**
49
+ (displacements, not appearances). Beat colour probes and held under lighting
50
+ drift, because brightness constancy is only assumed frame-to-frame. Live, the
51
+ *shoulders* became a steerable channel.
52
+ - **V4** β€” split the packets into **two frequency bands** and routed each band's
53
+ flow to its own packets. The `band_diagnostic` confirmed the field had split
54
+ *itself*, unsupervised, into a low-freq shading/luminance channel and a
55
+ high-freq oriented **contour/edge** channel β€” the V1 simple-cell
56
+ decomposition, exactly as Barlow's 1961 efficient-coding hypothesis predicts
57
+ for a localized-frequency basis under reconstruction pressure.
58
+ - **V5 (this file)** β€” generalized to **N log-spaced octaves** (a coarse-to-fine
59
+ cascade) with per-octave LK window / weight / precision schedules and a live
60
+ **graphical EQ** over the bands.
61
+
62
+ ---
63
+
64
+ ## 3. The manifold β€” `SplatVAE` (carried verbatim from the original repo)
65
+
66
+ The generative model is the original `the_splat` autoencoder, embedded
67
+ unchanged so trained checkpoints load `strict=True`.
68
+
69
+ - **`Encoder`** β€” a small conv stack, image β†’ `(mu, logvar)` in latent space.
70
+ Used only for **acquisition** (the GIST button); the loop does not use it to
71
+ track.
72
+ - **`Decoder`** β€” an MLP, `z (latent) β†’ raw (N packets Γ— 11 params)`.
73
+ - **`GaborRenderer`** β€” turns `raw` into an image. Each packet `i` has, via
74
+ `activate()`:
75
+ - `px, py` β€” position (anchored on a grid + learned offset),
76
+ - `sigma ∈ [0.012, 0.152]` β€” envelope size,
77
+ - `theta` β€” orientation,
78
+ - **`freq ∈ [1, 16]` β€” spatial frequency** (this is the axis V4/V5 split on),
79
+ - `coeff` β€” a 3Γ—2 colour/quadrature tensor.
80
+
81
+ The image is `sigmoid(Ξ£_i env_i Β· (aΒ·cos βˆ’ bΒ·sin))`, an anisotropic Gabor sum.
82
+ Typical trained field: `image_size=128, packets=512, latent=128, hidden=512`.
83
+
84
+ - **`render_probes(raw, pxy)`** β€” evaluates the field at arbitrary points
85
+ `pxy` instead of the pixel grid. Cost `O(KΒ·N)` not `O(HΒ·WΒ·N)`. **Verified to
86
+ match the full render at grid coordinates to float precision.** This is what
87
+ makes the sparse afferent cheap.
88
+
89
+ - **`load_v1(path)`** β€” infers `image_size, num_packets, latent, hidden` from
90
+ the checkpoint itself and loads `strict=True`. **Verified bit-identical**
91
+ (max render diff `0.0`) against the repo's original `SplatVAE`.
92
+
93
+ ---
94
+
95
+ ## 4. The afferent β€” sparse Lucas-Kanade flow
96
+
97
+ The cortex reads **where tracked things went**, not their colour.
98
+
99
+ - **`LKFlow`** β€” torch-native sparse Lucas-Kanade (no OpenCV needed for the core).
100
+ For each point it solves the 2Γ—2 structure-tensor system over a small window,
101
+ iterated, on a 2-level pyramid. Returns per-point flow (in `[0,1]` coords), a
102
+ confidence (min eigenvalue), and a post-fit residual. **Verified to recover a
103
+ known (+2, βˆ’1)-pixel shift exactly** (residual `~0.0004`).
104
+ - **`good_features`** β€” a cheap Shi-Tomasi: pick high-gradient points from random
105
+ candidates, keeping a minimum distance from existing probes. Used to seed and
106
+ to re-seed lost probes (the **saccade** β€” active sensing).
107
+
108
+ Why flow, not colour: the celeba manifold derives skin tone from webcam
109
+ luminance, so colour probes couple the belief to the *lighting*. Flow only
110
+ assumes brightness constancy frame-to-frame, so slow lighting drift passes
111
+ through untouched. (V3 `--selftest` [B] measured colour probes degrading *below
112
+ open-loop* under lighting drift, while flow held.)
113
+
114
+ ---
115
+
116
+ ## 5. The octave split β€” V5's core addition
117
+
118
+ `octave_bands(vae, n_oct)` splits the packets into `n_oct` **log-spaced
119
+ frequency octaves** by the field's own trained `freq`, using quantile edges so
120
+ each band holds a comparable count. Log spacing matches the roughly
121
+ octave-spaced frequency channels of visual cortex. On a real 512-packet field
122
+ this yields (verified in NumPy at true dims) four clean bands of 128 packets
123
+ each, spanning freq `1.3–6.0 / 6.0–8.3 / 8.4–11.0 / 11.0–15.3`, a full partition
124
+ with no overlap and none dropped.
125
+
126
+ - **`render_probes_subset` / `render_full_subset`** β€” render using only one
127
+ band's packets, with the anchor buffer **sliced to that band**. (This fixed a
128
+ real crash in V4 where the verbatim `activate()` added the full 512-row anchor
129
+ to a 256-packet subset. Verified in NumPy at 512 packets: the sliced subset
130
+ render equals the full render restricted to those packets β€” numbers unchanged,
131
+ only the shape bug gone.)
132
+ - **`octave_diagnostic`** β€” writes `FULL | O0 | O1 | … | O_{N-1}` for several
133
+ random `z`. This is the empirical test of whether the field learned a genuine
134
+ cascade: O0 shading, O_{N-1} fine contours, middle bands interpolating.
135
+
136
+ ---
137
+
138
+ ## 6. The cortex β€” `OctaveCortex`
139
+
140
+ Holds `z`; runs one loop tick per frame. The math per tick:
141
+
142
+ ```
143
+ # 1. prior flow β€” predict z from its own recent motion + a weak leak to a slow prior
144
+ vel = z - z_prev
145
+ z_pred = z + beta_mom * vel
146
+ z_pred = z_pred - leak * (z_pred - z_prior)
147
+
148
+ # 2. per octave i (skipped if inactive, EQ-muted, or empty):
149
+ d_i, conf_i, res_i = LK_octave_i(prev_frame, frame, probes_i) # sparse afferent
150
+ prec_i = sig_ref^2 / (sig_ref^2 + roughness(res_i)^2) # reliability
151
+ prec_i = min(prec_i, prec_cap_i) # per-octave trust cap
152
+ eff_i = weight_i * eq_i * prec_i # effective gain
153
+ # "what octave i rendered at p under old z must appear at p+d under new z":
154
+ loss += eff_i * || R_i(p_i + d_i ; z_pred) - R_i(p_i ; z) ||^2
155
+
156
+ # 3. correction β€” one gradient step through the decoder, trust-region clamped
157
+ z <- z_pred - clamp(eta * dloss/dz, dz_clamp)
158
+
159
+ # 4. probes ride their octave's flow, gated by that octave's precision;
160
+ # lost probes re-seed to high-gradient features (the saccade)
161
+ p_i <- clamp(p_i + prec_i * d_i)
162
+ ```
163
+
164
+ Per-octave schedules (octave 0 = lowest freq β†’ Nβˆ’1 = highest):
165
+
166
+ | octave | probes | LK window | weight | prec cap | role |
167
+ |-------:|-------:|:-----------------|-------:|---------:|:-------------------------|
168
+ | 0 low | 14 | 13 px on 2Γ— pyr | 1.00 | 1.00 | shading / pose / envelope |
169
+ | 1 | 11 | 11 px on 2Γ— pyr | 0.75 | 0.80 | major placement |
170
+ | 2 | 8 | 9 px full-res | 0.50 | 0.60 | orientation refine |
171
+ | 3 high | 5 | 5 px full-res | 0.25 | 0.40 | fine contours (near-immovable) |
172
+
173
+ (Verified monotone in NumPy: low octaves get more probes, higher weight, higher
174
+ trust.) The design intent: **low octaves are world-driven** (reliable
175
+ high-variance low-frequency motion the manifold should honour), **high octaves
176
+ are prior-dominated** (the strong, low-variance face-contour prior, steered only
177
+ by strong evidence). The lowest octave orients everything; each higher octave
178
+ refines within the basin below it.
179
+
180
+ **Acquisition vs holding.** The loop *holds*; it does not *find*. On its own the
181
+ sparse afferent can only correct within the current basin. `bootstrap()` (the
182
+ GIST button) runs the encoder once to place `z` in the right basin. The cascade
183
+ hypothesis is that higher octaves can inherit orientation from the low ones,
184
+ reducing how often a full GIST is needed β€” that is claim **[E]**.
185
+
186
+ ---
187
+
188
+ ## 7. The graphical EQ β€” the "sigh" idea, folded in
189
+
190
+ Antti's earlier FFT tool taught that low frequencies carry the *gist* by
191
+ filtering pixels in Fourier space. The splat field **already is** a frequency
192
+ decomposition β€” each packet is a localized frequency atom β€” so an EQ over
193
+ packet-frequency is a live mixing board on the manifold's octaves. Each octave
194
+ has a fader (`eq_i ∈ [0,1]`) that gates **both**:
195
+
196
+ - its **render** contribution β€” `belief_render` sums `eq_i Β· (octave_i βˆ’ 0.5)`
197
+ over octaves (additive, no division; all-zero EQ is safe flat gray), and
198
+ - its **correction** gradient β€” `eff_i = weight_i Β· eq_i Β· prec_i`, so a muted
199
+ octave drops out of the loss entirely.
200
+
201
+ Pull the top faders down: the gist (pose, shading) survives on the low bands.
202
+ Pull the bottom faders down: identity/detail drops, structure holds.
203
+
204
+ ---
205
+
206
+ ## 8. The GUI
207
+
208
+ Two live panes: **AFFERENT** (the camera frame with octave-coloured probes and
209
+ flow vectors β€” cyan = lowest freq, warm = highest) and **BELIEF**
210
+ (`render(dec(z))`). Controls:
211
+
212
+ - **START / STOP**
213
+ - **OCTAVE EQ** β€” a vertical fader per octave (gates render + correction live)
214
+ - **VIEW** β€” cycles the belief pane through the EQ-mix and each single octave
215
+ - **INJECT SLOP** β€” replaces the frame with noise for ~60 frames; watch precision
216
+ collapse and the belief coast on its prior
217
+ - **prec DYN / FIX** β€” dynamic vs fixed precision
218
+ - **GIST** β€” encoder re-anchor (needs `--model`)
219
+ - **K** β€” probe count (scaled across octaves; low bands get more)
220
+
221
+ Telemetry per octave: precision, EQ gain, probe count, plus `|dz|` and frame `t`.
222
+
223
+ ---
224
+
225
+ ## 9. The synthetic world and the scorecard
226
+
227
+ For falsifiable testing without a webcam, `OctaveWorld` renders a hidden `z`
228
+ moving on a low-D trajectory: the **low** latent axes move slowly (pose), the
229
+ **high** axes faster (detail), with optional luminance drift and injectable
230
+ slop. Ground truth exists, so the loop can be scored. `--selftest` prints:
231
+
232
+ - **[A]** all-octaves tracks pose better than open-loop.
233
+ - **[E] cascade inheritance β€” the headline.** Does the highest octave alone track
234
+ pose *better with the low octaves on* than with them off (inherited
235
+ orientation)? Holds iff `all ≀ high-alone`. If not, the cascade adds nothing
236
+ over independent bands β€” and the ledger must say so.
237
+ - **[B]** the low octave holds pose under luminance drift.
238
+ - **[D]** dynamic precision coasts through slop (`dyn ≀ fixed`).
239
+
240
+ ---
241
+
242
+ ## 10. Honest ledger β€” what is verified, and how
243
+
244
+ - **[V] carried & re-verified across versions:** strict `.pt` compatibility
245
+ (bit-identical renders); `render_probes` / `*_subset` match the full render
246
+ (anchor sliced) to float precision; LK recovers a known pixel shift exactly;
247
+ colour→flow and lighting-drift results (V3); the V1-like unsupervised
248
+ frequency split (V4 `band_diagnostic`).
249
+ - **[V] verified this build, in NumPy at real 512-packet dims:** the octave split
250
+ partitions all packets into log-spaced bands (no overlap/loss); the per-octave
251
+ schedules are monotone; the LK windows scale 13β†’5 px with a pyramid on the low
252
+ half; the EQ gates a muted octave out of *both* correction and render; the
253
+ belief EQ-mix is additive and safe at all-zero.
254
+ - **[UNVERIFIED β€” run on your GPU]:** the full torch scorecard ([A], **[E]**,
255
+ [B], [D]). The sandbox package proxy blocked installing torch, so these did not
256
+ run here. Seconds on CUDA: `python the_splatV5.py --selftest`.
257
+ - **[K] open questions:**
258
+ - The octave split is only as meaningful as the *trained field's* frequency
259
+ organization. On a 2-epoch celeba `.pt` this is empirical β€” run
260
+ `--diagnostic` to see whether four bands separate cleanly or whether the
261
+ middle bands are muddy (in which case use `--octaves 3`).
262
+ - The persistent held state's *effective* dimensionality that a sparse afferent
263
+ can steer is bounded by the motion's intrinsic dimension (Takens); pose is
264
+ low-D and tracks well, full identity/detail is the frontier.
265
+ - The manifold is the ceiling: a 2-epoch, 31 MB celeba field can't open a mouth
266
+ or turn to profile (not in its training distribution). More/again-trained
267
+ manifolds raise the ceiling with **no change to the loop**.
268
+ - **[B] boundary β€” what this is NOT:** it does not "navigate a learned world" or
269
+ do deepfake-style expression synthesis. It *holds and steers the pose/appearance
270
+ of a face render from a sparse pixel read*. The wire between predict β†’ render β†’
271
+ correct β†’ move is built and watchable; a richer manifold and a genuinely
272
+ multi-D navigable state are future work.
273
+
274
+ ---
275
+
276
+ ## 11. Running it
277
+
278
+ ```bash
279
+ pip install torch numpy pillow # opencv-python only for --webcam; tkinter ships with Python
280
+
281
+ # 1) SEE the cascade the field learned (do this first):
282
+ python the_splatV5.py --model "face model trained 2 epochs/model.pt" --diagnostic
283
+
284
+ # 2) the falsifiable scorecard (run [E] on your GPU):
285
+ python the_splatV5.py --selftest
286
+
287
+ # 3) live cortex on your webcam:
288
+ python the_splatV5.py --model "face model trained 2 epochs/model.pt" --webcam
289
+
290
+ # options:
291
+ python the_splatV5.py --octaves 3 ... # band count (default 4)
292
+ python the_splatV5.py # synthetic world, no model needed
293
+ ```
294
+
295
+ Suggested first live session: START, drop the top EQ faders and move around β€”
296
+ the low-octave belief should hold your pose; raise them and the face detail
297
+ returns. INJECT SLOP to watch the belief coast on its prior when the afferent
298
+ goes to noise. GIST if the belief falls out of its basin.
299
+
300
+ ---
301
+
302
+ ## 12. Files
303
+
304
+ - `the_splatV5.py` β€” the whole system (one file).
305
+ - `README.md` β€” this document.
306
+ - (produced on run) `octave_diagnostic.png` β€” the FULL | O0 | … | O_{N-1} grid.
307
+ - your `model.pt` β€” a trained `the_splat` SplatVAE checkpoint.
308
+
309
+ ---
310
+
311
+ ## 13. The idea in one line
312
+
313
+ A handful of moving points, a 128-D latent, a small Gabor renderer, and a
314
+ precision-weighted gradient loop keep an internal hallucination locked to a face
315
+ in real time β€” on one desktop GPU, in less than the size of an MP3 β€” and the
316
+ manifold organizes itself, unsupervised, into the same frequency cascade the
317
+ visual cortex uses. That last fact is the point: efficient coding predicted it in
318
+ 1961, and here it is in the code.