Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

latent padding training and inference different #660

Open
cdfan0627 opened this issue Jan 12, 2025 · 14 comments
Open

latent padding training and inference different #660

cdfan0627 opened this issue Jan 12, 2025 · 14 comments
Assignees

Comments

@cdfan0627
Copy link

cdfan0627 commented Jan 12, 2025

您好,請問為什麼在CogvideoX 1.5 I2V model training的時候是先補齊latent的shape然後再對image latent 做padding,如下code 是 lora_trainer.py

patch_size_t = self.state.transformer_config.patch_size_t
        if patch_size_t is not None:
            ncopy = latent.shape[2] % patch_size_t
            first_frame = latent[:, :, :1, :, :]  # Get first frame [B, C, 1, H, W]
            latent = torch.cat([first_frame.repeat(1, 1, ncopy, 1, 1), latent], dim=2)
            assert latent.shape[2] % patch_size_t == 0
latent = latent.permute(0, 2, 1, 3, 4)
image_latents = image_latents.permute(0, 2, 1, 3, 4)
padding_shape = (latent.shape[0], latent.shape[1] - 1, *latent.shape[2:])
        latent_padding = image_latents.new_zeros(padding_shape)
        image_latents = torch.cat([image_latents, latent_padding], dim=1)

inference的時候卻對image latent做padding後,再補上第一個frame,如下code是pipeline_cogvideox_image2video.py

padding_shape = (
            batch_size,
            num_frames - 1,
            num_channels_latents,
            height // self.vae_scale_factor_spatial,
            width // self.vae_scale_factor_spatial,
        )

        latent_padding = torch.zeros(padding_shape, device=device, dtype=dtype)
        image_latents = torch.cat([image_latents, latent_padding], dim=1)

        if self.transformer.config.patch_size_t is not None:
            first_frame = image_latents[:, : image_latents.size(1) % self.transformer.config.patch_size_t, ...]
            image_latents = torch.cat([first_frame, image_latents], dim=1)

理論上training跟inference應該要一樣,inference出來的結果才會正確的,所以想請問一下training跟inference哪個是對的呢

@cdfan0627 cdfan0627 changed the title latent padding training and inference latent padding training and inference different Jan 12, 2025
@OleehyO OleehyO self-assigned this Jan 13, 2025
@OleehyO
Copy link
Collaborator

OleehyO commented Jan 13, 2025

pipeline里的代码由于一些历史原因写起来有点啰嗦,建议以training的代码作为参考。虽然实现方式有区别,但是最后的结果都是一样的。

@cdfan0627
Copy link
Author

可是inference的看起來比較合理,因為這樣image_latents的每一個latent才會跟video latent 對齊

@JaywongWang
Copy link

可是inference的看起來比較合理,因為這樣image_latents的每一個latent才會跟video latent 對齊

@cdfan0627 看下面的推理代码。推理时num_frames已经提前算好了,肯定会整除patch_size_t的,所以不会触发补第一个frame的代码逻辑。
https://github.com/huggingface/diffusers/blob/145522cbb7ed9c492539ba08307a25d13985a0b5/src/diffusers/pipelines/cogvideo/pipeline_cogvideox_image2video.py#L772-L780

@cdfan0627
Copy link
Author

@JaywongWang 你可能要進去 def prepare_latents裡面看就可以看到我上面貼的code,我指的不是video latent,我指的是image latent,因為cogvideoX 1.5 需要整除patch_size_t,所以他在 image latent padding後又再concat一個condition image(對i2v model就是first frame)

@JaywongWang
Copy link

@JaywongWang 你可能要進去 def prepare_latents裡面看就可以看到我上面貼的code,我指的不是video latent,我指的是image latent,因為cogvideoX 1.5 需要整除patch_size_t,所以他在 image latent padding後又再concat一個condition image(對i2v model就是first frame)

@cdfan0627 image_latent是按照num_frames来pad的,保证了 image_latents.size(1) % self.transformer.config.patch_size_t 一定是0

@JaywongWang
Copy link

@JaywongWang 你可能要進去 def prepare_latents裡面看就可以看到我上面貼的code,我指的不是video latent,我指的是image latent,因為cogvideoX 1.5 需要整除patch_size_t,所以他在 image latent padding後又再concat一個condition image(對i2v model就是first frame)

@cdfan0627 否则如果触发这段代码,推理出来的结果肯定就不正常了。

@cdfan0627
Copy link
Author

cdfan0627 commented Feb 6, 2025

@JaywongWang 在padding_shape裡面num_frames會減1,所以image_latents.size(1) % self.transformer.config.patch_size_t不會是0,所以最後他又多concat一個first frame才會正常

@JaywongWang
Copy link

@JaywongWang 在padding shape裡面num_frames會減1,所以image_latents.size(1) % self.transformer.config.patch_size_t不會是0,所以最後他又多concat一個first frame才會正常

@cdfan0627 我print出来,49/81帧的输入,余数是0的。你也可以试试。

@JaywongWang
Copy link

@JaywongWang 在padding shape裡面num_frames會減1,所以image_latents.size(1) % self.transformer.config.patch_size_t不會是0,所以最後他又多concat一個first frame才會正常

@cdfan0627 减一是因为输入本身就是一张图了,padding后会变成num_frames的长度。

@cdfan0627
Copy link
Author

cdfan0627 commented Feb 6, 2025

@JaywongWang 你是對的,很抱歉我當初在trace code的時候有弄錯,非常謝謝糾正。只是我覺得如果按照余数是0會導致image latent除了first frame latent 是 image 以外其他都是 0 tensor,然後inference的code最後又會有latents = latents[:, additional_frames:]把additional_frames丟掉,additional_frames也含有image latent 的 first frame latent 資訊,這樣的inference方式好像跟cogvideoX (非1.5版本)的蠻不一樣的,因為cogvideoX 沒有patch_size_t不需要把additional_frames丟掉,所以更保留著image 的 first frame latent的資訊,不知道是不是這個原因導致cogvideoX 1.5效果好像比cogvideoX差。

@JaywongWang
Copy link

@JaywongWang 你是對的,很抱歉我當初在trace code的時候有弄錯,非常謝謝糾正。只是我覺得如果按照余数是0會導致image latent除了first frame latent 是 image 以外其他都是 0 tensor,然後inference的code最後又會有latents = latents[:, additional_frames:]把additional_frames丟掉,additional_frames也含有image latent 的 first frame latent 資訊,這樣的inference方式好像跟cogvideoX (非1.5版本)的蠻不一樣的,因為cogvideoX 沒有patch_size_t不需要把additional_frames丟掉,所以更保留著image 的 first frame latent的資訊,不知道是不是這個原因導致cogvideoX 1.5效果好像比cogvideoX差。

@cdfan0627 仔细对比了下代码,确实像你说的这样。不过丢additional_frames这一步,是在denoised latent上做的,可能影响也不大,从逻辑上看,可能是少解码了第一帧?

@cdfan0627
Copy link
Author

@JaywongWang 我覺得應該就是像你說的一樣少解码了第一帧,謝謝。

@JaywongWang
Copy link

@JaywongWang 我覺得應該就是像你說的一樣少解码了第一帧,謝謝。

@cdfan0627 好的不客气的。

@JaywongWang
Copy link

@JaywongWang 我覺得應該就是像你說的一樣少解码了第一帧,謝謝。

@cdfan0627 我仔细想了一下,因为video latent本身包含了首帧,并且又添加了additional_frames(所以video latent包含了2个首帧),所以denoised latent丢掉additional frames后,尽管image latent的部分丢掉了,但video latent里面还有首帧的信息。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants