Distilled 5-6 step sampling via folded Turbo LoRA, plus three fixes - #14
Distilled 5-6 step sampling via folded Turbo LoRA, plus three fixes#14guyz wants to merge 5 commits into
Conversation
A relative h3_shaders.metal that is absent from the current directory now falls back to the directory containing the binary, so h3 can be launched from anywhere (PATH installs, daemons, other projects) instead of failing with 'cannot compile h3_shaders.metal'. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The GPU path maps tensor data in place and assumes the data section (8 + header bytes) starts 8-byte aligned. Writers that do not pad the JSON header (e.g. MLX's save_safetensors) produce spec-valid files that load without error here but decode to garbage, rendering silent black video with intact audio. Verified by round-tripping a checkpoint through such a writer: unpadded renders black, the same file with the header padded to the next 8-byte boundary renders correctly, tensor order unchanged. Refuse such files at open with an actionable message rather than misrendering. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The env override accepted up to 512, but tiles above 320 produce a visible grid/quilt artifact across the whole frame (reproduced at 512 and 1088 on M5 Max, 960x544 canvas). Match the automatic search's 320 bound. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…heckpoint Folds W' = W + scale*(B@A) into the bf16 shards offline by cloning the originals (copy-on-write where available) and rewriting only the affected byte ranges, keeping headers, tensor order, and alignment byte-identical. Pure numpy, with a per-tensor parity probe before any bytes are written. With larryvrh's Turbo v4 adapter folded, 5-6 step sampling runs with no LoRA runtime and no speed flags. Measured on M5 Max at 960x544 against the tutorial's balanced preset (same prompt and seed, cold single-shot): 39 frames 87s -> 65s, 124-frame clip 8.8min -> 6.2min, at comparable visual quality. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
All four come from pull requests open against antirez/h3.c that have not been merged yet. Each was applied to this fork, built, and exercised here rather than taken on trust. Keep scaled queries in F32 for causal GQA (morluto, PR antirez#4). The kernel expanded a BF16 query to F32, applied the attention scale, then rounded the product back to BF16 before the QK contraction — into a threadgroup float array, so the rounding saved no storage and only discarded precision. Their regression test, included here, measures max absolute error 0.0039 and a 0.0076% BF16 mismatch rate on this machine, against 0.092 and 21.6% for the old rounding. This changes the numerics of every generation, which is why the test ships with it. Resolve a relative shader path against the executable's directory (guyz, PR antirez#14). Adapted rather than cherry-picked: upstream patches the inline path in h3_gpu_create, while this fork resolves paths in h3_gpu_shader_path, so the fallback lands there and covers the precompiled metallib too. Without it the binary only runs from the directory holding h3_shaders.metal. Clamp H3_VAE_TILE_PIXELS to 320 (guyz, PR antirez#14). Tiles above 320 produce a grid artifact across the frame. This fork's automatic search already stopped at 320; only the environment override could exceed it. Keep video VAE RGB output finite (morluto, PR antirez#9) and reject unrepresentable aligned frame counts (morluto, PR antirez#11). Both close paths where a bad value propagates instead of failing: NaN passes two ordered clamp comparisons untouched, and a large frame count overflows while being aligned. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Hi! |
|
hi thanks again for your lora scrit , make a script for bake 2-3 loras from Civitai (seems to work ) #!/bin/bash Universal LoRA Baking Script for h3.cUsage: ./bake.sh /path/to/your/new_lora.safetensorsif [ -z "$1" ]; then LORA_PATH=$1 echo "=================================================" 1. Clean and rename keys to h3.c formatecho "[1/5] Cleaning and renaming keys..." tensors = load_file('$LORA_PATH', device='cpu') Pattern 1 (lora_unet_blocks_ style)p1 = re.compile(r'^lora_unet_blocks_(\d+)([a-z]+)(.+).lora_(down|up).weight$') Pattern 2 (diffusion_model.blocks style)p2 = re.compile(r'^diffusion_model.blocks_(\d+)([a-z]+)(.+).lora_(A|B).weight$') for k, v in tensors.items(): if not new_tensors: save_file(new_tensors, 'temp_lora_cleaned.safetensors') 2. Bake FL2VA (Base -> Custom LoRA -> Turbo)echo "[2/5] Baking FL2VA (Base -> Custom LoRA -> Turbo)..." 3. Bake Ref2VAecho "[3/5] Baking Ref2VA (Base -> Custom LoRA -> Turbo)..." 4. Remove temp filerm -f ./temp_lora_cleaned.safetensors 5. Update Master folderecho "[4/5] Updating Master folder..." echo "[5/5] DONE! Model updated." |
This PR adds LoRA support to h3 by folding adapters into the bf16 checkpoint
offline, without adding a LoRA runtime. With the community Turbo distillation
adapter folded, the existing 5-6 step mode becomes usable at final quality
instead of serving as a preview mode, and runs ~1.35x faster than the balanced
preset. The README measures stock low-step sampling at 0.556 SSIM against the
reference. The folding code is adapter-agnostic, allowing use with the wider
LoRA ecosystem.
It handles style adapters and sequential folds, and it can be used for future
distillations. On APFS, each folded variant uses ~2-3 GB of real disk. The PR
also contains three small fixes found while running h3 on large real workloads;
I am happy to split them into separate PRs if preferred.
tools/fold_turbo_lora.py
tools/fold_turbo_lora.pyappliesW' = W + scale*(B@A)to the shards offline.It clones the original files, using copy-on-write where the filesystem supports
it, and rewrites only the affected byte ranges. The headers and tensor order
remain byte-identical, as does the alignment. The implementation is pure numpy
and runs a per-tensor parity probe before writing any bytes.
For a checkpoint folded with larryvrh's Turbo v4 adapter (Apache-2.0), h3 uses
--steps 5or6without other speed flags. Cold single-shot measurements onan M5 Max at 960x544 used the same prompt and seed, with the tutorial's balanced
preset (
--steps 20 --reuse 2 --layers 45) as the comparison:Visual quality was comparable on the clips tested, although fast action showed
motion smear at 4 steps. The README therefore documents 5 as the floor and warns
against combining the distilled schedule with
--reuseor--core-reuse, sincethat schedule removes the redundancy used by both options.
Fixes
Relative shader lookup
A relative shader path is now resolved against the executable's directory when
the file is absent from the CWD. Previously,
h3failed with "cannot compileh3_shaders.metal" unless it was launched from the source directory.
Misaligned safetensors
Files whose data section offset, 8 + header bytes, is not 8-byte aligned are now
rejected with an actionable message. Such files are spec-valid, but they
silently decode to garbage in h3, producing black video with intact audio.
MLX's
save_safetensorscan write these files because it does not pad the JSONheader. Round-tripping a checkpoint verified that the unpadded file renders
black, while the same file renders correctly after its header is padded to the
next 8-byte boundary without changing tensor order. Accepting these files would
be the proper fix; rejecting them explicitly is a first step.
VAE tile limit
H3_VAE_TILE_PIXELSis now clamped to 320 to match the automatic search. Tilesabove 320 produce a grid/quilt artifact across the whole frame. This was
reproduced at 512 and 1088 on an M5 Max at 960x544.
All measurements were made on a MacBook Pro with an M5 Max 128 GB configuration
running macOS 26.5. The MiniMax H3 Community License's territorial restrictions
apply to the weights and, under its terms, to the adapter as a derivative.