Preview the denoised estimate rather than the noisy sample - #34
Open
AlexanderIstomin wants to merge 1 commit into
Open
Preview the denoised estimate rather than the noisy sample#34AlexanderIstomin wants to merge 1 commit into
AlexanderIstomin wants to merge 1 commit into
Conversation
Denoising previews decode the sample the sampler is stepping through. At high sigma that sample genuinely is mostly noise, so on a short schedule the preview shows near-identical coloured latent mush for most of the run and only resolves on the last step — which defeats the point of a preview, since there is nothing to judge and nothing to cancel on. Decoding the model's current estimate of the finished frame instead gives a blurry version of the result from the first step, which then sharpens. The estimate is x0 = x_t + sigma * v, the same expression denoise_res already uses to build its denoised buffer; note the sign, because the Euler step moves the sample along +v as sigma falls, so this engine's velocity points toward the clean image rather than away from it. The estimate is written to a scratch buffer, so the sampler's own trajectory is untouched and final output is unchanged — verified bit-identical at SSIM 1.000000 against the same seed before and after. denoise_euler_gpu still previews the sample: its velocity lives in a BF16 GPU tensor and would need a separate readback to combine, and that path selects on M5-class hardware, which I could not test on. The comment records that rather than leaving it silently inconsistent. Measured on an M1 Pro with a turbo checkpoint at 8 passes: previews go from unusable to recognisable at step 1.
LachlanStuart
added a commit
to LachlanStuart/h3.c
that referenced
this pull request
Sep 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Denoising previews currently decode
video_latent— the sample thesampler is stepping through. At high sigma that sample genuinely is
mostly noise, so on a short schedule the preview shows near-identical
coloured latent mush for most of the run and only resolves on the final
step. That defeats the purpose: there is nothing to judge and nothing to
cancel on.
Decoding the model's current estimate of the finished frame instead
gives a blurry version of the result from the first step, which then
sharpens.
The change
x0 = x_t + sigma * v, written into a scratch buffer and handed to thepreview callback. That is the same expression
denoise_resalready usesto build its denoised buffer — worth noting the sign, since the Euler
step moves the sample along
+vas sigma falls, so this engine'svelocity points toward the clean image rather than away from it. I
initially wrote the textbook
-and it would have made previews worse;the existing sampler is what corrected me.
The sampler's own trajectory is untouched, so final output is unchanged:
verified bit-identical at SSIM 1.000000 against the same seed before and
after.
Before and after
Same generation, same seed, steps 1 / 4 / 8 of an 8-pass turbo run at
352 square. Before: two indistinguishable noise fields, then the result.
After: a soft shape, a recognisable cat, the finished cat.
Scope and what I could not test
denoise_euler_gpustill previews the sample. Its velocity lives in aBF16 GPU tensor and would need a separate readback to combine, and that
path selects on M5-class hardware which I do not have. Rather than push
an untested change through code I cannot exercise, I left it and
recorded why in a comment — happy to do it if you would prefer, or to
drop the comment if you would rather it stayed silent.
Measured on an M1 Pro. The commit also frees the scratch buffer on both
exit paths.