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

finetune CogVideoX frames #647

Open
cdfan0627 opened this issue Jan 8, 2025 · 15 comments
Open

finetune CogVideoX frames #647

cdfan0627 opened this issue Jan 8, 2025 · 15 comments
Assignees

Comments

@cdfan0627
Copy link

我在README中看到,finetune CogVideoX 帧数必须是8的倍数 +1 ,請問如果只是8的倍數沒有加1可以嗎,因為我在VAE code 裡面看到帧数可以是8的倍数 或 8的倍数 +1。

@zRzRzRzRzRzRzR zRzRzRzRzRzRzR self-assigned this Jan 9, 2025
@zRzRzRzRzRzRzR
Copy link
Member

这个 + 1 不是你准备数据哟用的,你准备数据就是8N。比如48帧 6秒

@zRzRzRzRzRzRzR
Copy link
Member

  • 1 是因为第一帧要么是图(来自视频第一帧复制得来) 或者空白的噪声(T2V)

@cdfan0627
Copy link
Author

不好意思我想再問一下,我在I2V model的 code 裡看到image 好像是vae encode後concat在video latent 的channel dimension 上,可以問一下為什麼你說那個 1 是因为第一帧要么是图(来自视频第一帧复制得来) 或者空白的噪声(T2V)嗎,因為好像concat是在channel dimension 上,好像跟frames數沒什麼關係嗎

@zRzRzRzRzRzRzR
Copy link
Member

是concat在latent,而且处理的是 8*N的部分在拼上前面的latent。我们在encode的时候,微调实现的逻辑是这样的。

latent初始化的时候是 21的形状。

如果是I2V,你准备8N长度的视频。代码复制视频第一帧变成 8N + 1。接着,vae encode。8N +1。 此时latent形状就是21。
如果是T2V,你准备8N长度的视频。vae encode 8N,latent[0]还是初始化的噪声。还是21。

@cdfan0627
Copy link
Author

cdfan0627 commented Jan 9, 2025

可是按照train code的話,如果是I2V,我準備8N长度的视频,vae 應該是 encode 8N frames 成video latent,然後vae會在encode 视频第一帧 image 成 image latent,並且padding image latent 的latent frames數跟video latent的frames數相同,如下code

image_latents = image_latents.permute(0, 2, 1, 3, 4)  # [B, F, C, H, W]
video_latents = video_latents.permute(0, 2, 1, 3, 4)  # [B, F, C, H, W]
padding_shape = (video_latents.shape[0], video_latents.shape[1] - 1, *video_latents.shape[2:])
latent_padding = image_latents.new_zeros(padding_shape)
image_latents = torch.cat([image_latents, latent_padding], dim=1)

然後video latent跟image latent,會一起concat在latent 的 channel dimension 上,不是frame dimension 上,如下code

noisy_video_latents = scheduler.add_noise(video_latents, noise, timesteps)
noisy_model_input = torch.cat([noisy_video_latents, image_latents], dim=2)

所以這樣好像跟latent 的frames數量沒有關係嗎?
想再請問一下inference 的時候設定輸出49frames,最後會輸出48frames還是49frames呢?

@zRzRzRzRzRzRzR
Copy link
Member

zRzRzRzRzRzRzR commented Jan 10, 2025

在此进行确认:
首先,我们在训练的时候(post train)视频长度就是81。(8N + 1),有两种情况

  1. 你的帧数超过了81,会直接裁剪前面的81帧。
  2. 如果你的帧没有到81,会pad最后一帧都视频到81。
  3. latent的第一个块要进行一次复制,不是对图像进行一次复制。
    这一版代码我们在dev分支会进行更新,预计今天完成,

@cdfan0627
Copy link
Author

cdfan0627 commented Jan 10, 2025

請問如果training frames數是8N的話例如48 frames不是就不需要複製第一個latent了嗎,為什麼還要用8n+1的frames去train,然後在複製第一個latent

而且你的code中有下面這段

sample_frames = self.state.train_frames - 1

        if self.args.model_type == "i2v":
            self.dataset = I2VDatasetWithResize(
                **(self.args.model_dump()),
                device=self.accelerator.device,
                max_num_frames=sample_frames,
                height=self.state.train_height,
                width=self.state.train_width,
                trainer=self,
            )

self.state.train_frames=49 sample_frames=48 這樣看起training時 我們要準備的video 長度還是準備 8N frames 對嗎

@zRzRzRzRzRzRzR
Copy link
Member

zRzRzRzRzRzRzR commented Jan 11, 2025

推理和训练并不相同。
用户想看到的其实是8N的视频,但是模型在postrain的时候,是使用8N + 1 训练的。

对于训练,则应该正常的使用8N + 1的视频长度座位数据集。正确的做法不应该是复制第一帧,而是把8N(假设N是6)的视频复制最后一帧(如果你的数据集都不足49, 比如你是43 的视频,则是pad最后一帧6次。
由于8N 和 8N + 1 只差距1帧率,导致之前在微调I2V的时候我们在测试迪士尼数据集的时候差距不大。忽略了这个问题。
正确的做法是,你可以准备任意长度的数据集,假设你的数据集是47帧,43帧,35帧,60帧(总帧)混合的数据集。他们在训练的时候都会变成49.
其中 47 pad 2个最后一帧,43pad6个,35 pad 14个,60的仅取前49帧。这样就行了。我们dev已经更新了最新的一个PR。
#654

@cdfan0627
Copy link
Author

cdfan0627 commented Jan 11, 2025

我目前用cli_demo.py 設num_frames=49 inference出來還是49張frames 好像不像你說的解码出来是8N frames (例如48 frames)

想再請問一下如果以 I2V model 的inference情況來說,有一張image 當作input condition 時,inference 時出來的video 會包含input的那張image嗎,還是只包含input image 下個timestep 之後的frames呢

再請問一下finetune的時候,是建議不要用main branch 改用CogvideoX_dev branch的code嗎

@zRzRzRzRzRzRzR
Copy link
Member

zRzRzRzRzRzRzR commented Jan 11, 2025

  1. 这点操作是这样的
    latent的形状是21,但是为了整除t patch,所以实际上推理中是22,所以要丢弃第一个latent来做vae,此时 4N + 1 被还原成了8N + 1.得到了81。这个确实是81(1.0 是49 且不存在pad 的问题,1.0版本没有tpatch,latent 应该就是13)。
  2. 包含,images是你的首帧, 但是这一帧经过VAE重建,可能与原始图像完全相同。
    3 如果你现在就要用,建议还是用dev,或者我们周末弄完确定合并PR后用main的版本。

@cdfan0627
Copy link
Author

了解,所以inference出來的video的第一個frame是經過VAE重建的condition image,那第二個frame就是condition image的下個timestep對嗎

@OleehyO
Copy link
Collaborator

OleehyO commented Jan 11, 2025

这已经是老的代码了,建议看一下新的代码 #654i2v_datasettrainer

对于I2V来说用户必须指定8N + 1,然后视频直接采样8N + 1(老的代码是用户输入8N+1,在视频里采样8N,然后把图片复制到第一帧,从而变成8N + 1帧)。

这里以81帧为例:vae decode时下采样四倍得到21个latent,由于CogvideoX1.5的patch_t = 2,因此要让latent数目满足2的倍数,所以后面会给第一个latent复制一次,变成22个latent然后训练。

推理也是同理,用户要跟训练时一样输入8N + 1的帧数,同样以用户输入81帧为例:先在这里转换到85帧(加了4帧),再在这里算出latent的个数( (85-1)//4 + 1 = 22)

vae解码前,需要先取出第一个复制出来的latent(参考这里),还剩21个latent,然后解码10次,每一次分别得到9帧,8帧,8帧, ...,8帧,最后得到81帧的视频(可以参考这部分代码)

@cdfan0627
Copy link
Author

cdfan0627 commented Jan 11, 2025

有,謝謝,zRzRzRzRzRzRzR 回我後我已經看過新的code了,我只是想再確認一下我上面提到的問題,也就是 inference出來的video的第一個frame是經過VAE重建的condition image,那第二個frame就是condition image的下個timestep對嗎

这已经是老的代码了,建议看一下新的代码 #654i2v_datasettrainer

对于I2V来说用户必须指定8N + 1,然后视频直接采样8N + 1(老的代码是用户输入8N+1,在视频里采样8N,然后把图片复制到第一帧,从而变成8N + 1帧)。

这里以81帧为例:vae decode时下采样四倍得到21个latent,由于CogvideoX1.5的patch_t = 2,因此要让latent数目满足2的倍数,所以后面会给第一个latent复制一次,变成22个latent然后训练。

推理也是同理,用户要跟训练时一样输入8N + 1的帧数,同样以用户输入81帧为例:先在这里转换到85帧(加了4帧),再在这里算出latent的个数( (85-1)//4 + 1 = 22)

vae解码前,需要先取出第一个复制出来的latent(参考这里),还剩21个latent,然后解码10次,每一次分别得到9帧,8帧,8帧, ...,8帧,最后得到81帧的视频(可以参考这部分代码)

@OleehyO
Copy link
Collaborator

OleehyO commented Jan 12, 2025

emm...也可以这么理解吧,但实际上生成视频帧的时候不是一帧一帧生成的,准确来说这里指的应该是latent

@cdfan0627
Copy link
Author

了解謝謝,我只是想確認最後生成的video 的第二個frame就是否就是condition image的下個timestep

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