Aluode commited on
Commit
2c6bc32
·
verified ·
1 Parent(s): a54efdf

Update README.md

Browse files
Files changed (1) hide show
  1. README.md +3 -295
README.md CHANGED
@@ -19,300 +19,8 @@ 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.
 
19
 
20
  ---
21
 
22
+ # What this is
23
 
24
+ Model for TheSplatV5 that lives in github at:
 
 
 
 
25
 
26
+ https://github.com/anttiluode/TheSplat5/