Fabrice-TIERCELIN commited on
Commit
5601aea
·
verified ·
1 Parent(s): 5ca407e

Upload 2 files

Browse files
video_to_video/__init__.py ADDED
File without changes
video_to_video/video_to_video_model.py ADDED
@@ -0,0 +1,237 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import os.path as osp
3
+ import random
4
+ from typing import Any, Dict
5
+
6
+ import torch
7
+ import torch.cuda.amp as amp
8
+ import torch.nn.functional as F
9
+
10
+ from video_to_video.modules import *
11
+ from video_to_video.utils.config import cfg
12
+ from video_to_video.diffusion.diffusion_sdedit import GaussianDiffusion
13
+ from video_to_video.diffusion.schedules_sdedit import noise_schedule
14
+ from video_to_video.utils.logger import get_logger
15
+
16
+ from diffusers import AutoencoderKLTemporalDecoder
17
+ import requests
18
+
19
+ def download_model(url, model_path):
20
+ if not os.path.exists(os.path.join(model_path, 'model.pt')):
21
+ print(f"Model not found at {model_path}, downloading...")
22
+ response = requests.get(url, stream=True)
23
+ with open(os.path.join(model_path, 'model.pt'), 'wb') as f:
24
+ for chunk in response.iter_content(chunk_size=1024):
25
+ if chunk:
26
+ f.write(chunk)
27
+ print(f"Model downloaded to {model_path}")
28
+ else:
29
+ print(f"Model found at {model_path}, skipping download.")
30
+
31
+
32
+ logger = get_logger()
33
+
34
+ class VideoToVideo_sr():
35
+ def __init__(self, opt, device=torch.device(f'cuda:0')):
36
+ self.opt = opt
37
+ self.device = device # torch.device(f'cuda:0')
38
+
39
+ # text_encoder
40
+ text_encoder = FrozenOpenCLIPEmbedder(device=self.device, pretrained="laion2b_s32b_b79k")
41
+ text_encoder.model.to(self.device)
42
+ self.text_encoder = text_encoder
43
+ logger.info(f'Build encoder with FrozenOpenCLIPEmbedder')
44
+
45
+ # U-Net with ControlNet
46
+ generator = ControlledV2VUNet()
47
+ generator = generator.to(self.device)
48
+ generator.eval()
49
+
50
+ # 确保 cfg.model_path 是文件夹路径,不要加上文件名
51
+ cfg.model_path = opt.model_path
52
+ # download weight
53
+ model_url = 'https://huggingface.co/SherryX/STAR/resolve/main/I2VGen-XL-based/heavy_deg.pt'
54
+ download_model(model_url, cfg.model_path)
55
+
56
+ # 拼接完整路径
57
+ model_file_path = os.path.join(cfg.model_path, 'model.pt')
58
+ print('model_file_path:', model_file_path)
59
+
60
+ # 加载模型
61
+ load_dict = torch.load(model_file_path, map_location='cpu')
62
+
63
+ if 'state_dict' in load_dict:
64
+ load_dict = load_dict['state_dict']
65
+ ret = generator.load_state_dict(load_dict, strict=False)
66
+
67
+ self.generator = generator.half()
68
+ logger.info('Load model path {}, with local status {}'.format(cfg.model_path, ret))
69
+
70
+ # Noise scheduler
71
+ sigmas = noise_schedule(
72
+ schedule='logsnr_cosine_interp',
73
+ n=1000,
74
+ zero_terminal_snr=True,
75
+ scale_min=2.0,
76
+ scale_max=4.0)
77
+ diffusion = GaussianDiffusion(sigmas=sigmas)
78
+ self.diffusion = diffusion
79
+ logger.info('Build diffusion with GaussianDiffusion')
80
+
81
+ # Temporal VAE
82
+ vae = AutoencoderKLTemporalDecoder.from_pretrained(
83
+ "stabilityai/stable-video-diffusion-img2vid", subfolder="vae", variant="fp16"
84
+ )
85
+ vae.eval()
86
+ vae.requires_grad_(False)
87
+ vae.to(self.device)
88
+ self.vae = vae
89
+ logger.info('Build Temporal VAE')
90
+
91
+ torch.cuda.empty_cache()
92
+
93
+ self.negative_prompt = cfg.negative_prompt
94
+ self.positive_prompt = cfg.positive_prompt
95
+
96
+ negative_y = text_encoder(self.negative_prompt).detach()
97
+ self.negative_y = negative_y
98
+
99
+ self.chunk_size = opt.chunk_size
100
+
101
+
102
+ def test(self, input: Dict[str, Any], total_noise_levels=1000, \
103
+ steps=50, solver_mode='fast', guide_scale=7.5, max_chunk_len=32):
104
+ video_data = input['video_data']
105
+ y = input['y']
106
+ (target_h, target_w) = input['target_res']
107
+
108
+ video_data = F.interpolate(video_data, [target_h,target_w], mode='bilinear')
109
+
110
+ logger.info(f'video_data shape: {video_data.shape}')
111
+ frames_num, _, h, w = video_data.shape
112
+
113
+ padding = pad_to_fit(h, w)
114
+ video_data = F.pad(video_data, padding, 'constant', 1)
115
+
116
+ video_data = video_data.unsqueeze(0)
117
+ bs = 1
118
+ video_data = video_data.to(self.device)
119
+
120
+ video_data_feature = self.vae_encode(video_data)
121
+ torch.cuda.empty_cache()
122
+
123
+ y = self.text_encoder(y).detach()
124
+
125
+ with amp.autocast(enabled=True):
126
+
127
+ t = torch.LongTensor([total_noise_levels-1]).to(self.device)
128
+ noised_lr = self.diffusion.diffuse(video_data_feature, t)
129
+
130
+ model_kwargs = [{'y': y}, {'y': self.negative_y}]
131
+ model_kwargs.append({'hint': video_data_feature})
132
+
133
+ torch.cuda.empty_cache()
134
+ chunk_inds = make_chunks(frames_num, interp_f_num=0, max_chunk_len=max_chunk_len) if frames_num > max_chunk_len else None
135
+
136
+ solver = 'dpmpp_2m_sde' # 'heun' | 'dpmpp_2m_sde'
137
+ gen_vid = self.diffusion.sample_sr(
138
+ noise=noised_lr,
139
+ model=self.generator,
140
+ model_kwargs=model_kwargs,
141
+ guide_scale=guide_scale,
142
+ guide_rescale=0.2,
143
+ solver=solver,
144
+ solver_mode=solver_mode,
145
+ return_intermediate=None,
146
+ steps=steps,
147
+ t_max=total_noise_levels - 1,
148
+ t_min=0,
149
+ discretization='trailing',
150
+ chunk_inds=chunk_inds,)
151
+ torch.cuda.empty_cache()
152
+
153
+ logger.info(f'sampling, finished.')
154
+ vid_tensor_gen = self.vae_decode_chunk(gen_vid, chunk_size=self.chunk_size)
155
+
156
+ logger.info(f'temporal vae decoding, finished.')
157
+
158
+ w1, w2, h1, h2 = padding
159
+ vid_tensor_gen = vid_tensor_gen[:,:,h1:h+h1,w1:w+w1]
160
+
161
+ gen_video = rearrange(
162
+ vid_tensor_gen, '(b f) c h w -> b c f h w', b=bs)
163
+
164
+ torch.cuda.empty_cache()
165
+
166
+ return gen_video.type(torch.float32).cpu()
167
+
168
+ def temporal_vae_decode(self, z, num_f):
169
+ return self.vae.decode(z/self.vae.config.scaling_factor, num_frames=num_f).sample
170
+
171
+ def vae_decode_chunk(self, z, chunk_size=3):
172
+ z = rearrange(z, "b c f h w -> (b f) c h w")
173
+ video = []
174
+ for ind in range(0, z.shape[0], chunk_size):
175
+ num_f = z[ind:ind+chunk_size].shape[0]
176
+ video.append(self.temporal_vae_decode(z[ind:ind+chunk_size],num_f))
177
+ video = torch.cat(video)
178
+ return video
179
+
180
+ def vae_encode(self, t, chunk_size=1):
181
+ num_f = t.shape[1]
182
+ t = rearrange(t, "b f c h w -> (b f) c h w")
183
+ z_list = []
184
+ for ind in range(0,t.shape[0],chunk_size):
185
+ z_list.append(self.vae.encode(t[ind:ind+chunk_size]).latent_dist.sample())
186
+ z = torch.cat(z_list, dim=0)
187
+ z = rearrange(z, "(b f) c h w -> b c f h w", f=num_f)
188
+ return z * self.vae.config.scaling_factor
189
+
190
+
191
+ def pad_to_fit(h, w):
192
+ BEST_H, BEST_W = 720, 1280
193
+
194
+ if h < BEST_H:
195
+ h1, h2 = _create_pad(h, BEST_H)
196
+ elif h == BEST_H:
197
+ h1 = h2 = 0
198
+ else:
199
+ h1 = 0
200
+ h2 = int((h + 48) // 64 * 64) + 64 - 48 - h
201
+
202
+ if w < BEST_W:
203
+ w1, w2 = _create_pad(w, BEST_W)
204
+ elif w == BEST_W:
205
+ w1 = w2 = 0
206
+ else:
207
+ w1 = 0
208
+ w2 = int(w // 64 * 64) + 64 - w
209
+ return (w1, w2, h1, h2)
210
+
211
+ def _create_pad(h, max_len):
212
+ h1 = int((max_len - h) // 2)
213
+ h2 = max_len - h1 - h
214
+ return h1, h2
215
+
216
+
217
+ def make_chunks(f_num, interp_f_num, max_chunk_len, chunk_overlap_ratio=0.5):
218
+ MAX_CHUNK_LEN = max_chunk_len
219
+ MAX_O_LEN = MAX_CHUNK_LEN * chunk_overlap_ratio
220
+ chunk_len = int((MAX_CHUNK_LEN-1)//(1+interp_f_num)*(interp_f_num+1)+1)
221
+ o_len = int((MAX_O_LEN-1)//(1+interp_f_num)*(interp_f_num+1)+1)
222
+ chunk_inds = sliding_windows_1d(f_num, chunk_len, o_len)
223
+ return chunk_inds
224
+
225
+
226
+ def sliding_windows_1d(length, window_size, overlap_size):
227
+ stride = window_size - overlap_size
228
+ ind = 0
229
+ coords = []
230
+ while ind<length:
231
+ if ind+window_size*1.25>=length:
232
+ coords.append((ind,length))
233
+ break
234
+ else:
235
+ coords.append((ind,ind+window_size))
236
+ ind += stride
237
+ return coords