ckadirt commited on
Commit
338c1d2
·
verified ·
1 Parent(s): 692a967

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. MindEyeV2/src/generative_models/scripts/tests/attention.py +319 -0
  2. MindEyeV2/src/generative_models/scripts/util/detection/nsfw_and_watermark_dectection.py +110 -0
  3. MindEyeV2/src/generative_models/sgm/__init__.py +4 -0
  4. MindEyeV2/src/generative_models/sgm/__pycache__/__init__.cpython-310.pyc +0 -0
  5. MindEyeV2/src/generative_models/sgm/__pycache__/__init__.cpython-311.pyc +0 -0
  6. MindEyeV2/src/generative_models/sgm/__pycache__/util.cpython-310.pyc +0 -0
  7. MindEyeV2/src/generative_models/sgm/__pycache__/util.cpython-311.pyc +0 -0
  8. MindEyeV2/src/generative_models/sgm/data/__init__.py +1 -0
  9. MindEyeV2/src/generative_models/sgm/data/cifar10.py +67 -0
  10. MindEyeV2/src/generative_models/sgm/data/dataset.py +80 -0
  11. MindEyeV2/src/generative_models/sgm/data/mnist.py +85 -0
  12. MindEyeV2/src/generative_models/sgm/lr_scheduler.py +135 -0
  13. MindEyeV2/src/generative_models/sgm/modules/__init__.py +6 -0
  14. MindEyeV2/src/generative_models/sgm/modules/__pycache__/__init__.cpython-310.pyc +0 -0
  15. MindEyeV2/src/generative_models/sgm/modules/__pycache__/__init__.cpython-311.pyc +0 -0
  16. MindEyeV2/src/generative_models/sgm/modules/__pycache__/attention.cpython-310.pyc +0 -0
  17. MindEyeV2/src/generative_models/sgm/modules/__pycache__/attention.cpython-311.pyc +0 -0
  18. MindEyeV2/src/generative_models/sgm/modules/__pycache__/ema.cpython-310.pyc +0 -0
  19. MindEyeV2/src/generative_models/sgm/modules/__pycache__/ema.cpython-311.pyc +0 -0
  20. MindEyeV2/src/generative_models/sgm/modules/__pycache__/video_attention.cpython-310.pyc +0 -0
  21. MindEyeV2/src/generative_models/sgm/modules/__pycache__/video_attention.cpython-311.pyc +0 -0
  22. MindEyeV2/src/generative_models/sgm/modules/attention.py +759 -0
  23. MindEyeV2/src/generative_models/sgm/modules/autoencoding/__init__.py +0 -0
  24. MindEyeV2/src/generative_models/sgm/modules/autoencoding/__pycache__/__init__.cpython-310.pyc +0 -0
  25. MindEyeV2/src/generative_models/sgm/modules/autoencoding/__pycache__/__init__.cpython-311.pyc +0 -0
  26. MindEyeV2/src/generative_models/sgm/modules/autoencoding/__pycache__/temporal_ae.cpython-310.pyc +0 -0
  27. MindEyeV2/src/generative_models/sgm/modules/autoencoding/__pycache__/temporal_ae.cpython-311.pyc +0 -0
  28. MindEyeV2/src/generative_models/sgm/modules/autoencoding/losses/__init__.py +7 -0
  29. MindEyeV2/src/generative_models/sgm/modules/autoencoding/losses/discriminator_loss.py +306 -0
  30. MindEyeV2/src/generative_models/sgm/modules/autoencoding/losses/lpips.py +73 -0
  31. MindEyeV2/src/generative_models/sgm/modules/autoencoding/lpips/__init__.py +0 -0
  32. MindEyeV2/src/generative_models/sgm/modules/autoencoding/lpips/loss/.gitignore +1 -0
  33. MindEyeV2/src/generative_models/sgm/modules/autoencoding/lpips/loss/LICENSE +23 -0
  34. MindEyeV2/src/generative_models/sgm/modules/autoencoding/lpips/loss/__init__.py +0 -0
  35. MindEyeV2/src/generative_models/sgm/modules/autoencoding/lpips/loss/lpips.py +147 -0
  36. MindEyeV2/src/generative_models/sgm/modules/autoencoding/lpips/model/LICENSE +58 -0
  37. MindEyeV2/src/generative_models/sgm/modules/autoencoding/lpips/model/__init__.py +0 -0
  38. MindEyeV2/src/generative_models/sgm/modules/autoencoding/lpips/model/model.py +88 -0
  39. MindEyeV2/src/generative_models/sgm/modules/autoencoding/lpips/util.py +128 -0
  40. MindEyeV2/src/generative_models/sgm/modules/autoencoding/lpips/vqperceptual.py +17 -0
  41. MindEyeV2/src/generative_models/sgm/modules/autoencoding/regularizers/__init__.py +31 -0
  42. MindEyeV2/src/generative_models/sgm/modules/autoencoding/regularizers/__pycache__/__init__.cpython-310.pyc +0 -0
  43. MindEyeV2/src/generative_models/sgm/modules/autoencoding/regularizers/__pycache__/__init__.cpython-311.pyc +0 -0
  44. MindEyeV2/src/generative_models/sgm/modules/autoencoding/regularizers/__pycache__/base.cpython-310.pyc +0 -0
  45. MindEyeV2/src/generative_models/sgm/modules/autoencoding/regularizers/__pycache__/base.cpython-311.pyc +0 -0
  46. MindEyeV2/src/generative_models/sgm/modules/autoencoding/regularizers/base.py +40 -0
  47. MindEyeV2/src/generative_models/sgm/modules/autoencoding/regularizers/quantize.py +487 -0
  48. MindEyeV2/src/generative_models/sgm/modules/autoencoding/temporal_ae.py +349 -0
  49. MindEyeV2/src/generative_models/sgm/modules/diffusionmodules/__init__.py +0 -0
  50. MindEyeV2/src/generative_models/sgm/modules/diffusionmodules/__pycache__/denoiser.cpython-311.pyc +0 -0
MindEyeV2/src/generative_models/scripts/tests/attention.py ADDED
@@ -0,0 +1,319 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import einops
2
+ import torch
3
+ import torch.nn.functional as F
4
+ import torch.utils.benchmark as benchmark
5
+ from torch.backends.cuda import SDPBackend
6
+
7
+ from sgm.modules.attention import BasicTransformerBlock, SpatialTransformer
8
+
9
+
10
+ def benchmark_attn():
11
+ # Lets define a helpful benchmarking function:
12
+ # https://pytorch.org/tutorials/intermediate/scaled_dot_product_attention_tutorial.html
13
+ device = "cuda" if torch.cuda.is_available() else "cpu"
14
+
15
+ def benchmark_torch_function_in_microseconds(f, *args, **kwargs):
16
+ t0 = benchmark.Timer(
17
+ stmt="f(*args, **kwargs)", globals={"args": args, "kwargs": kwargs, "f": f}
18
+ )
19
+ return t0.blocked_autorange().mean * 1e6
20
+
21
+ # Lets define the hyper-parameters of our input
22
+ batch_size = 32
23
+ max_sequence_len = 1024
24
+ num_heads = 32
25
+ embed_dimension = 32
26
+
27
+ dtype = torch.float16
28
+
29
+ query = torch.rand(
30
+ batch_size,
31
+ num_heads,
32
+ max_sequence_len,
33
+ embed_dimension,
34
+ device=device,
35
+ dtype=dtype,
36
+ )
37
+ key = torch.rand(
38
+ batch_size,
39
+ num_heads,
40
+ max_sequence_len,
41
+ embed_dimension,
42
+ device=device,
43
+ dtype=dtype,
44
+ )
45
+ value = torch.rand(
46
+ batch_size,
47
+ num_heads,
48
+ max_sequence_len,
49
+ embed_dimension,
50
+ device=device,
51
+ dtype=dtype,
52
+ )
53
+
54
+ print(f"q/k/v shape:", query.shape, key.shape, value.shape)
55
+
56
+ # Lets explore the speed of each of the 3 implementations
57
+ from torch.backends.cuda import SDPBackend, sdp_kernel
58
+
59
+ # Helpful arguments mapper
60
+ backend_map = {
61
+ SDPBackend.MATH: {
62
+ "enable_math": True,
63
+ "enable_flash": False,
64
+ "enable_mem_efficient": False,
65
+ },
66
+ SDPBackend.FLASH_ATTENTION: {
67
+ "enable_math": False,
68
+ "enable_flash": True,
69
+ "enable_mem_efficient": False,
70
+ },
71
+ SDPBackend.EFFICIENT_ATTENTION: {
72
+ "enable_math": False,
73
+ "enable_flash": False,
74
+ "enable_mem_efficient": True,
75
+ },
76
+ }
77
+
78
+ from torch.profiler import ProfilerActivity, profile, record_function
79
+
80
+ activities = [ProfilerActivity.CPU, ProfilerActivity.CUDA]
81
+
82
+ print(
83
+ f"The default implementation runs in {benchmark_torch_function_in_microseconds(F.scaled_dot_product_attention, query, key, value):.3f} microseconds"
84
+ )
85
+ with profile(
86
+ activities=activities, record_shapes=False, profile_memory=True
87
+ ) as prof:
88
+ with record_function("Default detailed stats"):
89
+ for _ in range(25):
90
+ o = F.scaled_dot_product_attention(query, key, value)
91
+ print(prof.key_averages().table(sort_by="cuda_time_total", row_limit=10))
92
+
93
+ print(
94
+ f"The math implementation runs in {benchmark_torch_function_in_microseconds(F.scaled_dot_product_attention, query, key, value):.3f} microseconds"
95
+ )
96
+ with sdp_kernel(**backend_map[SDPBackend.MATH]):
97
+ with profile(
98
+ activities=activities, record_shapes=False, profile_memory=True
99
+ ) as prof:
100
+ with record_function("Math implmentation stats"):
101
+ for _ in range(25):
102
+ o = F.scaled_dot_product_attention(query, key, value)
103
+ print(prof.key_averages().table(sort_by="cuda_time_total", row_limit=10))
104
+
105
+ with sdp_kernel(**backend_map[SDPBackend.FLASH_ATTENTION]):
106
+ try:
107
+ print(
108
+ f"The flash attention implementation runs in {benchmark_torch_function_in_microseconds(F.scaled_dot_product_attention, query, key, value):.3f} microseconds"
109
+ )
110
+ except RuntimeError:
111
+ print("FlashAttention is not supported. See warnings for reasons.")
112
+ with profile(
113
+ activities=activities, record_shapes=False, profile_memory=True
114
+ ) as prof:
115
+ with record_function("FlashAttention stats"):
116
+ for _ in range(25):
117
+ o = F.scaled_dot_product_attention(query, key, value)
118
+ print(prof.key_averages().table(sort_by="cuda_time_total", row_limit=10))
119
+
120
+ with sdp_kernel(**backend_map[SDPBackend.EFFICIENT_ATTENTION]):
121
+ try:
122
+ print(
123
+ f"The memory efficient implementation runs in {benchmark_torch_function_in_microseconds(F.scaled_dot_product_attention, query, key, value):.3f} microseconds"
124
+ )
125
+ except RuntimeError:
126
+ print("EfficientAttention is not supported. See warnings for reasons.")
127
+ with profile(
128
+ activities=activities, record_shapes=False, profile_memory=True
129
+ ) as prof:
130
+ with record_function("EfficientAttention stats"):
131
+ for _ in range(25):
132
+ o = F.scaled_dot_product_attention(query, key, value)
133
+ print(prof.key_averages().table(sort_by="cuda_time_total", row_limit=10))
134
+
135
+
136
+ def run_model(model, x, context):
137
+ return model(x, context)
138
+
139
+
140
+ def benchmark_transformer_blocks():
141
+ device = "cuda" if torch.cuda.is_available() else "cpu"
142
+ import torch.utils.benchmark as benchmark
143
+
144
+ def benchmark_torch_function_in_microseconds(f, *args, **kwargs):
145
+ t0 = benchmark.Timer(
146
+ stmt="f(*args, **kwargs)", globals={"args": args, "kwargs": kwargs, "f": f}
147
+ )
148
+ return t0.blocked_autorange().mean * 1e6
149
+
150
+ checkpoint = True
151
+ compile = False
152
+
153
+ batch_size = 32
154
+ h, w = 64, 64
155
+ context_len = 77
156
+ embed_dimension = 1024
157
+ context_dim = 1024
158
+ d_head = 64
159
+
160
+ transformer_depth = 4
161
+
162
+ n_heads = embed_dimension // d_head
163
+
164
+ dtype = torch.float16
165
+
166
+ model_native = SpatialTransformer(
167
+ embed_dimension,
168
+ n_heads,
169
+ d_head,
170
+ context_dim=context_dim,
171
+ use_linear=True,
172
+ use_checkpoint=checkpoint,
173
+ attn_type="softmax",
174
+ depth=transformer_depth,
175
+ sdp_backend=SDPBackend.FLASH_ATTENTION,
176
+ ).to(device)
177
+ model_efficient_attn = SpatialTransformer(
178
+ embed_dimension,
179
+ n_heads,
180
+ d_head,
181
+ context_dim=context_dim,
182
+ use_linear=True,
183
+ depth=transformer_depth,
184
+ use_checkpoint=checkpoint,
185
+ attn_type="softmax-xformers",
186
+ ).to(device)
187
+ if not checkpoint and compile:
188
+ print("compiling models")
189
+ model_native = torch.compile(model_native)
190
+ model_efficient_attn = torch.compile(model_efficient_attn)
191
+
192
+ x = torch.rand(batch_size, embed_dimension, h, w, device=device, dtype=dtype)
193
+ c = torch.rand(batch_size, context_len, context_dim, device=device, dtype=dtype)
194
+
195
+ from torch.profiler import ProfilerActivity, profile, record_function
196
+
197
+ activities = [ProfilerActivity.CPU, ProfilerActivity.CUDA]
198
+
199
+ with torch.autocast("cuda"):
200
+ print(
201
+ f"The native model runs in {benchmark_torch_function_in_microseconds(model_native.forward, x, c):.3f} microseconds"
202
+ )
203
+ print(
204
+ f"The efficientattn model runs in {benchmark_torch_function_in_microseconds(model_efficient_attn.forward, x, c):.3f} microseconds"
205
+ )
206
+
207
+ print(75 * "+")
208
+ print("NATIVE")
209
+ print(75 * "+")
210
+ torch.cuda.reset_peak_memory_stats()
211
+ with profile(
212
+ activities=activities, record_shapes=False, profile_memory=True
213
+ ) as prof:
214
+ with record_function("NativeAttention stats"):
215
+ for _ in range(25):
216
+ model_native(x, c)
217
+ print(prof.key_averages().table(sort_by="cuda_time_total", row_limit=10))
218
+ print(torch.cuda.max_memory_allocated() * 1e-9, "GB used by native block")
219
+
220
+ print(75 * "+")
221
+ print("Xformers")
222
+ print(75 * "+")
223
+ torch.cuda.reset_peak_memory_stats()
224
+ with profile(
225
+ activities=activities, record_shapes=False, profile_memory=True
226
+ ) as prof:
227
+ with record_function("xformers stats"):
228
+ for _ in range(25):
229
+ model_efficient_attn(x, c)
230
+ print(prof.key_averages().table(sort_by="cuda_time_total", row_limit=10))
231
+ print(torch.cuda.max_memory_allocated() * 1e-9, "GB used by xformers block")
232
+
233
+
234
+ def test01():
235
+ # conv1x1 vs linear
236
+ from sgm.util import count_params
237
+
238
+ conv = torch.nn.Conv2d(3, 32, kernel_size=1).cuda()
239
+ print(count_params(conv))
240
+ linear = torch.nn.Linear(3, 32).cuda()
241
+ print(count_params(linear))
242
+
243
+ print(conv.weight.shape)
244
+
245
+ # use same initialization
246
+ linear.weight = torch.nn.Parameter(conv.weight.squeeze(-1).squeeze(-1))
247
+ linear.bias = torch.nn.Parameter(conv.bias)
248
+
249
+ print(linear.weight.shape)
250
+
251
+ x = torch.randn(11, 3, 64, 64).cuda()
252
+
253
+ xr = einops.rearrange(x, "b c h w -> b (h w) c").contiguous()
254
+ print(xr.shape)
255
+ out_linear = linear(xr)
256
+ print(out_linear.mean(), out_linear.shape)
257
+
258
+ out_conv = conv(x)
259
+ print(out_conv.mean(), out_conv.shape)
260
+ print("done with test01.\n")
261
+
262
+
263
+ def test02():
264
+ # try cosine flash attention
265
+ import time
266
+
267
+ torch.backends.cuda.matmul.allow_tf32 = True
268
+ torch.backends.cudnn.allow_tf32 = True
269
+ torch.backends.cudnn.benchmark = True
270
+ print("testing cosine flash attention...")
271
+ DIM = 1024
272
+ SEQLEN = 4096
273
+ BS = 16
274
+
275
+ print(" softmax (vanilla) first...")
276
+ model = BasicTransformerBlock(
277
+ dim=DIM,
278
+ n_heads=16,
279
+ d_head=64,
280
+ dropout=0.0,
281
+ context_dim=None,
282
+ attn_mode="softmax",
283
+ ).cuda()
284
+ try:
285
+ x = torch.randn(BS, SEQLEN, DIM).cuda()
286
+ tic = time.time()
287
+ y = model(x)
288
+ toc = time.time()
289
+ print(y.shape, toc - tic)
290
+ except RuntimeError as e:
291
+ # likely oom
292
+ print(str(e))
293
+
294
+ print("\n now flash-cosine...")
295
+ model = BasicTransformerBlock(
296
+ dim=DIM,
297
+ n_heads=16,
298
+ d_head=64,
299
+ dropout=0.0,
300
+ context_dim=None,
301
+ attn_mode="flash-cosine",
302
+ ).cuda()
303
+ x = torch.randn(BS, SEQLEN, DIM).cuda()
304
+ tic = time.time()
305
+ y = model(x)
306
+ toc = time.time()
307
+ print(y.shape, toc - tic)
308
+ print("done with test02.\n")
309
+
310
+
311
+ if __name__ == "__main__":
312
+ # test01()
313
+ # test02()
314
+ # test03()
315
+
316
+ # benchmark_attn()
317
+ benchmark_transformer_blocks()
318
+
319
+ print("done.")
MindEyeV2/src/generative_models/scripts/util/detection/nsfw_and_watermark_dectection.py ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+
3
+ import clip
4
+ import numpy as np
5
+ import torch
6
+ import torchvision.transforms as T
7
+ from PIL import Image
8
+
9
+ RESOURCES_ROOT = "scripts/util/detection/"
10
+
11
+
12
+ def predict_proba(X, weights, biases):
13
+ logits = X @ weights.T + biases
14
+ proba = np.where(
15
+ logits >= 0, 1 / (1 + np.exp(-logits)), np.exp(logits) / (1 + np.exp(logits))
16
+ )
17
+ return proba.T
18
+
19
+
20
+ def load_model_weights(path: str):
21
+ model_weights = np.load(path)
22
+ return model_weights["weights"], model_weights["biases"]
23
+
24
+
25
+ def clip_process_images(images: torch.Tensor) -> torch.Tensor:
26
+ min_size = min(images.shape[-2:])
27
+ return T.Compose(
28
+ [
29
+ T.CenterCrop(min_size), # TODO: this might affect the watermark, check this
30
+ T.Resize(224, interpolation=T.InterpolationMode.BICUBIC, antialias=True),
31
+ T.Normalize(
32
+ (0.48145466, 0.4578275, 0.40821073),
33
+ (0.26862954, 0.26130258, 0.27577711),
34
+ ),
35
+ ]
36
+ )(images)
37
+
38
+
39
+ class DeepFloydDataFiltering(object):
40
+ def __init__(
41
+ self, verbose: bool = False, device: torch.device = torch.device("cpu")
42
+ ):
43
+ super().__init__()
44
+ self.verbose = verbose
45
+ self._device = None
46
+ self.clip_model, _ = clip.load("ViT-L/14", device=device)
47
+ self.clip_model.eval()
48
+
49
+ self.cpu_w_weights, self.cpu_w_biases = load_model_weights(
50
+ os.path.join(RESOURCES_ROOT, "w_head_v1.npz")
51
+ )
52
+ self.cpu_p_weights, self.cpu_p_biases = load_model_weights(
53
+ os.path.join(RESOURCES_ROOT, "p_head_v1.npz")
54
+ )
55
+ self.w_threshold, self.p_threshold = 0.5, 0.5
56
+
57
+ @torch.inference_mode()
58
+ def __call__(self, images: torch.Tensor) -> torch.Tensor:
59
+ imgs = clip_process_images(images)
60
+ if self._device is None:
61
+ self._device = next(p for p in self.clip_model.parameters()).device
62
+ image_features = self.clip_model.encode_image(imgs.to(self._device))
63
+ image_features = image_features.detach().cpu().numpy().astype(np.float16)
64
+ p_pred = predict_proba(image_features, self.cpu_p_weights, self.cpu_p_biases)
65
+ w_pred = predict_proba(image_features, self.cpu_w_weights, self.cpu_w_biases)
66
+ print(f"p_pred = {p_pred}, w_pred = {w_pred}") if self.verbose else None
67
+ query = p_pred > self.p_threshold
68
+ if query.sum() > 0:
69
+ print(f"Hit for p_threshold: {p_pred}") if self.verbose else None
70
+ images[query] = T.GaussianBlur(99, sigma=(100.0, 100.0))(images[query])
71
+ query = w_pred > self.w_threshold
72
+ if query.sum() > 0:
73
+ print(f"Hit for w_threshold: {w_pred}") if self.verbose else None
74
+ images[query] = T.GaussianBlur(99, sigma=(100.0, 100.0))(images[query])
75
+ return images
76
+
77
+
78
+ def load_img(path: str) -> torch.Tensor:
79
+ image = Image.open(path)
80
+ if not image.mode == "RGB":
81
+ image = image.convert("RGB")
82
+ image_transforms = T.Compose(
83
+ [
84
+ T.ToTensor(),
85
+ ]
86
+ )
87
+ return image_transforms(image)[None, ...]
88
+
89
+
90
+ def test(root):
91
+ from einops import rearrange
92
+
93
+ filter = DeepFloydDataFiltering(verbose=True)
94
+ for p in os.listdir((root)):
95
+ print(f"running on {p}...")
96
+ img = load_img(os.path.join(root, p))
97
+ filtered_img = filter(img)
98
+ filtered_img = rearrange(
99
+ 255.0 * (filtered_img.numpy())[0], "c h w -> h w c"
100
+ ).astype(np.uint8)
101
+ Image.fromarray(filtered_img).save(
102
+ os.path.join(root, f"{os.path.splitext(p)[0]}-filtered.jpg")
103
+ )
104
+
105
+
106
+ if __name__ == "__main__":
107
+ import fire
108
+
109
+ fire.Fire(test)
110
+ print("done.")
MindEyeV2/src/generative_models/sgm/__init__.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ from .models import AutoencodingEngine, DiffusionEngine
2
+ from .util import get_configs_path, instantiate_from_config
3
+
4
+ __version__ = "0.1.0"
MindEyeV2/src/generative_models/sgm/__pycache__/__init__.cpython-310.pyc ADDED
Binary file (344 Bytes). View file
 
MindEyeV2/src/generative_models/sgm/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (403 Bytes). View file
 
MindEyeV2/src/generative_models/sgm/__pycache__/util.cpython-310.pyc ADDED
Binary file (9.47 kB). View file
 
MindEyeV2/src/generative_models/sgm/__pycache__/util.cpython-311.pyc ADDED
Binary file (15.9 kB). View file
 
MindEyeV2/src/generative_models/sgm/data/__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+ from .dataset import StableDataModuleFromConfig
MindEyeV2/src/generative_models/sgm/data/cifar10.py ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pytorch_lightning as pl
2
+ import torchvision
3
+ from torch.utils.data import DataLoader, Dataset
4
+ from torchvision import transforms
5
+
6
+
7
+ class CIFAR10DataDictWrapper(Dataset):
8
+ def __init__(self, dset):
9
+ super().__init__()
10
+ self.dset = dset
11
+
12
+ def __getitem__(self, i):
13
+ x, y = self.dset[i]
14
+ return {"jpg": x, "cls": y}
15
+
16
+ def __len__(self):
17
+ return len(self.dset)
18
+
19
+
20
+ class CIFAR10Loader(pl.LightningDataModule):
21
+ def __init__(self, batch_size, num_workers=0, shuffle=True):
22
+ super().__init__()
23
+
24
+ transform = transforms.Compose(
25
+ [transforms.ToTensor(), transforms.Lambda(lambda x: x * 2.0 - 1.0)]
26
+ )
27
+
28
+ self.batch_size = batch_size
29
+ self.num_workers = num_workers
30
+ self.shuffle = shuffle
31
+ self.train_dataset = CIFAR10DataDictWrapper(
32
+ torchvision.datasets.CIFAR10(
33
+ root=".data/", train=True, download=True, transform=transform
34
+ )
35
+ )
36
+ self.test_dataset = CIFAR10DataDictWrapper(
37
+ torchvision.datasets.CIFAR10(
38
+ root=".data/", train=False, download=True, transform=transform
39
+ )
40
+ )
41
+
42
+ def prepare_data(self):
43
+ pass
44
+
45
+ def train_dataloader(self):
46
+ return DataLoader(
47
+ self.train_dataset,
48
+ batch_size=self.batch_size,
49
+ shuffle=self.shuffle,
50
+ num_workers=self.num_workers,
51
+ )
52
+
53
+ def test_dataloader(self):
54
+ return DataLoader(
55
+ self.test_dataset,
56
+ batch_size=self.batch_size,
57
+ shuffle=self.shuffle,
58
+ num_workers=self.num_workers,
59
+ )
60
+
61
+ def val_dataloader(self):
62
+ return DataLoader(
63
+ self.test_dataset,
64
+ batch_size=self.batch_size,
65
+ shuffle=self.shuffle,
66
+ num_workers=self.num_workers,
67
+ )
MindEyeV2/src/generative_models/sgm/data/dataset.py ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Optional
2
+
3
+ import torchdata.datapipes.iter
4
+ import webdataset as wds
5
+ from omegaconf import DictConfig
6
+ from pytorch_lightning import LightningDataModule
7
+
8
+ try:
9
+ from sdata import create_dataset, create_dummy_dataset, create_loader
10
+ except ImportError as e:
11
+ print("#" * 100)
12
+ print("Datasets not yet available")
13
+ print("to enable, we need to add stable-datasets as a submodule")
14
+ print("please use ``git submodule update --init --recursive``")
15
+ print("and do ``pip install -e stable-datasets/`` from the root of this repo")
16
+ print("#" * 100)
17
+ exit(1)
18
+
19
+
20
+ class StableDataModuleFromConfig(LightningDataModule):
21
+ def __init__(
22
+ self,
23
+ train: DictConfig,
24
+ validation: Optional[DictConfig] = None,
25
+ test: Optional[DictConfig] = None,
26
+ skip_val_loader: bool = False,
27
+ dummy: bool = False,
28
+ ):
29
+ super().__init__()
30
+ self.train_config = train
31
+ assert (
32
+ "datapipeline" in self.train_config and "loader" in self.train_config
33
+ ), "train config requires the fields `datapipeline` and `loader`"
34
+
35
+ self.val_config = validation
36
+ if not skip_val_loader:
37
+ if self.val_config is not None:
38
+ assert (
39
+ "datapipeline" in self.val_config and "loader" in self.val_config
40
+ ), "validation config requires the fields `datapipeline` and `loader`"
41
+ else:
42
+ print(
43
+ "Warning: No Validation datapipeline defined, using that one from training"
44
+ )
45
+ self.val_config = train
46
+
47
+ self.test_config = test
48
+ if self.test_config is not None:
49
+ assert (
50
+ "datapipeline" in self.test_config and "loader" in self.test_config
51
+ ), "test config requires the fields `datapipeline` and `loader`"
52
+
53
+ self.dummy = dummy
54
+ if self.dummy:
55
+ print("#" * 100)
56
+ print("USING DUMMY DATASET: HOPE YOU'RE DEBUGGING ;)")
57
+ print("#" * 100)
58
+
59
+ def setup(self, stage: str) -> None:
60
+ print("Preparing datasets")
61
+ if self.dummy:
62
+ data_fn = create_dummy_dataset
63
+ else:
64
+ data_fn = create_dataset
65
+
66
+ self.train_datapipeline = data_fn(**self.train_config.datapipeline)
67
+ if self.val_config:
68
+ self.val_datapipeline = data_fn(**self.val_config.datapipeline)
69
+ if self.test_config:
70
+ self.test_datapipeline = data_fn(**self.test_config.datapipeline)
71
+
72
+ def train_dataloader(self) -> torchdata.datapipes.iter.IterDataPipe:
73
+ loader = create_loader(self.train_datapipeline, **self.train_config.loader)
74
+ return loader
75
+
76
+ def val_dataloader(self) -> wds.DataPipeline:
77
+ return create_loader(self.val_datapipeline, **self.val_config.loader)
78
+
79
+ def test_dataloader(self) -> wds.DataPipeline:
80
+ return create_loader(self.test_datapipeline, **self.test_config.loader)
MindEyeV2/src/generative_models/sgm/data/mnist.py ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pytorch_lightning as pl
2
+ import torchvision
3
+ from torch.utils.data import DataLoader, Dataset
4
+ from torchvision import transforms
5
+
6
+
7
+ class MNISTDataDictWrapper(Dataset):
8
+ def __init__(self, dset):
9
+ super().__init__()
10
+ self.dset = dset
11
+
12
+ def __getitem__(self, i):
13
+ x, y = self.dset[i]
14
+ return {"jpg": x, "cls": y}
15
+
16
+ def __len__(self):
17
+ return len(self.dset)
18
+
19
+
20
+ class MNISTLoader(pl.LightningDataModule):
21
+ def __init__(self, batch_size, num_workers=0, prefetch_factor=2, shuffle=True):
22
+ super().__init__()
23
+
24
+ transform = transforms.Compose(
25
+ [transforms.ToTensor(), transforms.Lambda(lambda x: x * 2.0 - 1.0)]
26
+ )
27
+
28
+ self.batch_size = batch_size
29
+ self.num_workers = num_workers
30
+ self.prefetch_factor = prefetch_factor if num_workers > 0 else 0
31
+ self.shuffle = shuffle
32
+ self.train_dataset = MNISTDataDictWrapper(
33
+ torchvision.datasets.MNIST(
34
+ root=".data/", train=True, download=True, transform=transform
35
+ )
36
+ )
37
+ self.test_dataset = MNISTDataDictWrapper(
38
+ torchvision.datasets.MNIST(
39
+ root=".data/", train=False, download=True, transform=transform
40
+ )
41
+ )
42
+
43
+ def prepare_data(self):
44
+ pass
45
+
46
+ def train_dataloader(self):
47
+ return DataLoader(
48
+ self.train_dataset,
49
+ batch_size=self.batch_size,
50
+ shuffle=self.shuffle,
51
+ num_workers=self.num_workers,
52
+ prefetch_factor=self.prefetch_factor,
53
+ )
54
+
55
+ def test_dataloader(self):
56
+ return DataLoader(
57
+ self.test_dataset,
58
+ batch_size=self.batch_size,
59
+ shuffle=self.shuffle,
60
+ num_workers=self.num_workers,
61
+ prefetch_factor=self.prefetch_factor,
62
+ )
63
+
64
+ def val_dataloader(self):
65
+ return DataLoader(
66
+ self.test_dataset,
67
+ batch_size=self.batch_size,
68
+ shuffle=self.shuffle,
69
+ num_workers=self.num_workers,
70
+ prefetch_factor=self.prefetch_factor,
71
+ )
72
+
73
+
74
+ if __name__ == "__main__":
75
+ dset = MNISTDataDictWrapper(
76
+ torchvision.datasets.MNIST(
77
+ root=".data/",
78
+ train=False,
79
+ download=True,
80
+ transform=transforms.Compose(
81
+ [transforms.ToTensor(), transforms.Lambda(lambda x: x * 2.0 - 1.0)]
82
+ ),
83
+ )
84
+ )
85
+ ex = dset[0]
MindEyeV2/src/generative_models/sgm/lr_scheduler.py ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+
3
+
4
+ class LambdaWarmUpCosineScheduler:
5
+ """
6
+ note: use with a base_lr of 1.0
7
+ """
8
+
9
+ def __init__(
10
+ self,
11
+ warm_up_steps,
12
+ lr_min,
13
+ lr_max,
14
+ lr_start,
15
+ max_decay_steps,
16
+ verbosity_interval=0,
17
+ ):
18
+ self.lr_warm_up_steps = warm_up_steps
19
+ self.lr_start = lr_start
20
+ self.lr_min = lr_min
21
+ self.lr_max = lr_max
22
+ self.lr_max_decay_steps = max_decay_steps
23
+ self.last_lr = 0.0
24
+ self.verbosity_interval = verbosity_interval
25
+
26
+ def schedule(self, n, **kwargs):
27
+ if self.verbosity_interval > 0:
28
+ if n % self.verbosity_interval == 0:
29
+ print(f"current step: {n}, recent lr-multiplier: {self.last_lr}")
30
+ if n < self.lr_warm_up_steps:
31
+ lr = (
32
+ self.lr_max - self.lr_start
33
+ ) / self.lr_warm_up_steps * n + self.lr_start
34
+ self.last_lr = lr
35
+ return lr
36
+ else:
37
+ t = (n - self.lr_warm_up_steps) / (
38
+ self.lr_max_decay_steps - self.lr_warm_up_steps
39
+ )
40
+ t = min(t, 1.0)
41
+ lr = self.lr_min + 0.5 * (self.lr_max - self.lr_min) * (
42
+ 1 + np.cos(t * np.pi)
43
+ )
44
+ self.last_lr = lr
45
+ return lr
46
+
47
+ def __call__(self, n, **kwargs):
48
+ return self.schedule(n, **kwargs)
49
+
50
+
51
+ class LambdaWarmUpCosineScheduler2:
52
+ """
53
+ supports repeated iterations, configurable via lists
54
+ note: use with a base_lr of 1.0.
55
+ """
56
+
57
+ def __init__(
58
+ self, warm_up_steps, f_min, f_max, f_start, cycle_lengths, verbosity_interval=0
59
+ ):
60
+ assert (
61
+ len(warm_up_steps)
62
+ == len(f_min)
63
+ == len(f_max)
64
+ == len(f_start)
65
+ == len(cycle_lengths)
66
+ )
67
+ self.lr_warm_up_steps = warm_up_steps
68
+ self.f_start = f_start
69
+ self.f_min = f_min
70
+ self.f_max = f_max
71
+ self.cycle_lengths = cycle_lengths
72
+ self.cum_cycles = np.cumsum([0] + list(self.cycle_lengths))
73
+ self.last_f = 0.0
74
+ self.verbosity_interval = verbosity_interval
75
+
76
+ def find_in_interval(self, n):
77
+ interval = 0
78
+ for cl in self.cum_cycles[1:]:
79
+ if n <= cl:
80
+ return interval
81
+ interval += 1
82
+
83
+ def schedule(self, n, **kwargs):
84
+ cycle = self.find_in_interval(n)
85
+ n = n - self.cum_cycles[cycle]
86
+ if self.verbosity_interval > 0:
87
+ if n % self.verbosity_interval == 0:
88
+ print(
89
+ f"current step: {n}, recent lr-multiplier: {self.last_f}, "
90
+ f"current cycle {cycle}"
91
+ )
92
+ if n < self.lr_warm_up_steps[cycle]:
93
+ f = (self.f_max[cycle] - self.f_start[cycle]) / self.lr_warm_up_steps[
94
+ cycle
95
+ ] * n + self.f_start[cycle]
96
+ self.last_f = f
97
+ return f
98
+ else:
99
+ t = (n - self.lr_warm_up_steps[cycle]) / (
100
+ self.cycle_lengths[cycle] - self.lr_warm_up_steps[cycle]
101
+ )
102
+ t = min(t, 1.0)
103
+ f = self.f_min[cycle] + 0.5 * (self.f_max[cycle] - self.f_min[cycle]) * (
104
+ 1 + np.cos(t * np.pi)
105
+ )
106
+ self.last_f = f
107
+ return f
108
+
109
+ def __call__(self, n, **kwargs):
110
+ return self.schedule(n, **kwargs)
111
+
112
+
113
+ class LambdaLinearScheduler(LambdaWarmUpCosineScheduler2):
114
+ def schedule(self, n, **kwargs):
115
+ cycle = self.find_in_interval(n)
116
+ n = n - self.cum_cycles[cycle]
117
+ if self.verbosity_interval > 0:
118
+ if n % self.verbosity_interval == 0:
119
+ print(
120
+ f"current step: {n}, recent lr-multiplier: {self.last_f}, "
121
+ f"current cycle {cycle}"
122
+ )
123
+
124
+ if n < self.lr_warm_up_steps[cycle]:
125
+ f = (self.f_max[cycle] - self.f_start[cycle]) / self.lr_warm_up_steps[
126
+ cycle
127
+ ] * n + self.f_start[cycle]
128
+ self.last_f = f
129
+ return f
130
+ else:
131
+ f = self.f_min[cycle] + (self.f_max[cycle] - self.f_min[cycle]) * (
132
+ self.cycle_lengths[cycle] - n
133
+ ) / (self.cycle_lengths[cycle])
134
+ self.last_f = f
135
+ return f
MindEyeV2/src/generative_models/sgm/modules/__init__.py ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ from .encoders.modules import GeneralConditioner
2
+
3
+ UNCONDITIONAL_CONFIG = {
4
+ "target": "sgm.modules.GeneralConditioner",
5
+ "params": {"emb_models": []},
6
+ }
MindEyeV2/src/generative_models/sgm/modules/__pycache__/__init__.cpython-310.pyc ADDED
Binary file (335 Bytes). View file
 
MindEyeV2/src/generative_models/sgm/modules/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (385 Bytes). View file
 
MindEyeV2/src/generative_models/sgm/modules/__pycache__/attention.cpython-310.pyc ADDED
Binary file (18 kB). View file
 
MindEyeV2/src/generative_models/sgm/modules/__pycache__/attention.cpython-311.pyc ADDED
Binary file (34.6 kB). View file
 
MindEyeV2/src/generative_models/sgm/modules/__pycache__/ema.cpython-310.pyc ADDED
Binary file (3.23 kB). View file
 
MindEyeV2/src/generative_models/sgm/modules/__pycache__/ema.cpython-311.pyc ADDED
Binary file (5.85 kB). View file
 
MindEyeV2/src/generative_models/sgm/modules/__pycache__/video_attention.cpython-310.pyc ADDED
Binary file (6.29 kB). View file
 
MindEyeV2/src/generative_models/sgm/modules/__pycache__/video_attention.cpython-311.pyc ADDED
Binary file (11.6 kB). View file
 
MindEyeV2/src/generative_models/sgm/modules/attention.py ADDED
@@ -0,0 +1,759 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ import math
3
+ from inspect import isfunction
4
+ from typing import Any, Optional
5
+
6
+ import torch
7
+ import torch.nn.functional as F
8
+ from einops import rearrange, repeat
9
+ from packaging import version
10
+ from torch import nn
11
+ from torch.utils.checkpoint import checkpoint
12
+
13
+ logpy = logging.getLogger(__name__)
14
+
15
+ if version.parse(torch.__version__) >= version.parse("2.0.0"):
16
+ SDP_IS_AVAILABLE = True
17
+ from torch.backends.cuda import SDPBackend, sdp_kernel
18
+
19
+ BACKEND_MAP = {
20
+ SDPBackend.MATH: {
21
+ "enable_math": True,
22
+ "enable_flash": False,
23
+ "enable_mem_efficient": False,
24
+ },
25
+ SDPBackend.FLASH_ATTENTION: {
26
+ "enable_math": False,
27
+ "enable_flash": True,
28
+ "enable_mem_efficient": False,
29
+ },
30
+ SDPBackend.EFFICIENT_ATTENTION: {
31
+ "enable_math": False,
32
+ "enable_flash": False,
33
+ "enable_mem_efficient": True,
34
+ },
35
+ None: {"enable_math": True, "enable_flash": True, "enable_mem_efficient": True},
36
+ }
37
+ else:
38
+ from contextlib import nullcontext
39
+
40
+ SDP_IS_AVAILABLE = False
41
+ sdp_kernel = nullcontext
42
+ BACKEND_MAP = {}
43
+ logpy.warn(
44
+ f"No SDP backend available, likely because you are running in pytorch "
45
+ f"versions < 2.0. In fact, you are using PyTorch {torch.__version__}. "
46
+ f"You might want to consider upgrading."
47
+ )
48
+
49
+ try:
50
+ import xformers
51
+ import xformers.ops
52
+
53
+ XFORMERS_IS_AVAILABLE = True
54
+ except:
55
+ XFORMERS_IS_AVAILABLE = False
56
+ logpy.warn("no module 'xformers'. Processing without...")
57
+
58
+ # from .diffusionmodules.util import mixed_checkpoint as checkpoint
59
+
60
+
61
+ def exists(val):
62
+ return val is not None
63
+
64
+
65
+ def uniq(arr):
66
+ return {el: True for el in arr}.keys()
67
+
68
+
69
+ def default(val, d):
70
+ if exists(val):
71
+ return val
72
+ return d() if isfunction(d) else d
73
+
74
+
75
+ def max_neg_value(t):
76
+ return -torch.finfo(t.dtype).max
77
+
78
+
79
+ def init_(tensor):
80
+ dim = tensor.shape[-1]
81
+ std = 1 / math.sqrt(dim)
82
+ tensor.uniform_(-std, std)
83
+ return tensor
84
+
85
+
86
+ # feedforward
87
+ class GEGLU(nn.Module):
88
+ def __init__(self, dim_in, dim_out):
89
+ super().__init__()
90
+ self.proj = nn.Linear(dim_in, dim_out * 2)
91
+
92
+ def forward(self, x):
93
+ x, gate = self.proj(x).chunk(2, dim=-1)
94
+ return x * F.gelu(gate)
95
+
96
+
97
+ class FeedForward(nn.Module):
98
+ def __init__(self, dim, dim_out=None, mult=4, glu=False, dropout=0.0):
99
+ super().__init__()
100
+ inner_dim = int(dim * mult)
101
+ dim_out = default(dim_out, dim)
102
+ project_in = (
103
+ nn.Sequential(nn.Linear(dim, inner_dim), nn.GELU())
104
+ if not glu
105
+ else GEGLU(dim, inner_dim)
106
+ )
107
+
108
+ self.net = nn.Sequential(
109
+ project_in, nn.Dropout(dropout), nn.Linear(inner_dim, dim_out)
110
+ )
111
+
112
+ def forward(self, x):
113
+ return self.net(x)
114
+
115
+
116
+ def zero_module(module):
117
+ """
118
+ Zero out the parameters of a module and return it.
119
+ """
120
+ for p in module.parameters():
121
+ p.detach().zero_()
122
+ return module
123
+
124
+
125
+ def Normalize(in_channels):
126
+ return torch.nn.GroupNorm(
127
+ num_groups=32, num_channels=in_channels, eps=1e-6, affine=True
128
+ )
129
+
130
+
131
+ class LinearAttention(nn.Module):
132
+ def __init__(self, dim, heads=4, dim_head=32):
133
+ super().__init__()
134
+ self.heads = heads
135
+ hidden_dim = dim_head * heads
136
+ self.to_qkv = nn.Conv2d(dim, hidden_dim * 3, 1, bias=False)
137
+ self.to_out = nn.Conv2d(hidden_dim, dim, 1)
138
+
139
+ def forward(self, x):
140
+ b, c, h, w = x.shape
141
+ qkv = self.to_qkv(x)
142
+ q, k, v = rearrange(
143
+ qkv, "b (qkv heads c) h w -> qkv b heads c (h w)", heads=self.heads, qkv=3
144
+ )
145
+ k = k.softmax(dim=-1)
146
+ context = torch.einsum("bhdn,bhen->bhde", k, v)
147
+ out = torch.einsum("bhde,bhdn->bhen", context, q)
148
+ out = rearrange(
149
+ out, "b heads c (h w) -> b (heads c) h w", heads=self.heads, h=h, w=w
150
+ )
151
+ return self.to_out(out)
152
+
153
+
154
+ class SelfAttention(nn.Module):
155
+ ATTENTION_MODES = ("xformers", "torch", "math")
156
+
157
+ def __init__(
158
+ self,
159
+ dim: int,
160
+ num_heads: int = 8,
161
+ qkv_bias: bool = False,
162
+ qk_scale: Optional[float] = None,
163
+ attn_drop: float = 0.0,
164
+ proj_drop: float = 0.0,
165
+ attn_mode: str = "xformers",
166
+ ):
167
+ super().__init__()
168
+ self.num_heads = num_heads
169
+ head_dim = dim // num_heads
170
+ self.scale = qk_scale or head_dim**-0.5
171
+
172
+ self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias)
173
+ self.attn_drop = nn.Dropout(attn_drop)
174
+ self.proj = nn.Linear(dim, dim)
175
+ self.proj_drop = nn.Dropout(proj_drop)
176
+ assert attn_mode in self.ATTENTION_MODES
177
+ self.attn_mode = attn_mode
178
+
179
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
180
+ B, L, C = x.shape
181
+
182
+ qkv = self.qkv(x)
183
+ if self.attn_mode == "torch":
184
+ qkv = rearrange(
185
+ qkv, "B L (K H D) -> K B H L D", K=3, H=self.num_heads
186
+ ).float()
187
+ q, k, v = qkv[0], qkv[1], qkv[2] # B H L D
188
+ x = torch.nn.functional.scaled_dot_product_attention(q, k, v)
189
+ x = rearrange(x, "B H L D -> B L (H D)")
190
+ elif self.attn_mode == "xformers":
191
+ qkv = rearrange(qkv, "B L (K H D) -> K B L H D", K=3, H=self.num_heads)
192
+ q, k, v = qkv[0], qkv[1], qkv[2] # B L H D
193
+ x = xformers.ops.memory_efficient_attention(q, k, v)
194
+ x = rearrange(x, "B L H D -> B L (H D)", H=self.num_heads)
195
+ elif self.attn_mode == "math":
196
+ qkv = rearrange(qkv, "B L (K H D) -> K B H L D", K=3, H=self.num_heads)
197
+ q, k, v = qkv[0], qkv[1], qkv[2] # B H L D
198
+ attn = (q @ k.transpose(-2, -1)) * self.scale
199
+ attn = attn.softmax(dim=-1)
200
+ attn = self.attn_drop(attn)
201
+ x = (attn @ v).transpose(1, 2).reshape(B, L, C)
202
+ else:
203
+ raise NotImplemented
204
+
205
+ x = self.proj(x)
206
+ x = self.proj_drop(x)
207
+ return x
208
+
209
+
210
+ class SpatialSelfAttention(nn.Module):
211
+ def __init__(self, in_channels):
212
+ super().__init__()
213
+ self.in_channels = in_channels
214
+
215
+ self.norm = Normalize(in_channels)
216
+ self.q = torch.nn.Conv2d(
217
+ in_channels, in_channels, kernel_size=1, stride=1, padding=0
218
+ )
219
+ self.k = torch.nn.Conv2d(
220
+ in_channels, in_channels, kernel_size=1, stride=1, padding=0
221
+ )
222
+ self.v = torch.nn.Conv2d(
223
+ in_channels, in_channels, kernel_size=1, stride=1, padding=0
224
+ )
225
+ self.proj_out = torch.nn.Conv2d(
226
+ in_channels, in_channels, kernel_size=1, stride=1, padding=0
227
+ )
228
+
229
+ def forward(self, x):
230
+ h_ = x
231
+ h_ = self.norm(h_)
232
+ q = self.q(h_)
233
+ k = self.k(h_)
234
+ v = self.v(h_)
235
+
236
+ # compute attention
237
+ b, c, h, w = q.shape
238
+ q = rearrange(q, "b c h w -> b (h w) c")
239
+ k = rearrange(k, "b c h w -> b c (h w)")
240
+ w_ = torch.einsum("bij,bjk->bik", q, k)
241
+
242
+ w_ = w_ * (int(c) ** (-0.5))
243
+ w_ = torch.nn.functional.softmax(w_, dim=2)
244
+
245
+ # attend to values
246
+ v = rearrange(v, "b c h w -> b c (h w)")
247
+ w_ = rearrange(w_, "b i j -> b j i")
248
+ h_ = torch.einsum("bij,bjk->bik", v, w_)
249
+ h_ = rearrange(h_, "b c (h w) -> b c h w", h=h)
250
+ h_ = self.proj_out(h_)
251
+
252
+ return x + h_
253
+
254
+
255
+ class CrossAttention(nn.Module):
256
+ def __init__(
257
+ self,
258
+ query_dim,
259
+ context_dim=None,
260
+ heads=8,
261
+ dim_head=64,
262
+ dropout=0.0,
263
+ backend=None,
264
+ ):
265
+ super().__init__()
266
+ inner_dim = dim_head * heads
267
+ context_dim = default(context_dim, query_dim)
268
+
269
+ self.scale = dim_head**-0.5
270
+ self.heads = heads
271
+
272
+ self.to_q = nn.Linear(query_dim, inner_dim, bias=False)
273
+ self.to_k = nn.Linear(context_dim, inner_dim, bias=False)
274
+ self.to_v = nn.Linear(context_dim, inner_dim, bias=False)
275
+
276
+ self.to_out = nn.Sequential(
277
+ nn.Linear(inner_dim, query_dim), nn.Dropout(dropout)
278
+ )
279
+ self.backend = backend
280
+
281
+ def forward(
282
+ self,
283
+ x,
284
+ context=None,
285
+ mask=None,
286
+ additional_tokens=None,
287
+ n_times_crossframe_attn_in_self=0,
288
+ ):
289
+ h = self.heads
290
+
291
+ if additional_tokens is not None:
292
+ # get the number of masked tokens at the beginning of the output sequence
293
+ n_tokens_to_mask = additional_tokens.shape[1]
294
+ # add additional token
295
+ x = torch.cat([additional_tokens, x], dim=1)
296
+
297
+ q = self.to_q(x)
298
+ context = default(context, x)
299
+ k = self.to_k(context)
300
+ v = self.to_v(context)
301
+
302
+ if n_times_crossframe_attn_in_self:
303
+ # reprogramming cross-frame attention as in https://arxiv.org/abs/2303.13439
304
+ assert x.shape[0] % n_times_crossframe_attn_in_self == 0
305
+ n_cp = x.shape[0] // n_times_crossframe_attn_in_self
306
+ k = repeat(
307
+ k[::n_times_crossframe_attn_in_self], "b ... -> (b n) ...", n=n_cp
308
+ )
309
+ v = repeat(
310
+ v[::n_times_crossframe_attn_in_self], "b ... -> (b n) ...", n=n_cp
311
+ )
312
+
313
+ q, k, v = map(lambda t: rearrange(t, "b n (h d) -> b h n d", h=h), (q, k, v))
314
+
315
+ ## old
316
+ """
317
+ sim = einsum('b i d, b j d -> b i j', q, k) * self.scale
318
+ del q, k
319
+
320
+ if exists(mask):
321
+ mask = rearrange(mask, 'b ... -> b (...)')
322
+ max_neg_value = -torch.finfo(sim.dtype).max
323
+ mask = repeat(mask, 'b j -> (b h) () j', h=h)
324
+ sim.masked_fill_(~mask, max_neg_value)
325
+
326
+ # attention, what we cannot get enough of
327
+ sim = sim.softmax(dim=-1)
328
+
329
+ out = einsum('b i j, b j d -> b i d', sim, v)
330
+ """
331
+ ## new
332
+ with sdp_kernel(**BACKEND_MAP[self.backend]):
333
+ # print("dispatching into backend", self.backend, "q/k/v shape: ", q.shape, k.shape, v.shape)
334
+ out = F.scaled_dot_product_attention(
335
+ q, k, v, attn_mask=mask
336
+ ) # scale is dim_head ** -0.5 per default
337
+
338
+ del q, k, v
339
+ out = rearrange(out, "b h n d -> b n (h d)", h=h)
340
+
341
+ if additional_tokens is not None:
342
+ # remove additional token
343
+ out = out[:, n_tokens_to_mask:]
344
+ return self.to_out(out)
345
+
346
+
347
+ class MemoryEfficientCrossAttention(nn.Module):
348
+ # https://github.com/MatthieuTPHR/diffusers/blob/d80b531ff8060ec1ea982b65a1b8df70f73aa67c/src/diffusers/models/attention.py#L223
349
+ def __init__(
350
+ self, query_dim, context_dim=None, heads=8, dim_head=64, dropout=0.0, **kwargs
351
+ ):
352
+ super().__init__()
353
+ logpy.debug(
354
+ f"Setting up {self.__class__.__name__}. Query dim is {query_dim}, "
355
+ f"context_dim is {context_dim} and using {heads} heads with a "
356
+ f"dimension of {dim_head}."
357
+ )
358
+ inner_dim = dim_head * heads
359
+ context_dim = default(context_dim, query_dim)
360
+
361
+ self.heads = heads
362
+ self.dim_head = dim_head
363
+
364
+ self.to_q = nn.Linear(query_dim, inner_dim, bias=False)
365
+ self.to_k = nn.Linear(context_dim, inner_dim, bias=False)
366
+ self.to_v = nn.Linear(context_dim, inner_dim, bias=False)
367
+
368
+ self.to_out = nn.Sequential(
369
+ nn.Linear(inner_dim, query_dim), nn.Dropout(dropout)
370
+ )
371
+ self.attention_op: Optional[Any] = None
372
+
373
+ def forward(
374
+ self,
375
+ x,
376
+ context=None,
377
+ mask=None,
378
+ additional_tokens=None,
379
+ n_times_crossframe_attn_in_self=0,
380
+ ):
381
+ if additional_tokens is not None:
382
+ # get the number of masked tokens at the beginning of the output sequence
383
+ n_tokens_to_mask = additional_tokens.shape[1]
384
+ # add additional token
385
+ x = torch.cat([additional_tokens, x], dim=1)
386
+ q = self.to_q(x)
387
+ context = default(context, x)
388
+ k = self.to_k(context)
389
+ v = self.to_v(context)
390
+
391
+ if n_times_crossframe_attn_in_self:
392
+ # reprogramming cross-frame attention as in https://arxiv.org/abs/2303.13439
393
+ assert x.shape[0] % n_times_crossframe_attn_in_self == 0
394
+ # n_cp = x.shape[0]//n_times_crossframe_attn_in_self
395
+ k = repeat(
396
+ k[::n_times_crossframe_attn_in_self],
397
+ "b ... -> (b n) ...",
398
+ n=n_times_crossframe_attn_in_self,
399
+ )
400
+ v = repeat(
401
+ v[::n_times_crossframe_attn_in_self],
402
+ "b ... -> (b n) ...",
403
+ n=n_times_crossframe_attn_in_self,
404
+ )
405
+
406
+ b, _, _ = q.shape
407
+ q, k, v = map(
408
+ lambda t: t.unsqueeze(3)
409
+ .reshape(b, t.shape[1], self.heads, self.dim_head)
410
+ .permute(0, 2, 1, 3)
411
+ .reshape(b * self.heads, t.shape[1], self.dim_head)
412
+ .contiguous(),
413
+ (q, k, v),
414
+ )
415
+
416
+ # actually compute the attention, what we cannot get enough of
417
+ if version.parse(xformers.__version__) >= version.parse("0.0.21"):
418
+ # NOTE: workaround for
419
+ # https://github.com/facebookresearch/xformers/issues/845
420
+ max_bs = 32768
421
+ N = q.shape[0]
422
+ n_batches = math.ceil(N / max_bs)
423
+ out = list()
424
+ for i_batch in range(n_batches):
425
+ batch = slice(i_batch * max_bs, (i_batch + 1) * max_bs)
426
+ out.append(
427
+ xformers.ops.memory_efficient_attention(
428
+ q[batch],
429
+ k[batch],
430
+ v[batch],
431
+ attn_bias=None,
432
+ op=self.attention_op,
433
+ )
434
+ )
435
+ out = torch.cat(out, 0)
436
+ else:
437
+ out = xformers.ops.memory_efficient_attention(
438
+ q, k, v, attn_bias=None, op=self.attention_op
439
+ )
440
+
441
+ # TODO: Use this directly in the attention operation, as a bias
442
+ if exists(mask):
443
+ raise NotImplementedError
444
+ out = (
445
+ out.unsqueeze(0)
446
+ .reshape(b, self.heads, out.shape[1], self.dim_head)
447
+ .permute(0, 2, 1, 3)
448
+ .reshape(b, out.shape[1], self.heads * self.dim_head)
449
+ )
450
+ if additional_tokens is not None:
451
+ # remove additional token
452
+ out = out[:, n_tokens_to_mask:]
453
+ return self.to_out(out)
454
+
455
+
456
+ class BasicTransformerBlock(nn.Module):
457
+ ATTENTION_MODES = {
458
+ "softmax": CrossAttention, # vanilla attention
459
+ "softmax-xformers": MemoryEfficientCrossAttention, # ampere
460
+ }
461
+
462
+ def __init__(
463
+ self,
464
+ dim,
465
+ n_heads,
466
+ d_head,
467
+ dropout=0.0,
468
+ context_dim=None,
469
+ gated_ff=True,
470
+ checkpoint=True,
471
+ disable_self_attn=False,
472
+ attn_mode="softmax",
473
+ sdp_backend=None,
474
+ ):
475
+ super().__init__()
476
+ assert attn_mode in self.ATTENTION_MODES
477
+ if attn_mode != "softmax" and not XFORMERS_IS_AVAILABLE:
478
+ logpy.warn(
479
+ f"Attention mode '{attn_mode}' is not available. Falling "
480
+ f"back to native attention. This is not a problem in "
481
+ f"Pytorch >= 2.0. FYI, you are running with PyTorch "
482
+ f"version {torch.__version__}."
483
+ )
484
+ attn_mode = "softmax"
485
+ elif attn_mode == "softmax" and not SDP_IS_AVAILABLE:
486
+ logpy.warn(
487
+ "We do not support vanilla attention anymore, as it is too "
488
+ "expensive. Sorry."
489
+ )
490
+ if not XFORMERS_IS_AVAILABLE:
491
+ assert (
492
+ False
493
+ ), "Please install xformers via e.g. 'pip install xformers==0.0.16'"
494
+ else:
495
+ logpy.info("Falling back to xformers efficient attention.")
496
+ attn_mode = "softmax-xformers"
497
+ attn_cls = self.ATTENTION_MODES[attn_mode]
498
+ if version.parse(torch.__version__) >= version.parse("2.0.0"):
499
+ assert sdp_backend is None or isinstance(sdp_backend, SDPBackend)
500
+ else:
501
+ assert sdp_backend is None
502
+ self.disable_self_attn = disable_self_attn
503
+ self.attn1 = attn_cls(
504
+ query_dim=dim,
505
+ heads=n_heads,
506
+ dim_head=d_head,
507
+ dropout=dropout,
508
+ context_dim=context_dim if self.disable_self_attn else None,
509
+ backend=sdp_backend,
510
+ ) # is a self-attention if not self.disable_self_attn
511
+ self.ff = FeedForward(dim, dropout=dropout, glu=gated_ff)
512
+ self.attn2 = attn_cls(
513
+ query_dim=dim,
514
+ context_dim=context_dim,
515
+ heads=n_heads,
516
+ dim_head=d_head,
517
+ dropout=dropout,
518
+ backend=sdp_backend,
519
+ ) # is self-attn if context is none
520
+ self.norm1 = nn.LayerNorm(dim)
521
+ self.norm2 = nn.LayerNorm(dim)
522
+ self.norm3 = nn.LayerNorm(dim)
523
+ self.checkpoint = checkpoint
524
+ if self.checkpoint:
525
+ logpy.debug(f"{self.__class__.__name__} is using checkpointing")
526
+
527
+ def forward(
528
+ self, x, context=None, additional_tokens=None, n_times_crossframe_attn_in_self=0
529
+ ):
530
+ kwargs = {"x": x}
531
+
532
+ if context is not None:
533
+ kwargs.update({"context": context})
534
+
535
+ if additional_tokens is not None:
536
+ kwargs.update({"additional_tokens": additional_tokens})
537
+
538
+ if n_times_crossframe_attn_in_self:
539
+ kwargs.update(
540
+ {"n_times_crossframe_attn_in_self": n_times_crossframe_attn_in_self}
541
+ )
542
+
543
+ # return mixed_checkpoint(self._forward, kwargs, self.parameters(), self.checkpoint)
544
+ if self.checkpoint:
545
+ # inputs = {"x": x, "context": context}
546
+ return checkpoint(self._forward, x, context)
547
+ # return checkpoint(self._forward, inputs, self.parameters(), self.checkpoint)
548
+ else:
549
+ return self._forward(**kwargs)
550
+
551
+ def _forward(
552
+ self, x, context=None, additional_tokens=None, n_times_crossframe_attn_in_self=0
553
+ ):
554
+ x = (
555
+ self.attn1(
556
+ self.norm1(x),
557
+ context=context if self.disable_self_attn else None,
558
+ additional_tokens=additional_tokens,
559
+ n_times_crossframe_attn_in_self=n_times_crossframe_attn_in_self
560
+ if not self.disable_self_attn
561
+ else 0,
562
+ )
563
+ + x
564
+ )
565
+ x = (
566
+ self.attn2(
567
+ self.norm2(x), context=context, additional_tokens=additional_tokens
568
+ )
569
+ + x
570
+ )
571
+ x = self.ff(self.norm3(x)) + x
572
+ return x
573
+
574
+
575
+ class BasicTransformerSingleLayerBlock(nn.Module):
576
+ ATTENTION_MODES = {
577
+ "softmax": CrossAttention, # vanilla attention
578
+ "softmax-xformers": MemoryEfficientCrossAttention # on the A100s not quite as fast as the above version
579
+ # (todo might depend on head_dim, check, falls back to semi-optimized kernels for dim!=[16,32,64,128])
580
+ }
581
+
582
+ def __init__(
583
+ self,
584
+ dim,
585
+ n_heads,
586
+ d_head,
587
+ dropout=0.0,
588
+ context_dim=None,
589
+ gated_ff=True,
590
+ checkpoint=True,
591
+ attn_mode="softmax",
592
+ ):
593
+ super().__init__()
594
+ assert attn_mode in self.ATTENTION_MODES
595
+ attn_cls = self.ATTENTION_MODES[attn_mode]
596
+ self.attn1 = attn_cls(
597
+ query_dim=dim,
598
+ heads=n_heads,
599
+ dim_head=d_head,
600
+ dropout=dropout,
601
+ context_dim=context_dim,
602
+ )
603
+ self.ff = FeedForward(dim, dropout=dropout, glu=gated_ff)
604
+ self.norm1 = nn.LayerNorm(dim)
605
+ self.norm2 = nn.LayerNorm(dim)
606
+ self.checkpoint = checkpoint
607
+
608
+ def forward(self, x, context=None):
609
+ # inputs = {"x": x, "context": context}
610
+ # return checkpoint(self._forward, inputs, self.parameters(), self.checkpoint)
611
+ return checkpoint(self._forward, x, context)
612
+
613
+ def _forward(self, x, context=None):
614
+ x = self.attn1(self.norm1(x), context=context) + x
615
+ x = self.ff(self.norm2(x)) + x
616
+ return x
617
+
618
+
619
+ class SpatialTransformer(nn.Module):
620
+ """
621
+ Transformer block for image-like data.
622
+ First, project the input (aka embedding)
623
+ and reshape to b, t, d.
624
+ Then apply standard transformer action.
625
+ Finally, reshape to image
626
+ NEW: use_linear for more efficiency instead of the 1x1 convs
627
+ """
628
+
629
+ def __init__(
630
+ self,
631
+ in_channels,
632
+ n_heads,
633
+ d_head,
634
+ depth=1,
635
+ dropout=0.0,
636
+ context_dim=None,
637
+ disable_self_attn=False,
638
+ use_linear=False,
639
+ attn_type="softmax",
640
+ use_checkpoint=True,
641
+ # sdp_backend=SDPBackend.FLASH_ATTENTION
642
+ sdp_backend=None,
643
+ ):
644
+ super().__init__()
645
+ logpy.debug(
646
+ f"constructing {self.__class__.__name__} of depth {depth} w/ "
647
+ f"{in_channels} channels and {n_heads} heads."
648
+ )
649
+
650
+ if exists(context_dim) and not isinstance(context_dim, list):
651
+ context_dim = [context_dim]
652
+ if exists(context_dim) and isinstance(context_dim, list):
653
+ if depth != len(context_dim):
654
+ logpy.warn(
655
+ f"{self.__class__.__name__}: Found context dims "
656
+ f"{context_dim} of depth {len(context_dim)}, which does not "
657
+ f"match the specified 'depth' of {depth}. Setting context_dim "
658
+ f"to {depth * [context_dim[0]]} now."
659
+ )
660
+ # depth does not match context dims.
661
+ assert all(
662
+ map(lambda x: x == context_dim[0], context_dim)
663
+ ), "need homogenous context_dim to match depth automatically"
664
+ context_dim = depth * [context_dim[0]]
665
+ elif context_dim is None:
666
+ context_dim = [None] * depth
667
+ self.in_channels = in_channels
668
+ inner_dim = n_heads * d_head
669
+ self.norm = Normalize(in_channels)
670
+ if not use_linear:
671
+ self.proj_in = nn.Conv2d(
672
+ in_channels, inner_dim, kernel_size=1, stride=1, padding=0
673
+ )
674
+ else:
675
+ self.proj_in = nn.Linear(in_channels, inner_dim)
676
+
677
+ self.transformer_blocks = nn.ModuleList(
678
+ [
679
+ BasicTransformerBlock(
680
+ inner_dim,
681
+ n_heads,
682
+ d_head,
683
+ dropout=dropout,
684
+ context_dim=context_dim[d],
685
+ disable_self_attn=disable_self_attn,
686
+ attn_mode=attn_type,
687
+ checkpoint=use_checkpoint,
688
+ sdp_backend=sdp_backend,
689
+ )
690
+ for d in range(depth)
691
+ ]
692
+ )
693
+ if not use_linear:
694
+ self.proj_out = zero_module(
695
+ nn.Conv2d(inner_dim, in_channels, kernel_size=1, stride=1, padding=0)
696
+ )
697
+ else:
698
+ # self.proj_out = zero_module(nn.Linear(in_channels, inner_dim))
699
+ self.proj_out = zero_module(nn.Linear(inner_dim, in_channels))
700
+ self.use_linear = use_linear
701
+
702
+ def forward(self, x, context=None):
703
+ # note: if no context is given, cross-attention defaults to self-attention
704
+ if not isinstance(context, list):
705
+ context = [context]
706
+ b, c, h, w = x.shape
707
+ x_in = x
708
+ x = self.norm(x)
709
+ if not self.use_linear:
710
+ x = self.proj_in(x)
711
+ x = rearrange(x, "b c h w -> b (h w) c").contiguous()
712
+ if self.use_linear:
713
+ x = self.proj_in(x)
714
+ for i, block in enumerate(self.transformer_blocks):
715
+ if i > 0 and len(context) == 1:
716
+ i = 0 # use same context for each block
717
+ x = block(x, context=context[i])
718
+ if self.use_linear:
719
+ x = self.proj_out(x)
720
+ x = rearrange(x, "b (h w) c -> b c h w", h=h, w=w).contiguous()
721
+ if not self.use_linear:
722
+ x = self.proj_out(x)
723
+ return x + x_in
724
+
725
+
726
+ class SimpleTransformer(nn.Module):
727
+ def __init__(
728
+ self,
729
+ dim: int,
730
+ depth: int,
731
+ heads: int,
732
+ dim_head: int,
733
+ context_dim: Optional[int] = None,
734
+ dropout: float = 0.0,
735
+ checkpoint: bool = True,
736
+ ):
737
+ super().__init__()
738
+ self.layers = nn.ModuleList([])
739
+ for _ in range(depth):
740
+ self.layers.append(
741
+ BasicTransformerBlock(
742
+ dim,
743
+ heads,
744
+ dim_head,
745
+ dropout=dropout,
746
+ context_dim=context_dim,
747
+ attn_mode="softmax-xformers",
748
+ checkpoint=checkpoint,
749
+ )
750
+ )
751
+
752
+ def forward(
753
+ self,
754
+ x: torch.Tensor,
755
+ context: Optional[torch.Tensor] = None,
756
+ ) -> torch.Tensor:
757
+ for layer in self.layers:
758
+ x = layer(x, context)
759
+ return x
MindEyeV2/src/generative_models/sgm/modules/autoencoding/__init__.py ADDED
File without changes
MindEyeV2/src/generative_models/sgm/modules/autoencoding/__pycache__/__init__.cpython-310.pyc ADDED
Binary file (185 Bytes). View file
 
MindEyeV2/src/generative_models/sgm/modules/autoencoding/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (201 Bytes). View file
 
MindEyeV2/src/generative_models/sgm/modules/autoencoding/__pycache__/temporal_ae.cpython-310.pyc ADDED
Binary file (8.57 kB). View file
 
MindEyeV2/src/generative_models/sgm/modules/autoencoding/__pycache__/temporal_ae.cpython-311.pyc ADDED
Binary file (17 kB). View file
 
MindEyeV2/src/generative_models/sgm/modules/autoencoding/losses/__init__.py ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ __all__ = [
2
+ "GeneralLPIPSWithDiscriminator",
3
+ "LatentLPIPS",
4
+ ]
5
+
6
+ from .discriminator_loss import GeneralLPIPSWithDiscriminator
7
+ from .lpips import LatentLPIPS
MindEyeV2/src/generative_models/sgm/modules/autoencoding/losses/discriminator_loss.py ADDED
@@ -0,0 +1,306 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Dict, Iterator, List, Optional, Tuple, Union
2
+
3
+ import numpy as np
4
+ import torch
5
+ import torch.nn as nn
6
+ import torchvision
7
+ from einops import rearrange
8
+ from matplotlib import colormaps
9
+ from matplotlib import pyplot as plt
10
+
11
+ from ....util import default, instantiate_from_config
12
+ from ..lpips.loss.lpips import LPIPS
13
+ from ..lpips.model.model import weights_init
14
+ from ..lpips.vqperceptual import hinge_d_loss, vanilla_d_loss
15
+
16
+
17
+ class GeneralLPIPSWithDiscriminator(nn.Module):
18
+ def __init__(
19
+ self,
20
+ disc_start: int,
21
+ logvar_init: float = 0.0,
22
+ disc_num_layers: int = 3,
23
+ disc_in_channels: int = 3,
24
+ disc_factor: float = 1.0,
25
+ disc_weight: float = 1.0,
26
+ perceptual_weight: float = 1.0,
27
+ disc_loss: str = "hinge",
28
+ scale_input_to_tgt_size: bool = False,
29
+ dims: int = 2,
30
+ learn_logvar: bool = False,
31
+ regularization_weights: Union[None, Dict[str, float]] = None,
32
+ additional_log_keys: Optional[List[str]] = None,
33
+ discriminator_config: Optional[Dict] = None,
34
+ ):
35
+ super().__init__()
36
+ self.dims = dims
37
+ if self.dims > 2:
38
+ print(
39
+ f"running with dims={dims}. This means that for perceptual loss "
40
+ f"calculation, the LPIPS loss will be applied to each frame "
41
+ f"independently."
42
+ )
43
+ self.scale_input_to_tgt_size = scale_input_to_tgt_size
44
+ assert disc_loss in ["hinge", "vanilla"]
45
+ self.perceptual_loss = LPIPS().eval()
46
+ self.perceptual_weight = perceptual_weight
47
+ # output log variance
48
+ self.logvar = nn.Parameter(
49
+ torch.full((), logvar_init), requires_grad=learn_logvar
50
+ )
51
+ self.learn_logvar = learn_logvar
52
+
53
+ discriminator_config = default(
54
+ discriminator_config,
55
+ {
56
+ "target": "sgm.modules.autoencoding.lpips.model.model.NLayerDiscriminator",
57
+ "params": {
58
+ "input_nc": disc_in_channels,
59
+ "n_layers": disc_num_layers,
60
+ "use_actnorm": False,
61
+ },
62
+ },
63
+ )
64
+
65
+ self.discriminator = instantiate_from_config(discriminator_config).apply(
66
+ weights_init
67
+ )
68
+ self.discriminator_iter_start = disc_start
69
+ self.disc_loss = hinge_d_loss if disc_loss == "hinge" else vanilla_d_loss
70
+ self.disc_factor = disc_factor
71
+ self.discriminator_weight = disc_weight
72
+ self.regularization_weights = default(regularization_weights, {})
73
+
74
+ self.forward_keys = [
75
+ "optimizer_idx",
76
+ "global_step",
77
+ "last_layer",
78
+ "split",
79
+ "regularization_log",
80
+ ]
81
+
82
+ self.additional_log_keys = set(default(additional_log_keys, []))
83
+ self.additional_log_keys.update(set(self.regularization_weights.keys()))
84
+
85
+ def get_trainable_parameters(self) -> Iterator[nn.Parameter]:
86
+ return self.discriminator.parameters()
87
+
88
+ def get_trainable_autoencoder_parameters(self) -> Iterator[nn.Parameter]:
89
+ if self.learn_logvar:
90
+ yield self.logvar
91
+ yield from ()
92
+
93
+ @torch.no_grad()
94
+ def log_images(
95
+ self, inputs: torch.Tensor, reconstructions: torch.Tensor
96
+ ) -> Dict[str, torch.Tensor]:
97
+ # calc logits of real/fake
98
+ logits_real = self.discriminator(inputs.contiguous().detach())
99
+ if len(logits_real.shape) < 4:
100
+ # Non patch-discriminator
101
+ return dict()
102
+ logits_fake = self.discriminator(reconstructions.contiguous().detach())
103
+ # -> (b, 1, h, w)
104
+
105
+ # parameters for colormapping
106
+ high = max(logits_fake.abs().max(), logits_real.abs().max()).item()
107
+ cmap = colormaps["PiYG"] # diverging colormap
108
+
109
+ def to_colormap(logits: torch.Tensor) -> torch.Tensor:
110
+ """(b, 1, ...) -> (b, 3, ...)"""
111
+ logits = (logits + high) / (2 * high)
112
+ logits_np = cmap(logits.cpu().numpy())[..., :3] # truncate alpha channel
113
+ # -> (b, 1, ..., 3)
114
+ logits = torch.from_numpy(logits_np).to(logits.device)
115
+ return rearrange(logits, "b 1 ... c -> b c ...")
116
+
117
+ logits_real = torch.nn.functional.interpolate(
118
+ logits_real,
119
+ size=inputs.shape[-2:],
120
+ mode="nearest",
121
+ antialias=False,
122
+ )
123
+ logits_fake = torch.nn.functional.interpolate(
124
+ logits_fake,
125
+ size=reconstructions.shape[-2:],
126
+ mode="nearest",
127
+ antialias=False,
128
+ )
129
+
130
+ # alpha value of logits for overlay
131
+ alpha_real = torch.abs(logits_real) / high
132
+ alpha_fake = torch.abs(logits_fake) / high
133
+ # -> (b, 1, h, w) in range [0, 0.5]
134
+ # alpha value of lines don't really matter, since the values are the same
135
+ # for both images and logits anyway
136
+ grid_alpha_real = torchvision.utils.make_grid(alpha_real, nrow=4)
137
+ grid_alpha_fake = torchvision.utils.make_grid(alpha_fake, nrow=4)
138
+ grid_alpha = 0.8 * torch.cat((grid_alpha_real, grid_alpha_fake), dim=1)
139
+ # -> (1, h, w)
140
+ # blend logits and images together
141
+
142
+ # prepare logits for plotting
143
+ logits_real = to_colormap(logits_real)
144
+ logits_fake = to_colormap(logits_fake)
145
+ # resize logits
146
+ # -> (b, 3, h, w)
147
+
148
+ # make some grids
149
+ # add all logits to one plot
150
+ logits_real = torchvision.utils.make_grid(logits_real, nrow=4)
151
+ logits_fake = torchvision.utils.make_grid(logits_fake, nrow=4)
152
+ # I just love how torchvision calls the number of columns `nrow`
153
+ grid_logits = torch.cat((logits_real, logits_fake), dim=1)
154
+ # -> (3, h, w)
155
+
156
+ grid_images_real = torchvision.utils.make_grid(0.5 * inputs + 0.5, nrow=4)
157
+ grid_images_fake = torchvision.utils.make_grid(
158
+ 0.5 * reconstructions + 0.5, nrow=4
159
+ )
160
+ grid_images = torch.cat((grid_images_real, grid_images_fake), dim=1)
161
+ # -> (3, h, w) in range [0, 1]
162
+
163
+ grid_blend = grid_alpha * grid_logits + (1 - grid_alpha) * grid_images
164
+
165
+ # Create labeled colorbar
166
+ dpi = 100
167
+ height = 128 / dpi
168
+ width = grid_logits.shape[2] / dpi
169
+ fig, ax = plt.subplots(figsize=(width, height), dpi=dpi)
170
+ img = ax.imshow(np.array([[-high, high]]), cmap=cmap)
171
+ plt.colorbar(
172
+ img,
173
+ cax=ax,
174
+ orientation="horizontal",
175
+ fraction=0.9,
176
+ aspect=width / height,
177
+ pad=0.0,
178
+ )
179
+ img.set_visible(False)
180
+ fig.tight_layout()
181
+ fig.canvas.draw()
182
+ # manually convert figure to numpy
183
+ cbar_np = np.frombuffer(fig.canvas.tostring_rgb(), dtype=np.uint8)
184
+ cbar_np = cbar_np.reshape(fig.canvas.get_width_height()[::-1] + (3,))
185
+ cbar = torch.from_numpy(cbar_np.copy()).to(grid_logits.dtype) / 255.0
186
+ cbar = rearrange(cbar, "h w c -> c h w").to(grid_logits.device)
187
+
188
+ # Add colorbar to plot
189
+ annotated_grid = torch.cat((grid_logits, cbar), dim=1)
190
+ blended_grid = torch.cat((grid_blend, cbar), dim=1)
191
+ return {
192
+ "vis_logits": 2 * annotated_grid[None, ...] - 1,
193
+ "vis_logits_blended": 2 * blended_grid[None, ...] - 1,
194
+ }
195
+
196
+ def calculate_adaptive_weight(
197
+ self, nll_loss: torch.Tensor, g_loss: torch.Tensor, last_layer: torch.Tensor
198
+ ) -> torch.Tensor:
199
+ nll_grads = torch.autograd.grad(nll_loss, last_layer, retain_graph=True)[0]
200
+ g_grads = torch.autograd.grad(g_loss, last_layer, retain_graph=True)[0]
201
+
202
+ d_weight = torch.norm(nll_grads) / (torch.norm(g_grads) + 1e-4)
203
+ d_weight = torch.clamp(d_weight, 0.0, 1e4).detach()
204
+ d_weight = d_weight * self.discriminator_weight
205
+ return d_weight
206
+
207
+ def forward(
208
+ self,
209
+ inputs: torch.Tensor,
210
+ reconstructions: torch.Tensor,
211
+ *, # added because I changed the order here
212
+ regularization_log: Dict[str, torch.Tensor],
213
+ optimizer_idx: int,
214
+ global_step: int,
215
+ last_layer: torch.Tensor,
216
+ split: str = "train",
217
+ weights: Union[None, float, torch.Tensor] = None,
218
+ ) -> Tuple[torch.Tensor, dict]:
219
+ if self.scale_input_to_tgt_size:
220
+ inputs = torch.nn.functional.interpolate(
221
+ inputs, reconstructions.shape[2:], mode="bicubic", antialias=True
222
+ )
223
+
224
+ if self.dims > 2:
225
+ inputs, reconstructions = map(
226
+ lambda x: rearrange(x, "b c t h w -> (b t) c h w"),
227
+ (inputs, reconstructions),
228
+ )
229
+
230
+ rec_loss = torch.abs(inputs.contiguous() - reconstructions.contiguous())
231
+ if self.perceptual_weight > 0:
232
+ p_loss = self.perceptual_loss(
233
+ inputs.contiguous(), reconstructions.contiguous()
234
+ )
235
+ rec_loss = rec_loss + self.perceptual_weight * p_loss
236
+
237
+ nll_loss, weighted_nll_loss = self.get_nll_loss(rec_loss, weights)
238
+
239
+ # now the GAN part
240
+ if optimizer_idx == 0:
241
+ # generator update
242
+ if global_step >= self.discriminator_iter_start or not self.training:
243
+ logits_fake = self.discriminator(reconstructions.contiguous())
244
+ g_loss = -torch.mean(logits_fake)
245
+ if self.training:
246
+ d_weight = self.calculate_adaptive_weight(
247
+ nll_loss, g_loss, last_layer=last_layer
248
+ )
249
+ else:
250
+ d_weight = torch.tensor(1.0)
251
+ else:
252
+ d_weight = torch.tensor(0.0)
253
+ g_loss = torch.tensor(0.0, requires_grad=True)
254
+
255
+ loss = weighted_nll_loss + d_weight * self.disc_factor * g_loss
256
+ log = dict()
257
+ for k in regularization_log:
258
+ if k in self.regularization_weights:
259
+ loss = loss + self.regularization_weights[k] * regularization_log[k]
260
+ if k in self.additional_log_keys:
261
+ log[f"{split}/{k}"] = regularization_log[k].detach().float().mean()
262
+
263
+ log.update(
264
+ {
265
+ f"{split}/loss/total": loss.clone().detach().mean(),
266
+ f"{split}/loss/nll": nll_loss.detach().mean(),
267
+ f"{split}/loss/rec": rec_loss.detach().mean(),
268
+ f"{split}/loss/g": g_loss.detach().mean(),
269
+ f"{split}/scalars/logvar": self.logvar.detach(),
270
+ f"{split}/scalars/d_weight": d_weight.detach(),
271
+ }
272
+ )
273
+
274
+ return loss, log
275
+ elif optimizer_idx == 1:
276
+ # second pass for discriminator update
277
+ logits_real = self.discriminator(inputs.contiguous().detach())
278
+ logits_fake = self.discriminator(reconstructions.contiguous().detach())
279
+
280
+ if global_step >= self.discriminator_iter_start or not self.training:
281
+ d_loss = self.disc_factor * self.disc_loss(logits_real, logits_fake)
282
+ else:
283
+ d_loss = torch.tensor(0.0, requires_grad=True)
284
+
285
+ log = {
286
+ f"{split}/loss/disc": d_loss.clone().detach().mean(),
287
+ f"{split}/logits/real": logits_real.detach().mean(),
288
+ f"{split}/logits/fake": logits_fake.detach().mean(),
289
+ }
290
+ return d_loss, log
291
+ else:
292
+ raise NotImplementedError(f"Unknown optimizer_idx {optimizer_idx}")
293
+
294
+ def get_nll_loss(
295
+ self,
296
+ rec_loss: torch.Tensor,
297
+ weights: Optional[Union[float, torch.Tensor]] = None,
298
+ ) -> Tuple[torch.Tensor, torch.Tensor]:
299
+ nll_loss = rec_loss / torch.exp(self.logvar) + self.logvar
300
+ weighted_nll_loss = nll_loss
301
+ if weights is not None:
302
+ weighted_nll_loss = weights * nll_loss
303
+ weighted_nll_loss = torch.sum(weighted_nll_loss) / weighted_nll_loss.shape[0]
304
+ nll_loss = torch.sum(nll_loss) / nll_loss.shape[0]
305
+
306
+ return nll_loss, weighted_nll_loss
MindEyeV2/src/generative_models/sgm/modules/autoencoding/losses/lpips.py ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+
4
+ from ....util import default, instantiate_from_config
5
+ from ..lpips.loss.lpips import LPIPS
6
+
7
+
8
+ class LatentLPIPS(nn.Module):
9
+ def __init__(
10
+ self,
11
+ decoder_config,
12
+ perceptual_weight=1.0,
13
+ latent_weight=1.0,
14
+ scale_input_to_tgt_size=False,
15
+ scale_tgt_to_input_size=False,
16
+ perceptual_weight_on_inputs=0.0,
17
+ ):
18
+ super().__init__()
19
+ self.scale_input_to_tgt_size = scale_input_to_tgt_size
20
+ self.scale_tgt_to_input_size = scale_tgt_to_input_size
21
+ self.init_decoder(decoder_config)
22
+ self.perceptual_loss = LPIPS().eval()
23
+ self.perceptual_weight = perceptual_weight
24
+ self.latent_weight = latent_weight
25
+ self.perceptual_weight_on_inputs = perceptual_weight_on_inputs
26
+
27
+ def init_decoder(self, config):
28
+ self.decoder = instantiate_from_config(config)
29
+ if hasattr(self.decoder, "encoder"):
30
+ del self.decoder.encoder
31
+
32
+ def forward(self, latent_inputs, latent_predictions, image_inputs, split="train"):
33
+ log = dict()
34
+ loss = (latent_inputs - latent_predictions) ** 2
35
+ log[f"{split}/latent_l2_loss"] = loss.mean().detach()
36
+ image_reconstructions = None
37
+ if self.perceptual_weight > 0.0:
38
+ image_reconstructions = self.decoder.decode(latent_predictions)
39
+ image_targets = self.decoder.decode(latent_inputs)
40
+ perceptual_loss = self.perceptual_loss(
41
+ image_targets.contiguous(), image_reconstructions.contiguous()
42
+ )
43
+ loss = (
44
+ self.latent_weight * loss.mean()
45
+ + self.perceptual_weight * perceptual_loss.mean()
46
+ )
47
+ log[f"{split}/perceptual_loss"] = perceptual_loss.mean().detach()
48
+
49
+ if self.perceptual_weight_on_inputs > 0.0:
50
+ image_reconstructions = default(
51
+ image_reconstructions, self.decoder.decode(latent_predictions)
52
+ )
53
+ if self.scale_input_to_tgt_size:
54
+ image_inputs = torch.nn.functional.interpolate(
55
+ image_inputs,
56
+ image_reconstructions.shape[2:],
57
+ mode="bicubic",
58
+ antialias=True,
59
+ )
60
+ elif self.scale_tgt_to_input_size:
61
+ image_reconstructions = torch.nn.functional.interpolate(
62
+ image_reconstructions,
63
+ image_inputs.shape[2:],
64
+ mode="bicubic",
65
+ antialias=True,
66
+ )
67
+
68
+ perceptual_loss2 = self.perceptual_loss(
69
+ image_inputs.contiguous(), image_reconstructions.contiguous()
70
+ )
71
+ loss = loss + self.perceptual_weight_on_inputs * perceptual_loss2.mean()
72
+ log[f"{split}/perceptual_loss_on_inputs"] = perceptual_loss2.mean().detach()
73
+ return loss, log
MindEyeV2/src/generative_models/sgm/modules/autoencoding/lpips/__init__.py ADDED
File without changes
MindEyeV2/src/generative_models/sgm/modules/autoencoding/lpips/loss/.gitignore ADDED
@@ -0,0 +1 @@
 
 
1
+ vgg.pth
MindEyeV2/src/generative_models/sgm/modules/autoencoding/lpips/loss/LICENSE ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Copyright (c) 2018, Richard Zhang, Phillip Isola, Alexei A. Efros, Eli Shechtman, Oliver Wang
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice, this
8
+ list of conditions and the following disclaimer.
9
+
10
+ * Redistributions in binary form must reproduce the above copyright notice,
11
+ this list of conditions and the following disclaimer in the documentation
12
+ and/or other materials provided with the distribution.
13
+
14
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
MindEyeV2/src/generative_models/sgm/modules/autoencoding/lpips/loss/__init__.py ADDED
File without changes
MindEyeV2/src/generative_models/sgm/modules/autoencoding/lpips/loss/lpips.py ADDED
@@ -0,0 +1,147 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Stripped version of https://github.com/richzhang/PerceptualSimilarity/tree/master/models"""
2
+
3
+ from collections import namedtuple
4
+
5
+ import torch
6
+ import torch.nn as nn
7
+ from torchvision import models
8
+
9
+ from ..util import get_ckpt_path
10
+
11
+
12
+ class LPIPS(nn.Module):
13
+ # Learned perceptual metric
14
+ def __init__(self, use_dropout=True):
15
+ super().__init__()
16
+ self.scaling_layer = ScalingLayer()
17
+ self.chns = [64, 128, 256, 512, 512] # vg16 features
18
+ self.net = vgg16(pretrained=True, requires_grad=False)
19
+ self.lin0 = NetLinLayer(self.chns[0], use_dropout=use_dropout)
20
+ self.lin1 = NetLinLayer(self.chns[1], use_dropout=use_dropout)
21
+ self.lin2 = NetLinLayer(self.chns[2], use_dropout=use_dropout)
22
+ self.lin3 = NetLinLayer(self.chns[3], use_dropout=use_dropout)
23
+ self.lin4 = NetLinLayer(self.chns[4], use_dropout=use_dropout)
24
+ self.load_from_pretrained()
25
+ for param in self.parameters():
26
+ param.requires_grad = False
27
+
28
+ def load_from_pretrained(self, name="vgg_lpips"):
29
+ ckpt = get_ckpt_path(name, "sgm/modules/autoencoding/lpips/loss")
30
+ self.load_state_dict(
31
+ torch.load(ckpt, map_location=torch.device("cpu")), strict=False
32
+ )
33
+ print("loaded pretrained LPIPS loss from {}".format(ckpt))
34
+
35
+ @classmethod
36
+ def from_pretrained(cls, name="vgg_lpips"):
37
+ if name != "vgg_lpips":
38
+ raise NotImplementedError
39
+ model = cls()
40
+ ckpt = get_ckpt_path(name)
41
+ model.load_state_dict(
42
+ torch.load(ckpt, map_location=torch.device("cpu")), strict=False
43
+ )
44
+ return model
45
+
46
+ def forward(self, input, target):
47
+ in0_input, in1_input = (self.scaling_layer(input), self.scaling_layer(target))
48
+ outs0, outs1 = self.net(in0_input), self.net(in1_input)
49
+ feats0, feats1, diffs = {}, {}, {}
50
+ lins = [self.lin0, self.lin1, self.lin2, self.lin3, self.lin4]
51
+ for kk in range(len(self.chns)):
52
+ feats0[kk], feats1[kk] = normalize_tensor(outs0[kk]), normalize_tensor(
53
+ outs1[kk]
54
+ )
55
+ diffs[kk] = (feats0[kk] - feats1[kk]) ** 2
56
+
57
+ res = [
58
+ spatial_average(lins[kk].model(diffs[kk]), keepdim=True)
59
+ for kk in range(len(self.chns))
60
+ ]
61
+ val = res[0]
62
+ for l in range(1, len(self.chns)):
63
+ val += res[l]
64
+ return val
65
+
66
+
67
+ class ScalingLayer(nn.Module):
68
+ def __init__(self):
69
+ super(ScalingLayer, self).__init__()
70
+ self.register_buffer(
71
+ "shift", torch.Tensor([-0.030, -0.088, -0.188])[None, :, None, None]
72
+ )
73
+ self.register_buffer(
74
+ "scale", torch.Tensor([0.458, 0.448, 0.450])[None, :, None, None]
75
+ )
76
+
77
+ def forward(self, inp):
78
+ return (inp - self.shift) / self.scale
79
+
80
+
81
+ class NetLinLayer(nn.Module):
82
+ """A single linear layer which does a 1x1 conv"""
83
+
84
+ def __init__(self, chn_in, chn_out=1, use_dropout=False):
85
+ super(NetLinLayer, self).__init__()
86
+ layers = (
87
+ [
88
+ nn.Dropout(),
89
+ ]
90
+ if (use_dropout)
91
+ else []
92
+ )
93
+ layers += [
94
+ nn.Conv2d(chn_in, chn_out, 1, stride=1, padding=0, bias=False),
95
+ ]
96
+ self.model = nn.Sequential(*layers)
97
+
98
+
99
+ class vgg16(torch.nn.Module):
100
+ def __init__(self, requires_grad=False, pretrained=True):
101
+ super(vgg16, self).__init__()
102
+ vgg_pretrained_features = models.vgg16(pretrained=pretrained).features
103
+ self.slice1 = torch.nn.Sequential()
104
+ self.slice2 = torch.nn.Sequential()
105
+ self.slice3 = torch.nn.Sequential()
106
+ self.slice4 = torch.nn.Sequential()
107
+ self.slice5 = torch.nn.Sequential()
108
+ self.N_slices = 5
109
+ for x in range(4):
110
+ self.slice1.add_module(str(x), vgg_pretrained_features[x])
111
+ for x in range(4, 9):
112
+ self.slice2.add_module(str(x), vgg_pretrained_features[x])
113
+ for x in range(9, 16):
114
+ self.slice3.add_module(str(x), vgg_pretrained_features[x])
115
+ for x in range(16, 23):
116
+ self.slice4.add_module(str(x), vgg_pretrained_features[x])
117
+ for x in range(23, 30):
118
+ self.slice5.add_module(str(x), vgg_pretrained_features[x])
119
+ if not requires_grad:
120
+ for param in self.parameters():
121
+ param.requires_grad = False
122
+
123
+ def forward(self, X):
124
+ h = self.slice1(X)
125
+ h_relu1_2 = h
126
+ h = self.slice2(h)
127
+ h_relu2_2 = h
128
+ h = self.slice3(h)
129
+ h_relu3_3 = h
130
+ h = self.slice4(h)
131
+ h_relu4_3 = h
132
+ h = self.slice5(h)
133
+ h_relu5_3 = h
134
+ vgg_outputs = namedtuple(
135
+ "VggOutputs", ["relu1_2", "relu2_2", "relu3_3", "relu4_3", "relu5_3"]
136
+ )
137
+ out = vgg_outputs(h_relu1_2, h_relu2_2, h_relu3_3, h_relu4_3, h_relu5_3)
138
+ return out
139
+
140
+
141
+ def normalize_tensor(x, eps=1e-10):
142
+ norm_factor = torch.sqrt(torch.sum(x**2, dim=1, keepdim=True))
143
+ return x / (norm_factor + eps)
144
+
145
+
146
+ def spatial_average(x, keepdim=True):
147
+ return x.mean([2, 3], keepdim=keepdim)
MindEyeV2/src/generative_models/sgm/modules/autoencoding/lpips/model/LICENSE ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Copyright (c) 2017, Jun-Yan Zhu and Taesung Park
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice, this
8
+ list of conditions and the following disclaimer.
9
+
10
+ * Redistributions in binary form must reproduce the above copyright notice,
11
+ this list of conditions and the following disclaimer in the documentation
12
+ and/or other materials provided with the distribution.
13
+
14
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
+
25
+
26
+ --------------------------- LICENSE FOR pix2pix --------------------------------
27
+ BSD License
28
+
29
+ For pix2pix software
30
+ Copyright (c) 2016, Phillip Isola and Jun-Yan Zhu
31
+ All rights reserved.
32
+
33
+ Redistribution and use in source and binary forms, with or without
34
+ modification, are permitted provided that the following conditions are met:
35
+
36
+ * Redistributions of source code must retain the above copyright notice, this
37
+ list of conditions and the following disclaimer.
38
+
39
+ * Redistributions in binary form must reproduce the above copyright notice,
40
+ this list of conditions and the following disclaimer in the documentation
41
+ and/or other materials provided with the distribution.
42
+
43
+ ----------------------------- LICENSE FOR DCGAN --------------------------------
44
+ BSD License
45
+
46
+ For dcgan.torch software
47
+
48
+ Copyright (c) 2015, Facebook, Inc. All rights reserved.
49
+
50
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
51
+
52
+ Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
53
+
54
+ Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
55
+
56
+ Neither the name Facebook nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
57
+
58
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
MindEyeV2/src/generative_models/sgm/modules/autoencoding/lpips/model/__init__.py ADDED
File without changes
MindEyeV2/src/generative_models/sgm/modules/autoencoding/lpips/model/model.py ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import functools
2
+
3
+ import torch.nn as nn
4
+
5
+ from ..util import ActNorm
6
+
7
+
8
+ def weights_init(m):
9
+ classname = m.__class__.__name__
10
+ if classname.find("Conv") != -1:
11
+ nn.init.normal_(m.weight.data, 0.0, 0.02)
12
+ elif classname.find("BatchNorm") != -1:
13
+ nn.init.normal_(m.weight.data, 1.0, 0.02)
14
+ nn.init.constant_(m.bias.data, 0)
15
+
16
+
17
+ class NLayerDiscriminator(nn.Module):
18
+ """Defines a PatchGAN discriminator as in Pix2Pix
19
+ --> see https://github.com/junyanz/pytorch-CycleGAN-and-pix2pix/blob/master/models/networks.py
20
+ """
21
+
22
+ def __init__(self, input_nc=3, ndf=64, n_layers=3, use_actnorm=False):
23
+ """Construct a PatchGAN discriminator
24
+ Parameters:
25
+ input_nc (int) -- the number of channels in input images
26
+ ndf (int) -- the number of filters in the last conv layer
27
+ n_layers (int) -- the number of conv layers in the discriminator
28
+ norm_layer -- normalization layer
29
+ """
30
+ super(NLayerDiscriminator, self).__init__()
31
+ if not use_actnorm:
32
+ norm_layer = nn.BatchNorm2d
33
+ else:
34
+ norm_layer = ActNorm
35
+ if (
36
+ type(norm_layer) == functools.partial
37
+ ): # no need to use bias as BatchNorm2d has affine parameters
38
+ use_bias = norm_layer.func != nn.BatchNorm2d
39
+ else:
40
+ use_bias = norm_layer != nn.BatchNorm2d
41
+
42
+ kw = 4
43
+ padw = 1
44
+ sequence = [
45
+ nn.Conv2d(input_nc, ndf, kernel_size=kw, stride=2, padding=padw),
46
+ nn.LeakyReLU(0.2, True),
47
+ ]
48
+ nf_mult = 1
49
+ nf_mult_prev = 1
50
+ for n in range(1, n_layers): # gradually increase the number of filters
51
+ nf_mult_prev = nf_mult
52
+ nf_mult = min(2**n, 8)
53
+ sequence += [
54
+ nn.Conv2d(
55
+ ndf * nf_mult_prev,
56
+ ndf * nf_mult,
57
+ kernel_size=kw,
58
+ stride=2,
59
+ padding=padw,
60
+ bias=use_bias,
61
+ ),
62
+ norm_layer(ndf * nf_mult),
63
+ nn.LeakyReLU(0.2, True),
64
+ ]
65
+
66
+ nf_mult_prev = nf_mult
67
+ nf_mult = min(2**n_layers, 8)
68
+ sequence += [
69
+ nn.Conv2d(
70
+ ndf * nf_mult_prev,
71
+ ndf * nf_mult,
72
+ kernel_size=kw,
73
+ stride=1,
74
+ padding=padw,
75
+ bias=use_bias,
76
+ ),
77
+ norm_layer(ndf * nf_mult),
78
+ nn.LeakyReLU(0.2, True),
79
+ ]
80
+
81
+ sequence += [
82
+ nn.Conv2d(ndf * nf_mult, 1, kernel_size=kw, stride=1, padding=padw)
83
+ ] # output 1 channel prediction map
84
+ self.main = nn.Sequential(*sequence)
85
+
86
+ def forward(self, input):
87
+ """Standard forward."""
88
+ return self.main(input)
MindEyeV2/src/generative_models/sgm/modules/autoencoding/lpips/util.py ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import hashlib
2
+ import os
3
+
4
+ import requests
5
+ import torch
6
+ import torch.nn as nn
7
+ from tqdm import tqdm
8
+
9
+ URL_MAP = {"vgg_lpips": "https://heibox.uni-heidelberg.de/f/607503859c864bc1b30b/?dl=1"}
10
+
11
+ CKPT_MAP = {"vgg_lpips": "vgg.pth"}
12
+
13
+ MD5_MAP = {"vgg_lpips": "d507d7349b931f0638a25a48a722f98a"}
14
+
15
+
16
+ def download(url, local_path, chunk_size=1024):
17
+ os.makedirs(os.path.split(local_path)[0], exist_ok=True)
18
+ with requests.get(url, stream=True) as r:
19
+ total_size = int(r.headers.get("content-length", 0))
20
+ with tqdm(total=total_size, unit="B", unit_scale=True) as pbar:
21
+ with open(local_path, "wb") as f:
22
+ for data in r.iter_content(chunk_size=chunk_size):
23
+ if data:
24
+ f.write(data)
25
+ pbar.update(chunk_size)
26
+
27
+
28
+ def md5_hash(path):
29
+ with open(path, "rb") as f:
30
+ content = f.read()
31
+ return hashlib.md5(content).hexdigest()
32
+
33
+
34
+ def get_ckpt_path(name, root, check=False):
35
+ assert name in URL_MAP
36
+ path = os.path.join(root, CKPT_MAP[name])
37
+ if not os.path.exists(path) or (check and not md5_hash(path) == MD5_MAP[name]):
38
+ print("Downloading {} model from {} to {}".format(name, URL_MAP[name], path))
39
+ download(URL_MAP[name], path)
40
+ md5 = md5_hash(path)
41
+ assert md5 == MD5_MAP[name], md5
42
+ return path
43
+
44
+
45
+ class ActNorm(nn.Module):
46
+ def __init__(
47
+ self, num_features, logdet=False, affine=True, allow_reverse_init=False
48
+ ):
49
+ assert affine
50
+ super().__init__()
51
+ self.logdet = logdet
52
+ self.loc = nn.Parameter(torch.zeros(1, num_features, 1, 1))
53
+ self.scale = nn.Parameter(torch.ones(1, num_features, 1, 1))
54
+ self.allow_reverse_init = allow_reverse_init
55
+
56
+ self.register_buffer("initialized", torch.tensor(0, dtype=torch.uint8))
57
+
58
+ def initialize(self, input):
59
+ with torch.no_grad():
60
+ flatten = input.permute(1, 0, 2, 3).contiguous().view(input.shape[1], -1)
61
+ mean = (
62
+ flatten.mean(1)
63
+ .unsqueeze(1)
64
+ .unsqueeze(2)
65
+ .unsqueeze(3)
66
+ .permute(1, 0, 2, 3)
67
+ )
68
+ std = (
69
+ flatten.std(1)
70
+ .unsqueeze(1)
71
+ .unsqueeze(2)
72
+ .unsqueeze(3)
73
+ .permute(1, 0, 2, 3)
74
+ )
75
+
76
+ self.loc.data.copy_(-mean)
77
+ self.scale.data.copy_(1 / (std + 1e-6))
78
+
79
+ def forward(self, input, reverse=False):
80
+ if reverse:
81
+ return self.reverse(input)
82
+ if len(input.shape) == 2:
83
+ input = input[:, :, None, None]
84
+ squeeze = True
85
+ else:
86
+ squeeze = False
87
+
88
+ _, _, height, width = input.shape
89
+
90
+ if self.training and self.initialized.item() == 0:
91
+ self.initialize(input)
92
+ self.initialized.fill_(1)
93
+
94
+ h = self.scale * (input + self.loc)
95
+
96
+ if squeeze:
97
+ h = h.squeeze(-1).squeeze(-1)
98
+
99
+ if self.logdet:
100
+ log_abs = torch.log(torch.abs(self.scale))
101
+ logdet = height * width * torch.sum(log_abs)
102
+ logdet = logdet * torch.ones(input.shape[0]).to(input)
103
+ return h, logdet
104
+
105
+ return h
106
+
107
+ def reverse(self, output):
108
+ if self.training and self.initialized.item() == 0:
109
+ if not self.allow_reverse_init:
110
+ raise RuntimeError(
111
+ "Initializing ActNorm in reverse direction is "
112
+ "disabled by default. Use allow_reverse_init=True to enable."
113
+ )
114
+ else:
115
+ self.initialize(output)
116
+ self.initialized.fill_(1)
117
+
118
+ if len(output.shape) == 2:
119
+ output = output[:, :, None, None]
120
+ squeeze = True
121
+ else:
122
+ squeeze = False
123
+
124
+ h = output / self.scale - self.loc
125
+
126
+ if squeeze:
127
+ h = h.squeeze(-1).squeeze(-1)
128
+ return h
MindEyeV2/src/generative_models/sgm/modules/autoencoding/lpips/vqperceptual.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn.functional as F
3
+
4
+
5
+ def hinge_d_loss(logits_real, logits_fake):
6
+ loss_real = torch.mean(F.relu(1.0 - logits_real))
7
+ loss_fake = torch.mean(F.relu(1.0 + logits_fake))
8
+ d_loss = 0.5 * (loss_real + loss_fake)
9
+ return d_loss
10
+
11
+
12
+ def vanilla_d_loss(logits_real, logits_fake):
13
+ d_loss = 0.5 * (
14
+ torch.mean(torch.nn.functional.softplus(-logits_real))
15
+ + torch.mean(torch.nn.functional.softplus(logits_fake))
16
+ )
17
+ return d_loss
MindEyeV2/src/generative_models/sgm/modules/autoencoding/regularizers/__init__.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from abc import abstractmethod
2
+ from typing import Any, Tuple
3
+
4
+ import torch
5
+ import torch.nn as nn
6
+ import torch.nn.functional as F
7
+
8
+ from ....modules.distributions.distributions import \
9
+ DiagonalGaussianDistribution
10
+ from .base import AbstractRegularizer
11
+
12
+
13
+ class DiagonalGaussianRegularizer(AbstractRegularizer):
14
+ def __init__(self, sample: bool = True):
15
+ super().__init__()
16
+ self.sample = sample
17
+
18
+ def get_trainable_parameters(self) -> Any:
19
+ yield from ()
20
+
21
+ def forward(self, z: torch.Tensor) -> Tuple[torch.Tensor, dict]:
22
+ log = dict()
23
+ posterior = DiagonalGaussianDistribution(z)
24
+ if self.sample:
25
+ z = posterior.sample()
26
+ else:
27
+ z = posterior.mode()
28
+ kl_loss = posterior.kl()
29
+ kl_loss = torch.sum(kl_loss) / kl_loss.shape[0]
30
+ log["kl_loss"] = kl_loss
31
+ return z, log
MindEyeV2/src/generative_models/sgm/modules/autoencoding/regularizers/__pycache__/__init__.cpython-310.pyc ADDED
Binary file (1.51 kB). View file
 
MindEyeV2/src/generative_models/sgm/modules/autoencoding/regularizers/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (2.32 kB). View file
 
MindEyeV2/src/generative_models/sgm/modules/autoencoding/regularizers/__pycache__/base.cpython-310.pyc ADDED
Binary file (2.05 kB). View file
 
MindEyeV2/src/generative_models/sgm/modules/autoencoding/regularizers/__pycache__/base.cpython-311.pyc ADDED
Binary file (3.26 kB). View file
 
MindEyeV2/src/generative_models/sgm/modules/autoencoding/regularizers/base.py ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from abc import abstractmethod
2
+ from typing import Any, Tuple
3
+
4
+ import torch
5
+ import torch.nn.functional as F
6
+ from torch import nn
7
+
8
+
9
+ class AbstractRegularizer(nn.Module):
10
+ def __init__(self):
11
+ super().__init__()
12
+
13
+ def forward(self, z: torch.Tensor) -> Tuple[torch.Tensor, dict]:
14
+ raise NotImplementedError()
15
+
16
+ @abstractmethod
17
+ def get_trainable_parameters(self) -> Any:
18
+ raise NotImplementedError()
19
+
20
+
21
+ class IdentityRegularizer(AbstractRegularizer):
22
+ def forward(self, z: torch.Tensor) -> Tuple[torch.Tensor, dict]:
23
+ return z, dict()
24
+
25
+ def get_trainable_parameters(self) -> Any:
26
+ yield from ()
27
+
28
+
29
+ def measure_perplexity(
30
+ predicted_indices: torch.Tensor, num_centroids: int
31
+ ) -> Tuple[torch.Tensor, torch.Tensor]:
32
+ # src: https://github.com/karpathy/deep-vector-quantization/blob/main/model.py
33
+ # eval cluster perplexity. when perplexity == num_embeddings then all clusters are used exactly equally
34
+ encodings = (
35
+ F.one_hot(predicted_indices, num_centroids).float().reshape(-1, num_centroids)
36
+ )
37
+ avg_probs = encodings.mean(0)
38
+ perplexity = (-(avg_probs * torch.log(avg_probs + 1e-10)).sum()).exp()
39
+ cluster_use = torch.sum(avg_probs > 0)
40
+ return perplexity, cluster_use
MindEyeV2/src/generative_models/sgm/modules/autoencoding/regularizers/quantize.py ADDED
@@ -0,0 +1,487 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ from abc import abstractmethod
3
+ from typing import Dict, Iterator, Literal, Optional, Tuple, Union
4
+
5
+ import numpy as np
6
+ import torch
7
+ import torch.nn as nn
8
+ import torch.nn.functional as F
9
+ from einops import rearrange
10
+ from torch import einsum
11
+
12
+ from .base import AbstractRegularizer, measure_perplexity
13
+
14
+ logpy = logging.getLogger(__name__)
15
+
16
+
17
+ class AbstractQuantizer(AbstractRegularizer):
18
+ def __init__(self):
19
+ super().__init__()
20
+ # Define these in your init
21
+ # shape (N,)
22
+ self.used: Optional[torch.Tensor]
23
+ self.re_embed: int
24
+ self.unknown_index: Union[Literal["random"], int]
25
+
26
+ def remap_to_used(self, inds: torch.Tensor) -> torch.Tensor:
27
+ assert self.used is not None, "You need to define used indices for remap"
28
+ ishape = inds.shape
29
+ assert len(ishape) > 1
30
+ inds = inds.reshape(ishape[0], -1)
31
+ used = self.used.to(inds)
32
+ match = (inds[:, :, None] == used[None, None, ...]).long()
33
+ new = match.argmax(-1)
34
+ unknown = match.sum(2) < 1
35
+ if self.unknown_index == "random":
36
+ new[unknown] = torch.randint(0, self.re_embed, size=new[unknown].shape).to(
37
+ device=new.device
38
+ )
39
+ else:
40
+ new[unknown] = self.unknown_index
41
+ return new.reshape(ishape)
42
+
43
+ def unmap_to_all(self, inds: torch.Tensor) -> torch.Tensor:
44
+ assert self.used is not None, "You need to define used indices for remap"
45
+ ishape = inds.shape
46
+ assert len(ishape) > 1
47
+ inds = inds.reshape(ishape[0], -1)
48
+ used = self.used.to(inds)
49
+ if self.re_embed > self.used.shape[0]: # extra token
50
+ inds[inds >= self.used.shape[0]] = 0 # simply set to zero
51
+ back = torch.gather(used[None, :][inds.shape[0] * [0], :], 1, inds)
52
+ return back.reshape(ishape)
53
+
54
+ @abstractmethod
55
+ def get_codebook_entry(
56
+ self, indices: torch.Tensor, shape: Optional[Tuple[int, ...]] = None
57
+ ) -> torch.Tensor:
58
+ raise NotImplementedError()
59
+
60
+ def get_trainable_parameters(self) -> Iterator[torch.nn.Parameter]:
61
+ yield from self.parameters()
62
+
63
+
64
+ class GumbelQuantizer(AbstractQuantizer):
65
+ """
66
+ credit to @karpathy:
67
+ https://github.com/karpathy/deep-vector-quantization/blob/main/model.py (thanks!)
68
+ Gumbel Softmax trick quantizer
69
+ Categorical Reparameterization with Gumbel-Softmax, Jang et al. 2016
70
+ https://arxiv.org/abs/1611.01144
71
+ """
72
+
73
+ def __init__(
74
+ self,
75
+ num_hiddens: int,
76
+ embedding_dim: int,
77
+ n_embed: int,
78
+ straight_through: bool = True,
79
+ kl_weight: float = 5e-4,
80
+ temp_init: float = 1.0,
81
+ remap: Optional[str] = None,
82
+ unknown_index: str = "random",
83
+ loss_key: str = "loss/vq",
84
+ ) -> None:
85
+ super().__init__()
86
+
87
+ self.loss_key = loss_key
88
+ self.embedding_dim = embedding_dim
89
+ self.n_embed = n_embed
90
+
91
+ self.straight_through = straight_through
92
+ self.temperature = temp_init
93
+ self.kl_weight = kl_weight
94
+
95
+ self.proj = nn.Conv2d(num_hiddens, n_embed, 1)
96
+ self.embed = nn.Embedding(n_embed, embedding_dim)
97
+
98
+ self.remap = remap
99
+ if self.remap is not None:
100
+ self.register_buffer("used", torch.tensor(np.load(self.remap)))
101
+ self.re_embed = self.used.shape[0]
102
+ else:
103
+ self.used = None
104
+ self.re_embed = n_embed
105
+ if unknown_index == "extra":
106
+ self.unknown_index = self.re_embed
107
+ self.re_embed = self.re_embed + 1
108
+ else:
109
+ assert unknown_index == "random" or isinstance(
110
+ unknown_index, int
111
+ ), "unknown index needs to be 'random', 'extra' or any integer"
112
+ self.unknown_index = unknown_index # "random" or "extra" or integer
113
+ if self.remap is not None:
114
+ logpy.info(
115
+ f"Remapping {self.n_embed} indices to {self.re_embed} indices. "
116
+ f"Using {self.unknown_index} for unknown indices."
117
+ )
118
+
119
+ def forward(
120
+ self, z: torch.Tensor, temp: Optional[float] = None, return_logits: bool = False
121
+ ) -> Tuple[torch.Tensor, Dict]:
122
+ # force hard = True when we are in eval mode, as we must quantize.
123
+ # actually, always true seems to work
124
+ hard = self.straight_through if self.training else True
125
+ temp = self.temperature if temp is None else temp
126
+ out_dict = {}
127
+ logits = self.proj(z)
128
+ if self.remap is not None:
129
+ # continue only with used logits
130
+ full_zeros = torch.zeros_like(logits)
131
+ logits = logits[:, self.used, ...]
132
+
133
+ soft_one_hot = F.gumbel_softmax(logits, tau=temp, dim=1, hard=hard)
134
+ if self.remap is not None:
135
+ # go back to all entries but unused set to zero
136
+ full_zeros[:, self.used, ...] = soft_one_hot
137
+ soft_one_hot = full_zeros
138
+ z_q = einsum("b n h w, n d -> b d h w", soft_one_hot, self.embed.weight)
139
+
140
+ # + kl divergence to the prior loss
141
+ qy = F.softmax(logits, dim=1)
142
+ diff = (
143
+ self.kl_weight
144
+ * torch.sum(qy * torch.log(qy * self.n_embed + 1e-10), dim=1).mean()
145
+ )
146
+ out_dict[self.loss_key] = diff
147
+
148
+ ind = soft_one_hot.argmax(dim=1)
149
+ out_dict["indices"] = ind
150
+ if self.remap is not None:
151
+ ind = self.remap_to_used(ind)
152
+
153
+ if return_logits:
154
+ out_dict["logits"] = logits
155
+
156
+ return z_q, out_dict
157
+
158
+ def get_codebook_entry(self, indices, shape):
159
+ # TODO: shape not yet optional
160
+ b, h, w, c = shape
161
+ assert b * h * w == indices.shape[0]
162
+ indices = rearrange(indices, "(b h w) -> b h w", b=b, h=h, w=w)
163
+ if self.remap is not None:
164
+ indices = self.unmap_to_all(indices)
165
+ one_hot = (
166
+ F.one_hot(indices, num_classes=self.n_embed).permute(0, 3, 1, 2).float()
167
+ )
168
+ z_q = einsum("b n h w, n d -> b d h w", one_hot, self.embed.weight)
169
+ return z_q
170
+
171
+
172
+ class VectorQuantizer(AbstractQuantizer):
173
+ """
174
+ ____________________________________________
175
+ Discretization bottleneck part of the VQ-VAE.
176
+ Inputs:
177
+ - n_e : number of embeddings
178
+ - e_dim : dimension of embedding
179
+ - beta : commitment cost used in loss term,
180
+ beta * ||z_e(x)-sg[e]||^2
181
+ _____________________________________________
182
+ """
183
+
184
+ def __init__(
185
+ self,
186
+ n_e: int,
187
+ e_dim: int,
188
+ beta: float = 0.25,
189
+ remap: Optional[str] = None,
190
+ unknown_index: str = "random",
191
+ sane_index_shape: bool = False,
192
+ log_perplexity: bool = False,
193
+ embedding_weight_norm: bool = False,
194
+ loss_key: str = "loss/vq",
195
+ ):
196
+ super().__init__()
197
+ self.n_e = n_e
198
+ self.e_dim = e_dim
199
+ self.beta = beta
200
+ self.loss_key = loss_key
201
+
202
+ if not embedding_weight_norm:
203
+ self.embedding = nn.Embedding(self.n_e, self.e_dim)
204
+ self.embedding.weight.data.uniform_(-1.0 / self.n_e, 1.0 / self.n_e)
205
+ else:
206
+ self.embedding = torch.nn.utils.weight_norm(
207
+ nn.Embedding(self.n_e, self.e_dim), dim=1
208
+ )
209
+
210
+ self.remap = remap
211
+ if self.remap is not None:
212
+ self.register_buffer("used", torch.tensor(np.load(self.remap)))
213
+ self.re_embed = self.used.shape[0]
214
+ else:
215
+ self.used = None
216
+ self.re_embed = n_e
217
+ if unknown_index == "extra":
218
+ self.unknown_index = self.re_embed
219
+ self.re_embed = self.re_embed + 1
220
+ else:
221
+ assert unknown_index == "random" or isinstance(
222
+ unknown_index, int
223
+ ), "unknown index needs to be 'random', 'extra' or any integer"
224
+ self.unknown_index = unknown_index # "random" or "extra" or integer
225
+ if self.remap is not None:
226
+ logpy.info(
227
+ f"Remapping {self.n_e} indices to {self.re_embed} indices. "
228
+ f"Using {self.unknown_index} for unknown indices."
229
+ )
230
+
231
+ self.sane_index_shape = sane_index_shape
232
+ self.log_perplexity = log_perplexity
233
+
234
+ def forward(
235
+ self,
236
+ z: torch.Tensor,
237
+ ) -> Tuple[torch.Tensor, Dict]:
238
+ do_reshape = z.ndim == 4
239
+ if do_reshape:
240
+ # # reshape z -> (batch, height, width, channel) and flatten
241
+ z = rearrange(z, "b c h w -> b h w c").contiguous()
242
+
243
+ else:
244
+ assert z.ndim < 4, "No reshaping strategy for inputs > 4 dimensions defined"
245
+ z = z.contiguous()
246
+
247
+ z_flattened = z.view(-1, self.e_dim)
248
+ # distances from z to embeddings e_j (z - e)^2 = z^2 + e^2 - 2 e * z
249
+
250
+ d = (
251
+ torch.sum(z_flattened**2, dim=1, keepdim=True)
252
+ + torch.sum(self.embedding.weight**2, dim=1)
253
+ - 2
254
+ * torch.einsum(
255
+ "bd,dn->bn", z_flattened, rearrange(self.embedding.weight, "n d -> d n")
256
+ )
257
+ )
258
+
259
+ min_encoding_indices = torch.argmin(d, dim=1)
260
+ z_q = self.embedding(min_encoding_indices).view(z.shape)
261
+ loss_dict = {}
262
+ if self.log_perplexity:
263
+ perplexity, cluster_usage = measure_perplexity(
264
+ min_encoding_indices.detach(), self.n_e
265
+ )
266
+ loss_dict.update({"perplexity": perplexity, "cluster_usage": cluster_usage})
267
+
268
+ # compute loss for embedding
269
+ loss = self.beta * torch.mean((z_q.detach() - z) ** 2) + torch.mean(
270
+ (z_q - z.detach()) ** 2
271
+ )
272
+ loss_dict[self.loss_key] = loss
273
+
274
+ # preserve gradients
275
+ z_q = z + (z_q - z).detach()
276
+
277
+ # reshape back to match original input shape
278
+ if do_reshape:
279
+ z_q = rearrange(z_q, "b h w c -> b c h w").contiguous()
280
+
281
+ if self.remap is not None:
282
+ min_encoding_indices = min_encoding_indices.reshape(
283
+ z.shape[0], -1
284
+ ) # add batch axis
285
+ min_encoding_indices = self.remap_to_used(min_encoding_indices)
286
+ min_encoding_indices = min_encoding_indices.reshape(-1, 1) # flatten
287
+
288
+ if self.sane_index_shape:
289
+ if do_reshape:
290
+ min_encoding_indices = min_encoding_indices.reshape(
291
+ z_q.shape[0], z_q.shape[2], z_q.shape[3]
292
+ )
293
+ else:
294
+ min_encoding_indices = rearrange(
295
+ min_encoding_indices, "(b s) 1 -> b s", b=z_q.shape[0]
296
+ )
297
+
298
+ loss_dict["min_encoding_indices"] = min_encoding_indices
299
+
300
+ return z_q, loss_dict
301
+
302
+ def get_codebook_entry(
303
+ self, indices: torch.Tensor, shape: Optional[Tuple[int, ...]] = None
304
+ ) -> torch.Tensor:
305
+ # shape specifying (batch, height, width, channel)
306
+ if self.remap is not None:
307
+ assert shape is not None, "Need to give shape for remap"
308
+ indices = indices.reshape(shape[0], -1) # add batch axis
309
+ indices = self.unmap_to_all(indices)
310
+ indices = indices.reshape(-1) # flatten again
311
+
312
+ # get quantized latent vectors
313
+ z_q = self.embedding(indices)
314
+
315
+ if shape is not None:
316
+ z_q = z_q.view(shape)
317
+ # reshape back to match original input shape
318
+ z_q = z_q.permute(0, 3, 1, 2).contiguous()
319
+
320
+ return z_q
321
+
322
+
323
+ class EmbeddingEMA(nn.Module):
324
+ def __init__(self, num_tokens, codebook_dim, decay=0.99, eps=1e-5):
325
+ super().__init__()
326
+ self.decay = decay
327
+ self.eps = eps
328
+ weight = torch.randn(num_tokens, codebook_dim)
329
+ self.weight = nn.Parameter(weight, requires_grad=False)
330
+ self.cluster_size = nn.Parameter(torch.zeros(num_tokens), requires_grad=False)
331
+ self.embed_avg = nn.Parameter(weight.clone(), requires_grad=False)
332
+ self.update = True
333
+
334
+ def forward(self, embed_id):
335
+ return F.embedding(embed_id, self.weight)
336
+
337
+ def cluster_size_ema_update(self, new_cluster_size):
338
+ self.cluster_size.data.mul_(self.decay).add_(
339
+ new_cluster_size, alpha=1 - self.decay
340
+ )
341
+
342
+ def embed_avg_ema_update(self, new_embed_avg):
343
+ self.embed_avg.data.mul_(self.decay).add_(new_embed_avg, alpha=1 - self.decay)
344
+
345
+ def weight_update(self, num_tokens):
346
+ n = self.cluster_size.sum()
347
+ smoothed_cluster_size = (
348
+ (self.cluster_size + self.eps) / (n + num_tokens * self.eps) * n
349
+ )
350
+ # normalize embedding average with smoothed cluster size
351
+ embed_normalized = self.embed_avg / smoothed_cluster_size.unsqueeze(1)
352
+ self.weight.data.copy_(embed_normalized)
353
+
354
+
355
+ class EMAVectorQuantizer(AbstractQuantizer):
356
+ def __init__(
357
+ self,
358
+ n_embed: int,
359
+ embedding_dim: int,
360
+ beta: float,
361
+ decay: float = 0.99,
362
+ eps: float = 1e-5,
363
+ remap: Optional[str] = None,
364
+ unknown_index: str = "random",
365
+ loss_key: str = "loss/vq",
366
+ ):
367
+ super().__init__()
368
+ self.codebook_dim = embedding_dim
369
+ self.num_tokens = n_embed
370
+ self.beta = beta
371
+ self.loss_key = loss_key
372
+
373
+ self.embedding = EmbeddingEMA(self.num_tokens, self.codebook_dim, decay, eps)
374
+
375
+ self.remap = remap
376
+ if self.remap is not None:
377
+ self.register_buffer("used", torch.tensor(np.load(self.remap)))
378
+ self.re_embed = self.used.shape[0]
379
+ else:
380
+ self.used = None
381
+ self.re_embed = n_embed
382
+ if unknown_index == "extra":
383
+ self.unknown_index = self.re_embed
384
+ self.re_embed = self.re_embed + 1
385
+ else:
386
+ assert unknown_index == "random" or isinstance(
387
+ unknown_index, int
388
+ ), "unknown index needs to be 'random', 'extra' or any integer"
389
+ self.unknown_index = unknown_index # "random" or "extra" or integer
390
+ if self.remap is not None:
391
+ logpy.info(
392
+ f"Remapping {self.n_embed} indices to {self.re_embed} indices. "
393
+ f"Using {self.unknown_index} for unknown indices."
394
+ )
395
+
396
+ def forward(self, z: torch.Tensor) -> Tuple[torch.Tensor, Dict]:
397
+ # reshape z -> (batch, height, width, channel) and flatten
398
+ # z, 'b c h w -> b h w c'
399
+ z = rearrange(z, "b c h w -> b h w c")
400
+ z_flattened = z.reshape(-1, self.codebook_dim)
401
+
402
+ # distances from z to embeddings e_j (z - e)^2 = z^2 + e^2 - 2 e * z
403
+ d = (
404
+ z_flattened.pow(2).sum(dim=1, keepdim=True)
405
+ + self.embedding.weight.pow(2).sum(dim=1)
406
+ - 2 * torch.einsum("bd,nd->bn", z_flattened, self.embedding.weight)
407
+ ) # 'n d -> d n'
408
+
409
+ encoding_indices = torch.argmin(d, dim=1)
410
+
411
+ z_q = self.embedding(encoding_indices).view(z.shape)
412
+ encodings = F.one_hot(encoding_indices, self.num_tokens).type(z.dtype)
413
+ avg_probs = torch.mean(encodings, dim=0)
414
+ perplexity = torch.exp(-torch.sum(avg_probs * torch.log(avg_probs + 1e-10)))
415
+
416
+ if self.training and self.embedding.update:
417
+ # EMA cluster size
418
+ encodings_sum = encodings.sum(0)
419
+ self.embedding.cluster_size_ema_update(encodings_sum)
420
+ # EMA embedding average
421
+ embed_sum = encodings.transpose(0, 1) @ z_flattened
422
+ self.embedding.embed_avg_ema_update(embed_sum)
423
+ # normalize embed_avg and update weight
424
+ self.embedding.weight_update(self.num_tokens)
425
+
426
+ # compute loss for embedding
427
+ loss = self.beta * F.mse_loss(z_q.detach(), z)
428
+
429
+ # preserve gradients
430
+ z_q = z + (z_q - z).detach()
431
+
432
+ # reshape back to match original input shape
433
+ # z_q, 'b h w c -> b c h w'
434
+ z_q = rearrange(z_q, "b h w c -> b c h w")
435
+
436
+ out_dict = {
437
+ self.loss_key: loss,
438
+ "encodings": encodings,
439
+ "encoding_indices": encoding_indices,
440
+ "perplexity": perplexity,
441
+ }
442
+
443
+ return z_q, out_dict
444
+
445
+
446
+ class VectorQuantizerWithInputProjection(VectorQuantizer):
447
+ def __init__(
448
+ self,
449
+ input_dim: int,
450
+ n_codes: int,
451
+ codebook_dim: int,
452
+ beta: float = 1.0,
453
+ output_dim: Optional[int] = None,
454
+ **kwargs,
455
+ ):
456
+ super().__init__(n_codes, codebook_dim, beta, **kwargs)
457
+ self.proj_in = nn.Linear(input_dim, codebook_dim)
458
+ self.output_dim = output_dim
459
+ if output_dim is not None:
460
+ self.proj_out = nn.Linear(codebook_dim, output_dim)
461
+ else:
462
+ self.proj_out = nn.Identity()
463
+
464
+ def forward(self, z: torch.Tensor) -> Tuple[torch.Tensor, Dict]:
465
+ rearr = False
466
+ in_shape = z.shape
467
+
468
+ if z.ndim > 3:
469
+ rearr = self.output_dim is not None
470
+ z = rearrange(z, "b c ... -> b (...) c")
471
+ z = self.proj_in(z)
472
+ z_q, loss_dict = super().forward(z)
473
+
474
+ z_q = self.proj_out(z_q)
475
+ if rearr:
476
+ if len(in_shape) == 4:
477
+ z_q = rearrange(z_q, "b (h w) c -> b c h w ", w=in_shape[-1])
478
+ elif len(in_shape) == 5:
479
+ z_q = rearrange(
480
+ z_q, "b (t h w) c -> b c t h w ", w=in_shape[-1], h=in_shape[-2]
481
+ )
482
+ else:
483
+ raise NotImplementedError(
484
+ f"rearranging not available for {len(in_shape)}-dimensional input."
485
+ )
486
+
487
+ return z_q, loss_dict
MindEyeV2/src/generative_models/sgm/modules/autoencoding/temporal_ae.py ADDED
@@ -0,0 +1,349 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Callable, Iterable, Union
2
+
3
+ import torch
4
+ from einops import rearrange, repeat
5
+
6
+ from generative_models.sgm.modules.diffusionmodules.model import (
7
+ XFORMERS_IS_AVAILABLE,
8
+ AttnBlock,
9
+ Decoder,
10
+ MemoryEfficientAttnBlock,
11
+ ResnetBlock,
12
+ )
13
+ from generative_models.sgm.modules.diffusionmodules.openaimodel import ResBlock, timestep_embedding
14
+ from generative_models.sgm.modules.video_attention import VideoTransformerBlock
15
+ from generative_models.sgm.util import partialclass
16
+
17
+
18
+ class VideoResBlock(ResnetBlock):
19
+ def __init__(
20
+ self,
21
+ out_channels,
22
+ *args,
23
+ dropout=0.0,
24
+ video_kernel_size=3,
25
+ alpha=0.0,
26
+ merge_strategy="learned",
27
+ **kwargs,
28
+ ):
29
+ super().__init__(out_channels=out_channels, dropout=dropout, *args, **kwargs)
30
+ if video_kernel_size is None:
31
+ video_kernel_size = [3, 1, 1]
32
+ self.time_stack = ResBlock(
33
+ channels=out_channels,
34
+ emb_channels=0,
35
+ dropout=dropout,
36
+ dims=3,
37
+ use_scale_shift_norm=False,
38
+ use_conv=False,
39
+ up=False,
40
+ down=False,
41
+ kernel_size=video_kernel_size,
42
+ use_checkpoint=False,
43
+ skip_t_emb=True,
44
+ )
45
+
46
+ self.merge_strategy = merge_strategy
47
+ if self.merge_strategy == "fixed":
48
+ self.register_buffer("mix_factor", torch.Tensor([alpha]))
49
+ elif self.merge_strategy == "learned":
50
+ self.register_parameter(
51
+ "mix_factor", torch.nn.Parameter(torch.Tensor([alpha]))
52
+ )
53
+ else:
54
+ raise ValueError(f"unknown merge strategy {self.merge_strategy}")
55
+
56
+ def get_alpha(self, bs):
57
+ if self.merge_strategy == "fixed":
58
+ return self.mix_factor
59
+ elif self.merge_strategy == "learned":
60
+ return torch.sigmoid(self.mix_factor)
61
+ else:
62
+ raise NotImplementedError()
63
+
64
+ def forward(self, x, temb, skip_video=False, timesteps=None):
65
+ if timesteps is None:
66
+ timesteps = self.timesteps
67
+
68
+ b, c, h, w = x.shape
69
+
70
+ x = super().forward(x, temb)
71
+
72
+ if not skip_video:
73
+ x_mix = rearrange(x, "(b t) c h w -> b c t h w", t=timesteps)
74
+
75
+ x = rearrange(x, "(b t) c h w -> b c t h w", t=timesteps)
76
+
77
+ x = self.time_stack(x, temb)
78
+
79
+ alpha = self.get_alpha(bs=b // timesteps)
80
+ x = alpha * x + (1.0 - alpha) * x_mix
81
+
82
+ x = rearrange(x, "b c t h w -> (b t) c h w")
83
+ return x
84
+
85
+
86
+ class AE3DConv(torch.nn.Conv2d):
87
+ def __init__(self, in_channels, out_channels, video_kernel_size=3, *args, **kwargs):
88
+ super().__init__(in_channels, out_channels, *args, **kwargs)
89
+ if isinstance(video_kernel_size, Iterable):
90
+ padding = [int(k // 2) for k in video_kernel_size]
91
+ else:
92
+ padding = int(video_kernel_size // 2)
93
+
94
+ self.time_mix_conv = torch.nn.Conv3d(
95
+ in_channels=out_channels,
96
+ out_channels=out_channels,
97
+ kernel_size=video_kernel_size,
98
+ padding=padding,
99
+ )
100
+
101
+ def forward(self, input, timesteps, skip_video=False):
102
+ x = super().forward(input)
103
+ if skip_video:
104
+ return x
105
+ x = rearrange(x, "(b t) c h w -> b c t h w", t=timesteps)
106
+ x = self.time_mix_conv(x)
107
+ return rearrange(x, "b c t h w -> (b t) c h w")
108
+
109
+
110
+ class VideoBlock(AttnBlock):
111
+ def __init__(
112
+ self, in_channels: int, alpha: float = 0, merge_strategy: str = "learned"
113
+ ):
114
+ super().__init__(in_channels)
115
+ # no context, single headed, as in base class
116
+ self.time_mix_block = VideoTransformerBlock(
117
+ dim=in_channels,
118
+ n_heads=1,
119
+ d_head=in_channels,
120
+ checkpoint=False,
121
+ ff_in=True,
122
+ attn_mode="softmax",
123
+ )
124
+
125
+ time_embed_dim = self.in_channels * 4
126
+ self.video_time_embed = torch.nn.Sequential(
127
+ torch.nn.Linear(self.in_channels, time_embed_dim),
128
+ torch.nn.SiLU(),
129
+ torch.nn.Linear(time_embed_dim, self.in_channels),
130
+ )
131
+
132
+ self.merge_strategy = merge_strategy
133
+ if self.merge_strategy == "fixed":
134
+ self.register_buffer("mix_factor", torch.Tensor([alpha]))
135
+ elif self.merge_strategy == "learned":
136
+ self.register_parameter(
137
+ "mix_factor", torch.nn.Parameter(torch.Tensor([alpha]))
138
+ )
139
+ else:
140
+ raise ValueError(f"unknown merge strategy {self.merge_strategy}")
141
+
142
+ def forward(self, x, timesteps, skip_video=False):
143
+ if skip_video:
144
+ return super().forward(x)
145
+
146
+ x_in = x
147
+ x = self.attention(x)
148
+ h, w = x.shape[2:]
149
+ x = rearrange(x, "b c h w -> b (h w) c")
150
+
151
+ x_mix = x
152
+ num_frames = torch.arange(timesteps, device=x.device)
153
+ num_frames = repeat(num_frames, "t -> b t", b=x.shape[0] // timesteps)
154
+ num_frames = rearrange(num_frames, "b t -> (b t)")
155
+ t_emb = timestep_embedding(num_frames, self.in_channels, repeat_only=False)
156
+ emb = self.video_time_embed(t_emb) # b, n_channels
157
+ emb = emb[:, None, :]
158
+ x_mix = x_mix + emb
159
+
160
+ alpha = self.get_alpha()
161
+ x_mix = self.time_mix_block(x_mix, timesteps=timesteps)
162
+ x = alpha * x + (1.0 - alpha) * x_mix # alpha merge
163
+
164
+ x = rearrange(x, "b (h w) c -> b c h w", h=h, w=w)
165
+ x = self.proj_out(x)
166
+
167
+ return x_in + x
168
+
169
+ def get_alpha(
170
+ self,
171
+ ):
172
+ if self.merge_strategy == "fixed":
173
+ return self.mix_factor
174
+ elif self.merge_strategy == "learned":
175
+ return torch.sigmoid(self.mix_factor)
176
+ else:
177
+ raise NotImplementedError(f"unknown merge strategy {self.merge_strategy}")
178
+
179
+
180
+ class MemoryEfficientVideoBlock(MemoryEfficientAttnBlock):
181
+ def __init__(
182
+ self, in_channels: int, alpha: float = 0, merge_strategy: str = "learned"
183
+ ):
184
+ super().__init__(in_channels)
185
+ # no context, single headed, as in base class
186
+ self.time_mix_block = VideoTransformerBlock(
187
+ dim=in_channels,
188
+ n_heads=1,
189
+ d_head=in_channels,
190
+ checkpoint=False,
191
+ ff_in=True,
192
+ attn_mode="softmax-xformers",
193
+ )
194
+
195
+ time_embed_dim = self.in_channels * 4
196
+ self.video_time_embed = torch.nn.Sequential(
197
+ torch.nn.Linear(self.in_channels, time_embed_dim),
198
+ torch.nn.SiLU(),
199
+ torch.nn.Linear(time_embed_dim, self.in_channels),
200
+ )
201
+
202
+ self.merge_strategy = merge_strategy
203
+ if self.merge_strategy == "fixed":
204
+ self.register_buffer("mix_factor", torch.Tensor([alpha]))
205
+ elif self.merge_strategy == "learned":
206
+ self.register_parameter(
207
+ "mix_factor", torch.nn.Parameter(torch.Tensor([alpha]))
208
+ )
209
+ else:
210
+ raise ValueError(f"unknown merge strategy {self.merge_strategy}")
211
+
212
+ def forward(self, x, timesteps, skip_time_block=False):
213
+ if skip_time_block:
214
+ return super().forward(x)
215
+
216
+ x_in = x
217
+ x = self.attention(x)
218
+ h, w = x.shape[2:]
219
+ x = rearrange(x, "b c h w -> b (h w) c")
220
+
221
+ x_mix = x
222
+ num_frames = torch.arange(timesteps, device=x.device)
223
+ num_frames = repeat(num_frames, "t -> b t", b=x.shape[0] // timesteps)
224
+ num_frames = rearrange(num_frames, "b t -> (b t)")
225
+ t_emb = timestep_embedding(num_frames, self.in_channels, repeat_only=False)
226
+ emb = self.video_time_embed(t_emb) # b, n_channels
227
+ emb = emb[:, None, :]
228
+ x_mix = x_mix + emb
229
+
230
+ alpha = self.get_alpha()
231
+ x_mix = self.time_mix_block(x_mix, timesteps=timesteps)
232
+ x = alpha * x + (1.0 - alpha) * x_mix # alpha merge
233
+
234
+ x = rearrange(x, "b (h w) c -> b c h w", h=h, w=w)
235
+ x = self.proj_out(x)
236
+
237
+ return x_in + x
238
+
239
+ def get_alpha(
240
+ self,
241
+ ):
242
+ if self.merge_strategy == "fixed":
243
+ return self.mix_factor
244
+ elif self.merge_strategy == "learned":
245
+ return torch.sigmoid(self.mix_factor)
246
+ else:
247
+ raise NotImplementedError(f"unknown merge strategy {self.merge_strategy}")
248
+
249
+
250
+ def make_time_attn(
251
+ in_channels,
252
+ attn_type="vanilla",
253
+ attn_kwargs=None,
254
+ alpha: float = 0,
255
+ merge_strategy: str = "learned",
256
+ ):
257
+ assert attn_type in [
258
+ "vanilla",
259
+ "vanilla-xformers",
260
+ ], f"attn_type {attn_type} not supported for spatio-temporal attention"
261
+ print(
262
+ f"making spatial and temporal attention of type '{attn_type}' with {in_channels} in_channels"
263
+ )
264
+ if not XFORMERS_IS_AVAILABLE and attn_type == "vanilla-xformers":
265
+ print(
266
+ f"Attention mode '{attn_type}' is not available. Falling back to vanilla attention. "
267
+ f"This is not a problem in Pytorch >= 2.0. FYI, you are running with PyTorch version {torch.__version__}"
268
+ )
269
+ attn_type = "vanilla"
270
+
271
+ if attn_type == "vanilla":
272
+ assert attn_kwargs is None
273
+ return partialclass(
274
+ VideoBlock, in_channels, alpha=alpha, merge_strategy=merge_strategy
275
+ )
276
+ elif attn_type == "vanilla-xformers":
277
+ print(f"building MemoryEfficientAttnBlock with {in_channels} in_channels...")
278
+ return partialclass(
279
+ MemoryEfficientVideoBlock,
280
+ in_channels,
281
+ alpha=alpha,
282
+ merge_strategy=merge_strategy,
283
+ )
284
+ else:
285
+ return NotImplementedError()
286
+
287
+
288
+ class Conv2DWrapper(torch.nn.Conv2d):
289
+ def forward(self, input: torch.Tensor, **kwargs) -> torch.Tensor:
290
+ return super().forward(input)
291
+
292
+
293
+ class VideoDecoder(Decoder):
294
+ available_time_modes = ["all", "conv-only", "attn-only"]
295
+
296
+ def __init__(
297
+ self,
298
+ *args,
299
+ video_kernel_size: Union[int, list] = 3,
300
+ alpha: float = 0.0,
301
+ merge_strategy: str = "learned",
302
+ time_mode: str = "conv-only",
303
+ **kwargs,
304
+ ):
305
+ self.video_kernel_size = video_kernel_size
306
+ self.alpha = alpha
307
+ self.merge_strategy = merge_strategy
308
+ self.time_mode = time_mode
309
+ assert (
310
+ self.time_mode in self.available_time_modes
311
+ ), f"time_mode parameter has to be in {self.available_time_modes}"
312
+ super().__init__(*args, **kwargs)
313
+
314
+ def get_last_layer(self, skip_time_mix=False, **kwargs):
315
+ if self.time_mode == "attn-only":
316
+ raise NotImplementedError("TODO")
317
+ else:
318
+ return (
319
+ self.conv_out.time_mix_conv.weight
320
+ if not skip_time_mix
321
+ else self.conv_out.weight
322
+ )
323
+
324
+ def _make_attn(self) -> Callable:
325
+ if self.time_mode not in ["conv-only", "only-last-conv"]:
326
+ return partialclass(
327
+ make_time_attn,
328
+ alpha=self.alpha,
329
+ merge_strategy=self.merge_strategy,
330
+ )
331
+ else:
332
+ return super()._make_attn()
333
+
334
+ def _make_conv(self) -> Callable:
335
+ if self.time_mode != "attn-only":
336
+ return partialclass(AE3DConv, video_kernel_size=self.video_kernel_size)
337
+ else:
338
+ return Conv2DWrapper
339
+
340
+ def _make_resblock(self) -> Callable:
341
+ if self.time_mode not in ["attn-only", "only-last-conv"]:
342
+ return partialclass(
343
+ VideoResBlock,
344
+ video_kernel_size=self.video_kernel_size,
345
+ alpha=self.alpha,
346
+ merge_strategy=self.merge_strategy,
347
+ )
348
+ else:
349
+ return super()._make_resblock()
MindEyeV2/src/generative_models/sgm/modules/diffusionmodules/__init__.py ADDED
File without changes
MindEyeV2/src/generative_models/sgm/modules/diffusionmodules/__pycache__/denoiser.cpython-311.pyc ADDED
Binary file (5.07 kB). View file