Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- MindEye_Imagery/src/generative_models/data/DejaVuSans.ttf +0 -0
- MindEye_Imagery/src/generative_models/scripts/demo/__init__.py +0 -0
- MindEye_Imagery/src/generative_models/scripts/demo/detect.py +156 -0
- MindEye_Imagery/src/generative_models/scripts/demo/discretization.py +59 -0
- MindEye_Imagery/src/generative_models/scripts/demo/sampling.py +364 -0
- MindEye_Imagery/src/generative_models/scripts/demo/streamlit_helpers.py +887 -0
- MindEye_Imagery/src/generative_models/scripts/demo/turbo.py +223 -0
- MindEye_Imagery/src/generative_models/scripts/demo/video_sampling.py +200 -0
- MindEye_Imagery/src/generative_models/scripts/sampling/configs/svd.yaml +146 -0
- MindEye_Imagery/src/generative_models/scripts/sampling/configs/svd_image_decoder.yaml +129 -0
- MindEye_Imagery/src/generative_models/scripts/sampling/configs/svd_xt.yaml +146 -0
- MindEye_Imagery/src/generative_models/scripts/sampling/configs/svd_xt_image_decoder.yaml +129 -0
- MindEye_Imagery/src/generative_models/scripts/sampling/simple_video_sample.py +278 -0
- MindEye_Imagery/src/generative_models/scripts/tests/attention.py +319 -0
- MindEye_Imagery/src/generative_models/scripts/util/detection/__init__.py +0 -0
- MindEye_Imagery/src/generative_models/scripts/util/detection/nsfw_and_watermark_dectection.py +110 -0
- MindEye_Imagery/src/vdvae/.ipynb_checkpoints/vae-checkpoint.py +252 -0
- MindEye_Imagery/src/vdvae/LICENSE.md +7 -0
- MindEye_Imagery/src/vdvae/README.md +103 -0
- MindEye_Imagery/src/vdvae/__pycache__/data.cpython-311.pyc +0 -0
- MindEye_Imagery/src/vdvae/__pycache__/hps.cpython-311.pyc +0 -0
- MindEye_Imagery/src/vdvae/__pycache__/image_utils.cpython-311.pyc +0 -0
- MindEye_Imagery/src/vdvae/__pycache__/model_utils.cpython-311.pyc +0 -0
- MindEye_Imagery/src/vdvae/__pycache__/train_helpers.cpython-311.pyc +0 -0
- MindEye_Imagery/src/vdvae/__pycache__/vae.cpython-311.pyc +0 -0
- MindEye_Imagery/src/vdvae/__pycache__/vae_helpers.cpython-311.pyc +0 -0
- MindEye_Imagery/src/vdvae/__pycache__/vdvae_utils.cpython-311.pyc +0 -0
- MindEye_Imagery/src/vdvae/data.py +163 -0
- MindEye_Imagery/src/vdvae/files_to_npy.py +14 -0
- MindEye_Imagery/src/vdvae/hps.py +159 -0
- MindEye_Imagery/src/vdvae/image_utils.py +68 -0
- MindEye_Imagery/src/vdvae/model_utils.py +102 -0
- MindEye_Imagery/src/vdvae/setup_cifar10.sh +2 -0
- MindEye_Imagery/src/vdvae/setup_ffhq1024.sh +13 -0
- MindEye_Imagery/src/vdvae/setup_ffhq256.sh +12 -0
- MindEye_Imagery/src/vdvae/setup_imagenet.sh +28 -0
- MindEye_Imagery/src/vdvae/train.py +136 -0
- MindEye_Imagery/src/vdvae/train_helpers.py +190 -0
- MindEye_Imagery/src/vdvae/vae.py +252 -0
- MindEye_Imagery/src/vdvae/vae_helpers.py +165 -0
- MindEye_Imagery/src/vdvae/vdvae_utils.py +140 -0
- spurious_reconstruction/.gitignore +13 -0
- spurious_reconstruction/README.md +58 -0
- spurious_reconstruction/analysis/0_preprocessing/.ipynb_checkpoints/extract_features-checkpoint.ipynb +437 -0
- spurious_reconstruction/analysis/0_preprocessing/.ipynb_checkpoints/iCNN_image_vgg19_feature_extraction-checkpoint.py +130 -0
- spurious_reconstruction/analysis/0_preprocessing/BD_extract_CLIP_vision_features.py +115 -0
- spurious_reconstruction/analysis/0_preprocessing/BD_extract_Deeprecon_CLIP_text_features.py +101 -0
- spurious_reconstruction/analysis/0_preprocessing/BD_extract_NSD_CLIP_text_features.py +78 -0
- spurious_reconstruction/analysis/0_preprocessing/README.md +15 -0
- spurious_reconstruction/analysis/0_preprocessing/config/Deeprecon/ArtificialShapes.yaml +34 -0
MindEye_Imagery/src/generative_models/data/DejaVuSans.ttf
ADDED
|
Binary file (757 kB). View file
|
|
|
MindEye_Imagery/src/generative_models/scripts/demo/__init__.py
ADDED
|
File without changes
|
MindEye_Imagery/src/generative_models/scripts/demo/detect.py
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import argparse
|
| 2 |
+
|
| 3 |
+
import cv2
|
| 4 |
+
import numpy as np
|
| 5 |
+
|
| 6 |
+
try:
|
| 7 |
+
from imwatermark import WatermarkDecoder
|
| 8 |
+
except ImportError as e:
|
| 9 |
+
try:
|
| 10 |
+
# Assume some of the other dependencies such as torch are not fulfilled
|
| 11 |
+
# import file without loading unnecessary libraries.
|
| 12 |
+
import importlib.util
|
| 13 |
+
import sys
|
| 14 |
+
|
| 15 |
+
spec = importlib.util.find_spec("imwatermark.maxDct")
|
| 16 |
+
assert spec is not None
|
| 17 |
+
maxDct = importlib.util.module_from_spec(spec)
|
| 18 |
+
sys.modules["maxDct"] = maxDct
|
| 19 |
+
spec.loader.exec_module(maxDct)
|
| 20 |
+
|
| 21 |
+
class WatermarkDecoder(object):
|
| 22 |
+
"""A minimal version of
|
| 23 |
+
https://github.com/ShieldMnt/invisible-watermark/blob/main/imwatermark/watermark.py
|
| 24 |
+
to only reconstruct bits using dwtDct"""
|
| 25 |
+
|
| 26 |
+
def __init__(self, wm_type="bytes", length=0):
|
| 27 |
+
assert wm_type == "bits", "Only bits defined in minimal import"
|
| 28 |
+
self._wmType = wm_type
|
| 29 |
+
self._wmLen = length
|
| 30 |
+
|
| 31 |
+
def reconstruct(self, bits):
|
| 32 |
+
if len(bits) != self._wmLen:
|
| 33 |
+
raise RuntimeError("bits are not matched with watermark length")
|
| 34 |
+
|
| 35 |
+
return bits
|
| 36 |
+
|
| 37 |
+
def decode(self, cv2Image, method="dwtDct", **configs):
|
| 38 |
+
(r, c, channels) = cv2Image.shape
|
| 39 |
+
if r * c < 256 * 256:
|
| 40 |
+
raise RuntimeError("image too small, should be larger than 256x256")
|
| 41 |
+
|
| 42 |
+
bits = []
|
| 43 |
+
assert method == "dwtDct"
|
| 44 |
+
embed = maxDct.EmbedMaxDct(watermarks=[], wmLen=self._wmLen, **configs)
|
| 45 |
+
bits = embed.decode(cv2Image)
|
| 46 |
+
return self.reconstruct(bits)
|
| 47 |
+
|
| 48 |
+
except:
|
| 49 |
+
raise e
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
# A fixed 48-bit message that was choosen at random
|
| 53 |
+
# WATERMARK_MESSAGE = 0xB3EC907BB19E
|
| 54 |
+
WATERMARK_MESSAGE = 0b101100111110110010010000011110111011000110011110
|
| 55 |
+
# bin(x)[2:] gives bits of x as str, use int to convert them to 0/1
|
| 56 |
+
WATERMARK_BITS = [int(bit) for bit in bin(WATERMARK_MESSAGE)[2:]]
|
| 57 |
+
MATCH_VALUES = [
|
| 58 |
+
[27, "No watermark detected"],
|
| 59 |
+
[33, "Partial watermark match. Cannot determine with certainty."],
|
| 60 |
+
[
|
| 61 |
+
35,
|
| 62 |
+
(
|
| 63 |
+
"Likely watermarked. In our test 0.02% of real images were "
|
| 64 |
+
'falsely detected as "Likely watermarked"'
|
| 65 |
+
),
|
| 66 |
+
],
|
| 67 |
+
[
|
| 68 |
+
49,
|
| 69 |
+
(
|
| 70 |
+
"Very likely watermarked. In our test no real images were "
|
| 71 |
+
'falsely detected as "Very likely watermarked"'
|
| 72 |
+
),
|
| 73 |
+
],
|
| 74 |
+
]
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
class GetWatermarkMatch:
|
| 78 |
+
def __init__(self, watermark):
|
| 79 |
+
self.watermark = watermark
|
| 80 |
+
self.num_bits = len(self.watermark)
|
| 81 |
+
self.decoder = WatermarkDecoder("bits", self.num_bits)
|
| 82 |
+
|
| 83 |
+
def __call__(self, x: np.ndarray) -> np.ndarray:
|
| 84 |
+
"""
|
| 85 |
+
Detects the number of matching bits the predefined watermark with one
|
| 86 |
+
or multiple images. Images should be in cv2 format, e.g. h x w x c BGR.
|
| 87 |
+
|
| 88 |
+
Args:
|
| 89 |
+
x: ([B], h w, c) in range [0, 255]
|
| 90 |
+
|
| 91 |
+
Returns:
|
| 92 |
+
number of matched bits ([B],)
|
| 93 |
+
"""
|
| 94 |
+
squeeze = len(x.shape) == 3
|
| 95 |
+
if squeeze:
|
| 96 |
+
x = x[None, ...]
|
| 97 |
+
|
| 98 |
+
bs = x.shape[0]
|
| 99 |
+
detected = np.empty((bs, self.num_bits), dtype=bool)
|
| 100 |
+
for k in range(bs):
|
| 101 |
+
detected[k] = self.decoder.decode(x[k], "dwtDct")
|
| 102 |
+
result = np.sum(detected == self.watermark, axis=-1)
|
| 103 |
+
if squeeze:
|
| 104 |
+
return result[0]
|
| 105 |
+
else:
|
| 106 |
+
return result
|
| 107 |
+
|
| 108 |
+
|
| 109 |
+
get_watermark_match = GetWatermarkMatch(WATERMARK_BITS)
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
if __name__ == "__main__":
|
| 113 |
+
parser = argparse.ArgumentParser()
|
| 114 |
+
parser.add_argument(
|
| 115 |
+
"filename",
|
| 116 |
+
nargs="+",
|
| 117 |
+
type=str,
|
| 118 |
+
help="Image files to check for watermarks",
|
| 119 |
+
)
|
| 120 |
+
opts = parser.parse_args()
|
| 121 |
+
|
| 122 |
+
print(
|
| 123 |
+
"""
|
| 124 |
+
This script tries to detect watermarked images. Please be aware of
|
| 125 |
+
the following:
|
| 126 |
+
- As the watermark is supposed to be invisible, there is the risk that
|
| 127 |
+
watermarked images may not be detected.
|
| 128 |
+
- To maximize the chance of detection make sure that the image has the same
|
| 129 |
+
dimensions as when the watermark was applied (most likely 1024x1024
|
| 130 |
+
or 512x512).
|
| 131 |
+
- Specific image manipulation may drastically decrease the chance that
|
| 132 |
+
watermarks can be detected.
|
| 133 |
+
- There is also the chance that an image has the characteristics of the
|
| 134 |
+
watermark by chance.
|
| 135 |
+
- The watermark script is public, anybody may watermark any images, and
|
| 136 |
+
could therefore claim it to be generated.
|
| 137 |
+
- All numbers below are based on a test using 10,000 images without any
|
| 138 |
+
modifications after applying the watermark.
|
| 139 |
+
"""
|
| 140 |
+
)
|
| 141 |
+
|
| 142 |
+
for fn in opts.filename:
|
| 143 |
+
image = cv2.imread(fn)
|
| 144 |
+
if image is None:
|
| 145 |
+
print(f"Couldn't read {fn}. Skipping")
|
| 146 |
+
continue
|
| 147 |
+
|
| 148 |
+
num_bits = get_watermark_match(image)
|
| 149 |
+
k = 0
|
| 150 |
+
while num_bits > MATCH_VALUES[k][0]:
|
| 151 |
+
k += 1
|
| 152 |
+
print(
|
| 153 |
+
f"{fn}: {MATCH_VALUES[k][1]}",
|
| 154 |
+
f"Bits that matched the watermark {num_bits} from {len(WATERMARK_BITS)}\n",
|
| 155 |
+
sep="\n\t",
|
| 156 |
+
)
|
MindEye_Imagery/src/generative_models/scripts/demo/discretization.py
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
|
| 3 |
+
from sgm.modules.diffusionmodules.discretizer import Discretization
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
class Img2ImgDiscretizationWrapper:
|
| 7 |
+
"""
|
| 8 |
+
wraps a discretizer, and prunes the sigmas
|
| 9 |
+
params:
|
| 10 |
+
strength: float between 0.0 and 1.0. 1.0 means full sampling (all sigmas are returned)
|
| 11 |
+
"""
|
| 12 |
+
|
| 13 |
+
def __init__(self, discretization: Discretization, strength: float = 1.0):
|
| 14 |
+
self.discretization = discretization
|
| 15 |
+
self.strength = strength
|
| 16 |
+
assert 0.0 <= self.strength <= 1.0
|
| 17 |
+
|
| 18 |
+
def __call__(self, *args, **kwargs):
|
| 19 |
+
# sigmas start large first, and decrease then
|
| 20 |
+
sigmas = self.discretization(*args, **kwargs)
|
| 21 |
+
print(f"sigmas after discretization, before pruning img2img: ", sigmas)
|
| 22 |
+
sigmas = torch.flip(sigmas, (0,))
|
| 23 |
+
sigmas = sigmas[: max(int(self.strength * len(sigmas)), 1)]
|
| 24 |
+
print("prune index:", max(int(self.strength * len(sigmas)), 1))
|
| 25 |
+
sigmas = torch.flip(sigmas, (0,))
|
| 26 |
+
print(f"sigmas after pruning: ", sigmas)
|
| 27 |
+
return sigmas
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
class Txt2NoisyDiscretizationWrapper:
|
| 31 |
+
"""
|
| 32 |
+
wraps a discretizer, and prunes the sigmas
|
| 33 |
+
params:
|
| 34 |
+
strength: float between 0.0 and 1.0. 0.0 means full sampling (all sigmas are returned)
|
| 35 |
+
"""
|
| 36 |
+
|
| 37 |
+
def __init__(
|
| 38 |
+
self, discretization: Discretization, strength: float = 0.0, original_steps=None
|
| 39 |
+
):
|
| 40 |
+
self.discretization = discretization
|
| 41 |
+
self.strength = strength
|
| 42 |
+
self.original_steps = original_steps
|
| 43 |
+
assert 0.0 <= self.strength <= 1.0
|
| 44 |
+
|
| 45 |
+
def __call__(self, *args, **kwargs):
|
| 46 |
+
# sigmas start large first, and decrease then
|
| 47 |
+
sigmas = self.discretization(*args, **kwargs)
|
| 48 |
+
print(f"sigmas after discretization, before pruning img2img: ", sigmas)
|
| 49 |
+
sigmas = torch.flip(sigmas, (0,))
|
| 50 |
+
if self.original_steps is None:
|
| 51 |
+
steps = len(sigmas)
|
| 52 |
+
else:
|
| 53 |
+
steps = self.original_steps + 1
|
| 54 |
+
prune_index = max(min(int(self.strength * steps) - 1, steps - 1), 0)
|
| 55 |
+
sigmas = sigmas[prune_index:]
|
| 56 |
+
print("prune index:", prune_index)
|
| 57 |
+
sigmas = torch.flip(sigmas, (0,))
|
| 58 |
+
print(f"sigmas after pruning: ", sigmas)
|
| 59 |
+
return sigmas
|
MindEye_Imagery/src/generative_models/scripts/demo/sampling.py
ADDED
|
@@ -0,0 +1,364 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from pytorch_lightning import seed_everything
|
| 2 |
+
|
| 3 |
+
from scripts.demo.streamlit_helpers import *
|
| 4 |
+
|
| 5 |
+
SAVE_PATH = "outputs/demo/txt2img/"
|
| 6 |
+
|
| 7 |
+
SD_XL_BASE_RATIOS = {
|
| 8 |
+
"0.5": (704, 1408),
|
| 9 |
+
"0.52": (704, 1344),
|
| 10 |
+
"0.57": (768, 1344),
|
| 11 |
+
"0.6": (768, 1280),
|
| 12 |
+
"0.68": (832, 1216),
|
| 13 |
+
"0.72": (832, 1152),
|
| 14 |
+
"0.78": (896, 1152),
|
| 15 |
+
"0.82": (896, 1088),
|
| 16 |
+
"0.88": (960, 1088),
|
| 17 |
+
"0.94": (960, 1024),
|
| 18 |
+
"1.0": (1024, 1024),
|
| 19 |
+
"1.07": (1024, 960),
|
| 20 |
+
"1.13": (1088, 960),
|
| 21 |
+
"1.21": (1088, 896),
|
| 22 |
+
"1.29": (1152, 896),
|
| 23 |
+
"1.38": (1152, 832),
|
| 24 |
+
"1.46": (1216, 832),
|
| 25 |
+
"1.67": (1280, 768),
|
| 26 |
+
"1.75": (1344, 768),
|
| 27 |
+
"1.91": (1344, 704),
|
| 28 |
+
"2.0": (1408, 704),
|
| 29 |
+
"2.09": (1472, 704),
|
| 30 |
+
"2.4": (1536, 640),
|
| 31 |
+
"2.5": (1600, 640),
|
| 32 |
+
"2.89": (1664, 576),
|
| 33 |
+
"3.0": (1728, 576),
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
VERSION2SPECS = {
|
| 37 |
+
"SDXL-base-1.0": {
|
| 38 |
+
"H": 1024,
|
| 39 |
+
"W": 1024,
|
| 40 |
+
"C": 4,
|
| 41 |
+
"f": 8,
|
| 42 |
+
"is_legacy": False,
|
| 43 |
+
"config": "configs/inference/sd_xl_base.yaml",
|
| 44 |
+
"ckpt": "checkpoints/sd_xl_base_1.0.safetensors",
|
| 45 |
+
},
|
| 46 |
+
"SDXL-base-0.9": {
|
| 47 |
+
"H": 1024,
|
| 48 |
+
"W": 1024,
|
| 49 |
+
"C": 4,
|
| 50 |
+
"f": 8,
|
| 51 |
+
"is_legacy": False,
|
| 52 |
+
"config": "configs/inference/sd_xl_base.yaml",
|
| 53 |
+
"ckpt": "checkpoints/sd_xl_base_0.9.safetensors",
|
| 54 |
+
},
|
| 55 |
+
"SD-2.1": {
|
| 56 |
+
"H": 512,
|
| 57 |
+
"W": 512,
|
| 58 |
+
"C": 4,
|
| 59 |
+
"f": 8,
|
| 60 |
+
"is_legacy": True,
|
| 61 |
+
"config": "configs/inference/sd_2_1.yaml",
|
| 62 |
+
"ckpt": "checkpoints/v2-1_512-ema-pruned.safetensors",
|
| 63 |
+
},
|
| 64 |
+
"SD-2.1-768": {
|
| 65 |
+
"H": 768,
|
| 66 |
+
"W": 768,
|
| 67 |
+
"C": 4,
|
| 68 |
+
"f": 8,
|
| 69 |
+
"is_legacy": True,
|
| 70 |
+
"config": "configs/inference/sd_2_1_768.yaml",
|
| 71 |
+
"ckpt": "checkpoints/v2-1_768-ema-pruned.safetensors",
|
| 72 |
+
},
|
| 73 |
+
"SDXL-refiner-0.9": {
|
| 74 |
+
"H": 1024,
|
| 75 |
+
"W": 1024,
|
| 76 |
+
"C": 4,
|
| 77 |
+
"f": 8,
|
| 78 |
+
"is_legacy": True,
|
| 79 |
+
"config": "configs/inference/sd_xl_refiner.yaml",
|
| 80 |
+
"ckpt": "checkpoints/sd_xl_refiner_0.9.safetensors",
|
| 81 |
+
},
|
| 82 |
+
"SDXL-refiner-1.0": {
|
| 83 |
+
"H": 1024,
|
| 84 |
+
"W": 1024,
|
| 85 |
+
"C": 4,
|
| 86 |
+
"f": 8,
|
| 87 |
+
"is_legacy": True,
|
| 88 |
+
"config": "configs/inference/sd_xl_refiner.yaml",
|
| 89 |
+
"ckpt": "checkpoints/sd_xl_refiner_1.0.safetensors",
|
| 90 |
+
},
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
def load_img(display=True, key=None, device="cuda"):
|
| 95 |
+
image = get_interactive_image(key=key)
|
| 96 |
+
if image is None:
|
| 97 |
+
return None
|
| 98 |
+
if display:
|
| 99 |
+
st.image(image)
|
| 100 |
+
w, h = image.size
|
| 101 |
+
print(f"loaded input image of size ({w}, {h})")
|
| 102 |
+
width, height = map(
|
| 103 |
+
lambda x: x - x % 64, (w, h)
|
| 104 |
+
) # resize to integer multiple of 64
|
| 105 |
+
image = image.resize((width, height))
|
| 106 |
+
image = np.array(image.convert("RGB"))
|
| 107 |
+
image = image[None].transpose(0, 3, 1, 2)
|
| 108 |
+
image = torch.from_numpy(image).to(dtype=torch.float32) / 127.5 - 1.0
|
| 109 |
+
return image.to(device)
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
def run_txt2img(
|
| 113 |
+
state,
|
| 114 |
+
version,
|
| 115 |
+
version_dict,
|
| 116 |
+
is_legacy=False,
|
| 117 |
+
return_latents=False,
|
| 118 |
+
filter=None,
|
| 119 |
+
stage2strength=None,
|
| 120 |
+
):
|
| 121 |
+
if version.startswith("SDXL-base"):
|
| 122 |
+
W, H = st.selectbox("Resolution:", list(SD_XL_BASE_RATIOS.values()), 10)
|
| 123 |
+
else:
|
| 124 |
+
H = st.number_input("H", value=version_dict["H"], min_value=64, max_value=2048)
|
| 125 |
+
W = st.number_input("W", value=version_dict["W"], min_value=64, max_value=2048)
|
| 126 |
+
C = version_dict["C"]
|
| 127 |
+
F = version_dict["f"]
|
| 128 |
+
|
| 129 |
+
init_dict = {
|
| 130 |
+
"orig_width": W,
|
| 131 |
+
"orig_height": H,
|
| 132 |
+
"target_width": W,
|
| 133 |
+
"target_height": H,
|
| 134 |
+
}
|
| 135 |
+
value_dict = init_embedder_options(
|
| 136 |
+
get_unique_embedder_keys_from_conditioner(state["model"].conditioner),
|
| 137 |
+
init_dict,
|
| 138 |
+
prompt=prompt,
|
| 139 |
+
negative_prompt=negative_prompt,
|
| 140 |
+
)
|
| 141 |
+
sampler, num_rows, num_cols = init_sampling(stage2strength=stage2strength)
|
| 142 |
+
num_samples = num_rows * num_cols
|
| 143 |
+
|
| 144 |
+
if st.button("Sample"):
|
| 145 |
+
st.write(f"**Model I:** {version}")
|
| 146 |
+
out = do_sample(
|
| 147 |
+
state["model"],
|
| 148 |
+
sampler,
|
| 149 |
+
value_dict,
|
| 150 |
+
num_samples,
|
| 151 |
+
H,
|
| 152 |
+
W,
|
| 153 |
+
C,
|
| 154 |
+
F,
|
| 155 |
+
force_uc_zero_embeddings=["txt"] if not is_legacy else [],
|
| 156 |
+
return_latents=return_latents,
|
| 157 |
+
filter=filter,
|
| 158 |
+
)
|
| 159 |
+
return out
|
| 160 |
+
|
| 161 |
+
|
| 162 |
+
def run_img2img(
|
| 163 |
+
state,
|
| 164 |
+
version_dict,
|
| 165 |
+
is_legacy=False,
|
| 166 |
+
return_latents=False,
|
| 167 |
+
filter=None,
|
| 168 |
+
stage2strength=None,
|
| 169 |
+
):
|
| 170 |
+
img = load_img()
|
| 171 |
+
if img is None:
|
| 172 |
+
return None
|
| 173 |
+
H, W = img.shape[2], img.shape[3]
|
| 174 |
+
|
| 175 |
+
init_dict = {
|
| 176 |
+
"orig_width": W,
|
| 177 |
+
"orig_height": H,
|
| 178 |
+
"target_width": W,
|
| 179 |
+
"target_height": H,
|
| 180 |
+
}
|
| 181 |
+
value_dict = init_embedder_options(
|
| 182 |
+
get_unique_embedder_keys_from_conditioner(state["model"].conditioner),
|
| 183 |
+
init_dict,
|
| 184 |
+
prompt=prompt,
|
| 185 |
+
negative_prompt=negative_prompt,
|
| 186 |
+
)
|
| 187 |
+
strength = st.number_input(
|
| 188 |
+
"**Img2Img Strength**", value=0.75, min_value=0.0, max_value=1.0
|
| 189 |
+
)
|
| 190 |
+
sampler, num_rows, num_cols = init_sampling(
|
| 191 |
+
img2img_strength=strength,
|
| 192 |
+
stage2strength=stage2strength,
|
| 193 |
+
)
|
| 194 |
+
num_samples = num_rows * num_cols
|
| 195 |
+
|
| 196 |
+
if st.button("Sample"):
|
| 197 |
+
out = do_img2img(
|
| 198 |
+
repeat(img, "1 ... -> n ...", n=num_samples),
|
| 199 |
+
state["model"],
|
| 200 |
+
sampler,
|
| 201 |
+
value_dict,
|
| 202 |
+
num_samples,
|
| 203 |
+
force_uc_zero_embeddings=["txt"] if not is_legacy else [],
|
| 204 |
+
return_latents=return_latents,
|
| 205 |
+
filter=filter,
|
| 206 |
+
)
|
| 207 |
+
return out
|
| 208 |
+
|
| 209 |
+
|
| 210 |
+
def apply_refiner(
|
| 211 |
+
input,
|
| 212 |
+
state,
|
| 213 |
+
sampler,
|
| 214 |
+
num_samples,
|
| 215 |
+
prompt,
|
| 216 |
+
negative_prompt,
|
| 217 |
+
filter=None,
|
| 218 |
+
finish_denoising=False,
|
| 219 |
+
):
|
| 220 |
+
init_dict = {
|
| 221 |
+
"orig_width": input.shape[3] * 8,
|
| 222 |
+
"orig_height": input.shape[2] * 8,
|
| 223 |
+
"target_width": input.shape[3] * 8,
|
| 224 |
+
"target_height": input.shape[2] * 8,
|
| 225 |
+
}
|
| 226 |
+
|
| 227 |
+
value_dict = init_dict
|
| 228 |
+
value_dict["prompt"] = prompt
|
| 229 |
+
value_dict["negative_prompt"] = negative_prompt
|
| 230 |
+
|
| 231 |
+
value_dict["crop_coords_top"] = 0
|
| 232 |
+
value_dict["crop_coords_left"] = 0
|
| 233 |
+
|
| 234 |
+
value_dict["aesthetic_score"] = 6.0
|
| 235 |
+
value_dict["negative_aesthetic_score"] = 2.5
|
| 236 |
+
|
| 237 |
+
st.warning(f"refiner input shape: {input.shape}")
|
| 238 |
+
samples = do_img2img(
|
| 239 |
+
input,
|
| 240 |
+
state["model"],
|
| 241 |
+
sampler,
|
| 242 |
+
value_dict,
|
| 243 |
+
num_samples,
|
| 244 |
+
skip_encode=True,
|
| 245 |
+
filter=filter,
|
| 246 |
+
add_noise=not finish_denoising,
|
| 247 |
+
)
|
| 248 |
+
|
| 249 |
+
return samples
|
| 250 |
+
|
| 251 |
+
|
| 252 |
+
if __name__ == "__main__":
|
| 253 |
+
st.title("Stable Diffusion")
|
| 254 |
+
version = st.selectbox("Model Version", list(VERSION2SPECS.keys()), 0)
|
| 255 |
+
version_dict = VERSION2SPECS[version]
|
| 256 |
+
if st.checkbox("Load Model"):
|
| 257 |
+
mode = st.radio("Mode", ("txt2img", "img2img"), 0)
|
| 258 |
+
else:
|
| 259 |
+
mode = "skip"
|
| 260 |
+
st.write("__________________________")
|
| 261 |
+
|
| 262 |
+
set_lowvram_mode(st.checkbox("Low vram mode", True))
|
| 263 |
+
|
| 264 |
+
if version.startswith("SDXL-base"):
|
| 265 |
+
add_pipeline = st.checkbox("Load SDXL-refiner?", False)
|
| 266 |
+
st.write("__________________________")
|
| 267 |
+
else:
|
| 268 |
+
add_pipeline = False
|
| 269 |
+
|
| 270 |
+
seed = st.sidebar.number_input("seed", value=42, min_value=0, max_value=int(1e9))
|
| 271 |
+
seed_everything(seed)
|
| 272 |
+
|
| 273 |
+
save_locally, save_path = init_save_locally(os.path.join(SAVE_PATH, version))
|
| 274 |
+
|
| 275 |
+
if mode != "skip":
|
| 276 |
+
state = init_st(version_dict, load_filter=True)
|
| 277 |
+
if state["msg"]:
|
| 278 |
+
st.info(state["msg"])
|
| 279 |
+
model = state["model"]
|
| 280 |
+
|
| 281 |
+
is_legacy = version_dict["is_legacy"]
|
| 282 |
+
|
| 283 |
+
prompt = st.text_input(
|
| 284 |
+
"prompt",
|
| 285 |
+
"Astronaut in a jungle, cold color palette, muted colors, detailed, 8k",
|
| 286 |
+
)
|
| 287 |
+
if is_legacy:
|
| 288 |
+
negative_prompt = st.text_input("negative prompt", "")
|
| 289 |
+
else:
|
| 290 |
+
negative_prompt = "" # which is unused
|
| 291 |
+
|
| 292 |
+
stage2strength = None
|
| 293 |
+
finish_denoising = False
|
| 294 |
+
|
| 295 |
+
if add_pipeline:
|
| 296 |
+
st.write("__________________________")
|
| 297 |
+
version2 = st.selectbox("Refiner:", ["SDXL-refiner-1.0", "SDXL-refiner-0.9"])
|
| 298 |
+
st.warning(
|
| 299 |
+
f"Running with {version2} as the second stage model. Make sure to provide (V)RAM :) "
|
| 300 |
+
)
|
| 301 |
+
st.write("**Refiner Options:**")
|
| 302 |
+
|
| 303 |
+
version_dict2 = VERSION2SPECS[version2]
|
| 304 |
+
state2 = init_st(version_dict2, load_filter=False)
|
| 305 |
+
st.info(state2["msg"])
|
| 306 |
+
|
| 307 |
+
stage2strength = st.number_input(
|
| 308 |
+
"**Refinement strength**", value=0.15, min_value=0.0, max_value=1.0
|
| 309 |
+
)
|
| 310 |
+
|
| 311 |
+
sampler2, *_ = init_sampling(
|
| 312 |
+
key=2,
|
| 313 |
+
img2img_strength=stage2strength,
|
| 314 |
+
specify_num_samples=False,
|
| 315 |
+
)
|
| 316 |
+
st.write("__________________________")
|
| 317 |
+
finish_denoising = st.checkbox("Finish denoising with refiner.", True)
|
| 318 |
+
if not finish_denoising:
|
| 319 |
+
stage2strength = None
|
| 320 |
+
|
| 321 |
+
if mode == "txt2img":
|
| 322 |
+
out = run_txt2img(
|
| 323 |
+
state,
|
| 324 |
+
version,
|
| 325 |
+
version_dict,
|
| 326 |
+
is_legacy=is_legacy,
|
| 327 |
+
return_latents=add_pipeline,
|
| 328 |
+
filter=state.get("filter"),
|
| 329 |
+
stage2strength=stage2strength,
|
| 330 |
+
)
|
| 331 |
+
elif mode == "img2img":
|
| 332 |
+
out = run_img2img(
|
| 333 |
+
state,
|
| 334 |
+
version_dict,
|
| 335 |
+
is_legacy=is_legacy,
|
| 336 |
+
return_latents=add_pipeline,
|
| 337 |
+
filter=state.get("filter"),
|
| 338 |
+
stage2strength=stage2strength,
|
| 339 |
+
)
|
| 340 |
+
elif mode == "skip":
|
| 341 |
+
out = None
|
| 342 |
+
else:
|
| 343 |
+
raise ValueError(f"unknown mode {mode}")
|
| 344 |
+
if isinstance(out, (tuple, list)):
|
| 345 |
+
samples, samples_z = out
|
| 346 |
+
else:
|
| 347 |
+
samples = out
|
| 348 |
+
samples_z = None
|
| 349 |
+
|
| 350 |
+
if add_pipeline and samples_z is not None:
|
| 351 |
+
st.write("**Running Refinement Stage**")
|
| 352 |
+
samples = apply_refiner(
|
| 353 |
+
samples_z,
|
| 354 |
+
state2,
|
| 355 |
+
sampler2,
|
| 356 |
+
samples_z.shape[0],
|
| 357 |
+
prompt=prompt,
|
| 358 |
+
negative_prompt=negative_prompt if is_legacy else "",
|
| 359 |
+
filter=state.get("filter"),
|
| 360 |
+
finish_denoising=finish_denoising,
|
| 361 |
+
)
|
| 362 |
+
|
| 363 |
+
if save_locally and samples is not None:
|
| 364 |
+
perform_save_locally(save_path, samples)
|
MindEye_Imagery/src/generative_models/scripts/demo/streamlit_helpers.py
ADDED
|
@@ -0,0 +1,887 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import copy
|
| 2 |
+
import math
|
| 3 |
+
import os
|
| 4 |
+
from glob import glob
|
| 5 |
+
from typing import Dict, List, Optional, Tuple, Union
|
| 6 |
+
|
| 7 |
+
import cv2
|
| 8 |
+
import numpy as np
|
| 9 |
+
import streamlit as st
|
| 10 |
+
import torch
|
| 11 |
+
import torch.nn as nn
|
| 12 |
+
import torchvision.transforms as TT
|
| 13 |
+
from einops import rearrange, repeat
|
| 14 |
+
from imwatermark import WatermarkEncoder
|
| 15 |
+
from omegaconf import ListConfig, OmegaConf
|
| 16 |
+
from PIL import Image
|
| 17 |
+
from safetensors.torch import load_file as load_safetensors
|
| 18 |
+
from torch import autocast
|
| 19 |
+
from torchvision import transforms
|
| 20 |
+
from torchvision.utils import make_grid, save_image
|
| 21 |
+
|
| 22 |
+
from scripts.demo.discretization import (Img2ImgDiscretizationWrapper,
|
| 23 |
+
Txt2NoisyDiscretizationWrapper)
|
| 24 |
+
from scripts.util.detection.nsfw_and_watermark_dectection import \
|
| 25 |
+
DeepFloydDataFiltering
|
| 26 |
+
from sgm.inference.helpers import embed_watermark
|
| 27 |
+
from sgm.modules.diffusionmodules.guiders import (LinearPredictionGuider,
|
| 28 |
+
VanillaCFG)
|
| 29 |
+
from sgm.modules.diffusionmodules.sampling import (DPMPP2MSampler,
|
| 30 |
+
DPMPP2SAncestralSampler,
|
| 31 |
+
EulerAncestralSampler,
|
| 32 |
+
EulerEDMSampler,
|
| 33 |
+
HeunEDMSampler,
|
| 34 |
+
LinearMultistepSampler)
|
| 35 |
+
from sgm.util import append_dims, default, instantiate_from_config
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
@st.cache_resource()
|
| 39 |
+
def init_st(version_dict, load_ckpt=True, load_filter=True):
|
| 40 |
+
state = dict()
|
| 41 |
+
if not "model" in state:
|
| 42 |
+
config = version_dict["config"]
|
| 43 |
+
ckpt = version_dict["ckpt"]
|
| 44 |
+
|
| 45 |
+
config = OmegaConf.load(config)
|
| 46 |
+
model, msg = load_model_from_config(config, ckpt if load_ckpt else None)
|
| 47 |
+
|
| 48 |
+
state["msg"] = msg
|
| 49 |
+
state["model"] = model
|
| 50 |
+
state["ckpt"] = ckpt if load_ckpt else None
|
| 51 |
+
state["config"] = config
|
| 52 |
+
if load_filter:
|
| 53 |
+
state["filter"] = DeepFloydDataFiltering(verbose=False)
|
| 54 |
+
return state
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
def load_model(model):
|
| 58 |
+
model.cuda()
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
lowvram_mode = False
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
def set_lowvram_mode(mode):
|
| 65 |
+
global lowvram_mode
|
| 66 |
+
lowvram_mode = mode
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
def initial_model_load(model):
|
| 70 |
+
global lowvram_mode
|
| 71 |
+
if lowvram_mode:
|
| 72 |
+
model.model.half()
|
| 73 |
+
else:
|
| 74 |
+
model.cuda()
|
| 75 |
+
return model
|
| 76 |
+
|
| 77 |
+
|
| 78 |
+
def unload_model(model):
|
| 79 |
+
global lowvram_mode
|
| 80 |
+
if lowvram_mode:
|
| 81 |
+
model.cpu()
|
| 82 |
+
torch.cuda.empty_cache()
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
def load_model_from_config(config, ckpt=None, verbose=True):
|
| 86 |
+
model = instantiate_from_config(config.model)
|
| 87 |
+
|
| 88 |
+
if ckpt is not None:
|
| 89 |
+
print(f"Loading model from {ckpt}")
|
| 90 |
+
if ckpt.endswith("ckpt"):
|
| 91 |
+
pl_sd = torch.load(ckpt, map_location="cpu")
|
| 92 |
+
if "global_step" in pl_sd:
|
| 93 |
+
global_step = pl_sd["global_step"]
|
| 94 |
+
st.info(f"loaded ckpt from global step {global_step}")
|
| 95 |
+
print(f"Global Step: {pl_sd['global_step']}")
|
| 96 |
+
sd = pl_sd["state_dict"]
|
| 97 |
+
elif ckpt.endswith("safetensors"):
|
| 98 |
+
sd = load_safetensors(ckpt)
|
| 99 |
+
else:
|
| 100 |
+
raise NotImplementedError
|
| 101 |
+
|
| 102 |
+
msg = None
|
| 103 |
+
|
| 104 |
+
m, u = model.load_state_dict(sd, strict=False)
|
| 105 |
+
|
| 106 |
+
if len(m) > 0 and verbose:
|
| 107 |
+
print("missing keys:")
|
| 108 |
+
print(m)
|
| 109 |
+
if len(u) > 0 and verbose:
|
| 110 |
+
print("unexpected keys:")
|
| 111 |
+
print(u)
|
| 112 |
+
else:
|
| 113 |
+
msg = None
|
| 114 |
+
|
| 115 |
+
model = initial_model_load(model)
|
| 116 |
+
model.eval()
|
| 117 |
+
return model, msg
|
| 118 |
+
|
| 119 |
+
|
| 120 |
+
def get_unique_embedder_keys_from_conditioner(conditioner):
|
| 121 |
+
return list(set([x.input_key for x in conditioner.embedders]))
|
| 122 |
+
|
| 123 |
+
|
| 124 |
+
def init_embedder_options(keys, init_dict, prompt=None, negative_prompt=None):
|
| 125 |
+
# Hardcoded demo settings; might undergo some changes in the future
|
| 126 |
+
|
| 127 |
+
value_dict = {}
|
| 128 |
+
for key in keys:
|
| 129 |
+
if key == "txt":
|
| 130 |
+
if prompt is None:
|
| 131 |
+
prompt = "A professional photograph of an astronaut riding a pig"
|
| 132 |
+
if negative_prompt is None:
|
| 133 |
+
negative_prompt = ""
|
| 134 |
+
|
| 135 |
+
prompt = st.text_input("Prompt", prompt)
|
| 136 |
+
negative_prompt = st.text_input("Negative prompt", negative_prompt)
|
| 137 |
+
|
| 138 |
+
value_dict["prompt"] = prompt
|
| 139 |
+
value_dict["negative_prompt"] = negative_prompt
|
| 140 |
+
|
| 141 |
+
if key == "original_size_as_tuple":
|
| 142 |
+
orig_width = st.number_input(
|
| 143 |
+
"orig_width",
|
| 144 |
+
value=init_dict["orig_width"],
|
| 145 |
+
min_value=16,
|
| 146 |
+
)
|
| 147 |
+
orig_height = st.number_input(
|
| 148 |
+
"orig_height",
|
| 149 |
+
value=init_dict["orig_height"],
|
| 150 |
+
min_value=16,
|
| 151 |
+
)
|
| 152 |
+
|
| 153 |
+
value_dict["orig_width"] = orig_width
|
| 154 |
+
value_dict["orig_height"] = orig_height
|
| 155 |
+
|
| 156 |
+
if key == "crop_coords_top_left":
|
| 157 |
+
crop_coord_top = st.number_input("crop_coords_top", value=0, min_value=0)
|
| 158 |
+
crop_coord_left = st.number_input("crop_coords_left", value=0, min_value=0)
|
| 159 |
+
|
| 160 |
+
value_dict["crop_coords_top"] = crop_coord_top
|
| 161 |
+
value_dict["crop_coords_left"] = crop_coord_left
|
| 162 |
+
|
| 163 |
+
if key == "aesthetic_score":
|
| 164 |
+
value_dict["aesthetic_score"] = 6.0
|
| 165 |
+
value_dict["negative_aesthetic_score"] = 2.5
|
| 166 |
+
|
| 167 |
+
if key == "target_size_as_tuple":
|
| 168 |
+
value_dict["target_width"] = init_dict["target_width"]
|
| 169 |
+
value_dict["target_height"] = init_dict["target_height"]
|
| 170 |
+
|
| 171 |
+
if key in ["fps_id", "fps"]:
|
| 172 |
+
fps = st.number_input("fps", value=6, min_value=1)
|
| 173 |
+
|
| 174 |
+
value_dict["fps"] = fps
|
| 175 |
+
value_dict["fps_id"] = fps - 1
|
| 176 |
+
|
| 177 |
+
if key == "motion_bucket_id":
|
| 178 |
+
mb_id = st.number_input("motion bucket id", 0, 511, value=127)
|
| 179 |
+
value_dict["motion_bucket_id"] = mb_id
|
| 180 |
+
|
| 181 |
+
if key == "pool_image":
|
| 182 |
+
st.text("Image for pool conditioning")
|
| 183 |
+
image = load_img(
|
| 184 |
+
key="pool_image_input",
|
| 185 |
+
size=224,
|
| 186 |
+
center_crop=True,
|
| 187 |
+
)
|
| 188 |
+
if image is None:
|
| 189 |
+
st.info("Need an image here")
|
| 190 |
+
image = torch.zeros(1, 3, 224, 224)
|
| 191 |
+
value_dict["pool_image"] = image
|
| 192 |
+
|
| 193 |
+
return value_dict
|
| 194 |
+
|
| 195 |
+
|
| 196 |
+
def perform_save_locally(save_path, samples):
|
| 197 |
+
os.makedirs(os.path.join(save_path), exist_ok=True)
|
| 198 |
+
base_count = len(os.listdir(os.path.join(save_path)))
|
| 199 |
+
samples = embed_watermark(samples)
|
| 200 |
+
for sample in samples:
|
| 201 |
+
sample = 255.0 * rearrange(sample.cpu().numpy(), "c h w -> h w c")
|
| 202 |
+
Image.fromarray(sample.astype(np.uint8)).save(
|
| 203 |
+
os.path.join(save_path, f"{base_count:09}.png")
|
| 204 |
+
)
|
| 205 |
+
base_count += 1
|
| 206 |
+
|
| 207 |
+
|
| 208 |
+
def init_save_locally(_dir, init_value: bool = False):
|
| 209 |
+
save_locally = st.sidebar.checkbox("Save images locally", value=init_value)
|
| 210 |
+
if save_locally:
|
| 211 |
+
save_path = st.text_input("Save path", value=os.path.join(_dir, "samples"))
|
| 212 |
+
else:
|
| 213 |
+
save_path = None
|
| 214 |
+
|
| 215 |
+
return save_locally, save_path
|
| 216 |
+
|
| 217 |
+
|
| 218 |
+
def get_guider(options, key):
|
| 219 |
+
guider = st.sidebar.selectbox(
|
| 220 |
+
f"Discretization #{key}",
|
| 221 |
+
[
|
| 222 |
+
"VanillaCFG",
|
| 223 |
+
"IdentityGuider",
|
| 224 |
+
"LinearPredictionGuider",
|
| 225 |
+
],
|
| 226 |
+
options.get("guider", 0),
|
| 227 |
+
)
|
| 228 |
+
|
| 229 |
+
additional_guider_kwargs = options.pop("additional_guider_kwargs", {})
|
| 230 |
+
|
| 231 |
+
if guider == "IdentityGuider":
|
| 232 |
+
guider_config = {
|
| 233 |
+
"target": "sgm.modules.diffusionmodules.guiders.IdentityGuider"
|
| 234 |
+
}
|
| 235 |
+
elif guider == "VanillaCFG":
|
| 236 |
+
scale = st.number_input(
|
| 237 |
+
f"cfg-scale #{key}",
|
| 238 |
+
value=options.get("cfg", 5.0),
|
| 239 |
+
min_value=0.0,
|
| 240 |
+
)
|
| 241 |
+
|
| 242 |
+
guider_config = {
|
| 243 |
+
"target": "sgm.modules.diffusionmodules.guiders.VanillaCFG",
|
| 244 |
+
"params": {
|
| 245 |
+
"scale": scale,
|
| 246 |
+
**additional_guider_kwargs,
|
| 247 |
+
},
|
| 248 |
+
}
|
| 249 |
+
elif guider == "LinearPredictionGuider":
|
| 250 |
+
max_scale = st.number_input(
|
| 251 |
+
f"max-cfg-scale #{key}",
|
| 252 |
+
value=options.get("cfg", 1.5),
|
| 253 |
+
min_value=1.0,
|
| 254 |
+
)
|
| 255 |
+
min_scale = st.number_input(
|
| 256 |
+
f"min guidance scale",
|
| 257 |
+
value=options.get("min_cfg", 1.0),
|
| 258 |
+
min_value=1.0,
|
| 259 |
+
max_value=10.0,
|
| 260 |
+
)
|
| 261 |
+
|
| 262 |
+
guider_config = {
|
| 263 |
+
"target": "sgm.modules.diffusionmodules.guiders.LinearPredictionGuider",
|
| 264 |
+
"params": {
|
| 265 |
+
"max_scale": max_scale,
|
| 266 |
+
"min_scale": min_scale,
|
| 267 |
+
"num_frames": options["num_frames"],
|
| 268 |
+
**additional_guider_kwargs,
|
| 269 |
+
},
|
| 270 |
+
}
|
| 271 |
+
else:
|
| 272 |
+
raise NotImplementedError
|
| 273 |
+
return guider_config
|
| 274 |
+
|
| 275 |
+
|
| 276 |
+
def init_sampling(
|
| 277 |
+
key=1,
|
| 278 |
+
img2img_strength: Optional[float] = None,
|
| 279 |
+
specify_num_samples: bool = True,
|
| 280 |
+
stage2strength: Optional[float] = None,
|
| 281 |
+
options: Optional[Dict[str, int]] = None,
|
| 282 |
+
):
|
| 283 |
+
options = {} if options is None else options
|
| 284 |
+
|
| 285 |
+
num_rows, num_cols = 1, 1
|
| 286 |
+
if specify_num_samples:
|
| 287 |
+
num_cols = st.number_input(
|
| 288 |
+
f"num cols #{key}", value=num_cols, min_value=1, max_value=10
|
| 289 |
+
)
|
| 290 |
+
|
| 291 |
+
steps = st.sidebar.number_input(
|
| 292 |
+
f"steps #{key}", value=options.get("num_steps", 40), min_value=1, max_value=1000
|
| 293 |
+
)
|
| 294 |
+
sampler = st.sidebar.selectbox(
|
| 295 |
+
f"Sampler #{key}",
|
| 296 |
+
[
|
| 297 |
+
"EulerEDMSampler",
|
| 298 |
+
"HeunEDMSampler",
|
| 299 |
+
"EulerAncestralSampler",
|
| 300 |
+
"DPMPP2SAncestralSampler",
|
| 301 |
+
"DPMPP2MSampler",
|
| 302 |
+
"LinearMultistepSampler",
|
| 303 |
+
],
|
| 304 |
+
options.get("sampler", 0),
|
| 305 |
+
)
|
| 306 |
+
discretization = st.sidebar.selectbox(
|
| 307 |
+
f"Discretization #{key}",
|
| 308 |
+
[
|
| 309 |
+
"LegacyDDPMDiscretization",
|
| 310 |
+
"EDMDiscretization",
|
| 311 |
+
],
|
| 312 |
+
options.get("discretization", 0),
|
| 313 |
+
)
|
| 314 |
+
|
| 315 |
+
discretization_config = get_discretization(discretization, options=options, key=key)
|
| 316 |
+
|
| 317 |
+
guider_config = get_guider(options=options, key=key)
|
| 318 |
+
|
| 319 |
+
sampler = get_sampler(sampler, steps, discretization_config, guider_config, key=key)
|
| 320 |
+
if img2img_strength is not None:
|
| 321 |
+
st.warning(
|
| 322 |
+
f"Wrapping {sampler.__class__.__name__} with Img2ImgDiscretizationWrapper"
|
| 323 |
+
)
|
| 324 |
+
sampler.discretization = Img2ImgDiscretizationWrapper(
|
| 325 |
+
sampler.discretization, strength=img2img_strength
|
| 326 |
+
)
|
| 327 |
+
if stage2strength is not None:
|
| 328 |
+
sampler.discretization = Txt2NoisyDiscretizationWrapper(
|
| 329 |
+
sampler.discretization, strength=stage2strength, original_steps=steps
|
| 330 |
+
)
|
| 331 |
+
return sampler, num_rows, num_cols
|
| 332 |
+
|
| 333 |
+
|
| 334 |
+
def get_discretization(discretization, options, key=1):
|
| 335 |
+
if discretization == "LegacyDDPMDiscretization":
|
| 336 |
+
discretization_config = {
|
| 337 |
+
"target": "sgm.modules.diffusionmodules.discretizer.LegacyDDPMDiscretization",
|
| 338 |
+
}
|
| 339 |
+
elif discretization == "EDMDiscretization":
|
| 340 |
+
sigma_min = st.number_input(
|
| 341 |
+
f"sigma_min #{key}", value=options.get("sigma_min", 0.03)
|
| 342 |
+
) # 0.0292
|
| 343 |
+
sigma_max = st.number_input(
|
| 344 |
+
f"sigma_max #{key}", value=options.get("sigma_max", 14.61)
|
| 345 |
+
) # 14.6146
|
| 346 |
+
rho = st.number_input(f"rho #{key}", value=options.get("rho", 3.0))
|
| 347 |
+
discretization_config = {
|
| 348 |
+
"target": "sgm.modules.diffusionmodules.discretizer.EDMDiscretization",
|
| 349 |
+
"params": {
|
| 350 |
+
"sigma_min": sigma_min,
|
| 351 |
+
"sigma_max": sigma_max,
|
| 352 |
+
"rho": rho,
|
| 353 |
+
},
|
| 354 |
+
}
|
| 355 |
+
|
| 356 |
+
return discretization_config
|
| 357 |
+
|
| 358 |
+
|
| 359 |
+
def get_sampler(sampler_name, steps, discretization_config, guider_config, key=1):
|
| 360 |
+
if sampler_name == "EulerEDMSampler" or sampler_name == "HeunEDMSampler":
|
| 361 |
+
s_churn = st.sidebar.number_input(f"s_churn #{key}", value=0.0, min_value=0.0)
|
| 362 |
+
s_tmin = st.sidebar.number_input(f"s_tmin #{key}", value=0.0, min_value=0.0)
|
| 363 |
+
s_tmax = st.sidebar.number_input(f"s_tmax #{key}", value=999.0, min_value=0.0)
|
| 364 |
+
s_noise = st.sidebar.number_input(f"s_noise #{key}", value=1.0, min_value=0.0)
|
| 365 |
+
|
| 366 |
+
if sampler_name == "EulerEDMSampler":
|
| 367 |
+
sampler = EulerEDMSampler(
|
| 368 |
+
num_steps=steps,
|
| 369 |
+
discretization_config=discretization_config,
|
| 370 |
+
guider_config=guider_config,
|
| 371 |
+
s_churn=s_churn,
|
| 372 |
+
s_tmin=s_tmin,
|
| 373 |
+
s_tmax=s_tmax,
|
| 374 |
+
s_noise=s_noise,
|
| 375 |
+
verbose=True,
|
| 376 |
+
)
|
| 377 |
+
elif sampler_name == "HeunEDMSampler":
|
| 378 |
+
sampler = HeunEDMSampler(
|
| 379 |
+
num_steps=steps,
|
| 380 |
+
discretization_config=discretization_config,
|
| 381 |
+
guider_config=guider_config,
|
| 382 |
+
s_churn=s_churn,
|
| 383 |
+
s_tmin=s_tmin,
|
| 384 |
+
s_tmax=s_tmax,
|
| 385 |
+
s_noise=s_noise,
|
| 386 |
+
verbose=True,
|
| 387 |
+
)
|
| 388 |
+
elif (
|
| 389 |
+
sampler_name == "EulerAncestralSampler"
|
| 390 |
+
or sampler_name == "DPMPP2SAncestralSampler"
|
| 391 |
+
):
|
| 392 |
+
s_noise = st.sidebar.number_input("s_noise", value=1.0, min_value=0.0)
|
| 393 |
+
eta = st.sidebar.number_input("eta", value=1.0, min_value=0.0)
|
| 394 |
+
|
| 395 |
+
if sampler_name == "EulerAncestralSampler":
|
| 396 |
+
sampler = EulerAncestralSampler(
|
| 397 |
+
num_steps=steps,
|
| 398 |
+
discretization_config=discretization_config,
|
| 399 |
+
guider_config=guider_config,
|
| 400 |
+
eta=eta,
|
| 401 |
+
s_noise=s_noise,
|
| 402 |
+
verbose=True,
|
| 403 |
+
)
|
| 404 |
+
elif sampler_name == "DPMPP2SAncestralSampler":
|
| 405 |
+
sampler = DPMPP2SAncestralSampler(
|
| 406 |
+
num_steps=steps,
|
| 407 |
+
discretization_config=discretization_config,
|
| 408 |
+
guider_config=guider_config,
|
| 409 |
+
eta=eta,
|
| 410 |
+
s_noise=s_noise,
|
| 411 |
+
verbose=True,
|
| 412 |
+
)
|
| 413 |
+
elif sampler_name == "DPMPP2MSampler":
|
| 414 |
+
sampler = DPMPP2MSampler(
|
| 415 |
+
num_steps=steps,
|
| 416 |
+
discretization_config=discretization_config,
|
| 417 |
+
guider_config=guider_config,
|
| 418 |
+
verbose=True,
|
| 419 |
+
)
|
| 420 |
+
elif sampler_name == "LinearMultistepSampler":
|
| 421 |
+
order = st.sidebar.number_input("order", value=4, min_value=1)
|
| 422 |
+
sampler = LinearMultistepSampler(
|
| 423 |
+
num_steps=steps,
|
| 424 |
+
discretization_config=discretization_config,
|
| 425 |
+
guider_config=guider_config,
|
| 426 |
+
order=order,
|
| 427 |
+
verbose=True,
|
| 428 |
+
)
|
| 429 |
+
else:
|
| 430 |
+
raise ValueError(f"unknown sampler {sampler_name}!")
|
| 431 |
+
|
| 432 |
+
return sampler
|
| 433 |
+
|
| 434 |
+
|
| 435 |
+
def get_interactive_image() -> Image.Image:
|
| 436 |
+
image = st.file_uploader("Input", type=["jpg", "JPEG", "png"])
|
| 437 |
+
if image is not None:
|
| 438 |
+
image = Image.open(image)
|
| 439 |
+
if not image.mode == "RGB":
|
| 440 |
+
image = image.convert("RGB")
|
| 441 |
+
return image
|
| 442 |
+
|
| 443 |
+
|
| 444 |
+
def load_img(
|
| 445 |
+
display: bool = True,
|
| 446 |
+
size: Union[None, int, Tuple[int, int]] = None,
|
| 447 |
+
center_crop: bool = False,
|
| 448 |
+
):
|
| 449 |
+
image = get_interactive_image()
|
| 450 |
+
if image is None:
|
| 451 |
+
return None
|
| 452 |
+
if display:
|
| 453 |
+
st.image(image)
|
| 454 |
+
w, h = image.size
|
| 455 |
+
print(f"loaded input image of size ({w}, {h})")
|
| 456 |
+
|
| 457 |
+
transform = []
|
| 458 |
+
if size is not None:
|
| 459 |
+
transform.append(transforms.Resize(size))
|
| 460 |
+
if center_crop:
|
| 461 |
+
transform.append(transforms.CenterCrop(size))
|
| 462 |
+
transform.append(transforms.ToTensor())
|
| 463 |
+
transform.append(transforms.Lambda(lambda x: 2.0 * x - 1.0))
|
| 464 |
+
|
| 465 |
+
transform = transforms.Compose(transform)
|
| 466 |
+
img = transform(image)[None, ...]
|
| 467 |
+
st.text(f"input min/max/mean: {img.min():.3f}/{img.max():.3f}/{img.mean():.3f}")
|
| 468 |
+
return img
|
| 469 |
+
|
| 470 |
+
|
| 471 |
+
def get_init_img(batch_size=1, key=None):
|
| 472 |
+
init_image = load_img(key=key).cuda()
|
| 473 |
+
init_image = repeat(init_image, "1 ... -> b ...", b=batch_size)
|
| 474 |
+
return init_image
|
| 475 |
+
|
| 476 |
+
|
| 477 |
+
def do_sample(
|
| 478 |
+
model,
|
| 479 |
+
sampler,
|
| 480 |
+
value_dict,
|
| 481 |
+
num_samples,
|
| 482 |
+
H,
|
| 483 |
+
W,
|
| 484 |
+
C,
|
| 485 |
+
F,
|
| 486 |
+
force_uc_zero_embeddings: Optional[List] = None,
|
| 487 |
+
force_cond_zero_embeddings: Optional[List] = None,
|
| 488 |
+
batch2model_input: List = None,
|
| 489 |
+
return_latents=False,
|
| 490 |
+
filter=None,
|
| 491 |
+
T=None,
|
| 492 |
+
additional_batch_uc_fields=None,
|
| 493 |
+
decoding_t=None,
|
| 494 |
+
):
|
| 495 |
+
force_uc_zero_embeddings = default(force_uc_zero_embeddings, [])
|
| 496 |
+
batch2model_input = default(batch2model_input, [])
|
| 497 |
+
additional_batch_uc_fields = default(additional_batch_uc_fields, [])
|
| 498 |
+
|
| 499 |
+
st.text("Sampling")
|
| 500 |
+
|
| 501 |
+
outputs = st.empty()
|
| 502 |
+
precision_scope = autocast
|
| 503 |
+
with torch.no_grad():
|
| 504 |
+
with precision_scope("cuda"):
|
| 505 |
+
with model.ema_scope():
|
| 506 |
+
if T is not None:
|
| 507 |
+
num_samples = [num_samples, T]
|
| 508 |
+
else:
|
| 509 |
+
num_samples = [num_samples]
|
| 510 |
+
|
| 511 |
+
load_model(model.conditioner)
|
| 512 |
+
batch, batch_uc = get_batch(
|
| 513 |
+
get_unique_embedder_keys_from_conditioner(model.conditioner),
|
| 514 |
+
value_dict,
|
| 515 |
+
num_samples,
|
| 516 |
+
T=T,
|
| 517 |
+
additional_batch_uc_fields=additional_batch_uc_fields,
|
| 518 |
+
)
|
| 519 |
+
|
| 520 |
+
c, uc = model.conditioner.get_unconditional_conditioning(
|
| 521 |
+
batch,
|
| 522 |
+
batch_uc=batch_uc,
|
| 523 |
+
force_uc_zero_embeddings=force_uc_zero_embeddings,
|
| 524 |
+
force_cond_zero_embeddings=force_cond_zero_embeddings,
|
| 525 |
+
)
|
| 526 |
+
unload_model(model.conditioner)
|
| 527 |
+
|
| 528 |
+
for k in c:
|
| 529 |
+
if not k == "crossattn":
|
| 530 |
+
c[k], uc[k] = map(
|
| 531 |
+
lambda y: y[k][: math.prod(num_samples)].to("cuda"), (c, uc)
|
| 532 |
+
)
|
| 533 |
+
if k in ["crossattn", "concat"] and T is not None:
|
| 534 |
+
uc[k] = repeat(uc[k], "b ... -> b t ...", t=T)
|
| 535 |
+
uc[k] = rearrange(uc[k], "b t ... -> (b t) ...", t=T)
|
| 536 |
+
c[k] = repeat(c[k], "b ... -> b t ...", t=T)
|
| 537 |
+
c[k] = rearrange(c[k], "b t ... -> (b t) ...", t=T)
|
| 538 |
+
|
| 539 |
+
additional_model_inputs = {}
|
| 540 |
+
for k in batch2model_input:
|
| 541 |
+
if k == "image_only_indicator":
|
| 542 |
+
assert T is not None
|
| 543 |
+
|
| 544 |
+
if isinstance(
|
| 545 |
+
sampler.guider, (VanillaCFG, LinearPredictionGuider)
|
| 546 |
+
):
|
| 547 |
+
additional_model_inputs[k] = torch.zeros(
|
| 548 |
+
num_samples[0] * 2, num_samples[1]
|
| 549 |
+
).to("cuda")
|
| 550 |
+
else:
|
| 551 |
+
additional_model_inputs[k] = torch.zeros(num_samples).to(
|
| 552 |
+
"cuda"
|
| 553 |
+
)
|
| 554 |
+
else:
|
| 555 |
+
additional_model_inputs[k] = batch[k]
|
| 556 |
+
|
| 557 |
+
shape = (math.prod(num_samples), C, H // F, W // F)
|
| 558 |
+
randn = torch.randn(shape).to("cuda")
|
| 559 |
+
|
| 560 |
+
def denoiser(input, sigma, c):
|
| 561 |
+
return model.denoiser(
|
| 562 |
+
model.model, input, sigma, c, **additional_model_inputs
|
| 563 |
+
)
|
| 564 |
+
|
| 565 |
+
load_model(model.denoiser)
|
| 566 |
+
load_model(model.model)
|
| 567 |
+
samples_z = sampler(denoiser, randn, cond=c, uc=uc)
|
| 568 |
+
unload_model(model.model)
|
| 569 |
+
unload_model(model.denoiser)
|
| 570 |
+
|
| 571 |
+
load_model(model.first_stage_model)
|
| 572 |
+
model.en_and_decode_n_samples_a_time = (
|
| 573 |
+
decoding_t # Decode n frames at a time
|
| 574 |
+
)
|
| 575 |
+
samples_x = model.decode_first_stage(samples_z)
|
| 576 |
+
samples = torch.clamp((samples_x + 1.0) / 2.0, min=0.0, max=1.0)
|
| 577 |
+
unload_model(model.first_stage_model)
|
| 578 |
+
|
| 579 |
+
if filter is not None:
|
| 580 |
+
samples = filter(samples)
|
| 581 |
+
|
| 582 |
+
if T is None:
|
| 583 |
+
grid = torch.stack([samples])
|
| 584 |
+
grid = rearrange(grid, "n b c h w -> (n h) (b w) c")
|
| 585 |
+
outputs.image(grid.cpu().numpy())
|
| 586 |
+
else:
|
| 587 |
+
as_vids = rearrange(samples, "(b t) c h w -> b t c h w", t=T)
|
| 588 |
+
for i, vid in enumerate(as_vids):
|
| 589 |
+
grid = rearrange(make_grid(vid, nrow=4), "c h w -> h w c")
|
| 590 |
+
st.image(
|
| 591 |
+
grid.cpu().numpy(),
|
| 592 |
+
f"Sample #{i} as image",
|
| 593 |
+
)
|
| 594 |
+
|
| 595 |
+
if return_latents:
|
| 596 |
+
return samples, samples_z
|
| 597 |
+
return samples
|
| 598 |
+
|
| 599 |
+
|
| 600 |
+
def get_batch(
|
| 601 |
+
keys,
|
| 602 |
+
value_dict: dict,
|
| 603 |
+
N: Union[List, ListConfig],
|
| 604 |
+
device: str = "cuda",
|
| 605 |
+
T: int = None,
|
| 606 |
+
additional_batch_uc_fields: List[str] = [],
|
| 607 |
+
):
|
| 608 |
+
# Hardcoded demo setups; might undergo some changes in the future
|
| 609 |
+
|
| 610 |
+
batch = {}
|
| 611 |
+
batch_uc = {}
|
| 612 |
+
|
| 613 |
+
for key in keys:
|
| 614 |
+
if key == "txt":
|
| 615 |
+
batch["txt"] = [value_dict["prompt"]] * math.prod(N)
|
| 616 |
+
|
| 617 |
+
batch_uc["txt"] = [value_dict["negative_prompt"]] * math.prod(N)
|
| 618 |
+
|
| 619 |
+
elif key == "original_size_as_tuple":
|
| 620 |
+
batch["original_size_as_tuple"] = (
|
| 621 |
+
torch.tensor([value_dict["orig_height"], value_dict["orig_width"]])
|
| 622 |
+
.to(device)
|
| 623 |
+
.repeat(math.prod(N), 1)
|
| 624 |
+
)
|
| 625 |
+
elif key == "crop_coords_top_left":
|
| 626 |
+
batch["crop_coords_top_left"] = (
|
| 627 |
+
torch.tensor(
|
| 628 |
+
[value_dict["crop_coords_top"], value_dict["crop_coords_left"]]
|
| 629 |
+
)
|
| 630 |
+
.to(device)
|
| 631 |
+
.repeat(math.prod(N), 1)
|
| 632 |
+
)
|
| 633 |
+
elif key == "aesthetic_score":
|
| 634 |
+
batch["aesthetic_score"] = (
|
| 635 |
+
torch.tensor([value_dict["aesthetic_score"]])
|
| 636 |
+
.to(device)
|
| 637 |
+
.repeat(math.prod(N), 1)
|
| 638 |
+
)
|
| 639 |
+
batch_uc["aesthetic_score"] = (
|
| 640 |
+
torch.tensor([value_dict["negative_aesthetic_score"]])
|
| 641 |
+
.to(device)
|
| 642 |
+
.repeat(math.prod(N), 1)
|
| 643 |
+
)
|
| 644 |
+
|
| 645 |
+
elif key == "target_size_as_tuple":
|
| 646 |
+
batch["target_size_as_tuple"] = (
|
| 647 |
+
torch.tensor([value_dict["target_height"], value_dict["target_width"]])
|
| 648 |
+
.to(device)
|
| 649 |
+
.repeat(math.prod(N), 1)
|
| 650 |
+
)
|
| 651 |
+
elif key == "fps":
|
| 652 |
+
batch[key] = (
|
| 653 |
+
torch.tensor([value_dict["fps"]]).to(device).repeat(math.prod(N))
|
| 654 |
+
)
|
| 655 |
+
elif key == "fps_id":
|
| 656 |
+
batch[key] = (
|
| 657 |
+
torch.tensor([value_dict["fps_id"]]).to(device).repeat(math.prod(N))
|
| 658 |
+
)
|
| 659 |
+
elif key == "motion_bucket_id":
|
| 660 |
+
batch[key] = (
|
| 661 |
+
torch.tensor([value_dict["motion_bucket_id"]])
|
| 662 |
+
.to(device)
|
| 663 |
+
.repeat(math.prod(N))
|
| 664 |
+
)
|
| 665 |
+
elif key == "pool_image":
|
| 666 |
+
batch[key] = repeat(value_dict[key], "1 ... -> b ...", b=math.prod(N)).to(
|
| 667 |
+
device, dtype=torch.half
|
| 668 |
+
)
|
| 669 |
+
elif key == "cond_aug":
|
| 670 |
+
batch[key] = repeat(
|
| 671 |
+
torch.tensor([value_dict["cond_aug"]]).to("cuda"),
|
| 672 |
+
"1 -> b",
|
| 673 |
+
b=math.prod(N),
|
| 674 |
+
)
|
| 675 |
+
elif key == "cond_frames":
|
| 676 |
+
batch[key] = repeat(value_dict["cond_frames"], "1 ... -> b ...", b=N[0])
|
| 677 |
+
elif key == "cond_frames_without_noise":
|
| 678 |
+
batch[key] = repeat(
|
| 679 |
+
value_dict["cond_frames_without_noise"], "1 ... -> b ...", b=N[0]
|
| 680 |
+
)
|
| 681 |
+
else:
|
| 682 |
+
batch[key] = value_dict[key]
|
| 683 |
+
|
| 684 |
+
if T is not None:
|
| 685 |
+
batch["num_video_frames"] = T
|
| 686 |
+
|
| 687 |
+
for key in batch.keys():
|
| 688 |
+
if key not in batch_uc and isinstance(batch[key], torch.Tensor):
|
| 689 |
+
batch_uc[key] = torch.clone(batch[key])
|
| 690 |
+
elif key in additional_batch_uc_fields and key not in batch_uc:
|
| 691 |
+
batch_uc[key] = copy.copy(batch[key])
|
| 692 |
+
return batch, batch_uc
|
| 693 |
+
|
| 694 |
+
|
| 695 |
+
@torch.no_grad()
|
| 696 |
+
def do_img2img(
|
| 697 |
+
img,
|
| 698 |
+
model,
|
| 699 |
+
sampler,
|
| 700 |
+
value_dict,
|
| 701 |
+
num_samples,
|
| 702 |
+
force_uc_zero_embeddings: Optional[List] = None,
|
| 703 |
+
force_cond_zero_embeddings: Optional[List] = None,
|
| 704 |
+
additional_kwargs={},
|
| 705 |
+
offset_noise_level: int = 0.0,
|
| 706 |
+
return_latents=False,
|
| 707 |
+
skip_encode=False,
|
| 708 |
+
filter=None,
|
| 709 |
+
add_noise=True,
|
| 710 |
+
):
|
| 711 |
+
st.text("Sampling")
|
| 712 |
+
|
| 713 |
+
outputs = st.empty()
|
| 714 |
+
precision_scope = autocast
|
| 715 |
+
with torch.no_grad():
|
| 716 |
+
with precision_scope("cuda"):
|
| 717 |
+
with model.ema_scope():
|
| 718 |
+
load_model(model.conditioner)
|
| 719 |
+
batch, batch_uc = get_batch(
|
| 720 |
+
get_unique_embedder_keys_from_conditioner(model.conditioner),
|
| 721 |
+
value_dict,
|
| 722 |
+
[num_samples],
|
| 723 |
+
)
|
| 724 |
+
c, uc = model.conditioner.get_unconditional_conditioning(
|
| 725 |
+
batch,
|
| 726 |
+
batch_uc=batch_uc,
|
| 727 |
+
force_uc_zero_embeddings=force_uc_zero_embeddings,
|
| 728 |
+
force_cond_zero_embeddings=force_cond_zero_embeddings,
|
| 729 |
+
)
|
| 730 |
+
unload_model(model.conditioner)
|
| 731 |
+
for k in c:
|
| 732 |
+
c[k], uc[k] = map(lambda y: y[k][:num_samples].to("cuda"), (c, uc))
|
| 733 |
+
|
| 734 |
+
for k in additional_kwargs:
|
| 735 |
+
c[k] = uc[k] = additional_kwargs[k]
|
| 736 |
+
if skip_encode:
|
| 737 |
+
z = img
|
| 738 |
+
else:
|
| 739 |
+
load_model(model.first_stage_model)
|
| 740 |
+
z = model.encode_first_stage(img)
|
| 741 |
+
unload_model(model.first_stage_model)
|
| 742 |
+
|
| 743 |
+
noise = torch.randn_like(z)
|
| 744 |
+
|
| 745 |
+
sigmas = sampler.discretization(sampler.num_steps).cuda()
|
| 746 |
+
sigma = sigmas[0]
|
| 747 |
+
|
| 748 |
+
st.info(f"all sigmas: {sigmas}")
|
| 749 |
+
st.info(f"noising sigma: {sigma}")
|
| 750 |
+
if offset_noise_level > 0.0:
|
| 751 |
+
noise = noise + offset_noise_level * append_dims(
|
| 752 |
+
torch.randn(z.shape[0], device=z.device), z.ndim
|
| 753 |
+
)
|
| 754 |
+
if add_noise:
|
| 755 |
+
noised_z = z + noise * append_dims(sigma, z.ndim).cuda()
|
| 756 |
+
noised_z = noised_z / torch.sqrt(
|
| 757 |
+
1.0 + sigmas[0] ** 2.0
|
| 758 |
+
) # Note: hardcoded to DDPM-like scaling. need to generalize later.
|
| 759 |
+
else:
|
| 760 |
+
noised_z = z / torch.sqrt(1.0 + sigmas[0] ** 2.0)
|
| 761 |
+
|
| 762 |
+
def denoiser(x, sigma, c):
|
| 763 |
+
return model.denoiser(model.model, x, sigma, c)
|
| 764 |
+
|
| 765 |
+
load_model(model.denoiser)
|
| 766 |
+
load_model(model.model)
|
| 767 |
+
samples_z = sampler(denoiser, noised_z, cond=c, uc=uc)
|
| 768 |
+
unload_model(model.model)
|
| 769 |
+
unload_model(model.denoiser)
|
| 770 |
+
|
| 771 |
+
load_model(model.first_stage_model)
|
| 772 |
+
samples_x = model.decode_first_stage(samples_z)
|
| 773 |
+
unload_model(model.first_stage_model)
|
| 774 |
+
samples = torch.clamp((samples_x + 1.0) / 2.0, min=0.0, max=1.0)
|
| 775 |
+
|
| 776 |
+
if filter is not None:
|
| 777 |
+
samples = filter(samples)
|
| 778 |
+
|
| 779 |
+
grid = rearrange(grid, "n b c h w -> (n h) (b w) c")
|
| 780 |
+
outputs.image(grid.cpu().numpy())
|
| 781 |
+
if return_latents:
|
| 782 |
+
return samples, samples_z
|
| 783 |
+
return samples
|
| 784 |
+
|
| 785 |
+
|
| 786 |
+
def get_resizing_factor(
|
| 787 |
+
desired_shape: Tuple[int, int], current_shape: Tuple[int, int]
|
| 788 |
+
) -> float:
|
| 789 |
+
r_bound = desired_shape[1] / desired_shape[0]
|
| 790 |
+
aspect_r = current_shape[1] / current_shape[0]
|
| 791 |
+
if r_bound >= 1.0:
|
| 792 |
+
if aspect_r >= r_bound:
|
| 793 |
+
factor = min(desired_shape) / min(current_shape)
|
| 794 |
+
else:
|
| 795 |
+
if aspect_r < 1.0:
|
| 796 |
+
factor = max(desired_shape) / min(current_shape)
|
| 797 |
+
else:
|
| 798 |
+
factor = max(desired_shape) / max(current_shape)
|
| 799 |
+
else:
|
| 800 |
+
if aspect_r <= r_bound:
|
| 801 |
+
factor = min(desired_shape) / min(current_shape)
|
| 802 |
+
else:
|
| 803 |
+
if aspect_r > 1:
|
| 804 |
+
factor = max(desired_shape) / min(current_shape)
|
| 805 |
+
else:
|
| 806 |
+
factor = max(desired_shape) / max(current_shape)
|
| 807 |
+
|
| 808 |
+
return factor
|
| 809 |
+
|
| 810 |
+
|
| 811 |
+
def get_interactive_image(key=None) -> Image.Image:
|
| 812 |
+
image = st.file_uploader("Input", type=["jpg", "JPEG", "png"], key=key)
|
| 813 |
+
if image is not None:
|
| 814 |
+
image = Image.open(image)
|
| 815 |
+
if not image.mode == "RGB":
|
| 816 |
+
image = image.convert("RGB")
|
| 817 |
+
return image
|
| 818 |
+
|
| 819 |
+
|
| 820 |
+
def load_img_for_prediction(
|
| 821 |
+
W: int, H: int, display=True, key=None, device="cuda"
|
| 822 |
+
) -> torch.Tensor:
|
| 823 |
+
image = get_interactive_image(key=key)
|
| 824 |
+
if image is None:
|
| 825 |
+
return None
|
| 826 |
+
if display:
|
| 827 |
+
st.image(image)
|
| 828 |
+
w, h = image.size
|
| 829 |
+
|
| 830 |
+
image = np.array(image).transpose(2, 0, 1)
|
| 831 |
+
image = torch.from_numpy(image).to(dtype=torch.float32) / 255.0
|
| 832 |
+
image = image.unsqueeze(0)
|
| 833 |
+
|
| 834 |
+
rfs = get_resizing_factor((H, W), (h, w))
|
| 835 |
+
resize_size = [int(np.ceil(rfs * s)) for s in (h, w)]
|
| 836 |
+
top = (resize_size[0] - H) // 2
|
| 837 |
+
left = (resize_size[1] - W) // 2
|
| 838 |
+
|
| 839 |
+
image = torch.nn.functional.interpolate(
|
| 840 |
+
image, resize_size, mode="area", antialias=False
|
| 841 |
+
)
|
| 842 |
+
image = TT.functional.crop(image, top=top, left=left, height=H, width=W)
|
| 843 |
+
|
| 844 |
+
if display:
|
| 845 |
+
numpy_img = np.transpose(image[0].numpy(), (1, 2, 0))
|
| 846 |
+
pil_image = Image.fromarray((numpy_img * 255).astype(np.uint8))
|
| 847 |
+
st.image(pil_image)
|
| 848 |
+
return image.to(device) * 2.0 - 1.0
|
| 849 |
+
|
| 850 |
+
|
| 851 |
+
def save_video_as_grid_and_mp4(
|
| 852 |
+
video_batch: torch.Tensor, save_path: str, T: int, fps: int = 5
|
| 853 |
+
):
|
| 854 |
+
os.makedirs(save_path, exist_ok=True)
|
| 855 |
+
base_count = len(glob(os.path.join(save_path, "*.mp4")))
|
| 856 |
+
|
| 857 |
+
video_batch = rearrange(video_batch, "(b t) c h w -> b t c h w", t=T)
|
| 858 |
+
video_batch = embed_watermark(video_batch)
|
| 859 |
+
for vid in video_batch:
|
| 860 |
+
save_image(vid, fp=os.path.join(save_path, f"{base_count:06d}.png"), nrow=4)
|
| 861 |
+
|
| 862 |
+
video_path = os.path.join(save_path, f"{base_count:06d}.mp4")
|
| 863 |
+
|
| 864 |
+
writer = cv2.VideoWriter(
|
| 865 |
+
video_path,
|
| 866 |
+
cv2.VideoWriter_fourcc(*"MP4V"),
|
| 867 |
+
fps,
|
| 868 |
+
(vid.shape[-1], vid.shape[-2]),
|
| 869 |
+
)
|
| 870 |
+
|
| 871 |
+
vid = (
|
| 872 |
+
(rearrange(vid, "t c h w -> t h w c") * 255).cpu().numpy().astype(np.uint8)
|
| 873 |
+
)
|
| 874 |
+
for frame in vid:
|
| 875 |
+
frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
|
| 876 |
+
writer.write(frame)
|
| 877 |
+
|
| 878 |
+
writer.release()
|
| 879 |
+
|
| 880 |
+
video_path_h264 = video_path[:-4] + "_h264.mp4"
|
| 881 |
+
os.system(f"ffmpeg -i {video_path} -c:v libx264 {video_path_h264}")
|
| 882 |
+
|
| 883 |
+
with open(video_path_h264, "rb") as f:
|
| 884 |
+
video_bytes = f.read()
|
| 885 |
+
st.video(video_bytes)
|
| 886 |
+
|
| 887 |
+
base_count += 1
|
MindEye_Imagery/src/generative_models/scripts/demo/turbo.py
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from streamlit_helpers import *
|
| 2 |
+
from st_keyup import st_keyup
|
| 3 |
+
from sgm.modules.diffusionmodules.sampling import EulerAncestralSampler
|
| 4 |
+
|
| 5 |
+
VERSION2SPECS = {
|
| 6 |
+
"SDXL-Turbo": {
|
| 7 |
+
"H": 512,
|
| 8 |
+
"W": 512,
|
| 9 |
+
"C": 4,
|
| 10 |
+
"f": 8,
|
| 11 |
+
"is_legacy": False,
|
| 12 |
+
"config": "configs/inference/sd_xl_base.yaml",
|
| 13 |
+
"ckpt": "checkpoints/sd_xl_turbo_1.0.safetensors",
|
| 14 |
+
},
|
| 15 |
+
"SD-Turbo": {
|
| 16 |
+
"H": 512,
|
| 17 |
+
"W": 512,
|
| 18 |
+
"C": 4,
|
| 19 |
+
"f": 8,
|
| 20 |
+
"is_legacy": False,
|
| 21 |
+
"config": "configs/inference/sd_2_1.yaml",
|
| 22 |
+
"ckpt": "checkpoints/sd_turbo.safetensors",
|
| 23 |
+
},
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
class SubstepSampler(EulerAncestralSampler):
|
| 28 |
+
def __init__(self, n_sample_steps=1, *args, **kwargs):
|
| 29 |
+
super().__init__(*args, **kwargs)
|
| 30 |
+
self.n_sample_steps = n_sample_steps
|
| 31 |
+
self.steps_subset = [0, 100, 200, 300, 1000]
|
| 32 |
+
|
| 33 |
+
def prepare_sampling_loop(self, x, cond, uc=None, num_steps=None):
|
| 34 |
+
sigmas = self.discretization(
|
| 35 |
+
self.num_steps if num_steps is None else num_steps, device=self.device
|
| 36 |
+
)
|
| 37 |
+
sigmas = sigmas[
|
| 38 |
+
self.steps_subset[: self.n_sample_steps] + self.steps_subset[-1:]
|
| 39 |
+
]
|
| 40 |
+
uc = cond
|
| 41 |
+
x *= torch.sqrt(1.0 + sigmas[0] ** 2.0)
|
| 42 |
+
num_sigmas = len(sigmas)
|
| 43 |
+
s_in = x.new_ones([x.shape[0]])
|
| 44 |
+
return x, s_in, sigmas, num_sigmas, cond, uc
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
def seeded_randn(shape, seed):
|
| 48 |
+
randn = np.random.RandomState(seed).randn(*shape)
|
| 49 |
+
randn = torch.from_numpy(randn).to(device="cuda", dtype=torch.float32)
|
| 50 |
+
return randn
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
class SeededNoise:
|
| 54 |
+
def __init__(self, seed):
|
| 55 |
+
self.seed = seed
|
| 56 |
+
|
| 57 |
+
def __call__(self, x):
|
| 58 |
+
self.seed = self.seed + 1
|
| 59 |
+
return seeded_randn(x.shape, self.seed)
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
def init_embedder_options(keys, init_dict, prompt=None, negative_prompt=None):
|
| 63 |
+
value_dict = {}
|
| 64 |
+
for key in keys:
|
| 65 |
+
if key == "txt":
|
| 66 |
+
value_dict["prompt"] = prompt
|
| 67 |
+
value_dict["negative_prompt"] = ""
|
| 68 |
+
|
| 69 |
+
if key == "original_size_as_tuple":
|
| 70 |
+
orig_width = init_dict["orig_width"]
|
| 71 |
+
orig_height = init_dict["orig_height"]
|
| 72 |
+
|
| 73 |
+
value_dict["orig_width"] = orig_width
|
| 74 |
+
value_dict["orig_height"] = orig_height
|
| 75 |
+
|
| 76 |
+
if key == "crop_coords_top_left":
|
| 77 |
+
crop_coord_top = 0
|
| 78 |
+
crop_coord_left = 0
|
| 79 |
+
|
| 80 |
+
value_dict["crop_coords_top"] = crop_coord_top
|
| 81 |
+
value_dict["crop_coords_left"] = crop_coord_left
|
| 82 |
+
|
| 83 |
+
if key == "aesthetic_score":
|
| 84 |
+
value_dict["aesthetic_score"] = 6.0
|
| 85 |
+
value_dict["negative_aesthetic_score"] = 2.5
|
| 86 |
+
|
| 87 |
+
if key == "target_size_as_tuple":
|
| 88 |
+
value_dict["target_width"] = init_dict["target_width"]
|
| 89 |
+
value_dict["target_height"] = init_dict["target_height"]
|
| 90 |
+
|
| 91 |
+
return value_dict
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
def sample(
|
| 95 |
+
model,
|
| 96 |
+
sampler,
|
| 97 |
+
prompt="A lush garden with oversized flowers and vibrant colors, inhabited by miniature animals.",
|
| 98 |
+
H=1024,
|
| 99 |
+
W=1024,
|
| 100 |
+
seed=0,
|
| 101 |
+
filter=None,
|
| 102 |
+
):
|
| 103 |
+
F = 8
|
| 104 |
+
C = 4
|
| 105 |
+
shape = (1, C, H // F, W // F)
|
| 106 |
+
|
| 107 |
+
value_dict = init_embedder_options(
|
| 108 |
+
keys=get_unique_embedder_keys_from_conditioner(model.conditioner),
|
| 109 |
+
init_dict={
|
| 110 |
+
"orig_width": W,
|
| 111 |
+
"orig_height": H,
|
| 112 |
+
"target_width": W,
|
| 113 |
+
"target_height": H,
|
| 114 |
+
},
|
| 115 |
+
prompt=prompt,
|
| 116 |
+
)
|
| 117 |
+
|
| 118 |
+
if seed is None:
|
| 119 |
+
seed = torch.seed()
|
| 120 |
+
precision_scope = autocast
|
| 121 |
+
with torch.no_grad():
|
| 122 |
+
with precision_scope("cuda"):
|
| 123 |
+
batch, batch_uc = get_batch(
|
| 124 |
+
get_unique_embedder_keys_from_conditioner(model.conditioner),
|
| 125 |
+
value_dict,
|
| 126 |
+
[1],
|
| 127 |
+
)
|
| 128 |
+
c = model.conditioner(batch)
|
| 129 |
+
uc = None
|
| 130 |
+
randn = seeded_randn(shape, seed)
|
| 131 |
+
|
| 132 |
+
def denoiser(input, sigma, c):
|
| 133 |
+
return model.denoiser(
|
| 134 |
+
model.model,
|
| 135 |
+
input,
|
| 136 |
+
sigma,
|
| 137 |
+
c,
|
| 138 |
+
)
|
| 139 |
+
|
| 140 |
+
samples_z = sampler(denoiser, randn, cond=c, uc=uc)
|
| 141 |
+
samples_x = model.decode_first_stage(samples_z)
|
| 142 |
+
samples = torch.clamp((samples_x + 1.0) / 2.0, min=0.0, max=1.0)
|
| 143 |
+
if filter is not None:
|
| 144 |
+
samples = filter(samples)
|
| 145 |
+
samples = (
|
| 146 |
+
(255 * samples)
|
| 147 |
+
.to(dtype=torch.uint8)
|
| 148 |
+
.permute(0, 2, 3, 1)
|
| 149 |
+
.detach()
|
| 150 |
+
.cpu()
|
| 151 |
+
.numpy()
|
| 152 |
+
)
|
| 153 |
+
return samples
|
| 154 |
+
|
| 155 |
+
|
| 156 |
+
def v_spacer(height) -> None:
|
| 157 |
+
for _ in range(height):
|
| 158 |
+
st.write("\n")
|
| 159 |
+
|
| 160 |
+
|
| 161 |
+
if __name__ == "__main__":
|
| 162 |
+
st.title("Turbo")
|
| 163 |
+
|
| 164 |
+
head_cols = st.columns([1, 1, 1])
|
| 165 |
+
with head_cols[0]:
|
| 166 |
+
version = st.selectbox("Model Version", list(VERSION2SPECS.keys()), 0)
|
| 167 |
+
version_dict = VERSION2SPECS[version]
|
| 168 |
+
|
| 169 |
+
with head_cols[1]:
|
| 170 |
+
v_spacer(2)
|
| 171 |
+
if st.checkbox("Load Model"):
|
| 172 |
+
mode = "txt2img"
|
| 173 |
+
else:
|
| 174 |
+
mode = "skip"
|
| 175 |
+
|
| 176 |
+
if mode != "skip":
|
| 177 |
+
state = init_st(version_dict, load_filter=True)
|
| 178 |
+
if state["msg"]:
|
| 179 |
+
st.info(state["msg"])
|
| 180 |
+
model = state["model"]
|
| 181 |
+
load_model(model)
|
| 182 |
+
|
| 183 |
+
# seed
|
| 184 |
+
if "seed" not in st.session_state:
|
| 185 |
+
st.session_state.seed = 0
|
| 186 |
+
|
| 187 |
+
def increment_counter():
|
| 188 |
+
st.session_state.seed += 1
|
| 189 |
+
|
| 190 |
+
def decrement_counter():
|
| 191 |
+
if st.session_state.seed > 0:
|
| 192 |
+
st.session_state.seed -= 1
|
| 193 |
+
|
| 194 |
+
with head_cols[2]:
|
| 195 |
+
n_steps = st.number_input(label="number of steps", min_value=1, max_value=4)
|
| 196 |
+
|
| 197 |
+
sampler = SubstepSampler(
|
| 198 |
+
n_sample_steps=1,
|
| 199 |
+
num_steps=1000,
|
| 200 |
+
eta=1.0,
|
| 201 |
+
discretization_config=dict(
|
| 202 |
+
target="sgm.modules.diffusionmodules.discretizer.LegacyDDPMDiscretization"
|
| 203 |
+
),
|
| 204 |
+
)
|
| 205 |
+
sampler.n_sample_steps = n_steps
|
| 206 |
+
default_prompt = "A cinematic shot of a baby racoon wearing an intricate italian priest robe."
|
| 207 |
+
prompt = st_keyup("Enter a value", value=default_prompt, debounce=300, key="interactive_text")
|
| 208 |
+
|
| 209 |
+
cols = st.columns([1, 5, 1])
|
| 210 |
+
if mode != "skip":
|
| 211 |
+
with cols[0]:
|
| 212 |
+
v_spacer(14)
|
| 213 |
+
st.button("↩", on_click=decrement_counter)
|
| 214 |
+
with cols[2]:
|
| 215 |
+
v_spacer(14)
|
| 216 |
+
st.button("↪", on_click=increment_counter)
|
| 217 |
+
|
| 218 |
+
sampler.noise_sampler = SeededNoise(seed=st.session_state.seed)
|
| 219 |
+
out = sample(
|
| 220 |
+
model, sampler, H=512, W=512, seed=st.session_state.seed, prompt=prompt, filter=state.get("filter")
|
| 221 |
+
)
|
| 222 |
+
with cols[1]:
|
| 223 |
+
st.image(out[0])
|
MindEye_Imagery/src/generative_models/scripts/demo/video_sampling.py
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
|
| 3 |
+
from pytorch_lightning import seed_everything
|
| 4 |
+
|
| 5 |
+
from scripts.demo.streamlit_helpers import *
|
| 6 |
+
|
| 7 |
+
SAVE_PATH = "outputs/demo/vid/"
|
| 8 |
+
|
| 9 |
+
VERSION2SPECS = {
|
| 10 |
+
"svd": {
|
| 11 |
+
"T": 14,
|
| 12 |
+
"H": 576,
|
| 13 |
+
"W": 1024,
|
| 14 |
+
"C": 4,
|
| 15 |
+
"f": 8,
|
| 16 |
+
"config": "configs/inference/svd.yaml",
|
| 17 |
+
"ckpt": "checkpoints/svd.safetensors",
|
| 18 |
+
"options": {
|
| 19 |
+
"discretization": 1,
|
| 20 |
+
"cfg": 2.5,
|
| 21 |
+
"sigma_min": 0.002,
|
| 22 |
+
"sigma_max": 700.0,
|
| 23 |
+
"rho": 7.0,
|
| 24 |
+
"guider": 2,
|
| 25 |
+
"force_uc_zero_embeddings": ["cond_frames", "cond_frames_without_noise"],
|
| 26 |
+
"num_steps": 25,
|
| 27 |
+
},
|
| 28 |
+
},
|
| 29 |
+
"svd_image_decoder": {
|
| 30 |
+
"T": 14,
|
| 31 |
+
"H": 576,
|
| 32 |
+
"W": 1024,
|
| 33 |
+
"C": 4,
|
| 34 |
+
"f": 8,
|
| 35 |
+
"config": "configs/inference/svd_image_decoder.yaml",
|
| 36 |
+
"ckpt": "checkpoints/svd_image_decoder.safetensors",
|
| 37 |
+
"options": {
|
| 38 |
+
"discretization": 1,
|
| 39 |
+
"cfg": 2.5,
|
| 40 |
+
"sigma_min": 0.002,
|
| 41 |
+
"sigma_max": 700.0,
|
| 42 |
+
"rho": 7.0,
|
| 43 |
+
"guider": 2,
|
| 44 |
+
"force_uc_zero_embeddings": ["cond_frames", "cond_frames_without_noise"],
|
| 45 |
+
"num_steps": 25,
|
| 46 |
+
},
|
| 47 |
+
},
|
| 48 |
+
"svd_xt": {
|
| 49 |
+
"T": 25,
|
| 50 |
+
"H": 576,
|
| 51 |
+
"W": 1024,
|
| 52 |
+
"C": 4,
|
| 53 |
+
"f": 8,
|
| 54 |
+
"config": "configs/inference/svd.yaml",
|
| 55 |
+
"ckpt": "checkpoints/svd_xt.safetensors",
|
| 56 |
+
"options": {
|
| 57 |
+
"discretization": 1,
|
| 58 |
+
"cfg": 3.0,
|
| 59 |
+
"min_cfg": 1.5,
|
| 60 |
+
"sigma_min": 0.002,
|
| 61 |
+
"sigma_max": 700.0,
|
| 62 |
+
"rho": 7.0,
|
| 63 |
+
"guider": 2,
|
| 64 |
+
"force_uc_zero_embeddings": ["cond_frames", "cond_frames_without_noise"],
|
| 65 |
+
"num_steps": 30,
|
| 66 |
+
"decoding_t": 14,
|
| 67 |
+
},
|
| 68 |
+
},
|
| 69 |
+
"svd_xt_image_decoder": {
|
| 70 |
+
"T": 25,
|
| 71 |
+
"H": 576,
|
| 72 |
+
"W": 1024,
|
| 73 |
+
"C": 4,
|
| 74 |
+
"f": 8,
|
| 75 |
+
"config": "configs/inference/svd_image_decoder.yaml",
|
| 76 |
+
"ckpt": "checkpoints/svd_xt_image_decoder.safetensors",
|
| 77 |
+
"options": {
|
| 78 |
+
"discretization": 1,
|
| 79 |
+
"cfg": 3.0,
|
| 80 |
+
"min_cfg": 1.5,
|
| 81 |
+
"sigma_min": 0.002,
|
| 82 |
+
"sigma_max": 700.0,
|
| 83 |
+
"rho": 7.0,
|
| 84 |
+
"guider": 2,
|
| 85 |
+
"force_uc_zero_embeddings": ["cond_frames", "cond_frames_without_noise"],
|
| 86 |
+
"num_steps": 30,
|
| 87 |
+
"decoding_t": 14,
|
| 88 |
+
},
|
| 89 |
+
},
|
| 90 |
+
}
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
if __name__ == "__main__":
|
| 94 |
+
st.title("Stable Video Diffusion")
|
| 95 |
+
version = st.selectbox(
|
| 96 |
+
"Model Version",
|
| 97 |
+
[k for k in VERSION2SPECS.keys()],
|
| 98 |
+
0,
|
| 99 |
+
)
|
| 100 |
+
version_dict = VERSION2SPECS[version]
|
| 101 |
+
if st.checkbox("Load Model"):
|
| 102 |
+
mode = "img2vid"
|
| 103 |
+
else:
|
| 104 |
+
mode = "skip"
|
| 105 |
+
|
| 106 |
+
H = st.sidebar.number_input(
|
| 107 |
+
"H", value=version_dict["H"], min_value=64, max_value=2048
|
| 108 |
+
)
|
| 109 |
+
W = st.sidebar.number_input(
|
| 110 |
+
"W", value=version_dict["W"], min_value=64, max_value=2048
|
| 111 |
+
)
|
| 112 |
+
T = st.sidebar.number_input(
|
| 113 |
+
"T", value=version_dict["T"], min_value=0, max_value=128
|
| 114 |
+
)
|
| 115 |
+
C = version_dict["C"]
|
| 116 |
+
F = version_dict["f"]
|
| 117 |
+
options = version_dict["options"]
|
| 118 |
+
|
| 119 |
+
if mode != "skip":
|
| 120 |
+
state = init_st(version_dict, load_filter=True)
|
| 121 |
+
if state["msg"]:
|
| 122 |
+
st.info(state["msg"])
|
| 123 |
+
model = state["model"]
|
| 124 |
+
|
| 125 |
+
ukeys = set(
|
| 126 |
+
get_unique_embedder_keys_from_conditioner(state["model"].conditioner)
|
| 127 |
+
)
|
| 128 |
+
|
| 129 |
+
value_dict = init_embedder_options(
|
| 130 |
+
ukeys,
|
| 131 |
+
{},
|
| 132 |
+
)
|
| 133 |
+
|
| 134 |
+
value_dict["image_only_indicator"] = 0
|
| 135 |
+
|
| 136 |
+
if mode == "img2vid":
|
| 137 |
+
img = load_img_for_prediction(W, H)
|
| 138 |
+
cond_aug = st.number_input(
|
| 139 |
+
"Conditioning augmentation:", value=0.02, min_value=0.0
|
| 140 |
+
)
|
| 141 |
+
value_dict["cond_frames_without_noise"] = img
|
| 142 |
+
value_dict["cond_frames"] = img + cond_aug * torch.randn_like(img)
|
| 143 |
+
value_dict["cond_aug"] = cond_aug
|
| 144 |
+
|
| 145 |
+
seed = st.sidebar.number_input(
|
| 146 |
+
"seed", value=23, min_value=0, max_value=int(1e9)
|
| 147 |
+
)
|
| 148 |
+
seed_everything(seed)
|
| 149 |
+
|
| 150 |
+
save_locally, save_path = init_save_locally(
|
| 151 |
+
os.path.join(SAVE_PATH, version), init_value=True
|
| 152 |
+
)
|
| 153 |
+
|
| 154 |
+
options["num_frames"] = T
|
| 155 |
+
|
| 156 |
+
sampler, num_rows, num_cols = init_sampling(options=options)
|
| 157 |
+
num_samples = num_rows * num_cols
|
| 158 |
+
|
| 159 |
+
decoding_t = st.number_input(
|
| 160 |
+
"Decode t frames at a time (set small if you are low on VRAM)",
|
| 161 |
+
value=options.get("decoding_t", T),
|
| 162 |
+
min_value=1,
|
| 163 |
+
max_value=int(1e9),
|
| 164 |
+
)
|
| 165 |
+
|
| 166 |
+
if st.checkbox("Overwrite fps in mp4 generator", False):
|
| 167 |
+
saving_fps = st.number_input(
|
| 168 |
+
f"saving video at fps:", value=value_dict["fps"], min_value=1
|
| 169 |
+
)
|
| 170 |
+
else:
|
| 171 |
+
saving_fps = value_dict["fps"]
|
| 172 |
+
|
| 173 |
+
if st.button("Sample"):
|
| 174 |
+
out = do_sample(
|
| 175 |
+
model,
|
| 176 |
+
sampler,
|
| 177 |
+
value_dict,
|
| 178 |
+
num_samples,
|
| 179 |
+
H,
|
| 180 |
+
W,
|
| 181 |
+
C,
|
| 182 |
+
F,
|
| 183 |
+
T=T,
|
| 184 |
+
batch2model_input=["num_video_frames", "image_only_indicator"],
|
| 185 |
+
force_uc_zero_embeddings=options.get("force_uc_zero_embeddings", None),
|
| 186 |
+
force_cond_zero_embeddings=options.get(
|
| 187 |
+
"force_cond_zero_embeddings", None
|
| 188 |
+
),
|
| 189 |
+
return_latents=False,
|
| 190 |
+
decoding_t=decoding_t,
|
| 191 |
+
)
|
| 192 |
+
|
| 193 |
+
if isinstance(out, (tuple, list)):
|
| 194 |
+
samples, samples_z = out
|
| 195 |
+
else:
|
| 196 |
+
samples = out
|
| 197 |
+
samples_z = None
|
| 198 |
+
|
| 199 |
+
if save_locally:
|
| 200 |
+
save_video_as_grid_and_mp4(samples, save_path, T, fps=saving_fps)
|
MindEye_Imagery/src/generative_models/scripts/sampling/configs/svd.yaml
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
model:
|
| 2 |
+
target: sgm.models.diffusion.DiffusionEngine
|
| 3 |
+
params:
|
| 4 |
+
scale_factor: 0.18215
|
| 5 |
+
disable_first_stage_autocast: True
|
| 6 |
+
ckpt_path: checkpoints/svd.safetensors
|
| 7 |
+
|
| 8 |
+
denoiser_config:
|
| 9 |
+
target: sgm.modules.diffusionmodules.denoiser.Denoiser
|
| 10 |
+
params:
|
| 11 |
+
scaling_config:
|
| 12 |
+
target: sgm.modules.diffusionmodules.denoiser_scaling.VScalingWithEDMcNoise
|
| 13 |
+
|
| 14 |
+
network_config:
|
| 15 |
+
target: sgm.modules.diffusionmodules.video_model.VideoUNet
|
| 16 |
+
params:
|
| 17 |
+
adm_in_channels: 768
|
| 18 |
+
num_classes: sequential
|
| 19 |
+
use_checkpoint: True
|
| 20 |
+
in_channels: 8
|
| 21 |
+
out_channels: 4
|
| 22 |
+
model_channels: 320
|
| 23 |
+
attention_resolutions: [4, 2, 1]
|
| 24 |
+
num_res_blocks: 2
|
| 25 |
+
channel_mult: [1, 2, 4, 4]
|
| 26 |
+
num_head_channels: 64
|
| 27 |
+
use_linear_in_transformer: True
|
| 28 |
+
transformer_depth: 1
|
| 29 |
+
context_dim: 1024
|
| 30 |
+
spatial_transformer_attn_type: softmax-xformers
|
| 31 |
+
extra_ff_mix_layer: True
|
| 32 |
+
use_spatial_context: True
|
| 33 |
+
merge_strategy: learned_with_images
|
| 34 |
+
video_kernel_size: [3, 1, 1]
|
| 35 |
+
|
| 36 |
+
conditioner_config:
|
| 37 |
+
target: sgm.modules.GeneralConditioner
|
| 38 |
+
params:
|
| 39 |
+
emb_models:
|
| 40 |
+
- is_trainable: False
|
| 41 |
+
input_key: cond_frames_without_noise
|
| 42 |
+
target: sgm.modules.encoders.modules.FrozenOpenCLIPImagePredictionEmbedder
|
| 43 |
+
params:
|
| 44 |
+
n_cond_frames: 1
|
| 45 |
+
n_copies: 1
|
| 46 |
+
open_clip_embedding_config:
|
| 47 |
+
target: sgm.modules.encoders.modules.FrozenOpenCLIPImageEmbedder
|
| 48 |
+
params:
|
| 49 |
+
freeze: True
|
| 50 |
+
|
| 51 |
+
- input_key: fps_id
|
| 52 |
+
is_trainable: False
|
| 53 |
+
target: sgm.modules.encoders.modules.ConcatTimestepEmbedderND
|
| 54 |
+
params:
|
| 55 |
+
outdim: 256
|
| 56 |
+
|
| 57 |
+
- input_key: motion_bucket_id
|
| 58 |
+
is_trainable: False
|
| 59 |
+
target: sgm.modules.encoders.modules.ConcatTimestepEmbedderND
|
| 60 |
+
params:
|
| 61 |
+
outdim: 256
|
| 62 |
+
|
| 63 |
+
- input_key: cond_frames
|
| 64 |
+
is_trainable: False
|
| 65 |
+
target: sgm.modules.encoders.modules.VideoPredictionEmbedderWithEncoder
|
| 66 |
+
params:
|
| 67 |
+
disable_encoder_autocast: True
|
| 68 |
+
n_cond_frames: 1
|
| 69 |
+
n_copies: 1
|
| 70 |
+
is_ae: True
|
| 71 |
+
encoder_config:
|
| 72 |
+
target: sgm.models.autoencoder.AutoencoderKLModeOnly
|
| 73 |
+
params:
|
| 74 |
+
embed_dim: 4
|
| 75 |
+
monitor: val/rec_loss
|
| 76 |
+
ddconfig:
|
| 77 |
+
attn_type: vanilla-xformers
|
| 78 |
+
double_z: True
|
| 79 |
+
z_channels: 4
|
| 80 |
+
resolution: 256
|
| 81 |
+
in_channels: 3
|
| 82 |
+
out_ch: 3
|
| 83 |
+
ch: 128
|
| 84 |
+
ch_mult: [1, 2, 4, 4]
|
| 85 |
+
num_res_blocks: 2
|
| 86 |
+
attn_resolutions: []
|
| 87 |
+
dropout: 0.0
|
| 88 |
+
lossconfig:
|
| 89 |
+
target: torch.nn.Identity
|
| 90 |
+
|
| 91 |
+
- input_key: cond_aug
|
| 92 |
+
is_trainable: False
|
| 93 |
+
target: sgm.modules.encoders.modules.ConcatTimestepEmbedderND
|
| 94 |
+
params:
|
| 95 |
+
outdim: 256
|
| 96 |
+
|
| 97 |
+
first_stage_config:
|
| 98 |
+
target: sgm.models.autoencoder.AutoencodingEngine
|
| 99 |
+
params:
|
| 100 |
+
loss_config:
|
| 101 |
+
target: torch.nn.Identity
|
| 102 |
+
regularizer_config:
|
| 103 |
+
target: sgm.modules.autoencoding.regularizers.DiagonalGaussianRegularizer
|
| 104 |
+
encoder_config:
|
| 105 |
+
target: sgm.modules.diffusionmodules.model.Encoder
|
| 106 |
+
params:
|
| 107 |
+
attn_type: vanilla
|
| 108 |
+
double_z: True
|
| 109 |
+
z_channels: 4
|
| 110 |
+
resolution: 256
|
| 111 |
+
in_channels: 3
|
| 112 |
+
out_ch: 3
|
| 113 |
+
ch: 128
|
| 114 |
+
ch_mult: [1, 2, 4, 4]
|
| 115 |
+
num_res_blocks: 2
|
| 116 |
+
attn_resolutions: []
|
| 117 |
+
dropout: 0.0
|
| 118 |
+
decoder_config:
|
| 119 |
+
target: sgm.modules.autoencoding.temporal_ae.VideoDecoder
|
| 120 |
+
params:
|
| 121 |
+
attn_type: vanilla
|
| 122 |
+
double_z: True
|
| 123 |
+
z_channels: 4
|
| 124 |
+
resolution: 256
|
| 125 |
+
in_channels: 3
|
| 126 |
+
out_ch: 3
|
| 127 |
+
ch: 128
|
| 128 |
+
ch_mult: [1, 2, 4, 4]
|
| 129 |
+
num_res_blocks: 2
|
| 130 |
+
attn_resolutions: []
|
| 131 |
+
dropout: 0.0
|
| 132 |
+
video_kernel_size: [3, 1, 1]
|
| 133 |
+
|
| 134 |
+
sampler_config:
|
| 135 |
+
target: sgm.modules.diffusionmodules.sampling.EulerEDMSampler
|
| 136 |
+
params:
|
| 137 |
+
discretization_config:
|
| 138 |
+
target: sgm.modules.diffusionmodules.discretizer.EDMDiscretization
|
| 139 |
+
params:
|
| 140 |
+
sigma_max: 700.0
|
| 141 |
+
|
| 142 |
+
guider_config:
|
| 143 |
+
target: sgm.modules.diffusionmodules.guiders.LinearPredictionGuider
|
| 144 |
+
params:
|
| 145 |
+
max_scale: 2.5
|
| 146 |
+
min_scale: 1.0
|
MindEye_Imagery/src/generative_models/scripts/sampling/configs/svd_image_decoder.yaml
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
model:
|
| 2 |
+
target: sgm.models.diffusion.DiffusionEngine
|
| 3 |
+
params:
|
| 4 |
+
scale_factor: 0.18215
|
| 5 |
+
disable_first_stage_autocast: True
|
| 6 |
+
ckpt_path: checkpoints/svd_image_decoder.safetensors
|
| 7 |
+
|
| 8 |
+
denoiser_config:
|
| 9 |
+
target: sgm.modules.diffusionmodules.denoiser.Denoiser
|
| 10 |
+
params:
|
| 11 |
+
scaling_config:
|
| 12 |
+
target: sgm.modules.diffusionmodules.denoiser_scaling.VScalingWithEDMcNoise
|
| 13 |
+
|
| 14 |
+
network_config:
|
| 15 |
+
target: sgm.modules.diffusionmodules.video_model.VideoUNet
|
| 16 |
+
params:
|
| 17 |
+
adm_in_channels: 768
|
| 18 |
+
num_classes: sequential
|
| 19 |
+
use_checkpoint: True
|
| 20 |
+
in_channels: 8
|
| 21 |
+
out_channels: 4
|
| 22 |
+
model_channels: 320
|
| 23 |
+
attention_resolutions: [4, 2, 1]
|
| 24 |
+
num_res_blocks: 2
|
| 25 |
+
channel_mult: [1, 2, 4, 4]
|
| 26 |
+
num_head_channels: 64
|
| 27 |
+
use_linear_in_transformer: True
|
| 28 |
+
transformer_depth: 1
|
| 29 |
+
context_dim: 1024
|
| 30 |
+
spatial_transformer_attn_type: softmax-xformers
|
| 31 |
+
extra_ff_mix_layer: True
|
| 32 |
+
use_spatial_context: True
|
| 33 |
+
merge_strategy: learned_with_images
|
| 34 |
+
video_kernel_size: [3, 1, 1]
|
| 35 |
+
|
| 36 |
+
conditioner_config:
|
| 37 |
+
target: sgm.modules.GeneralConditioner
|
| 38 |
+
params:
|
| 39 |
+
emb_models:
|
| 40 |
+
- is_trainable: False
|
| 41 |
+
input_key: cond_frames_without_noise
|
| 42 |
+
target: sgm.modules.encoders.modules.FrozenOpenCLIPImagePredictionEmbedder
|
| 43 |
+
params:
|
| 44 |
+
n_cond_frames: 1
|
| 45 |
+
n_copies: 1
|
| 46 |
+
open_clip_embedding_config:
|
| 47 |
+
target: sgm.modules.encoders.modules.FrozenOpenCLIPImageEmbedder
|
| 48 |
+
params:
|
| 49 |
+
freeze: True
|
| 50 |
+
|
| 51 |
+
- input_key: fps_id
|
| 52 |
+
is_trainable: False
|
| 53 |
+
target: sgm.modules.encoders.modules.ConcatTimestepEmbedderND
|
| 54 |
+
params:
|
| 55 |
+
outdim: 256
|
| 56 |
+
|
| 57 |
+
- input_key: motion_bucket_id
|
| 58 |
+
is_trainable: False
|
| 59 |
+
target: sgm.modules.encoders.modules.ConcatTimestepEmbedderND
|
| 60 |
+
params:
|
| 61 |
+
outdim: 256
|
| 62 |
+
|
| 63 |
+
- input_key: cond_frames
|
| 64 |
+
is_trainable: False
|
| 65 |
+
target: sgm.modules.encoders.modules.VideoPredictionEmbedderWithEncoder
|
| 66 |
+
params:
|
| 67 |
+
disable_encoder_autocast: True
|
| 68 |
+
n_cond_frames: 1
|
| 69 |
+
n_copies: 1
|
| 70 |
+
is_ae: True
|
| 71 |
+
encoder_config:
|
| 72 |
+
target: sgm.models.autoencoder.AutoencoderKLModeOnly
|
| 73 |
+
params:
|
| 74 |
+
embed_dim: 4
|
| 75 |
+
monitor: val/rec_loss
|
| 76 |
+
ddconfig:
|
| 77 |
+
attn_type: vanilla-xformers
|
| 78 |
+
double_z: True
|
| 79 |
+
z_channels: 4
|
| 80 |
+
resolution: 256
|
| 81 |
+
in_channels: 3
|
| 82 |
+
out_ch: 3
|
| 83 |
+
ch: 128
|
| 84 |
+
ch_mult: [1, 2, 4, 4]
|
| 85 |
+
num_res_blocks: 2
|
| 86 |
+
attn_resolutions: []
|
| 87 |
+
dropout: 0.0
|
| 88 |
+
lossconfig:
|
| 89 |
+
target: torch.nn.Identity
|
| 90 |
+
|
| 91 |
+
- input_key: cond_aug
|
| 92 |
+
is_trainable: False
|
| 93 |
+
target: sgm.modules.encoders.modules.ConcatTimestepEmbedderND
|
| 94 |
+
params:
|
| 95 |
+
outdim: 256
|
| 96 |
+
|
| 97 |
+
first_stage_config:
|
| 98 |
+
target: sgm.models.autoencoder.AutoencoderKL
|
| 99 |
+
params:
|
| 100 |
+
embed_dim: 4
|
| 101 |
+
monitor: val/rec_loss
|
| 102 |
+
ddconfig:
|
| 103 |
+
attn_type: vanilla-xformers
|
| 104 |
+
double_z: True
|
| 105 |
+
z_channels: 4
|
| 106 |
+
resolution: 256
|
| 107 |
+
in_channels: 3
|
| 108 |
+
out_ch: 3
|
| 109 |
+
ch: 128
|
| 110 |
+
ch_mult: [1, 2, 4, 4]
|
| 111 |
+
num_res_blocks: 2
|
| 112 |
+
attn_resolutions: []
|
| 113 |
+
dropout: 0.0
|
| 114 |
+
lossconfig:
|
| 115 |
+
target: torch.nn.Identity
|
| 116 |
+
|
| 117 |
+
sampler_config:
|
| 118 |
+
target: sgm.modules.diffusionmodules.sampling.EulerEDMSampler
|
| 119 |
+
params:
|
| 120 |
+
discretization_config:
|
| 121 |
+
target: sgm.modules.diffusionmodules.discretizer.EDMDiscretization
|
| 122 |
+
params:
|
| 123 |
+
sigma_max: 700.0
|
| 124 |
+
|
| 125 |
+
guider_config:
|
| 126 |
+
target: sgm.modules.diffusionmodules.guiders.LinearPredictionGuider
|
| 127 |
+
params:
|
| 128 |
+
max_scale: 2.5
|
| 129 |
+
min_scale: 1.0
|
MindEye_Imagery/src/generative_models/scripts/sampling/configs/svd_xt.yaml
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
model:
|
| 2 |
+
target: sgm.models.diffusion.DiffusionEngine
|
| 3 |
+
params:
|
| 4 |
+
scale_factor: 0.18215
|
| 5 |
+
disable_first_stage_autocast: True
|
| 6 |
+
ckpt_path: checkpoints/svd_xt.safetensors
|
| 7 |
+
|
| 8 |
+
denoiser_config:
|
| 9 |
+
target: sgm.modules.diffusionmodules.denoiser.Denoiser
|
| 10 |
+
params:
|
| 11 |
+
scaling_config:
|
| 12 |
+
target: sgm.modules.diffusionmodules.denoiser_scaling.VScalingWithEDMcNoise
|
| 13 |
+
|
| 14 |
+
network_config:
|
| 15 |
+
target: sgm.modules.diffusionmodules.video_model.VideoUNet
|
| 16 |
+
params:
|
| 17 |
+
adm_in_channels: 768
|
| 18 |
+
num_classes: sequential
|
| 19 |
+
use_checkpoint: True
|
| 20 |
+
in_channels: 8
|
| 21 |
+
out_channels: 4
|
| 22 |
+
model_channels: 320
|
| 23 |
+
attention_resolutions: [4, 2, 1]
|
| 24 |
+
num_res_blocks: 2
|
| 25 |
+
channel_mult: [1, 2, 4, 4]
|
| 26 |
+
num_head_channels: 64
|
| 27 |
+
use_linear_in_transformer: True
|
| 28 |
+
transformer_depth: 1
|
| 29 |
+
context_dim: 1024
|
| 30 |
+
spatial_transformer_attn_type: softmax-xformers
|
| 31 |
+
extra_ff_mix_layer: True
|
| 32 |
+
use_spatial_context: True
|
| 33 |
+
merge_strategy: learned_with_images
|
| 34 |
+
video_kernel_size: [3, 1, 1]
|
| 35 |
+
|
| 36 |
+
conditioner_config:
|
| 37 |
+
target: sgm.modules.GeneralConditioner
|
| 38 |
+
params:
|
| 39 |
+
emb_models:
|
| 40 |
+
- is_trainable: False
|
| 41 |
+
input_key: cond_frames_without_noise
|
| 42 |
+
target: sgm.modules.encoders.modules.FrozenOpenCLIPImagePredictionEmbedder
|
| 43 |
+
params:
|
| 44 |
+
n_cond_frames: 1
|
| 45 |
+
n_copies: 1
|
| 46 |
+
open_clip_embedding_config:
|
| 47 |
+
target: sgm.modules.encoders.modules.FrozenOpenCLIPImageEmbedder
|
| 48 |
+
params:
|
| 49 |
+
freeze: True
|
| 50 |
+
|
| 51 |
+
- input_key: fps_id
|
| 52 |
+
is_trainable: False
|
| 53 |
+
target: sgm.modules.encoders.modules.ConcatTimestepEmbedderND
|
| 54 |
+
params:
|
| 55 |
+
outdim: 256
|
| 56 |
+
|
| 57 |
+
- input_key: motion_bucket_id
|
| 58 |
+
is_trainable: False
|
| 59 |
+
target: sgm.modules.encoders.modules.ConcatTimestepEmbedderND
|
| 60 |
+
params:
|
| 61 |
+
outdim: 256
|
| 62 |
+
|
| 63 |
+
- input_key: cond_frames
|
| 64 |
+
is_trainable: False
|
| 65 |
+
target: sgm.modules.encoders.modules.VideoPredictionEmbedderWithEncoder
|
| 66 |
+
params:
|
| 67 |
+
disable_encoder_autocast: True
|
| 68 |
+
n_cond_frames: 1
|
| 69 |
+
n_copies: 1
|
| 70 |
+
is_ae: True
|
| 71 |
+
encoder_config:
|
| 72 |
+
target: sgm.models.autoencoder.AutoencoderKLModeOnly
|
| 73 |
+
params:
|
| 74 |
+
embed_dim: 4
|
| 75 |
+
monitor: val/rec_loss
|
| 76 |
+
ddconfig:
|
| 77 |
+
attn_type: vanilla-xformers
|
| 78 |
+
double_z: True
|
| 79 |
+
z_channels: 4
|
| 80 |
+
resolution: 256
|
| 81 |
+
in_channels: 3
|
| 82 |
+
out_ch: 3
|
| 83 |
+
ch: 128
|
| 84 |
+
ch_mult: [1, 2, 4, 4]
|
| 85 |
+
num_res_blocks: 2
|
| 86 |
+
attn_resolutions: []
|
| 87 |
+
dropout: 0.0
|
| 88 |
+
lossconfig:
|
| 89 |
+
target: torch.nn.Identity
|
| 90 |
+
|
| 91 |
+
- input_key: cond_aug
|
| 92 |
+
is_trainable: False
|
| 93 |
+
target: sgm.modules.encoders.modules.ConcatTimestepEmbedderND
|
| 94 |
+
params:
|
| 95 |
+
outdim: 256
|
| 96 |
+
|
| 97 |
+
first_stage_config:
|
| 98 |
+
target: sgm.models.autoencoder.AutoencodingEngine
|
| 99 |
+
params:
|
| 100 |
+
loss_config:
|
| 101 |
+
target: torch.nn.Identity
|
| 102 |
+
regularizer_config:
|
| 103 |
+
target: sgm.modules.autoencoding.regularizers.DiagonalGaussianRegularizer
|
| 104 |
+
encoder_config:
|
| 105 |
+
target: sgm.modules.diffusionmodules.model.Encoder
|
| 106 |
+
params:
|
| 107 |
+
attn_type: vanilla
|
| 108 |
+
double_z: True
|
| 109 |
+
z_channels: 4
|
| 110 |
+
resolution: 256
|
| 111 |
+
in_channels: 3
|
| 112 |
+
out_ch: 3
|
| 113 |
+
ch: 128
|
| 114 |
+
ch_mult: [1, 2, 4, 4]
|
| 115 |
+
num_res_blocks: 2
|
| 116 |
+
attn_resolutions: []
|
| 117 |
+
dropout: 0.0
|
| 118 |
+
decoder_config:
|
| 119 |
+
target: sgm.modules.autoencoding.temporal_ae.VideoDecoder
|
| 120 |
+
params:
|
| 121 |
+
attn_type: vanilla
|
| 122 |
+
double_z: True
|
| 123 |
+
z_channels: 4
|
| 124 |
+
resolution: 256
|
| 125 |
+
in_channels: 3
|
| 126 |
+
out_ch: 3
|
| 127 |
+
ch: 128
|
| 128 |
+
ch_mult: [1, 2, 4, 4]
|
| 129 |
+
num_res_blocks: 2
|
| 130 |
+
attn_resolutions: []
|
| 131 |
+
dropout: 0.0
|
| 132 |
+
video_kernel_size: [3, 1, 1]
|
| 133 |
+
|
| 134 |
+
sampler_config:
|
| 135 |
+
target: sgm.modules.diffusionmodules.sampling.EulerEDMSampler
|
| 136 |
+
params:
|
| 137 |
+
discretization_config:
|
| 138 |
+
target: sgm.modules.diffusionmodules.discretizer.EDMDiscretization
|
| 139 |
+
params:
|
| 140 |
+
sigma_max: 700.0
|
| 141 |
+
|
| 142 |
+
guider_config:
|
| 143 |
+
target: sgm.modules.diffusionmodules.guiders.LinearPredictionGuider
|
| 144 |
+
params:
|
| 145 |
+
max_scale: 3.0
|
| 146 |
+
min_scale: 1.5
|
MindEye_Imagery/src/generative_models/scripts/sampling/configs/svd_xt_image_decoder.yaml
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
model:
|
| 2 |
+
target: sgm.models.diffusion.DiffusionEngine
|
| 3 |
+
params:
|
| 4 |
+
scale_factor: 0.18215
|
| 5 |
+
disable_first_stage_autocast: True
|
| 6 |
+
ckpt_path: checkpoints/svd_xt_image_decoder.safetensors
|
| 7 |
+
|
| 8 |
+
denoiser_config:
|
| 9 |
+
target: sgm.modules.diffusionmodules.denoiser.Denoiser
|
| 10 |
+
params:
|
| 11 |
+
scaling_config:
|
| 12 |
+
target: sgm.modules.diffusionmodules.denoiser_scaling.VScalingWithEDMcNoise
|
| 13 |
+
|
| 14 |
+
network_config:
|
| 15 |
+
target: sgm.modules.diffusionmodules.video_model.VideoUNet
|
| 16 |
+
params:
|
| 17 |
+
adm_in_channels: 768
|
| 18 |
+
num_classes: sequential
|
| 19 |
+
use_checkpoint: True
|
| 20 |
+
in_channels: 8
|
| 21 |
+
out_channels: 4
|
| 22 |
+
model_channels: 320
|
| 23 |
+
attention_resolutions: [4, 2, 1]
|
| 24 |
+
num_res_blocks: 2
|
| 25 |
+
channel_mult: [1, 2, 4, 4]
|
| 26 |
+
num_head_channels: 64
|
| 27 |
+
use_linear_in_transformer: True
|
| 28 |
+
transformer_depth: 1
|
| 29 |
+
context_dim: 1024
|
| 30 |
+
spatial_transformer_attn_type: softmax-xformers
|
| 31 |
+
extra_ff_mix_layer: True
|
| 32 |
+
use_spatial_context: True
|
| 33 |
+
merge_strategy: learned_with_images
|
| 34 |
+
video_kernel_size: [3, 1, 1]
|
| 35 |
+
|
| 36 |
+
conditioner_config:
|
| 37 |
+
target: sgm.modules.GeneralConditioner
|
| 38 |
+
params:
|
| 39 |
+
emb_models:
|
| 40 |
+
- is_trainable: False
|
| 41 |
+
input_key: cond_frames_without_noise
|
| 42 |
+
target: sgm.modules.encoders.modules.FrozenOpenCLIPImagePredictionEmbedder
|
| 43 |
+
params:
|
| 44 |
+
n_cond_frames: 1
|
| 45 |
+
n_copies: 1
|
| 46 |
+
open_clip_embedding_config:
|
| 47 |
+
target: sgm.modules.encoders.modules.FrozenOpenCLIPImageEmbedder
|
| 48 |
+
params:
|
| 49 |
+
freeze: True
|
| 50 |
+
|
| 51 |
+
- input_key: fps_id
|
| 52 |
+
is_trainable: False
|
| 53 |
+
target: sgm.modules.encoders.modules.ConcatTimestepEmbedderND
|
| 54 |
+
params:
|
| 55 |
+
outdim: 256
|
| 56 |
+
|
| 57 |
+
- input_key: motion_bucket_id
|
| 58 |
+
is_trainable: False
|
| 59 |
+
target: sgm.modules.encoders.modules.ConcatTimestepEmbedderND
|
| 60 |
+
params:
|
| 61 |
+
outdim: 256
|
| 62 |
+
|
| 63 |
+
- input_key: cond_frames
|
| 64 |
+
is_trainable: False
|
| 65 |
+
target: sgm.modules.encoders.modules.VideoPredictionEmbedderWithEncoder
|
| 66 |
+
params:
|
| 67 |
+
disable_encoder_autocast: True
|
| 68 |
+
n_cond_frames: 1
|
| 69 |
+
n_copies: 1
|
| 70 |
+
is_ae: True
|
| 71 |
+
encoder_config:
|
| 72 |
+
target: sgm.models.autoencoder.AutoencoderKLModeOnly
|
| 73 |
+
params:
|
| 74 |
+
embed_dim: 4
|
| 75 |
+
monitor: val/rec_loss
|
| 76 |
+
ddconfig:
|
| 77 |
+
attn_type: vanilla-xformers
|
| 78 |
+
double_z: True
|
| 79 |
+
z_channels: 4
|
| 80 |
+
resolution: 256
|
| 81 |
+
in_channels: 3
|
| 82 |
+
out_ch: 3
|
| 83 |
+
ch: 128
|
| 84 |
+
ch_mult: [1, 2, 4, 4]
|
| 85 |
+
num_res_blocks: 2
|
| 86 |
+
attn_resolutions: []
|
| 87 |
+
dropout: 0.0
|
| 88 |
+
lossconfig:
|
| 89 |
+
target: torch.nn.Identity
|
| 90 |
+
|
| 91 |
+
- input_key: cond_aug
|
| 92 |
+
is_trainable: False
|
| 93 |
+
target: sgm.modules.encoders.modules.ConcatTimestepEmbedderND
|
| 94 |
+
params:
|
| 95 |
+
outdim: 256
|
| 96 |
+
|
| 97 |
+
first_stage_config:
|
| 98 |
+
target: sgm.models.autoencoder.AutoencoderKL
|
| 99 |
+
params:
|
| 100 |
+
embed_dim: 4
|
| 101 |
+
monitor: val/rec_loss
|
| 102 |
+
ddconfig:
|
| 103 |
+
attn_type: vanilla-xformers
|
| 104 |
+
double_z: True
|
| 105 |
+
z_channels: 4
|
| 106 |
+
resolution: 256
|
| 107 |
+
in_channels: 3
|
| 108 |
+
out_ch: 3
|
| 109 |
+
ch: 128
|
| 110 |
+
ch_mult: [1, 2, 4, 4]
|
| 111 |
+
num_res_blocks: 2
|
| 112 |
+
attn_resolutions: []
|
| 113 |
+
dropout: 0.0
|
| 114 |
+
lossconfig:
|
| 115 |
+
target: torch.nn.Identity
|
| 116 |
+
|
| 117 |
+
sampler_config:
|
| 118 |
+
target: sgm.modules.diffusionmodules.sampling.EulerEDMSampler
|
| 119 |
+
params:
|
| 120 |
+
discretization_config:
|
| 121 |
+
target: sgm.modules.diffusionmodules.discretizer.EDMDiscretization
|
| 122 |
+
params:
|
| 123 |
+
sigma_max: 700.0
|
| 124 |
+
|
| 125 |
+
guider_config:
|
| 126 |
+
target: sgm.modules.diffusionmodules.guiders.LinearPredictionGuider
|
| 127 |
+
params:
|
| 128 |
+
max_scale: 3.0
|
| 129 |
+
min_scale: 1.5
|
MindEye_Imagery/src/generative_models/scripts/sampling/simple_video_sample.py
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import math
|
| 2 |
+
import os
|
| 3 |
+
from glob import glob
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
from typing import Optional
|
| 6 |
+
|
| 7 |
+
import cv2
|
| 8 |
+
import numpy as np
|
| 9 |
+
import torch
|
| 10 |
+
from einops import rearrange, repeat
|
| 11 |
+
from fire import Fire
|
| 12 |
+
from omegaconf import OmegaConf
|
| 13 |
+
from PIL import Image
|
| 14 |
+
from torchvision.transforms import ToTensor
|
| 15 |
+
|
| 16 |
+
from scripts.util.detection.nsfw_and_watermark_dectection import \
|
| 17 |
+
DeepFloydDataFiltering
|
| 18 |
+
from sgm.inference.helpers import embed_watermark
|
| 19 |
+
from sgm.util import default, instantiate_from_config
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def sample(
|
| 23 |
+
input_path: str = "assets/test_image.png", # Can either be image file or folder with image files
|
| 24 |
+
num_frames: Optional[int] = None,
|
| 25 |
+
num_steps: Optional[int] = None,
|
| 26 |
+
version: str = "svd",
|
| 27 |
+
fps_id: int = 6,
|
| 28 |
+
motion_bucket_id: int = 127,
|
| 29 |
+
cond_aug: float = 0.02,
|
| 30 |
+
seed: int = 23,
|
| 31 |
+
decoding_t: int = 14, # Number of frames decoded at a time! This eats most VRAM. Reduce if necessary.
|
| 32 |
+
device: str = "cuda",
|
| 33 |
+
output_folder: Optional[str] = None,
|
| 34 |
+
):
|
| 35 |
+
"""
|
| 36 |
+
Simple script to generate a single sample conditioned on an image `input_path` or multiple images, one for each
|
| 37 |
+
image file in folder `input_path`. If you run out of VRAM, try decreasing `decoding_t`.
|
| 38 |
+
"""
|
| 39 |
+
|
| 40 |
+
if version == "svd":
|
| 41 |
+
num_frames = default(num_frames, 14)
|
| 42 |
+
num_steps = default(num_steps, 25)
|
| 43 |
+
output_folder = default(output_folder, "outputs/simple_video_sample/svd/")
|
| 44 |
+
model_config = "scripts/sampling/configs/svd.yaml"
|
| 45 |
+
elif version == "svd_xt":
|
| 46 |
+
num_frames = default(num_frames, 25)
|
| 47 |
+
num_steps = default(num_steps, 30)
|
| 48 |
+
output_folder = default(output_folder, "outputs/simple_video_sample/svd_xt/")
|
| 49 |
+
model_config = "scripts/sampling/configs/svd_xt.yaml"
|
| 50 |
+
elif version == "svd_image_decoder":
|
| 51 |
+
num_frames = default(num_frames, 14)
|
| 52 |
+
num_steps = default(num_steps, 25)
|
| 53 |
+
output_folder = default(
|
| 54 |
+
output_folder, "outputs/simple_video_sample/svd_image_decoder/"
|
| 55 |
+
)
|
| 56 |
+
model_config = "scripts/sampling/configs/svd_image_decoder.yaml"
|
| 57 |
+
elif version == "svd_xt_image_decoder":
|
| 58 |
+
num_frames = default(num_frames, 25)
|
| 59 |
+
num_steps = default(num_steps, 30)
|
| 60 |
+
output_folder = default(
|
| 61 |
+
output_folder, "outputs/simple_video_sample/svd_xt_image_decoder/"
|
| 62 |
+
)
|
| 63 |
+
model_config = "scripts/sampling/configs/svd_xt_image_decoder.yaml"
|
| 64 |
+
else:
|
| 65 |
+
raise ValueError(f"Version {version} does not exist.")
|
| 66 |
+
|
| 67 |
+
model, filter = load_model(
|
| 68 |
+
model_config,
|
| 69 |
+
device,
|
| 70 |
+
num_frames,
|
| 71 |
+
num_steps,
|
| 72 |
+
)
|
| 73 |
+
torch.manual_seed(seed)
|
| 74 |
+
|
| 75 |
+
path = Path(input_path)
|
| 76 |
+
all_img_paths = []
|
| 77 |
+
if path.is_file():
|
| 78 |
+
if any([input_path.endswith(x) for x in ["jpg", "jpeg", "png"]]):
|
| 79 |
+
all_img_paths = [input_path]
|
| 80 |
+
else:
|
| 81 |
+
raise ValueError("Path is not valid image file.")
|
| 82 |
+
elif path.is_dir():
|
| 83 |
+
all_img_paths = sorted(
|
| 84 |
+
[
|
| 85 |
+
f
|
| 86 |
+
for f in path.iterdir()
|
| 87 |
+
if f.is_file() and f.suffix.lower() in [".jpg", ".jpeg", ".png"]
|
| 88 |
+
]
|
| 89 |
+
)
|
| 90 |
+
if len(all_img_paths) == 0:
|
| 91 |
+
raise ValueError("Folder does not contain any images.")
|
| 92 |
+
else:
|
| 93 |
+
raise ValueError
|
| 94 |
+
|
| 95 |
+
for input_img_path in all_img_paths:
|
| 96 |
+
with Image.open(input_img_path) as image:
|
| 97 |
+
if image.mode == "RGBA":
|
| 98 |
+
image = image.convert("RGB")
|
| 99 |
+
w, h = image.size
|
| 100 |
+
|
| 101 |
+
if h % 64 != 0 or w % 64 != 0:
|
| 102 |
+
width, height = map(lambda x: x - x % 64, (w, h))
|
| 103 |
+
image = image.resize((width, height))
|
| 104 |
+
print(
|
| 105 |
+
f"WARNING: Your image is of size {h}x{w} which is not divisible by 64. We are resizing to {height}x{width}!"
|
| 106 |
+
)
|
| 107 |
+
|
| 108 |
+
image = ToTensor()(image)
|
| 109 |
+
image = image * 2.0 - 1.0
|
| 110 |
+
|
| 111 |
+
image = image.unsqueeze(0).to(device)
|
| 112 |
+
H, W = image.shape[2:]
|
| 113 |
+
assert image.shape[1] == 3
|
| 114 |
+
F = 8
|
| 115 |
+
C = 4
|
| 116 |
+
shape = (num_frames, C, H // F, W // F)
|
| 117 |
+
if (H, W) != (576, 1024):
|
| 118 |
+
print(
|
| 119 |
+
"WARNING: The conditioning frame you provided is not 576x1024. This leads to suboptimal performance as model was only trained on 576x1024. Consider increasing `cond_aug`."
|
| 120 |
+
)
|
| 121 |
+
if motion_bucket_id > 255:
|
| 122 |
+
print(
|
| 123 |
+
"WARNING: High motion bucket! This may lead to suboptimal performance."
|
| 124 |
+
)
|
| 125 |
+
|
| 126 |
+
if fps_id < 5:
|
| 127 |
+
print("WARNING: Small fps value! This may lead to suboptimal performance.")
|
| 128 |
+
|
| 129 |
+
if fps_id > 30:
|
| 130 |
+
print("WARNING: Large fps value! This may lead to suboptimal performance.")
|
| 131 |
+
|
| 132 |
+
value_dict = {}
|
| 133 |
+
value_dict["motion_bucket_id"] = motion_bucket_id
|
| 134 |
+
value_dict["fps_id"] = fps_id
|
| 135 |
+
value_dict["cond_aug"] = cond_aug
|
| 136 |
+
value_dict["cond_frames_without_noise"] = image
|
| 137 |
+
value_dict["cond_frames"] = image + cond_aug * torch.randn_like(image)
|
| 138 |
+
value_dict["cond_aug"] = cond_aug
|
| 139 |
+
|
| 140 |
+
with torch.no_grad():
|
| 141 |
+
with torch.autocast(device):
|
| 142 |
+
batch, batch_uc = get_batch(
|
| 143 |
+
get_unique_embedder_keys_from_conditioner(model.conditioner),
|
| 144 |
+
value_dict,
|
| 145 |
+
[1, num_frames],
|
| 146 |
+
T=num_frames,
|
| 147 |
+
device=device,
|
| 148 |
+
)
|
| 149 |
+
c, uc = model.conditioner.get_unconditional_conditioning(
|
| 150 |
+
batch,
|
| 151 |
+
batch_uc=batch_uc,
|
| 152 |
+
force_uc_zero_embeddings=[
|
| 153 |
+
"cond_frames",
|
| 154 |
+
"cond_frames_without_noise",
|
| 155 |
+
],
|
| 156 |
+
)
|
| 157 |
+
|
| 158 |
+
for k in ["crossattn", "concat"]:
|
| 159 |
+
uc[k] = repeat(uc[k], "b ... -> b t ...", t=num_frames)
|
| 160 |
+
uc[k] = rearrange(uc[k], "b t ... -> (b t) ...", t=num_frames)
|
| 161 |
+
c[k] = repeat(c[k], "b ... -> b t ...", t=num_frames)
|
| 162 |
+
c[k] = rearrange(c[k], "b t ... -> (b t) ...", t=num_frames)
|
| 163 |
+
|
| 164 |
+
randn = torch.randn(shape, device=device)
|
| 165 |
+
|
| 166 |
+
additional_model_inputs = {}
|
| 167 |
+
additional_model_inputs["image_only_indicator"] = torch.zeros(
|
| 168 |
+
2, num_frames
|
| 169 |
+
).to(device)
|
| 170 |
+
additional_model_inputs["num_video_frames"] = batch["num_video_frames"]
|
| 171 |
+
|
| 172 |
+
def denoiser(input, sigma, c):
|
| 173 |
+
return model.denoiser(
|
| 174 |
+
model.model, input, sigma, c, **additional_model_inputs
|
| 175 |
+
)
|
| 176 |
+
|
| 177 |
+
samples_z = model.sampler(denoiser, randn, cond=c, uc=uc)
|
| 178 |
+
model.en_and_decode_n_samples_a_time = decoding_t
|
| 179 |
+
samples_x = model.decode_first_stage(samples_z)
|
| 180 |
+
samples = torch.clamp((samples_x + 1.0) / 2.0, min=0.0, max=1.0)
|
| 181 |
+
|
| 182 |
+
os.makedirs(output_folder, exist_ok=True)
|
| 183 |
+
base_count = len(glob(os.path.join(output_folder, "*.mp4")))
|
| 184 |
+
video_path = os.path.join(output_folder, f"{base_count:06d}.mp4")
|
| 185 |
+
writer = cv2.VideoWriter(
|
| 186 |
+
video_path,
|
| 187 |
+
cv2.VideoWriter_fourcc(*"MP4V"),
|
| 188 |
+
fps_id + 1,
|
| 189 |
+
(samples.shape[-1], samples.shape[-2]),
|
| 190 |
+
)
|
| 191 |
+
|
| 192 |
+
samples = embed_watermark(samples)
|
| 193 |
+
samples = filter(samples)
|
| 194 |
+
vid = (
|
| 195 |
+
(rearrange(samples, "t c h w -> t h w c") * 255)
|
| 196 |
+
.cpu()
|
| 197 |
+
.numpy()
|
| 198 |
+
.astype(np.uint8)
|
| 199 |
+
)
|
| 200 |
+
for frame in vid:
|
| 201 |
+
frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
|
| 202 |
+
writer.write(frame)
|
| 203 |
+
writer.release()
|
| 204 |
+
|
| 205 |
+
|
| 206 |
+
def get_unique_embedder_keys_from_conditioner(conditioner):
|
| 207 |
+
return list(set([x.input_key for x in conditioner.embedders]))
|
| 208 |
+
|
| 209 |
+
|
| 210 |
+
def get_batch(keys, value_dict, N, T, device):
|
| 211 |
+
batch = {}
|
| 212 |
+
batch_uc = {}
|
| 213 |
+
|
| 214 |
+
for key in keys:
|
| 215 |
+
if key == "fps_id":
|
| 216 |
+
batch[key] = (
|
| 217 |
+
torch.tensor([value_dict["fps_id"]])
|
| 218 |
+
.to(device)
|
| 219 |
+
.repeat(int(math.prod(N)))
|
| 220 |
+
)
|
| 221 |
+
elif key == "motion_bucket_id":
|
| 222 |
+
batch[key] = (
|
| 223 |
+
torch.tensor([value_dict["motion_bucket_id"]])
|
| 224 |
+
.to(device)
|
| 225 |
+
.repeat(int(math.prod(N)))
|
| 226 |
+
)
|
| 227 |
+
elif key == "cond_aug":
|
| 228 |
+
batch[key] = repeat(
|
| 229 |
+
torch.tensor([value_dict["cond_aug"]]).to(device),
|
| 230 |
+
"1 -> b",
|
| 231 |
+
b=math.prod(N),
|
| 232 |
+
)
|
| 233 |
+
elif key == "cond_frames":
|
| 234 |
+
batch[key] = repeat(value_dict["cond_frames"], "1 ... -> b ...", b=N[0])
|
| 235 |
+
elif key == "cond_frames_without_noise":
|
| 236 |
+
batch[key] = repeat(
|
| 237 |
+
value_dict["cond_frames_without_noise"], "1 ... -> b ...", b=N[0]
|
| 238 |
+
)
|
| 239 |
+
else:
|
| 240 |
+
batch[key] = value_dict[key]
|
| 241 |
+
|
| 242 |
+
if T is not None:
|
| 243 |
+
batch["num_video_frames"] = T
|
| 244 |
+
|
| 245 |
+
for key in batch.keys():
|
| 246 |
+
if key not in batch_uc and isinstance(batch[key], torch.Tensor):
|
| 247 |
+
batch_uc[key] = torch.clone(batch[key])
|
| 248 |
+
return batch, batch_uc
|
| 249 |
+
|
| 250 |
+
|
| 251 |
+
def load_model(
|
| 252 |
+
config: str,
|
| 253 |
+
device: str,
|
| 254 |
+
num_frames: int,
|
| 255 |
+
num_steps: int,
|
| 256 |
+
):
|
| 257 |
+
config = OmegaConf.load(config)
|
| 258 |
+
if device == "cuda":
|
| 259 |
+
config.model.params.conditioner_config.params.emb_models[
|
| 260 |
+
0
|
| 261 |
+
].params.open_clip_embedding_config.params.init_device = device
|
| 262 |
+
|
| 263 |
+
config.model.params.sampler_config.params.num_steps = num_steps
|
| 264 |
+
config.model.params.sampler_config.params.guider_config.params.num_frames = (
|
| 265 |
+
num_frames
|
| 266 |
+
)
|
| 267 |
+
if device == "cuda":
|
| 268 |
+
with torch.device(device):
|
| 269 |
+
model = instantiate_from_config(config.model).to(device).eval()
|
| 270 |
+
else:
|
| 271 |
+
model = instantiate_from_config(config.model).to(device).eval()
|
| 272 |
+
|
| 273 |
+
filter = DeepFloydDataFiltering(verbose=False, device=device)
|
| 274 |
+
return model, filter
|
| 275 |
+
|
| 276 |
+
|
| 277 |
+
if __name__ == "__main__":
|
| 278 |
+
Fire(sample)
|
MindEye_Imagery/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.")
|
MindEye_Imagery/src/generative_models/scripts/util/detection/__init__.py
ADDED
|
File without changes
|
MindEye_Imagery/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.")
|
MindEye_Imagery/src/vdvae/.ipynb_checkpoints/vae-checkpoint.py
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
from torch import nn
|
| 3 |
+
from torch.nn import functional as F
|
| 4 |
+
from vae_helpers import HModule, get_1x1, get_3x3, DmolNet, draw_gaussian_diag_samples, gaussian_analytical_kl
|
| 5 |
+
from collections import defaultdict
|
| 6 |
+
import numpy as np
|
| 7 |
+
import itertools
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
class Block(nn.Module):
|
| 11 |
+
def __init__(self, in_width, middle_width, out_width, down_rate=None, residual=False, use_3x3=True, zero_last=False):
|
| 12 |
+
super().__init__()
|
| 13 |
+
self.down_rate = down_rate
|
| 14 |
+
self.residual = residual
|
| 15 |
+
self.c1 = get_1x1(in_width, middle_width)
|
| 16 |
+
self.c2 = get_3x3(middle_width, middle_width) if use_3x3 else get_1x1(middle_width, middle_width)
|
| 17 |
+
self.c3 = get_3x3(middle_width, middle_width) if use_3x3 else get_1x1(middle_width, middle_width)
|
| 18 |
+
self.c4 = get_1x1(middle_width, out_width, zero_weights=zero_last)
|
| 19 |
+
|
| 20 |
+
def forward(self, x):
|
| 21 |
+
xhat = self.c1(F.gelu(x))
|
| 22 |
+
xhat = self.c2(F.gelu(xhat))
|
| 23 |
+
xhat = self.c3(F.gelu(xhat))
|
| 24 |
+
xhat = self.c4(F.gelu(xhat))
|
| 25 |
+
out = x + xhat if self.residual else xhat
|
| 26 |
+
if self.down_rate is not None:
|
| 27 |
+
out = F.avg_pool2d(out, kernel_size=self.down_rate, stride=self.down_rate)
|
| 28 |
+
return out
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
def parse_layer_string(s):
|
| 32 |
+
layers = []
|
| 33 |
+
for ss in s.split(','):
|
| 34 |
+
if 'x' in ss:
|
| 35 |
+
res, num = ss.split('x')
|
| 36 |
+
count = int(num)
|
| 37 |
+
layers += [(int(res), None) for _ in range(count)]
|
| 38 |
+
elif 'm' in ss:
|
| 39 |
+
res, mixin = [int(a) for a in ss.split('m')]
|
| 40 |
+
layers.append((res, mixin))
|
| 41 |
+
elif 'd' in ss:
|
| 42 |
+
res, down_rate = [int(a) for a in ss.split('d')]
|
| 43 |
+
layers.append((res, down_rate))
|
| 44 |
+
else:
|
| 45 |
+
res = int(ss)
|
| 46 |
+
layers.append((res, None))
|
| 47 |
+
return layers
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def pad_channels(t, width):
|
| 51 |
+
d1, d2, d3, d4 = t.shape
|
| 52 |
+
empty = torch.zeros(d1, width, d3, d4, device=t.device)
|
| 53 |
+
empty[:, :d2, :, :] = t
|
| 54 |
+
return empty
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
def get_width_settings(width, s):
|
| 58 |
+
mapping = defaultdict(lambda: width)
|
| 59 |
+
if s:
|
| 60 |
+
s = s.split(',')
|
| 61 |
+
for ss in s:
|
| 62 |
+
k, v = ss.split(':')
|
| 63 |
+
mapping[int(k)] = int(v)
|
| 64 |
+
return mapping
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
class Encoder(HModule):
|
| 68 |
+
def build(self):
|
| 69 |
+
H = self.H
|
| 70 |
+
self.in_conv = get_3x3(H.image_channels, H.width)
|
| 71 |
+
self.widths = get_width_settings(H.width, H.custom_width_str)
|
| 72 |
+
enc_blocks = []
|
| 73 |
+
blockstr = parse_layer_string(H.enc_blocks)
|
| 74 |
+
for res, down_rate in blockstr:
|
| 75 |
+
use_3x3 = res > 2 # Don't use 3x3s for 1x1, 2x2 patches
|
| 76 |
+
enc_blocks.append(Block(self.widths[res], int(self.widths[res] * H.bottleneck_multiple), self.widths[res], down_rate=down_rate, residual=True, use_3x3=use_3x3))
|
| 77 |
+
n_blocks = len(blockstr)
|
| 78 |
+
for b in enc_blocks:
|
| 79 |
+
b.c4.weight.data *= np.sqrt(1 / n_blocks)
|
| 80 |
+
self.enc_blocks = nn.ModuleList(enc_blocks)
|
| 81 |
+
|
| 82 |
+
def forward(self, x):
|
| 83 |
+
x = x.permute(0, 3, 1, 2).contiguous()
|
| 84 |
+
x = self.in_conv(x)
|
| 85 |
+
activations = {}
|
| 86 |
+
activations[x.shape[2]] = x
|
| 87 |
+
for block in self.enc_blocks:
|
| 88 |
+
x = block(x)
|
| 89 |
+
res = x.shape[2]
|
| 90 |
+
x = x if x.shape[1] == self.widths[res] else pad_channels(x, self.widths[res])
|
| 91 |
+
activations[res] = x
|
| 92 |
+
return activations
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
class DecBlock(nn.Module):
|
| 96 |
+
def __init__(self, H, res, mixin, n_blocks):
|
| 97 |
+
super().__init__()
|
| 98 |
+
self.base = res
|
| 99 |
+
self.mixin = mixin
|
| 100 |
+
self.H = H
|
| 101 |
+
self.widths = get_width_settings(H.width, H.custom_width_str)
|
| 102 |
+
width = self.widths[res]
|
| 103 |
+
use_3x3 = res > 2
|
| 104 |
+
cond_width = int(width * H.bottleneck_multiple)
|
| 105 |
+
self.zdim = H.zdim
|
| 106 |
+
self.enc = Block(width * 2, cond_width, H.zdim * 2, residual=False, use_3x3=use_3x3)
|
| 107 |
+
self.prior = Block(width, cond_width, H.zdim * 2 + width, residual=False, use_3x3=use_3x3, zero_last=True)
|
| 108 |
+
self.z_proj = get_1x1(H.zdim, width)
|
| 109 |
+
self.z_proj.weight.data *= np.sqrt(1 / n_blocks)
|
| 110 |
+
self.resnet = Block(width, cond_width, width, residual=True, use_3x3=use_3x3)
|
| 111 |
+
self.resnet.c4.weight.data *= np.sqrt(1 / n_blocks)
|
| 112 |
+
self.z_fn = lambda x: self.z_proj(x)
|
| 113 |
+
|
| 114 |
+
def sample(self, x, acts):
|
| 115 |
+
qm, qv = self.enc(torch.cat([x, acts], dim=1)).chunk(2, dim=1)
|
| 116 |
+
feats = self.prior(x)
|
| 117 |
+
pm, pv, xpp = feats[:, :self.zdim, ...], feats[:, self.zdim:self.zdim * 2, ...], feats[:, self.zdim * 2:, ...]
|
| 118 |
+
x = x + xpp
|
| 119 |
+
z = draw_gaussian_diag_samples(qm, qv)
|
| 120 |
+
kl = gaussian_analytical_kl(qm, pm, qv, pv)
|
| 121 |
+
return z, x, kl
|
| 122 |
+
|
| 123 |
+
def sample_uncond(self, x, t=None, lvs=None):
|
| 124 |
+
n, c, h, w = x.shape
|
| 125 |
+
feats = self.prior(x)
|
| 126 |
+
pm, pv, xpp = feats[:, :self.zdim, ...], feats[:, self.zdim:self.zdim * 2, ...], feats[:, self.zdim * 2:, ...]
|
| 127 |
+
x = x + xpp
|
| 128 |
+
if lvs is not None:
|
| 129 |
+
z = lvs
|
| 130 |
+
else:
|
| 131 |
+
if t is not None:
|
| 132 |
+
pv = pv + torch.ones_like(pv) * np.log(t)
|
| 133 |
+
z = draw_gaussian_diag_samples(pm, pv)
|
| 134 |
+
return z, x
|
| 135 |
+
|
| 136 |
+
def get_inputs(self, xs, activations):
|
| 137 |
+
acts = activations[self.base]
|
| 138 |
+
try:
|
| 139 |
+
x = xs[self.base]
|
| 140 |
+
except KeyError:
|
| 141 |
+
x = torch.zeros_like(acts)
|
| 142 |
+
if acts.shape[0] != x.shape[0]:
|
| 143 |
+
x = x.repeat(acts.shape[0], 1, 1, 1)
|
| 144 |
+
return x, acts
|
| 145 |
+
|
| 146 |
+
def forward(self, xs, activations, get_latents=False):
|
| 147 |
+
x, acts = self.get_inputs(xs, activations)
|
| 148 |
+
if self.mixin is not None:
|
| 149 |
+
x = x + F.interpolate(xs[self.mixin][:, :x.shape[1], ...], scale_factor=self.base // self.mixin)
|
| 150 |
+
z, x, kl = self.sample(x, acts)
|
| 151 |
+
x = x + self.z_fn(z)
|
| 152 |
+
x = self.resnet(x)
|
| 153 |
+
xs[self.base] = x
|
| 154 |
+
if get_latents:
|
| 155 |
+
return xs, dict(z=z.detach(), kl=kl)
|
| 156 |
+
return xs, dict(kl=kl)
|
| 157 |
+
|
| 158 |
+
def forward_uncond(self, xs, t=None, lvs=None):
|
| 159 |
+
try:
|
| 160 |
+
x = xs[self.base]
|
| 161 |
+
except KeyError:
|
| 162 |
+
ref = xs[list(xs.keys())[0]]
|
| 163 |
+
x = torch.zeros(dtype=ref.dtype, size=(ref.shape[0], self.widths[self.base], self.base, self.base), device=ref.device)
|
| 164 |
+
if self.mixin is not None:
|
| 165 |
+
x = x + F.interpolate(xs[self.mixin][:, :x.shape[1], ...], scale_factor=self.base // self.mixin)
|
| 166 |
+
z, x = self.sample_uncond(x, t, lvs=lvs)
|
| 167 |
+
x = x + self.z_fn(z)
|
| 168 |
+
x = self.resnet(x)
|
| 169 |
+
xs[self.base] = x
|
| 170 |
+
return xs
|
| 171 |
+
|
| 172 |
+
|
| 173 |
+
class Decoder(HModule):
|
| 174 |
+
|
| 175 |
+
def build(self):
|
| 176 |
+
H = self.H
|
| 177 |
+
resos = set()
|
| 178 |
+
dec_blocks = []
|
| 179 |
+
self.widths = get_width_settings(H.width, H.custom_width_str)
|
| 180 |
+
blocks = parse_layer_string(H.dec_blocks)
|
| 181 |
+
for idx, (res, mixin) in enumerate(blocks):
|
| 182 |
+
dec_blocks.append(DecBlock(H, res, mixin, n_blocks=len(blocks)))
|
| 183 |
+
resos.add(res)
|
| 184 |
+
self.resolutions = sorted(resos)
|
| 185 |
+
self.dec_blocks = nn.ModuleList(dec_blocks)
|
| 186 |
+
self.bias_xs = nn.ParameterList([nn.Parameter(torch.zeros(1, self.widths[res], res, res)) for res in self.resolutions if res <= H.no_bias_above])
|
| 187 |
+
self.out_net = DmolNet(H)
|
| 188 |
+
self.gain = nn.Parameter(torch.ones(1, H.width, 1, 1))
|
| 189 |
+
self.bias = nn.Parameter(torch.zeros(1, H.width, 1, 1))
|
| 190 |
+
self.final_fn = lambda x: x * self.gain + self.bias
|
| 191 |
+
|
| 192 |
+
def forward(self, activations, get_latents=False):
|
| 193 |
+
stats = []
|
| 194 |
+
xs = {a.shape[2]: a for a in self.bias_xs}
|
| 195 |
+
for block in self.dec_blocks:
|
| 196 |
+
xs, block_stats = block(xs, activations, get_latents=get_latents)
|
| 197 |
+
stats.append(block_stats)
|
| 198 |
+
xs[self.H.image_size] = self.final_fn(xs[self.H.image_size])
|
| 199 |
+
return xs[self.H.image_size], stats
|
| 200 |
+
|
| 201 |
+
def forward_uncond(self, n, t=None, y=None):
|
| 202 |
+
xs = {}
|
| 203 |
+
for bias in self.bias_xs:
|
| 204 |
+
xs[bias.shape[2]] = bias.repeat(n, 1, 1, 1)
|
| 205 |
+
for idx, block in enumerate(self.dec_blocks):
|
| 206 |
+
try:
|
| 207 |
+
temp = t[idx]
|
| 208 |
+
except TypeError:
|
| 209 |
+
temp = t
|
| 210 |
+
xs = block.forward_uncond(xs, temp)
|
| 211 |
+
xs[self.H.image_size] = self.final_fn(xs[self.H.image_size])
|
| 212 |
+
return xs[self.H.image_size]
|
| 213 |
+
|
| 214 |
+
def forward_manual_latents(self, n, latents, t=None):
|
| 215 |
+
xs = {}
|
| 216 |
+
for bias in self.bias_xs:
|
| 217 |
+
xs[bias.shape[2]] = bias.repeat(n, 1, 1, 1)
|
| 218 |
+
for block, lvs in itertools.zip_longest(self.dec_blocks, latents):
|
| 219 |
+
xs = block.forward_uncond(xs, t, lvs=lvs)
|
| 220 |
+
xs[self.H.image_size] = self.final_fn(xs[self.H.image_size])
|
| 221 |
+
return xs[self.H.image_size]
|
| 222 |
+
|
| 223 |
+
|
| 224 |
+
class VAE(HModule):
|
| 225 |
+
def build(self):
|
| 226 |
+
self.encoder = Encoder(self.H)
|
| 227 |
+
self.decoder = Decoder(self.H)
|
| 228 |
+
|
| 229 |
+
def forward(self, x, x_target):
|
| 230 |
+
activations = self.encoder.forward(x)
|
| 231 |
+
px_z, stats = self.decoder.forward(activations)
|
| 232 |
+
distortion_per_pixel = self.decoder.out_net.nll(px_z, x_target)
|
| 233 |
+
rate_per_pixel = torch.zeros_like(distortion_per_pixel)
|
| 234 |
+
ndims = np.prod(x.shape[1:])
|
| 235 |
+
for statdict in stats:
|
| 236 |
+
rate_per_pixel += statdict['kl'].sum(dim=(1, 2, 3))
|
| 237 |
+
rate_per_pixel /= ndims
|
| 238 |
+
elbo = (distortion_per_pixel + rate_per_pixel).mean()
|
| 239 |
+
return dict(elbo=elbo, distortion=distortion_per_pixel.mean(), rate=rate_per_pixel.mean())
|
| 240 |
+
|
| 241 |
+
def forward_get_latents(self, x):
|
| 242 |
+
activations = self.encoder.forward(x)
|
| 243 |
+
_, stats = self.decoder.forward(activations, get_latents=True)
|
| 244 |
+
return stats
|
| 245 |
+
|
| 246 |
+
def forward_uncond_samples(self, n_batch, t=None):
|
| 247 |
+
px_z = self.decoder.forward_uncond(n_batch, t=t)
|
| 248 |
+
return self.decoder.out_net.sample(px_z)
|
| 249 |
+
|
| 250 |
+
def forward_samples_set_latents(self, n_batch, latents, t=None):
|
| 251 |
+
px_z = self.decoder.forward_manual_latents(n_batch, latents, t=t)
|
| 252 |
+
return self.decoder.out_net.sample(px_z)
|
MindEye_Imagery/src/vdvae/LICENSE.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Copyright © 2020 OpenAI
|
| 2 |
+
|
| 3 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
| 4 |
+
|
| 5 |
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
| 6 |
+
|
| 7 |
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
MindEye_Imagery/src/vdvae/README.md
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Very Deep VAEs
|
| 2 |
+
|
| 3 |
+
Repository for the paper "Very Deep VAEs Generalize Autoregressive Models and Can Outperform Them on Images" (https://arxiv.org/abs/2011.10650)
|
| 4 |
+
|
| 5 |
+
Some model samples and a visualization of how it generates them:
|
| 6 |
+

|
| 7 |
+
|
| 8 |
+
This repository is tested with PyTorch 1.6, CUDA 10.1, Numpy 1.16, Ubuntu 18.04, and V100 GPUs.
|
| 9 |
+
|
| 10 |
+
# Setup
|
| 11 |
+
Several additional packages are required, including NVIDIA Apex:
|
| 12 |
+
```
|
| 13 |
+
pip install imageio
|
| 14 |
+
pip install mpi4py
|
| 15 |
+
pip install sklearn
|
| 16 |
+
git clone https://github.com/NVIDIA/apex
|
| 17 |
+
cd apex
|
| 18 |
+
pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" ./
|
| 19 |
+
cd ..
|
| 20 |
+
```
|
| 21 |
+
|
| 22 |
+
Also, you'll have to download the data, depending on which one you want to run:
|
| 23 |
+
```
|
| 24 |
+
./setup_cifar10.sh
|
| 25 |
+
./setup_imagenet.sh imagenet32
|
| 26 |
+
./setup_imagenet.sh imagenet64
|
| 27 |
+
./setup_ffhq256.sh
|
| 28 |
+
./setup_ffhq1024.sh /path/to/images1024x1024 # this one depends on you first downloading the subfolder `images_1024x1024` from https://github.com/NVlabs/ffhq-dataset on your own
|
| 29 |
+
```
|
| 30 |
+
|
| 31 |
+
# Training models
|
| 32 |
+
Hyperparameters all reside in `hps.py`. We use 2 gpus for our CIFAR-10 runs, and 32 for the rest of the models. (Using a lower batch size is also possible and results in slower learning, and may also require a lower learning rate).
|
| 33 |
+
|
| 34 |
+
The `mpiexec` arguments you use for runs with more than 1 node depend on the configuration of your system, so please adapt accordingly.
|
| 35 |
+
|
| 36 |
+
```bash
|
| 37 |
+
mpiexec -n 2 python train.py --hps cifar10
|
| 38 |
+
mpiexec -n 32 python train.py --hps imagenet32
|
| 39 |
+
mpiexec -n 32 python train.py --hps imagenet64
|
| 40 |
+
mpiexec -n 32 python train.py --hps ffhq256
|
| 41 |
+
mpiexec -n 32 python train.py --hps ffhq1024
|
| 42 |
+
```
|
| 43 |
+
|
| 44 |
+
# Restoring saved models
|
| 45 |
+
For convenience, we have included training checkpoints which can be restored in order to confirm performance, continue training, or generate samples.
|
| 46 |
+
|
| 47 |
+
### ImageNet 32
|
| 48 |
+
```bash
|
| 49 |
+
# 119M parameter model, trained for 1.7M iters (about 2.5 weeks on 32 V100)
|
| 50 |
+
wget https://openaipublic.blob.core.windows.net/very-deep-vaes-assets/vdvae-assets/imagenet32-iter-1700000-log.jsonl
|
| 51 |
+
wget https://openaipublic.blob.core.windows.net/very-deep-vaes-assets/vdvae-assets/imagenet32-iter-1700000-model.th
|
| 52 |
+
wget https://openaipublic.blob.core.windows.net/very-deep-vaes-assets/vdvae-assets/imagenet32-iter-1700000-model-ema.th
|
| 53 |
+
wget https://openaipublic.blob.core.windows.net/very-deep-vaes-assets/vdvae-assets/imagenet32-iter-1700000-opt.th
|
| 54 |
+
python train.py --hps imagenet32 --restore_path imagenet32-iter-1700000-model.th --restore_ema_path imagenet32-iter-1700000-model-ema.th --restore_log_path imagenet32-iter-1700000-log.jsonl --restore_optimizer_path imagenet32-iter-1700000-opt.th --test_eval
|
| 55 |
+
# should give 2.6364 nats per dim, which is 3.80 bpd
|
| 56 |
+
```
|
| 57 |
+
|
| 58 |
+
### ImageNet 64
|
| 59 |
+
```bash
|
| 60 |
+
# 125M parameter model, trained for 1.6M iters (about 2.5 weeks on 32 V100)
|
| 61 |
+
wget https://openaipublic.blob.core.windows.net/very-deep-vaes-assets/vdvae-assets-2/imagenet64-iter-1600000-log.jsonl
|
| 62 |
+
wget https://openaipublic.blob.core.windows.net/very-deep-vaes-assets/vdvae-assets-2/imagenet64-iter-1600000-model.th
|
| 63 |
+
wget https://openaipublic.blob.core.windows.net/very-deep-vaes-assets/vdvae-assets-2/imagenet64-iter-1600000-model-ema.th
|
| 64 |
+
wget https://openaipublic.blob.core.windows.net/very-deep-vaes-assets/vdvae-assets-2/imagenet64-iter-1600000-opt.th
|
| 65 |
+
python train.py --hps imagenet64 --restore_path imagenet64-iter-1600000-model.th --restore_ema_path imagenet64-iter-1600000-model-ema.th --restore_log_path imagenet64-iter-1600000-log.jsonl --restore_optimizer_path imagenet64-iter-1600000-opt.th --test_eval
|
| 66 |
+
# should be 2.44 nats, or 3.52 bits per dim
|
| 67 |
+
```
|
| 68 |
+
|
| 69 |
+
### FFHQ-256
|
| 70 |
+
```bash
|
| 71 |
+
# 115M parameters, trained for 1.7M iterations (or about 2.5 weeks) on 32 V100
|
| 72 |
+
wget https://openaipublic.blob.core.windows.net/very-deep-vaes-assets/vdvae-assets/ffhq256-iter-1700000-log.jsonl
|
| 73 |
+
wget https://openaipublic.blob.core.windows.net/very-deep-vaes-assets/vdvae-assets/ffhq256-iter-1700000-model.th
|
| 74 |
+
wget https://openaipublic.blob.core.windows.net/very-deep-vaes-assets/vdvae-assets/ffhq256-iter-1700000-model-ema.th
|
| 75 |
+
wget https://openaipublic.blob.core.windows.net/very-deep-vaes-assets/vdvae-assets/ffhq256-iter-1700000-opt.th
|
| 76 |
+
python train.py --hps ffhq256 --restore_path ffhq256-iter-1700000-model.th --restore_ema_path ffhq256-iter-1700000-model-ema.th --restore_log_path ffhq256-iter-1700000-log.jsonl --restore_optimizer_path ffhq256-iter-1700000-opt.th --test_eval
|
| 77 |
+
# should be 0.4232 nats, or 0.61 bits per dim
|
| 78 |
+
```
|
| 79 |
+
|
| 80 |
+
### FFHQ-1024
|
| 81 |
+
```bash
|
| 82 |
+
# 115M parameters, trained for 1.7M iterations (or about 2.5 weeks) on 32 V100
|
| 83 |
+
wget https://openaipublic.blob.core.windows.net/very-deep-vaes-assets/vdvae-assets/ffhq1024-iter-1700000-log.jsonl
|
| 84 |
+
wget https://openaipublic.blob.core.windows.net/very-deep-vaes-assets/vdvae-assets/ffhq1024-iter-1700000-model.th
|
| 85 |
+
wget https://openaipublic.blob.core.windows.net/very-deep-vaes-assets/vdvae-assets/ffhq1024-iter-1700000-model-ema.th
|
| 86 |
+
wget https://openaipublic.blob.core.windows.net/very-deep-vaes-assets/vdvae-assets/ffhq1024-iter-1700000-opt.th
|
| 87 |
+
python train.py --hps ffhq1024 --restore_path ffhq1024-iter-1700000-model.th --restore_ema_path ffhq1024-iter-1700000-model-ema.th --restore_log_path ffhq1024-iter-1700000-log.jsonl --restore_optimizer_path ffhq1024-iter-1700000-opt.th --test_eval
|
| 88 |
+
# should be 1.678 nats, or 2.42 bits per dim
|
| 89 |
+
```
|
| 90 |
+
|
| 91 |
+
### CIFAR-10
|
| 92 |
+
```bash
|
| 93 |
+
# 39M parameters, trained for ~1M iterations with early stopping (a little less than a week on 2 GPUs)
|
| 94 |
+
wget https://openaipublic.blob.core.windows.net/very-deep-vaes-assets/vdvae-assets-2/cifar10-seed0-iter-900000-model-ema.th
|
| 95 |
+
wget https://openaipublic.blob.core.windows.net/very-deep-vaes-assets/vdvae-assets-2/cifar10-seed1-iter-1050000-model-ema.th
|
| 96 |
+
wget https://openaipublic.blob.core.windows.net/very-deep-vaes-assets/vdvae-assets-2/cifar10-seed2-iter-650000-model-ema.th
|
| 97 |
+
wget https://openaipublic.blob.core.windows.net/very-deep-vaes-assets/vdvae-assets-2/cifar10-seed3-iter-1050000-model-ema.th
|
| 98 |
+
python train.py --hps cifar10 --restore_ema_path cifar10-seed0-iter-900000-model-ema.th --test_eval
|
| 99 |
+
python train.py --hps cifar10 --restore_ema_path cifar10-seed1-iter-1050000-model-ema.th --test_eval
|
| 100 |
+
python train.py --hps cifar10 --restore_ema_path cifar10-seed2-iter-650000-model-ema.th --test_eval
|
| 101 |
+
python train.py --hps cifar10 --restore_ema_path cifar10-seed3-iter-1050000-model-ema.th --test_eval
|
| 102 |
+
# seeds 0, 1, 2, 3 should give 2.879, 2.842, 2.898, 2.864 bits per dim, for an average of 2.87 bits per dim.
|
| 103 |
+
```
|
MindEye_Imagery/src/vdvae/__pycache__/data.cpython-311.pyc
ADDED
|
Binary file (11 kB). View file
|
|
|
MindEye_Imagery/src/vdvae/__pycache__/hps.cpython-311.pyc
ADDED
|
Binary file (9.83 kB). View file
|
|
|
MindEye_Imagery/src/vdvae/__pycache__/image_utils.cpython-311.pyc
ADDED
|
Binary file (4.66 kB). View file
|
|
|
MindEye_Imagery/src/vdvae/__pycache__/model_utils.cpython-311.pyc
ADDED
|
Binary file (4.91 kB). View file
|
|
|
MindEye_Imagery/src/vdvae/__pycache__/train_helpers.cpython-311.pyc
ADDED
|
Binary file (14.9 kB). View file
|
|
|
MindEye_Imagery/src/vdvae/__pycache__/vae.cpython-311.pyc
ADDED
|
Binary file (21.4 kB). View file
|
|
|
MindEye_Imagery/src/vdvae/__pycache__/vae_helpers.cpython-311.pyc
ADDED
|
Binary file (14.5 kB). View file
|
|
|
MindEye_Imagery/src/vdvae/__pycache__/vdvae_utils.cpython-311.pyc
ADDED
|
Binary file (8.52 kB). View file
|
|
|
MindEye_Imagery/src/vdvae/data.py
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
import pickle
|
| 3 |
+
import os
|
| 4 |
+
import torch
|
| 5 |
+
from torch.utils.data import TensorDataset
|
| 6 |
+
from torchvision.datasets import ImageFolder
|
| 7 |
+
import torchvision.transforms as transforms
|
| 8 |
+
from sklearn.model_selection import train_test_split
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
def set_up_data(H):
|
| 12 |
+
shift_loss = -127.5
|
| 13 |
+
scale_loss = 1. / 127.5
|
| 14 |
+
if H.dataset == 'imagenet32':
|
| 15 |
+
trX, vaX, teX = imagenet32(H.data_root)
|
| 16 |
+
H.image_size = 32
|
| 17 |
+
H.image_channels = 3
|
| 18 |
+
shift = -116.2373
|
| 19 |
+
scale = 1. / 69.37404
|
| 20 |
+
elif H.dataset == 'imagenet64':
|
| 21 |
+
trX, vaX, teX = imagenet64(H.data_root)
|
| 22 |
+
H.image_size = 64
|
| 23 |
+
H.image_channels = 3
|
| 24 |
+
shift = -115.92961967
|
| 25 |
+
scale = 1. / 69.37404
|
| 26 |
+
elif H.dataset == 'ffhq_256':
|
| 27 |
+
trX, vaX, teX = ffhq256(H.data_root)
|
| 28 |
+
H.image_size = 256
|
| 29 |
+
H.image_channels = 3
|
| 30 |
+
shift = -112.8666757481
|
| 31 |
+
scale = 1. / 69.84780273
|
| 32 |
+
elif H.dataset == 'ffhq_1024':
|
| 33 |
+
trX, vaX, teX = ffhq1024(H.data_root)
|
| 34 |
+
H.image_size = 1024
|
| 35 |
+
H.image_channels = 3
|
| 36 |
+
shift = -0.4387
|
| 37 |
+
scale = 1.0 / 0.2743
|
| 38 |
+
shift_loss = -0.5
|
| 39 |
+
scale_loss = 2.0
|
| 40 |
+
elif H.dataset == 'cifar10':
|
| 41 |
+
(trX, _), (vaX, _), (teX, _) = cifar10(H.data_root, one_hot=False)
|
| 42 |
+
H.image_size = 32
|
| 43 |
+
H.image_channels = 3
|
| 44 |
+
shift = -120.63838
|
| 45 |
+
scale = 1. / 64.16736
|
| 46 |
+
else:
|
| 47 |
+
raise ValueError('unknown dataset: ', H.dataset)
|
| 48 |
+
|
| 49 |
+
do_low_bit = H.dataset in ['ffhq_256']
|
| 50 |
+
|
| 51 |
+
if H.test_eval:
|
| 52 |
+
print('DOING TEST')
|
| 53 |
+
eval_dataset = teX
|
| 54 |
+
else:
|
| 55 |
+
eval_dataset = vaX
|
| 56 |
+
|
| 57 |
+
shift = torch.tensor([shift]).cuda().view(1, 1, 1, 1)
|
| 58 |
+
scale = torch.tensor([scale]).cuda().view(1, 1, 1, 1)
|
| 59 |
+
shift_loss = torch.tensor([shift_loss]).cuda().view(1, 1, 1, 1)
|
| 60 |
+
scale_loss = torch.tensor([scale_loss]).cuda().view(1, 1, 1, 1)
|
| 61 |
+
|
| 62 |
+
if H.dataset == 'ffhq_1024':
|
| 63 |
+
train_data = ImageFolder(trX, transforms.ToTensor())
|
| 64 |
+
valid_data = ImageFolder(eval_dataset, transforms.ToTensor())
|
| 65 |
+
untranspose = True
|
| 66 |
+
else:
|
| 67 |
+
train_data = TensorDataset(torch.as_tensor(trX))
|
| 68 |
+
valid_data = TensorDataset(torch.as_tensor(eval_dataset))
|
| 69 |
+
untranspose = False
|
| 70 |
+
|
| 71 |
+
def preprocess_func(x):
|
| 72 |
+
nonlocal shift
|
| 73 |
+
nonlocal scale
|
| 74 |
+
nonlocal shift_loss
|
| 75 |
+
nonlocal scale_loss
|
| 76 |
+
nonlocal do_low_bit
|
| 77 |
+
nonlocal untranspose
|
| 78 |
+
'takes in a data example and returns the preprocessed input'
|
| 79 |
+
'as well as the input processed for the loss'
|
| 80 |
+
if untranspose:
|
| 81 |
+
x[0] = x[0].permute(0, 2, 3, 1)
|
| 82 |
+
inp = x[0].cuda(non_blocking=True).float()
|
| 83 |
+
out = inp.clone()
|
| 84 |
+
inp.add_(shift).mul_(scale)
|
| 85 |
+
if do_low_bit:
|
| 86 |
+
# 5 bits of precision
|
| 87 |
+
out.mul_(1. / 8.).floor_().mul_(8.)
|
| 88 |
+
out.add_(shift_loss).mul_(scale_loss)
|
| 89 |
+
return inp, out
|
| 90 |
+
|
| 91 |
+
return H, train_data, valid_data, preprocess_func
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
def mkdir_p(path):
|
| 95 |
+
os.makedirs(path, exist_ok=True)
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
def flatten(outer):
|
| 99 |
+
return [el for inner in outer for el in inner]
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
def unpickle_cifar10(file):
|
| 103 |
+
fo = open(file, 'rb')
|
| 104 |
+
data = pickle.load(fo, encoding='bytes')
|
| 105 |
+
fo.close()
|
| 106 |
+
data = dict(zip([k.decode() for k in data.keys()], data.values()))
|
| 107 |
+
return data
|
| 108 |
+
|
| 109 |
+
|
| 110 |
+
def imagenet32(data_root):
|
| 111 |
+
trX = np.load(os.path.join(data_root, 'imagenet32-train.npy'), mmap_mode='r')
|
| 112 |
+
np.random.seed(42)
|
| 113 |
+
tr_va_split_indices = np.random.permutation(trX.shape[0])
|
| 114 |
+
train = trX[tr_va_split_indices[:-5000]]
|
| 115 |
+
valid = trX[tr_va_split_indices[-5000:]]
|
| 116 |
+
test = np.load(os.path.join(data_root, 'imagenet32-valid.npy'), mmap_mode='r')
|
| 117 |
+
return train, valid, test
|
| 118 |
+
|
| 119 |
+
|
| 120 |
+
def imagenet64(data_root):
|
| 121 |
+
trX = np.load(os.path.join(data_root, 'imagenet64-train.npy'), mmap_mode='r')
|
| 122 |
+
np.random.seed(42)
|
| 123 |
+
tr_va_split_indices = np.random.permutation(trX.shape[0])
|
| 124 |
+
train = trX[tr_va_split_indices[:-5000]]
|
| 125 |
+
valid = trX[tr_va_split_indices[-5000:]]
|
| 126 |
+
test = np.load(os.path.join(data_root, 'imagenet64-valid.npy'), mmap_mode='r') # this is test.
|
| 127 |
+
return train, valid, test
|
| 128 |
+
|
| 129 |
+
|
| 130 |
+
def ffhq1024(data_root):
|
| 131 |
+
# we did not significantly tune hyperparameters on ffhq-1024, and so simply evaluate on the test set
|
| 132 |
+
return os.path.join(data_root, 'ffhq1024/train'), os.path.join(data_root, 'ffhq1024/valid'), os.path.join(data_root, 'ffhq1024/valid')
|
| 133 |
+
|
| 134 |
+
|
| 135 |
+
def ffhq256(data_root):
|
| 136 |
+
trX = np.load(os.path.join(data_root, 'ffhq-256.npy'), mmap_mode='r')
|
| 137 |
+
np.random.seed(5)
|
| 138 |
+
tr_va_split_indices = np.random.permutation(trX.shape[0])
|
| 139 |
+
train = trX[tr_va_split_indices[:-7000]]
|
| 140 |
+
valid = trX[tr_va_split_indices[-7000:]]
|
| 141 |
+
# we did not significantly tune hyperparameters on ffhq-256, and so simply evaluate on the test set
|
| 142 |
+
return train, valid, valid
|
| 143 |
+
|
| 144 |
+
|
| 145 |
+
def cifar10(data_root, one_hot=True):
|
| 146 |
+
tr_data = [unpickle_cifar10(os.path.join(data_root, 'cifar-10-batches-py/', 'data_batch_%d' % i)) for i in range(1, 6)]
|
| 147 |
+
trX = np.vstack(data['data'] for data in tr_data)
|
| 148 |
+
trY = np.asarray(flatten([data['labels'] for data in tr_data]))
|
| 149 |
+
te_data = unpickle_cifar10(os.path.join(data_root, 'cifar-10-batches-py/', 'test_batch'))
|
| 150 |
+
teX = np.asarray(te_data['data'])
|
| 151 |
+
teY = np.asarray(te_data['labels'])
|
| 152 |
+
trX = trX.reshape(-1, 3, 32, 32).transpose(0, 2, 3, 1)
|
| 153 |
+
teX = teX.reshape(-1, 3, 32, 32).transpose(0, 2, 3, 1)
|
| 154 |
+
trX, vaX, trY, vaY = train_test_split(trX, trY, test_size=5000, random_state=11172018)
|
| 155 |
+
if one_hot:
|
| 156 |
+
trY = np.eye(10, dtype=np.float32)[trY]
|
| 157 |
+
vaY = np.eye(10, dtype=np.float32)[vaY]
|
| 158 |
+
teY = np.eye(10, dtype=np.float32)[teY]
|
| 159 |
+
else:
|
| 160 |
+
trY = np.reshape(trY, [-1, 1])
|
| 161 |
+
vaY = np.reshape(vaY, [-1, 1])
|
| 162 |
+
teY = np.reshape(teY, [-1, 1])
|
| 163 |
+
return (trX, trY), (vaX, vaY), (teX, teY)
|
MindEye_Imagery/src/vdvae/files_to_npy.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import sys
|
| 2 |
+
import numpy as np
|
| 3 |
+
import imageio
|
| 4 |
+
import glob
|
| 5 |
+
import os
|
| 6 |
+
|
| 7 |
+
if __name__ == "__main__":
|
| 8 |
+
print("moving images in", sys.argv[1], "to", sys.argv[2])
|
| 9 |
+
files = glob.glob(os.path.join(sys.argv[1], "*.png"))
|
| 10 |
+
shape = imageio.imread(files[0]).shape
|
| 11 |
+
data = np.zeros(shape=(len(files), *shape), dtype=np.uint8)
|
| 12 |
+
for idx, f in enumerate(files):
|
| 13 |
+
data[idx] = imageio.imread(f)
|
| 14 |
+
np.save(sys.argv[2], data)
|
MindEye_Imagery/src/vdvae/hps.py
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
HPARAMS_REGISTRY = {}
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
class Hyperparams(dict):
|
| 5 |
+
def __getattr__(self, attr):
|
| 6 |
+
try:
|
| 7 |
+
return self[attr]
|
| 8 |
+
except KeyError:
|
| 9 |
+
return None
|
| 10 |
+
|
| 11 |
+
def __setattr__(self, attr, value):
|
| 12 |
+
self[attr] = value
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
cifar10 = Hyperparams()
|
| 16 |
+
cifar10.width = 384
|
| 17 |
+
cifar10.lr = 0.0002
|
| 18 |
+
cifar10.zdim = 16
|
| 19 |
+
cifar10.wd = 0.01
|
| 20 |
+
cifar10.dec_blocks = "1x1,4m1,4x2,8m4,8x5,16m8,16x10,32m16,32x21"
|
| 21 |
+
cifar10.enc_blocks = "32x11,32d2,16x6,16d2,8x6,8d2,4x3,4d4,1x3"
|
| 22 |
+
cifar10.warmup_iters = 100
|
| 23 |
+
cifar10.dataset = 'cifar10'
|
| 24 |
+
cifar10.n_batch = 16
|
| 25 |
+
cifar10.ema_rate = 0.9999
|
| 26 |
+
HPARAMS_REGISTRY['cifar10'] = cifar10
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
i32 = Hyperparams()
|
| 30 |
+
i32.update(cifar10)
|
| 31 |
+
i32.dataset = 'imagenet32'
|
| 32 |
+
i32.ema_rate = 0.999
|
| 33 |
+
i32.dec_blocks = "1x2,4m1,4x4,8m4,8x9,16m8,16x19,32m16,32x40"
|
| 34 |
+
i32.enc_blocks = "32x15,32d2,16x9,16d2,8x8,8d2,4x6,4d4,1x6"
|
| 35 |
+
i32.width = 512
|
| 36 |
+
i32.n_batch = 8
|
| 37 |
+
i32.lr = 0.00015
|
| 38 |
+
i32.grad_clip = 200.
|
| 39 |
+
i32.skip_threshold = 300.
|
| 40 |
+
i32.epochs_per_eval = 1
|
| 41 |
+
i32.epochs_per_eval_save = 1
|
| 42 |
+
HPARAMS_REGISTRY['imagenet32'] = i32
|
| 43 |
+
|
| 44 |
+
i64 = Hyperparams()
|
| 45 |
+
i64.update(i32)
|
| 46 |
+
i64.n_batch = 4
|
| 47 |
+
i64.grad_clip = 220.0
|
| 48 |
+
i64.skip_threshold = 380.0
|
| 49 |
+
i64.dataset = 'imagenet64'
|
| 50 |
+
i64.dec_blocks = "1x2,4m1,4x3,8m4,8x7,16m8,16x15,32m16,32x31,64m32,64x12"
|
| 51 |
+
i64.enc_blocks = "64x11,64d2,32x20,32d2,16x9,16d2,8x8,8d2,4x7,4d4,1x5"
|
| 52 |
+
HPARAMS_REGISTRY['imagenet64'] = i64
|
| 53 |
+
|
| 54 |
+
ffhq_256 = Hyperparams()
|
| 55 |
+
ffhq_256.update(i64)
|
| 56 |
+
ffhq_256.n_batch = 1
|
| 57 |
+
ffhq_256.lr = 0.00015
|
| 58 |
+
ffhq_256.dataset = 'ffhq_256'
|
| 59 |
+
ffhq_256.epochs_per_eval = 1
|
| 60 |
+
ffhq_256.epochs_per_eval_save = 1
|
| 61 |
+
ffhq_256.num_images_visualize = 2
|
| 62 |
+
ffhq_256.num_variables_visualize = 3
|
| 63 |
+
ffhq_256.num_temperatures_visualize = 1
|
| 64 |
+
ffhq_256.dec_blocks = "1x2,4m1,4x3,8m4,8x4,16m8,16x9,32m16,32x21,64m32,64x13,128m64,128x7,256m128"
|
| 65 |
+
ffhq_256.enc_blocks = "256x3,256d2,128x8,128d2,64x12,64d2,32x17,32d2,16x7,16d2,8x5,8d2,4x5,4d4,1x4"
|
| 66 |
+
ffhq_256.no_bias_above = 64
|
| 67 |
+
ffhq_256.grad_clip = 130.
|
| 68 |
+
ffhq_256.skip_threshold = 180.
|
| 69 |
+
HPARAMS_REGISTRY['ffhq256'] = ffhq_256
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
ffhq1024 = Hyperparams()
|
| 73 |
+
ffhq1024.update(ffhq_256)
|
| 74 |
+
ffhq1024.dataset = 'ffhq_1024'
|
| 75 |
+
ffhq1024.data_root = './ffhq_images1024x1024'
|
| 76 |
+
ffhq1024.epochs_per_eval = 1
|
| 77 |
+
ffhq1024.epochs_per_eval_save = 1
|
| 78 |
+
ffhq1024.num_images_visualize = 1
|
| 79 |
+
ffhq1024.iters_per_images = 25000
|
| 80 |
+
ffhq1024.num_variables_visualize = 0
|
| 81 |
+
ffhq1024.num_temperatures_visualize = 4
|
| 82 |
+
ffhq1024.grad_clip = 360.
|
| 83 |
+
ffhq1024.skip_threshold = 500.
|
| 84 |
+
ffhq1024.num_mixtures = 2
|
| 85 |
+
ffhq1024.width = 16
|
| 86 |
+
ffhq1024.lr = 0.00007
|
| 87 |
+
ffhq1024.dec_blocks = "1x2,4m1,4x3,8m4,8x4,16m8,16x9,32m16,32x20,64m32,64x14,128m64,128x7,256m128,256x2,512m256,1024m512"
|
| 88 |
+
ffhq1024.enc_blocks = "1024x1,1024d2,512x3,512d2,256x5,256d2,128x7,128d2,64x10,64d2,32x14,32d2,16x7,16d2,8x5,8d2,4x5,4d4,1x4"
|
| 89 |
+
ffhq1024.custom_width_str = "512:32,256:64,128:512,64:512,32:512,16:512,8:512,4:512,1:512"
|
| 90 |
+
HPARAMS_REGISTRY['ffhq1024'] = ffhq1024
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
def parse_args_and_update_hparams(H, parser, s=None):
|
| 94 |
+
args = parser.parse_args(s)
|
| 95 |
+
valid_args = set(args.__dict__.keys())
|
| 96 |
+
hparam_sets = [x for x in args.hparam_sets.split(',') if x]
|
| 97 |
+
for hp_set in hparam_sets:
|
| 98 |
+
hps = HPARAMS_REGISTRY[hp_set]
|
| 99 |
+
for k in hps:
|
| 100 |
+
if k not in valid_args:
|
| 101 |
+
raise ValueError(f"{k} not in default args")
|
| 102 |
+
parser.set_defaults(**hps)
|
| 103 |
+
H.update(parser.parse_args(s).__dict__)
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
def add_vae_arguments(parser):
|
| 107 |
+
parser.add_argument('--seed', type=int, default=0)
|
| 108 |
+
parser.add_argument('--port', type=int, default=29500)
|
| 109 |
+
parser.add_argument('--save_dir', type=str, default='./saved_models')
|
| 110 |
+
parser.add_argument('--data_root', type=str, default='./')
|
| 111 |
+
|
| 112 |
+
parser.add_argument('--desc', type=str, default='test')
|
| 113 |
+
parser.add_argument('--hparam_sets', '--hps', type=str)
|
| 114 |
+
parser.add_argument('--restore_path', type=str, default=None)
|
| 115 |
+
parser.add_argument('--restore_ema_path', type=str, default=None)
|
| 116 |
+
parser.add_argument('--restore_log_path', type=str, default=None)
|
| 117 |
+
parser.add_argument('--restore_optimizer_path', type=str, default=None)
|
| 118 |
+
parser.add_argument('--dataset', type=str, default='cifar10')
|
| 119 |
+
|
| 120 |
+
parser.add_argument('--ema_rate', type=float, default=0.999)
|
| 121 |
+
|
| 122 |
+
parser.add_argument('--enc_blocks', type=str, default=None)
|
| 123 |
+
parser.add_argument('--dec_blocks', type=str, default=None)
|
| 124 |
+
parser.add_argument('--zdim', type=int, default=16)
|
| 125 |
+
parser.add_argument('--width', type=int, default=512)
|
| 126 |
+
parser.add_argument('--custom_width_str', type=str, default='')
|
| 127 |
+
parser.add_argument('--bottleneck_multiple', type=float, default=0.25)
|
| 128 |
+
|
| 129 |
+
parser.add_argument('--no_bias_above', type=int, default=64)
|
| 130 |
+
parser.add_argument('--scale_encblock', action="store_true")
|
| 131 |
+
|
| 132 |
+
parser.add_argument('--test_eval', action="store_true")
|
| 133 |
+
parser.add_argument('--warmup_iters', type=float, default=0)
|
| 134 |
+
|
| 135 |
+
parser.add_argument('--num_mixtures', type=int, default=10)
|
| 136 |
+
parser.add_argument('--grad_clip', type=float, default=200.0)
|
| 137 |
+
parser.add_argument('--skip_threshold', type=float, default=400.0)
|
| 138 |
+
parser.add_argument('--lr', type=float, default=0.00015)
|
| 139 |
+
parser.add_argument('--lr_prior', type=float, default=0.00015)
|
| 140 |
+
parser.add_argument('--wd', type=float, default=0.0)
|
| 141 |
+
parser.add_argument('--wd_prior', type=float, default=0.0)
|
| 142 |
+
parser.add_argument('--num_epochs', type=int, default=10000)
|
| 143 |
+
parser.add_argument('--n_batch', type=int, default=32)
|
| 144 |
+
parser.add_argument('--adam_beta1', type=float, default=0.9)
|
| 145 |
+
parser.add_argument('--adam_beta2', type=float, default=0.9)
|
| 146 |
+
|
| 147 |
+
parser.add_argument('--temperature', type=float, default=1.0)
|
| 148 |
+
|
| 149 |
+
parser.add_argument('--iters_per_ckpt', type=int, default=25000)
|
| 150 |
+
parser.add_argument('--iters_per_print', type=int, default=1000)
|
| 151 |
+
parser.add_argument('--iters_per_save', type=int, default=10000)
|
| 152 |
+
parser.add_argument('--iters_per_images', type=int, default=10000)
|
| 153 |
+
parser.add_argument('--epochs_per_eval', type=int, default=10)
|
| 154 |
+
parser.add_argument('--epochs_per_probe', type=int, default=None)
|
| 155 |
+
parser.add_argument('--epochs_per_eval_save', type=int, default=20)
|
| 156 |
+
parser.add_argument('--num_images_visualize', type=int, default=8)
|
| 157 |
+
parser.add_argument('--num_variables_visualize', type=int, default=6)
|
| 158 |
+
parser.add_argument('--num_temperatures_visualize', type=int, default=3)
|
| 159 |
+
return parser
|
MindEye_Imagery/src/vdvae/image_utils.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import io
|
| 2 |
+
import IPython.display
|
| 3 |
+
import PIL.Image
|
| 4 |
+
import os
|
| 5 |
+
from pprint import pformat
|
| 6 |
+
import numpy as np
|
| 7 |
+
|
| 8 |
+
def imgrid(imarray, cols=4, pad=1, padval=255, row_major=True):
|
| 9 |
+
"""Lays out a [N, H, W, C] image array as a single image grid."""
|
| 10 |
+
pad = int(pad)
|
| 11 |
+
if pad < 0:
|
| 12 |
+
raise ValueError('pad must be non-negative')
|
| 13 |
+
cols = int(cols)
|
| 14 |
+
assert cols >= 1
|
| 15 |
+
N, H, W, C = imarray.shape
|
| 16 |
+
rows = N // cols + int(N % cols != 0)
|
| 17 |
+
batch_pad = rows * cols - N
|
| 18 |
+
assert batch_pad >= 0
|
| 19 |
+
post_pad = [batch_pad, pad, pad, 0]
|
| 20 |
+
pad_arg = [[0, p] for p in post_pad]
|
| 21 |
+
imarray = np.pad(imarray, pad_arg, 'constant', constant_values=padval)
|
| 22 |
+
H += pad
|
| 23 |
+
W += pad
|
| 24 |
+
grid = (imarray
|
| 25 |
+
.reshape(rows, cols, H, W, C)
|
| 26 |
+
.transpose(0, 2, 1, 3, 4)
|
| 27 |
+
.reshape(rows*H, cols*W, C))
|
| 28 |
+
if pad:
|
| 29 |
+
grid = grid[:-pad, :-pad]
|
| 30 |
+
return grid
|
| 31 |
+
|
| 32 |
+
def interleave(*args):
|
| 33 |
+
"""Interleaves input arrays of the same shape along the batch axis."""
|
| 34 |
+
if not args:
|
| 35 |
+
raise ValueError('At least one argument is required.')
|
| 36 |
+
a0 = args[0]
|
| 37 |
+
if any(a.shape != a0.shape for a in args):
|
| 38 |
+
raise ValueError('All inputs must have the same shape.')
|
| 39 |
+
if not a0.shape:
|
| 40 |
+
raise ValueError('Inputs must have at least one axis.')
|
| 41 |
+
out = np.transpose(args, [1, 0] + list(range(2, len(a0.shape) + 1)))
|
| 42 |
+
out = out.reshape(-1, *a0.shape[1:])
|
| 43 |
+
return out
|
| 44 |
+
|
| 45 |
+
def imshow(a, format='png', jpeg_fallback=True):
|
| 46 |
+
"""Displays an image in the given format."""
|
| 47 |
+
a = a.astype(np.uint8)
|
| 48 |
+
data = io.BytesIO()
|
| 49 |
+
PIL.Image.fromarray(a).save(data, format)
|
| 50 |
+
im_data = data.getvalue()
|
| 51 |
+
try:
|
| 52 |
+
disp = IPython.display.display(IPython.display.Image(im_data))
|
| 53 |
+
except IOError:
|
| 54 |
+
if jpeg_fallback and format != 'jpeg':
|
| 55 |
+
print ('Warning: image was too large to display in format "{}"; '
|
| 56 |
+
'trying jpeg instead.').format(format)
|
| 57 |
+
return imshow(a, format='jpeg')
|
| 58 |
+
else:
|
| 59 |
+
raise
|
| 60 |
+
return disp
|
| 61 |
+
|
| 62 |
+
def image_to_uint8(x):
|
| 63 |
+
"""Converts [-1, 1] float array to [0, 255] uint8."""
|
| 64 |
+
x = np.asarray(x)
|
| 65 |
+
x = (256. / 2.) * (x + 1.)
|
| 66 |
+
x = np.clip(x, 0, 255)
|
| 67 |
+
x = x.astype(np.uint8)
|
| 68 |
+
return x
|
MindEye_Imagery/src/vdvae/model_utils.py
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
import numpy as np
|
| 3 |
+
#from mpi4py import MPI
|
| 4 |
+
import socket
|
| 5 |
+
import argparse
|
| 6 |
+
import os
|
| 7 |
+
import json
|
| 8 |
+
import subprocess
|
| 9 |
+
from hps import Hyperparams, parse_args_and_update_hparams, add_vae_arguments
|
| 10 |
+
from vdvae_utils import (logger,
|
| 11 |
+
local_mpi_rank,
|
| 12 |
+
mpi_size,
|
| 13 |
+
maybe_download,
|
| 14 |
+
mpi_rank)
|
| 15 |
+
from data import mkdir_p
|
| 16 |
+
from contextlib import contextmanager
|
| 17 |
+
import torch.distributed as dist
|
| 18 |
+
#from apex.optimizers import FusedAdam as AdamW
|
| 19 |
+
from vae import VAE
|
| 20 |
+
from torch.nn.parallel.distributed import DistributedDataParallel
|
| 21 |
+
from train_helpers import restore_params
|
| 22 |
+
|
| 23 |
+
def set_up_hyperparams(s=None):
|
| 24 |
+
H = Hyperparams()
|
| 25 |
+
parser = argparse.ArgumentParser()
|
| 26 |
+
parser = add_vae_arguments(parser)
|
| 27 |
+
parse_args_and_update_hparams(H, parser, s=s)
|
| 28 |
+
setup_mpi(H)
|
| 29 |
+
setup_save_dirs(H)
|
| 30 |
+
logprint = logger(H.logdir)
|
| 31 |
+
for i, k in enumerate(sorted(H)):
|
| 32 |
+
logprint(type='hparam', key=k, value=H[k])
|
| 33 |
+
np.random.seed(H.seed)
|
| 34 |
+
torch.manual_seed(H.seed)
|
| 35 |
+
torch.cuda.manual_seed(H.seed)
|
| 36 |
+
logprint('training model', H.desc, 'on', H.dataset)
|
| 37 |
+
return H, logprint
|
| 38 |
+
|
| 39 |
+
def set_up_data(H, device="cuda"):
|
| 40 |
+
shift_loss = -127.5
|
| 41 |
+
scale_loss = 1. / 127.5
|
| 42 |
+
|
| 43 |
+
#trX, vaX, teX = imagenet64(H.data_root)
|
| 44 |
+
H.image_size = 64
|
| 45 |
+
H.image_channels = 3
|
| 46 |
+
shift = -115.92961967
|
| 47 |
+
scale = 1. / 69.37404
|
| 48 |
+
|
| 49 |
+
#if H.test_eval:
|
| 50 |
+
# print('DOING TEST')
|
| 51 |
+
# eval_dataset = teX
|
| 52 |
+
#else:
|
| 53 |
+
# eval_dataset = vaX
|
| 54 |
+
|
| 55 |
+
shift = torch.tensor([shift]).to(device).view(1, 1, 1, 1)
|
| 56 |
+
scale = torch.tensor([scale]).to(device).view(1, 1, 1, 1)
|
| 57 |
+
shift_loss = torch.tensor([shift_loss]).to(device).view(1, 1, 1, 1)
|
| 58 |
+
scale_loss = torch.tensor([scale_loss]).to(device).view(1, 1, 1, 1)
|
| 59 |
+
|
| 60 |
+
#train_data = TensorDataset(torch.as_tensor(trX))
|
| 61 |
+
#valid_data = TensorDataset(torch.as_tensor(eval_dataset))
|
| 62 |
+
#untranspose = False
|
| 63 |
+
|
| 64 |
+
def preprocess_func(x):
|
| 65 |
+
nonlocal shift
|
| 66 |
+
nonlocal scale
|
| 67 |
+
nonlocal shift_loss
|
| 68 |
+
nonlocal scale_loss
|
| 69 |
+
'takes in a data example and returns the preprocessed input'
|
| 70 |
+
'as well as the input processed for the loss'
|
| 71 |
+
#untranspose = False
|
| 72 |
+
#if untranspose:
|
| 73 |
+
# x[0] = x[0].permute(0, 2, 3, 1)
|
| 74 |
+
inp = x.to(device, non_blocking=True).float()
|
| 75 |
+
out = inp.clone()
|
| 76 |
+
inp.add_(shift).mul_(scale)
|
| 77 |
+
out.add_(shift_loss).mul_(scale_loss)
|
| 78 |
+
return inp, out
|
| 79 |
+
|
| 80 |
+
return H, preprocess_func
|
| 81 |
+
|
| 82 |
+
def load_vaes(H, logprint=None, device="cuda"):
|
| 83 |
+
|
| 84 |
+
ema_vae = VAE(H)
|
| 85 |
+
if H.restore_ema_path:
|
| 86 |
+
print(f'Restoring ema vae from {H.restore_ema_path}')
|
| 87 |
+
restore_params(ema_vae, H.restore_ema_path, map_cpu=True, local_rank=H.local_rank, mpi_size=H.mpi_size)
|
| 88 |
+
else:
|
| 89 |
+
ema_vae.load_state_dict(vae.state_dict())
|
| 90 |
+
ema_vae.requires_grad_(False)
|
| 91 |
+
ema_vae = ema_vae.to(device)
|
| 92 |
+
|
| 93 |
+
#vae = DistributedDataParallel(vae, device_ids=[H.local_rank], output_device=H.local_rank)
|
| 94 |
+
|
| 95 |
+
#if len(list(vae.named_parameters())) != len(list(vae.parameters())):
|
| 96 |
+
# raise ValueError('Some params are not named. Please name all params.')
|
| 97 |
+
#total_params = 0
|
| 98 |
+
#for name, p in vae.named_parameters():
|
| 99 |
+
# total_params += np.prod(p.shape)
|
| 100 |
+
|
| 101 |
+
#print(total_params=total_params, readable=f'{total_params:,}')
|
| 102 |
+
return ema_vae
|
MindEye_Imagery/src/vdvae/setup_cifar10.sh
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
wget https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
|
| 2 |
+
tar -xf cifar-10-python.tar.gz
|
MindEye_Imagery/src/vdvae/setup_ffhq1024.sh
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# the first argument to this script should be the path to the ffhq_images1024x1024 folder
|
| 2 |
+
# the same path should be provided as the `data_root` argument to train.py
|
| 3 |
+
cd $1
|
| 4 |
+
mkdir train
|
| 5 |
+
mkdir train/0
|
| 6 |
+
mkdir valid
|
| 7 |
+
mkdir valid/0
|
| 8 |
+
for i in $(seq -f "%05g" 0 64999); do
|
| 9 |
+
mv $i.png train/0
|
| 10 |
+
done
|
| 11 |
+
for i in $(seq -f "%05g" 65000 69999); do
|
| 12 |
+
mv $i.png valid/0
|
| 13 |
+
done
|
MindEye_Imagery/src/vdvae/setup_ffhq256.sh
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# we provide a copy of ffhq-256 for convenience, downsampled using the same function as NVAE (https://github.com/NVlabs/NVAE) (personal communication with author)
|
| 2 |
+
|
| 3 |
+
# Resizing function is this one, with the default second argument and size=256
|
| 4 |
+
# https://pytorch.org/docs/stable/torchvision/transforms.html#torchvision.transforms.Resize
|
| 5 |
+
|
| 6 |
+
# 5-bit precision is calculated using the following lines, with num_bits=5 and for an x in [0, 1]
|
| 7 |
+
# x = torch.floor(x * 255 / 2 ** (8 - num_bits))
|
| 8 |
+
# x /= (2 ** num_bits - 1)
|
| 9 |
+
|
| 10 |
+
# the DMOL loss should also be adjusted to have 32 buckets instead of 256 (this code, or NVAE, can be used as reference)
|
| 11 |
+
|
| 12 |
+
wget https://openaipublic.blob.core.windows.net/very-deep-vaes-assets/vdvae-assets/ffhq-256.npy
|
MindEye_Imagery/src/vdvae/setup_imagenet.sh
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
if [ "$1" == "imagenet32" ]; then
|
| 2 |
+
|
| 3 |
+
echo "downloading imagenet32"
|
| 4 |
+
wget http://www.image-net.org/small/train_32x32.tar
|
| 5 |
+
wget http://www.image-net.org/small/valid_32x32.tar
|
| 6 |
+
tar -xvf train_32x32.tar
|
| 7 |
+
tar -xvf valid_32x32.tar
|
| 8 |
+
python files_to_npy.py train_32x32/ imagenet32-train.npy
|
| 9 |
+
python files_to_npy.py valid_32x32/ imagenet32-valid.npy
|
| 10 |
+
|
| 11 |
+
elif [ "$1" == "imagenet64" ]; then
|
| 12 |
+
|
| 13 |
+
echo "downloading imagenet64"
|
| 14 |
+
wget http://www.image-net.org/small/train_64x64.tar
|
| 15 |
+
wget http://www.image-net.org/small/valid_64x64.tar
|
| 16 |
+
tar -xvf train_64x64.tar
|
| 17 |
+
tar -xvf valid_64x64.tar
|
| 18 |
+
python files_to_npy.py train_64x64/ imagenet64-train.npy
|
| 19 |
+
python files_to_npy.py valid_64x64/ imagenet64-valid.npy
|
| 20 |
+
|
| 21 |
+
else
|
| 22 |
+
|
| 23 |
+
echo "please pass the string imagenet32 or imagenet64 as an argument"
|
| 24 |
+
|
| 25 |
+
fi
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
|
MindEye_Imagery/src/vdvae/train.py
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
import imageio
|
| 3 |
+
import os
|
| 4 |
+
import time
|
| 5 |
+
import torch
|
| 6 |
+
from torch.utils.data import DataLoader
|
| 7 |
+
from torch.utils.data.distributed import DistributedSampler
|
| 8 |
+
from data import set_up_data
|
| 9 |
+
from vdvae_utils import get_cpu_stats_over_ranks
|
| 10 |
+
from train_helpers import set_up_hyperparams, load_vaes, load_opt, accumulate_stats, save_model, update_ema
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
def training_step(H, data_input, target, vae, ema_vae, optimizer, iterate):
|
| 14 |
+
t0 = time.time()
|
| 15 |
+
vae.zero_grad()
|
| 16 |
+
stats = vae.forward(data_input, target)
|
| 17 |
+
stats['elbo'].backward()
|
| 18 |
+
grad_norm = torch.nn.utils.clip_grad_norm_(vae.parameters(), H.grad_clip).item()
|
| 19 |
+
distortion_nans = torch.isnan(stats['distortion']).sum()
|
| 20 |
+
rate_nans = torch.isnan(stats['rate']).sum()
|
| 21 |
+
stats.update(dict(rate_nans=0 if rate_nans == 0 else 1, distortion_nans=0 if distortion_nans == 0 else 1))
|
| 22 |
+
stats = get_cpu_stats_over_ranks(stats)
|
| 23 |
+
|
| 24 |
+
skipped_updates = 1
|
| 25 |
+
# only update if no rank has a nan and if the grad norm is below a specific threshold
|
| 26 |
+
if stats['distortion_nans'] == 0 and stats['rate_nans'] == 0 and (H.skip_threshold == -1 or grad_norm < H.skip_threshold):
|
| 27 |
+
optimizer.step()
|
| 28 |
+
skipped_updates = 0
|
| 29 |
+
update_ema(vae, ema_vae, H.ema_rate)
|
| 30 |
+
|
| 31 |
+
t1 = time.time()
|
| 32 |
+
stats.update(skipped_updates=skipped_updates, iter_time=t1 - t0, grad_norm=grad_norm)
|
| 33 |
+
return stats
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def eval_step(data_input, target, ema_vae):
|
| 37 |
+
with torch.no_grad():
|
| 38 |
+
stats = ema_vae.forward(data_input, target)
|
| 39 |
+
stats = get_cpu_stats_over_ranks(stats)
|
| 40 |
+
return stats
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
def get_sample_for_visualization(data, preprocess_fn, num, dataset):
|
| 44 |
+
for x in DataLoader(data, batch_size=num):
|
| 45 |
+
break
|
| 46 |
+
orig_image = (x[0] * 255.0).to(torch.uint8).permute(0, 2, 3, 1) if dataset == 'ffhq_1024' else x[0]
|
| 47 |
+
preprocessed = preprocess_fn(x)[0]
|
| 48 |
+
return orig_image, preprocessed
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
def train_loop(H, data_train, data_valid, preprocess_fn, vae, ema_vae, logprint):
|
| 52 |
+
optimizer, scheduler, cur_eval_loss, iterate, starting_epoch = load_opt(H, vae, logprint)
|
| 53 |
+
train_sampler = DistributedSampler(data_train, num_replicas=H.mpi_size, rank=H.rank)
|
| 54 |
+
viz_batch_original, viz_batch_processed = get_sample_for_visualization(data_valid, preprocess_fn, H.num_images_visualize, H.dataset)
|
| 55 |
+
early_evals = set([1] + [2 ** exp for exp in range(3, 14)])
|
| 56 |
+
stats = []
|
| 57 |
+
iters_since_starting = 0
|
| 58 |
+
H.ema_rate = torch.as_tensor(H.ema_rate).cuda()
|
| 59 |
+
for epoch in range(starting_epoch, H.num_epochs):
|
| 60 |
+
train_sampler.set_epoch(epoch)
|
| 61 |
+
for x in DataLoader(data_train, batch_size=H.n_batch, drop_last=True, pin_memory=True, sampler=train_sampler):
|
| 62 |
+
data_input, target = preprocess_fn(x)
|
| 63 |
+
training_stats = training_step(H, data_input, target, vae, ema_vae, optimizer, iterate)
|
| 64 |
+
stats.append(training_stats)
|
| 65 |
+
scheduler.step()
|
| 66 |
+
if iterate % H.iters_per_print == 0 or iters_since_starting in early_evals:
|
| 67 |
+
logprint(model=H.desc, type='train_loss', lr=scheduler.get_last_lr()[0], epoch=epoch, step=iterate, **accumulate_stats(stats, H.iters_per_print))
|
| 68 |
+
|
| 69 |
+
if iterate % H.iters_per_images == 0 or (iters_since_starting in early_evals and H.dataset != 'ffhq_1024') and H.rank == 0:
|
| 70 |
+
write_images(H, ema_vae, viz_batch_original, viz_batch_processed, f'{H.save_dir}/samples-{iterate}.png', logprint)
|
| 71 |
+
|
| 72 |
+
iterate += 1
|
| 73 |
+
iters_since_starting += 1
|
| 74 |
+
if iterate % H.iters_per_save == 0 and H.rank == 0:
|
| 75 |
+
if np.isfinite(stats[-1]['elbo']):
|
| 76 |
+
logprint(model=H.desc, type='train_loss', epoch=epoch, step=iterate, **accumulate_stats(stats, H.iters_per_print))
|
| 77 |
+
fp = os.path.join(H.save_dir, 'latest')
|
| 78 |
+
logprint(f'Saving model@ {iterate} to {fp}')
|
| 79 |
+
save_model(fp, vae, ema_vae, optimizer, H)
|
| 80 |
+
|
| 81 |
+
if iterate % H.iters_per_ckpt == 0 and H.rank == 0:
|
| 82 |
+
save_model(os.path.join(H.save_dir, f'iter-{iterate}'), vae, ema_vae, optimizer, H)
|
| 83 |
+
|
| 84 |
+
if epoch % H.epochs_per_eval == 0:
|
| 85 |
+
valid_stats = evaluate(H, ema_vae, data_valid, preprocess_fn)
|
| 86 |
+
logprint(model=H.desc, type='eval_loss', epoch=epoch, step=iterate, **valid_stats)
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
def evaluate(H, ema_vae, data_valid, preprocess_fn):
|
| 90 |
+
stats_valid = []
|
| 91 |
+
valid_sampler = DistributedSampler(data_valid, num_replicas=H.mpi_size, rank=H.rank)
|
| 92 |
+
for x in DataLoader(data_valid, batch_size=H.n_batch, drop_last=True, pin_memory=True, sampler=valid_sampler):
|
| 93 |
+
data_input, target = preprocess_fn(x)
|
| 94 |
+
stats_valid.append(eval_step(data_input, target, ema_vae))
|
| 95 |
+
vals = [a['elbo'] for a in stats_valid]
|
| 96 |
+
finites = np.array(vals)[np.isfinite(vals)]
|
| 97 |
+
stats = dict(n_batches=len(vals), filtered_elbo=np.mean(finites), **{k: np.mean([a[k] for a in stats_valid]) for k in stats_valid[-1]})
|
| 98 |
+
return stats
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
def write_images(H, ema_vae, viz_batch_original, viz_batch_processed, fname, logprint):
|
| 102 |
+
zs = [s['z'].cuda() for s in ema_vae.forward_get_latents(viz_batch_processed)]
|
| 103 |
+
batches = [viz_batch_original.numpy()]
|
| 104 |
+
mb = viz_batch_processed.shape[0]
|
| 105 |
+
lv_points = np.floor(np.linspace(0, 1, H.num_variables_visualize + 2) * len(zs)).astype(int)[1:-1]
|
| 106 |
+
for i in lv_points:
|
| 107 |
+
batches.append(ema_vae.forward_samples_set_latents(mb, zs[:i], t=0.1))
|
| 108 |
+
for t in [1.0, 0.9, 0.8, 0.7][:H.num_temperatures_visualize]:
|
| 109 |
+
batches.append(ema_vae.forward_uncond_samples(mb, t=t))
|
| 110 |
+
n_rows = len(batches)
|
| 111 |
+
im = np.concatenate(batches, axis=0).reshape((n_rows, mb, *viz_batch_processed.shape[1:])).transpose([0, 2, 1, 3, 4]).reshape([n_rows * viz_batch_processed.shape[1], mb * viz_batch_processed.shape[2], 3])
|
| 112 |
+
logprint(f'printing samples to {fname}')
|
| 113 |
+
imageio.imwrite(fname, im)
|
| 114 |
+
|
| 115 |
+
|
| 116 |
+
def run_test_eval(H, ema_vae, data_test, preprocess_fn, logprint):
|
| 117 |
+
print('evaluating')
|
| 118 |
+
stats = evaluate(H, ema_vae, data_test, preprocess_fn)
|
| 119 |
+
print('test results')
|
| 120 |
+
for k in stats:
|
| 121 |
+
print(k, stats[k])
|
| 122 |
+
logprint(type='test_loss', **stats)
|
| 123 |
+
|
| 124 |
+
|
| 125 |
+
def main():
|
| 126 |
+
H, logprint = set_up_hyperparams()
|
| 127 |
+
H, data_train, data_valid_or_test, preprocess_fn = set_up_data(H)
|
| 128 |
+
vae, ema_vae = load_vaes(H, logprint)
|
| 129 |
+
if H.test_eval:
|
| 130 |
+
run_test_eval(H, ema_vae, data_valid_or_test, preprocess_fn, logprint)
|
| 131 |
+
else:
|
| 132 |
+
train_loop(H, data_train, data_valid_or_test, preprocess_fn, vae, ema_vae, logprint)
|
| 133 |
+
|
| 134 |
+
|
| 135 |
+
if __name__ == "__main__":
|
| 136 |
+
main()
|
MindEye_Imagery/src/vdvae/train_helpers.py
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
import numpy as np
|
| 3 |
+
#from mpi4py import MPI
|
| 4 |
+
import socket
|
| 5 |
+
import argparse
|
| 6 |
+
import os
|
| 7 |
+
import json
|
| 8 |
+
import subprocess
|
| 9 |
+
from hps import Hyperparams, parse_args_and_update_hparams, add_vae_arguments
|
| 10 |
+
from vdvae_utils import (logger,
|
| 11 |
+
local_mpi_rank,
|
| 12 |
+
mpi_size,
|
| 13 |
+
maybe_download,
|
| 14 |
+
mpi_rank)
|
| 15 |
+
from data import mkdir_p
|
| 16 |
+
from contextlib import contextmanager
|
| 17 |
+
import torch.distributed as dist
|
| 18 |
+
#from apex.optimizers import FusedAdam as AdamW
|
| 19 |
+
from vae import VAE
|
| 20 |
+
from torch.nn.parallel.distributed import DistributedDataParallel
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def update_ema(vae, ema_vae, ema_rate):
|
| 24 |
+
for p1, p2 in zip(vae.parameters(), ema_vae.parameters()):
|
| 25 |
+
p2.data.mul_(ema_rate)
|
| 26 |
+
p2.data.add_(p1.data * (1 - ema_rate))
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
def save_model(path, vae, ema_vae, optimizer, H):
|
| 30 |
+
torch.save(vae.state_dict(), f'{path}-model.th')
|
| 31 |
+
torch.save(ema_vae.state_dict(), f'{path}-model-ema.th')
|
| 32 |
+
torch.save(optimizer.state_dict(), f'{path}-opt.th')
|
| 33 |
+
from_log = os.path.join(H.save_dir, 'log.jsonl')
|
| 34 |
+
to_log = f'{os.path.dirname(path)}/{os.path.basename(path)}-log.jsonl'
|
| 35 |
+
subprocess.check_output(['cp', from_log, to_log])
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def accumulate_stats(stats, frequency):
|
| 39 |
+
z = {}
|
| 40 |
+
for k in stats[-1]:
|
| 41 |
+
if k in ['distortion_nans', 'rate_nans', 'skipped_updates', 'gcskip']:
|
| 42 |
+
z[k] = np.sum([a[k] for a in stats[-frequency:]])
|
| 43 |
+
elif k == 'grad_norm':
|
| 44 |
+
vals = [a[k] for a in stats[-frequency:]]
|
| 45 |
+
finites = np.array(vals)[np.isfinite(vals)]
|
| 46 |
+
if len(finites) == 0:
|
| 47 |
+
z[k] = 0.0
|
| 48 |
+
else:
|
| 49 |
+
z[k] = np.max(finites)
|
| 50 |
+
elif k == 'elbo':
|
| 51 |
+
vals = [a[k] for a in stats[-frequency:]]
|
| 52 |
+
finites = np.array(vals)[np.isfinite(vals)]
|
| 53 |
+
z['elbo'] = np.mean(vals)
|
| 54 |
+
z['elbo_filtered'] = np.mean(finites)
|
| 55 |
+
elif k == 'iter_time':
|
| 56 |
+
z[k] = stats[-1][k] if len(stats) < frequency else np.mean([a[k] for a in stats[-frequency:]])
|
| 57 |
+
else:
|
| 58 |
+
z[k] = np.mean([a[k] for a in stats[-frequency:]])
|
| 59 |
+
return z
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
def linear_warmup(warmup_iters):
|
| 63 |
+
def f(iteration):
|
| 64 |
+
return 1.0 if iteration > warmup_iters else iteration / warmup_iters
|
| 65 |
+
return f
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
def setup_mpi(H):
|
| 69 |
+
H.mpi_size = mpi_size()
|
| 70 |
+
H.local_rank = local_mpi_rank()
|
| 71 |
+
H.rank = mpi_rank()
|
| 72 |
+
os.environ["RANK"] = str(H.rank)
|
| 73 |
+
os.environ["WORLD_SIZE"] = str(H.mpi_size)
|
| 74 |
+
os.environ["MASTER_PORT"] = str(H.port)
|
| 75 |
+
# os.environ["NCCL_LL_THRESHOLD"] = "0"
|
| 76 |
+
os.environ["MASTER_ADDR"] = MPI.COMM_WORLD.bcast(socket.gethostname(), root=0)
|
| 77 |
+
torch.cuda.set_device(H.local_rank)
|
| 78 |
+
dist.init_process_group(backend='nccl', init_method=f"env://")
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
def distributed_maybe_download(path, local_rank, mpi_size):
|
| 82 |
+
if not path.startswith('gs://'):
|
| 83 |
+
return path
|
| 84 |
+
filename = path[5:].replace('/', '-')
|
| 85 |
+
with first_rank_first(local_rank, mpi_size):
|
| 86 |
+
fp = maybe_download(path, filename)
|
| 87 |
+
return fp
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
@contextmanager
|
| 91 |
+
def first_rank_first(local_rank, mpi_size):
|
| 92 |
+
if mpi_size > 1 and local_rank > 0:
|
| 93 |
+
dist.barrier()
|
| 94 |
+
|
| 95 |
+
try:
|
| 96 |
+
yield
|
| 97 |
+
finally:
|
| 98 |
+
if mpi_size > 1 and local_rank == 0:
|
| 99 |
+
dist.barrier()
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
def setup_save_dirs(H):
|
| 103 |
+
H.save_dir = os.path.join(H.save_dir, H.desc)
|
| 104 |
+
mkdir_p(H.save_dir)
|
| 105 |
+
H.logdir = os.path.join(H.save_dir, 'log')
|
| 106 |
+
|
| 107 |
+
|
| 108 |
+
def set_up_hyperparams(s=None):
|
| 109 |
+
H = Hyperparams()
|
| 110 |
+
parser = argparse.ArgumentParser()
|
| 111 |
+
parser = add_vae_arguments(parser)
|
| 112 |
+
parse_args_and_update_hparams(H, parser, s=s)
|
| 113 |
+
setup_mpi(H)
|
| 114 |
+
setup_save_dirs(H)
|
| 115 |
+
logprint = logger(H.logdir)
|
| 116 |
+
for i, k in enumerate(sorted(H)):
|
| 117 |
+
logprint(type='hparam', key=k, value=H[k])
|
| 118 |
+
np.random.seed(H.seed)
|
| 119 |
+
torch.manual_seed(H.seed)
|
| 120 |
+
torch.cuda.manual_seed(H.seed)
|
| 121 |
+
logprint('training model', H.desc, 'on', H.dataset)
|
| 122 |
+
return H, logprint
|
| 123 |
+
|
| 124 |
+
|
| 125 |
+
def restore_params(model, path, local_rank, mpi_size, map_ddp=True, map_cpu=False):
|
| 126 |
+
state_dict = torch.load(distributed_maybe_download(path, local_rank, mpi_size), map_location='cpu' if map_cpu else None)
|
| 127 |
+
if map_ddp:
|
| 128 |
+
new_state_dict = {}
|
| 129 |
+
l = len('module.')
|
| 130 |
+
for k in state_dict:
|
| 131 |
+
if k.startswith('module.'):
|
| 132 |
+
new_state_dict[k[l:]] = state_dict[k]
|
| 133 |
+
else:
|
| 134 |
+
new_state_dict[k] = state_dict[k]
|
| 135 |
+
state_dict = new_state_dict
|
| 136 |
+
model.load_state_dict(state_dict)
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
def restore_log(path, local_rank, mpi_size):
|
| 140 |
+
loaded = [json.loads(l) for l in open(distributed_maybe_download(path, local_rank, mpi_size))]
|
| 141 |
+
try:
|
| 142 |
+
cur_eval_loss = min([z['elbo'] for z in loaded if 'type' in z and z['type'] == 'eval_loss'])
|
| 143 |
+
except ValueError:
|
| 144 |
+
cur_eval_loss = float('inf')
|
| 145 |
+
starting_epoch = max([z['epoch'] for z in loaded if 'type' in z and z['type'] == 'train_loss'])
|
| 146 |
+
iterate = max([z['step'] for z in loaded if 'type' in z and z['type'] == 'train_loss'])
|
| 147 |
+
return cur_eval_loss, iterate, starting_epoch
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
def load_vaes(H, logprint):
|
| 151 |
+
vae = VAE(H)
|
| 152 |
+
if H.restore_path:
|
| 153 |
+
logprint(f'Restoring vae from {H.restore_path}')
|
| 154 |
+
restore_params(vae, H.restore_path, map_cpu=True, local_rank=H.local_rank, mpi_size=H.mpi_size)
|
| 155 |
+
|
| 156 |
+
ema_vae = VAE(H)
|
| 157 |
+
if H.restore_ema_path:
|
| 158 |
+
logprint(f'Restoring ema vae from {H.restore_ema_path}')
|
| 159 |
+
restore_params(ema_vae, H.restore_ema_path, map_cpu=True, local_rank=H.local_rank, mpi_size=H.mpi_size)
|
| 160 |
+
else:
|
| 161 |
+
ema_vae.load_state_dict(vae.state_dict())
|
| 162 |
+
ema_vae.requires_grad_(False)
|
| 163 |
+
|
| 164 |
+
vae = vae.cuda(H.local_rank)
|
| 165 |
+
ema_vae = ema_vae.cuda(H.local_rank)
|
| 166 |
+
|
| 167 |
+
vae = DistributedDataParallel(vae, device_ids=[H.local_rank], output_device=H.local_rank)
|
| 168 |
+
|
| 169 |
+
if len(list(vae.named_parameters())) != len(list(vae.parameters())):
|
| 170 |
+
raise ValueError('Some params are not named. Please name all params.')
|
| 171 |
+
total_params = 0
|
| 172 |
+
for name, p in vae.named_parameters():
|
| 173 |
+
total_params += np.prod(p.shape)
|
| 174 |
+
logprint(total_params=total_params, readable=f'{total_params:,}')
|
| 175 |
+
return vae, ema_vae
|
| 176 |
+
|
| 177 |
+
|
| 178 |
+
def load_opt(H, vae, logprint):
|
| 179 |
+
optimizer = AdamW(vae.parameters(), weight_decay=H.wd, lr=H.lr, betas=(H.adam_beta1, H.adam_beta2))
|
| 180 |
+
scheduler = torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda=linear_warmup(H.warmup_iters))
|
| 181 |
+
|
| 182 |
+
if H.restore_optimizer_path:
|
| 183 |
+
optimizer.load_state_dict(
|
| 184 |
+
torch.load(distributed_maybe_download(H.restore_optimizer_path, H.local_rank, H.mpi_size), map_location='cpu'))
|
| 185 |
+
if H.restore_log_path:
|
| 186 |
+
cur_eval_loss, iterate, starting_epoch = restore_log(H.restore_log_path, H.local_rank, H.mpi_size)
|
| 187 |
+
else:
|
| 188 |
+
cur_eval_loss, iterate, starting_epoch = float('inf'), 0, 0
|
| 189 |
+
logprint('starting at epoch', starting_epoch, 'iterate', iterate, 'eval loss', cur_eval_loss)
|
| 190 |
+
return optimizer, scheduler, cur_eval_loss, iterate, starting_epoch
|
MindEye_Imagery/src/vdvae/vae.py
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
from torch import nn
|
| 3 |
+
from torch.nn import functional as F
|
| 4 |
+
from vae_helpers import HModule, get_1x1, get_3x3, DmolNet, draw_gaussian_diag_samples, gaussian_analytical_kl
|
| 5 |
+
from collections import defaultdict
|
| 6 |
+
import numpy as np
|
| 7 |
+
import itertools
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
class Block(nn.Module):
|
| 11 |
+
def __init__(self, in_width, middle_width, out_width, down_rate=None, residual=False, use_3x3=True, zero_last=False):
|
| 12 |
+
super().__init__()
|
| 13 |
+
self.down_rate = down_rate
|
| 14 |
+
self.residual = residual
|
| 15 |
+
self.c1 = get_1x1(in_width, middle_width)
|
| 16 |
+
self.c2 = get_3x3(middle_width, middle_width) if use_3x3 else get_1x1(middle_width, middle_width)
|
| 17 |
+
self.c3 = get_3x3(middle_width, middle_width) if use_3x3 else get_1x1(middle_width, middle_width)
|
| 18 |
+
self.c4 = get_1x1(middle_width, out_width, zero_weights=zero_last)
|
| 19 |
+
|
| 20 |
+
def forward(self, x):
|
| 21 |
+
xhat = self.c1(F.gelu(x))
|
| 22 |
+
xhat = self.c2(F.gelu(xhat))
|
| 23 |
+
xhat = self.c3(F.gelu(xhat))
|
| 24 |
+
xhat = self.c4(F.gelu(xhat))
|
| 25 |
+
out = x + xhat if self.residual else xhat
|
| 26 |
+
if self.down_rate is not None:
|
| 27 |
+
out = F.avg_pool2d(out, kernel_size=self.down_rate, stride=self.down_rate)
|
| 28 |
+
return out
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
def parse_layer_string(s):
|
| 32 |
+
layers = []
|
| 33 |
+
for ss in s.split(','):
|
| 34 |
+
if 'x' in ss:
|
| 35 |
+
res, num = ss.split('x')
|
| 36 |
+
count = int(num)
|
| 37 |
+
layers += [(int(res), None) for _ in range(count)]
|
| 38 |
+
elif 'm' in ss:
|
| 39 |
+
res, mixin = [int(a) for a in ss.split('m')]
|
| 40 |
+
layers.append((res, mixin))
|
| 41 |
+
elif 'd' in ss:
|
| 42 |
+
res, down_rate = [int(a) for a in ss.split('d')]
|
| 43 |
+
layers.append((res, down_rate))
|
| 44 |
+
else:
|
| 45 |
+
res = int(ss)
|
| 46 |
+
layers.append((res, None))
|
| 47 |
+
return layers
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def pad_channels(t, width):
|
| 51 |
+
d1, d2, d3, d4 = t.shape
|
| 52 |
+
empty = torch.zeros(d1, width, d3, d4, device=t.device)
|
| 53 |
+
empty[:, :d2, :, :] = t
|
| 54 |
+
return empty
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
def get_width_settings(width, s):
|
| 58 |
+
mapping = defaultdict(lambda: width)
|
| 59 |
+
if s:
|
| 60 |
+
s = s.split(',')
|
| 61 |
+
for ss in s:
|
| 62 |
+
k, v = ss.split(':')
|
| 63 |
+
mapping[int(k)] = int(v)
|
| 64 |
+
return mapping
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
class Encoder(HModule):
|
| 68 |
+
def build(self):
|
| 69 |
+
H = self.H
|
| 70 |
+
self.in_conv = get_3x3(H.image_channels, H.width)
|
| 71 |
+
self.widths = get_width_settings(H.width, H.custom_width_str)
|
| 72 |
+
enc_blocks = []
|
| 73 |
+
blockstr = parse_layer_string(H.enc_blocks)
|
| 74 |
+
for res, down_rate in blockstr:
|
| 75 |
+
use_3x3 = res > 2 # Don't use 3x3s for 1x1, 2x2 patches
|
| 76 |
+
enc_blocks.append(Block(self.widths[res], int(self.widths[res] * H.bottleneck_multiple), self.widths[res], down_rate=down_rate, residual=True, use_3x3=use_3x3))
|
| 77 |
+
n_blocks = len(blockstr)
|
| 78 |
+
for b in enc_blocks:
|
| 79 |
+
b.c4.weight.data *= np.sqrt(1 / n_blocks)
|
| 80 |
+
self.enc_blocks = nn.ModuleList(enc_blocks)
|
| 81 |
+
|
| 82 |
+
def forward(self, x):
|
| 83 |
+
x = x.permute(0, 3, 1, 2).contiguous()
|
| 84 |
+
x = self.in_conv(x)
|
| 85 |
+
activations = {}
|
| 86 |
+
activations[x.shape[2]] = x
|
| 87 |
+
for block in self.enc_blocks:
|
| 88 |
+
x = block(x)
|
| 89 |
+
res = x.shape[2]
|
| 90 |
+
x = x if x.shape[1] == self.widths[res] else pad_channels(x, self.widths[res])
|
| 91 |
+
activations[res] = x
|
| 92 |
+
return activations
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
class DecBlock(nn.Module):
|
| 96 |
+
def __init__(self, H, res, mixin, n_blocks):
|
| 97 |
+
super().__init__()
|
| 98 |
+
self.base = res
|
| 99 |
+
self.mixin = mixin
|
| 100 |
+
self.H = H
|
| 101 |
+
self.widths = get_width_settings(H.width, H.custom_width_str)
|
| 102 |
+
width = self.widths[res]
|
| 103 |
+
use_3x3 = res > 2
|
| 104 |
+
cond_width = int(width * H.bottleneck_multiple)
|
| 105 |
+
self.zdim = H.zdim
|
| 106 |
+
self.enc = Block(width * 2, cond_width, H.zdim * 2, residual=False, use_3x3=use_3x3)
|
| 107 |
+
self.prior = Block(width, cond_width, H.zdim * 2 + width, residual=False, use_3x3=use_3x3, zero_last=True)
|
| 108 |
+
self.z_proj = get_1x1(H.zdim, width)
|
| 109 |
+
self.z_proj.weight.data *= np.sqrt(1 / n_blocks)
|
| 110 |
+
self.resnet = Block(width, cond_width, width, residual=True, use_3x3=use_3x3)
|
| 111 |
+
self.resnet.c4.weight.data *= np.sqrt(1 / n_blocks)
|
| 112 |
+
self.z_fn = lambda x: self.z_proj(x)
|
| 113 |
+
|
| 114 |
+
def sample(self, x, acts):
|
| 115 |
+
qm, qv = self.enc(torch.cat([x, acts], dim=1)).chunk(2, dim=1)
|
| 116 |
+
feats = self.prior(x)
|
| 117 |
+
pm, pv, xpp = feats[:, :self.zdim, ...], feats[:, self.zdim:self.zdim * 2, ...], feats[:, self.zdim * 2:, ...]
|
| 118 |
+
x = x + xpp
|
| 119 |
+
z = draw_gaussian_diag_samples(qm, qv)
|
| 120 |
+
kl = gaussian_analytical_kl(qm, pm, qv, pv)
|
| 121 |
+
return z, x, kl
|
| 122 |
+
|
| 123 |
+
def sample_uncond(self, x, t=None, lvs=None):
|
| 124 |
+
n, c, h, w = x.shape
|
| 125 |
+
feats = self.prior(x)
|
| 126 |
+
pm, pv, xpp = feats[:, :self.zdim, ...], feats[:, self.zdim:self.zdim * 2, ...], feats[:, self.zdim * 2:, ...]
|
| 127 |
+
x = x + xpp
|
| 128 |
+
if lvs is not None:
|
| 129 |
+
z = lvs
|
| 130 |
+
else:
|
| 131 |
+
if t is not None:
|
| 132 |
+
pv = pv + torch.ones_like(pv) * np.log(t)
|
| 133 |
+
z = draw_gaussian_diag_samples(pm, pv)
|
| 134 |
+
return z, x
|
| 135 |
+
|
| 136 |
+
def get_inputs(self, xs, activations):
|
| 137 |
+
acts = activations[self.base]
|
| 138 |
+
try:
|
| 139 |
+
x = xs[self.base]
|
| 140 |
+
except KeyError:
|
| 141 |
+
x = torch.zeros_like(acts)
|
| 142 |
+
if acts.shape[0] != x.shape[0]:
|
| 143 |
+
x = x.repeat(acts.shape[0], 1, 1, 1)
|
| 144 |
+
return x, acts
|
| 145 |
+
|
| 146 |
+
def forward(self, xs, activations, get_latents=False):
|
| 147 |
+
x, acts = self.get_inputs(xs, activations)
|
| 148 |
+
if self.mixin is not None:
|
| 149 |
+
x = x + F.interpolate(xs[self.mixin][:, :x.shape[1], ...], scale_factor=self.base // self.mixin)
|
| 150 |
+
z, x, kl = self.sample(x, acts)
|
| 151 |
+
x = x + self.z_fn(z)
|
| 152 |
+
x = self.resnet(x)
|
| 153 |
+
xs[self.base] = x
|
| 154 |
+
if get_latents:
|
| 155 |
+
return xs, dict(z=z.detach(), kl=kl)
|
| 156 |
+
return xs, dict(kl=kl)
|
| 157 |
+
|
| 158 |
+
def forward_uncond(self, xs, t=None, lvs=None):
|
| 159 |
+
try:
|
| 160 |
+
x = xs[self.base]
|
| 161 |
+
except KeyError:
|
| 162 |
+
ref = xs[list(xs.keys())[0]]
|
| 163 |
+
x = torch.zeros(dtype=ref.dtype, size=(ref.shape[0], self.widths[self.base], self.base, self.base), device=ref.device)
|
| 164 |
+
if self.mixin is not None:
|
| 165 |
+
x = x + F.interpolate(xs[self.mixin][:, :x.shape[1], ...], scale_factor=self.base // self.mixin)
|
| 166 |
+
z, x = self.sample_uncond(x, t, lvs=lvs)
|
| 167 |
+
x = x + self.z_fn(z)
|
| 168 |
+
x = self.resnet(x)
|
| 169 |
+
xs[self.base] = x
|
| 170 |
+
return xs
|
| 171 |
+
|
| 172 |
+
|
| 173 |
+
class Decoder(HModule):
|
| 174 |
+
|
| 175 |
+
def build(self):
|
| 176 |
+
H = self.H
|
| 177 |
+
resos = set()
|
| 178 |
+
dec_blocks = []
|
| 179 |
+
self.widths = get_width_settings(H.width, H.custom_width_str)
|
| 180 |
+
blocks = parse_layer_string(H.dec_blocks)
|
| 181 |
+
for idx, (res, mixin) in enumerate(blocks):
|
| 182 |
+
dec_blocks.append(DecBlock(H, res, mixin, n_blocks=len(blocks)))
|
| 183 |
+
resos.add(res)
|
| 184 |
+
self.resolutions = sorted(resos)
|
| 185 |
+
self.dec_blocks = nn.ModuleList(dec_blocks)
|
| 186 |
+
self.bias_xs = nn.ParameterList([nn.Parameter(torch.zeros(1, self.widths[res], res, res)) for res in self.resolutions if res <= H.no_bias_above])
|
| 187 |
+
self.out_net = DmolNet(H)
|
| 188 |
+
self.gain = nn.Parameter(torch.ones(1, H.width, 1, 1))
|
| 189 |
+
self.bias = nn.Parameter(torch.zeros(1, H.width, 1, 1))
|
| 190 |
+
self.final_fn = lambda x: x * self.gain + self.bias
|
| 191 |
+
|
| 192 |
+
def forward(self, activations, get_latents=False):
|
| 193 |
+
stats = []
|
| 194 |
+
xs = {a.shape[2]: a for a in self.bias_xs}
|
| 195 |
+
for block in self.dec_blocks:
|
| 196 |
+
xs, block_stats = block(xs, activations, get_latents=get_latents)
|
| 197 |
+
stats.append(block_stats)
|
| 198 |
+
xs[self.H.image_size] = self.final_fn(xs[self.H.image_size])
|
| 199 |
+
return xs[self.H.image_size], stats
|
| 200 |
+
|
| 201 |
+
def forward_uncond(self, n, t=None, y=None):
|
| 202 |
+
xs = {}
|
| 203 |
+
for bias in self.bias_xs:
|
| 204 |
+
xs[bias.shape[2]] = bias.repeat(n, 1, 1, 1)
|
| 205 |
+
for idx, block in enumerate(self.dec_blocks):
|
| 206 |
+
try:
|
| 207 |
+
temp = t[idx]
|
| 208 |
+
except TypeError:
|
| 209 |
+
temp = t
|
| 210 |
+
xs = block.forward_uncond(xs, temp)
|
| 211 |
+
xs[self.H.image_size] = self.final_fn(xs[self.H.image_size])
|
| 212 |
+
return xs[self.H.image_size]
|
| 213 |
+
|
| 214 |
+
def forward_manual_latents(self, n, latents, t=None):
|
| 215 |
+
xs = {}
|
| 216 |
+
for bias in self.bias_xs:
|
| 217 |
+
xs[bias.shape[2]] = bias.repeat(n, 1, 1, 1)
|
| 218 |
+
for block, lvs in itertools.zip_longest(self.dec_blocks, latents):
|
| 219 |
+
xs = block.forward_uncond(xs, t, lvs=lvs)
|
| 220 |
+
xs[self.H.image_size] = self.final_fn(xs[self.H.image_size])
|
| 221 |
+
return xs[self.H.image_size]
|
| 222 |
+
|
| 223 |
+
|
| 224 |
+
class VAE(HModule):
|
| 225 |
+
def build(self):
|
| 226 |
+
self.encoder = Encoder(self.H)
|
| 227 |
+
self.decoder = Decoder(self.H)
|
| 228 |
+
|
| 229 |
+
def forward(self, x, x_target):
|
| 230 |
+
activations = self.encoder.forward(x)
|
| 231 |
+
px_z, stats = self.decoder.forward(activations)
|
| 232 |
+
distortion_per_pixel = self.decoder.out_net.nll(px_z, x_target)
|
| 233 |
+
rate_per_pixel = torch.zeros_like(distortion_per_pixel)
|
| 234 |
+
ndims = np.prod(x.shape[1:])
|
| 235 |
+
for statdict in stats:
|
| 236 |
+
rate_per_pixel += statdict['kl'].sum(dim=(1, 2, 3))
|
| 237 |
+
rate_per_pixel /= ndims
|
| 238 |
+
elbo = (distortion_per_pixel + rate_per_pixel).mean()
|
| 239 |
+
return dict(elbo=elbo, distortion=distortion_per_pixel.mean(), rate=rate_per_pixel.mean())
|
| 240 |
+
|
| 241 |
+
def forward_get_latents(self, x):
|
| 242 |
+
activations = self.encoder.forward(x)
|
| 243 |
+
_, stats = self.decoder.forward(activations, get_latents=True)
|
| 244 |
+
return stats
|
| 245 |
+
|
| 246 |
+
def forward_uncond_samples(self, n_batch, t=None):
|
| 247 |
+
px_z = self.decoder.forward_uncond(n_batch, t=t)
|
| 248 |
+
return self.decoder.out_net.sample(px_z)
|
| 249 |
+
|
| 250 |
+
def forward_samples_set_latents(self, n_batch, latents, t=None):
|
| 251 |
+
px_z = self.decoder.forward_manual_latents(n_batch, latents, t=t)
|
| 252 |
+
return self.decoder.out_net.sample(px_z)
|
MindEye_Imagery/src/vdvae/vae_helpers.py
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
import torch
|
| 3 |
+
import torch.nn as nn
|
| 4 |
+
import torch.nn.functional as F
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
@torch.jit.script
|
| 8 |
+
def gaussian_analytical_kl(mu1, mu2, logsigma1, logsigma2):
|
| 9 |
+
return -0.5 + logsigma2 - logsigma1 + 0.5 * (logsigma1.exp() ** 2 + (mu1 - mu2) ** 2) / (logsigma2.exp() ** 2)
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
@torch.jit.script
|
| 13 |
+
def draw_gaussian_diag_samples(mu, logsigma):
|
| 14 |
+
eps = torch.empty_like(mu).normal_(0., 1.)
|
| 15 |
+
return torch.exp(logsigma) * eps + mu
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def get_conv(in_dim, out_dim, kernel_size, stride, padding, zero_bias=True, zero_weights=False, groups=1, scaled=False):
|
| 19 |
+
c = nn.Conv2d(in_dim, out_dim, kernel_size, stride, padding, groups=groups)
|
| 20 |
+
if zero_bias:
|
| 21 |
+
c.bias.data *= 0.0
|
| 22 |
+
if zero_weights:
|
| 23 |
+
c.weight.data *= 0.0
|
| 24 |
+
return c
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def get_3x3(in_dim, out_dim, zero_bias=True, zero_weights=False, groups=1, scaled=False):
|
| 28 |
+
return get_conv(in_dim, out_dim, 3, 1, 1, zero_bias, zero_weights, groups=groups, scaled=scaled)
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
def get_1x1(in_dim, out_dim, zero_bias=True, zero_weights=False, groups=1, scaled=False):
|
| 32 |
+
return get_conv(in_dim, out_dim, 1, 1, 0, zero_bias, zero_weights, groups=groups, scaled=scaled)
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def log_prob_from_logits(x):
|
| 36 |
+
""" numerically stable log_softmax implementation that prevents overflow """
|
| 37 |
+
axis = len(x.shape) - 1
|
| 38 |
+
m = x.max(dim=axis, keepdim=True)[0]
|
| 39 |
+
return x - m - torch.log(torch.exp(x - m).sum(dim=axis, keepdim=True))
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
def const_max(t, constant):
|
| 43 |
+
other = torch.ones_like(t) * constant
|
| 44 |
+
return torch.max(t, other)
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
def const_min(t, constant):
|
| 48 |
+
other = torch.ones_like(t) * constant
|
| 49 |
+
return torch.min(t, other)
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
def discretized_mix_logistic_loss(x, l, low_bit=False):
|
| 53 |
+
""" log-likelihood for mixture of discretized logistics, assumes the data has been rescaled to [-1,1] interval """
|
| 54 |
+
# Adapted from https://github.com/openai/pixel-cnn/blob/master/pixel_cnn_pp/nn.py
|
| 55 |
+
xs = [s for s in x.shape] # true image (i.e. labels) to regress to, e.g. (B,32,32,3)
|
| 56 |
+
ls = [s for s in l.shape] # predicted distribution, e.g. (B,32,32,100)
|
| 57 |
+
nr_mix = int(ls[-1] / 10) # here and below: unpacking the params of the mixture of logistics
|
| 58 |
+
logit_probs = l[:, :, :, :nr_mix]
|
| 59 |
+
l = torch.reshape(l[:, :, :, nr_mix:], xs + [nr_mix * 3])
|
| 60 |
+
means = l[:, :, :, :, :nr_mix]
|
| 61 |
+
log_scales = const_max(l[:, :, :, :, nr_mix:2 * nr_mix], -7.)
|
| 62 |
+
coeffs = torch.tanh(l[:, :, :, :, 2 * nr_mix:3 * nr_mix])
|
| 63 |
+
x = torch.reshape(x, xs + [1]) + torch.zeros(xs + [nr_mix]).to(x.device) # here and below: getting the means and adjusting them based on preceding sub-pixels
|
| 64 |
+
m2 = torch.reshape(means[:, :, :, 1, :] + coeffs[:, :, :, 0, :] * x[:, :, :, 0, :], [xs[0], xs[1], xs[2], 1, nr_mix])
|
| 65 |
+
m3 = torch.reshape(means[:, :, :, 2, :] + coeffs[:, :, :, 1, :] * x[:, :, :, 0, :] + coeffs[:, :, :, 2, :] * x[:, :, :, 1, :], [xs[0], xs[1], xs[2], 1, nr_mix])
|
| 66 |
+
means = torch.cat([torch.reshape(means[:, :, :, 0, :], [xs[0], xs[1], xs[2], 1, nr_mix]), m2, m3], dim=3)
|
| 67 |
+
centered_x = x - means
|
| 68 |
+
inv_stdv = torch.exp(-log_scales)
|
| 69 |
+
if low_bit:
|
| 70 |
+
plus_in = inv_stdv * (centered_x + 1. / 31.)
|
| 71 |
+
cdf_plus = torch.sigmoid(plus_in)
|
| 72 |
+
min_in = inv_stdv * (centered_x - 1. / 31.)
|
| 73 |
+
else:
|
| 74 |
+
plus_in = inv_stdv * (centered_x + 1. / 255.)
|
| 75 |
+
cdf_plus = torch.sigmoid(plus_in)
|
| 76 |
+
min_in = inv_stdv * (centered_x - 1. / 255.)
|
| 77 |
+
cdf_min = torch.sigmoid(min_in)
|
| 78 |
+
log_cdf_plus = plus_in - F.softplus(plus_in) # log probability for edge case of 0 (before scaling)
|
| 79 |
+
log_one_minus_cdf_min = -F.softplus(min_in) # log probability for edge case of 255 (before scaling)
|
| 80 |
+
cdf_delta = cdf_plus - cdf_min # probability for all other cases
|
| 81 |
+
mid_in = inv_stdv * centered_x
|
| 82 |
+
log_pdf_mid = mid_in - log_scales - 2. * F.softplus(mid_in) # log probability in the center of the bin, to be used in extreme cases (not actually used in our code)
|
| 83 |
+
|
| 84 |
+
# now select the right output: left edge case, right edge case, normal case, extremely low prob case (doesn't actually happen for us)
|
| 85 |
+
|
| 86 |
+
# this is what we are really doing, but using the robust version below for extreme cases in other applications and to avoid NaN issue with tf.select()
|
| 87 |
+
# log_probs = tf.select(x < -0.999, log_cdf_plus, tf.select(x > 0.999, log_one_minus_cdf_min, tf.log(cdf_delta)))
|
| 88 |
+
|
| 89 |
+
# robust version, that still works if probabilities are below 1e-5 (which never happens in our code)
|
| 90 |
+
# tensorflow backpropagates through tf.select() by multiplying with zero instead of selecting: this requires use to use some ugly tricks to avoid potential NaNs
|
| 91 |
+
# the 1e-12 in tf.maximum(cdf_delta, 1e-12) is never actually used as output, it's purely there to get around the tf.select() gradient issue
|
| 92 |
+
# if the probability on a sub-pixel is below 1e-5, we use an approximation based on the assumption that the log-density is constant in the bin of the observed sub-pixel value
|
| 93 |
+
if low_bit:
|
| 94 |
+
log_probs = torch.where(x < -0.999,
|
| 95 |
+
log_cdf_plus,
|
| 96 |
+
torch.where(x > 0.999,
|
| 97 |
+
log_one_minus_cdf_min,
|
| 98 |
+
torch.where(cdf_delta > 1e-5,
|
| 99 |
+
torch.log(const_max(cdf_delta, 1e-12)),
|
| 100 |
+
log_pdf_mid - np.log(15.5))))
|
| 101 |
+
else:
|
| 102 |
+
log_probs = torch.where(x < -0.999,
|
| 103 |
+
log_cdf_plus,
|
| 104 |
+
torch.where(x > 0.999,
|
| 105 |
+
log_one_minus_cdf_min,
|
| 106 |
+
torch.where(cdf_delta > 1e-5,
|
| 107 |
+
torch.log(const_max(cdf_delta, 1e-12)),
|
| 108 |
+
log_pdf_mid - np.log(127.5))))
|
| 109 |
+
log_probs = log_probs.sum(dim=3) + log_prob_from_logits(logit_probs)
|
| 110 |
+
mixture_probs = torch.logsumexp(log_probs, -1)
|
| 111 |
+
return -1. * mixture_probs.sum(dim=[1, 2]) / np.prod(xs[1:])
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
def sample_from_discretized_mix_logistic(l, nr_mix):
|
| 115 |
+
ls = [s for s in l.shape]
|
| 116 |
+
xs = ls[:-1] + [3]
|
| 117 |
+
# unpack parameters
|
| 118 |
+
logit_probs = l[:, :, :, :nr_mix]
|
| 119 |
+
l = torch.reshape(l[:, :, :, nr_mix:], xs + [nr_mix * 3])
|
| 120 |
+
# sample mixture indicator from softmax
|
| 121 |
+
eps = torch.empty(logit_probs.shape, device=l.device).uniform_(1e-5, 1. - 1e-5)
|
| 122 |
+
amax = torch.argmax(logit_probs - torch.log(-torch.log(eps)), dim=3)
|
| 123 |
+
sel = F.one_hot(amax, num_classes=nr_mix).float()
|
| 124 |
+
sel = torch.reshape(sel, xs[:-1] + [1, nr_mix])
|
| 125 |
+
# select logistic parameters
|
| 126 |
+
means = (l[:, :, :, :, :nr_mix] * sel).sum(dim=4)
|
| 127 |
+
log_scales = const_max((l[:, :, :, :, nr_mix:nr_mix * 2] * sel).sum(dim=4), -7.)
|
| 128 |
+
coeffs = (torch.tanh(l[:, :, :, :, nr_mix * 2:nr_mix * 3]) * sel).sum(dim=4)
|
| 129 |
+
# sample from logistic & clip to interval
|
| 130 |
+
# we don't actually round to the nearest 8bit value when sampling
|
| 131 |
+
u = torch.empty(means.shape, device=means.device).uniform_(1e-5, 1. - 1e-5)
|
| 132 |
+
x = means + torch.exp(log_scales) * (torch.log(u) - torch.log(1. - u))
|
| 133 |
+
x0 = const_min(const_max(x[:, :, :, 0], -1.), 1.)
|
| 134 |
+
x1 = const_min(const_max(x[:, :, :, 1] + coeffs[:, :, :, 0] * x0, -1.), 1.)
|
| 135 |
+
x2 = const_min(const_max(x[:, :, :, 2] + coeffs[:, :, :, 1] * x0 + coeffs[:, :, :, 2] * x1, -1.), 1.)
|
| 136 |
+
return torch.cat([torch.reshape(x0, xs[:-1] + [1]), torch.reshape(x1, xs[:-1] + [1]), torch.reshape(x2, xs[:-1] + [1])], dim=3)
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
class HModule(nn.Module):
|
| 140 |
+
def __init__(self, H):
|
| 141 |
+
super().__init__()
|
| 142 |
+
self.H = H
|
| 143 |
+
self.build()
|
| 144 |
+
|
| 145 |
+
|
| 146 |
+
class DmolNet(nn.Module):
|
| 147 |
+
def __init__(self, H):
|
| 148 |
+
super().__init__()
|
| 149 |
+
self.H = H
|
| 150 |
+
self.width = H.width
|
| 151 |
+
self.out_conv = get_conv(H.width, H.num_mixtures * 10, kernel_size=1, stride=1, padding=0)
|
| 152 |
+
|
| 153 |
+
def nll(self, px_z, x):
|
| 154 |
+
return discretized_mix_logistic_loss(x=x, l=self.forward(px_z), low_bit=self.H.dataset in ['ffhq_256'])
|
| 155 |
+
|
| 156 |
+
def forward(self, px_z):
|
| 157 |
+
xhat = self.out_conv(px_z)
|
| 158 |
+
return xhat.permute(0, 2, 3, 1)
|
| 159 |
+
|
| 160 |
+
def sample(self, px_z):
|
| 161 |
+
im = sample_from_discretized_mix_logistic(self.forward(px_z), self.H.num_mixtures)
|
| 162 |
+
xhat = (im + 1.0) * 127.5
|
| 163 |
+
xhat = xhat.detach().cpu().numpy()
|
| 164 |
+
xhat = np.minimum(np.maximum(0.0, xhat), 255.0).astype(np.uint8)
|
| 165 |
+
return xhat
|
MindEye_Imagery/src/vdvae/vdvae_utils.py
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#from mpi4py import MPI
|
| 2 |
+
import os
|
| 3 |
+
import json
|
| 4 |
+
import tempfile
|
| 5 |
+
import numpy as np
|
| 6 |
+
import torch
|
| 7 |
+
import time
|
| 8 |
+
import subprocess
|
| 9 |
+
import torch.distributed as dist
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
def allreduce(x, average):
|
| 13 |
+
if mpi_size() > 1:
|
| 14 |
+
dist.all_reduce(x, dist.ReduceOp.SUM)
|
| 15 |
+
return x / mpi_size() if average else x
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def get_cpu_stats_over_ranks(stat_dict):
|
| 19 |
+
keys = sorted(stat_dict.keys())
|
| 20 |
+
allreduced = allreduce(torch.stack([torch.as_tensor(stat_dict[k]).detach().cuda().float() for k in keys]), average=True).cpu()
|
| 21 |
+
return {k: allreduced[i].item() for (i, k) in enumerate(keys)}
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
class Hyperparams(dict):
|
| 25 |
+
def __getattr__(self, attr):
|
| 26 |
+
try:
|
| 27 |
+
return self[attr]
|
| 28 |
+
except KeyError:
|
| 29 |
+
return None
|
| 30 |
+
|
| 31 |
+
def __setattr__(self, attr, value):
|
| 32 |
+
self[attr] = value
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def logger(log_prefix):
|
| 36 |
+
'Prints the arguments out to stdout, .txt, and .jsonl files'
|
| 37 |
+
|
| 38 |
+
jsonl_path = f'{log_prefix}.jsonl'
|
| 39 |
+
txt_path = f'{log_prefix}.txt'
|
| 40 |
+
|
| 41 |
+
def log(*args, pprint=False, **kwargs):
|
| 42 |
+
if mpi_rank() != 0:
|
| 43 |
+
return
|
| 44 |
+
t = time.ctime()
|
| 45 |
+
argdict = {'time': t}
|
| 46 |
+
if len(args) > 0:
|
| 47 |
+
argdict['message'] = ' '.join([str(x) for x in args])
|
| 48 |
+
argdict.update(kwargs)
|
| 49 |
+
|
| 50 |
+
txt_str = []
|
| 51 |
+
args_iter = sorted(argdict) if pprint else argdict
|
| 52 |
+
for k in args_iter:
|
| 53 |
+
val = argdict[k]
|
| 54 |
+
if isinstance(val, np.ndarray):
|
| 55 |
+
val = val.tolist()
|
| 56 |
+
elif isinstance(val, np.integer):
|
| 57 |
+
val = int(val)
|
| 58 |
+
elif isinstance(val, np.floating):
|
| 59 |
+
val = float(val)
|
| 60 |
+
argdict[k] = val
|
| 61 |
+
if isinstance(val, float):
|
| 62 |
+
val = f'{val:.5f}'
|
| 63 |
+
txt_str.append(f'{k}: {val}')
|
| 64 |
+
txt_str = ', '.join(txt_str)
|
| 65 |
+
|
| 66 |
+
if pprint:
|
| 67 |
+
json_str = json.dumps(argdict, sort_keys=True)
|
| 68 |
+
txt_str = json.dumps(argdict, sort_keys=True, indent=4)
|
| 69 |
+
else:
|
| 70 |
+
json_str = json.dumps(argdict)
|
| 71 |
+
|
| 72 |
+
print(txt_str, flush=True)
|
| 73 |
+
|
| 74 |
+
with open(txt_path, "a+") as f:
|
| 75 |
+
print(txt_str, file=f, flush=True)
|
| 76 |
+
with open(jsonl_path, "a+") as f:
|
| 77 |
+
print(json_str, file=f, flush=True)
|
| 78 |
+
|
| 79 |
+
return log
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
def maybe_download(path, filename=None):
|
| 83 |
+
'''If a path is a gsutil path, download it and return the local link,
|
| 84 |
+
otherwise return link'''
|
| 85 |
+
if not path.startswith('gs://'):
|
| 86 |
+
return path
|
| 87 |
+
if filename:
|
| 88 |
+
local_dest = f'/tmp/'
|
| 89 |
+
out_path = f'/tmp/{filename}'
|
| 90 |
+
if os.path.isfile(out_path):
|
| 91 |
+
return out_path
|
| 92 |
+
subprocess.check_output(['gsutil', '-m', 'cp', '-R', path, out_path])
|
| 93 |
+
return out_path
|
| 94 |
+
else:
|
| 95 |
+
local_dest = tempfile.mkstemp()[1]
|
| 96 |
+
subprocess.check_output(['gsutil', '-m', 'cp', path, local_dest])
|
| 97 |
+
return local_dest
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
def tile_images(images, d1=4, d2=4, border=1):
|
| 101 |
+
id1, id2, c = images[0].shape
|
| 102 |
+
out = np.ones([d1 * id1 + border * (d1 + 1),
|
| 103 |
+
d2 * id2 + border * (d2 + 1),
|
| 104 |
+
c], dtype=np.uint8)
|
| 105 |
+
out *= 255
|
| 106 |
+
if len(images) != d1 * d2:
|
| 107 |
+
raise ValueError('Wrong num of images')
|
| 108 |
+
for imgnum, im in enumerate(images):
|
| 109 |
+
num_d1 = imgnum // d2
|
| 110 |
+
num_d2 = imgnum % d2
|
| 111 |
+
start_d1 = num_d1 * id1 + border * (num_d1 + 1)
|
| 112 |
+
start_d2 = num_d2 * id2 + border * (num_d2 + 1)
|
| 113 |
+
out[start_d1:start_d1 + id1, start_d2:start_d2 + id2, :] = im
|
| 114 |
+
return out
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
def mpi_size():
|
| 118 |
+
return MPI.COMM_WORLD.Get_size()
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
def mpi_rank():
|
| 122 |
+
return MPI.COMM_WORLD.Get_rank()
|
| 123 |
+
|
| 124 |
+
|
| 125 |
+
def num_nodes():
|
| 126 |
+
nn = mpi_size()
|
| 127 |
+
if nn % 8 == 0:
|
| 128 |
+
return nn // 8
|
| 129 |
+
return nn // 8 + 1
|
| 130 |
+
|
| 131 |
+
|
| 132 |
+
def gpus_per_node():
|
| 133 |
+
size = mpi_size()
|
| 134 |
+
if size > 1:
|
| 135 |
+
return max(size // num_nodes(), 1)
|
| 136 |
+
return 1
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
def local_mpi_rank():
|
| 140 |
+
return mpi_rank() % gpus_per_node()
|
spurious_reconstruction/.gitignore
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# python generated files
|
| 2 |
+
__pycache__/
|
| 3 |
+
*.py[oc]
|
| 4 |
+
build/
|
| 5 |
+
dist/
|
| 6 |
+
wheels/
|
| 7 |
+
*.egg-info
|
| 8 |
+
|
| 9 |
+
# venv
|
| 10 |
+
.venv
|
| 11 |
+
./results
|
| 12 |
+
./analysis/my_playground
|
| 13 |
+
./data
|
spurious_reconstruction/README.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Spurious-reconstruction
|
| 2 |
+
|
| 3 |
+
This repository contains demo code for the paper:
|
| 4 |
+
Ken Shirakawa, Yoshihiro Nagano, Misato Tanaka, Shuntaro C. Aoki, Yusuke Muraki, Kei Majima, and Yukiyasu Kamitani, "Spurious reconstruction from brain activity" ([arXiv](https://arxiv.org/abs/2405.10078)).
|
| 5 |
+
|
| 6 |
+
## Getting Started
|
| 7 |
+
|
| 8 |
+
### Installation
|
| 9 |
+
To clone this repository on your local machine, use the following `git clone` command with the project URL:
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
```
|
| 13 |
+
git clone https://github.com/KamitaniLab/spurious_reconstruction.git
|
| 14 |
+
```
|
| 15 |
+
### Environment Setup
|
| 16 |
+
The environment for this project was created using [Rye](https://rye.astral.sh/). To set it up, follow the official instructions to install Rye. After installation, you can synchronize the environment for this repository using:
|
| 17 |
+
|
| 18 |
+
```
|
| 19 |
+
cd spurious_reconstruction
|
| 20 |
+
rye sync
|
| 21 |
+
```
|
| 22 |
+
|
| 23 |
+
## Usage
|
| 24 |
+
|
| 25 |
+
---
|
| 26 |
+
|
| 27 |
+
We are currently preparing to share the preprocessed data and files. These files will be made available on Figshare at [this URL](https://figshare.com/articles/dataset/Spurious_reconstruction_from_brain_activity/27013342).
|
| 28 |
+
|
| 29 |
+
Reproducing the full analysis requires a large amount of data (approximately 3TB) and some analyses take considerable time to complete (up to ~2 weeks). Therefore, we recommend downloading only the minimum necessary files to reproduce specific analysis, such as image reconstruction, UMAP results or simulation analysis.
|
| 30 |
+
|
| 31 |
+
For example, if you want to reproduce the UMAP results (related to Figure 4), you can download the required data by running the following command:
|
| 32 |
+
|
| 33 |
+
```
|
| 34 |
+
python ./download.py "UMAP visualization analysis"
|
| 35 |
+
```
|
| 36 |
+
|
| 37 |
+
Alternatively, you can directly download the results of UMAP analysis with:
|
| 38 |
+
```
|
| 39 |
+
python ./download.py "UMAP visualization results"
|
| 40 |
+
```
|
| 41 |
+
Note: At the moment, only the download of **result data** is supported. Please wait a little longer for the availability of **analysis data**.
|
| 42 |
+
|
| 43 |
+
Each analysis directory contains additional information on how to reproduce the corresponding results. Please check the README files within each directory for specific instructions.
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
### Original Dataset
|
| 47 |
+
We used publicly available datasets for this project. The key datasets are:
|
| 48 |
+
|
| 49 |
+
- **NSD (Natural Scenes Dataset)**
|
| 50 |
+
- Raw fMRI data (including visual images and text annotations): Available upon request via [Spurious Reconstruction@figshare](https://forms.gle/eT4jHxaWwYUDEf2i9).
|
| 51 |
+
|
| 52 |
+
- **Deep Image Reconstruction**
|
| 53 |
+
- Raw fMRI data: Available from [OpenNeuro](https://openneuro.org/datasets/ds001506).
|
| 54 |
+
- Preprocessed fMRI data, DNN features extracted from images, and decoded DNN features: Available via [Deep Image Reconstruction@figshare](https://github.com/KamitaniLab/DeepImageReconstruction?tab=readme-ov-file#:~:text=Preprocessed%20fMRI%20data,Image%20Reconstruction%40figshare).
|
| 55 |
+
- Visual images: Available upon request via [this form](https://forms.gle/ujvA34948Xg49jdn9).
|
| 56 |
+
- Text annotations: Available from [GOD Stimuli Annotations](https://github.com/KamitaniLab/GOD_stimuli_annotations).
|
| 57 |
+
|
| 58 |
+
If you want to fully reproduce the analysis, you can use these brain data, image stimuli and corresponding text annotations.
|
spurious_reconstruction/analysis/0_preprocessing/.ipynb_checkpoints/extract_features-checkpoint.ipynb
ADDED
|
@@ -0,0 +1,437 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cells": [
|
| 3 |
+
{
|
| 4 |
+
"cell_type": "code",
|
| 5 |
+
"execution_count": 1,
|
| 6 |
+
"id": "5082cdc1-b052-433d-b018-29ba6fa3d313",
|
| 7 |
+
"metadata": {},
|
| 8 |
+
"outputs": [],
|
| 9 |
+
"source": [
|
| 10 |
+
"# %% [Block 1]\n",
|
| 11 |
+
"from glob import glob\n",
|
| 12 |
+
"from tqdm.auto import tqdm\n",
|
| 13 |
+
"import os\n",
|
| 14 |
+
"from PIL import Image\n",
|
| 15 |
+
"import numpy as np\n",
|
| 16 |
+
"import torch\n",
|
| 17 |
+
"from scipy.io import savemat\n",
|
| 18 |
+
"from bdpy.dl.torch import FeatureExtractor\n",
|
| 19 |
+
"from torchvision import models, transforms\n",
|
| 20 |
+
"import yaml\n",
|
| 21 |
+
"import h5py"
|
| 22 |
+
]
|
| 23 |
+
},
|
| 24 |
+
{
|
| 25 |
+
"cell_type": "code",
|
| 26 |
+
"execution_count": 2,
|
| 27 |
+
"id": "a31be173-61ff-4adf-a558-63a3efe74cff",
|
| 28 |
+
"metadata": {},
|
| 29 |
+
"outputs": [],
|
| 30 |
+
"source": [
|
| 31 |
+
"# %% [Block 2]\n",
|
| 32 |
+
"# Custom transform class to convert RGB to BGR\n",
|
| 33 |
+
"class ConvertRGBtoBGR:\n",
|
| 34 |
+
" def __call__(self, image):\n",
|
| 35 |
+
" return image[[2, 1, 0], :, :] \n",
|
| 36 |
+
" \n",
|
| 37 |
+
"# Custom transform class to convert Image format to tensor while keeping pixel ranges\n",
|
| 38 |
+
"class ToTensorWithoutScaling:\n",
|
| 39 |
+
" def __call__(self, image):\n",
|
| 40 |
+
" image = np.array(image).astype(np.float32) # Convert PIL Image to NumPy array\n",
|
| 41 |
+
" tensor = torch.from_numpy(image).permute(2, 0, 1).float() # Convert NumPy array to tensor and rearrange dimensions\n",
|
| 42 |
+
" return tensor\n",
|
| 43 |
+
" \n",
|
| 44 |
+
"class Convert32to16:\n",
|
| 45 |
+
" def __call__(self, image):\n",
|
| 46 |
+
" return image.type(torch.float16)\n"
|
| 47 |
+
]
|
| 48 |
+
},
|
| 49 |
+
{
|
| 50 |
+
"cell_type": "code",
|
| 51 |
+
"execution_count": 34,
|
| 52 |
+
"id": "969abfe4-e4b6-4fa2-bd09-17f77ddf2292",
|
| 53 |
+
"metadata": {},
|
| 54 |
+
"outputs": [],
|
| 55 |
+
"source": [
|
| 56 |
+
"# %% [Block 3]\n",
|
| 57 |
+
"def load_model(network):\n",
|
| 58 |
+
" \n",
|
| 59 |
+
" if network == \"VGG19_ILSVRC_19_layers\":\n",
|
| 60 |
+
" from bdpy.dl.torch.models import layer_map, model_factory\n",
|
| 61 |
+
" model = model_factory('vgg19')\n",
|
| 62 |
+
" encoder_param_file = '/weka/proj-fmri/ckadirt/spurious_reconstruction/analysis/VGG_ILSVRC_19_layers/VGG_ILSVRC_19_layers.pt'\n",
|
| 63 |
+
" model.load_state_dict(torch.load(encoder_param_file))\n",
|
| 64 |
+
" model.eval()\n",
|
| 65 |
+
" layer_mapping = layer_map('vgg19')\n",
|
| 66 |
+
" mean_image = [104., 117., 123.] # BGR\n",
|
| 67 |
+
" preprocess = transforms.Compose([\n",
|
| 68 |
+
" transforms.Resize((224, 224), interpolation=Image.BICUBIC),\n",
|
| 69 |
+
" # ToTensorWithoutScaling(), # Custom transform added\n",
|
| 70 |
+
" # ConvertRGBtoBGR(), # Custom transform added\n",
|
| 71 |
+
" transforms.Normalize(mean=mean_image, std=[1.,1.,1.]),\n",
|
| 72 |
+
" ])\n",
|
| 73 |
+
" def preprocess_and_check(img):\n",
|
| 74 |
+
" print(\"Original shape:\", img.shape)\n",
|
| 75 |
+
" img = transforms.Resize((224, 224), interpolation=Image.BICUBIC)(img)\n",
|
| 76 |
+
" print(\"After ToTensor:\", img.shape)\n",
|
| 77 |
+
" print(\"After Resize:\", img.shape)\n",
|
| 78 |
+
" img = transforms.Normalize(mean=mean_image, std=[1.,1.,1.])(img)\n",
|
| 79 |
+
" return img\n",
|
| 80 |
+
" \n",
|
| 81 |
+
" elif network == \"vgg19_torchvision\":\n",
|
| 82 |
+
" model = models.vgg19(pretrained=True)\n",
|
| 83 |
+
" model.eval()\n",
|
| 84 |
+
" \n",
|
| 85 |
+
" preprocess = transforms.Compose([\n",
|
| 86 |
+
" transforms.Resize((224, 224)), \n",
|
| 87 |
+
" transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),\n",
|
| 88 |
+
" ]) \n",
|
| 89 |
+
" def preprocess_and_check(img):\n",
|
| 90 |
+
" print(\"Original shape:\", img.shape)\n",
|
| 91 |
+
" img = transforms.ToTensor()(img)\n",
|
| 92 |
+
" print(\"After ToTensor:\", img.shape)\n",
|
| 93 |
+
" img = transforms.Resize(224)(img)\n",
|
| 94 |
+
" print(\"After Resize:\", img.shape)\n",
|
| 95 |
+
" img = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])(img)\n",
|
| 96 |
+
" return img\n",
|
| 97 |
+
" else:\n",
|
| 98 |
+
" raise ValueError(\"Network not supported. Please choose from: VGG19_ILSVRC_19_layers\"\n",
|
| 99 |
+
" +\"or define by yourself. The output should be model and preprocessing functions from RGB image to model input.\")\n",
|
| 100 |
+
" \n",
|
| 101 |
+
" return model, preprocess\n"
|
| 102 |
+
]
|
| 103 |
+
},
|
| 104 |
+
{
|
| 105 |
+
"cell_type": "code",
|
| 106 |
+
"execution_count": 35,
|
| 107 |
+
"id": "8020d232-72cd-42ed-bb8e-183c8c0ee9b6",
|
| 108 |
+
"metadata": {},
|
| 109 |
+
"outputs": [],
|
| 110 |
+
"source": [
|
| 111 |
+
"# %% [Block 4]\n",
|
| 112 |
+
"def load_config(config_path):\n",
|
| 113 |
+
" '''Load configuration file.'''\n",
|
| 114 |
+
" with open(config_path, 'r') as file:\n",
|
| 115 |
+
" config = yaml.safe_load(file)\n",
|
| 116 |
+
" return config\n"
|
| 117 |
+
]
|
| 118 |
+
},
|
| 119 |
+
{
|
| 120 |
+
"cell_type": "code",
|
| 121 |
+
"execution_count": 36,
|
| 122 |
+
"id": "a766c128-7e43-419c-9d7e-6f317e44753e",
|
| 123 |
+
"metadata": {},
|
| 124 |
+
"outputs": [
|
| 125 |
+
{
|
| 126 |
+
"name": "stdout",
|
| 127 |
+
"output_type": "stream",
|
| 128 |
+
"text": [
|
| 129 |
+
"/weka/proj-medarc/shared/mindeyev2_dataset//wds/subj01/train/{0..39}.tar\n",
|
| 130 |
+
"/weka/proj-medarc/shared/mindeyev2_dataset//wds/subj01/new_test/0.tar\n",
|
| 131 |
+
"Loaded test dl for subj1!\n",
|
| 132 |
+
"\n"
|
| 133 |
+
]
|
| 134 |
+
},
|
| 135 |
+
{
|
| 136 |
+
"data": {
|
| 137 |
+
"application/vnd.jupyter.widget-view+json": {
|
| 138 |
+
"model_id": "65cb44139d1e4cf788e5a8956d9c1eb1",
|
| 139 |
+
"version_major": 2,
|
| 140 |
+
"version_minor": 0
|
| 141 |
+
},
|
| 142 |
+
"text/plain": [
|
| 143 |
+
"0it [00:00, ?it/s]"
|
| 144 |
+
]
|
| 145 |
+
},
|
| 146 |
+
"metadata": {},
|
| 147 |
+
"output_type": "display_data"
|
| 148 |
+
},
|
| 149 |
+
{
|
| 150 |
+
"data": {
|
| 151 |
+
"application/vnd.jupyter.widget-view+json": {
|
| 152 |
+
"model_id": "981c8b8963d84fbf9994421e1e8ce02b",
|
| 153 |
+
"version_major": 2,
|
| 154 |
+
"version_minor": 0
|
| 155 |
+
},
|
| 156 |
+
"text/plain": [
|
| 157 |
+
"0it [00:00, ?it/s]"
|
| 158 |
+
]
|
| 159 |
+
},
|
| 160 |
+
"metadata": {},
|
| 161 |
+
"output_type": "display_data"
|
| 162 |
+
}
|
| 163 |
+
],
|
| 164 |
+
"source": [
|
| 165 |
+
"import webdataset as wds\n",
|
| 166 |
+
"import random\n",
|
| 167 |
+
"\n",
|
| 168 |
+
"def my_split_by_node(urls): return urls\n",
|
| 169 |
+
"data_path = '/weka/proj-medarc/shared/mindeyev2_dataset/'\n",
|
| 170 |
+
"subj_list = [1]\n",
|
| 171 |
+
"num_sessions = 40\n",
|
| 172 |
+
"multi_subject = False\n",
|
| 173 |
+
"batch_size = 1\n",
|
| 174 |
+
"data_type = torch.float16\n",
|
| 175 |
+
"subj = 1\n",
|
| 176 |
+
"\n",
|
| 177 |
+
"train_data = {}\n",
|
| 178 |
+
"train_dl = {}\n",
|
| 179 |
+
"num_voxels = {}\n",
|
| 180 |
+
"voxels = {}\n",
|
| 181 |
+
"\n",
|
| 182 |
+
"train_url = f\"{data_path}/wds/subj0{subj}/train/\" + \"{0..\" + f\"{num_sessions-1}\" + \"}.tar\"\n",
|
| 183 |
+
"print(train_url)\n",
|
| 184 |
+
"\n",
|
| 185 |
+
"train_data = wds.WebDataset(train_url,resampled=False,nodesplitter=my_split_by_node)\\\n",
|
| 186 |
+
" .decode(\"torch\")\\\n",
|
| 187 |
+
" .rename(behav=\"behav.npy\", past_behav=\"past_behav.npy\", future_behav=\"future_behav.npy\", olds_behav=\"olds_behav.npy\")\\\n",
|
| 188 |
+
" .to_tuple(*[\"behav\", \"past_behav\", \"future_behav\", \"olds_behav\"])\n",
|
| 189 |
+
"train_dl = torch.utils.data.DataLoader(train_data, batch_size=batch_size, shuffle=False, drop_last=False, pin_memory=True)\n",
|
| 190 |
+
"\n",
|
| 191 |
+
"# f = h5py.File(f'{data_path}/betas_all_subj0{s}_fp32_renorm.hdf5', 'r')\n",
|
| 192 |
+
"# betas = f['betas'][:]\n",
|
| 193 |
+
"# betas = torch.Tensor(betas).to(\"cpu\").to(data_type)\n",
|
| 194 |
+
"# num_voxels_list.append(betas[0].shape[-1])\n",
|
| 195 |
+
"# num_voxels[f'subj0{s}'] = betas[0].shape[-1]\n",
|
| 196 |
+
"# voxels[f'subj0{s}'] = betas\n",
|
| 197 |
+
"# print(f\"num_voxels for subj0{s}: {num_voxels[f'subj0{s}']}\")\n",
|
| 198 |
+
"\n",
|
| 199 |
+
"\n",
|
| 200 |
+
"num_test=3000\n",
|
| 201 |
+
"test_url = f\"{data_path}/wds/subj0{subj}/new_test/\" + \"0.tar\"\n",
|
| 202 |
+
"print(test_url)\n",
|
| 203 |
+
"test_data = wds.WebDataset(test_url,resampled=False,nodesplitter=my_split_by_node)\\\n",
|
| 204 |
+
" .decode(\"torch\")\\\n",
|
| 205 |
+
" .rename(behav=\"behav.npy\", past_behav=\"past_behav.npy\", future_behav=\"future_behav.npy\", olds_behav=\"olds_behav.npy\")\\\n",
|
| 206 |
+
" .to_tuple(*[\"behav\", \"past_behav\", \"future_behav\", \"olds_behav\"])\n",
|
| 207 |
+
"test_dl = torch.utils.data.DataLoader(test_data, batch_size=1, shuffle=False, drop_last=True, pin_memory=True)\n",
|
| 208 |
+
"print(f\"Loaded test dl for subj{subj}!\\n\")\n",
|
| 209 |
+
"\n",
|
| 210 |
+
"all_indexes_train = []\n",
|
| 211 |
+
"\n",
|
| 212 |
+
"for behav0, past_behav0, future_behav0, old_behav0 in tqdm(train_dl):\n",
|
| 213 |
+
" img_idx = behav0[:,0,0].cpu().long().numpy()[0]\n",
|
| 214 |
+
" all_indexes_train.append(img_idx)\n",
|
| 215 |
+
"\n",
|
| 216 |
+
"all_indexes_test = []\n",
|
| 217 |
+
"\n",
|
| 218 |
+
"for behav0, past_behav0, future_behav0, old_behav0 in tqdm(test_dl):\n",
|
| 219 |
+
" img_idx = behav0[:,0,0].cpu().long().numpy()[0]\n",
|
| 220 |
+
" all_indexes_test.append(img_idx)"
|
| 221 |
+
]
|
| 222 |
+
},
|
| 223 |
+
{
|
| 224 |
+
"cell_type": "code",
|
| 225 |
+
"execution_count": 37,
|
| 226 |
+
"id": "17a4377a-67dc-49fc-b89c-7d641ef218ce",
|
| 227 |
+
"metadata": {},
|
| 228 |
+
"outputs": [],
|
| 229 |
+
"source": [
|
| 230 |
+
"def extract_features(config, device='cuda'):\n",
|
| 231 |
+
" '''Extract features based on the configuration.'''\n",
|
| 232 |
+
" print(\"Extracting features using network:\", config['network'])\n",
|
| 233 |
+
" \n",
|
| 234 |
+
" f = h5py.File(f'{config[\"image path\"]}/coco_images_224_float16.hdf5', 'r')\n",
|
| 235 |
+
" images = f['images']\n",
|
| 236 |
+
" print(images.shape)\n",
|
| 237 |
+
" model, preprocess = load_model(config['network'])\n",
|
| 238 |
+
" layers = config[\"features\"]\n",
|
| 239 |
+
" feature_extractor = FeatureExtractor(model, layers, device=device, detach=True)\n",
|
| 240 |
+
" \n",
|
| 241 |
+
" output_dir = os.path.join(config[\"output base dir\"], \"pytorch\", config['network'])\n",
|
| 242 |
+
"\n",
|
| 243 |
+
" all_indexes_to_compute = set(all_indexes_train + list(set(all_indexes_test)))\n",
|
| 244 |
+
" \n",
|
| 245 |
+
" # First, ensure all layer directories exist\n",
|
| 246 |
+
" # for layer in layers:\n",
|
| 247 |
+
" # layer_output_dir = os.path.join(output_dir, layer)\n",
|
| 248 |
+
" # os.makedirs(layer_output_dir, exist_ok=True)\n",
|
| 249 |
+
" # img = torch.Tensor(images[0])\n",
|
| 250 |
+
"\n",
|
| 251 |
+
" # x = preprocess(img).unsqueeze(0).to(device)\n",
|
| 252 |
+
" # # Extract features\n",
|
| 253 |
+
" # features = feature_extractor.run(x)\n",
|
| 254 |
+
" \n",
|
| 255 |
+
" # # Get the feature for the current layer\n",
|
| 256 |
+
" # f = features.get(layer)\n",
|
| 257 |
+
" # print(f.shape)\n",
|
| 258 |
+
" \n",
|
| 259 |
+
"\n",
|
| 260 |
+
" \n",
|
| 261 |
+
" for layer in tqdm(layers, desc=\"Processing layers\"): # Iterate over each layer first\n",
|
| 262 |
+
" layer_output_dir = os.path.join(output_dir, layer)\n",
|
| 263 |
+
"\n",
|
| 264 |
+
" with h5py.File(f'{layer_output_dir}/{subj}.h5', 'a') as hdf5_file:\n",
|
| 265 |
+
"\n",
|
| 266 |
+
" # initial_shape = (0, 100) # Start with 0 rows and 100 columns (or your array shape)\n",
|
| 267 |
+
" # max_shape = (None, 100) # Allow unlimited rows\n",
|
| 268 |
+
" \n",
|
| 269 |
+
" # if 'dataset' not in hdf5_file:\n",
|
| 270 |
+
" # dataset = hdf5_file.create_dataset(\n",
|
| 271 |
+
" # 'dataset', \n",
|
| 272 |
+
" # shape=initial_shape, \n",
|
| 273 |
+
" # maxshape=max_shape, \n",
|
| 274 |
+
" # dtype='float64'\n",
|
| 275 |
+
" # )\n",
|
| 276 |
+
" # else:\n",
|
| 277 |
+
" # dataset = hdf5_file['dataset']\n",
|
| 278 |
+
" for i, image_index in tqdm(enumerate(all_indexes_to_compute), total = len(all_indexes_to_compute)):\n",
|
| 279 |
+
" output_file = os.path.join(layer_output_dir, f\"{image_index}.npy\")\n",
|
| 280 |
+
" \n",
|
| 281 |
+
" if os.path.exists(output_file):\n",
|
| 282 |
+
" continue # Skip if the feature for this image and layer already exists\n",
|
| 283 |
+
" \n",
|
| 284 |
+
" # Load and preprocess the image\n",
|
| 285 |
+
" img = torch.Tensor(images[image_index])\n",
|
| 286 |
+
" x = preprocess(img).unsqueeze(0).to(device)\n",
|
| 287 |
+
" \n",
|
| 288 |
+
" # Extract features\n",
|
| 289 |
+
" features = feature_extractor.run(x)\n",
|
| 290 |
+
" \n",
|
| 291 |
+
" # Get the feature for the current layer\n",
|
| 292 |
+
" f = features.get(layer)\n",
|
| 293 |
+
" if f is None:\n",
|
| 294 |
+
" print(f\"Warning: Layer '{layer}' not found in the extracted features.\")\n",
|
| 295 |
+
" continue\n",
|
| 296 |
+
"\n",
|
| 297 |
+
" if i == 0:\n",
|
| 298 |
+
" initial_shape = f.shape\n",
|
| 299 |
+
" max_shape = (None,) + initial_shape[1:]\n",
|
| 300 |
+
"\n",
|
| 301 |
+
" if 'dataset' not in hdf5_file:\n",
|
| 302 |
+
" dataset = hdf5_file.create_dataset(\n",
|
| 303 |
+
" 'dataset', \n",
|
| 304 |
+
" shape=initial_shape, \n",
|
| 305 |
+
" maxshape=max_shape, \n",
|
| 306 |
+
" dtype='float16'\n",
|
| 307 |
+
" )\n",
|
| 308 |
+
" else:\n",
|
| 309 |
+
" dataset = hdf5_file['dataset']\n",
|
| 310 |
+
"\n",
|
| 311 |
+
" dataset.resize(dataset.shape[0] + f.shape[0], axis=0)\n",
|
| 312 |
+
" \n",
|
| 313 |
+
" # Append the data\n",
|
| 314 |
+
" dataset[-f.shape[0]:] = f.astype(np.float16)\n",
|
| 315 |
+
" \n",
|
| 316 |
+
" # # Save the feature\n",
|
| 317 |
+
" # np.save(output_file, f.astype(np.float16))\n",
|
| 318 |
+
" \n",
|
| 319 |
+
" # Optional: Break early for testing\n",
|
| 320 |
+
" # if layer == some_condition:\n",
|
| 321 |
+
" # break\n",
|
| 322 |
+
"\n",
|
| 323 |
+
" print('All done')"
|
| 324 |
+
]
|
| 325 |
+
},
|
| 326 |
+
{
|
| 327 |
+
"cell_type": "code",
|
| 328 |
+
"execution_count": 38,
|
| 329 |
+
"id": "5dc66f30-9406-4e7a-adca-81161df3611a",
|
| 330 |
+
"metadata": {},
|
| 331 |
+
"outputs": [
|
| 332 |
+
{
|
| 333 |
+
"name": "stdout",
|
| 334 |
+
"output_type": "stream",
|
| 335 |
+
"text": [
|
| 336 |
+
"Extracting features using network: VGG19_ILSVRC_19_layers\n",
|
| 337 |
+
"(73000, 3, 224, 224)\n",
|
| 338 |
+
"(1, 64, 224, 224)\n",
|
| 339 |
+
"(1, 64, 224, 224)\n",
|
| 340 |
+
"(1, 128, 112, 112)\n",
|
| 341 |
+
"(1, 128, 112, 112)\n",
|
| 342 |
+
"(1, 256, 56, 56)\n",
|
| 343 |
+
"(1, 256, 56, 56)\n",
|
| 344 |
+
"(1, 256, 56, 56)\n",
|
| 345 |
+
"(1, 256, 56, 56)\n",
|
| 346 |
+
"(1, 512, 28, 28)\n",
|
| 347 |
+
"(1, 512, 28, 28)\n",
|
| 348 |
+
"(1, 512, 28, 28)\n",
|
| 349 |
+
"(1, 512, 28, 28)\n",
|
| 350 |
+
"(1, 512, 14, 14)\n",
|
| 351 |
+
"(1, 512, 14, 14)\n",
|
| 352 |
+
"(1, 512, 14, 14)\n",
|
| 353 |
+
"(1, 512, 14, 14)\n",
|
| 354 |
+
"(1, 4096)\n",
|
| 355 |
+
"(1, 4096)\n",
|
| 356 |
+
"(1, 1000)\n"
|
| 357 |
+
]
|
| 358 |
+
},
|
| 359 |
+
{
|
| 360 |
+
"ename": "NameError",
|
| 361 |
+
"evalue": "name 'ththth' is not defined",
|
| 362 |
+
"output_type": "error",
|
| 363 |
+
"traceback": [
|
| 364 |
+
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
| 365 |
+
"\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
|
| 366 |
+
"Cell \u001b[0;32mIn[38], line 8\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[38;5;66;03m# %%\u001b[39;00m\n\u001b[1;32m 6\u001b[0m \u001b[38;5;66;03m# Load config and extract features\u001b[39;00m\n\u001b[1;32m 7\u001b[0m config \u001b[38;5;241m=\u001b[39m load_config(config_path)\n\u001b[0;32m----> 8\u001b[0m \u001b[43mextract_features\u001b[49m\u001b[43m(\u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m)\u001b[49m\n",
|
| 367 |
+
"Cell \u001b[0;32mIn[37], line 31\u001b[0m, in \u001b[0;36mextract_features\u001b[0;34m(config, device)\u001b[0m\n\u001b[1;32m 27\u001b[0m f \u001b[38;5;241m=\u001b[39m features\u001b[38;5;241m.\u001b[39mget(layer)\n\u001b[1;32m 28\u001b[0m \u001b[38;5;28mprint\u001b[39m(f\u001b[38;5;241m.\u001b[39mshape)\n\u001b[0;32m---> 31\u001b[0m \u001b[43mththth\u001b[49m\n\u001b[1;32m 32\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m layer \u001b[38;5;129;01min\u001b[39;00m tqdm(layers, desc\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mProcessing layers\u001b[39m\u001b[38;5;124m\"\u001b[39m): \u001b[38;5;66;03m# Iterate over each layer first\u001b[39;00m\n\u001b[1;32m 33\u001b[0m layer_output_dir \u001b[38;5;241m=\u001b[39m os\u001b[38;5;241m.\u001b[39mpath\u001b[38;5;241m.\u001b[39mjoin(output_dir, layer)\n",
|
| 368 |
+
"\u001b[0;31mNameError\u001b[0m: name 'ththth' is not defined"
|
| 369 |
+
]
|
| 370 |
+
}
|
| 371 |
+
],
|
| 372 |
+
"source": [
|
| 373 |
+
"# %% [Block 6]\n",
|
| 374 |
+
"# Instead of using argparse, manually provide the config file path for a notebook\n",
|
| 375 |
+
"config_path = '/weka/proj-fmri/ckadirt/spurious_reconstruction/analysis/0_preprocessing/config/NSD/NSD.yaml' # Replace with your config file path\n",
|
| 376 |
+
"\n",
|
| 377 |
+
"# %%\n",
|
| 378 |
+
"# Load config and extract features\n",
|
| 379 |
+
"config = load_config(config_path)\n",
|
| 380 |
+
"extract_features(config)\n"
|
| 381 |
+
]
|
| 382 |
+
},
|
| 383 |
+
{
|
| 384 |
+
"cell_type": "code",
|
| 385 |
+
"execution_count": null,
|
| 386 |
+
"id": "35e4f307-1652-4af7-ad82-3ee4c3f142fd",
|
| 387 |
+
"metadata": {},
|
| 388 |
+
"outputs": [],
|
| 389 |
+
"source": []
|
| 390 |
+
},
|
| 391 |
+
{
|
| 392 |
+
"cell_type": "code",
|
| 393 |
+
"execution_count": 8,
|
| 394 |
+
"id": "2d6c4809-0aab-4257-8994-4e892e23de9f",
|
| 395 |
+
"metadata": {},
|
| 396 |
+
"outputs": [],
|
| 397 |
+
"source": [
|
| 398 |
+
"# with h5py.File(f'/weka/proj-fmri/ckadirt/spurious_reconstruction/analysis/0_preprocessing/features/pytorch/vgg19_torchvision/features[0]/1.h5', 'a') as hdf5_file:\n",
|
| 399 |
+
"# dataset = hdf5_file['dataset']\n",
|
| 400 |
+
"# print(len(dataset))\n",
|
| 401 |
+
"# print(dataset[10].shape, dataset[10].dtype)\n",
|
| 402 |
+
"# print(dataset.shape)"
|
| 403 |
+
]
|
| 404 |
+
},
|
| 405 |
+
{
|
| 406 |
+
"cell_type": "code",
|
| 407 |
+
"execution_count": 9,
|
| 408 |
+
"id": "fcf6d112-e24c-4fd5-ac59-f21e3611ebbc",
|
| 409 |
+
"metadata": {},
|
| 410 |
+
"outputs": [],
|
| 411 |
+
"source": [
|
| 412 |
+
"# dataset"
|
| 413 |
+
]
|
| 414 |
+
}
|
| 415 |
+
],
|
| 416 |
+
"metadata": {
|
| 417 |
+
"kernelspec": {
|
| 418 |
+
"display_name": "mindeye",
|
| 419 |
+
"language": "python",
|
| 420 |
+
"name": "mindeye"
|
| 421 |
+
},
|
| 422 |
+
"language_info": {
|
| 423 |
+
"codemirror_mode": {
|
| 424 |
+
"name": "ipython",
|
| 425 |
+
"version": 3
|
| 426 |
+
},
|
| 427 |
+
"file_extension": ".py",
|
| 428 |
+
"mimetype": "text/x-python",
|
| 429 |
+
"name": "python",
|
| 430 |
+
"nbconvert_exporter": "python",
|
| 431 |
+
"pygments_lexer": "ipython3",
|
| 432 |
+
"version": "3.11.10"
|
| 433 |
+
}
|
| 434 |
+
},
|
| 435 |
+
"nbformat": 4,
|
| 436 |
+
"nbformat_minor": 5
|
| 437 |
+
}
|
spurious_reconstruction/analysis/0_preprocessing/.ipynb_checkpoints/iCNN_image_vgg19_feature_extraction-checkpoint.py
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'''DNN Feature extraction script'''
|
| 2 |
+
|
| 3 |
+
# %%%
|
| 4 |
+
from glob import glob
|
| 5 |
+
from tqdm import tqdm
|
| 6 |
+
import os
|
| 7 |
+
import argparse
|
| 8 |
+
from PIL import Image
|
| 9 |
+
import numpy as np
|
| 10 |
+
import torch
|
| 11 |
+
from scipy.io import savemat
|
| 12 |
+
from bdpy.dl.torch import FeatureExtractor
|
| 13 |
+
from torchvision import models, transforms
|
| 14 |
+
import yaml
|
| 15 |
+
# %%%
|
| 16 |
+
# Custum transform class to convert RGB to BGR
|
| 17 |
+
class ConvertRGBtoBGR:
|
| 18 |
+
def __call__(self, image):
|
| 19 |
+
return image[[2, 1, 0], :, :]
|
| 20 |
+
|
| 21 |
+
# Custum transform class to convert Image format to tensor while keeping pixel ranges
|
| 22 |
+
class ToTensorWithoutScaling:
|
| 23 |
+
def __call__(self, image):
|
| 24 |
+
image = np.array(image).astype(np.float32) # PIL ImageをNumPy配列に変換
|
| 25 |
+
tensor = torch.from_numpy(image).permute(2, 0, 1).float() # NumPy配列をテンソルに変換し、次元を並べ替える
|
| 26 |
+
return tensor
|
| 27 |
+
|
| 28 |
+
class Convert32to16:
|
| 29 |
+
def __call__(self, image):
|
| 30 |
+
return image.type(torch.float16)
|
| 31 |
+
|
| 32 |
+
# %%%
|
| 33 |
+
def load_model(network):
|
| 34 |
+
|
| 35 |
+
if network == "VGG19_ILSVRC_19_layers":
|
| 36 |
+
from bdpy.dl.torch.models import layer_map, model_factory
|
| 37 |
+
model = model_factory('vgg19')
|
| 38 |
+
encoder_param_file = './data/models_shared/pytorch/VGG_ILSVRC_19_layers/VGG_ILSVRC_19_layers.pt'
|
| 39 |
+
model.load_state_dict(torch.load(encoder_param_file))
|
| 40 |
+
model.eval()
|
| 41 |
+
layer_mapping = layer_map('vgg19')
|
| 42 |
+
# change RGB-> BGR and subtract mean via lambda function
|
| 43 |
+
mean_image = [104., 117., 123.] #BGR!
|
| 44 |
+
#mean_image = [103.939, 116.779, 123.68] #BGR!
|
| 45 |
+
preprocess = transforms.Compose([
|
| 46 |
+
transforms.Resize(224, interpolation=Image.BICUBIC),
|
| 47 |
+
#transforms.CenterCrop(224),
|
| 48 |
+
#transforms.ToTensor(),
|
| 49 |
+
ToTensorWithoutScaling(), # カスタム変換を追加
|
| 50 |
+
ConvertRGBtoBGR(), # カスタム変換を追加
|
| 51 |
+
transforms.Normalize(mean=mean_image, std=[1.,1.,1.]),
|
| 52 |
+
])
|
| 53 |
+
|
| 54 |
+
elif network == "vgg19_torchvision":
|
| 55 |
+
model = models.vgg19(pretrained=True)
|
| 56 |
+
model.eval()
|
| 57 |
+
|
| 58 |
+
# 画像の前処理
|
| 59 |
+
preprocess = transforms.Compose([
|
| 60 |
+
transforms.Resize(224),#transforms.Resize(256),
|
| 61 |
+
#transforms.CenterCrop(224),
|
| 62 |
+
transforms.ToTensor(),
|
| 63 |
+
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
|
| 64 |
+
])
|
| 65 |
+
else:
|
| 66 |
+
raise ValueError("Network not supported. Please choose from: VGG19_ILSVRC_19_layers"
|
| 67 |
+
+"or define by yourself. The output should be model and preprocessing functions from RGB image to model input."
|
| 68 |
+
)
|
| 69 |
+
|
| 70 |
+
return model, preprocess
|
| 71 |
+
|
| 72 |
+
def load_config(config_path):
|
| 73 |
+
'''Load configuration file.'''
|
| 74 |
+
with open(config_path, 'r') as file:
|
| 75 |
+
config = yaml.safe_load(file)
|
| 76 |
+
return config
|
| 77 |
+
|
| 78 |
+
def extract_features(config, device='cuda'):
|
| 79 |
+
'''Extract features based on the configuration.'''
|
| 80 |
+
print("Extracting features using network:", config['network'])
|
| 81 |
+
|
| 82 |
+
image_dir = config['image path']
|
| 83 |
+
image_ext = config["image_ext"]
|
| 84 |
+
image_files = glob(os.path.join(image_dir, '*.' + image_ext))
|
| 85 |
+
|
| 86 |
+
model, preprocess = load_model(config['network'])
|
| 87 |
+
layers = config["features"]
|
| 88 |
+
feature_extractor = FeatureExtractor(model, layers, device=device, detach=True)
|
| 89 |
+
|
| 90 |
+
output_dir = os.path.join(config["output base dir"], "pytorch",config['network'])
|
| 91 |
+
|
| 92 |
+
for image_file in tqdm(image_files):
|
| 93 |
+
img = Image.open(image_file).convert('RGB')
|
| 94 |
+
|
| 95 |
+
x = preprocess(img).unsqueeze(0).to(device)
|
| 96 |
+
|
| 97 |
+
# Extract features
|
| 98 |
+
features = feature_extractor.run(x)
|
| 99 |
+
|
| 100 |
+
# Save features
|
| 101 |
+
for layer in features.keys():
|
| 102 |
+
f = features[layer]
|
| 103 |
+
|
| 104 |
+
output_file = os.path.join(
|
| 105 |
+
output_dir,
|
| 106 |
+
layer,
|
| 107 |
+
os.path.splitext(os.path.basename(image_file))[0] + '.mat'
|
| 108 |
+
)
|
| 109 |
+
|
| 110 |
+
if os.path.exists(output_file):
|
| 111 |
+
continue
|
| 112 |
+
|
| 113 |
+
os.makedirs(os.path.join(output_dir, layer), exist_ok=True)
|
| 114 |
+
|
| 115 |
+
savemat(output_file, {'feat': f})
|
| 116 |
+
#print('Saved {}'.format(output_file))
|
| 117 |
+
|
| 118 |
+
print('All done')
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
|
| 122 |
+
# %%%
|
| 123 |
+
if __name__ == '__main__':
|
| 124 |
+
parser = argparse.ArgumentParser(description='DNN Feature extraction')
|
| 125 |
+
parser.add_argument('config', help='Configuration file')
|
| 126 |
+
args = parser.parse_args()
|
| 127 |
+
|
| 128 |
+
config = load_config(args.config)
|
| 129 |
+
extract_features(config)
|
| 130 |
+
# %%
|
spurious_reconstruction/analysis/0_preprocessing/BD_extract_CLIP_vision_features.py
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
## Code is based on https://github.com/ozcelikfu/brain-diffuser/blob/main/scripts/clipvision_extract_features.py
|
| 2 |
+
|
| 3 |
+
# %%
|
| 4 |
+
import sys
|
| 5 |
+
# %%
|
| 6 |
+
sys.path.append('brain-diffuser/versatile_diffusion')
|
| 7 |
+
import os
|
| 8 |
+
import PIL
|
| 9 |
+
from PIL import Image
|
| 10 |
+
import numpy as np
|
| 11 |
+
|
| 12 |
+
import torch
|
| 13 |
+
from lib.cfg_helper import model_cfg_bank
|
| 14 |
+
from lib.model_zoo import get_model
|
| 15 |
+
#from lib.experiments.sd_default import color_adjust, auto_merge_imlist
|
| 16 |
+
from torch.utils.data import DataLoader, Dataset
|
| 17 |
+
|
| 18 |
+
from lib.model_zoo.vd import VD
|
| 19 |
+
from lib.cfg_holder import cfg_unique_holder as cfguh
|
| 20 |
+
from lib.cfg_helper import get_command_line_args, cfg_initiates, load_cfg_yaml
|
| 21 |
+
import torchvision.transforms as T
|
| 22 |
+
import yaml
|
| 23 |
+
from easydict import EasyDict as edict
|
| 24 |
+
import argparse
|
| 25 |
+
import os.path as osp
|
| 26 |
+
|
| 27 |
+
from scipy.io import savemat
|
| 28 |
+
# %%
|
| 29 |
+
# %%
|
| 30 |
+
class batch_generator_external_image_files(Dataset):
|
| 31 |
+
|
| 32 |
+
def __init__(self, data_path):
|
| 33 |
+
self.data_path = data_path
|
| 34 |
+
self.im = sorted(os.listdir(self.data_path))
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def __getitem__(self,idx):
|
| 38 |
+
img = Image.open(os.path.join(self.data_path,self.im[idx])).convert('RGB')
|
| 39 |
+
img = T.functional.resize(img,(512,512))
|
| 40 |
+
img = torch.tensor(np.array(img)).float()
|
| 41 |
+
#img = img/255
|
| 42 |
+
img = img*2 - 1
|
| 43 |
+
return img.permute(2,0, 1), self.im[idx]
|
| 44 |
+
|
| 45 |
+
def __len__(self):
|
| 46 |
+
return len(self.im)
|
| 47 |
+
|
| 48 |
+
def load_config(config_path):
|
| 49 |
+
'''Load configuration file.'''
|
| 50 |
+
with open(config_path, 'r') as file:
|
| 51 |
+
config = yaml.safe_load(file)
|
| 52 |
+
return config
|
| 53 |
+
|
| 54 |
+
def extract_CLIP_vision_features(config):
|
| 55 |
+
batch_size=1
|
| 56 |
+
# %%
|
| 57 |
+
cfgm_name = 'vd_noema'
|
| 58 |
+
cfgm = model_cfg_bank()(cfgm_name)
|
| 59 |
+
net = get_model()(cfgm)
|
| 60 |
+
# %%
|
| 61 |
+
pth = 'versatile_diffusion/pretrained/vd-four-flow-v1-0-fp16-deprecated.pth'
|
| 62 |
+
sd = torch.load(pth, map_location='cpu')
|
| 63 |
+
net.load_state_dict(sd, strict=False)
|
| 64 |
+
# %%
|
| 65 |
+
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
|
| 66 |
+
net.clip = net.clip.to(device)
|
| 67 |
+
# %%
|
| 68 |
+
|
| 69 |
+
data_path = config['image path']
|
| 70 |
+
# %%
|
| 71 |
+
image_data = batch_generator_external_image_files(data_path)
|
| 72 |
+
data_loader = DataLoader(image_data,batch_size,shuffle=False)
|
| 73 |
+
# %%
|
| 74 |
+
num_embed, num_features, num_image = 257, 768, image_data.__len__()
|
| 75 |
+
|
| 76 |
+
clip_feat = np.zeros((num_image,num_embed,num_features))
|
| 77 |
+
# %%
|
| 78 |
+
output_dir = os.path.join(config["output base dir"], "pytorch", 'brain_diffuser_versatile_diffusion')
|
| 79 |
+
# %%
|
| 80 |
+
layer = 'vision_encoder'
|
| 81 |
+
# %%
|
| 82 |
+
with torch.no_grad():
|
| 83 |
+
# %%
|
| 84 |
+
for i,(imgs_torch_tensor, image_files) in enumerate(data_loader):
|
| 85 |
+
|
| 86 |
+
# %%
|
| 87 |
+
c_v_feature = net.clip_encode_vision(imgs_torch_tensor)
|
| 88 |
+
|
| 89 |
+
for j, image_file in enumerate(image_files):
|
| 90 |
+
f = c_v_feature[j][np.newaxis].cpu().numpy()
|
| 91 |
+
|
| 92 |
+
output_file = os.path.join(
|
| 93 |
+
output_dir,
|
| 94 |
+
layer,
|
| 95 |
+
os.path.splitext(os.path.basename(image_file))[0] + '.mat'
|
| 96 |
+
)
|
| 97 |
+
|
| 98 |
+
if os.path.exists(output_file):
|
| 99 |
+
continue
|
| 100 |
+
|
| 101 |
+
os.makedirs(os.path.join(output_dir, layer), exist_ok=True)
|
| 102 |
+
|
| 103 |
+
savemat(output_file, {'feat': f})
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
# %%
|
| 107 |
+
|
| 108 |
+
# %%%
|
| 109 |
+
if __name__ == '__main__':
|
| 110 |
+
parser = argparse.ArgumentParser(description='DNN Feature extraction')
|
| 111 |
+
parser.add_argument('config', help='Configuration file')
|
| 112 |
+
args = parser.parse_args()
|
| 113 |
+
|
| 114 |
+
config = load_config(args.config)
|
| 115 |
+
extract_CLIP_vision_features(config)
|
spurious_reconstruction/analysis/0_preprocessing/BD_extract_Deeprecon_CLIP_text_features.py
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# %%
|
| 2 |
+
import sys
|
| 3 |
+
sys.path.append('versatile_diffusion')
|
| 4 |
+
import os
|
| 5 |
+
import numpy as np
|
| 6 |
+
|
| 7 |
+
import torch
|
| 8 |
+
from lib.cfg_helper import model_cfg_bank
|
| 9 |
+
from lib.model_zoo import get_model
|
| 10 |
+
from torch.utils.data import DataLoader, Dataset
|
| 11 |
+
|
| 12 |
+
from lib.model_zoo.vd import VD
|
| 13 |
+
from lib.cfg_holder import cfg_unique_holder as cfguh
|
| 14 |
+
from lib.cfg_helper import get_command_line_args, cfg_initiates, load_cfg_yaml
|
| 15 |
+
import matplotlib.pyplot as plt
|
| 16 |
+
import torchvision.transforms as T
|
| 17 |
+
from scipy.io import savemat
|
| 18 |
+
from glob import glob
|
| 19 |
+
import pandas as pd
|
| 20 |
+
# %%
|
| 21 |
+
|
| 22 |
+
#def extract_NSD_CLIP_text_features():
|
| 23 |
+
def extract_Deeprecon_CLIP_text_features():
|
| 24 |
+
cfgm_name = 'vd_noema'
|
| 25 |
+
pth = 'versatile_diffusion/pretrained/vd-four-flow-v1-0-fp16-deprecated.pth'
|
| 26 |
+
cfgm = model_cfg_bank()(cfgm_name)
|
| 27 |
+
net = get_model()(cfgm)
|
| 28 |
+
sd = torch.load(pth, map_location='cpu')
|
| 29 |
+
net.load_state_dict(sd, strict=False)
|
| 30 |
+
# %%
|
| 31 |
+
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
|
| 32 |
+
net.clip = net.clip.to(device)
|
| 33 |
+
|
| 34 |
+
# %%
|
| 35 |
+
num_embed, num_features = 77, 768
|
| 36 |
+
layer = 'text_encoder'
|
| 37 |
+
# Deeprecon test setting
|
| 38 |
+
image_list, df, save_base_path = Deeprecon_test_setting()
|
| 39 |
+
|
| 40 |
+
output_dir = os.path.join(save_base_path, "pytorch", 'brain_diffuser_versatile_diffusion')
|
| 41 |
+
print('Extract text features from Deeprecon test images')
|
| 42 |
+
extract_CLIP_text_features(image_list, df, output_dir, layer, net)
|
| 43 |
+
print('Done')
|
| 44 |
+
# %%
|
| 45 |
+
|
| 46 |
+
# Deeprecon traininig setting
|
| 47 |
+
training_image_list, df, save_base_path_training = Deeprecon_training_setting()
|
| 48 |
+
output_dir_training = os.path.join(save_base_path_training, "pytorch", 'brain_diffuser_versatile_diffusion')
|
| 49 |
+
print('Extract text features from Deeprecon training images')
|
| 50 |
+
extract_CLIP_text_features(training_image_list, df, output_dir_training, layer, net)
|
| 51 |
+
print('Done')
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
def Deeprecon_test_setting():
|
| 55 |
+
original_DeepreconTest_dir = './data/ImageNetTest'
|
| 56 |
+
image_list = glob(os.path.join(original_DeepreconTest_dir, 'source', '*.JPEG'))
|
| 57 |
+
# we didn't share the test annotation file due to the possibility to traing the future AI models.
|
| 58 |
+
df = pd.read_csv(os.path.join(original_DeepreconTest_dir, 'derivatives/captions/amt_20181204/amt_20181204.csv'))
|
| 59 |
+
save_base_path = "./data/ImageNetTest/derivatives/features"
|
| 60 |
+
return image_list, df, save_base_path
|
| 61 |
+
|
| 62 |
+
def Deeprecon_training_setting():
|
| 63 |
+
original_DeepreconTraining_dir = './data/contents_shared/ImageNetTraining'
|
| 64 |
+
image_list = glob(os.path.join(original_DeepreconTraining_dir, 'source', '*.JPEG'))
|
| 65 |
+
df = pd.read_csv(os.path.join(original_DeepreconTraining_dir, 'derivatives/captions/amt_20181204/amt_20181204.csv'))
|
| 66 |
+
save_base_path = "./data/ImageNetTraining/derivatives/features"
|
| 67 |
+
return image_list, df, save_base_path
|
| 68 |
+
|
| 69 |
+
def extract_CLIP_text_features(image_list, df, output_dir, layer, net):
|
| 70 |
+
for image in image_list:
|
| 71 |
+
file_name = os.path.basename(image).split('.')[0]
|
| 72 |
+
caption_texts = df[df['content_id'] == file_name]['caption'].values
|
| 73 |
+
#print(img)
|
| 74 |
+
out_text_list =[]
|
| 75 |
+
# %%
|
| 76 |
+
for cap in caption_texts:
|
| 77 |
+
c_t_feature = net.clip_encode_text(cap)
|
| 78 |
+
out_text_list.append(c_t_feature.cpu().detach().numpy())
|
| 79 |
+
out_text_list = np.array(out_text_list).squeeze() #[5, 77, 768]
|
| 80 |
+
|
| 81 |
+
# %%
|
| 82 |
+
output_file = os.path.join(
|
| 83 |
+
output_dir,
|
| 84 |
+
layer,
|
| 85 |
+
file_name + '.mat'
|
| 86 |
+
)
|
| 87 |
+
if os.path.exists(output_file):
|
| 88 |
+
continue
|
| 89 |
+
|
| 90 |
+
os.makedirs(os.path.join(output_dir, layer), exist_ok=True)
|
| 91 |
+
|
| 92 |
+
savemat(output_file, dict([('feat', np.mean(out_text_list, 0, keepdims=True)),
|
| 93 |
+
('raw_feat', out_text_list)]) )
|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
# %%
|
| 97 |
+
|
| 98 |
+
# %%%
|
| 99 |
+
if __name__ == '__main__':
|
| 100 |
+
|
| 101 |
+
extract_Deeprecon_CLIP_text_features()
|
spurious_reconstruction/analysis/0_preprocessing/BD_extract_NSD_CLIP_text_features.py
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# %%
|
| 2 |
+
import sys
|
| 3 |
+
sys.path.append('versatile_diffusion')
|
| 4 |
+
import os
|
| 5 |
+
import numpy as np
|
| 6 |
+
|
| 7 |
+
import torch
|
| 8 |
+
from lib.cfg_helper import model_cfg_bank
|
| 9 |
+
from lib.model_zoo import get_model
|
| 10 |
+
from torch.utils.data import DataLoader, Dataset
|
| 11 |
+
|
| 12 |
+
from lib.model_zoo.vd import VD
|
| 13 |
+
from lib.cfg_holder import cfg_unique_holder as cfguh
|
| 14 |
+
from lib.cfg_helper import get_command_line_args, cfg_initiates, load_cfg_yaml
|
| 15 |
+
import matplotlib.pyplot as plt
|
| 16 |
+
import torchvision.transforms as T
|
| 17 |
+
from nsd_access.nsd_access.nsda import NSDAccess
|
| 18 |
+
from scipy.io import savemat
|
| 19 |
+
# %%
|
| 20 |
+
|
| 21 |
+
def extract_NSD_CLIP_text_features():
|
| 22 |
+
|
| 23 |
+
cfgm_name = 'vd_noema'
|
| 24 |
+
pth = 'versatile_diffusion/pretrained/vd-four-flow-v1-0-fp16-deprecated.pth'
|
| 25 |
+
cfgm = model_cfg_bank()(cfgm_name)
|
| 26 |
+
net = get_model()(cfgm)
|
| 27 |
+
sd = torch.load(pth, map_location='cpu')
|
| 28 |
+
net.load_state_dict(sd, strict=False)
|
| 29 |
+
# %%
|
| 30 |
+
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
|
| 31 |
+
net.clip = net.clip.to(device)
|
| 32 |
+
|
| 33 |
+
# %%
|
| 34 |
+
num_embed, num_features = 77, 768
|
| 35 |
+
|
| 36 |
+
origina_nsd_dir = '[PATH_TO_NSD_DATASET_DIR]' #'/home/nu/data/fmri_shared/public/NSD/latest/'
|
| 37 |
+
nsda = NSDAccess(origina_nsd_dir)
|
| 38 |
+
|
| 39 |
+
output_dir = os.path.join("./data/NSD-stimuli/derivatives/features/", "pytorch", 'brain_diffuser_versatile_diffusion')
|
| 40 |
+
layer = 'text_encoder'
|
| 41 |
+
# %%
|
| 42 |
+
total_num = 73000
|
| 43 |
+
for img in range(total_num):
|
| 44 |
+
file_name = f'nsd{img+1:05}'+ '.mat'
|
| 45 |
+
ci = nsda.read_image_coco_info([img], info_type='captions', show_annot=True)
|
| 46 |
+
#print(img)
|
| 47 |
+
out_text_list =[]
|
| 48 |
+
# %%
|
| 49 |
+
|
| 50 |
+
for annotator in ci:
|
| 51 |
+
cap = annotator['caption']
|
| 52 |
+
|
| 53 |
+
c_v_feature = net.clip_encode_text(cap)
|
| 54 |
+
out_text_list.append(c_v_feature.cpu().detach().numpy())
|
| 55 |
+
out_text_list = np.array(out_text_list).squeeze() #[5, 77, 768]
|
| 56 |
+
|
| 57 |
+
# %%
|
| 58 |
+
output_file = os.path.join(
|
| 59 |
+
output_dir,
|
| 60 |
+
layer,
|
| 61 |
+
file_name
|
| 62 |
+
)
|
| 63 |
+
if os.path.exists(output_file):
|
| 64 |
+
continue
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
os.makedirs(os.path.join(output_dir, layer), exist_ok=True)
|
| 68 |
+
|
| 69 |
+
savemat(output_file, dict([('feat', np.mean(out_text_list, 0, keepdims=True)),
|
| 70 |
+
('raw_feat', out_text_list)]) )
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
# %%
|
| 74 |
+
|
| 75 |
+
# %%%
|
| 76 |
+
if __name__ == '__main__':
|
| 77 |
+
|
| 78 |
+
extract_NSD_CLIP_text_features()
|
spurious_reconstruction/analysis/0_preprocessing/README.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Scripts for extracting deep neural networks (DNNs) features from images (or text annotation), located at `./data/[dataset]/source` folders. You should put the stimuli files appropriately beforehand or run the download script.
|
| 2 |
+
|
| 3 |
+
# Usage (using rye environment)
|
| 4 |
+
If you want to extract VGG19 (for iCNN) in the Deeprecon dataset, running this command:
|
| 5 |
+
```rye run python ./analysis/0_preprocessing/iCNN_image_vgg19_feature_extraction.py ./analysis/0_preprocessing/config/Deeprecon/ImageNetTest.yaml```
|
| 6 |
+
|
| 7 |
+
If you want to extract CLIP text (for Brain-Diffuser) in the Deeprecon dataset, running this command:
|
| 8 |
+
```rye run python ./analysis/0_preprocessing/BD_extract_NSD_CLIP_tex_feature.py ./analysis/0_preprocessing/config/NSD/NSD.yaml```
|
| 9 |
+
|
| 10 |
+
If you want to extract CLIP vision (for Brain-Diffuser) in the NSD dataset, running this command:
|
| 11 |
+
```rye run python ./analysis/0_preprocessing/BD_extract_CLIP_vision_feature.py ./analysis/0_preprocessing/config/NSD/NSD.yaml```
|
| 12 |
+
|
| 13 |
+
Note:
|
| 14 |
+
If you want to extract CLIP features used in the Brain-Diffuser models, you need additonaly prepare[versatile_diffusion](https://github.com/ozcelikfu/brain-diffuser/tree/main/versatile_diffusion) at the top of this directory.
|
| 15 |
+
|
spurious_reconstruction/analysis/0_preprocessing/config/Deeprecon/ArtificialShapes.yaml
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
image path:
|
| 2 |
+
./data/ArtificialShapes/source
|
| 3 |
+
|
| 4 |
+
image_ext:
|
| 5 |
+
tiff
|
| 6 |
+
|
| 7 |
+
output base dir:
|
| 8 |
+
./data/ArtificialShapes/derivatives/features/
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
# This is only related to the script "iCNN_image_vgg19_feature_extraction.py"
|
| 12 |
+
network:
|
| 13 |
+
VGG19_ILSVRC_19_layers
|
| 14 |
+
|
| 15 |
+
features:
|
| 16 |
+
- features[0] # conv1_1
|
| 17 |
+
- features[2] # conv1_2
|
| 18 |
+
- features[5] # conv2_1
|
| 19 |
+
- features[7] # conv2_2
|
| 20 |
+
- features[10] # conv3_1
|
| 21 |
+
- features[12] # conv3_2
|
| 22 |
+
- features[14] # conv3_3
|
| 23 |
+
- features[16] # conv3_4
|
| 24 |
+
- features[19] # conv4_1
|
| 25 |
+
- features[21] # conv4_2
|
| 26 |
+
- features[23] # conv4_3
|
| 27 |
+
- features[25] # conv4_4
|
| 28 |
+
- features[28] # conv5_1
|
| 29 |
+
- features[30] # conv5_2
|
| 30 |
+
- features[32] # conv5_3
|
| 31 |
+
- features[34] # conv5_4
|
| 32 |
+
- classifier[0] # fc6
|
| 33 |
+
- classifier[3] # fc7
|
| 34 |
+
- classifier[6] # fc8
|