ClipProj 4B encoder variant: 23.47 GB -> 13.16 GB, 2x faster, still four bits everywhere
Browse files
README.md
CHANGED
|
@@ -61,7 +61,9 @@ not ported.
|
|
| 61 |
|
| 62 |
| file | size | |
|
| 63 |
|---|---|---|
|
| 64 |
-
| `mmh3-turbo-fl2va-q4tp.cmf` | 23.94 GB | **use this one** |
|
|
|
|
|
|
|
| 65 |
| `mmh3-turbo-fl2va-q2tp.cmf` | 18.74 GB | two bits on the gate/up planes. Smaller, faster, and it stops following the prompt β kept for anyone who wants to push on it, not for rendering. See below |
|
| 66 |
|
| 67 |
## Keyframe to video
|
|
@@ -194,6 +196,11 @@ RAM at least the file's size β 24 GB β or every step faults on non-resident
|
|
| 194 |
pages; the weights are memory-mapped, not read. Disk: 24 GB. A GPU is optional
|
| 195 |
and wants ~14 GB of VRAM for the DiT's planes. No network access at run time.
|
| 196 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 197 |
## Two bits: smaller, faster, and answering a different question
|
| 198 |
|
| 199 |
The obvious next cut is the DeepSeek-V4 policy: gate/up at two bits,
|
|
@@ -230,6 +237,121 @@ measuring next β the packer's policy is one predicate,
|
|
| 230 |
that experiment starts from something rather than nothing; four bits is
|
| 231 |
what to render with.
|
| 232 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 233 |
## What it costs to run
|
| 234 |
|
| 235 |
The file is memory-mapped, so plan on RAM at least its size or every step
|
|
|
|
| 61 |
|
| 62 |
| file | size | |
|
| 63 |
|---|---|---|
|
| 64 |
+
| `mmh3-turbo-fl2va-q4tp.cmf` | 23.94 GB | **use this one** β text-to-video AND keyframe-to-video |
|
| 65 |
+
| `mmh3-turbo-q4tp.cmf` | 23.47 GB | the same without the vision tower: text-to-video only |
|
| 66 |
+
| `mmh3-turbo-clipproj4b-q4tp.cmf` | **13.16 GB** | text-to-video with a 4B stand-in prompt encoder. Peaks at 15.1 GB of VRAM, so a 20 GB card holds the whole run; 2x faster, and still four bits everywhere. Costs some set dressing β see below |
|
| 67 |
| `mmh3-turbo-fl2va-q2tp.cmf` | 18.74 GB | two bits on the gate/up planes. Smaller, faster, and it stops following the prompt β kept for anyone who wants to push on it, not for rendering. See below |
|
| 68 |
|
| 69 |
## Keyframe to video
|
|
|
|
| 196 |
pages; the weights are memory-mapped, not read. Disk: 24 GB. A GPU is optional
|
| 197 |
and wants ~14 GB of VRAM for the DiT's planes. No network access at run time.
|
| 198 |
|
| 199 |
+
`mmh3-turbo-clipproj4b-q4tp.cmf` asks for 14 GB of RAM and disk instead, and
|
| 200 |
+
peaks at 15.1 GB of VRAM β a whole-run maximum, polled, not a snapshot. That is
|
| 201 |
+
what makes it the one to reach for on a 20 GB card: below that the prompt
|
| 202 |
+
encoder pages, and on this workload paging costs more than any kernel.
|
| 203 |
+
|
| 204 |
## Two bits: smaller, faster, and answering a different question
|
| 205 |
|
| 206 |
The obvious next cut is the DeepSeek-V4 policy: gate/up at two bits,
|
|
|
|
| 237 |
that experiment starts from something rather than nothing; four bits is
|
| 238 |
what to render with.
|
| 239 |
|
| 240 |
+
## A smaller encoder instead of fewer bits
|
| 241 |
+
|
| 242 |
+
The two-bit section above ends on a diagnosis: half this file is the PROMPT
|
| 243 |
+
ENCODER, and squeezing it is what broke the prompt. There is a second way to act
|
| 244 |
+
on that diagnosis β **don't compress the encoder, replace it.**
|
| 245 |
+
|
| 246 |
+
[ClipProj](https://github.com/nicolab28/ComfyUI-ClipProj) fits a ridge
|
| 247 |
+
regression from a small Qwen3-VL's hidden state into the space the DiT was
|
| 248 |
+
conditioned on. Same tokenizer, same family, one affine map:
|
| 249 |
+
|
| 250 |
+
```text
|
| 251 |
+
cond = ((h - mean_in) / std_in) @ W [+ GELU residual] * std_out + mean_out
|
| 252 |
+
```
|
| 253 |
+
|
| 254 |
+
`mmh3-turbo-clipproj4b-q4tp.cmf` is the text-to-video file with Qwen3-VL-4B
|
| 255 |
+
tapped at layer 24 standing in for the 32B tapped at 50, plus the 304 MB
|
| 256 |
+
projection kept **exact** β f32, no quantization on the piece that carries the
|
| 257 |
+
whole substitution. Everything else is copied through byte for byte: DiT and
|
| 258 |
+
both VAE decoders, still `q4tp`. Nothing anywhere is two bits.
|
| 259 |
+
|
| 260 |
+
**23.47 GB β 13.16 GB.** The encoder went from 552 tensors to 277.
|
| 261 |
+
|
| 262 |
+
### Does it still mean the same thing?
|
| 263 |
+
|
| 264 |
+
That is measurable without rendering a frame: dump what the DiT actually
|
| 265 |
+
receives (`CMF_TE_DUMP=<path>`) from both files on one prompt, and take the
|
| 266 |
+
cosine per token.
|
| 267 |
+
|
| 268 |
+
| | mean cosine to the 32B | worst token |
|
| 269 |
+
|---|---|---|
|
| 270 |
+
| 4B tapped at **24** | **0.9198** | 0.7982 |
|
| 271 |
+
| 4B tapped at 25 | 0.8452 | 0.5910 |
|
| 272 |
+
| *floor β two different tokens of the 32B itself* | *0.5914* | |
|
| 273 |
+
|
| 274 |
+
The tap index is 0-based, and off-by-one is a real failure mode rather than a
|
| 275 |
+
theoretical one: at 25 the worst token sits **on the floor**, uncorrelated.
|
| 276 |
+
Token 0 is not projected at all but replaced by a stored `sink_out` β the
|
| 277 |
+
attention sink is an outlier no regression fits β and it lands at cosine
|
| 278 |
+
**0.9999** against the teacher's, which is the sharpest single confirmation
|
| 279 |
+
that the mechanism is wired right.
|
| 280 |
+
|
| 281 |
+
### What it costs
|
| 282 |
+
|
| 283 |
+
Same prompt, same seed, same four steps, one RTX 3090, both files under
|
| 284 |
+
identical settings:
|
| 285 |
+
|
| 286 |
+
| | encode | denoise | video VAE | audio VAE | **total** |
|
| 287 |
+
|---|---|---|---|---|---|
|
| 288 |
+
| `mmh3-turbo-q4tp` | 49.2 s | 116.4 s | 101.9 s | 6.7 s | **281 s** |
|
| 289 |
+
| `mmh3-turbo-clipproj4b-q4tp` | **1.9 s** | 84.5 s | 45.6 s | 5.9 s | **140 s** |
|
| 290 |
+
|
| 291 |
+
Encoding is 26x faster, which is the part ClipProj actually replaced. The rest
|
| 292 |
+
is residency: 13.16 GB leaves the decoder room on a 24 GB card where 23.47 GB
|
| 293 |
+
does not, and the video VAE more than halves without a line of its own
|
| 294 |
+
changing. On the 20 GB card this variant exists for, that gap is the whole
|
| 295 |
+
point β a reader of this repo measured 20 minutes for one 512x288 clip on an
|
| 296 |
+
RTX 3080 20 GB, paging the encoder in and out of a ~19 GB weight budget.
|
| 297 |
+
|
| 298 |
+
The parity probe takes the device arm on both files at the same `rel rms
|
| 299 |
+
4.65e-3`, which is its own small proof that the DiT came through untouched.
|
| 300 |
+
|
| 301 |
+
### What it costs in quality
|
| 302 |
+
|
| 303 |
+
Judge it on the clip, not on a frame: a still catches the pancake at rest and
|
| 304 |
+
reads as a loss that is not there.
|
| 305 |
+
|
| 306 |
+
| four bits, 32B encoder | four bits, 4B + ClipProj | two bits, 32B encoder |
|
| 307 |
+
|---|---|---|
|
| 308 |
+
|  |  |  |
|
| 309 |
+
| 23.94 GB | **13.16 GB** | 18.74 GB |
|
| 310 |
+
|
| 311 |
+
Across the 39 frames the 4B does the whole job: corgi, chef hat, flat clean
|
| 312 |
+
style, and the pancake **leaves the surface and comes back**, the dish empty
|
| 313 |
+
underneath at the top of the toss. The verb survives β that is what `q2tp`
|
| 314 |
+
lost, along with the animal and the pan.
|
| 315 |
+
|
| 316 |
+
What drifts is set dressing. The 32B renders the cooking surface as a griddle
|
| 317 |
+
and puts patterned wallpaper behind; the 4B gives a rimmed white plate and a
|
| 318 |
+
plain ground. A 0.92 cosine is close, not equal, and where it is not equal is
|
| 319 |
+
the scene's furniture rather than its subject or its action.
|
| 320 |
+
|
| 321 |
+
So the ordering is not "smaller is worse". The two-bit file answers a different
|
| 322 |
+
question; this one answers the right question with a plainer set, for 56% of
|
| 323 |
+
the size and half the time. If you have the VRAM for the 32B encoder, use it β
|
| 324 |
+
its framing is richer. If you are paging, this is the better trade, and unlike
|
| 325 |
+
the two-bit build it is a trade rather than a loss.
|
| 326 |
+
|
| 327 |
+
Sound is untouched either way: the audio branch never sees the prompt encoder.
|
| 328 |
+
[The clip with its audio.](https://huggingface.co/infosave/MiniMax-H3-Turbo-cmf/resolve/main/samples/ab_clipproj.mp4)
|
| 329 |
+
|
| 330 |
+
### Building one
|
| 331 |
+
|
| 332 |
+
```bash
|
| 333 |
+
cortiq animate-pack \
|
| 334 |
+
--in mmh3-turbo-q4tp.cmf \
|
| 335 |
+
--te qwen3vl_4b_bf16.safetensors --te-layers 24 \
|
| 336 |
+
--clip-proj mmh3-4b-ClipProj-celeb-mlp.safetensors \
|
| 337 |
+
--quant q4tp --out mmh3-turbo-clipproj4b-q4tp.cmf
|
| 338 |
+
```
|
| 339 |
+
|
| 340 |
+
`--te-layers` is not a size knob, it is the tap: layers above it never execute,
|
| 341 |
+
so packing them is pure file. `--clip-proj` carries the projection in exact and
|
| 342 |
+
replaces the encoder **as a whole component** β matching tensor names alone
|
| 343 |
+
would leave `te.layers.24..49` of the 32B behind, six gigabytes that
|
| 344 |
+
`num_hidden_layers` then excludes from the forward while disk and VRAM budget
|
| 345 |
+
still pay for them.
|
| 346 |
+
|
| 347 |
+
The encoder is [`Comfy-Org/Qwen3-VL`](https://huggingface.co/Comfy-Org/Qwen3-VL)
|
| 348 |
+
`text_encoders/qwen3vl_4b_bf16.safetensors`, and the projection is
|
| 349 |
+
[`NicoLab28/ClipProj-MiniMax-H3`](https://huggingface.co/NicoLab28/ClipProj-MiniMax-H3)
|
| 350 |
+
`mmh3-4b-ClipProj-celeb-mlp.safetensors` β use the file the projection was
|
| 351 |
+
fitted on, since the map is only valid for those exact weights. An 8B
|
| 352 |
+
projection is published too and scores higher on its author's corpus (0.8037
|
| 353 |
+
against 0.7930); it costs about 4 GB more.
|
| 354 |
+
|
| 355 |
## What it costs to run
|
| 356 |
|
| 357 |
The file is memory-mapped, so plan on RAM at least its size or every step
|