Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- MindEyeV2/src/generative_models/scripts/tests/attention.py +319 -0
- MindEyeV2/src/generative_models/scripts/util/detection/nsfw_and_watermark_dectection.py +110 -0
- MindEyeV2/src/generative_models/sgm/__init__.py +4 -0
- MindEyeV2/src/generative_models/sgm/__pycache__/__init__.cpython-310.pyc +0 -0
- MindEyeV2/src/generative_models/sgm/__pycache__/__init__.cpython-311.pyc +0 -0
- MindEyeV2/src/generative_models/sgm/__pycache__/util.cpython-310.pyc +0 -0
- MindEyeV2/src/generative_models/sgm/__pycache__/util.cpython-311.pyc +0 -0
- MindEyeV2/src/generative_models/sgm/data/__init__.py +1 -0
- MindEyeV2/src/generative_models/sgm/data/cifar10.py +67 -0
- MindEyeV2/src/generative_models/sgm/data/dataset.py +80 -0
- MindEyeV2/src/generative_models/sgm/data/mnist.py +85 -0
- MindEyeV2/src/generative_models/sgm/lr_scheduler.py +135 -0
- MindEyeV2/src/generative_models/sgm/modules/__init__.py +6 -0
- MindEyeV2/src/generative_models/sgm/modules/__pycache__/__init__.cpython-310.pyc +0 -0
- MindEyeV2/src/generative_models/sgm/modules/__pycache__/__init__.cpython-311.pyc +0 -0
- MindEyeV2/src/generative_models/sgm/modules/__pycache__/attention.cpython-310.pyc +0 -0
- MindEyeV2/src/generative_models/sgm/modules/__pycache__/attention.cpython-311.pyc +0 -0
- MindEyeV2/src/generative_models/sgm/modules/__pycache__/ema.cpython-310.pyc +0 -0
- MindEyeV2/src/generative_models/sgm/modules/__pycache__/ema.cpython-311.pyc +0 -0
- MindEyeV2/src/generative_models/sgm/modules/__pycache__/video_attention.cpython-310.pyc +0 -0
- MindEyeV2/src/generative_models/sgm/modules/__pycache__/video_attention.cpython-311.pyc +0 -0
- MindEyeV2/src/generative_models/sgm/modules/attention.py +759 -0
- MindEyeV2/src/generative_models/sgm/modules/autoencoding/__init__.py +0 -0
- MindEyeV2/src/generative_models/sgm/modules/autoencoding/__pycache__/__init__.cpython-310.pyc +0 -0
- MindEyeV2/src/generative_models/sgm/modules/autoencoding/__pycache__/__init__.cpython-311.pyc +0 -0
- MindEyeV2/src/generative_models/sgm/modules/autoencoding/__pycache__/temporal_ae.cpython-310.pyc +0 -0
- MindEyeV2/src/generative_models/sgm/modules/autoencoding/__pycache__/temporal_ae.cpython-311.pyc +0 -0
- MindEyeV2/src/generative_models/sgm/modules/autoencoding/losses/__init__.py +7 -0
- MindEyeV2/src/generative_models/sgm/modules/autoencoding/losses/discriminator_loss.py +306 -0
- MindEyeV2/src/generative_models/sgm/modules/autoencoding/losses/lpips.py +73 -0
- MindEyeV2/src/generative_models/sgm/modules/autoencoding/lpips/__init__.py +0 -0
- MindEyeV2/src/generative_models/sgm/modules/autoencoding/lpips/loss/.gitignore +1 -0
- MindEyeV2/src/generative_models/sgm/modules/autoencoding/lpips/loss/LICENSE +23 -0
- MindEyeV2/src/generative_models/sgm/modules/autoencoding/lpips/loss/__init__.py +0 -0
- MindEyeV2/src/generative_models/sgm/modules/autoencoding/lpips/loss/lpips.py +147 -0
- MindEyeV2/src/generative_models/sgm/modules/autoencoding/lpips/model/LICENSE +58 -0
- MindEyeV2/src/generative_models/sgm/modules/autoencoding/lpips/model/__init__.py +0 -0
- MindEyeV2/src/generative_models/sgm/modules/autoencoding/lpips/model/model.py +88 -0
- MindEyeV2/src/generative_models/sgm/modules/autoencoding/lpips/util.py +128 -0
- MindEyeV2/src/generative_models/sgm/modules/autoencoding/lpips/vqperceptual.py +17 -0
- MindEyeV2/src/generative_models/sgm/modules/autoencoding/regularizers/__init__.py +31 -0
- MindEyeV2/src/generative_models/sgm/modules/autoencoding/regularizers/__pycache__/__init__.cpython-310.pyc +0 -0
- MindEyeV2/src/generative_models/sgm/modules/autoencoding/regularizers/__pycache__/__init__.cpython-311.pyc +0 -0
- MindEyeV2/src/generative_models/sgm/modules/autoencoding/regularizers/__pycache__/base.cpython-310.pyc +0 -0
- MindEyeV2/src/generative_models/sgm/modules/autoencoding/regularizers/__pycache__/base.cpython-311.pyc +0 -0
- MindEyeV2/src/generative_models/sgm/modules/autoencoding/regularizers/base.py +40 -0
- MindEyeV2/src/generative_models/sgm/modules/autoencoding/regularizers/quantize.py +487 -0
- MindEyeV2/src/generative_models/sgm/modules/autoencoding/temporal_ae.py +349 -0
- MindEyeV2/src/generative_models/sgm/modules/diffusionmodules/__init__.py +0 -0
- 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
|
|
|