You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Wan I2V expand_timesteps: why hard-clamp only first frame (no last-frame clamp)? #13167
I have a question on expand_timesteps option within WanImageToVideoPipeline. I see that the mechanism hard-clamps only the first frame. For FLF (first+last) conditioning, is there a reason we can’t (or shouldn’t) apply the same mechanism to both endpoints?
Question
Is it a limitation of the Wan2.2 I2V checkpoint training (only first-frame conditioning)?
Or a design choice because per-token timestep masking doesn’t extend cleanly to a last-frame constraint?
I see that the corresponding part was written by @yiyixuxu, thanks!
Hi @emirks, the first-frame-only clamp is what that branch is doing, and the last frame is handled on the other path.
Root cause
prepare_latents forks on self.config.expand_timesteps.
When it is true, video_condition is only image, last_image is not encoded, and first_frame_mask[:, :, 0] = 0. The denoising loop then builds latent_model_input from that mask and sets per-token timesteps with temp_ts = (first_frame_mask[0][0][:, ::2, ::2] * t). Frame 0 stays at timestep 0. Every other frame, including the last, stays at t. That is the image-to-video schedule this checkpoint was trained with.
When it is false and last_image is set, the condition is [first, zeros, last] and the mask keeps both endpoints. First-and-last-frame conditioning already goes through that branch.
Clamping the last frame inside expand_timesteps would change the timestep layout of a model that was not trained that way. The two schedules are not interchangeable.
Proposed approach
Leave expand_timesteps as first-frame-only. A docstring on prepare_latents should say that this flag ignores last_image, and that first-and-last-frame conditioning is the expand_timesteps=False path. I would not add a last-frame clamp to this branch.
I would be glad to open a PR for that docstring if it would help.
Activity
chinmayirm commentedon Sep 22, 2026
Hi @emirks, the first-frame-only clamp is what that branch is doing, and the last frame is handled on the other path.
Root cause
prepare_latentsforks onself.config.expand_timesteps.When it is true,
video_conditionis onlyimage,last_imageis not encoded, andfirst_frame_mask[:, :, 0] = 0. The denoising loop then buildslatent_model_inputfrom that mask and sets per-token timesteps withtemp_ts = (first_frame_mask[0][0][:, ::2, ::2] * t). Frame 0 stays at timestep 0. Every other frame, including the last, stays att. That is the image-to-video schedule this checkpoint was trained with.When it is false and
last_imageis set, the condition is[first, zeros, last]and the mask keeps both endpoints. First-and-last-frame conditioning already goes through that branch.Clamping the last frame inside
expand_timestepswould change the timestep layout of a model that was not trained that way. The two schedules are not interchangeable.Proposed approach
Leave
expand_timestepsas first-frame-only. A docstring onprepare_latentsshould say that this flag ignoreslast_image, and that first-and-last-frame conditioning is theexpand_timesteps=Falsepath. I would not add a last-frame clamp to this branch.I would be glad to open a PR for that docstring if it would help.