diff --git a/README.md b/README.md
index bcfb999de36cb08a6c76e1a94e7363ffb719457f..46693f113e40b612de98e4471aebb904919fae9e 100644
--- a/README.md
+++ b/README.md
@@ -3,14 +3,9 @@ title: Latent Diffusion
emoji: π
colorFrom: pink
colorTo: indigo
-sdk: static
+sdk: gradio
+sdk_version: 2.9.1
+app_file: app.py
pinned: false
----
-
-
Under maintenance due to concerns on the biases of the model
-
- This space contained a way to quickly execute the open source text-to-image Latent Diffusion model by CompVis, trained on the LAION-400M dataset.
- We believe transparency and bringing and open and honest discussions about model biases is the best way to deal with such challegnges. However after some users reported seeing some gruesome NSFW images with certain prompts from this model, we decided to take down this Spaces for now.
-
-
-
\ No newline at end of file
+license: mit
+---
\ No newline at end of file
diff --git a/app.py b/app.py
new file mode 100644
index 0000000000000000000000000000000000000000..14f4ef6097182c39b2aa9338929b6eb448da04bf
--- /dev/null
+++ b/app.py
@@ -0,0 +1,149 @@
+from pydoc import describe
+import gradio as gr
+import torch
+from omegaconf import OmegaConf
+import sys
+sys.path.append(".")
+sys.path.append('./taming-transformers')
+sys.path.append('./latent-diffusion')
+from taming.models import vqgan
+from ldm.util import instantiate_from_config
+
+torch.hub.download_url_to_file('http://batbot.ai/models/latent-diffusion/models/ldm/text2img-large/model.ckpt','txt2img-f8-large.ckpt')
+
+#@title Import stuff
+import argparse, os, sys, glob
+import numpy as np
+from PIL import Image
+from einops import rearrange
+from torchvision.utils import make_grid
+import transformers
+import gc
+from ldm.util import instantiate_from_config
+from ldm.models.diffusion.ddim import DDIMSampler
+from ldm.models.diffusion.plms import PLMSSampler
+from open_clip import tokenizer
+import open_clip
+
+def load_model_from_config(config, ckpt, verbose=False):
+ print(f"Loading model from {ckpt}")
+ pl_sd = torch.load(ckpt, map_location="cuda")
+ sd = pl_sd["state_dict"]
+ model = instantiate_from_config(config.model)
+ m, u = model.load_state_dict(sd, strict=False)
+ if len(m) > 0 and verbose:
+ print("missing keys:")
+ print(m)
+ if len(u) > 0 and verbose:
+ print("unexpected keys:")
+ print(u)
+
+ model = model.half().cuda()
+ model.eval()
+ return model
+
+config = OmegaConf.load("latent-diffusion/configs/latent-diffusion/txt2img-1p4B-eval.yaml")
+model = load_model_from_config(config, f"txt2img-f8-large.ckpt")
+device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")
+model = model.to(device)
+#NSFW CLIP Filter
+clip_model, _, preprocess = open_clip.create_model_and_transforms('ViT-B-32-quickgelu', pretrained='laion400m_e32')
+text = tokenizer.tokenize(["NSFW", "adult content", "porn", "naked people","genitalia","penis","vagina"])
+with torch.no_grad():
+ text_features = clip_model.encode_text(text)
+
+def run(prompt, steps, width, height, images, scale):
+ opt = argparse.Namespace(
+ prompt = prompt,
+ outdir='latent-diffusion/outputs',
+ ddim_steps = int(steps),
+ ddim_eta = 0,
+ n_iter = 1,
+ W=int(width),
+ H=int(height),
+ n_samples=int(images),
+ scale=scale,
+ plms=True
+ )
+
+ if opt.plms:
+ opt.ddim_eta = 0
+ sampler = PLMSSampler(model)
+ else:
+ sampler = DDIMSampler(model)
+
+ os.makedirs(opt.outdir, exist_ok=True)
+ outpath = opt.outdir
+
+ prompt = opt.prompt
+
+
+ sample_path = os.path.join(outpath, "samples")
+ os.makedirs(sample_path, exist_ok=True)
+ base_count = len(os.listdir(sample_path))
+
+ all_samples=list()
+ all_samples_images=list()
+ with torch.no_grad():
+ with torch.cuda.amp.autocast():
+ with model.ema_scope():
+ uc = None
+ if opt.scale > 0:
+ uc = model.get_learned_conditioning(opt.n_samples * [""])
+ for n in range(opt.n_iter):
+ c = model.get_learned_conditioning(opt.n_samples * [prompt])
+ shape = [4, opt.H//8, opt.W//8]
+ samples_ddim, _ = sampler.sample(S=opt.ddim_steps,
+ conditioning=c,
+ batch_size=opt.n_samples,
+ shape=shape,
+ verbose=False,
+ unconditional_guidance_scale=opt.scale,
+ unconditional_conditioning=uc,
+ eta=opt.ddim_eta)
+
+ x_samples_ddim = model.decode_first_stage(samples_ddim)
+ x_samples_ddim = torch.clamp((x_samples_ddim+1.0)/2.0, min=0.0, max=1.0)
+
+ for x_sample in x_samples_ddim:
+ x_sample = 255. * rearrange(x_sample.cpu().numpy(), 'c h w -> h w c')
+ image_vector = Image.fromarray(x_sample.astype(np.uint8))
+ image = preprocess(image_vector).unsqueeze(0)
+ image_features = clip_model.encode_image(image)
+ sims = image_features @ text_features.T
+ if(sims.max()<18):
+ all_samples_images.append(image_vector)
+ else:
+ return(None,None,"Sorry, NSFW content was detected on your outputs. Try again with different prompts. If you feel your prompt was not supposed to give NSFW outputs, this may be due to a bias in the model. Read more about biases in the Biases Acknowledgment section below.")
+ #Image.fromarray(x_sample.astype(np.uint8)).save(os.path.join(sample_path, f"{base_count:04}.png"))
+ base_count += 1
+ all_samples.append(x_samples_ddim)
+
+
+ # additionally, save as grid
+ grid = torch.stack(all_samples, 0)
+ grid = rearrange(grid, 'n b c h w -> (n b) c h w')
+ grid = make_grid(grid, nrow=2)
+ # to image
+ grid = 255. * rearrange(grid, 'c h w -> h w c').cpu().numpy()
+
+ Image.fromarray(grid.astype(np.uint8)).save(os.path.join(outpath, f'{prompt.replace(" ", "-")}.png'))
+ return(Image.fromarray(grid.astype(np.uint8)),all_samples_images,None)
+
+image = gr.outputs.Image(type="pil", label="Your result")
+css = ".output-image{height: 528px !important} .output-carousel .output-image{height:272px !important} a{text-decoration: underline}"
+iface = gr.Interface(fn=run, inputs=[
+ gr.inputs.Textbox(label="Prompt - try adding increments to your prompt such as 'oil on canvas', 'a painting', 'a book cover'",default="chalk pastel drawing of a dog wearing a funny hat"),
+ gr.inputs.Slider(label="Steps - more steps can increase quality but will take longer to generate",default=45,maximum=50,minimum=1,step=1),
+ gr.inputs.Radio(label="Width", choices=[32,64,128,256],default=256),
+ gr.inputs.Radio(label="Height", choices=[32,64,128,256],default=256),
+ gr.inputs.Slider(label="Images - How many images you wish to generate", default=2, step=1, minimum=1, maximum=4),
+ gr.inputs.Slider(label="Diversity scale - How different from one another you wish the images to be",default=5.0, minimum=1.0, maximum=15.0),
+ #gr.inputs.Slider(label="ETA - between 0 and 1. Lower values can provide better quality, higher values can be more diverse",default=0.0,minimum=0.0, maximum=1.0,step=0.1),
+ ],
+ outputs=[image,gr.outputs.Carousel(label="Individual images",components=["image"]),gr.outputs.Textbox(label="Error")],
+ css=css,
+ title="Generate images from text with Latent Diffusion LAION-400M",
+ description="",
+ article="Biases acknowledgment
Despite how impressive being able to turn text into image is, beware to the fact that this model may output content that reinforces or exarcbates societal biases. According to the
Latent Diffusion paper:
\"Deep learning modules tend to reproduce or exacerbate biases that are already present in the data\". The model was trained on an unfiltered version the LAION-400M dataset, which scrapped non-curated image-text-pairs from the internet (the exception being the the removal of illegal content) and is meant to be used for research purposes, such as this one.
You can read more on LAION's websiteWho owns the images produced by this demo?
")
+iface.launch(enable_queue=True)
\ No newline at end of file
diff --git a/latent-diffusion/LICENSE b/latent-diffusion/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..be24ebeed0fb31665dc3c33d2610d35f77b12709
--- /dev/null
+++ b/latent-diffusion/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2022 Machine Vision and Learning Group, LMU Munich
+
+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:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+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.
diff --git a/latent-diffusion/README.md b/latent-diffusion/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..5fe33f22ddffed4680bba15eaa9fa6ec0fd03aec
--- /dev/null
+++ b/latent-diffusion/README.md
@@ -0,0 +1,274 @@
+# Latent Diffusion Models
+[arXiv](https://arxiv.org/abs/2112.10752) | [BibTeX](#bibtex)
+
+
+
+
+
+
+
+[**High-Resolution Image Synthesis with Latent Diffusion Models**](https://arxiv.org/abs/2112.10752)
+[Robin Rombach](https://github.com/rromb)\*,
+[Andreas Blattmann](https://github.com/ablattmann)\*,
+[Dominik Lorenz](https://github.com/qp-qp)\,
+[Patrick Esser](https://github.com/pesser),
+[BjΓΆrn Ommer](https://hci.iwr.uni-heidelberg.de/Staff/bommer)
+\* equal contribution
+
+
+
+
+
+## News
+### April 2022
+- More pre-trained LDMs are available:
+ - A 1.45B [model](#text-to-image) trained on the [LAION-400M](https://arxiv.org/abs/2111.02114) database.
+ - A class-conditional model on ImageNet, achieving a FID of 3.6 when using [classifier-free guidance](https://openreview.net/pdf?id=qw8AKxfYbI) Available via a [colab notebook](https://colab.research.google.com/github/CompVis/latent-diffusion/blob/main/scripts/latent_imagenet_diffusion.ipynb) [![][colab]][colab-cin].
+
+## Requirements
+A suitable [conda](https://conda.io/) environment named `ldm` can be created
+and activated with:
+
+```
+conda env create -f environment.yaml
+conda activate ldm
+```
+
+# Pretrained Models
+A general list of all available checkpoints is available in via our [model zoo](#model-zoo).
+If you use any of these models in your work, we are always happy to receive a [citation](#bibtex).
+
+## Text-to-Image
+![text2img-figure](assets/txt2img-preview.png)
+
+
+Download the pre-trained weights (5.7GB)
+```
+mkdir -p models/ldm/text2img-large/
+wget -O models/ldm/text2img-large/model.ckpt https://ommer-lab.com/files/latent-diffusion/nitro/txt2img-f8-large/model.ckpt
+```
+and sample with
+```
+python scripts/txt2img.py --prompt "a virus monster is playing guitar, oil on canvas" --ddim_eta 0.0 --n_samples 4 --n_iter 4 --scale 5.0 --ddim_steps 50
+```
+This will save each sample individually as well as a grid of size `n_iter` x `n_samples` at the specified output location (default: `outputs/txt2img-samples`).
+Quality, sampling speed and diversity are best controlled via the `scale`, `ddim_steps` and `ddim_eta` arguments.
+As a rule of thumb, higher values of `scale` produce better samples at the cost of a reduced output diversity.
+Furthermore, increasing `ddim_steps` generally also gives higher quality samples, but returns are diminishing for values > 250.
+Fast sampling (i.e. low values of `ddim_steps`) while retaining good quality can be achieved by using `--ddim_eta 0.0`.
+Faster sampling (i.e. even lower values of `ddim_steps`) while retaining good quality can be achieved by using `--ddim_eta 0.0` and `--plms` (added by Katherine Crowson, see [Pseudo Numerical Methods for Diffusion Models on Manifolds](https://arxiv.org/abs/2202.09778)).
+
+#### Beyond 256Β²
+
+For certain inputs, simply running the model in a convolutional fashion on larger features than it was trained on
+can sometimes result in interesting results. To try it out, tune the `H` and `W` arguments (which will be integer-divided
+by 8 in order to calculate the corresponding latent size), e.g. run
+
+```
+python scripts/txt2img.py --prompt "a sunset behind a mountain range, vector image" --ddim_eta 1.0 --n_samples 1 --n_iter 1 --H 384 --W 1024 --scale 5.0
+```
+to create a sample of size 384x1024. Note, however, that controllability is reduced compared to the 256x256 setting.
+
+The example below was generated using the above command.
+![text2img-figure-conv](assets/txt2img-convsample.png)
+
+
+
+## Inpainting
+![inpainting](assets/inpainting.png)
+
+Download the pre-trained weights
+```
+wget -O models/ldm/inpainting_big/last.ckpt https://heibox.uni-heidelberg.de/f/4d9ac7ea40c64582b7c9/?dl=1
+```
+
+and sample with
+```
+python scripts/inpaint.py --indir data/inpainting_examples/ --outdir outputs/inpainting_results
+```
+`indir` should contain images `*.png` and masks `_mask.png` like
+the examples provided in `data/inpainting_examples`.
+
+## Class-Conditional ImageNet
+
+Available via a [notebook](scripts/latent_imagenet_diffusion.ipynb) [![][colab]][colab-cin].
+![class-conditional](assets/birdhouse.png)
+
+[colab]:
+[colab-cin]:
+
+
+## Unconditional Models
+
+We also provide a script for sampling from unconditional LDMs (e.g. LSUN, FFHQ, ...). Start it via
+
+```shell script
+CUDA_VISIBLE_DEVICES= python scripts/sample_diffusion.py -r models/ldm//model.ckpt -l -n <\#samples> --batch_size -c <\#ddim steps> -e <\#eta>
+```
+
+# Train your own LDMs
+
+## Data preparation
+
+### Faces
+For downloading the CelebA-HQ and FFHQ datasets, proceed as described in the [taming-transformers](https://github.com/CompVis/taming-transformers#celeba-hq)
+repository.
+
+### LSUN
+
+The LSUN datasets can be conveniently downloaded via the script available [here](https://github.com/fyu/lsun).
+We performed a custom split into training and validation images, and provide the corresponding filenames
+at [https://ommer-lab.com/files/lsun.zip](https://ommer-lab.com/files/lsun.zip).
+After downloading, extract them to `./data/lsun`. The beds/cats/churches subsets should
+also be placed/symlinked at `./data/lsun/bedrooms`/`./data/lsun/cats`/`./data/lsun/churches`, respectively.
+
+### ImageNet
+The code will try to download (through [Academic
+Torrents](http://academictorrents.com/)) and prepare ImageNet the first time it
+is used. However, since ImageNet is quite large, this requires a lot of disk
+space and time. If you already have ImageNet on your disk, you can speed things
+up by putting the data into
+`${XDG_CACHE}/autoencoders/data/ILSVRC2012_{split}/data/` (which defaults to
+`~/.cache/autoencoders/data/ILSVRC2012_{split}/data/`), where `{split}` is one
+of `train`/`validation`. It should have the following structure:
+
+```
+${XDG_CACHE}/autoencoders/data/ILSVRC2012_{split}/data/
+βββ n01440764
+β βββ n01440764_10026.JPEG
+β βββ n01440764_10027.JPEG
+β βββ ...
+βββ n01443537
+β βββ n01443537_10007.JPEG
+β βββ n01443537_10014.JPEG
+β βββ ...
+βββ ...
+```
+
+If you haven't extracted the data, you can also place
+`ILSVRC2012_img_train.tar`/`ILSVRC2012_img_val.tar` (or symlinks to them) into
+`${XDG_CACHE}/autoencoders/data/ILSVRC2012_train/` /
+`${XDG_CACHE}/autoencoders/data/ILSVRC2012_validation/`, which will then be
+extracted into above structure without downloading it again. Note that this
+will only happen if neither a folder
+`${XDG_CACHE}/autoencoders/data/ILSVRC2012_{split}/data/` nor a file
+`${XDG_CACHE}/autoencoders/data/ILSVRC2012_{split}/.ready` exist. Remove them
+if you want to force running the dataset preparation again.
+
+
+## Model Training
+
+Logs and checkpoints for trained models are saved to `logs/_`.
+
+### Training autoencoder models
+
+Configs for training a KL-regularized autoencoder on ImageNet are provided at `configs/autoencoder`.
+Training can be started by running
+```
+CUDA_VISIBLE_DEVICES= python main.py --base configs/autoencoder/.yaml -t --gpus 0,
+```
+where `config_spec` is one of {`autoencoder_kl_8x8x64`(f=32, d=64), `autoencoder_kl_16x16x16`(f=16, d=16),
+`autoencoder_kl_32x32x4`(f=8, d=4), `autoencoder_kl_64x64x3`(f=4, d=3)}.
+
+For training VQ-regularized models, see the [taming-transformers](https://github.com/CompVis/taming-transformers)
+repository.
+
+### Training LDMs
+
+In ``configs/latent-diffusion/`` we provide configs for training LDMs on the LSUN-, CelebA-HQ, FFHQ and ImageNet datasets.
+Training can be started by running
+
+```shell script
+CUDA_VISIBLE_DEVICES= python main.py --base configs/latent-diffusion/.yaml -t --gpus 0,
+```
+
+where ```` is one of {`celebahq-ldm-vq-4`(f=4, VQ-reg. autoencoder, spatial size 64x64x3),`ffhq-ldm-vq-4`(f=4, VQ-reg. autoencoder, spatial size 64x64x3),
+`lsun_bedrooms-ldm-vq-4`(f=4, VQ-reg. autoencoder, spatial size 64x64x3),
+`lsun_churches-ldm-vq-4`(f=8, KL-reg. autoencoder, spatial size 32x32x4),`cin-ldm-vq-8`(f=8, VQ-reg. autoencoder, spatial size 32x32x4)}.
+
+# Model Zoo
+
+## Pretrained Autoencoding Models
+![rec2](assets/reconstruction2.png)
+
+All models were trained until convergence (no further substantial improvement in rFID).
+
+| Model | rFID vs val | train steps |PSNR | PSIM | Link | Comments
+|-------------------------|------------|----------------|----------------|---------------|-------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------|
+| f=4, VQ (Z=8192, d=3) | 0.58 | 533066 | 27.43 +/- 4.26 | 0.53 +/- 0.21 | https://ommer-lab.com/files/latent-diffusion/vq-f4.zip | |
+| f=4, VQ (Z=8192, d=3) | 1.06 | 658131 | 25.21 +/- 4.17 | 0.72 +/- 0.26 | https://heibox.uni-heidelberg.de/f/9c6681f64bb94338a069/?dl=1 | no attention |
+| f=8, VQ (Z=16384, d=4) | 1.14 | 971043 | 23.07 +/- 3.99 | 1.17 +/- 0.36 | https://ommer-lab.com/files/latent-diffusion/vq-f8.zip | |
+| f=8, VQ (Z=256, d=4) | 1.49 | 1608649 | 22.35 +/- 3.81 | 1.26 +/- 0.37 | https://ommer-lab.com/files/latent-diffusion/vq-f8-n256.zip |
+| f=16, VQ (Z=16384, d=8) | 5.15 | 1101166 | 20.83 +/- 3.61 | 1.73 +/- 0.43 | https://heibox.uni-heidelberg.de/f/0e42b04e2e904890a9b6/?dl=1 | |
+| | | | | | | |
+| f=4, KL | 0.27 | 176991 | 27.53 +/- 4.54 | 0.55 +/- 0.24 | https://ommer-lab.com/files/latent-diffusion/kl-f4.zip | |
+| f=8, KL | 0.90 | 246803 | 24.19 +/- 4.19 | 1.02 +/- 0.35 | https://ommer-lab.com/files/latent-diffusion/kl-f8.zip | |
+| f=16, KL (d=16) | 0.87 | 442998 | 24.08 +/- 4.22 | 1.07 +/- 0.36 | https://ommer-lab.com/files/latent-diffusion/kl-f16.zip | |
+ | f=32, KL (d=64) | 2.04 | 406763 | 22.27 +/- 3.93 | 1.41 +/- 0.40 | https://ommer-lab.com/files/latent-diffusion/kl-f32.zip | |
+
+### Get the models
+
+Running the following script downloads und extracts all available pretrained autoencoding models.
+```shell script
+bash scripts/download_first_stages.sh
+```
+
+The first stage models can then be found in `models/first_stage_models/`
+
+
+
+## Pretrained LDMs
+| Datset | Task | Model | FID | IS | Prec | Recall | Link | Comments
+|---------------------------------|------|--------------|---------------|-----------------|------|------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------|
+| CelebA-HQ | Unconditional Image Synthesis | LDM-VQ-4 (200 DDIM steps, eta=0)| 5.11 (5.11) | 3.29 | 0.72 | 0.49 | https://ommer-lab.com/files/latent-diffusion/celeba.zip | |
+| FFHQ | Unconditional Image Synthesis | LDM-VQ-4 (200 DDIM steps, eta=1)| 4.98 (4.98) | 4.50 (4.50) | 0.73 | 0.50 | https://ommer-lab.com/files/latent-diffusion/ffhq.zip | |
+| LSUN-Churches | Unconditional Image Synthesis | LDM-KL-8 (400 DDIM steps, eta=0)| 4.02 (4.02) | 2.72 | 0.64 | 0.52 | https://ommer-lab.com/files/latent-diffusion/lsun_churches.zip | |
+| LSUN-Bedrooms | Unconditional Image Synthesis | LDM-VQ-4 (200 DDIM steps, eta=1)| 2.95 (3.0) | 2.22 (2.23)| 0.66 | 0.48 | https://ommer-lab.com/files/latent-diffusion/lsun_bedrooms.zip | |
+| ImageNet | Class-conditional Image Synthesis | LDM-VQ-8 (200 DDIM steps, eta=1) | 7.77(7.76)* /15.82** | 201.56(209.52)* /78.82** | 0.84* / 0.65** | 0.35* / 0.63** | https://ommer-lab.com/files/latent-diffusion/cin.zip | *: w/ guiding, classifier_scale 10 **: w/o guiding, scores in bracket calculated with script provided by [ADM](https://github.com/openai/guided-diffusion) |
+| Conceptual Captions | Text-conditional Image Synthesis | LDM-VQ-f4 (100 DDIM steps, eta=0) | 16.79 | 13.89 | N/A | N/A | https://ommer-lab.com/files/latent-diffusion/text2img.zip | finetuned from LAION |
+| OpenImages | Super-resolution | LDM-VQ-4 | N/A | N/A | N/A | N/A | https://ommer-lab.com/files/latent-diffusion/sr_bsr.zip | BSR image degradation |
+| OpenImages | Layout-to-Image Synthesis | LDM-VQ-4 (200 DDIM steps, eta=0) | 32.02 | 15.92 | N/A | N/A | https://ommer-lab.com/files/latent-diffusion/layout2img_model.zip | |
+| Landscapes | Semantic Image Synthesis | LDM-VQ-4 | N/A | N/A | N/A | N/A | https://ommer-lab.com/files/latent-diffusion/semantic_synthesis256.zip | |
+| Landscapes | Semantic Image Synthesis | LDM-VQ-4 | N/A | N/A | N/A | N/A | https://ommer-lab.com/files/latent-diffusion/semantic_synthesis.zip | finetuned on resolution 512x512 |
+
+
+### Get the models
+
+The LDMs listed above can jointly be downloaded and extracted via
+
+```shell script
+bash scripts/download_models.sh
+```
+
+The models can then be found in `models/ldm/`.
+
+
+
+## Coming Soon...
+
+* More inference scripts for conditional LDMs.
+* In the meantime, you can play with our colab notebook https://colab.research.google.com/drive/1xqzUi2iXQXDqXBHQGP9Mqt2YrYW6cx-J?usp=sharing
+
+## Comments
+
+- Our codebase for the diffusion models builds heavily on [OpenAI's ADM codebase](https://github.com/openai/guided-diffusion)
+and [https://github.com/lucidrains/denoising-diffusion-pytorch](https://github.com/lucidrains/denoising-diffusion-pytorch).
+Thanks for open-sourcing!
+
+- The implementation of the transformer encoder is from [x-transformers](https://github.com/lucidrains/x-transformers) by [lucidrains](https://github.com/lucidrains?tab=repositories).
+
+
+## BibTeX
+
+```
+@misc{rombach2021highresolution,
+ title={High-Resolution Image Synthesis with Latent Diffusion Models},
+ author={Robin Rombach and Andreas Blattmann and Dominik Lorenz and Patrick Esser and BjΓΆrn Ommer},
+ year={2021},
+ eprint={2112.10752},
+ archivePrefix={arXiv},
+ primaryClass={cs.CV}
+}
+```
+
+
diff --git a/latent-diffusion/configs/autoencoder/autoencoder_kl_16x16x16.yaml b/latent-diffusion/configs/autoencoder/autoencoder_kl_16x16x16.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..5f1d10ec75e5de5932cdcf0e8d3c712feac7578e
--- /dev/null
+++ b/latent-diffusion/configs/autoencoder/autoencoder_kl_16x16x16.yaml
@@ -0,0 +1,54 @@
+model:
+ base_learning_rate: 4.5e-6
+ target: ldm.models.autoencoder.AutoencoderKL
+ params:
+ monitor: "val/rec_loss"
+ embed_dim: 16
+ lossconfig:
+ target: ldm.modules.losses.LPIPSWithDiscriminator
+ params:
+ disc_start: 50001
+ kl_weight: 0.000001
+ disc_weight: 0.5
+
+ ddconfig:
+ double_z: True
+ z_channels: 16
+ resolution: 256
+ in_channels: 3
+ out_ch: 3
+ ch: 128
+ ch_mult: [ 1,1,2,2,4] # num_down = len(ch_mult)-1
+ num_res_blocks: 2
+ attn_resolutions: [16]
+ dropout: 0.0
+
+
+data:
+ target: main.DataModuleFromConfig
+ params:
+ batch_size: 12
+ wrap: True
+ train:
+ target: ldm.data.imagenet.ImageNetSRTrain
+ params:
+ size: 256
+ degradation: pil_nearest
+ validation:
+ target: ldm.data.imagenet.ImageNetSRValidation
+ params:
+ size: 256
+ degradation: pil_nearest
+
+lightning:
+ callbacks:
+ image_logger:
+ target: main.ImageLogger
+ params:
+ batch_frequency: 1000
+ max_images: 8
+ increase_log_steps: True
+
+ trainer:
+ benchmark: True
+ accumulate_grad_batches: 2
diff --git a/latent-diffusion/configs/autoencoder/autoencoder_kl_32x32x4.yaml b/latent-diffusion/configs/autoencoder/autoencoder_kl_32x32x4.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..ab8b36fe6e3e95df2942a437b7d9c919b60d5c86
--- /dev/null
+++ b/latent-diffusion/configs/autoencoder/autoencoder_kl_32x32x4.yaml
@@ -0,0 +1,53 @@
+model:
+ base_learning_rate: 4.5e-6
+ target: ldm.models.autoencoder.AutoencoderKL
+ params:
+ monitor: "val/rec_loss"
+ embed_dim: 4
+ lossconfig:
+ target: ldm.modules.losses.LPIPSWithDiscriminator
+ params:
+ disc_start: 50001
+ kl_weight: 0.000001
+ disc_weight: 0.5
+
+ ddconfig:
+ double_z: True
+ z_channels: 4
+ resolution: 256
+ in_channels: 3
+ out_ch: 3
+ ch: 128
+ ch_mult: [ 1,2,4,4 ] # num_down = len(ch_mult)-1
+ num_res_blocks: 2
+ attn_resolutions: [ ]
+ dropout: 0.0
+
+data:
+ target: main.DataModuleFromConfig
+ params:
+ batch_size: 12
+ wrap: True
+ train:
+ target: ldm.data.imagenet.ImageNetSRTrain
+ params:
+ size: 256
+ degradation: pil_nearest
+ validation:
+ target: ldm.data.imagenet.ImageNetSRValidation
+ params:
+ size: 256
+ degradation: pil_nearest
+
+lightning:
+ callbacks:
+ image_logger:
+ target: main.ImageLogger
+ params:
+ batch_frequency: 1000
+ max_images: 8
+ increase_log_steps: True
+
+ trainer:
+ benchmark: True
+ accumulate_grad_batches: 2
diff --git a/latent-diffusion/configs/autoencoder/autoencoder_kl_64x64x3.yaml b/latent-diffusion/configs/autoencoder/autoencoder_kl_64x64x3.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..5e3db5c4e28bcb58be4ee0872511059f5cc965ad
--- /dev/null
+++ b/latent-diffusion/configs/autoencoder/autoencoder_kl_64x64x3.yaml
@@ -0,0 +1,54 @@
+model:
+ base_learning_rate: 4.5e-6
+ target: ldm.models.autoencoder.AutoencoderKL
+ params:
+ monitor: "val/rec_loss"
+ embed_dim: 3
+ lossconfig:
+ target: ldm.modules.losses.LPIPSWithDiscriminator
+ params:
+ disc_start: 50001
+ kl_weight: 0.000001
+ disc_weight: 0.5
+
+ ddconfig:
+ double_z: True
+ z_channels: 3
+ resolution: 256
+ in_channels: 3
+ out_ch: 3
+ ch: 128
+ ch_mult: [ 1,2,4 ] # num_down = len(ch_mult)-1
+ num_res_blocks: 2
+ attn_resolutions: [ ]
+ dropout: 0.0
+
+
+data:
+ target: main.DataModuleFromConfig
+ params:
+ batch_size: 12
+ wrap: True
+ train:
+ target: ldm.data.imagenet.ImageNetSRTrain
+ params:
+ size: 256
+ degradation: pil_nearest
+ validation:
+ target: ldm.data.imagenet.ImageNetSRValidation
+ params:
+ size: 256
+ degradation: pil_nearest
+
+lightning:
+ callbacks:
+ image_logger:
+ target: main.ImageLogger
+ params:
+ batch_frequency: 1000
+ max_images: 8
+ increase_log_steps: True
+
+ trainer:
+ benchmark: True
+ accumulate_grad_batches: 2
diff --git a/latent-diffusion/configs/autoencoder/autoencoder_kl_8x8x64.yaml b/latent-diffusion/configs/autoencoder/autoencoder_kl_8x8x64.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..5ccd09d38e4926706fb1d287f4f65619627e0eb7
--- /dev/null
+++ b/latent-diffusion/configs/autoencoder/autoencoder_kl_8x8x64.yaml
@@ -0,0 +1,53 @@
+model:
+ base_learning_rate: 4.5e-6
+ target: ldm.models.autoencoder.AutoencoderKL
+ params:
+ monitor: "val/rec_loss"
+ embed_dim: 64
+ lossconfig:
+ target: ldm.modules.losses.LPIPSWithDiscriminator
+ params:
+ disc_start: 50001
+ kl_weight: 0.000001
+ disc_weight: 0.5
+
+ ddconfig:
+ double_z: True
+ z_channels: 64
+ resolution: 256
+ in_channels: 3
+ out_ch: 3
+ ch: 128
+ ch_mult: [ 1,1,2,2,4,4] # num_down = len(ch_mult)-1
+ num_res_blocks: 2
+ attn_resolutions: [16,8]
+ dropout: 0.0
+
+data:
+ target: main.DataModuleFromConfig
+ params:
+ batch_size: 12
+ wrap: True
+ train:
+ target: ldm.data.imagenet.ImageNetSRTrain
+ params:
+ size: 256
+ degradation: pil_nearest
+ validation:
+ target: ldm.data.imagenet.ImageNetSRValidation
+ params:
+ size: 256
+ degradation: pil_nearest
+
+lightning:
+ callbacks:
+ image_logger:
+ target: main.ImageLogger
+ params:
+ batch_frequency: 1000
+ max_images: 8
+ increase_log_steps: True
+
+ trainer:
+ benchmark: True
+ accumulate_grad_batches: 2
diff --git a/latent-diffusion/configs/latent-diffusion/celebahq-ldm-vq-4.yaml b/latent-diffusion/configs/latent-diffusion/celebahq-ldm-vq-4.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..89b3df4fe1822295d509dca2237ea891cdd964bf
--- /dev/null
+++ b/latent-diffusion/configs/latent-diffusion/celebahq-ldm-vq-4.yaml
@@ -0,0 +1,86 @@
+model:
+ base_learning_rate: 2.0e-06
+ target: ldm.models.diffusion.ddpm.LatentDiffusion
+ params:
+ linear_start: 0.0015
+ linear_end: 0.0195
+ num_timesteps_cond: 1
+ log_every_t: 200
+ timesteps: 1000
+ first_stage_key: image
+ image_size: 64
+ channels: 3
+ monitor: val/loss_simple_ema
+
+ unet_config:
+ target: ldm.modules.diffusionmodules.openaimodel.UNetModel
+ params:
+ image_size: 64
+ in_channels: 3
+ out_channels: 3
+ model_channels: 224
+ attention_resolutions:
+ # note: this isn\t actually the resolution but
+ # the downsampling factor, i.e. this corresnponds to
+ # attention on spatial resolution 8,16,32, as the
+ # spatial reolution of the latents is 64 for f4
+ - 8
+ - 4
+ - 2
+ num_res_blocks: 2
+ channel_mult:
+ - 1
+ - 2
+ - 3
+ - 4
+ num_head_channels: 32
+ first_stage_config:
+ target: ldm.models.autoencoder.VQModelInterface
+ params:
+ embed_dim: 3
+ n_embed: 8192
+ ckpt_path: models/first_stage_models/vq-f4/model.ckpt
+ ddconfig:
+ double_z: false
+ z_channels: 3
+ resolution: 256
+ in_channels: 3
+ out_ch: 3
+ ch: 128
+ ch_mult:
+ - 1
+ - 2
+ - 4
+ num_res_blocks: 2
+ attn_resolutions: []
+ dropout: 0.0
+ lossconfig:
+ target: torch.nn.Identity
+ cond_stage_config: __is_unconditional__
+data:
+ target: main.DataModuleFromConfig
+ params:
+ batch_size: 48
+ num_workers: 5
+ wrap: false
+ train:
+ target: taming.data.faceshq.CelebAHQTrain
+ params:
+ size: 256
+ validation:
+ target: taming.data.faceshq.CelebAHQValidation
+ params:
+ size: 256
+
+
+lightning:
+ callbacks:
+ image_logger:
+ target: main.ImageLogger
+ params:
+ batch_frequency: 5000
+ max_images: 8
+ increase_log_steps: False
+
+ trainer:
+ benchmark: True
\ No newline at end of file
diff --git a/latent-diffusion/configs/latent-diffusion/cin-ldm-vq-f8.yaml b/latent-diffusion/configs/latent-diffusion/cin-ldm-vq-f8.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..b8cd9e2ef5d26870bdbb26bf04a9b47aaa78feeb
--- /dev/null
+++ b/latent-diffusion/configs/latent-diffusion/cin-ldm-vq-f8.yaml
@@ -0,0 +1,98 @@
+model:
+ base_learning_rate: 1.0e-06
+ target: ldm.models.diffusion.ddpm.LatentDiffusion
+ params:
+ linear_start: 0.0015
+ linear_end: 0.0195
+ num_timesteps_cond: 1
+ log_every_t: 200
+ timesteps: 1000
+ first_stage_key: image
+ cond_stage_key: class_label
+ image_size: 32
+ channels: 4
+ cond_stage_trainable: true
+ conditioning_key: crossattn
+ monitor: val/loss_simple_ema
+ unet_config:
+ target: ldm.modules.diffusionmodules.openaimodel.UNetModel
+ params:
+ image_size: 32
+ in_channels: 4
+ out_channels: 4
+ model_channels: 256
+ attention_resolutions:
+ #note: this isn\t actually the resolution but
+ # the downsampling factor, i.e. this corresnponds to
+ # attention on spatial resolution 8,16,32, as the
+ # spatial reolution of the latents is 32 for f8
+ - 4
+ - 2
+ - 1
+ num_res_blocks: 2
+ channel_mult:
+ - 1
+ - 2
+ - 4
+ num_head_channels: 32
+ use_spatial_transformer: true
+ transformer_depth: 1
+ context_dim: 512
+ first_stage_config:
+ target: ldm.models.autoencoder.VQModelInterface
+ params:
+ embed_dim: 4
+ n_embed: 16384
+ ckpt_path: configs/first_stage_models/vq-f8/model.yaml
+ ddconfig:
+ double_z: false
+ z_channels: 4
+ resolution: 256
+ in_channels: 3
+ out_ch: 3
+ ch: 128
+ ch_mult:
+ - 1
+ - 2
+ - 2
+ - 4
+ num_res_blocks: 2
+ attn_resolutions:
+ - 32
+ dropout: 0.0
+ lossconfig:
+ target: torch.nn.Identity
+ cond_stage_config:
+ target: ldm.modules.encoders.modules.ClassEmbedder
+ params:
+ embed_dim: 512
+ key: class_label
+data:
+ target: main.DataModuleFromConfig
+ params:
+ batch_size: 64
+ num_workers: 12
+ wrap: false
+ train:
+ target: ldm.data.imagenet.ImageNetTrain
+ params:
+ config:
+ size: 256
+ validation:
+ target: ldm.data.imagenet.ImageNetValidation
+ params:
+ config:
+ size: 256
+
+
+lightning:
+ callbacks:
+ image_logger:
+ target: main.ImageLogger
+ params:
+ batch_frequency: 5000
+ max_images: 8
+ increase_log_steps: False
+
+ trainer:
+ benchmark: True
\ No newline at end of file
diff --git a/latent-diffusion/configs/latent-diffusion/cin256-v2.yaml b/latent-diffusion/configs/latent-diffusion/cin256-v2.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..b7c1aa240c740d1e5b7693f9543f996d727a302d
--- /dev/null
+++ b/latent-diffusion/configs/latent-diffusion/cin256-v2.yaml
@@ -0,0 +1,68 @@
+model:
+ base_learning_rate: 0.0001
+ target: ldm.models.diffusion.ddpm.LatentDiffusion
+ params:
+ linear_start: 0.0015
+ linear_end: 0.0195
+ num_timesteps_cond: 1
+ log_every_t: 200
+ timesteps: 1000
+ first_stage_key: image
+ cond_stage_key: class_label
+ image_size: 64
+ channels: 3
+ cond_stage_trainable: true
+ conditioning_key: crossattn
+ monitor: val/loss
+ use_ema: False
+
+ unet_config:
+ target: ldm.modules.diffusionmodules.openaimodel.UNetModel
+ params:
+ image_size: 64
+ in_channels: 3
+ out_channels: 3
+ model_channels: 192
+ attention_resolutions:
+ - 8
+ - 4
+ - 2
+ num_res_blocks: 2
+ channel_mult:
+ - 1
+ - 2
+ - 3
+ - 5
+ num_heads: 1
+ use_spatial_transformer: true
+ transformer_depth: 1
+ context_dim: 512
+
+ first_stage_config:
+ target: ldm.models.autoencoder.VQModelInterface
+ params:
+ embed_dim: 3
+ n_embed: 8192
+ ddconfig:
+ double_z: false
+ z_channels: 3
+ resolution: 256
+ in_channels: 3
+ out_ch: 3
+ ch: 128
+ ch_mult:
+ - 1
+ - 2
+ - 4
+ num_res_blocks: 2
+ attn_resolutions: []
+ dropout: 0.0
+ lossconfig:
+ target: torch.nn.Identity
+
+ cond_stage_config:
+ target: ldm.modules.encoders.modules.ClassEmbedder
+ params:
+ n_classes: 1001
+ embed_dim: 512
+ key: class_label
diff --git a/latent-diffusion/configs/latent-diffusion/ffhq-ldm-vq-4.yaml b/latent-diffusion/configs/latent-diffusion/ffhq-ldm-vq-4.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..1899e30f77222142d7b33f45a6dcff086a31e174
--- /dev/null
+++ b/latent-diffusion/configs/latent-diffusion/ffhq-ldm-vq-4.yaml
@@ -0,0 +1,85 @@
+model:
+ base_learning_rate: 2.0e-06
+ target: ldm.models.diffusion.ddpm.LatentDiffusion
+ params:
+ linear_start: 0.0015
+ linear_end: 0.0195
+ num_timesteps_cond: 1
+ log_every_t: 200
+ timesteps: 1000
+ first_stage_key: image
+ image_size: 64
+ channels: 3
+ monitor: val/loss_simple_ema
+ unet_config:
+ target: ldm.modules.diffusionmodules.openaimodel.UNetModel
+ params:
+ image_size: 64
+ in_channels: 3
+ out_channels: 3
+ model_channels: 224
+ attention_resolutions:
+ # note: this isn\t actually the resolution but
+ # the downsampling factor, i.e. this corresnponds to
+ # attention on spatial resolution 8,16,32, as the
+ # spatial reolution of the latents is 64 for f4
+ - 8
+ - 4
+ - 2
+ num_res_blocks: 2
+ channel_mult:
+ - 1
+ - 2
+ - 3
+ - 4
+ num_head_channels: 32
+ first_stage_config:
+ target: ldm.models.autoencoder.VQModelInterface
+ params:
+ embed_dim: 3
+ n_embed: 8192
+ ckpt_path: configs/first_stage_models/vq-f4/model.yaml
+ ddconfig:
+ double_z: false
+ z_channels: 3
+ resolution: 256
+ in_channels: 3
+ out_ch: 3
+ ch: 128
+ ch_mult:
+ - 1
+ - 2
+ - 4
+ num_res_blocks: 2
+ attn_resolutions: []
+ dropout: 0.0
+ lossconfig:
+ target: torch.nn.Identity
+ cond_stage_config: __is_unconditional__
+data:
+ target: main.DataModuleFromConfig
+ params:
+ batch_size: 42
+ num_workers: 5
+ wrap: false
+ train:
+ target: taming.data.faceshq.FFHQTrain
+ params:
+ size: 256
+ validation:
+ target: taming.data.faceshq.FFHQValidation
+ params:
+ size: 256
+
+
+lightning:
+ callbacks:
+ image_logger:
+ target: main.ImageLogger
+ params:
+ batch_frequency: 5000
+ max_images: 8
+ increase_log_steps: False
+
+ trainer:
+ benchmark: True
\ No newline at end of file
diff --git a/latent-diffusion/configs/latent-diffusion/lsun_bedrooms-ldm-vq-4.yaml b/latent-diffusion/configs/latent-diffusion/lsun_bedrooms-ldm-vq-4.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..c4ca66c16c00a0c3fd13ae1ad03635039161e7ad
--- /dev/null
+++ b/latent-diffusion/configs/latent-diffusion/lsun_bedrooms-ldm-vq-4.yaml
@@ -0,0 +1,85 @@
+model:
+ base_learning_rate: 2.0e-06
+ target: ldm.models.diffusion.ddpm.LatentDiffusion
+ params:
+ linear_start: 0.0015
+ linear_end: 0.0195
+ num_timesteps_cond: 1
+ log_every_t: 200
+ timesteps: 1000
+ first_stage_key: image
+ image_size: 64
+ channels: 3
+ monitor: val/loss_simple_ema
+ unet_config:
+ target: ldm.modules.diffusionmodules.openaimodel.UNetModel
+ params:
+ image_size: 64
+ in_channels: 3
+ out_channels: 3
+ model_channels: 224
+ attention_resolutions:
+ # note: this isn\t actually the resolution but
+ # the downsampling factor, i.e. this corresnponds to
+ # attention on spatial resolution 8,16,32, as the
+ # spatial reolution of the latents is 64 for f4
+ - 8
+ - 4
+ - 2
+ num_res_blocks: 2
+ channel_mult:
+ - 1
+ - 2
+ - 3
+ - 4
+ num_head_channels: 32
+ first_stage_config:
+ target: ldm.models.autoencoder.VQModelInterface
+ params:
+ ckpt_path: configs/first_stage_models/vq-f4/model.yaml
+ embed_dim: 3
+ n_embed: 8192
+ ddconfig:
+ double_z: false
+ z_channels: 3
+ resolution: 256
+ in_channels: 3
+ out_ch: 3
+ ch: 128
+ ch_mult:
+ - 1
+ - 2
+ - 4
+ num_res_blocks: 2
+ attn_resolutions: []
+ dropout: 0.0
+ lossconfig:
+ target: torch.nn.Identity
+ cond_stage_config: __is_unconditional__
+data:
+ target: main.DataModuleFromConfig
+ params:
+ batch_size: 48
+ num_workers: 5
+ wrap: false
+ train:
+ target: ldm.data.lsun.LSUNBedroomsTrain
+ params:
+ size: 256
+ validation:
+ target: ldm.data.lsun.LSUNBedroomsValidation
+ params:
+ size: 256
+
+
+lightning:
+ callbacks:
+ image_logger:
+ target: main.ImageLogger
+ params:
+ batch_frequency: 5000
+ max_images: 8
+ increase_log_steps: False
+
+ trainer:
+ benchmark: True
\ No newline at end of file
diff --git a/latent-diffusion/configs/latent-diffusion/lsun_churches-ldm-kl-8.yaml b/latent-diffusion/configs/latent-diffusion/lsun_churches-ldm-kl-8.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..18dc8c2d9cfb925b0f45e5b89186d71e3274b086
--- /dev/null
+++ b/latent-diffusion/configs/latent-diffusion/lsun_churches-ldm-kl-8.yaml
@@ -0,0 +1,91 @@
+model:
+ base_learning_rate: 5.0e-5 # set to target_lr by starting main.py with '--scale_lr False'
+ target: ldm.models.diffusion.ddpm.LatentDiffusion
+ params:
+ linear_start: 0.0015
+ linear_end: 0.0155
+ num_timesteps_cond: 1
+ log_every_t: 200
+ timesteps: 1000
+ loss_type: l1
+ first_stage_key: "image"
+ cond_stage_key: "image"
+ image_size: 32
+ channels: 4
+ cond_stage_trainable: False
+ concat_mode: False
+ scale_by_std: True
+ monitor: 'val/loss_simple_ema'
+
+ scheduler_config: # 10000 warmup steps
+ target: ldm.lr_scheduler.LambdaLinearScheduler
+ params:
+ warm_up_steps: [10000]
+ cycle_lengths: [10000000000000]
+ f_start: [1.e-6]
+ f_max: [1.]
+ f_min: [ 1.]
+
+ unet_config:
+ target: ldm.modules.diffusionmodules.openaimodel.UNetModel
+ params:
+ image_size: 32
+ in_channels: 4
+ out_channels: 4
+ model_channels: 192
+ attention_resolutions: [ 1, 2, 4, 8 ] # 32, 16, 8, 4
+ num_res_blocks: 2
+ channel_mult: [ 1,2,2,4,4 ] # 32, 16, 8, 4, 2
+ num_heads: 8
+ use_scale_shift_norm: True
+ resblock_updown: True
+
+ first_stage_config:
+ target: ldm.models.autoencoder.AutoencoderKL
+ params:
+ embed_dim: 4
+ monitor: "val/rec_loss"
+ ckpt_path: "models/first_stage_models/kl-f8/model.ckpt"
+ ddconfig:
+ double_z: True
+ z_channels: 4
+ resolution: 256
+ in_channels: 3
+ out_ch: 3
+ ch: 128
+ ch_mult: [ 1,2,4,4 ] # num_down = len(ch_mult)-1
+ num_res_blocks: 2
+ attn_resolutions: [ ]
+ dropout: 0.0
+ lossconfig:
+ target: torch.nn.Identity
+
+ cond_stage_config: "__is_unconditional__"
+
+data:
+ target: main.DataModuleFromConfig
+ params:
+ batch_size: 96
+ num_workers: 5
+ wrap: False
+ train:
+ target: ldm.data.lsun.LSUNChurchesTrain
+ params:
+ size: 256
+ validation:
+ target: ldm.data.lsun.LSUNChurchesValidation
+ params:
+ size: 256
+
+lightning:
+ callbacks:
+ image_logger:
+ target: main.ImageLogger
+ params:
+ batch_frequency: 5000
+ max_images: 8
+ increase_log_steps: False
+
+
+ trainer:
+ benchmark: True
\ No newline at end of file
diff --git a/latent-diffusion/configs/latent-diffusion/txt2img-1p4B-eval.yaml b/latent-diffusion/configs/latent-diffusion/txt2img-1p4B-eval.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..8e331cbfdff7ece1ef9008754e97f60f68585a07
--- /dev/null
+++ b/latent-diffusion/configs/latent-diffusion/txt2img-1p4B-eval.yaml
@@ -0,0 +1,71 @@
+model:
+ base_learning_rate: 5.0e-05
+ target: ldm.models.diffusion.ddpm.LatentDiffusion
+ params:
+ linear_start: 0.00085
+ linear_end: 0.012
+ num_timesteps_cond: 1
+ log_every_t: 200
+ timesteps: 1000
+ first_stage_key: image
+ cond_stage_key: caption
+ image_size: 32
+ channels: 4
+ cond_stage_trainable: true
+ conditioning_key: crossattn
+ monitor: val/loss_simple_ema
+ scale_factor: 0.18215
+ use_ema: False
+
+ unet_config:
+ target: ldm.modules.diffusionmodules.openaimodel.UNetModel
+ params:
+ image_size: 32
+ in_channels: 4
+ out_channels: 4
+ model_channels: 320
+ attention_resolutions:
+ - 4
+ - 2
+ - 1
+ num_res_blocks: 2
+ channel_mult:
+ - 1
+ - 2
+ - 4
+ - 4
+ num_heads: 8
+ use_spatial_transformer: true
+ transformer_depth: 1
+ context_dim: 1280
+ use_checkpoint: true
+ legacy: False
+
+ first_stage_config:
+ target: ldm.models.autoencoder.AutoencoderKL
+ params:
+ embed_dim: 4
+ monitor: val/rec_loss
+ ddconfig:
+ double_z: true
+ z_channels: 4
+ resolution: 256
+ in_channels: 3
+ out_ch: 3
+ ch: 128
+ ch_mult:
+ - 1
+ - 2
+ - 4
+ - 4
+ num_res_blocks: 2
+ attn_resolutions: []
+ dropout: 0.0
+ lossconfig:
+ target: torch.nn.Identity
+
+ cond_stage_config:
+ target: ldm.modules.encoders.modules.BERTEmbedder
+ params:
+ n_embed: 1280
+ n_layer: 32
diff --git a/latent-diffusion/environment.yaml b/latent-diffusion/environment.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..f36b0e17dfd2484d9686b34b272ff363039d1214
--- /dev/null
+++ b/latent-diffusion/environment.yaml
@@ -0,0 +1,27 @@
+name: ldm
+channels:
+ - pytorch
+ - defaults
+dependencies:
+ - python=3.8.5
+ - pip=20.3
+ - cudatoolkit=11.0
+ - pytorch=1.7.0
+ - torchvision=0.8.1
+ - numpy=1.19.2
+ - pip:
+ - albumentations==0.4.3
+ - opencv-python==4.1.2.30
+ - pudb==2019.2
+ - imageio==2.9.0
+ - imageio-ffmpeg==0.4.2
+ - pytorch-lightning==1.4.2
+ - omegaconf==2.1.1
+ - test-tube>=0.7.5
+ - streamlit>=0.73.1
+ - einops==0.3.0
+ - torch-fidelity==0.3.0
+ - transformers==4.3.1
+ - -e git+https://github.com/CompVis/taming-transformers.git@master#egg=taming-transformers
+ - -e git+https://github.com/openai/CLIP.git@main#egg=clip
+ - -e .
\ No newline at end of file
diff --git a/latent-diffusion/ldm/__pycache__/util.cpython-39.pyc b/latent-diffusion/ldm/__pycache__/util.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..299dbe8237dd7e0377cb61c9f313af3949bb7a13
Binary files /dev/null and b/latent-diffusion/ldm/__pycache__/util.cpython-39.pyc differ
diff --git a/latent-diffusion/ldm/data/__init__.py b/latent-diffusion/ldm/data/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/latent-diffusion/ldm/data/base.py b/latent-diffusion/ldm/data/base.py
new file mode 100644
index 0000000000000000000000000000000000000000..b196c2f7aa583a3e8bc4aad9f943df0c4dae0da7
--- /dev/null
+++ b/latent-diffusion/ldm/data/base.py
@@ -0,0 +1,23 @@
+from abc import abstractmethod
+from torch.utils.data import Dataset, ConcatDataset, ChainDataset, IterableDataset
+
+
+class Txt2ImgIterableBaseDataset(IterableDataset):
+ '''
+ Define an interface to make the IterableDatasets for text2img data chainable
+ '''
+ def __init__(self, num_records=0, valid_ids=None, size=256):
+ super().__init__()
+ self.num_records = num_records
+ self.valid_ids = valid_ids
+ self.sample_ids = valid_ids
+ self.size = size
+
+ print(f'{self.__class__.__name__} dataset contains {self.__len__()} examples.')
+
+ def __len__(self):
+ return self.num_records
+
+ @abstractmethod
+ def __iter__(self):
+ pass
\ No newline at end of file
diff --git a/latent-diffusion/ldm/data/imagenet.py b/latent-diffusion/ldm/data/imagenet.py
new file mode 100644
index 0000000000000000000000000000000000000000..1c473f9c6965b22315dbb289eff8247c71bdc790
--- /dev/null
+++ b/latent-diffusion/ldm/data/imagenet.py
@@ -0,0 +1,394 @@
+import os, yaml, pickle, shutil, tarfile, glob
+import cv2
+import albumentations
+import PIL
+import numpy as np
+import torchvision.transforms.functional as TF
+from omegaconf import OmegaConf
+from functools import partial
+from PIL import Image
+from tqdm import tqdm
+from torch.utils.data import Dataset, Subset
+
+import taming.data.utils as tdu
+from taming.data.imagenet import str_to_indices, give_synsets_from_indices, download, retrieve
+from taming.data.imagenet import ImagePaths
+
+from ldm.modules.image_degradation import degradation_fn_bsr, degradation_fn_bsr_light
+
+
+def synset2idx(path_to_yaml="data/index_synset.yaml"):
+ with open(path_to_yaml) as f:
+ di2s = yaml.load(f)
+ return dict((v,k) for k,v in di2s.items())
+
+
+class ImageNetBase(Dataset):
+ def __init__(self, config=None):
+ self.config = config or OmegaConf.create()
+ if not type(self.config)==dict:
+ self.config = OmegaConf.to_container(self.config)
+ self.keep_orig_class_label = self.config.get("keep_orig_class_label", False)
+ self.process_images = True # if False we skip loading & processing images and self.data contains filepaths
+ self._prepare()
+ self._prepare_synset_to_human()
+ self._prepare_idx_to_synset()
+ self._prepare_human_to_integer_label()
+ self._load()
+
+ def __len__(self):
+ return len(self.data)
+
+ def __getitem__(self, i):
+ return self.data[i]
+
+ def _prepare(self):
+ raise NotImplementedError()
+
+ def _filter_relpaths(self, relpaths):
+ ignore = set([
+ "n06596364_9591.JPEG",
+ ])
+ relpaths = [rpath for rpath in relpaths if not rpath.split("/")[-1] in ignore]
+ if "sub_indices" in self.config:
+ indices = str_to_indices(self.config["sub_indices"])
+ synsets = give_synsets_from_indices(indices, path_to_yaml=self.idx2syn) # returns a list of strings
+ self.synset2idx = synset2idx(path_to_yaml=self.idx2syn)
+ files = []
+ for rpath in relpaths:
+ syn = rpath.split("/")[0]
+ if syn in synsets:
+ files.append(rpath)
+ return files
+ else:
+ return relpaths
+
+ def _prepare_synset_to_human(self):
+ SIZE = 2655750
+ URL = "https://heibox.uni-heidelberg.de/f/9f28e956cd304264bb82/?dl=1"
+ self.human_dict = os.path.join(self.root, "synset_human.txt")
+ if (not os.path.exists(self.human_dict) or
+ not os.path.getsize(self.human_dict)==SIZE):
+ download(URL, self.human_dict)
+
+ def _prepare_idx_to_synset(self):
+ URL = "https://heibox.uni-heidelberg.de/f/d835d5b6ceda4d3aa910/?dl=1"
+ self.idx2syn = os.path.join(self.root, "index_synset.yaml")
+ if (not os.path.exists(self.idx2syn)):
+ download(URL, self.idx2syn)
+
+ def _prepare_human_to_integer_label(self):
+ URL = "https://heibox.uni-heidelberg.de/f/2362b797d5be43b883f6/?dl=1"
+ self.human2integer = os.path.join(self.root, "imagenet1000_clsidx_to_labels.txt")
+ if (not os.path.exists(self.human2integer)):
+ download(URL, self.human2integer)
+ with open(self.human2integer, "r") as f:
+ lines = f.read().splitlines()
+ assert len(lines) == 1000
+ self.human2integer_dict = dict()
+ for line in lines:
+ value, key = line.split(":")
+ self.human2integer_dict[key] = int(value)
+
+ def _load(self):
+ with open(self.txt_filelist, "r") as f:
+ self.relpaths = f.read().splitlines()
+ l1 = len(self.relpaths)
+ self.relpaths = self._filter_relpaths(self.relpaths)
+ print("Removed {} files from filelist during filtering.".format(l1 - len(self.relpaths)))
+
+ self.synsets = [p.split("/")[0] for p in self.relpaths]
+ self.abspaths = [os.path.join(self.datadir, p) for p in self.relpaths]
+
+ unique_synsets = np.unique(self.synsets)
+ class_dict = dict((synset, i) for i, synset in enumerate(unique_synsets))
+ if not self.keep_orig_class_label:
+ self.class_labels = [class_dict[s] for s in self.synsets]
+ else:
+ self.class_labels = [self.synset2idx[s] for s in self.synsets]
+
+ with open(self.human_dict, "r") as f:
+ human_dict = f.read().splitlines()
+ human_dict = dict(line.split(maxsplit=1) for line in human_dict)
+
+ self.human_labels = [human_dict[s] for s in self.synsets]
+
+ labels = {
+ "relpath": np.array(self.relpaths),
+ "synsets": np.array(self.synsets),
+ "class_label": np.array(self.class_labels),
+ "human_label": np.array(self.human_labels),
+ }
+
+ if self.process_images:
+ self.size = retrieve(self.config, "size", default=256)
+ self.data = ImagePaths(self.abspaths,
+ labels=labels,
+ size=self.size,
+ random_crop=self.random_crop,
+ )
+ else:
+ self.data = self.abspaths
+
+
+class ImageNetTrain(ImageNetBase):
+ NAME = "ILSVRC2012_train"
+ URL = "http://www.image-net.org/challenges/LSVRC/2012/"
+ AT_HASH = "a306397ccf9c2ead27155983c254227c0fd938e2"
+ FILES = [
+ "ILSVRC2012_img_train.tar",
+ ]
+ SIZES = [
+ 147897477120,
+ ]
+
+ def __init__(self, process_images=True, data_root=None, **kwargs):
+ self.process_images = process_images
+ self.data_root = data_root
+ super().__init__(**kwargs)
+
+ def _prepare(self):
+ if self.data_root:
+ self.root = os.path.join(self.data_root, self.NAME)
+ else:
+ cachedir = os.environ.get("XDG_CACHE_HOME", os.path.expanduser("~/.cache"))
+ self.root = os.path.join(cachedir, "autoencoders/data", self.NAME)
+
+ self.datadir = os.path.join(self.root, "data")
+ self.txt_filelist = os.path.join(self.root, "filelist.txt")
+ self.expected_length = 1281167
+ self.random_crop = retrieve(self.config, "ImageNetTrain/random_crop",
+ default=True)
+ if not tdu.is_prepared(self.root):
+ # prep
+ print("Preparing dataset {} in {}".format(self.NAME, self.root))
+
+ datadir = self.datadir
+ if not os.path.exists(datadir):
+ path = os.path.join(self.root, self.FILES[0])
+ if not os.path.exists(path) or not os.path.getsize(path)==self.SIZES[0]:
+ import academictorrents as at
+ atpath = at.get(self.AT_HASH, datastore=self.root)
+ assert atpath == path
+
+ print("Extracting {} to {}".format(path, datadir))
+ os.makedirs(datadir, exist_ok=True)
+ with tarfile.open(path, "r:") as tar:
+ tar.extractall(path=datadir)
+
+ print("Extracting sub-tars.")
+ subpaths = sorted(glob.glob(os.path.join(datadir, "*.tar")))
+ for subpath in tqdm(subpaths):
+ subdir = subpath[:-len(".tar")]
+ os.makedirs(subdir, exist_ok=True)
+ with tarfile.open(subpath, "r:") as tar:
+ tar.extractall(path=subdir)
+
+ filelist = glob.glob(os.path.join(datadir, "**", "*.JPEG"))
+ filelist = [os.path.relpath(p, start=datadir) for p in filelist]
+ filelist = sorted(filelist)
+ filelist = "\n".join(filelist)+"\n"
+ with open(self.txt_filelist, "w") as f:
+ f.write(filelist)
+
+ tdu.mark_prepared(self.root)
+
+
+class ImageNetValidation(ImageNetBase):
+ NAME = "ILSVRC2012_validation"
+ URL = "http://www.image-net.org/challenges/LSVRC/2012/"
+ AT_HASH = "5d6d0df7ed81efd49ca99ea4737e0ae5e3a5f2e5"
+ VS_URL = "https://heibox.uni-heidelberg.de/f/3e0f6e9c624e45f2bd73/?dl=1"
+ FILES = [
+ "ILSVRC2012_img_val.tar",
+ "validation_synset.txt",
+ ]
+ SIZES = [
+ 6744924160,
+ 1950000,
+ ]
+
+ def __init__(self, process_images=True, data_root=None, **kwargs):
+ self.data_root = data_root
+ self.process_images = process_images
+ super().__init__(**kwargs)
+
+ def _prepare(self):
+ if self.data_root:
+ self.root = os.path.join(self.data_root, self.NAME)
+ else:
+ cachedir = os.environ.get("XDG_CACHE_HOME", os.path.expanduser("~/.cache"))
+ self.root = os.path.join(cachedir, "autoencoders/data", self.NAME)
+ self.datadir = os.path.join(self.root, "data")
+ self.txt_filelist = os.path.join(self.root, "filelist.txt")
+ self.expected_length = 50000
+ self.random_crop = retrieve(self.config, "ImageNetValidation/random_crop",
+ default=False)
+ if not tdu.is_prepared(self.root):
+ # prep
+ print("Preparing dataset {} in {}".format(self.NAME, self.root))
+
+ datadir = self.datadir
+ if not os.path.exists(datadir):
+ path = os.path.join(self.root, self.FILES[0])
+ if not os.path.exists(path) or not os.path.getsize(path)==self.SIZES[0]:
+ import academictorrents as at
+ atpath = at.get(self.AT_HASH, datastore=self.root)
+ assert atpath == path
+
+ print("Extracting {} to {}".format(path, datadir))
+ os.makedirs(datadir, exist_ok=True)
+ with tarfile.open(path, "r:") as tar:
+ tar.extractall(path=datadir)
+
+ vspath = os.path.join(self.root, self.FILES[1])
+ if not os.path.exists(vspath) or not os.path.getsize(vspath)==self.SIZES[1]:
+ download(self.VS_URL, vspath)
+
+ with open(vspath, "r") as f:
+ synset_dict = f.read().splitlines()
+ synset_dict = dict(line.split() for line in synset_dict)
+
+ print("Reorganizing into synset folders")
+ synsets = np.unique(list(synset_dict.values()))
+ for s in synsets:
+ os.makedirs(os.path.join(datadir, s), exist_ok=True)
+ for k, v in synset_dict.items():
+ src = os.path.join(datadir, k)
+ dst = os.path.join(datadir, v)
+ shutil.move(src, dst)
+
+ filelist = glob.glob(os.path.join(datadir, "**", "*.JPEG"))
+ filelist = [os.path.relpath(p, start=datadir) for p in filelist]
+ filelist = sorted(filelist)
+ filelist = "\n".join(filelist)+"\n"
+ with open(self.txt_filelist, "w") as f:
+ f.write(filelist)
+
+ tdu.mark_prepared(self.root)
+
+
+
+class ImageNetSR(Dataset):
+ def __init__(self, size=None,
+ degradation=None, downscale_f=4, min_crop_f=0.5, max_crop_f=1.,
+ random_crop=True):
+ """
+ Imagenet Superresolution Dataloader
+ Performs following ops in order:
+ 1. crops a crop of size s from image either as random or center crop
+ 2. resizes crop to size with cv2.area_interpolation
+ 3. degrades resized crop with degradation_fn
+
+ :param size: resizing to size after cropping
+ :param degradation: degradation_fn, e.g. cv_bicubic or bsrgan_light
+ :param downscale_f: Low Resolution Downsample factor
+ :param min_crop_f: determines crop size s,
+ where s = c * min_img_side_len with c sampled from interval (min_crop_f, max_crop_f)
+ :param max_crop_f: ""
+ :param data_root:
+ :param random_crop:
+ """
+ self.base = self.get_base()
+ assert size
+ assert (size / downscale_f).is_integer()
+ self.size = size
+ self.LR_size = int(size / downscale_f)
+ self.min_crop_f = min_crop_f
+ self.max_crop_f = max_crop_f
+ assert(max_crop_f <= 1.)
+ self.center_crop = not random_crop
+
+ self.image_rescaler = albumentations.SmallestMaxSize(max_size=size, interpolation=cv2.INTER_AREA)
+
+ self.pil_interpolation = False # gets reset later if incase interp_op is from pillow
+
+ if degradation == "bsrgan":
+ self.degradation_process = partial(degradation_fn_bsr, sf=downscale_f)
+
+ elif degradation == "bsrgan_light":
+ self.degradation_process = partial(degradation_fn_bsr_light, sf=downscale_f)
+
+ else:
+ interpolation_fn = {
+ "cv_nearest": cv2.INTER_NEAREST,
+ "cv_bilinear": cv2.INTER_LINEAR,
+ "cv_bicubic": cv2.INTER_CUBIC,
+ "cv_area": cv2.INTER_AREA,
+ "cv_lanczos": cv2.INTER_LANCZOS4,
+ "pil_nearest": PIL.Image.NEAREST,
+ "pil_bilinear": PIL.Image.BILINEAR,
+ "pil_bicubic": PIL.Image.BICUBIC,
+ "pil_box": PIL.Image.BOX,
+ "pil_hamming": PIL.Image.HAMMING,
+ "pil_lanczos": PIL.Image.LANCZOS,
+ }[degradation]
+
+ self.pil_interpolation = degradation.startswith("pil_")
+
+ if self.pil_interpolation:
+ self.degradation_process = partial(TF.resize, size=self.LR_size, interpolation=interpolation_fn)
+
+ else:
+ self.degradation_process = albumentations.SmallestMaxSize(max_size=self.LR_size,
+ interpolation=interpolation_fn)
+
+ def __len__(self):
+ return len(self.base)
+
+ def __getitem__(self, i):
+ example = self.base[i]
+ image = Image.open(example["file_path_"])
+
+ if not image.mode == "RGB":
+ image = image.convert("RGB")
+
+ image = np.array(image).astype(np.uint8)
+
+ min_side_len = min(image.shape[:2])
+ crop_side_len = min_side_len * np.random.uniform(self.min_crop_f, self.max_crop_f, size=None)
+ crop_side_len = int(crop_side_len)
+
+ if self.center_crop:
+ self.cropper = albumentations.CenterCrop(height=crop_side_len, width=crop_side_len)
+
+ else:
+ self.cropper = albumentations.RandomCrop(height=crop_side_len, width=crop_side_len)
+
+ image = self.cropper(image=image)["image"]
+ image = self.image_rescaler(image=image)["image"]
+
+ if self.pil_interpolation:
+ image_pil = PIL.Image.fromarray(image)
+ LR_image = self.degradation_process(image_pil)
+ LR_image = np.array(LR_image).astype(np.uint8)
+
+ else:
+ LR_image = self.degradation_process(image=image)["image"]
+
+ example["image"] = (image/127.5 - 1.0).astype(np.float32)
+ example["LR_image"] = (LR_image/127.5 - 1.0).astype(np.float32)
+
+ return example
+
+
+class ImageNetSRTrain(ImageNetSR):
+ def __init__(self, **kwargs):
+ super().__init__(**kwargs)
+
+ def get_base(self):
+ with open("data/imagenet_train_hr_indices.p", "rb") as f:
+ indices = pickle.load(f)
+ dset = ImageNetTrain(process_images=False,)
+ return Subset(dset, indices)
+
+
+class ImageNetSRValidation(ImageNetSR):
+ def __init__(self, **kwargs):
+ super().__init__(**kwargs)
+
+ def get_base(self):
+ with open("data/imagenet_val_hr_indices.p", "rb") as f:
+ indices = pickle.load(f)
+ dset = ImageNetValidation(process_images=False,)
+ return Subset(dset, indices)
diff --git a/latent-diffusion/ldm/data/lsun.py b/latent-diffusion/ldm/data/lsun.py
new file mode 100644
index 0000000000000000000000000000000000000000..6256e45715ff0b57c53f985594d27cbbbff0e68e
--- /dev/null
+++ b/latent-diffusion/ldm/data/lsun.py
@@ -0,0 +1,92 @@
+import os
+import numpy as np
+import PIL
+from PIL import Image
+from torch.utils.data import Dataset
+from torchvision import transforms
+
+
+class LSUNBase(Dataset):
+ def __init__(self,
+ txt_file,
+ data_root,
+ size=None,
+ interpolation="bicubic",
+ flip_p=0.5
+ ):
+ self.data_paths = txt_file
+ self.data_root = data_root
+ with open(self.data_paths, "r") as f:
+ self.image_paths = f.read().splitlines()
+ self._length = len(self.image_paths)
+ self.labels = {
+ "relative_file_path_": [l for l in self.image_paths],
+ "file_path_": [os.path.join(self.data_root, l)
+ for l in self.image_paths],
+ }
+
+ self.size = size
+ self.interpolation = {"linear": PIL.Image.LINEAR,
+ "bilinear": PIL.Image.BILINEAR,
+ "bicubic": PIL.Image.BICUBIC,
+ "lanczos": PIL.Image.LANCZOS,
+ }[interpolation]
+ self.flip = transforms.RandomHorizontalFlip(p=flip_p)
+
+ def __len__(self):
+ return self._length
+
+ def __getitem__(self, i):
+ example = dict((k, self.labels[k][i]) for k in self.labels)
+ image = Image.open(example["file_path_"])
+ if not image.mode == "RGB":
+ image = image.convert("RGB")
+
+ # default to score-sde preprocessing
+ img = np.array(image).astype(np.uint8)
+ crop = min(img.shape[0], img.shape[1])
+ h, w, = img.shape[0], img.shape[1]
+ img = img[(h - crop) // 2:(h + crop) // 2,
+ (w - crop) // 2:(w + crop) // 2]
+
+ image = Image.fromarray(img)
+ if self.size is not None:
+ image = image.resize((self.size, self.size), resample=self.interpolation)
+
+ image = self.flip(image)
+ image = np.array(image).astype(np.uint8)
+ example["image"] = (image / 127.5 - 1.0).astype(np.float32)
+ return example
+
+
+class LSUNChurchesTrain(LSUNBase):
+ def __init__(self, **kwargs):
+ super().__init__(txt_file="data/lsun/church_outdoor_train.txt", data_root="data/lsun/churches", **kwargs)
+
+
+class LSUNChurchesValidation(LSUNBase):
+ def __init__(self, flip_p=0., **kwargs):
+ super().__init__(txt_file="data/lsun/church_outdoor_val.txt", data_root="data/lsun/churches",
+ flip_p=flip_p, **kwargs)
+
+
+class LSUNBedroomsTrain(LSUNBase):
+ def __init__(self, **kwargs):
+ super().__init__(txt_file="data/lsun/bedrooms_train.txt", data_root="data/lsun/bedrooms", **kwargs)
+
+
+class LSUNBedroomsValidation(LSUNBase):
+ def __init__(self, flip_p=0.0, **kwargs):
+ super().__init__(txt_file="data/lsun/bedrooms_val.txt", data_root="data/lsun/bedrooms",
+ flip_p=flip_p, **kwargs)
+
+
+class LSUNCatsTrain(LSUNBase):
+ def __init__(self, **kwargs):
+ super().__init__(txt_file="data/lsun/cat_train.txt", data_root="data/lsun/cats", **kwargs)
+
+
+class LSUNCatsValidation(LSUNBase):
+ def __init__(self, flip_p=0., **kwargs):
+ super().__init__(txt_file="data/lsun/cat_val.txt", data_root="data/lsun/cats",
+ flip_p=flip_p, **kwargs)
diff --git a/latent-diffusion/ldm/lr_scheduler.py b/latent-diffusion/ldm/lr_scheduler.py
new file mode 100644
index 0000000000000000000000000000000000000000..be39da9ca6dacc22bf3df9c7389bbb403a4a3ade
--- /dev/null
+++ b/latent-diffusion/ldm/lr_scheduler.py
@@ -0,0 +1,98 @@
+import numpy as np
+
+
+class LambdaWarmUpCosineScheduler:
+ """
+ note: use with a base_lr of 1.0
+ """
+ def __init__(self, warm_up_steps, lr_min, lr_max, lr_start, max_decay_steps, verbosity_interval=0):
+ self.lr_warm_up_steps = warm_up_steps
+ self.lr_start = lr_start
+ self.lr_min = lr_min
+ self.lr_max = lr_max
+ self.lr_max_decay_steps = max_decay_steps
+ self.last_lr = 0.
+ self.verbosity_interval = verbosity_interval
+
+ def schedule(self, n, **kwargs):
+ if self.verbosity_interval > 0:
+ if n % self.verbosity_interval == 0: print(f"current step: {n}, recent lr-multiplier: {self.last_lr}")
+ if n < self.lr_warm_up_steps:
+ lr = (self.lr_max - self.lr_start) / self.lr_warm_up_steps * n + self.lr_start
+ self.last_lr = lr
+ return lr
+ else:
+ t = (n - self.lr_warm_up_steps) / (self.lr_max_decay_steps - self.lr_warm_up_steps)
+ t = min(t, 1.0)
+ lr = self.lr_min + 0.5 * (self.lr_max - self.lr_min) * (
+ 1 + np.cos(t * np.pi))
+ self.last_lr = lr
+ return lr
+
+ def __call__(self, n, **kwargs):
+ return self.schedule(n,**kwargs)
+
+
+class LambdaWarmUpCosineScheduler2:
+ """
+ supports repeated iterations, configurable via lists
+ note: use with a base_lr of 1.0.
+ """
+ def __init__(self, warm_up_steps, f_min, f_max, f_start, cycle_lengths, verbosity_interval=0):
+ assert len(warm_up_steps) == len(f_min) == len(f_max) == len(f_start) == len(cycle_lengths)
+ self.lr_warm_up_steps = warm_up_steps
+ self.f_start = f_start
+ self.f_min = f_min
+ self.f_max = f_max
+ self.cycle_lengths = cycle_lengths
+ self.cum_cycles = np.cumsum([0] + list(self.cycle_lengths))
+ self.last_f = 0.
+ self.verbosity_interval = verbosity_interval
+
+ def find_in_interval(self, n):
+ interval = 0
+ for cl in self.cum_cycles[1:]:
+ if n <= cl:
+ return interval
+ interval += 1
+
+ def schedule(self, n, **kwargs):
+ cycle = self.find_in_interval(n)
+ n = n - self.cum_cycles[cycle]
+ if self.verbosity_interval > 0:
+ if n % self.verbosity_interval == 0: print(f"current step: {n}, recent lr-multiplier: {self.last_f}, "
+ f"current cycle {cycle}")
+ if n < self.lr_warm_up_steps[cycle]:
+ f = (self.f_max[cycle] - self.f_start[cycle]) / self.lr_warm_up_steps[cycle] * n + self.f_start[cycle]
+ self.last_f = f
+ return f
+ else:
+ t = (n - self.lr_warm_up_steps[cycle]) / (self.cycle_lengths[cycle] - self.lr_warm_up_steps[cycle])
+ t = min(t, 1.0)
+ f = self.f_min[cycle] + 0.5 * (self.f_max[cycle] - self.f_min[cycle]) * (
+ 1 + np.cos(t * np.pi))
+ self.last_f = f
+ return f
+
+ def __call__(self, n, **kwargs):
+ return self.schedule(n, **kwargs)
+
+
+class LambdaLinearScheduler(LambdaWarmUpCosineScheduler2):
+
+ def schedule(self, n, **kwargs):
+ cycle = self.find_in_interval(n)
+ n = n - self.cum_cycles[cycle]
+ if self.verbosity_interval > 0:
+ if n % self.verbosity_interval == 0: print(f"current step: {n}, recent lr-multiplier: {self.last_f}, "
+ f"current cycle {cycle}")
+
+ if n < self.lr_warm_up_steps[cycle]:
+ f = (self.f_max[cycle] - self.f_start[cycle]) / self.lr_warm_up_steps[cycle] * n + self.f_start[cycle]
+ self.last_f = f
+ return f
+ else:
+ f = self.f_min[cycle] + (self.f_max[cycle] - self.f_min[cycle]) * (self.cycle_lengths[cycle] - n) / (self.cycle_lengths[cycle])
+ self.last_f = f
+ return f
+
diff --git a/latent-diffusion/ldm/models/__pycache__/autoencoder.cpython-39.pyc b/latent-diffusion/ldm/models/__pycache__/autoencoder.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..c3cd3b77c12d3df1b89c445581ba86d57cd8d004
Binary files /dev/null and b/latent-diffusion/ldm/models/__pycache__/autoencoder.cpython-39.pyc differ
diff --git a/latent-diffusion/ldm/models/autoencoder.py b/latent-diffusion/ldm/models/autoencoder.py
new file mode 100644
index 0000000000000000000000000000000000000000..6a9c4f45498561953b8085981609b2a3298a5473
--- /dev/null
+++ b/latent-diffusion/ldm/models/autoencoder.py
@@ -0,0 +1,443 @@
+import torch
+import pytorch_lightning as pl
+import torch.nn.functional as F
+from contextlib import contextmanager
+
+from taming.modules.vqvae.quantize import VectorQuantizer2 as VectorQuantizer
+
+from ldm.modules.diffusionmodules.model import Encoder, Decoder
+from ldm.modules.distributions.distributions import DiagonalGaussianDistribution
+
+from ldm.util import instantiate_from_config
+
+
+class VQModel(pl.LightningModule):
+ def __init__(self,
+ ddconfig,
+ lossconfig,
+ n_embed,
+ embed_dim,
+ ckpt_path=None,
+ ignore_keys=[],
+ image_key="image",
+ colorize_nlabels=None,
+ monitor=None,
+ batch_resize_range=None,
+ scheduler_config=None,
+ lr_g_factor=1.0,
+ remap=None,
+ sane_index_shape=False, # tell vector quantizer to return indices as bhw
+ use_ema=False
+ ):
+ super().__init__()
+ self.embed_dim = embed_dim
+ self.n_embed = n_embed
+ self.image_key = image_key
+ self.encoder = Encoder(**ddconfig)
+ self.decoder = Decoder(**ddconfig)
+ self.loss = instantiate_from_config(lossconfig)
+ self.quantize = VectorQuantizer(n_embed, embed_dim, beta=0.25,
+ remap=remap,
+ sane_index_shape=sane_index_shape)
+ self.quant_conv = torch.nn.Conv2d(ddconfig["z_channels"], embed_dim, 1)
+ self.post_quant_conv = torch.nn.Conv2d(embed_dim, ddconfig["z_channels"], 1)
+ if colorize_nlabels is not None:
+ assert type(colorize_nlabels)==int
+ self.register_buffer("colorize", torch.randn(3, colorize_nlabels, 1, 1))
+ if monitor is not None:
+ self.monitor = monitor
+ self.batch_resize_range = batch_resize_range
+ if self.batch_resize_range is not None:
+ print(f"{self.__class__.__name__}: Using per-batch resizing in range {batch_resize_range}.")
+
+ self.use_ema = use_ema
+ if self.use_ema:
+ self.model_ema = LitEma(self)
+ print(f"Keeping EMAs of {len(list(self.model_ema.buffers()))}.")
+
+ if ckpt_path is not None:
+ self.init_from_ckpt(ckpt_path, ignore_keys=ignore_keys)
+ self.scheduler_config = scheduler_config
+ self.lr_g_factor = lr_g_factor
+
+ @contextmanager
+ def ema_scope(self, context=None):
+ if self.use_ema:
+ self.model_ema.store(self.parameters())
+ self.model_ema.copy_to(self)
+ if context is not None:
+ print(f"{context}: Switched to EMA weights")
+ try:
+ yield None
+ finally:
+ if self.use_ema:
+ self.model_ema.restore(self.parameters())
+ if context is not None:
+ print(f"{context}: Restored training weights")
+
+ def init_from_ckpt(self, path, ignore_keys=list()):
+ sd = torch.load(path, map_location="cpu")["state_dict"]
+ keys = list(sd.keys())
+ for k in keys:
+ for ik in ignore_keys:
+ if k.startswith(ik):
+ print("Deleting key {} from state_dict.".format(k))
+ del sd[k]
+ missing, unexpected = self.load_state_dict(sd, strict=False)
+ print(f"Restored from {path} with {len(missing)} missing and {len(unexpected)} unexpected keys")
+ if len(missing) > 0:
+ print(f"Missing Keys: {missing}")
+ print(f"Unexpected Keys: {unexpected}")
+
+ def on_train_batch_end(self, *args, **kwargs):
+ if self.use_ema:
+ self.model_ema(self)
+
+ def encode(self, x):
+ h = self.encoder(x)
+ h = self.quant_conv(h)
+ quant, emb_loss, info = self.quantize(h)
+ return quant, emb_loss, info
+
+ def encode_to_prequant(self, x):
+ h = self.encoder(x)
+ h = self.quant_conv(h)
+ return h
+
+ def decode(self, quant):
+ quant = self.post_quant_conv(quant)
+ dec = self.decoder(quant)
+ return dec
+
+ def decode_code(self, code_b):
+ quant_b = self.quantize.embed_code(code_b)
+ dec = self.decode(quant_b)
+ return dec
+
+ def forward(self, input, return_pred_indices=False):
+ quant, diff, (_,_,ind) = self.encode(input)
+ dec = self.decode(quant)
+ if return_pred_indices:
+ return dec, diff, ind
+ return dec, diff
+
+ def get_input(self, batch, k):
+ x = batch[k]
+ if len(x.shape) == 3:
+ x = x[..., None]
+ x = x.permute(0, 3, 1, 2).to(memory_format=torch.contiguous_format).float()
+ if self.batch_resize_range is not None:
+ lower_size = self.batch_resize_range[0]
+ upper_size = self.batch_resize_range[1]
+ if self.global_step <= 4:
+ # do the first few batches with max size to avoid later oom
+ new_resize = upper_size
+ else:
+ new_resize = np.random.choice(np.arange(lower_size, upper_size+16, 16))
+ if new_resize != x.shape[2]:
+ x = F.interpolate(x, size=new_resize, mode="bicubic")
+ x = x.detach()
+ return x
+
+ def training_step(self, batch, batch_idx, optimizer_idx):
+ # https://github.com/pytorch/pytorch/issues/37142
+ # try not to fool the heuristics
+ x = self.get_input(batch, self.image_key)
+ xrec, qloss, ind = self(x, return_pred_indices=True)
+
+ if optimizer_idx == 0:
+ # autoencode
+ aeloss, log_dict_ae = self.loss(qloss, x, xrec, optimizer_idx, self.global_step,
+ last_layer=self.get_last_layer(), split="train",
+ predicted_indices=ind)
+
+ self.log_dict(log_dict_ae, prog_bar=False, logger=True, on_step=True, on_epoch=True)
+ return aeloss
+
+ if optimizer_idx == 1:
+ # discriminator
+ discloss, log_dict_disc = self.loss(qloss, x, xrec, optimizer_idx, self.global_step,
+ last_layer=self.get_last_layer(), split="train")
+ self.log_dict(log_dict_disc, prog_bar=False, logger=True, on_step=True, on_epoch=True)
+ return discloss
+
+ def validation_step(self, batch, batch_idx):
+ log_dict = self._validation_step(batch, batch_idx)
+ with self.ema_scope():
+ log_dict_ema = self._validation_step(batch, batch_idx, suffix="_ema")
+ return log_dict
+
+ def _validation_step(self, batch, batch_idx, suffix=""):
+ x = self.get_input(batch, self.image_key)
+ xrec, qloss, ind = self(x, return_pred_indices=True)
+ aeloss, log_dict_ae = self.loss(qloss, x, xrec, 0,
+ self.global_step,
+ last_layer=self.get_last_layer(),
+ split="val"+suffix,
+ predicted_indices=ind
+ )
+
+ discloss, log_dict_disc = self.loss(qloss, x, xrec, 1,
+ self.global_step,
+ last_layer=self.get_last_layer(),
+ split="val"+suffix,
+ predicted_indices=ind
+ )
+ rec_loss = log_dict_ae[f"val{suffix}/rec_loss"]
+ self.log(f"val{suffix}/rec_loss", rec_loss,
+ prog_bar=True, logger=True, on_step=False, on_epoch=True, sync_dist=True)
+ self.log(f"val{suffix}/aeloss", aeloss,
+ prog_bar=True, logger=True, on_step=False, on_epoch=True, sync_dist=True)
+ if version.parse(pl.__version__) >= version.parse('1.4.0'):
+ del log_dict_ae[f"val{suffix}/rec_loss"]
+ self.log_dict(log_dict_ae)
+ self.log_dict(log_dict_disc)
+ return self.log_dict
+
+ def configure_optimizers(self):
+ lr_d = self.learning_rate
+ lr_g = self.lr_g_factor*self.learning_rate
+ print("lr_d", lr_d)
+ print("lr_g", lr_g)
+ opt_ae = torch.optim.Adam(list(self.encoder.parameters())+
+ list(self.decoder.parameters())+
+ list(self.quantize.parameters())+
+ list(self.quant_conv.parameters())+
+ list(self.post_quant_conv.parameters()),
+ lr=lr_g, betas=(0.5, 0.9))
+ opt_disc = torch.optim.Adam(self.loss.discriminator.parameters(),
+ lr=lr_d, betas=(0.5, 0.9))
+
+ if self.scheduler_config is not None:
+ scheduler = instantiate_from_config(self.scheduler_config)
+
+ print("Setting up LambdaLR scheduler...")
+ scheduler = [
+ {
+ 'scheduler': LambdaLR(opt_ae, lr_lambda=scheduler.schedule),
+ 'interval': 'step',
+ 'frequency': 1
+ },
+ {
+ 'scheduler': LambdaLR(opt_disc, lr_lambda=scheduler.schedule),
+ 'interval': 'step',
+ 'frequency': 1
+ },
+ ]
+ return [opt_ae, opt_disc], scheduler
+ return [opt_ae, opt_disc], []
+
+ def get_last_layer(self):
+ return self.decoder.conv_out.weight
+
+ def log_images(self, batch, only_inputs=False, plot_ema=False, **kwargs):
+ log = dict()
+ x = self.get_input(batch, self.image_key)
+ x = x.to(self.device)
+ if only_inputs:
+ log["inputs"] = x
+ return log
+ xrec, _ = self(x)
+ if x.shape[1] > 3:
+ # colorize with random projection
+ assert xrec.shape[1] > 3
+ x = self.to_rgb(x)
+ xrec = self.to_rgb(xrec)
+ log["inputs"] = x
+ log["reconstructions"] = xrec
+ if plot_ema:
+ with self.ema_scope():
+ xrec_ema, _ = self(x)
+ if x.shape[1] > 3: xrec_ema = self.to_rgb(xrec_ema)
+ log["reconstructions_ema"] = xrec_ema
+ return log
+
+ def to_rgb(self, x):
+ assert self.image_key == "segmentation"
+ if not hasattr(self, "colorize"):
+ self.register_buffer("colorize", torch.randn(3, x.shape[1], 1, 1).to(x))
+ x = F.conv2d(x, weight=self.colorize)
+ x = 2.*(x-x.min())/(x.max()-x.min()) - 1.
+ return x
+
+
+class VQModelInterface(VQModel):
+ def __init__(self, embed_dim, *args, **kwargs):
+ super().__init__(embed_dim=embed_dim, *args, **kwargs)
+ self.embed_dim = embed_dim
+
+ def encode(self, x):
+ h = self.encoder(x)
+ h = self.quant_conv(h)
+ return h
+
+ def decode(self, h, force_not_quantize=False):
+ # also go through quantization layer
+ if not force_not_quantize:
+ quant, emb_loss, info = self.quantize(h)
+ else:
+ quant = h
+ quant = self.post_quant_conv(quant)
+ dec = self.decoder(quant)
+ return dec
+
+
+class AutoencoderKL(pl.LightningModule):
+ def __init__(self,
+ ddconfig,
+ lossconfig,
+ embed_dim,
+ ckpt_path=None,
+ ignore_keys=[],
+ image_key="image",
+ colorize_nlabels=None,
+ monitor=None,
+ ):
+ super().__init__()
+ self.image_key = image_key
+ self.encoder = Encoder(**ddconfig)
+ self.decoder = Decoder(**ddconfig)
+ self.loss = instantiate_from_config(lossconfig)
+ assert ddconfig["double_z"]
+ self.quant_conv = torch.nn.Conv2d(2*ddconfig["z_channels"], 2*embed_dim, 1)
+ self.post_quant_conv = torch.nn.Conv2d(embed_dim, ddconfig["z_channels"], 1)
+ self.embed_dim = embed_dim
+ if colorize_nlabels is not None:
+ assert type(colorize_nlabels)==int
+ self.register_buffer("colorize", torch.randn(3, colorize_nlabels, 1, 1))
+ if monitor is not None:
+ self.monitor = monitor
+ if ckpt_path is not None:
+ self.init_from_ckpt(ckpt_path, ignore_keys=ignore_keys)
+
+ def init_from_ckpt(self, path, ignore_keys=list()):
+ sd = torch.load(path, map_location="cpu")["state_dict"]
+ keys = list(sd.keys())
+ for k in keys:
+ for ik in ignore_keys:
+ if k.startswith(ik):
+ print("Deleting key {} from state_dict.".format(k))
+ del sd[k]
+ self.load_state_dict(sd, strict=False)
+ print(f"Restored from {path}")
+
+ def encode(self, x):
+ h = self.encoder(x)
+ moments = self.quant_conv(h)
+ posterior = DiagonalGaussianDistribution(moments)
+ return posterior
+
+ def decode(self, z):
+ z = self.post_quant_conv(z)
+ dec = self.decoder(z)
+ return dec
+
+ def forward(self, input, sample_posterior=True):
+ posterior = self.encode(input)
+ if sample_posterior:
+ z = posterior.sample()
+ else:
+ z = posterior.mode()
+ dec = self.decode(z)
+ return dec, posterior
+
+ def get_input(self, batch, k):
+ x = batch[k]
+ if len(x.shape) == 3:
+ x = x[..., None]
+ x = x.permute(0, 3, 1, 2).to(memory_format=torch.contiguous_format).float()
+ return x
+
+ def training_step(self, batch, batch_idx, optimizer_idx):
+ inputs = self.get_input(batch, self.image_key)
+ reconstructions, posterior = self(inputs)
+
+ if optimizer_idx == 0:
+ # train encoder+decoder+logvar
+ aeloss, log_dict_ae = self.loss(inputs, reconstructions, posterior, optimizer_idx, self.global_step,
+ last_layer=self.get_last_layer(), split="train")
+ self.log("aeloss", aeloss, prog_bar=True, logger=True, on_step=True, on_epoch=True)
+ self.log_dict(log_dict_ae, prog_bar=False, logger=True, on_step=True, on_epoch=False)
+ return aeloss
+
+ if optimizer_idx == 1:
+ # train the discriminator
+ discloss, log_dict_disc = self.loss(inputs, reconstructions, posterior, optimizer_idx, self.global_step,
+ last_layer=self.get_last_layer(), split="train")
+
+ self.log("discloss", discloss, prog_bar=True, logger=True, on_step=True, on_epoch=True)
+ self.log_dict(log_dict_disc, prog_bar=False, logger=True, on_step=True, on_epoch=False)
+ return discloss
+
+ def validation_step(self, batch, batch_idx):
+ inputs = self.get_input(batch, self.image_key)
+ reconstructions, posterior = self(inputs)
+ aeloss, log_dict_ae = self.loss(inputs, reconstructions, posterior, 0, self.global_step,
+ last_layer=self.get_last_layer(), split="val")
+
+ discloss, log_dict_disc = self.loss(inputs, reconstructions, posterior, 1, self.global_step,
+ last_layer=self.get_last_layer(), split="val")
+
+ self.log("val/rec_loss", log_dict_ae["val/rec_loss"])
+ self.log_dict(log_dict_ae)
+ self.log_dict(log_dict_disc)
+ return self.log_dict
+
+ def configure_optimizers(self):
+ lr = self.learning_rate
+ opt_ae = torch.optim.Adam(list(self.encoder.parameters())+
+ list(self.decoder.parameters())+
+ list(self.quant_conv.parameters())+
+ list(self.post_quant_conv.parameters()),
+ lr=lr, betas=(0.5, 0.9))
+ opt_disc = torch.optim.Adam(self.loss.discriminator.parameters(),
+ lr=lr, betas=(0.5, 0.9))
+ return [opt_ae, opt_disc], []
+
+ def get_last_layer(self):
+ return self.decoder.conv_out.weight
+
+ @torch.no_grad()
+ def log_images(self, batch, only_inputs=False, **kwargs):
+ log = dict()
+ x = self.get_input(batch, self.image_key)
+ x = x.to(self.device)
+ if not only_inputs:
+ xrec, posterior = self(x)
+ if x.shape[1] > 3:
+ # colorize with random projection
+ assert xrec.shape[1] > 3
+ x = self.to_rgb(x)
+ xrec = self.to_rgb(xrec)
+ log["samples"] = self.decode(torch.randn_like(posterior.sample()))
+ log["reconstructions"] = xrec
+ log["inputs"] = x
+ return log
+
+ def to_rgb(self, x):
+ assert self.image_key == "segmentation"
+ if not hasattr(self, "colorize"):
+ self.register_buffer("colorize", torch.randn(3, x.shape[1], 1, 1).to(x))
+ x = F.conv2d(x, weight=self.colorize)
+ x = 2.*(x-x.min())/(x.max()-x.min()) - 1.
+ return x
+
+
+class IdentityFirstStage(torch.nn.Module):
+ def __init__(self, *args, vq_interface=False, **kwargs):
+ self.vq_interface = vq_interface # TODO: Should be true by default but check to not break older stuff
+ super().__init__()
+
+ def encode(self, x, *args, **kwargs):
+ return x
+
+ def decode(self, x, *args, **kwargs):
+ return x
+
+ def quantize(self, x, *args, **kwargs):
+ if self.vq_interface:
+ return x, None, [None, None, None]
+ return x
+
+ def forward(self, x, *args, **kwargs):
+ return x
diff --git a/latent-diffusion/ldm/models/diffusion/__init__.py b/latent-diffusion/ldm/models/diffusion/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/latent-diffusion/ldm/models/diffusion/__pycache__/__init__.cpython-39.pyc b/latent-diffusion/ldm/models/diffusion/__pycache__/__init__.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..5f06191abf54835e6fbe689c5760c17612cf4e2c
Binary files /dev/null and b/latent-diffusion/ldm/models/diffusion/__pycache__/__init__.cpython-39.pyc differ
diff --git a/latent-diffusion/ldm/models/diffusion/__pycache__/ddim.cpython-39.pyc b/latent-diffusion/ldm/models/diffusion/__pycache__/ddim.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..73086bc58150cbf8465104819bf39cdb3e01f24b
Binary files /dev/null and b/latent-diffusion/ldm/models/diffusion/__pycache__/ddim.cpython-39.pyc differ
diff --git a/latent-diffusion/ldm/models/diffusion/__pycache__/ddpm.cpython-39.pyc b/latent-diffusion/ldm/models/diffusion/__pycache__/ddpm.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..ca9ef61a20172e2bbdef529ce033fb98c491c7ab
Binary files /dev/null and b/latent-diffusion/ldm/models/diffusion/__pycache__/ddpm.cpython-39.pyc differ
diff --git a/latent-diffusion/ldm/models/diffusion/__pycache__/plms.cpython-39.pyc b/latent-diffusion/ldm/models/diffusion/__pycache__/plms.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..cc6b5b1339d5780ebe4b1da0d4d64636efe5dca6
Binary files /dev/null and b/latent-diffusion/ldm/models/diffusion/__pycache__/plms.cpython-39.pyc differ
diff --git a/latent-diffusion/ldm/models/diffusion/classifier.py b/latent-diffusion/ldm/models/diffusion/classifier.py
new file mode 100644
index 0000000000000000000000000000000000000000..67e98b9d8ffb96a150b517497ace0a242d7163ef
--- /dev/null
+++ b/latent-diffusion/ldm/models/diffusion/classifier.py
@@ -0,0 +1,267 @@
+import os
+import torch
+import pytorch_lightning as pl
+from omegaconf import OmegaConf
+from torch.nn import functional as F
+from torch.optim import AdamW
+from torch.optim.lr_scheduler import LambdaLR
+from copy import deepcopy
+from einops import rearrange
+from glob import glob
+from natsort import natsorted
+
+from ldm.modules.diffusionmodules.openaimodel import EncoderUNetModel, UNetModel
+from ldm.util import log_txt_as_img, default, ismap, instantiate_from_config
+
+__models__ = {
+ 'class_label': EncoderUNetModel,
+ 'segmentation': UNetModel
+}
+
+
+def disabled_train(self, mode=True):
+ """Overwrite model.train with this function to make sure train/eval mode
+ does not change anymore."""
+ return self
+
+
+class NoisyLatentImageClassifier(pl.LightningModule):
+
+ def __init__(self,
+ diffusion_path,
+ num_classes,
+ ckpt_path=None,
+ pool='attention',
+ label_key=None,
+ diffusion_ckpt_path=None,
+ scheduler_config=None,
+ weight_decay=1.e-2,
+ log_steps=10,
+ monitor='val/loss',
+ *args,
+ **kwargs):
+ super().__init__(*args, **kwargs)
+ self.num_classes = num_classes
+ # get latest config of diffusion model
+ diffusion_config = natsorted(glob(os.path.join(diffusion_path, 'configs', '*-project.yaml')))[-1]
+ self.diffusion_config = OmegaConf.load(diffusion_config).model
+ self.diffusion_config.params.ckpt_path = diffusion_ckpt_path
+ self.load_diffusion()
+
+ self.monitor = monitor
+ self.numd = self.diffusion_model.first_stage_model.encoder.num_resolutions - 1
+ self.log_time_interval = self.diffusion_model.num_timesteps // log_steps
+ self.log_steps = log_steps
+
+ self.label_key = label_key if not hasattr(self.diffusion_model, 'cond_stage_key') \
+ else self.diffusion_model.cond_stage_key
+
+ assert self.label_key is not None, 'label_key neither in diffusion model nor in model.params'
+
+ if self.label_key not in __models__:
+ raise NotImplementedError()
+
+ self.load_classifier(ckpt_path, pool)
+
+ self.scheduler_config = scheduler_config
+ self.use_scheduler = self.scheduler_config is not None
+ self.weight_decay = weight_decay
+
+ def init_from_ckpt(self, path, ignore_keys=list(), only_model=False):
+ sd = torch.load(path, map_location="cpu")
+ if "state_dict" in list(sd.keys()):
+ sd = sd["state_dict"]
+ keys = list(sd.keys())
+ for k in keys:
+ for ik in ignore_keys:
+ if k.startswith(ik):
+ print("Deleting key {} from state_dict.".format(k))
+ del sd[k]
+ missing, unexpected = self.load_state_dict(sd, strict=False) if not only_model else self.model.load_state_dict(
+ sd, strict=False)
+ print(f"Restored from {path} with {len(missing)} missing and {len(unexpected)} unexpected keys")
+ if len(missing) > 0:
+ print(f"Missing Keys: {missing}")
+ if len(unexpected) > 0:
+ print(f"Unexpected Keys: {unexpected}")
+
+ def load_diffusion(self):
+ model = instantiate_from_config(self.diffusion_config)
+ self.diffusion_model = model.eval()
+ self.diffusion_model.train = disabled_train
+ for param in self.diffusion_model.parameters():
+ param.requires_grad = False
+
+ def load_classifier(self, ckpt_path, pool):
+ model_config = deepcopy(self.diffusion_config.params.unet_config.params)
+ model_config.in_channels = self.diffusion_config.params.unet_config.params.out_channels
+ model_config.out_channels = self.num_classes
+ if self.label_key == 'class_label':
+ model_config.pool = pool
+
+ self.model = __models__[self.label_key](**model_config)
+ if ckpt_path is not None:
+ print('#####################################################################')
+ print(f'load from ckpt "{ckpt_path}"')
+ print('#####################################################################')
+ self.init_from_ckpt(ckpt_path)
+
+ @torch.no_grad()
+ def get_x_noisy(self, x, t, noise=None):
+ noise = default(noise, lambda: torch.randn_like(x))
+ continuous_sqrt_alpha_cumprod = None
+ if self.diffusion_model.use_continuous_noise:
+ continuous_sqrt_alpha_cumprod = self.diffusion_model.sample_continuous_noise_level(x.shape[0], t + 1)
+ # todo: make sure t+1 is correct here
+
+ return self.diffusion_model.q_sample(x_start=x, t=t, noise=noise,
+ continuous_sqrt_alpha_cumprod=continuous_sqrt_alpha_cumprod)
+
+ def forward(self, x_noisy, t, *args, **kwargs):
+ return self.model(x_noisy, t)
+
+ @torch.no_grad()
+ def get_input(self, batch, k):
+ x = batch[k]
+ if len(x.shape) == 3:
+ x = x[..., None]
+ x = rearrange(x, 'b h w c -> b c h w')
+ x = x.to(memory_format=torch.contiguous_format).float()
+ return x
+
+ @torch.no_grad()
+ def get_conditioning(self, batch, k=None):
+ if k is None:
+ k = self.label_key
+ assert k is not None, 'Needs to provide label key'
+
+ targets = batch[k].to(self.device)
+
+ if self.label_key == 'segmentation':
+ targets = rearrange(targets, 'b h w c -> b c h w')
+ for down in range(self.numd):
+ h, w = targets.shape[-2:]
+ targets = F.interpolate(targets, size=(h // 2, w // 2), mode='nearest')
+
+ # targets = rearrange(targets,'b c h w -> b h w c')
+
+ return targets
+
+ def compute_top_k(self, logits, labels, k, reduction="mean"):
+ _, top_ks = torch.topk(logits, k, dim=1)
+ if reduction == "mean":
+ return (top_ks == labels[:, None]).float().sum(dim=-1).mean().item()
+ elif reduction == "none":
+ return (top_ks == labels[:, None]).float().sum(dim=-1)
+
+ def on_train_epoch_start(self):
+ # save some memory
+ self.diffusion_model.model.to('cpu')
+
+ @torch.no_grad()
+ def write_logs(self, loss, logits, targets):
+ log_prefix = 'train' if self.training else 'val'
+ log = {}
+ log[f"{log_prefix}/loss"] = loss.mean()
+ log[f"{log_prefix}/acc@1"] = self.compute_top_k(
+ logits, targets, k=1, reduction="mean"
+ )
+ log[f"{log_prefix}/acc@5"] = self.compute_top_k(
+ logits, targets, k=5, reduction="mean"
+ )
+
+ self.log_dict(log, prog_bar=False, logger=True, on_step=self.training, on_epoch=True)
+ self.log('loss', log[f"{log_prefix}/loss"], prog_bar=True, logger=False)
+ self.log('global_step', self.global_step, logger=False, on_epoch=False, prog_bar=True)
+ lr = self.optimizers().param_groups[0]['lr']
+ self.log('lr_abs', lr, on_step=True, logger=True, on_epoch=False, prog_bar=True)
+
+ def shared_step(self, batch, t=None):
+ x, *_ = self.diffusion_model.get_input(batch, k=self.diffusion_model.first_stage_key)
+ targets = self.get_conditioning(batch)
+ if targets.dim() == 4:
+ targets = targets.argmax(dim=1)
+ if t is None:
+ t = torch.randint(0, self.diffusion_model.num_timesteps, (x.shape[0],), device=self.device).long()
+ else:
+ t = torch.full(size=(x.shape[0],), fill_value=t, device=self.device).long()
+ x_noisy = self.get_x_noisy(x, t)
+ logits = self(x_noisy, t)
+
+ loss = F.cross_entropy(logits, targets, reduction='none')
+
+ self.write_logs(loss.detach(), logits.detach(), targets.detach())
+
+ loss = loss.mean()
+ return loss, logits, x_noisy, targets
+
+ def training_step(self, batch, batch_idx):
+ loss, *_ = self.shared_step(batch)
+ return loss
+
+ def reset_noise_accs(self):
+ self.noisy_acc = {t: {'acc@1': [], 'acc@5': []} for t in
+ range(0, self.diffusion_model.num_timesteps, self.diffusion_model.log_every_t)}
+
+ def on_validation_start(self):
+ self.reset_noise_accs()
+
+ @torch.no_grad()
+ def validation_step(self, batch, batch_idx):
+ loss, *_ = self.shared_step(batch)
+
+ for t in self.noisy_acc:
+ _, logits, _, targets = self.shared_step(batch, t)
+ self.noisy_acc[t]['acc@1'].append(self.compute_top_k(logits, targets, k=1, reduction='mean'))
+ self.noisy_acc[t]['acc@5'].append(self.compute_top_k(logits, targets, k=5, reduction='mean'))
+
+ return loss
+
+ def configure_optimizers(self):
+ optimizer = AdamW(self.model.parameters(), lr=self.learning_rate, weight_decay=self.weight_decay)
+
+ if self.use_scheduler:
+ scheduler = instantiate_from_config(self.scheduler_config)
+
+ print("Setting up LambdaLR scheduler...")
+ scheduler = [
+ {
+ 'scheduler': LambdaLR(optimizer, lr_lambda=scheduler.schedule),
+ 'interval': 'step',
+ 'frequency': 1
+ }]
+ return [optimizer], scheduler
+
+ return optimizer
+
+ @torch.no_grad()
+ def log_images(self, batch, N=8, *args, **kwargs):
+ log = dict()
+ x = self.get_input(batch, self.diffusion_model.first_stage_key)
+ log['inputs'] = x
+
+ y = self.get_conditioning(batch)
+
+ if self.label_key == 'class_label':
+ y = log_txt_as_img((x.shape[2], x.shape[3]), batch["human_label"])
+ log['labels'] = y
+
+ if ismap(y):
+ log['labels'] = self.diffusion_model.to_rgb(y)
+
+ for step in range(self.log_steps):
+ current_time = step * self.log_time_interval
+
+ _, logits, x_noisy, _ = self.shared_step(batch, t=current_time)
+
+ log[f'inputs@t{current_time}'] = x_noisy
+
+ pred = F.one_hot(logits.argmax(dim=1), num_classes=self.num_classes)
+ pred = rearrange(pred, 'b h w c -> b c h w')
+
+ log[f'pred@t{current_time}'] = self.diffusion_model.to_rgb(pred)
+
+ for key in log:
+ log[key] = log[key][:N]
+
+ return log
diff --git a/latent-diffusion/ldm/models/diffusion/ddim.py b/latent-diffusion/ldm/models/diffusion/ddim.py
new file mode 100644
index 0000000000000000000000000000000000000000..edf1eaff9e78ac2e6778914b706b6a4fff51a8fe
--- /dev/null
+++ b/latent-diffusion/ldm/models/diffusion/ddim.py
@@ -0,0 +1,203 @@
+"""SAMPLING ONLY."""
+
+import torch
+import numpy as np
+from tqdm import tqdm
+from functools import partial
+
+from ldm.modules.diffusionmodules.util import make_ddim_sampling_parameters, make_ddim_timesteps, noise_like
+
+
+class DDIMSampler(object):
+ def __init__(self, model, schedule="linear", **kwargs):
+ super().__init__()
+ self.model = model
+ self.ddpm_num_timesteps = model.num_timesteps
+ self.schedule = schedule
+
+ def register_buffer(self, name, attr):
+ if type(attr) == torch.Tensor:
+ if attr.device != torch.device("cuda"):
+ attr = attr.to(torch.device("cuda"))
+ setattr(self, name, attr)
+
+ def make_schedule(self, ddim_num_steps, ddim_discretize="uniform", ddim_eta=0., verbose=True):
+ self.ddim_timesteps = make_ddim_timesteps(ddim_discr_method=ddim_discretize, num_ddim_timesteps=ddim_num_steps,
+ num_ddpm_timesteps=self.ddpm_num_timesteps,verbose=verbose)
+ alphas_cumprod = self.model.alphas_cumprod
+ assert alphas_cumprod.shape[0] == self.ddpm_num_timesteps, 'alphas have to be defined for each timestep'
+ to_torch = lambda x: x.clone().detach().to(torch.float32).to(self.model.device)
+
+ self.register_buffer('betas', to_torch(self.model.betas))
+ self.register_buffer('alphas_cumprod', to_torch(alphas_cumprod))
+ self.register_buffer('alphas_cumprod_prev', to_torch(self.model.alphas_cumprod_prev))
+
+ # calculations for diffusion q(x_t | x_{t-1}) and others
+ self.register_buffer('sqrt_alphas_cumprod', to_torch(np.sqrt(alphas_cumprod.cpu())))
+ self.register_buffer('sqrt_one_minus_alphas_cumprod', to_torch(np.sqrt(1. - alphas_cumprod.cpu())))
+ self.register_buffer('log_one_minus_alphas_cumprod', to_torch(np.log(1. - alphas_cumprod.cpu())))
+ self.register_buffer('sqrt_recip_alphas_cumprod', to_torch(np.sqrt(1. / alphas_cumprod.cpu())))
+ self.register_buffer('sqrt_recipm1_alphas_cumprod', to_torch(np.sqrt(1. / alphas_cumprod.cpu() - 1)))
+
+ # ddim sampling parameters
+ ddim_sigmas, ddim_alphas, ddim_alphas_prev = make_ddim_sampling_parameters(alphacums=alphas_cumprod.cpu(),
+ ddim_timesteps=self.ddim_timesteps,
+ eta=ddim_eta,verbose=verbose)
+ self.register_buffer('ddim_sigmas', ddim_sigmas)
+ self.register_buffer('ddim_alphas', ddim_alphas)
+ self.register_buffer('ddim_alphas_prev', ddim_alphas_prev)
+ self.register_buffer('ddim_sqrt_one_minus_alphas', np.sqrt(1. - ddim_alphas))
+ sigmas_for_original_sampling_steps = ddim_eta * torch.sqrt(
+ (1 - self.alphas_cumprod_prev) / (1 - self.alphas_cumprod) * (
+ 1 - self.alphas_cumprod / self.alphas_cumprod_prev))
+ self.register_buffer('ddim_sigmas_for_original_num_steps', sigmas_for_original_sampling_steps)
+
+ @torch.no_grad()
+ def sample(self,
+ S,
+ batch_size,
+ shape,
+ conditioning=None,
+ callback=None,
+ normals_sequence=None,
+ img_callback=None,
+ quantize_x0=False,
+ eta=0.,
+ mask=None,
+ x0=None,
+ temperature=1.,
+ noise_dropout=0.,
+ score_corrector=None,
+ corrector_kwargs=None,
+ verbose=True,
+ x_T=None,
+ log_every_t=100,
+ unconditional_guidance_scale=1.,
+ unconditional_conditioning=None,
+ # this has to come in the same format as the conditioning, # e.g. as encoded tokens, ...
+ **kwargs
+ ):
+ if conditioning is not None:
+ if isinstance(conditioning, dict):
+ cbs = conditioning[list(conditioning.keys())[0]].shape[0]
+ if cbs != batch_size:
+ print(f"Warning: Got {cbs} conditionings but batch-size is {batch_size}")
+ else:
+ if conditioning.shape[0] != batch_size:
+ print(f"Warning: Got {conditioning.shape[0]} conditionings but batch-size is {batch_size}")
+
+ self.make_schedule(ddim_num_steps=S, ddim_eta=eta, verbose=verbose)
+ # sampling
+ C, H, W = shape
+ size = (batch_size, C, H, W)
+ print(f'Data shape for DDIM sampling is {size}, eta {eta}')
+
+ samples, intermediates = self.ddim_sampling(conditioning, size,
+ callback=callback,
+ img_callback=img_callback,
+ quantize_denoised=quantize_x0,
+ mask=mask, x0=x0,
+ ddim_use_original_steps=False,
+ noise_dropout=noise_dropout,
+ temperature=temperature,
+ score_corrector=score_corrector,
+ corrector_kwargs=corrector_kwargs,
+ x_T=x_T,
+ log_every_t=log_every_t,
+ unconditional_guidance_scale=unconditional_guidance_scale,
+ unconditional_conditioning=unconditional_conditioning,
+ )
+ return samples, intermediates
+
+ @torch.no_grad()
+ def ddim_sampling(self, cond, shape,
+ x_T=None, ddim_use_original_steps=False,
+ callback=None, timesteps=None, quantize_denoised=False,
+ mask=None, x0=None, img_callback=None, log_every_t=100,
+ temperature=1., noise_dropout=0., score_corrector=None, corrector_kwargs=None,
+ unconditional_guidance_scale=1., unconditional_conditioning=None,):
+ device = self.model.betas.device
+ b = shape[0]
+ if x_T is None:
+ img = torch.randn(shape, device=device)
+ else:
+ img = x_T
+
+ if timesteps is None:
+ timesteps = self.ddpm_num_timesteps if ddim_use_original_steps else self.ddim_timesteps
+ elif timesteps is not None and not ddim_use_original_steps:
+ subset_end = int(min(timesteps / self.ddim_timesteps.shape[0], 1) * self.ddim_timesteps.shape[0]) - 1
+ timesteps = self.ddim_timesteps[:subset_end]
+
+ intermediates = {'x_inter': [img], 'pred_x0': [img]}
+ time_range = reversed(range(0,timesteps)) if ddim_use_original_steps else np.flip(timesteps)
+ total_steps = timesteps if ddim_use_original_steps else timesteps.shape[0]
+ print(f"Running DDIM Sampling with {total_steps} timesteps")
+
+ iterator = tqdm(time_range, desc='DDIM Sampler', total=total_steps)
+
+ for i, step in enumerate(iterator):
+ index = total_steps - i - 1
+ ts = torch.full((b,), step, device=device, dtype=torch.long)
+
+ if mask is not None:
+ assert x0 is not None
+ img_orig = self.model.q_sample(x0, ts) # TODO: deterministic forward pass?
+ img = img_orig * mask + (1. - mask) * img
+
+ outs = self.p_sample_ddim(img, cond, ts, index=index, use_original_steps=ddim_use_original_steps,
+ quantize_denoised=quantize_denoised, temperature=temperature,
+ noise_dropout=noise_dropout, score_corrector=score_corrector,
+ corrector_kwargs=corrector_kwargs,
+ unconditional_guidance_scale=unconditional_guidance_scale,
+ unconditional_conditioning=unconditional_conditioning)
+ img, pred_x0 = outs
+ if callback: callback(i)
+ if img_callback: img_callback(pred_x0, i)
+
+ if index % log_every_t == 0 or index == total_steps - 1:
+ intermediates['x_inter'].append(img)
+ intermediates['pred_x0'].append(pred_x0)
+
+ return img, intermediates
+
+ @torch.no_grad()
+ def p_sample_ddim(self, x, c, t, index, repeat_noise=False, use_original_steps=False, quantize_denoised=False,
+ temperature=1., noise_dropout=0., score_corrector=None, corrector_kwargs=None,
+ unconditional_guidance_scale=1., unconditional_conditioning=None):
+ b, *_, device = *x.shape, x.device
+
+ if unconditional_conditioning is None or unconditional_guidance_scale == 1.:
+ e_t = self.model.apply_model(x, t, c)
+ else:
+ x_in = torch.cat([x] * 2)
+ t_in = torch.cat([t] * 2)
+ c_in = torch.cat([unconditional_conditioning, c])
+ e_t_uncond, e_t = self.model.apply_model(x_in, t_in, c_in).chunk(2)
+ e_t = e_t_uncond + unconditional_guidance_scale * (e_t - e_t_uncond)
+
+ if score_corrector is not None:
+ assert self.model.parameterization == "eps"
+ e_t = score_corrector.modify_score(self.model, e_t, x, t, c, **corrector_kwargs)
+
+ alphas = self.model.alphas_cumprod if use_original_steps else self.ddim_alphas
+ alphas_prev = self.model.alphas_cumprod_prev if use_original_steps else self.ddim_alphas_prev
+ sqrt_one_minus_alphas = self.model.sqrt_one_minus_alphas_cumprod if use_original_steps else self.ddim_sqrt_one_minus_alphas
+ sigmas = self.model.ddim_sigmas_for_original_num_steps if use_original_steps else self.ddim_sigmas
+ # select parameters corresponding to the currently considered timestep
+ a_t = torch.full((b, 1, 1, 1), alphas[index], device=device)
+ a_prev = torch.full((b, 1, 1, 1), alphas_prev[index], device=device)
+ sigma_t = torch.full((b, 1, 1, 1), sigmas[index], device=device)
+ sqrt_one_minus_at = torch.full((b, 1, 1, 1), sqrt_one_minus_alphas[index],device=device)
+
+ # current prediction for x_0
+ pred_x0 = (x - sqrt_one_minus_at * e_t) / a_t.sqrt()
+ if quantize_denoised:
+ pred_x0, _, *_ = self.model.first_stage_model.quantize(pred_x0)
+ # direction pointing to x_t
+ dir_xt = (1. - a_prev - sigma_t**2).sqrt() * e_t
+ noise = sigma_t * noise_like(x.shape, device, repeat_noise) * temperature
+ if noise_dropout > 0.:
+ noise = torch.nn.functional.dropout(noise, p=noise_dropout)
+ x_prev = a_prev.sqrt() * pred_x0 + dir_xt + noise
+ return x_prev, pred_x0
diff --git a/latent-diffusion/ldm/models/diffusion/ddpm.py b/latent-diffusion/ldm/models/diffusion/ddpm.py
new file mode 100644
index 0000000000000000000000000000000000000000..bbedd04cfd6f736ac066434a75618b9ba5125be7
--- /dev/null
+++ b/latent-diffusion/ldm/models/diffusion/ddpm.py
@@ -0,0 +1,1445 @@
+"""
+wild mixture of
+https://github.com/lucidrains/denoising-diffusion-pytorch/blob/7706bdfc6f527f58d33f84b7b522e61e6e3164b3/denoising_diffusion_pytorch/denoising_diffusion_pytorch.py
+https://github.com/openai/improved-diffusion/blob/e94489283bb876ac1477d5dd7709bbbd2d9902ce/improved_diffusion/gaussian_diffusion.py
+https://github.com/CompVis/taming-transformers
+-- merci
+"""
+
+import torch
+import torch.nn as nn
+import numpy as np
+import pytorch_lightning as pl
+from torch.optim.lr_scheduler import LambdaLR
+from einops import rearrange, repeat
+from contextlib import contextmanager
+from functools import partial
+from tqdm import tqdm
+from torchvision.utils import make_grid
+from pytorch_lightning.utilities.distributed import rank_zero_only
+
+from ldm.util import log_txt_as_img, exists, default, ismap, isimage, mean_flat, count_params, instantiate_from_config
+from ldm.modules.ema import LitEma
+from ldm.modules.distributions.distributions import normal_kl, DiagonalGaussianDistribution
+from ldm.models.autoencoder import VQModelInterface, IdentityFirstStage, AutoencoderKL
+from ldm.modules.diffusionmodules.util import make_beta_schedule, extract_into_tensor, noise_like
+from ldm.models.diffusion.ddim import DDIMSampler
+
+
+__conditioning_keys__ = {'concat': 'c_concat',
+ 'crossattn': 'c_crossattn',
+ 'adm': 'y'}
+
+
+def disabled_train(self, mode=True):
+ """Overwrite model.train with this function to make sure train/eval mode
+ does not change anymore."""
+ return self
+
+
+def uniform_on_device(r1, r2, shape, device):
+ return (r1 - r2) * torch.rand(*shape, device=device) + r2
+
+
+class DDPM(pl.LightningModule):
+ # classic DDPM with Gaussian diffusion, in image space
+ def __init__(self,
+ unet_config,
+ timesteps=1000,
+ beta_schedule="linear",
+ loss_type="l2",
+ ckpt_path=None,
+ ignore_keys=[],
+ load_only_unet=False,
+ monitor="val/loss",
+ use_ema=True,
+ first_stage_key="image",
+ image_size=256,
+ channels=3,
+ log_every_t=100,
+ clip_denoised=True,
+ linear_start=1e-4,
+ linear_end=2e-2,
+ cosine_s=8e-3,
+ given_betas=None,
+ original_elbo_weight=0.,
+ v_posterior=0., # weight for choosing posterior variance as sigma = (1-v) * beta_tilde + v * beta
+ l_simple_weight=1.,
+ conditioning_key=None,
+ parameterization="eps", # all assuming fixed variance schedules
+ scheduler_config=None,
+ use_positional_encodings=False,
+ learn_logvar=False,
+ logvar_init=0.,
+ ):
+ super().__init__()
+ assert parameterization in ["eps", "x0"], 'currently only supporting "eps" and "x0"'
+ self.parameterization = parameterization
+ print(f"{self.__class__.__name__}: Running in {self.parameterization}-prediction mode")
+ self.cond_stage_model = None
+ self.clip_denoised = clip_denoised
+ self.log_every_t = log_every_t
+ self.first_stage_key = first_stage_key
+ self.image_size = image_size # try conv?
+ self.channels = channels
+ self.use_positional_encodings = use_positional_encodings
+ self.model = DiffusionWrapper(unet_config, conditioning_key)
+ count_params(self.model, verbose=True)
+ self.use_ema = use_ema
+ if self.use_ema:
+ self.model_ema = LitEma(self.model)
+ print(f"Keeping EMAs of {len(list(self.model_ema.buffers()))}.")
+
+ self.use_scheduler = scheduler_config is not None
+ if self.use_scheduler:
+ self.scheduler_config = scheduler_config
+
+ self.v_posterior = v_posterior
+ self.original_elbo_weight = original_elbo_weight
+ self.l_simple_weight = l_simple_weight
+
+ if monitor is not None:
+ self.monitor = monitor
+ if ckpt_path is not None:
+ self.init_from_ckpt(ckpt_path, ignore_keys=ignore_keys, only_model=load_only_unet)
+
+ self.register_schedule(given_betas=given_betas, beta_schedule=beta_schedule, timesteps=timesteps,
+ linear_start=linear_start, linear_end=linear_end, cosine_s=cosine_s)
+
+ self.loss_type = loss_type
+
+ self.learn_logvar = learn_logvar
+ self.logvar = torch.full(fill_value=logvar_init, size=(self.num_timesteps,))
+ if self.learn_logvar:
+ self.logvar = nn.Parameter(self.logvar, requires_grad=True)
+
+
+ def register_schedule(self, given_betas=None, beta_schedule="linear", timesteps=1000,
+ linear_start=1e-4, linear_end=2e-2, cosine_s=8e-3):
+ if exists(given_betas):
+ betas = given_betas
+ else:
+ betas = make_beta_schedule(beta_schedule, timesteps, linear_start=linear_start, linear_end=linear_end,
+ cosine_s=cosine_s)
+ alphas = 1. - betas
+ alphas_cumprod = np.cumprod(alphas, axis=0)
+ alphas_cumprod_prev = np.append(1., alphas_cumprod[:-1])
+
+ timesteps, = betas.shape
+ self.num_timesteps = int(timesteps)
+ self.linear_start = linear_start
+ self.linear_end = linear_end
+ assert alphas_cumprod.shape[0] == self.num_timesteps, 'alphas have to be defined for each timestep'
+
+ to_torch = partial(torch.tensor, dtype=torch.float32)
+
+ self.register_buffer('betas', to_torch(betas))
+ self.register_buffer('alphas_cumprod', to_torch(alphas_cumprod))
+ self.register_buffer('alphas_cumprod_prev', to_torch(alphas_cumprod_prev))
+
+ # calculations for diffusion q(x_t | x_{t-1}) and others
+ self.register_buffer('sqrt_alphas_cumprod', to_torch(np.sqrt(alphas_cumprod)))
+ self.register_buffer('sqrt_one_minus_alphas_cumprod', to_torch(np.sqrt(1. - alphas_cumprod)))
+ self.register_buffer('log_one_minus_alphas_cumprod', to_torch(np.log(1. - alphas_cumprod)))
+ self.register_buffer('sqrt_recip_alphas_cumprod', to_torch(np.sqrt(1. / alphas_cumprod)))
+ self.register_buffer('sqrt_recipm1_alphas_cumprod', to_torch(np.sqrt(1. / alphas_cumprod - 1)))
+
+ # calculations for posterior q(x_{t-1} | x_t, x_0)
+ posterior_variance = (1 - self.v_posterior) * betas * (1. - alphas_cumprod_prev) / (
+ 1. - alphas_cumprod) + self.v_posterior * betas
+ # above: equal to 1. / (1. / (1. - alpha_cumprod_tm1) + alpha_t / beta_t)
+ self.register_buffer('posterior_variance', to_torch(posterior_variance))
+ # below: log calculation clipped because the posterior variance is 0 at the beginning of the diffusion chain
+ self.register_buffer('posterior_log_variance_clipped', to_torch(np.log(np.maximum(posterior_variance, 1e-20))))
+ self.register_buffer('posterior_mean_coef1', to_torch(
+ betas * np.sqrt(alphas_cumprod_prev) / (1. - alphas_cumprod)))
+ self.register_buffer('posterior_mean_coef2', to_torch(
+ (1. - alphas_cumprod_prev) * np.sqrt(alphas) / (1. - alphas_cumprod)))
+
+ if self.parameterization == "eps":
+ lvlb_weights = self.betas ** 2 / (
+ 2 * self.posterior_variance * to_torch(alphas) * (1 - self.alphas_cumprod))
+ elif self.parameterization == "x0":
+ lvlb_weights = 0.5 * np.sqrt(torch.Tensor(alphas_cumprod)) / (2. * 1 - torch.Tensor(alphas_cumprod))
+ else:
+ raise NotImplementedError("mu not supported")
+ # TODO how to choose this term
+ lvlb_weights[0] = lvlb_weights[1]
+ self.register_buffer('lvlb_weights', lvlb_weights, persistent=False)
+ assert not torch.isnan(self.lvlb_weights).all()
+
+ @contextmanager
+ def ema_scope(self, context=None):
+ if self.use_ema:
+ self.model_ema.store(self.model.parameters())
+ self.model_ema.copy_to(self.model)
+ if context is not None:
+ print(f"{context}: Switched to EMA weights")
+ try:
+ yield None
+ finally:
+ if self.use_ema:
+ self.model_ema.restore(self.model.parameters())
+ if context is not None:
+ print(f"{context}: Restored training weights")
+
+ def init_from_ckpt(self, path, ignore_keys=list(), only_model=False):
+ sd = torch.load(path, map_location="cpu")
+ if "state_dict" in list(sd.keys()):
+ sd = sd["state_dict"]
+ keys = list(sd.keys())
+ for k in keys:
+ for ik in ignore_keys:
+ if k.startswith(ik):
+ print("Deleting key {} from state_dict.".format(k))
+ del sd[k]
+ missing, unexpected = self.load_state_dict(sd, strict=False) if not only_model else self.model.load_state_dict(
+ sd, strict=False)
+ print(f"Restored from {path} with {len(missing)} missing and {len(unexpected)} unexpected keys")
+ if len(missing) > 0:
+ print(f"Missing Keys: {missing}")
+ if len(unexpected) > 0:
+ print(f"Unexpected Keys: {unexpected}")
+
+ def q_mean_variance(self, x_start, t):
+ """
+ Get the distribution q(x_t | x_0).
+ :param x_start: the [N x C x ...] tensor of noiseless inputs.
+ :param t: the number of diffusion steps (minus 1). Here, 0 means one step.
+ :return: A tuple (mean, variance, log_variance), all of x_start's shape.
+ """
+ mean = (extract_into_tensor(self.sqrt_alphas_cumprod, t, x_start.shape) * x_start)
+ variance = extract_into_tensor(1.0 - self.alphas_cumprod, t, x_start.shape)
+ log_variance = extract_into_tensor(self.log_one_minus_alphas_cumprod, t, x_start.shape)
+ return mean, variance, log_variance
+
+ def predict_start_from_noise(self, x_t, t, noise):
+ return (
+ extract_into_tensor(self.sqrt_recip_alphas_cumprod, t, x_t.shape) * x_t -
+ extract_into_tensor(self.sqrt_recipm1_alphas_cumprod, t, x_t.shape) * noise
+ )
+
+ def q_posterior(self, x_start, x_t, t):
+ posterior_mean = (
+ extract_into_tensor(self.posterior_mean_coef1, t, x_t.shape) * x_start +
+ extract_into_tensor(self.posterior_mean_coef2, t, x_t.shape) * x_t
+ )
+ posterior_variance = extract_into_tensor(self.posterior_variance, t, x_t.shape)
+ posterior_log_variance_clipped = extract_into_tensor(self.posterior_log_variance_clipped, t, x_t.shape)
+ return posterior_mean, posterior_variance, posterior_log_variance_clipped
+
+ def p_mean_variance(self, x, t, clip_denoised: bool):
+ model_out = self.model(x, t)
+ if self.parameterization == "eps":
+ x_recon = self.predict_start_from_noise(x, t=t, noise=model_out)
+ elif self.parameterization == "x0":
+ x_recon = model_out
+ if clip_denoised:
+ x_recon.clamp_(-1., 1.)
+
+ model_mean, posterior_variance, posterior_log_variance = self.q_posterior(x_start=x_recon, x_t=x, t=t)
+ return model_mean, posterior_variance, posterior_log_variance
+
+ @torch.no_grad()
+ def p_sample(self, x, t, clip_denoised=True, repeat_noise=False):
+ b, *_, device = *x.shape, x.device
+ model_mean, _, model_log_variance = self.p_mean_variance(x=x, t=t, clip_denoised=clip_denoised)
+ noise = noise_like(x.shape, device, repeat_noise)
+ # no noise when t == 0
+ nonzero_mask = (1 - (t == 0).float()).reshape(b, *((1,) * (len(x.shape) - 1)))
+ return model_mean + nonzero_mask * (0.5 * model_log_variance).exp() * noise
+
+ @torch.no_grad()
+ def p_sample_loop(self, shape, return_intermediates=False):
+ device = self.betas.device
+ b = shape[0]
+ img = torch.randn(shape, device=device)
+ intermediates = [img]
+ for i in tqdm(reversed(range(0, self.num_timesteps)), desc='Sampling t', total=self.num_timesteps):
+ img = self.p_sample(img, torch.full((b,), i, device=device, dtype=torch.long),
+ clip_denoised=self.clip_denoised)
+ if i % self.log_every_t == 0 or i == self.num_timesteps - 1:
+ intermediates.append(img)
+ if return_intermediates:
+ return img, intermediates
+ return img
+
+ @torch.no_grad()
+ def sample(self, batch_size=16, return_intermediates=False):
+ image_size = self.image_size
+ channels = self.channels
+ return self.p_sample_loop((batch_size, channels, image_size, image_size),
+ return_intermediates=return_intermediates)
+
+ def q_sample(self, x_start, t, noise=None):
+ noise = default(noise, lambda: torch.randn_like(x_start))
+ return (extract_into_tensor(self.sqrt_alphas_cumprod, t, x_start.shape) * x_start +
+ extract_into_tensor(self.sqrt_one_minus_alphas_cumprod, t, x_start.shape) * noise)
+
+ def get_loss(self, pred, target, mean=True):
+ if self.loss_type == 'l1':
+ loss = (target - pred).abs()
+ if mean:
+ loss = loss.mean()
+ elif self.loss_type == 'l2':
+ if mean:
+ loss = torch.nn.functional.mse_loss(target, pred)
+ else:
+ loss = torch.nn.functional.mse_loss(target, pred, reduction='none')
+ else:
+ raise NotImplementedError("unknown loss type '{loss_type}'")
+
+ return loss
+
+ def p_losses(self, x_start, t, noise=None):
+ noise = default(noise, lambda: torch.randn_like(x_start))
+ x_noisy = self.q_sample(x_start=x_start, t=t, noise=noise)
+ model_out = self.model(x_noisy, t)
+
+ loss_dict = {}
+ if self.parameterization == "eps":
+ target = noise
+ elif self.parameterization == "x0":
+ target = x_start
+ else:
+ raise NotImplementedError(f"Paramterization {self.parameterization} not yet supported")
+
+ loss = self.get_loss(model_out, target, mean=False).mean(dim=[1, 2, 3])
+
+ log_prefix = 'train' if self.training else 'val'
+
+ loss_dict.update({f'{log_prefix}/loss_simple': loss.mean()})
+ loss_simple = loss.mean() * self.l_simple_weight
+
+ loss_vlb = (self.lvlb_weights[t] * loss).mean()
+ loss_dict.update({f'{log_prefix}/loss_vlb': loss_vlb})
+
+ loss = loss_simple + self.original_elbo_weight * loss_vlb
+
+ loss_dict.update({f'{log_prefix}/loss': loss})
+
+ return loss, loss_dict
+
+ def forward(self, x, *args, **kwargs):
+ # b, c, h, w, device, img_size, = *x.shape, x.device, self.image_size
+ # assert h == img_size and w == img_size, f'height and width of image must be {img_size}'
+ t = torch.randint(0, self.num_timesteps, (x.shape[0],), device=self.device).long()
+ return self.p_losses(x, t, *args, **kwargs)
+
+ def get_input(self, batch, k):
+ x = batch[k]
+ if len(x.shape) == 3:
+ x = x[..., None]
+ x = rearrange(x, 'b h w c -> b c h w')
+ x = x.to(memory_format=torch.contiguous_format).float()
+ return x
+
+ def shared_step(self, batch):
+ x = self.get_input(batch, self.first_stage_key)
+ loss, loss_dict = self(x)
+ return loss, loss_dict
+
+ def training_step(self, batch, batch_idx):
+ loss, loss_dict = self.shared_step(batch)
+
+ self.log_dict(loss_dict, prog_bar=True,
+ logger=True, on_step=True, on_epoch=True)
+
+ self.log("global_step", self.global_step,
+ prog_bar=True, logger=True, on_step=True, on_epoch=False)
+
+ if self.use_scheduler:
+ lr = self.optimizers().param_groups[0]['lr']
+ self.log('lr_abs', lr, prog_bar=True, logger=True, on_step=True, on_epoch=False)
+
+ return loss
+
+ @torch.no_grad()
+ def validation_step(self, batch, batch_idx):
+ _, loss_dict_no_ema = self.shared_step(batch)
+ with self.ema_scope():
+ _, loss_dict_ema = self.shared_step(batch)
+ loss_dict_ema = {key + '_ema': loss_dict_ema[key] for key in loss_dict_ema}
+ self.log_dict(loss_dict_no_ema, prog_bar=False, logger=True, on_step=False, on_epoch=True)
+ self.log_dict(loss_dict_ema, prog_bar=False, logger=True, on_step=False, on_epoch=True)
+
+ def on_train_batch_end(self, *args, **kwargs):
+ if self.use_ema:
+ self.model_ema(self.model)
+
+ def _get_rows_from_list(self, samples):
+ n_imgs_per_row = len(samples)
+ denoise_grid = rearrange(samples, 'n b c h w -> b n c h w')
+ denoise_grid = rearrange(denoise_grid, 'b n c h w -> (b n) c h w')
+ denoise_grid = make_grid(denoise_grid, nrow=n_imgs_per_row)
+ return denoise_grid
+
+ @torch.no_grad()
+ def log_images(self, batch, N=8, n_row=2, sample=True, return_keys=None, **kwargs):
+ log = dict()
+ x = self.get_input(batch, self.first_stage_key)
+ N = min(x.shape[0], N)
+ n_row = min(x.shape[0], n_row)
+ x = x.to(self.device)[:N]
+ log["inputs"] = x
+
+ # get diffusion row
+ diffusion_row = list()
+ x_start = x[:n_row]
+
+ for t in range(self.num_timesteps):
+ if t % self.log_every_t == 0 or t == self.num_timesteps - 1:
+ t = repeat(torch.tensor([t]), '1 -> b', b=n_row)
+ t = t.to(self.device).long()
+ noise = torch.randn_like(x_start)
+ x_noisy = self.q_sample(x_start=x_start, t=t, noise=noise)
+ diffusion_row.append(x_noisy)
+
+ log["diffusion_row"] = self._get_rows_from_list(diffusion_row)
+
+ if sample:
+ # get denoise row
+ with self.ema_scope("Plotting"):
+ samples, denoise_row = self.sample(batch_size=N, return_intermediates=True)
+
+ log["samples"] = samples
+ log["denoise_row"] = self._get_rows_from_list(denoise_row)
+
+ if return_keys:
+ if np.intersect1d(list(log.keys()), return_keys).shape[0] == 0:
+ return log
+ else:
+ return {key: log[key] for key in return_keys}
+ return log
+
+ def configure_optimizers(self):
+ lr = self.learning_rate
+ params = list(self.model.parameters())
+ if self.learn_logvar:
+ params = params + [self.logvar]
+ opt = torch.optim.AdamW(params, lr=lr)
+ return opt
+
+
+class LatentDiffusion(DDPM):
+ """main class"""
+ def __init__(self,
+ first_stage_config,
+ cond_stage_config,
+ num_timesteps_cond=None,
+ cond_stage_key="image",
+ cond_stage_trainable=False,
+ concat_mode=True,
+ cond_stage_forward=None,
+ conditioning_key=None,
+ scale_factor=1.0,
+ scale_by_std=False,
+ *args, **kwargs):
+ self.num_timesteps_cond = default(num_timesteps_cond, 1)
+ self.scale_by_std = scale_by_std
+ assert self.num_timesteps_cond <= kwargs['timesteps']
+ # for backwards compatibility after implementation of DiffusionWrapper
+ if conditioning_key is None:
+ conditioning_key = 'concat' if concat_mode else 'crossattn'
+ if cond_stage_config == '__is_unconditional__':
+ conditioning_key = None
+ ckpt_path = kwargs.pop("ckpt_path", None)
+ ignore_keys = kwargs.pop("ignore_keys", [])
+ super().__init__(conditioning_key=conditioning_key, *args, **kwargs)
+ self.concat_mode = concat_mode
+ self.cond_stage_trainable = cond_stage_trainable
+ self.cond_stage_key = cond_stage_key
+ try:
+ self.num_downs = len(first_stage_config.params.ddconfig.ch_mult) - 1
+ except:
+ self.num_downs = 0
+ if not scale_by_std:
+ self.scale_factor = scale_factor
+ else:
+ self.register_buffer('scale_factor', torch.tensor(scale_factor))
+ self.instantiate_first_stage(first_stage_config)
+ self.instantiate_cond_stage(cond_stage_config)
+ self.cond_stage_forward = cond_stage_forward
+ self.clip_denoised = False
+ self.bbox_tokenizer = None
+
+ self.restarted_from_ckpt = False
+ if ckpt_path is not None:
+ self.init_from_ckpt(ckpt_path, ignore_keys)
+ self.restarted_from_ckpt = True
+
+ def make_cond_schedule(self, ):
+ self.cond_ids = torch.full(size=(self.num_timesteps,), fill_value=self.num_timesteps - 1, dtype=torch.long)
+ ids = torch.round(torch.linspace(0, self.num_timesteps - 1, self.num_timesteps_cond)).long()
+ self.cond_ids[:self.num_timesteps_cond] = ids
+
+ @rank_zero_only
+ @torch.no_grad()
+ def on_train_batch_start(self, batch, batch_idx, dataloader_idx):
+ # only for very first batch
+ if self.scale_by_std and self.current_epoch == 0 and self.global_step == 0 and batch_idx == 0 and not self.restarted_from_ckpt:
+ assert self.scale_factor == 1., 'rather not use custom rescaling and std-rescaling simultaneously'
+ # set rescale weight to 1./std of encodings
+ print("### USING STD-RESCALING ###")
+ x = super().get_input(batch, self.first_stage_key)
+ x = x.to(self.device)
+ encoder_posterior = self.encode_first_stage(x)
+ z = self.get_first_stage_encoding(encoder_posterior).detach()
+ del self.scale_factor
+ self.register_buffer('scale_factor', 1. / z.flatten().std())
+ print(f"setting self.scale_factor to {self.scale_factor}")
+ print("### USING STD-RESCALING ###")
+
+ def register_schedule(self,
+ given_betas=None, beta_schedule="linear", timesteps=1000,
+ linear_start=1e-4, linear_end=2e-2, cosine_s=8e-3):
+ super().register_schedule(given_betas, beta_schedule, timesteps, linear_start, linear_end, cosine_s)
+
+ self.shorten_cond_schedule = self.num_timesteps_cond > 1
+ if self.shorten_cond_schedule:
+ self.make_cond_schedule()
+
+ def instantiate_first_stage(self, config):
+ model = instantiate_from_config(config)
+ self.first_stage_model = model.eval()
+ self.first_stage_model.train = disabled_train
+ for param in self.first_stage_model.parameters():
+ param.requires_grad = False
+
+ def instantiate_cond_stage(self, config):
+ if not self.cond_stage_trainable:
+ if config == "__is_first_stage__":
+ print("Using first stage also as cond stage.")
+ self.cond_stage_model = self.first_stage_model
+ elif config == "__is_unconditional__":
+ print(f"Training {self.__class__.__name__} as an unconditional model.")
+ self.cond_stage_model = None
+ # self.be_unconditional = True
+ else:
+ model = instantiate_from_config(config)
+ self.cond_stage_model = model.eval()
+ self.cond_stage_model.train = disabled_train
+ for param in self.cond_stage_model.parameters():
+ param.requires_grad = False
+ else:
+ assert config != '__is_first_stage__'
+ assert config != '__is_unconditional__'
+ model = instantiate_from_config(config)
+ self.cond_stage_model = model
+
+ def _get_denoise_row_from_list(self, samples, desc='', force_no_decoder_quantization=False):
+ denoise_row = []
+ for zd in tqdm(samples, desc=desc):
+ denoise_row.append(self.decode_first_stage(zd.to(self.device),
+ force_not_quantize=force_no_decoder_quantization))
+ n_imgs_per_row = len(denoise_row)
+ denoise_row = torch.stack(denoise_row) # n_log_step, n_row, C, H, W
+ denoise_grid = rearrange(denoise_row, 'n b c h w -> b n c h w')
+ denoise_grid = rearrange(denoise_grid, 'b n c h w -> (b n) c h w')
+ denoise_grid = make_grid(denoise_grid, nrow=n_imgs_per_row)
+ return denoise_grid
+
+ def get_first_stage_encoding(self, encoder_posterior):
+ if isinstance(encoder_posterior, DiagonalGaussianDistribution):
+ z = encoder_posterior.sample()
+ elif isinstance(encoder_posterior, torch.Tensor):
+ z = encoder_posterior
+ else:
+ raise NotImplementedError(f"encoder_posterior of type '{type(encoder_posterior)}' not yet implemented")
+ return self.scale_factor * z
+
+ def get_learned_conditioning(self, c):
+ if self.cond_stage_forward is None:
+ if hasattr(self.cond_stage_model, 'encode') and callable(self.cond_stage_model.encode):
+ c = self.cond_stage_model.encode(c)
+ if isinstance(c, DiagonalGaussianDistribution):
+ c = c.mode()
+ else:
+ c = self.cond_stage_model(c)
+ else:
+ assert hasattr(self.cond_stage_model, self.cond_stage_forward)
+ c = getattr(self.cond_stage_model, self.cond_stage_forward)(c)
+ return c
+
+ def meshgrid(self, h, w):
+ y = torch.arange(0, h).view(h, 1, 1).repeat(1, w, 1)
+ x = torch.arange(0, w).view(1, w, 1).repeat(h, 1, 1)
+
+ arr = torch.cat([y, x], dim=-1)
+ return arr
+
+ def delta_border(self, h, w):
+ """
+ :param h: height
+ :param w: width
+ :return: normalized distance to image border,
+ wtith min distance = 0 at border and max dist = 0.5 at image center
+ """
+ lower_right_corner = torch.tensor([h - 1, w - 1]).view(1, 1, 2)
+ arr = self.meshgrid(h, w) / lower_right_corner
+ dist_left_up = torch.min(arr, dim=-1, keepdims=True)[0]
+ dist_right_down = torch.min(1 - arr, dim=-1, keepdims=True)[0]
+ edge_dist = torch.min(torch.cat([dist_left_up, dist_right_down], dim=-1), dim=-1)[0]
+ return edge_dist
+
+ def get_weighting(self, h, w, Ly, Lx, device):
+ weighting = self.delta_border(h, w)
+ weighting = torch.clip(weighting, self.split_input_params["clip_min_weight"],
+ self.split_input_params["clip_max_weight"], )
+ weighting = weighting.view(1, h * w, 1).repeat(1, 1, Ly * Lx).to(device)
+
+ if self.split_input_params["tie_braker"]:
+ L_weighting = self.delta_border(Ly, Lx)
+ L_weighting = torch.clip(L_weighting,
+ self.split_input_params["clip_min_tie_weight"],
+ self.split_input_params["clip_max_tie_weight"])
+
+ L_weighting = L_weighting.view(1, 1, Ly * Lx).to(device)
+ weighting = weighting * L_weighting
+ return weighting
+
+ def get_fold_unfold(self, x, kernel_size, stride, uf=1, df=1): # todo load once not every time, shorten code
+ """
+ :param x: img of size (bs, c, h, w)
+ :return: n img crops of size (n, bs, c, kernel_size[0], kernel_size[1])
+ """
+ bs, nc, h, w = x.shape
+
+ # number of crops in image
+ Ly = (h - kernel_size[0]) // stride[0] + 1
+ Lx = (w - kernel_size[1]) // stride[1] + 1
+
+ if uf == 1 and df == 1:
+ fold_params = dict(kernel_size=kernel_size, dilation=1, padding=0, stride=stride)
+ unfold = torch.nn.Unfold(**fold_params)
+
+ fold = torch.nn.Fold(output_size=x.shape[2:], **fold_params)
+
+ weighting = self.get_weighting(kernel_size[0], kernel_size[1], Ly, Lx, x.device).to(x.dtype)
+ normalization = fold(weighting).view(1, 1, h, w) # normalizes the overlap
+ weighting = weighting.view((1, 1, kernel_size[0], kernel_size[1], Ly * Lx))
+
+ elif uf > 1 and df == 1:
+ fold_params = dict(kernel_size=kernel_size, dilation=1, padding=0, stride=stride)
+ unfold = torch.nn.Unfold(**fold_params)
+
+ fold_params2 = dict(kernel_size=(kernel_size[0] * uf, kernel_size[0] * uf),
+ dilation=1, padding=0,
+ stride=(stride[0] * uf, stride[1] * uf))
+ fold = torch.nn.Fold(output_size=(x.shape[2] * uf, x.shape[3] * uf), **fold_params2)
+
+ weighting = self.get_weighting(kernel_size[0] * uf, kernel_size[1] * uf, Ly, Lx, x.device).to(x.dtype)
+ normalization = fold(weighting).view(1, 1, h * uf, w * uf) # normalizes the overlap
+ weighting = weighting.view((1, 1, kernel_size[0] * uf, kernel_size[1] * uf, Ly * Lx))
+
+ elif df > 1 and uf == 1:
+ fold_params = dict(kernel_size=kernel_size, dilation=1, padding=0, stride=stride)
+ unfold = torch.nn.Unfold(**fold_params)
+
+ fold_params2 = dict(kernel_size=(kernel_size[0] // df, kernel_size[0] // df),
+ dilation=1, padding=0,
+ stride=(stride[0] // df, stride[1] // df))
+ fold = torch.nn.Fold(output_size=(x.shape[2] // df, x.shape[3] // df), **fold_params2)
+
+ weighting = self.get_weighting(kernel_size[0] // df, kernel_size[1] // df, Ly, Lx, x.device).to(x.dtype)
+ normalization = fold(weighting).view(1, 1, h // df, w // df) # normalizes the overlap
+ weighting = weighting.view((1, 1, kernel_size[0] // df, kernel_size[1] // df, Ly * Lx))
+
+ else:
+ raise NotImplementedError
+
+ return fold, unfold, normalization, weighting
+
+ @torch.no_grad()
+ def get_input(self, batch, k, return_first_stage_outputs=False, force_c_encode=False,
+ cond_key=None, return_original_cond=False, bs=None):
+ x = super().get_input(batch, k)
+ if bs is not None:
+ x = x[:bs]
+ x = x.to(self.device)
+ encoder_posterior = self.encode_first_stage(x)
+ z = self.get_first_stage_encoding(encoder_posterior).detach()
+
+ if self.model.conditioning_key is not None:
+ if cond_key is None:
+ cond_key = self.cond_stage_key
+ if cond_key != self.first_stage_key:
+ if cond_key in ['caption', 'coordinates_bbox']:
+ xc = batch[cond_key]
+ elif cond_key == 'class_label':
+ xc = batch
+ else:
+ xc = super().get_input(batch, cond_key).to(self.device)
+ else:
+ xc = x
+ if not self.cond_stage_trainable or force_c_encode:
+ if isinstance(xc, dict) or isinstance(xc, list):
+ # import pudb; pudb.set_trace()
+ c = self.get_learned_conditioning(xc)
+ else:
+ c = self.get_learned_conditioning(xc.to(self.device))
+ else:
+ c = xc
+ if bs is not None:
+ c = c[:bs]
+
+ if self.use_positional_encodings:
+ pos_x, pos_y = self.compute_latent_shifts(batch)
+ ckey = __conditioning_keys__[self.model.conditioning_key]
+ c = {ckey: c, 'pos_x': pos_x, 'pos_y': pos_y}
+
+ else:
+ c = None
+ xc = None
+ if self.use_positional_encodings:
+ pos_x, pos_y = self.compute_latent_shifts(batch)
+ c = {'pos_x': pos_x, 'pos_y': pos_y}
+ out = [z, c]
+ if return_first_stage_outputs:
+ xrec = self.decode_first_stage(z)
+ out.extend([x, xrec])
+ if return_original_cond:
+ out.append(xc)
+ return out
+
+ @torch.no_grad()
+ def decode_first_stage(self, z, predict_cids=False, force_not_quantize=False):
+ if predict_cids:
+ if z.dim() == 4:
+ z = torch.argmax(z.exp(), dim=1).long()
+ z = self.first_stage_model.quantize.get_codebook_entry(z, shape=None)
+ z = rearrange(z, 'b h w c -> b c h w').contiguous()
+
+ z = 1. / self.scale_factor * z
+
+ if hasattr(self, "split_input_params"):
+ if self.split_input_params["patch_distributed_vq"]:
+ ks = self.split_input_params["ks"] # eg. (128, 128)
+ stride = self.split_input_params["stride"] # eg. (64, 64)
+ uf = self.split_input_params["vqf"]
+ bs, nc, h, w = z.shape
+ if ks[0] > h or ks[1] > w:
+ ks = (min(ks[0], h), min(ks[1], w))
+ print("reducing Kernel")
+
+ if stride[0] > h or stride[1] > w:
+ stride = (min(stride[0], h), min(stride[1], w))
+ print("reducing stride")
+
+ fold, unfold, normalization, weighting = self.get_fold_unfold(z, ks, stride, uf=uf)
+
+ z = unfold(z) # (bn, nc * prod(**ks), L)
+ # 1. Reshape to img shape
+ z = z.view((z.shape[0], -1, ks[0], ks[1], z.shape[-1])) # (bn, nc, ks[0], ks[1], L )
+
+ # 2. apply model loop over last dim
+ if isinstance(self.first_stage_model, VQModelInterface):
+ output_list = [self.first_stage_model.decode(z[:, :, :, :, i],
+ force_not_quantize=predict_cids or force_not_quantize)
+ for i in range(z.shape[-1])]
+ else:
+
+ output_list = [self.first_stage_model.decode(z[:, :, :, :, i])
+ for i in range(z.shape[-1])]
+
+ o = torch.stack(output_list, axis=-1) # # (bn, nc, ks[0], ks[1], L)
+ o = o * weighting
+ # Reverse 1. reshape to img shape
+ o = o.view((o.shape[0], -1, o.shape[-1])) # (bn, nc * ks[0] * ks[1], L)
+ # stitch crops together
+ decoded = fold(o)
+ decoded = decoded / normalization # norm is shape (1, 1, h, w)
+ return decoded
+ else:
+ if isinstance(self.first_stage_model, VQModelInterface):
+ return self.first_stage_model.decode(z, force_not_quantize=predict_cids or force_not_quantize)
+ else:
+ return self.first_stage_model.decode(z)
+
+ else:
+ if isinstance(self.first_stage_model, VQModelInterface):
+ return self.first_stage_model.decode(z, force_not_quantize=predict_cids or force_not_quantize)
+ else:
+ return self.first_stage_model.decode(z)
+
+ # same as above but without decorator
+ def differentiable_decode_first_stage(self, z, predict_cids=False, force_not_quantize=False):
+ if predict_cids:
+ if z.dim() == 4:
+ z = torch.argmax(z.exp(), dim=1).long()
+ z = self.first_stage_model.quantize.get_codebook_entry(z, shape=None)
+ z = rearrange(z, 'b h w c -> b c h w').contiguous()
+
+ z = 1. / self.scale_factor * z
+
+ if hasattr(self, "split_input_params"):
+ if self.split_input_params["patch_distributed_vq"]:
+ ks = self.split_input_params["ks"] # eg. (128, 128)
+ stride = self.split_input_params["stride"] # eg. (64, 64)
+ uf = self.split_input_params["vqf"]
+ bs, nc, h, w = z.shape
+ if ks[0] > h or ks[1] > w:
+ ks = (min(ks[0], h), min(ks[1], w))
+ print("reducing Kernel")
+
+ if stride[0] > h or stride[1] > w:
+ stride = (min(stride[0], h), min(stride[1], w))
+ print("reducing stride")
+
+ fold, unfold, normalization, weighting = self.get_fold_unfold(z, ks, stride, uf=uf)
+
+ z = unfold(z) # (bn, nc * prod(**ks), L)
+ # 1. Reshape to img shape
+ z = z.view((z.shape[0], -1, ks[0], ks[1], z.shape[-1])) # (bn, nc, ks[0], ks[1], L )
+
+ # 2. apply model loop over last dim
+ if isinstance(self.first_stage_model, VQModelInterface):
+ output_list = [self.first_stage_model.decode(z[:, :, :, :, i],
+ force_not_quantize=predict_cids or force_not_quantize)
+ for i in range(z.shape[-1])]
+ else:
+
+ output_list = [self.first_stage_model.decode(z[:, :, :, :, i])
+ for i in range(z.shape[-1])]
+
+ o = torch.stack(output_list, axis=-1) # # (bn, nc, ks[0], ks[1], L)
+ o = o * weighting
+ # Reverse 1. reshape to img shape
+ o = o.view((o.shape[0], -1, o.shape[-1])) # (bn, nc * ks[0] * ks[1], L)
+ # stitch crops together
+ decoded = fold(o)
+ decoded = decoded / normalization # norm is shape (1, 1, h, w)
+ return decoded
+ else:
+ if isinstance(self.first_stage_model, VQModelInterface):
+ return self.first_stage_model.decode(z, force_not_quantize=predict_cids or force_not_quantize)
+ else:
+ return self.first_stage_model.decode(z)
+
+ else:
+ if isinstance(self.first_stage_model, VQModelInterface):
+ return self.first_stage_model.decode(z, force_not_quantize=predict_cids or force_not_quantize)
+ else:
+ return self.first_stage_model.decode(z)
+
+ @torch.no_grad()
+ def encode_first_stage(self, x):
+ if hasattr(self, "split_input_params"):
+ if self.split_input_params["patch_distributed_vq"]:
+ ks = self.split_input_params["ks"] # eg. (128, 128)
+ stride = self.split_input_params["stride"] # eg. (64, 64)
+ df = self.split_input_params["vqf"]
+ self.split_input_params['original_image_size'] = x.shape[-2:]
+ bs, nc, h, w = x.shape
+ if ks[0] > h or ks[1] > w:
+ ks = (min(ks[0], h), min(ks[1], w))
+ print("reducing Kernel")
+
+ if stride[0] > h or stride[1] > w:
+ stride = (min(stride[0], h), min(stride[1], w))
+ print("reducing stride")
+
+ fold, unfold, normalization, weighting = self.get_fold_unfold(x, ks, stride, df=df)
+ z = unfold(x) # (bn, nc * prod(**ks), L)
+ # Reshape to img shape
+ z = z.view((z.shape[0], -1, ks[0], ks[1], z.shape[-1])) # (bn, nc, ks[0], ks[1], L )
+
+ output_list = [self.first_stage_model.encode(z[:, :, :, :, i])
+ for i in range(z.shape[-1])]
+
+ o = torch.stack(output_list, axis=-1)
+ o = o * weighting
+
+ # Reverse reshape to img shape
+ o = o.view((o.shape[0], -1, o.shape[-1])) # (bn, nc * ks[0] * ks[1], L)
+ # stitch crops together
+ decoded = fold(o)
+ decoded = decoded / normalization
+ return decoded
+
+ else:
+ return self.first_stage_model.encode(x)
+ else:
+ return self.first_stage_model.encode(x)
+
+ def shared_step(self, batch, **kwargs):
+ x, c = self.get_input(batch, self.first_stage_key)
+ loss = self(x, c)
+ return loss
+
+ def forward(self, x, c, *args, **kwargs):
+ t = torch.randint(0, self.num_timesteps, (x.shape[0],), device=self.device).long()
+ if self.model.conditioning_key is not None:
+ assert c is not None
+ if self.cond_stage_trainable:
+ c = self.get_learned_conditioning(c)
+ if self.shorten_cond_schedule: # TODO: drop this option
+ tc = self.cond_ids[t].to(self.device)
+ c = self.q_sample(x_start=c, t=tc, noise=torch.randn_like(c.float()))
+ return self.p_losses(x, c, t, *args, **kwargs)
+
+ def _rescale_annotations(self, bboxes, crop_coordinates): # TODO: move to dataset
+ def rescale_bbox(bbox):
+ x0 = clamp((bbox[0] - crop_coordinates[0]) / crop_coordinates[2])
+ y0 = clamp((bbox[1] - crop_coordinates[1]) / crop_coordinates[3])
+ w = min(bbox[2] / crop_coordinates[2], 1 - x0)
+ h = min(bbox[3] / crop_coordinates[3], 1 - y0)
+ return x0, y0, w, h
+
+ return [rescale_bbox(b) for b in bboxes]
+
+ def apply_model(self, x_noisy, t, cond, return_ids=False):
+
+ if isinstance(cond, dict):
+ # hybrid case, cond is exptected to be a dict
+ pass
+ else:
+ if not isinstance(cond, list):
+ cond = [cond]
+ key = 'c_concat' if self.model.conditioning_key == 'concat' else 'c_crossattn'
+ cond = {key: cond}
+
+ if hasattr(self, "split_input_params"):
+ assert len(cond) == 1 # todo can only deal with one conditioning atm
+ assert not return_ids
+ ks = self.split_input_params["ks"] # eg. (128, 128)
+ stride = self.split_input_params["stride"] # eg. (64, 64)
+
+ h, w = x_noisy.shape[-2:]
+
+ fold, unfold, normalization, weighting = self.get_fold_unfold(x_noisy, ks, stride)
+
+ z = unfold(x_noisy) # (bn, nc * prod(**ks), L)
+ # Reshape to img shape
+ z = z.view((z.shape[0], -1, ks[0], ks[1], z.shape[-1])) # (bn, nc, ks[0], ks[1], L )
+ z_list = [z[:, :, :, :, i] for i in range(z.shape[-1])]
+
+ if self.cond_stage_key in ["image", "LR_image", "segmentation",
+ 'bbox_img'] and self.model.conditioning_key: # todo check for completeness
+ c_key = next(iter(cond.keys())) # get key
+ c = next(iter(cond.values())) # get value
+ assert (len(c) == 1) # todo extend to list with more than one elem
+ c = c[0] # get element
+
+ c = unfold(c)
+ c = c.view((c.shape[0], -1, ks[0], ks[1], c.shape[-1])) # (bn, nc, ks[0], ks[1], L )
+
+ cond_list = [{c_key: [c[:, :, :, :, i]]} for i in range(c.shape[-1])]
+
+ elif self.cond_stage_key == 'coordinates_bbox':
+ assert 'original_image_size' in self.split_input_params, 'BoudingBoxRescaling is missing original_image_size'
+
+ # assuming padding of unfold is always 0 and its dilation is always 1
+ n_patches_per_row = int((w - ks[0]) / stride[0] + 1)
+ full_img_h, full_img_w = self.split_input_params['original_image_size']
+ # as we are operating on latents, we need the factor from the original image size to the
+ # spatial latent size to properly rescale the crops for regenerating the bbox annotations
+ num_downs = self.first_stage_model.encoder.num_resolutions - 1
+ rescale_latent = 2 ** (num_downs)
+
+ # get top left postions of patches as conforming for the bbbox tokenizer, therefore we
+ # need to rescale the tl patch coordinates to be in between (0,1)
+ tl_patch_coordinates = [(rescale_latent * stride[0] * (patch_nr % n_patches_per_row) / full_img_w,
+ rescale_latent * stride[1] * (patch_nr // n_patches_per_row) / full_img_h)
+ for patch_nr in range(z.shape[-1])]
+
+ # patch_limits are tl_coord, width and height coordinates as (x_tl, y_tl, h, w)
+ patch_limits = [(x_tl, y_tl,
+ rescale_latent * ks[0] / full_img_w,
+ rescale_latent * ks[1] / full_img_h) for x_tl, y_tl in tl_patch_coordinates]
+ # patch_values = [(np.arange(x_tl,min(x_tl+ks, 1.)),np.arange(y_tl,min(y_tl+ks, 1.))) for x_tl, y_tl in tl_patch_coordinates]
+
+ # tokenize crop coordinates for the bounding boxes of the respective patches
+ patch_limits_tknzd = [torch.LongTensor(self.bbox_tokenizer._crop_encoder(bbox))[None].to(self.device)
+ for bbox in patch_limits] # list of length l with tensors of shape (1, 2)
+ print(patch_limits_tknzd[0].shape)
+ # cut tknzd crop position from conditioning
+ assert isinstance(cond, dict), 'cond must be dict to be fed into model'
+ cut_cond = cond['c_crossattn'][0][..., :-2].to(self.device)
+ print(cut_cond.shape)
+
+ adapted_cond = torch.stack([torch.cat([cut_cond, p], dim=1) for p in patch_limits_tknzd])
+ adapted_cond = rearrange(adapted_cond, 'l b n -> (l b) n')
+ print(adapted_cond.shape)
+ adapted_cond = self.get_learned_conditioning(adapted_cond)
+ print(adapted_cond.shape)
+ adapted_cond = rearrange(adapted_cond, '(l b) n d -> l b n d', l=z.shape[-1])
+ print(adapted_cond.shape)
+
+ cond_list = [{'c_crossattn': [e]} for e in adapted_cond]
+
+ else:
+ cond_list = [cond for i in range(z.shape[-1])] # Todo make this more efficient
+
+ # apply model by loop over crops
+ output_list = [self.model(z_list[i], t, **cond_list[i]) for i in range(z.shape[-1])]
+ assert not isinstance(output_list[0],
+ tuple) # todo cant deal with multiple model outputs check this never happens
+
+ o = torch.stack(output_list, axis=-1)
+ o = o * weighting
+ # Reverse reshape to img shape
+ o = o.view((o.shape[0], -1, o.shape[-1])) # (bn, nc * ks[0] * ks[1], L)
+ # stitch crops together
+ x_recon = fold(o) / normalization
+
+ else:
+ x_recon = self.model(x_noisy, t, **cond)
+
+ if isinstance(x_recon, tuple) and not return_ids:
+ return x_recon[0]
+ else:
+ return x_recon
+
+ def _predict_eps_from_xstart(self, x_t, t, pred_xstart):
+ return (extract_into_tensor(self.sqrt_recip_alphas_cumprod, t, x_t.shape) * x_t - pred_xstart) / \
+ extract_into_tensor(self.sqrt_recipm1_alphas_cumprod, t, x_t.shape)
+
+ def _prior_bpd(self, x_start):
+ """
+ Get the prior KL term for the variational lower-bound, measured in
+ bits-per-dim.
+ This term can't be optimized, as it only depends on the encoder.
+ :param x_start: the [N x C x ...] tensor of inputs.
+ :return: a batch of [N] KL values (in bits), one per batch element.
+ """
+ batch_size = x_start.shape[0]
+ t = torch.tensor([self.num_timesteps - 1] * batch_size, device=x_start.device)
+ qt_mean, _, qt_log_variance = self.q_mean_variance(x_start, t)
+ kl_prior = normal_kl(mean1=qt_mean, logvar1=qt_log_variance, mean2=0.0, logvar2=0.0)
+ return mean_flat(kl_prior) / np.log(2.0)
+
+ def p_losses(self, x_start, cond, t, noise=None):
+ noise = default(noise, lambda: torch.randn_like(x_start))
+ x_noisy = self.q_sample(x_start=x_start, t=t, noise=noise)
+ model_output = self.apply_model(x_noisy, t, cond)
+
+ loss_dict = {}
+ prefix = 'train' if self.training else 'val'
+
+ if self.parameterization == "x0":
+ target = x_start
+ elif self.parameterization == "eps":
+ target = noise
+ else:
+ raise NotImplementedError()
+
+ loss_simple = self.get_loss(model_output, target, mean=False).mean([1, 2, 3])
+ loss_dict.update({f'{prefix}/loss_simple': loss_simple.mean()})
+
+ logvar_t = self.logvar[t].to(self.device)
+ loss = loss_simple / torch.exp(logvar_t) + logvar_t
+ # loss = loss_simple / torch.exp(self.logvar) + self.logvar
+ if self.learn_logvar:
+ loss_dict.update({f'{prefix}/loss_gamma': loss.mean()})
+ loss_dict.update({'logvar': self.logvar.data.mean()})
+
+ loss = self.l_simple_weight * loss.mean()
+
+ loss_vlb = self.get_loss(model_output, target, mean=False).mean(dim=(1, 2, 3))
+ loss_vlb = (self.lvlb_weights[t] * loss_vlb).mean()
+ loss_dict.update({f'{prefix}/loss_vlb': loss_vlb})
+ loss += (self.original_elbo_weight * loss_vlb)
+ loss_dict.update({f'{prefix}/loss': loss})
+
+ return loss, loss_dict
+
+ def p_mean_variance(self, x, c, t, clip_denoised: bool, return_codebook_ids=False, quantize_denoised=False,
+ return_x0=False, score_corrector=None, corrector_kwargs=None):
+ t_in = t
+ model_out = self.apply_model(x, t_in, c, return_ids=return_codebook_ids)
+
+ if score_corrector is not None:
+ assert self.parameterization == "eps"
+ model_out = score_corrector.modify_score(self, model_out, x, t, c, **corrector_kwargs)
+
+ if return_codebook_ids:
+ model_out, logits = model_out
+
+ if self.parameterization == "eps":
+ x_recon = self.predict_start_from_noise(x, t=t, noise=model_out)
+ elif self.parameterization == "x0":
+ x_recon = model_out
+ else:
+ raise NotImplementedError()
+
+ if clip_denoised:
+ x_recon.clamp_(-1., 1.)
+ if quantize_denoised:
+ x_recon, _, [_, _, indices] = self.first_stage_model.quantize(x_recon)
+ model_mean, posterior_variance, posterior_log_variance = self.q_posterior(x_start=x_recon, x_t=x, t=t)
+ if return_codebook_ids:
+ return model_mean, posterior_variance, posterior_log_variance, logits
+ elif return_x0:
+ return model_mean, posterior_variance, posterior_log_variance, x_recon
+ else:
+ return model_mean, posterior_variance, posterior_log_variance
+
+ @torch.no_grad()
+ def p_sample(self, x, c, t, clip_denoised=False, repeat_noise=False,
+ return_codebook_ids=False, quantize_denoised=False, return_x0=False,
+ temperature=1., noise_dropout=0., score_corrector=None, corrector_kwargs=None):
+ b, *_, device = *x.shape, x.device
+ outputs = self.p_mean_variance(x=x, c=c, t=t, clip_denoised=clip_denoised,
+ return_codebook_ids=return_codebook_ids,
+ quantize_denoised=quantize_denoised,
+ return_x0=return_x0,
+ score_corrector=score_corrector, corrector_kwargs=corrector_kwargs)
+ if return_codebook_ids:
+ raise DeprecationWarning("Support dropped.")
+ model_mean, _, model_log_variance, logits = outputs
+ elif return_x0:
+ model_mean, _, model_log_variance, x0 = outputs
+ else:
+ model_mean, _, model_log_variance = outputs
+
+ noise = noise_like(x.shape, device, repeat_noise) * temperature
+ if noise_dropout > 0.:
+ noise = torch.nn.functional.dropout(noise, p=noise_dropout)
+ # no noise when t == 0
+ nonzero_mask = (1 - (t == 0).float()).reshape(b, *((1,) * (len(x.shape) - 1)))
+
+ if return_codebook_ids:
+ return model_mean + nonzero_mask * (0.5 * model_log_variance).exp() * noise, logits.argmax(dim=1)
+ if return_x0:
+ return model_mean + nonzero_mask * (0.5 * model_log_variance).exp() * noise, x0
+ else:
+ return model_mean + nonzero_mask * (0.5 * model_log_variance).exp() * noise
+
+ @torch.no_grad()
+ def progressive_denoising(self, cond, shape, verbose=True, callback=None, quantize_denoised=False,
+ img_callback=None, mask=None, x0=None, temperature=1., noise_dropout=0.,
+ score_corrector=None, corrector_kwargs=None, batch_size=None, x_T=None, start_T=None,
+ log_every_t=None):
+ if not log_every_t:
+ log_every_t = self.log_every_t
+ timesteps = self.num_timesteps
+ if batch_size is not None:
+ b = batch_size if batch_size is not None else shape[0]
+ shape = [batch_size] + list(shape)
+ else:
+ b = batch_size = shape[0]
+ if x_T is None:
+ img = torch.randn(shape, device=self.device)
+ else:
+ img = x_T
+ intermediates = []
+ if cond is not None:
+ if isinstance(cond, dict):
+ cond = {key: cond[key][:batch_size] if not isinstance(cond[key], list) else
+ list(map(lambda x: x[:batch_size], cond[key])) for key in cond}
+ else:
+ cond = [c[:batch_size] for c in cond] if isinstance(cond, list) else cond[:batch_size]
+
+ if start_T is not None:
+ timesteps = min(timesteps, start_T)
+ iterator = tqdm(reversed(range(0, timesteps)), desc='Progressive Generation',
+ total=timesteps) if verbose else reversed(
+ range(0, timesteps))
+ if type(temperature) == float:
+ temperature = [temperature] * timesteps
+
+ for i in iterator:
+ ts = torch.full((b,), i, device=self.device, dtype=torch.long)
+ if self.shorten_cond_schedule:
+ assert self.model.conditioning_key != 'hybrid'
+ tc = self.cond_ids[ts].to(cond.device)
+ cond = self.q_sample(x_start=cond, t=tc, noise=torch.randn_like(cond))
+
+ img, x0_partial = self.p_sample(img, cond, ts,
+ clip_denoised=self.clip_denoised,
+ quantize_denoised=quantize_denoised, return_x0=True,
+ temperature=temperature[i], noise_dropout=noise_dropout,
+ score_corrector=score_corrector, corrector_kwargs=corrector_kwargs)
+ if mask is not None:
+ assert x0 is not None
+ img_orig = self.q_sample(x0, ts)
+ img = img_orig * mask + (1. - mask) * img
+
+ if i % log_every_t == 0 or i == timesteps - 1:
+ intermediates.append(x0_partial)
+ if callback: callback(i)
+ if img_callback: img_callback(img, i)
+ return img, intermediates
+
+ @torch.no_grad()
+ def p_sample_loop(self, cond, shape, return_intermediates=False,
+ x_T=None, verbose=True, callback=None, timesteps=None, quantize_denoised=False,
+ mask=None, x0=None, img_callback=None, start_T=None,
+ log_every_t=None):
+
+ if not log_every_t:
+ log_every_t = self.log_every_t
+ device = self.betas.device
+ b = shape[0]
+ if x_T is None:
+ img = torch.randn(shape, device=device)
+ else:
+ img = x_T
+
+ intermediates = [img]
+ if timesteps is None:
+ timesteps = self.num_timesteps
+
+ if start_T is not None:
+ timesteps = min(timesteps, start_T)
+ iterator = tqdm(reversed(range(0, timesteps)), desc='Sampling t', total=timesteps) if verbose else reversed(
+ range(0, timesteps))
+
+ if mask is not None:
+ assert x0 is not None
+ assert x0.shape[2:3] == mask.shape[2:3] # spatial size has to match
+
+ for i in iterator:
+ ts = torch.full((b,), i, device=device, dtype=torch.long)
+ if self.shorten_cond_schedule:
+ assert self.model.conditioning_key != 'hybrid'
+ tc = self.cond_ids[ts].to(cond.device)
+ cond = self.q_sample(x_start=cond, t=tc, noise=torch.randn_like(cond))
+
+ img = self.p_sample(img, cond, ts,
+ clip_denoised=self.clip_denoised,
+ quantize_denoised=quantize_denoised)
+ if mask is not None:
+ img_orig = self.q_sample(x0, ts)
+ img = img_orig * mask + (1. - mask) * img
+
+ if i % log_every_t == 0 or i == timesteps - 1:
+ intermediates.append(img)
+ if callback: callback(i)
+ if img_callback: img_callback(img, i)
+
+ if return_intermediates:
+ return img, intermediates
+ return img
+
+ @torch.no_grad()
+ def sample(self, cond, batch_size=16, return_intermediates=False, x_T=None,
+ verbose=True, timesteps=None, quantize_denoised=False,
+ mask=None, x0=None, shape=None,**kwargs):
+ if shape is None:
+ shape = (batch_size, self.channels, self.image_size, self.image_size)
+ if cond is not None:
+ if isinstance(cond, dict):
+ cond = {key: cond[key][:batch_size] if not isinstance(cond[key], list) else
+ list(map(lambda x: x[:batch_size], cond[key])) for key in cond}
+ else:
+ cond = [c[:batch_size] for c in cond] if isinstance(cond, list) else cond[:batch_size]
+ return self.p_sample_loop(cond,
+ shape,
+ return_intermediates=return_intermediates, x_T=x_T,
+ verbose=verbose, timesteps=timesteps, quantize_denoised=quantize_denoised,
+ mask=mask, x0=x0)
+
+ @torch.no_grad()
+ def sample_log(self,cond,batch_size,ddim, ddim_steps,**kwargs):
+
+ if ddim:
+ ddim_sampler = DDIMSampler(self)
+ shape = (self.channels, self.image_size, self.image_size)
+ samples, intermediates =ddim_sampler.sample(ddim_steps,batch_size,
+ shape,cond,verbose=False,**kwargs)
+
+ else:
+ samples, intermediates = self.sample(cond=cond, batch_size=batch_size,
+ return_intermediates=True,**kwargs)
+
+ return samples, intermediates
+
+
+ @torch.no_grad()
+ def log_images(self, batch, N=8, n_row=4, sample=True, ddim_steps=200, ddim_eta=1., return_keys=None,
+ quantize_denoised=True, inpaint=True, plot_denoise_rows=False, plot_progressive_rows=True,
+ plot_diffusion_rows=True, **kwargs):
+
+ use_ddim = ddim_steps is not None
+
+ log = dict()
+ z, c, x, xrec, xc = self.get_input(batch, self.first_stage_key,
+ return_first_stage_outputs=True,
+ force_c_encode=True,
+ return_original_cond=True,
+ bs=N)
+ N = min(x.shape[0], N)
+ n_row = min(x.shape[0], n_row)
+ log["inputs"] = x
+ log["reconstruction"] = xrec
+ if self.model.conditioning_key is not None:
+ if hasattr(self.cond_stage_model, "decode"):
+ xc = self.cond_stage_model.decode(c)
+ log["conditioning"] = xc
+ elif self.cond_stage_key in ["caption"]:
+ xc = log_txt_as_img((x.shape[2], x.shape[3]), batch["caption"])
+ log["conditioning"] = xc
+ elif self.cond_stage_key == 'class_label':
+ xc = log_txt_as_img((x.shape[2], x.shape[3]), batch["human_label"])
+ log['conditioning'] = xc
+ elif isimage(xc):
+ log["conditioning"] = xc
+ if ismap(xc):
+ log["original_conditioning"] = self.to_rgb(xc)
+
+ if plot_diffusion_rows:
+ # get diffusion row
+ diffusion_row = list()
+ z_start = z[:n_row]
+ for t in range(self.num_timesteps):
+ if t % self.log_every_t == 0 or t == self.num_timesteps - 1:
+ t = repeat(torch.tensor([t]), '1 -> b', b=n_row)
+ t = t.to(self.device).long()
+ noise = torch.randn_like(z_start)
+ z_noisy = self.q_sample(x_start=z_start, t=t, noise=noise)
+ diffusion_row.append(self.decode_first_stage(z_noisy))
+
+ diffusion_row = torch.stack(diffusion_row) # n_log_step, n_row, C, H, W
+ diffusion_grid = rearrange(diffusion_row, 'n b c h w -> b n c h w')
+ diffusion_grid = rearrange(diffusion_grid, 'b n c h w -> (b n) c h w')
+ diffusion_grid = make_grid(diffusion_grid, nrow=diffusion_row.shape[0])
+ log["diffusion_row"] = diffusion_grid
+
+ if sample:
+ # get denoise row
+ with self.ema_scope("Plotting"):
+ samples, z_denoise_row = self.sample_log(cond=c,batch_size=N,ddim=use_ddim,
+ ddim_steps=ddim_steps,eta=ddim_eta)
+ # samples, z_denoise_row = self.sample(cond=c, batch_size=N, return_intermediates=True)
+ x_samples = self.decode_first_stage(samples)
+ log["samples"] = x_samples
+ if plot_denoise_rows:
+ denoise_grid = self._get_denoise_row_from_list(z_denoise_row)
+ log["denoise_row"] = denoise_grid
+
+ if quantize_denoised and not isinstance(self.first_stage_model, AutoencoderKL) and not isinstance(
+ self.first_stage_model, IdentityFirstStage):
+ # also display when quantizing x0 while sampling
+ with self.ema_scope("Plotting Quantized Denoised"):
+ samples, z_denoise_row = self.sample_log(cond=c,batch_size=N,ddim=use_ddim,
+ ddim_steps=ddim_steps,eta=ddim_eta,
+ quantize_denoised=True)
+ # samples, z_denoise_row = self.sample(cond=c, batch_size=N, return_intermediates=True,
+ # quantize_denoised=True)
+ x_samples = self.decode_first_stage(samples.to(self.device))
+ log["samples_x0_quantized"] = x_samples
+
+ if inpaint:
+ # make a simple center square
+ b, h, w = z.shape[0], z.shape[2], z.shape[3]
+ mask = torch.ones(N, h, w).to(self.device)
+ # zeros will be filled in
+ mask[:, h // 4:3 * h // 4, w // 4:3 * w // 4] = 0.
+ mask = mask[:, None, ...]
+ with self.ema_scope("Plotting Inpaint"):
+
+ samples, _ = self.sample_log(cond=c,batch_size=N,ddim=use_ddim, eta=ddim_eta,
+ ddim_steps=ddim_steps, x0=z[:N], mask=mask)
+ x_samples = self.decode_first_stage(samples.to(self.device))
+ log["samples_inpainting"] = x_samples
+ log["mask"] = mask
+
+ # outpaint
+ with self.ema_scope("Plotting Outpaint"):
+ samples, _ = self.sample_log(cond=c, batch_size=N, ddim=use_ddim,eta=ddim_eta,
+ ddim_steps=ddim_steps, x0=z[:N], mask=mask)
+ x_samples = self.decode_first_stage(samples.to(self.device))
+ log["samples_outpainting"] = x_samples
+
+ if plot_progressive_rows:
+ with self.ema_scope("Plotting Progressives"):
+ img, progressives = self.progressive_denoising(c,
+ shape=(self.channels, self.image_size, self.image_size),
+ batch_size=N)
+ prog_row = self._get_denoise_row_from_list(progressives, desc="Progressive Generation")
+ log["progressive_row"] = prog_row
+
+ if return_keys:
+ if np.intersect1d(list(log.keys()), return_keys).shape[0] == 0:
+ return log
+ else:
+ return {key: log[key] for key in return_keys}
+ return log
+
+ def configure_optimizers(self):
+ lr = self.learning_rate
+ params = list(self.model.parameters())
+ if self.cond_stage_trainable:
+ print(f"{self.__class__.__name__}: Also optimizing conditioner params!")
+ params = params + list(self.cond_stage_model.parameters())
+ if self.learn_logvar:
+ print('Diffusion model optimizing logvar')
+ params.append(self.logvar)
+ opt = torch.optim.AdamW(params, lr=lr)
+ if self.use_scheduler:
+ assert 'target' in self.scheduler_config
+ scheduler = instantiate_from_config(self.scheduler_config)
+
+ print("Setting up LambdaLR scheduler...")
+ scheduler = [
+ {
+ 'scheduler': LambdaLR(opt, lr_lambda=scheduler.schedule),
+ 'interval': 'step',
+ 'frequency': 1
+ }]
+ return [opt], scheduler
+ return opt
+
+ @torch.no_grad()
+ def to_rgb(self, x):
+ x = x.float()
+ if not hasattr(self, "colorize"):
+ self.colorize = torch.randn(3, x.shape[1], 1, 1).to(x)
+ x = nn.functional.conv2d(x, weight=self.colorize)
+ x = 2. * (x - x.min()) / (x.max() - x.min()) - 1.
+ return x
+
+
+class DiffusionWrapper(pl.LightningModule):
+ def __init__(self, diff_model_config, conditioning_key):
+ super().__init__()
+ self.diffusion_model = instantiate_from_config(diff_model_config)
+ self.conditioning_key = conditioning_key
+ assert self.conditioning_key in [None, 'concat', 'crossattn', 'hybrid', 'adm']
+
+ def forward(self, x, t, c_concat: list = None, c_crossattn: list = None):
+ if self.conditioning_key is None:
+ out = self.diffusion_model(x, t)
+ elif self.conditioning_key == 'concat':
+ xc = torch.cat([x] + c_concat, dim=1)
+ out = self.diffusion_model(xc, t)
+ elif self.conditioning_key == 'crossattn':
+ cc = torch.cat(c_crossattn, 1)
+ out = self.diffusion_model(x, t, context=cc)
+ elif self.conditioning_key == 'hybrid':
+ xc = torch.cat([x] + c_concat, dim=1)
+ cc = torch.cat(c_crossattn, 1)
+ out = self.diffusion_model(xc, t, context=cc)
+ elif self.conditioning_key == 'adm':
+ cc = c_crossattn[0]
+ out = self.diffusion_model(x, t, y=cc)
+ else:
+ raise NotImplementedError()
+
+ return out
+
+
+class Layout2ImgDiffusion(LatentDiffusion):
+ # TODO: move all layout-specific hacks to this class
+ def __init__(self, cond_stage_key, *args, **kwargs):
+ assert cond_stage_key == 'coordinates_bbox', 'Layout2ImgDiffusion only for cond_stage_key="coordinates_bbox"'
+ super().__init__(cond_stage_key=cond_stage_key, *args, **kwargs)
+
+ def log_images(self, batch, N=8, *args, **kwargs):
+ logs = super().log_images(batch=batch, N=N, *args, **kwargs)
+
+ key = 'train' if self.training else 'validation'
+ dset = self.trainer.datamodule.datasets[key]
+ mapper = dset.conditional_builders[self.cond_stage_key]
+
+ bbox_imgs = []
+ map_fn = lambda catno: dset.get_textual_label(dset.get_category_id(catno))
+ for tknzd_bbox in batch[self.cond_stage_key][:N]:
+ bboximg = mapper.plot(tknzd_bbox.detach().cpu(), map_fn, (256, 256))
+ bbox_imgs.append(bboximg)
+
+ cond_img = torch.stack(bbox_imgs, dim=0)
+ logs['bbox_image'] = cond_img
+ return logs
diff --git a/latent-diffusion/ldm/models/diffusion/plms.py b/latent-diffusion/ldm/models/diffusion/plms.py
new file mode 100644
index 0000000000000000000000000000000000000000..78eeb1003aa45d27bdbfc6b4a1d7ccbff57cd2e3
--- /dev/null
+++ b/latent-diffusion/ldm/models/diffusion/plms.py
@@ -0,0 +1,236 @@
+"""SAMPLING ONLY."""
+
+import torch
+import numpy as np
+from tqdm import tqdm
+from functools import partial
+
+from ldm.modules.diffusionmodules.util import make_ddim_sampling_parameters, make_ddim_timesteps, noise_like
+
+
+class PLMSSampler(object):
+ def __init__(self, model, schedule="linear", **kwargs):
+ super().__init__()
+ self.model = model
+ self.ddpm_num_timesteps = model.num_timesteps
+ self.schedule = schedule
+
+ def register_buffer(self, name, attr):
+ if type(attr) == torch.Tensor:
+ if attr.device != torch.device("cuda"):
+ attr = attr.to(torch.device("cuda"))
+ setattr(self, name, attr)
+
+ def make_schedule(self, ddim_num_steps, ddim_discretize="uniform", ddim_eta=0., verbose=True):
+ if ddim_eta != 0:
+ raise ValueError('ddim_eta must be 0 for PLMS')
+ self.ddim_timesteps = make_ddim_timesteps(ddim_discr_method=ddim_discretize, num_ddim_timesteps=ddim_num_steps,
+ num_ddpm_timesteps=self.ddpm_num_timesteps,verbose=verbose)
+ alphas_cumprod = self.model.alphas_cumprod
+ assert alphas_cumprod.shape[0] == self.ddpm_num_timesteps, 'alphas have to be defined for each timestep'
+ to_torch = lambda x: x.clone().detach().to(torch.float32).to(self.model.device)
+
+ self.register_buffer('betas', to_torch(self.model.betas))
+ self.register_buffer('alphas_cumprod', to_torch(alphas_cumprod))
+ self.register_buffer('alphas_cumprod_prev', to_torch(self.model.alphas_cumprod_prev))
+
+ # calculations for diffusion q(x_t | x_{t-1}) and others
+ self.register_buffer('sqrt_alphas_cumprod', to_torch(np.sqrt(alphas_cumprod.cpu())))
+ self.register_buffer('sqrt_one_minus_alphas_cumprod', to_torch(np.sqrt(1. - alphas_cumprod.cpu())))
+ self.register_buffer('log_one_minus_alphas_cumprod', to_torch(np.log(1. - alphas_cumprod.cpu())))
+ self.register_buffer('sqrt_recip_alphas_cumprod', to_torch(np.sqrt(1. / alphas_cumprod.cpu())))
+ self.register_buffer('sqrt_recipm1_alphas_cumprod', to_torch(np.sqrt(1. / alphas_cumprod.cpu() - 1)))
+
+ # ddim sampling parameters
+ ddim_sigmas, ddim_alphas, ddim_alphas_prev = make_ddim_sampling_parameters(alphacums=alphas_cumprod.cpu(),
+ ddim_timesteps=self.ddim_timesteps,
+ eta=ddim_eta,verbose=verbose)
+ self.register_buffer('ddim_sigmas', ddim_sigmas)
+ self.register_buffer('ddim_alphas', ddim_alphas)
+ self.register_buffer('ddim_alphas_prev', ddim_alphas_prev)
+ self.register_buffer('ddim_sqrt_one_minus_alphas', np.sqrt(1. - ddim_alphas))
+ sigmas_for_original_sampling_steps = ddim_eta * torch.sqrt(
+ (1 - self.alphas_cumprod_prev) / (1 - self.alphas_cumprod) * (
+ 1 - self.alphas_cumprod / self.alphas_cumprod_prev))
+ self.register_buffer('ddim_sigmas_for_original_num_steps', sigmas_for_original_sampling_steps)
+
+ @torch.no_grad()
+ def sample(self,
+ S,
+ batch_size,
+ shape,
+ conditioning=None,
+ callback=None,
+ normals_sequence=None,
+ img_callback=None,
+ quantize_x0=False,
+ eta=0.,
+ mask=None,
+ x0=None,
+ temperature=1.,
+ noise_dropout=0.,
+ score_corrector=None,
+ corrector_kwargs=None,
+ verbose=True,
+ x_T=None,
+ log_every_t=100,
+ unconditional_guidance_scale=1.,
+ unconditional_conditioning=None,
+ # this has to come in the same format as the conditioning, # e.g. as encoded tokens, ...
+ **kwargs
+ ):
+ if conditioning is not None:
+ if isinstance(conditioning, dict):
+ cbs = conditioning[list(conditioning.keys())[0]].shape[0]
+ if cbs != batch_size:
+ print(f"Warning: Got {cbs} conditionings but batch-size is {batch_size}")
+ else:
+ if conditioning.shape[0] != batch_size:
+ print(f"Warning: Got {conditioning.shape[0]} conditionings but batch-size is {batch_size}")
+
+ self.make_schedule(ddim_num_steps=S, ddim_eta=eta, verbose=verbose)
+ # sampling
+ C, H, W = shape
+ size = (batch_size, C, H, W)
+ print(f'Data shape for PLMS sampling is {size}')
+
+ samples, intermediates = self.plms_sampling(conditioning, size,
+ callback=callback,
+ img_callback=img_callback,
+ quantize_denoised=quantize_x0,
+ mask=mask, x0=x0,
+ ddim_use_original_steps=False,
+ noise_dropout=noise_dropout,
+ temperature=temperature,
+ score_corrector=score_corrector,
+ corrector_kwargs=corrector_kwargs,
+ x_T=x_T,
+ log_every_t=log_every_t,
+ unconditional_guidance_scale=unconditional_guidance_scale,
+ unconditional_conditioning=unconditional_conditioning,
+ )
+ return samples, intermediates
+
+ @torch.no_grad()
+ def plms_sampling(self, cond, shape,
+ x_T=None, ddim_use_original_steps=False,
+ callback=None, timesteps=None, quantize_denoised=False,
+ mask=None, x0=None, img_callback=None, log_every_t=100,
+ temperature=1., noise_dropout=0., score_corrector=None, corrector_kwargs=None,
+ unconditional_guidance_scale=1., unconditional_conditioning=None,):
+ device = self.model.betas.device
+ b = shape[0]
+ if x_T is None:
+ img = torch.randn(shape, device=device)
+ else:
+ img = x_T
+
+ if timesteps is None:
+ timesteps = self.ddpm_num_timesteps if ddim_use_original_steps else self.ddim_timesteps
+ elif timesteps is not None and not ddim_use_original_steps:
+ subset_end = int(min(timesteps / self.ddim_timesteps.shape[0], 1) * self.ddim_timesteps.shape[0]) - 1
+ timesteps = self.ddim_timesteps[:subset_end]
+
+ intermediates = {'x_inter': [img], 'pred_x0': [img]}
+ time_range = list(reversed(range(0,timesteps))) if ddim_use_original_steps else np.flip(timesteps)
+ total_steps = timesteps if ddim_use_original_steps else timesteps.shape[0]
+ print(f"Running PLMS Sampling with {total_steps} timesteps")
+
+ iterator = tqdm(time_range, desc='PLMS Sampler', total=total_steps)
+ old_eps = []
+
+ for i, step in enumerate(iterator):
+ index = total_steps - i - 1
+ ts = torch.full((b,), step, device=device, dtype=torch.long)
+ ts_next = torch.full((b,), time_range[min(i + 1, len(time_range) - 1)], device=device, dtype=torch.long)
+
+ if mask is not None:
+ assert x0 is not None
+ img_orig = self.model.q_sample(x0, ts) # TODO: deterministic forward pass?
+ img = img_orig * mask + (1. - mask) * img
+
+ outs = self.p_sample_plms(img, cond, ts, index=index, use_original_steps=ddim_use_original_steps,
+ quantize_denoised=quantize_denoised, temperature=temperature,
+ noise_dropout=noise_dropout, score_corrector=score_corrector,
+ corrector_kwargs=corrector_kwargs,
+ unconditional_guidance_scale=unconditional_guidance_scale,
+ unconditional_conditioning=unconditional_conditioning,
+ old_eps=old_eps, t_next=ts_next)
+ img, pred_x0, e_t = outs
+ old_eps.append(e_t)
+ if len(old_eps) >= 4:
+ old_eps.pop(0)
+ if callback: callback(i)
+ if img_callback: img_callback(pred_x0, i)
+
+ if index % log_every_t == 0 or index == total_steps - 1:
+ intermediates['x_inter'].append(img)
+ intermediates['pred_x0'].append(pred_x0)
+
+ return img, intermediates
+
+ @torch.no_grad()
+ def p_sample_plms(self, x, c, t, index, repeat_noise=False, use_original_steps=False, quantize_denoised=False,
+ temperature=1., noise_dropout=0., score_corrector=None, corrector_kwargs=None,
+ unconditional_guidance_scale=1., unconditional_conditioning=None, old_eps=None, t_next=None):
+ b, *_, device = *x.shape, x.device
+
+ def get_model_output(x, t):
+ if unconditional_conditioning is None or unconditional_guidance_scale == 1.:
+ e_t = self.model.apply_model(x, t, c)
+ else:
+ x_in = torch.cat([x] * 2)
+ t_in = torch.cat([t] * 2)
+ c_in = torch.cat([unconditional_conditioning, c])
+ e_t_uncond, e_t = self.model.apply_model(x_in, t_in, c_in).chunk(2)
+ e_t = e_t_uncond + unconditional_guidance_scale * (e_t - e_t_uncond)
+
+ if score_corrector is not None:
+ assert self.model.parameterization == "eps"
+ e_t = score_corrector.modify_score(self.model, e_t, x, t, c, **corrector_kwargs)
+
+ return e_t
+
+ alphas = self.model.alphas_cumprod if use_original_steps else self.ddim_alphas
+ alphas_prev = self.model.alphas_cumprod_prev if use_original_steps else self.ddim_alphas_prev
+ sqrt_one_minus_alphas = self.model.sqrt_one_minus_alphas_cumprod if use_original_steps else self.ddim_sqrt_one_minus_alphas
+ sigmas = self.model.ddim_sigmas_for_original_num_steps if use_original_steps else self.ddim_sigmas
+
+ def get_x_prev_and_pred_x0(e_t, index):
+ # select parameters corresponding to the currently considered timestep
+ a_t = torch.full((b, 1, 1, 1), alphas[index], device=device)
+ a_prev = torch.full((b, 1, 1, 1), alphas_prev[index], device=device)
+ sigma_t = torch.full((b, 1, 1, 1), sigmas[index], device=device)
+ sqrt_one_minus_at = torch.full((b, 1, 1, 1), sqrt_one_minus_alphas[index],device=device)
+
+ # current prediction for x_0
+ pred_x0 = (x - sqrt_one_minus_at * e_t) / a_t.sqrt()
+ if quantize_denoised:
+ pred_x0, _, *_ = self.model.first_stage_model.quantize(pred_x0)
+ # direction pointing to x_t
+ dir_xt = (1. - a_prev - sigma_t**2).sqrt() * e_t
+ noise = sigma_t * noise_like(x.shape, device, repeat_noise) * temperature
+ if noise_dropout > 0.:
+ noise = torch.nn.functional.dropout(noise, p=noise_dropout)
+ x_prev = a_prev.sqrt() * pred_x0 + dir_xt + noise
+ return x_prev, pred_x0
+
+ e_t = get_model_output(x, t)
+ if len(old_eps) == 0:
+ # Pseudo Improved Euler (2nd order)
+ x_prev, pred_x0 = get_x_prev_and_pred_x0(e_t, index)
+ e_t_next = get_model_output(x_prev, t_next)
+ e_t_prime = (e_t + e_t_next) / 2
+ elif len(old_eps) == 1:
+ # 2nd order Pseudo Linear Multistep (Adams-Bashforth)
+ e_t_prime = (3 * e_t - old_eps[-1]) / 2
+ elif len(old_eps) == 2:
+ # 3nd order Pseudo Linear Multistep (Adams-Bashforth)
+ e_t_prime = (23 * e_t - 16 * old_eps[-1] + 5 * old_eps[-2]) / 12
+ elif len(old_eps) >= 3:
+ # 4nd order Pseudo Linear Multistep (Adams-Bashforth)
+ e_t_prime = (55 * e_t - 59 * old_eps[-1] + 37 * old_eps[-2] - 9 * old_eps[-3]) / 24
+
+ x_prev, pred_x0 = get_x_prev_and_pred_x0(e_t_prime, index)
+
+ return x_prev, pred_x0, e_t
diff --git a/latent-diffusion/ldm/modules/__pycache__/attention.cpython-39.pyc b/latent-diffusion/ldm/modules/__pycache__/attention.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..e37c6c47b464c5570b1cb3d7b2d97cef44fbda01
Binary files /dev/null and b/latent-diffusion/ldm/modules/__pycache__/attention.cpython-39.pyc differ
diff --git a/latent-diffusion/ldm/modules/__pycache__/ema.cpython-39.pyc b/latent-diffusion/ldm/modules/__pycache__/ema.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..da62e09028d8f324f8cf9d6f3f743403334d48b0
Binary files /dev/null and b/latent-diffusion/ldm/modules/__pycache__/ema.cpython-39.pyc differ
diff --git a/latent-diffusion/ldm/modules/__pycache__/x_transformer.cpython-39.pyc b/latent-diffusion/ldm/modules/__pycache__/x_transformer.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..b2132eed804d9513107333a17832504ea6266a31
Binary files /dev/null and b/latent-diffusion/ldm/modules/__pycache__/x_transformer.cpython-39.pyc differ
diff --git a/latent-diffusion/ldm/modules/attention.py b/latent-diffusion/ldm/modules/attention.py
new file mode 100644
index 0000000000000000000000000000000000000000..f4eff39ccb6d75daa764f6eb70a7cef024fb5a3f
--- /dev/null
+++ b/latent-diffusion/ldm/modules/attention.py
@@ -0,0 +1,261 @@
+from inspect import isfunction
+import math
+import torch
+import torch.nn.functional as F
+from torch import nn, einsum
+from einops import rearrange, repeat
+
+from ldm.modules.diffusionmodules.util import checkpoint
+
+
+def exists(val):
+ return val is not None
+
+
+def uniq(arr):
+ return{el: True for el in arr}.keys()
+
+
+def default(val, d):
+ if exists(val):
+ return val
+ return d() if isfunction(d) else d
+
+
+def max_neg_value(t):
+ return -torch.finfo(t.dtype).max
+
+
+def init_(tensor):
+ dim = tensor.shape[-1]
+ std = 1 / math.sqrt(dim)
+ tensor.uniform_(-std, std)
+ return tensor
+
+
+# feedforward
+class GEGLU(nn.Module):
+ def __init__(self, dim_in, dim_out):
+ super().__init__()
+ self.proj = nn.Linear(dim_in, dim_out * 2)
+
+ def forward(self, x):
+ x, gate = self.proj(x).chunk(2, dim=-1)
+ return x * F.gelu(gate)
+
+
+class FeedForward(nn.Module):
+ def __init__(self, dim, dim_out=None, mult=4, glu=False, dropout=0.):
+ super().__init__()
+ inner_dim = int(dim * mult)
+ dim_out = default(dim_out, dim)
+ project_in = nn.Sequential(
+ nn.Linear(dim, inner_dim),
+ nn.GELU()
+ ) if not glu else GEGLU(dim, inner_dim)
+
+ self.net = nn.Sequential(
+ project_in,
+ nn.Dropout(dropout),
+ nn.Linear(inner_dim, dim_out)
+ )
+
+ def forward(self, x):
+ return self.net(x)
+
+
+def zero_module(module):
+ """
+ Zero out the parameters of a module and return it.
+ """
+ for p in module.parameters():
+ p.detach().zero_()
+ return module
+
+
+def Normalize(in_channels):
+ return torch.nn.GroupNorm(num_groups=32, num_channels=in_channels, eps=1e-6, affine=True)
+
+
+class LinearAttention(nn.Module):
+ def __init__(self, dim, heads=4, dim_head=32):
+ super().__init__()
+ self.heads = heads
+ hidden_dim = dim_head * heads
+ self.to_qkv = nn.Conv2d(dim, hidden_dim * 3, 1, bias = False)
+ self.to_out = nn.Conv2d(hidden_dim, dim, 1)
+
+ def forward(self, x):
+ b, c, h, w = x.shape
+ qkv = self.to_qkv(x)
+ q, k, v = rearrange(qkv, 'b (qkv heads c) h w -> qkv b heads c (h w)', heads = self.heads, qkv=3)
+ k = k.softmax(dim=-1)
+ context = torch.einsum('bhdn,bhen->bhde', k, v)
+ out = torch.einsum('bhde,bhdn->bhen', context, q)
+ out = rearrange(out, 'b heads c (h w) -> b (heads c) h w', heads=self.heads, h=h, w=w)
+ return self.to_out(out)
+
+
+class SpatialSelfAttention(nn.Module):
+ def __init__(self, in_channels):
+ super().__init__()
+ self.in_channels = in_channels
+
+ self.norm = Normalize(in_channels)
+ self.q = torch.nn.Conv2d(in_channels,
+ in_channels,
+ kernel_size=1,
+ stride=1,
+ padding=0)
+ self.k = torch.nn.Conv2d(in_channels,
+ in_channels,
+ kernel_size=1,
+ stride=1,
+ padding=0)
+ self.v = torch.nn.Conv2d(in_channels,
+ in_channels,
+ kernel_size=1,
+ stride=1,
+ padding=0)
+ self.proj_out = torch.nn.Conv2d(in_channels,
+ in_channels,
+ kernel_size=1,
+ stride=1,
+ padding=0)
+
+ def forward(self, x):
+ h_ = x
+ h_ = self.norm(h_)
+ q = self.q(h_)
+ k = self.k(h_)
+ v = self.v(h_)
+
+ # compute attention
+ b,c,h,w = q.shape
+ q = rearrange(q, 'b c h w -> b (h w) c')
+ k = rearrange(k, 'b c h w -> b c (h w)')
+ w_ = torch.einsum('bij,bjk->bik', q, k)
+
+ w_ = w_ * (int(c)**(-0.5))
+ w_ = torch.nn.functional.softmax(w_, dim=2)
+
+ # attend to values
+ v = rearrange(v, 'b c h w -> b c (h w)')
+ w_ = rearrange(w_, 'b i j -> b j i')
+ h_ = torch.einsum('bij,bjk->bik', v, w_)
+ h_ = rearrange(h_, 'b c (h w) -> b c h w', h=h)
+ h_ = self.proj_out(h_)
+
+ return x+h_
+
+
+class CrossAttention(nn.Module):
+ def __init__(self, query_dim, context_dim=None, heads=8, dim_head=64, dropout=0.):
+ super().__init__()
+ inner_dim = dim_head * heads
+ context_dim = default(context_dim, query_dim)
+
+ self.scale = dim_head ** -0.5
+ self.heads = heads
+
+ self.to_q = nn.Linear(query_dim, inner_dim, bias=False)
+ self.to_k = nn.Linear(context_dim, inner_dim, bias=False)
+ self.to_v = nn.Linear(context_dim, inner_dim, bias=False)
+
+ self.to_out = nn.Sequential(
+ nn.Linear(inner_dim, query_dim),
+ nn.Dropout(dropout)
+ )
+
+ def forward(self, x, context=None, mask=None):
+ h = self.heads
+
+ q = self.to_q(x)
+ context = default(context, x)
+ k = self.to_k(context)
+ v = self.to_v(context)
+
+ q, k, v = map(lambda t: rearrange(t, 'b n (h d) -> (b h) n d', h=h), (q, k, v))
+
+ sim = einsum('b i d, b j d -> b i j', q, k) * self.scale
+
+ if exists(mask):
+ mask = rearrange(mask, 'b ... -> b (...)')
+ max_neg_value = -torch.finfo(sim.dtype).max
+ mask = repeat(mask, 'b j -> (b h) () j', h=h)
+ sim.masked_fill_(~mask, max_neg_value)
+
+ # attention, what we cannot get enough of
+ attn = sim.softmax(dim=-1)
+
+ out = einsum('b i j, b j d -> b i d', attn, v)
+ out = rearrange(out, '(b h) n d -> b n (h d)', h=h)
+ return self.to_out(out)
+
+
+class BasicTransformerBlock(nn.Module):
+ def __init__(self, dim, n_heads, d_head, dropout=0., context_dim=None, gated_ff=True, checkpoint=True):
+ super().__init__()
+ self.attn1 = CrossAttention(query_dim=dim, heads=n_heads, dim_head=d_head, dropout=dropout) # is a self-attention
+ self.ff = FeedForward(dim, dropout=dropout, glu=gated_ff)
+ self.attn2 = CrossAttention(query_dim=dim, context_dim=context_dim,
+ heads=n_heads, dim_head=d_head, dropout=dropout) # is self-attn if context is none
+ self.norm1 = nn.LayerNorm(dim)
+ self.norm2 = nn.LayerNorm(dim)
+ self.norm3 = nn.LayerNorm(dim)
+ self.checkpoint = checkpoint
+
+ def forward(self, x, context=None):
+ return checkpoint(self._forward, (x, context), self.parameters(), self.checkpoint)
+
+ def _forward(self, x, context=None):
+ x = self.attn1(self.norm1(x)) + x
+ x = self.attn2(self.norm2(x), context=context) + x
+ x = self.ff(self.norm3(x)) + x
+ return x
+
+
+class SpatialTransformer(nn.Module):
+ """
+ Transformer block for image-like data.
+ First, project the input (aka embedding)
+ and reshape to b, t, d.
+ Then apply standard transformer action.
+ Finally, reshape to image
+ """
+ def __init__(self, in_channels, n_heads, d_head,
+ depth=1, dropout=0., context_dim=None):
+ super().__init__()
+ self.in_channels = in_channels
+ inner_dim = n_heads * d_head
+ self.norm = Normalize(in_channels)
+
+ self.proj_in = nn.Conv2d(in_channels,
+ inner_dim,
+ kernel_size=1,
+ stride=1,
+ padding=0)
+
+ self.transformer_blocks = nn.ModuleList(
+ [BasicTransformerBlock(inner_dim, n_heads, d_head, dropout=dropout, context_dim=context_dim)
+ for d in range(depth)]
+ )
+
+ self.proj_out = zero_module(nn.Conv2d(inner_dim,
+ in_channels,
+ kernel_size=1,
+ stride=1,
+ padding=0))
+
+ def forward(self, x, context=None):
+ # note: if no context is given, cross-attention defaults to self-attention
+ b, c, h, w = x.shape
+ x_in = x
+ x = self.norm(x)
+ x = self.proj_in(x)
+ x = rearrange(x, 'b c h w -> b (h w) c')
+ for block in self.transformer_blocks:
+ x = block(x, context=context)
+ x = rearrange(x, 'b (h w) c -> b c h w', h=h, w=w)
+ x = self.proj_out(x)
+ return x + x_in
\ No newline at end of file
diff --git a/latent-diffusion/ldm/modules/diffusionmodules/__init__.py b/latent-diffusion/ldm/modules/diffusionmodules/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/latent-diffusion/ldm/modules/diffusionmodules/__pycache__/__init__.cpython-39.pyc b/latent-diffusion/ldm/modules/diffusionmodules/__pycache__/__init__.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..12e91ab4ad4d8f931c55e1c57b4fdccc327b5800
Binary files /dev/null and b/latent-diffusion/ldm/modules/diffusionmodules/__pycache__/__init__.cpython-39.pyc differ
diff --git a/latent-diffusion/ldm/modules/diffusionmodules/__pycache__/model.cpython-39.pyc b/latent-diffusion/ldm/modules/diffusionmodules/__pycache__/model.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..da45886790185d850f42777672fe1ca36ee23b94
Binary files /dev/null and b/latent-diffusion/ldm/modules/diffusionmodules/__pycache__/model.cpython-39.pyc differ
diff --git a/latent-diffusion/ldm/modules/diffusionmodules/__pycache__/openaimodel.cpython-39.pyc b/latent-diffusion/ldm/modules/diffusionmodules/__pycache__/openaimodel.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..146452407eedbc469c37e7ecbf64c1d0ee926797
Binary files /dev/null and b/latent-diffusion/ldm/modules/diffusionmodules/__pycache__/openaimodel.cpython-39.pyc differ
diff --git a/latent-diffusion/ldm/modules/diffusionmodules/__pycache__/util.cpython-39.pyc b/latent-diffusion/ldm/modules/diffusionmodules/__pycache__/util.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..f12311600e8b5b568121810a7e66152a9fa4ba49
Binary files /dev/null and b/latent-diffusion/ldm/modules/diffusionmodules/__pycache__/util.cpython-39.pyc differ
diff --git a/latent-diffusion/ldm/modules/diffusionmodules/model.py b/latent-diffusion/ldm/modules/diffusionmodules/model.py
new file mode 100644
index 0000000000000000000000000000000000000000..533e589a2024f1d7c52093d8c472c3b1b6617e26
--- /dev/null
+++ b/latent-diffusion/ldm/modules/diffusionmodules/model.py
@@ -0,0 +1,835 @@
+# pytorch_diffusion + derived encoder decoder
+import math
+import torch
+import torch.nn as nn
+import numpy as np
+from einops import rearrange
+
+from ldm.util import instantiate_from_config
+from ldm.modules.attention import LinearAttention
+
+
+def get_timestep_embedding(timesteps, embedding_dim):
+ """
+ This matches the implementation in Denoising Diffusion Probabilistic Models:
+ From Fairseq.
+ Build sinusoidal embeddings.
+ This matches the implementation in tensor2tensor, but differs slightly
+ from the description in Section 3.5 of "Attention Is All You Need".
+ """
+ assert len(timesteps.shape) == 1
+
+ half_dim = embedding_dim // 2
+ emb = math.log(10000) / (half_dim - 1)
+ emb = torch.exp(torch.arange(half_dim, dtype=torch.float32) * -emb)
+ emb = emb.to(device=timesteps.device)
+ emb = timesteps.float()[:, None] * emb[None, :]
+ emb = torch.cat([torch.sin(emb), torch.cos(emb)], dim=1)
+ if embedding_dim % 2 == 1: # zero pad
+ emb = torch.nn.functional.pad(emb, (0,1,0,0))
+ return emb
+
+
+def nonlinearity(x):
+ # swish
+ return x*torch.sigmoid(x)
+
+
+def Normalize(in_channels, num_groups=32):
+ return torch.nn.GroupNorm(num_groups=num_groups, num_channels=in_channels, eps=1e-6, affine=True)
+
+
+class Upsample(nn.Module):
+ def __init__(self, in_channels, with_conv):
+ super().__init__()
+ self.with_conv = with_conv
+ if self.with_conv:
+ self.conv = torch.nn.Conv2d(in_channels,
+ in_channels,
+ kernel_size=3,
+ stride=1,
+ padding=1)
+
+ def forward(self, x):
+ x = torch.nn.functional.interpolate(x, scale_factor=2.0, mode="nearest")
+ if self.with_conv:
+ x = self.conv(x)
+ return x
+
+
+class Downsample(nn.Module):
+ def __init__(self, in_channels, with_conv):
+ super().__init__()
+ self.with_conv = with_conv
+ if self.with_conv:
+ # no asymmetric padding in torch conv, must do it ourselves
+ self.conv = torch.nn.Conv2d(in_channels,
+ in_channels,
+ kernel_size=3,
+ stride=2,
+ padding=0)
+
+ def forward(self, x):
+ if self.with_conv:
+ pad = (0,1,0,1)
+ x = torch.nn.functional.pad(x, pad, mode="constant", value=0)
+ x = self.conv(x)
+ else:
+ x = torch.nn.functional.avg_pool2d(x, kernel_size=2, stride=2)
+ return x
+
+
+class ResnetBlock(nn.Module):
+ def __init__(self, *, in_channels, out_channels=None, conv_shortcut=False,
+ dropout, temb_channels=512):
+ super().__init__()
+ self.in_channels = in_channels
+ out_channels = in_channels if out_channels is None else out_channels
+ self.out_channels = out_channels
+ self.use_conv_shortcut = conv_shortcut
+
+ self.norm1 = Normalize(in_channels)
+ self.conv1 = torch.nn.Conv2d(in_channels,
+ out_channels,
+ kernel_size=3,
+ stride=1,
+ padding=1)
+ if temb_channels > 0:
+ self.temb_proj = torch.nn.Linear(temb_channels,
+ out_channels)
+ self.norm2 = Normalize(out_channels)
+ self.dropout = torch.nn.Dropout(dropout)
+ self.conv2 = torch.nn.Conv2d(out_channels,
+ out_channels,
+ kernel_size=3,
+ stride=1,
+ padding=1)
+ if self.in_channels != self.out_channels:
+ if self.use_conv_shortcut:
+ self.conv_shortcut = torch.nn.Conv2d(in_channels,
+ out_channels,
+ kernel_size=3,
+ stride=1,
+ padding=1)
+ else:
+ self.nin_shortcut = torch.nn.Conv2d(in_channels,
+ out_channels,
+ kernel_size=1,
+ stride=1,
+ padding=0)
+
+ def forward(self, x, temb):
+ h = x
+ h = self.norm1(h)
+ h = nonlinearity(h)
+ h = self.conv1(h)
+
+ if temb is not None:
+ h = h + self.temb_proj(nonlinearity(temb))[:,:,None,None]
+
+ h = self.norm2(h)
+ h = nonlinearity(h)
+ h = self.dropout(h)
+ h = self.conv2(h)
+
+ if self.in_channels != self.out_channels:
+ if self.use_conv_shortcut:
+ x = self.conv_shortcut(x)
+ else:
+ x = self.nin_shortcut(x)
+
+ return x+h
+
+
+class LinAttnBlock(LinearAttention):
+ """to match AttnBlock usage"""
+ def __init__(self, in_channels):
+ super().__init__(dim=in_channels, heads=1, dim_head=in_channels)
+
+
+class AttnBlock(nn.Module):
+ def __init__(self, in_channels):
+ super().__init__()
+ self.in_channels = in_channels
+
+ self.norm = Normalize(in_channels)
+ self.q = torch.nn.Conv2d(in_channels,
+ in_channels,
+ kernel_size=1,
+ stride=1,
+ padding=0)
+ self.k = torch.nn.Conv2d(in_channels,
+ in_channels,
+ kernel_size=1,
+ stride=1,
+ padding=0)
+ self.v = torch.nn.Conv2d(in_channels,
+ in_channels,
+ kernel_size=1,
+ stride=1,
+ padding=0)
+ self.proj_out = torch.nn.Conv2d(in_channels,
+ in_channels,
+ kernel_size=1,
+ stride=1,
+ padding=0)
+
+
+ def forward(self, x):
+ h_ = x
+ h_ = self.norm(h_)
+ q = self.q(h_)
+ k = self.k(h_)
+ v = self.v(h_)
+
+ # compute attention
+ b,c,h,w = q.shape
+ q = q.reshape(b,c,h*w)
+ q = q.permute(0,2,1) # b,hw,c
+ k = k.reshape(b,c,h*w) # b,c,hw
+ w_ = torch.bmm(q,k) # b,hw,hw w[b,i,j]=sum_c q[b,i,c]k[b,c,j]
+ w_ = w_ * (int(c)**(-0.5))
+ w_ = torch.nn.functional.softmax(w_, dim=2)
+
+ # attend to values
+ v = v.reshape(b,c,h*w)
+ w_ = w_.permute(0,2,1) # b,hw,hw (first hw of k, second of q)
+ h_ = torch.bmm(v,w_) # b, c,hw (hw of q) h_[b,c,j] = sum_i v[b,c,i] w_[b,i,j]
+ h_ = h_.reshape(b,c,h,w)
+
+ h_ = self.proj_out(h_)
+
+ return x+h_
+
+
+def make_attn(in_channels, attn_type="vanilla"):
+ assert attn_type in ["vanilla", "linear", "none"], f'attn_type {attn_type} unknown'
+ print(f"making attention of type '{attn_type}' with {in_channels} in_channels")
+ if attn_type == "vanilla":
+ return AttnBlock(in_channels)
+ elif attn_type == "none":
+ return nn.Identity(in_channels)
+ else:
+ return LinAttnBlock(in_channels)
+
+
+class Model(nn.Module):
+ def __init__(self, *, ch, out_ch, ch_mult=(1,2,4,8), num_res_blocks,
+ attn_resolutions, dropout=0.0, resamp_with_conv=True, in_channels,
+ resolution, use_timestep=True, use_linear_attn=False, attn_type="vanilla"):
+ super().__init__()
+ if use_linear_attn: attn_type = "linear"
+ self.ch = ch
+ self.temb_ch = self.ch*4
+ self.num_resolutions = len(ch_mult)
+ self.num_res_blocks = num_res_blocks
+ self.resolution = resolution
+ self.in_channels = in_channels
+
+ self.use_timestep = use_timestep
+ if self.use_timestep:
+ # timestep embedding
+ self.temb = nn.Module()
+ self.temb.dense = nn.ModuleList([
+ torch.nn.Linear(self.ch,
+ self.temb_ch),
+ torch.nn.Linear(self.temb_ch,
+ self.temb_ch),
+ ])
+
+ # downsampling
+ self.conv_in = torch.nn.Conv2d(in_channels,
+ self.ch,
+ kernel_size=3,
+ stride=1,
+ padding=1)
+
+ curr_res = resolution
+ in_ch_mult = (1,)+tuple(ch_mult)
+ self.down = nn.ModuleList()
+ for i_level in range(self.num_resolutions):
+ block = nn.ModuleList()
+ attn = nn.ModuleList()
+ block_in = ch*in_ch_mult[i_level]
+ block_out = ch*ch_mult[i_level]
+ for i_block in range(self.num_res_blocks):
+ block.append(ResnetBlock(in_channels=block_in,
+ out_channels=block_out,
+ temb_channels=self.temb_ch,
+ dropout=dropout))
+ block_in = block_out
+ if curr_res in attn_resolutions:
+ attn.append(make_attn(block_in, attn_type=attn_type))
+ down = nn.Module()
+ down.block = block
+ down.attn = attn
+ if i_level != self.num_resolutions-1:
+ down.downsample = Downsample(block_in, resamp_with_conv)
+ curr_res = curr_res // 2
+ self.down.append(down)
+
+ # middle
+ self.mid = nn.Module()
+ self.mid.block_1 = ResnetBlock(in_channels=block_in,
+ out_channels=block_in,
+ temb_channels=self.temb_ch,
+ dropout=dropout)
+ self.mid.attn_1 = make_attn(block_in, attn_type=attn_type)
+ self.mid.block_2 = ResnetBlock(in_channels=block_in,
+ out_channels=block_in,
+ temb_channels=self.temb_ch,
+ dropout=dropout)
+
+ # upsampling
+ self.up = nn.ModuleList()
+ for i_level in reversed(range(self.num_resolutions)):
+ block = nn.ModuleList()
+ attn = nn.ModuleList()
+ block_out = ch*ch_mult[i_level]
+ skip_in = ch*ch_mult[i_level]
+ for i_block in range(self.num_res_blocks+1):
+ if i_block == self.num_res_blocks:
+ skip_in = ch*in_ch_mult[i_level]
+ block.append(ResnetBlock(in_channels=block_in+skip_in,
+ out_channels=block_out,
+ temb_channels=self.temb_ch,
+ dropout=dropout))
+ block_in = block_out
+ if curr_res in attn_resolutions:
+ attn.append(make_attn(block_in, attn_type=attn_type))
+ up = nn.Module()
+ up.block = block
+ up.attn = attn
+ if i_level != 0:
+ up.upsample = Upsample(block_in, resamp_with_conv)
+ curr_res = curr_res * 2
+ self.up.insert(0, up) # prepend to get consistent order
+
+ # end
+ self.norm_out = Normalize(block_in)
+ self.conv_out = torch.nn.Conv2d(block_in,
+ out_ch,
+ kernel_size=3,
+ stride=1,
+ padding=1)
+
+ def forward(self, x, t=None, context=None):
+ #assert x.shape[2] == x.shape[3] == self.resolution
+ if context is not None:
+ # assume aligned context, cat along channel axis
+ x = torch.cat((x, context), dim=1)
+ if self.use_timestep:
+ # timestep embedding
+ assert t is not None
+ temb = get_timestep_embedding(t, self.ch)
+ temb = self.temb.dense[0](temb)
+ temb = nonlinearity(temb)
+ temb = self.temb.dense[1](temb)
+ else:
+ temb = None
+
+ # downsampling
+ hs = [self.conv_in(x)]
+ for i_level in range(self.num_resolutions):
+ for i_block in range(self.num_res_blocks):
+ h = self.down[i_level].block[i_block](hs[-1], temb)
+ if len(self.down[i_level].attn) > 0:
+ h = self.down[i_level].attn[i_block](h)
+ hs.append(h)
+ if i_level != self.num_resolutions-1:
+ hs.append(self.down[i_level].downsample(hs[-1]))
+
+ # middle
+ h = hs[-1]
+ h = self.mid.block_1(h, temb)
+ h = self.mid.attn_1(h)
+ h = self.mid.block_2(h, temb)
+
+ # upsampling
+ for i_level in reversed(range(self.num_resolutions)):
+ for i_block in range(self.num_res_blocks+1):
+ h = self.up[i_level].block[i_block](
+ torch.cat([h, hs.pop()], dim=1), temb)
+ if len(self.up[i_level].attn) > 0:
+ h = self.up[i_level].attn[i_block](h)
+ if i_level != 0:
+ h = self.up[i_level].upsample(h)
+
+ # end
+ h = self.norm_out(h)
+ h = nonlinearity(h)
+ h = self.conv_out(h)
+ return h
+
+ def get_last_layer(self):
+ return self.conv_out.weight
+
+
+class Encoder(nn.Module):
+ def __init__(self, *, ch, out_ch, ch_mult=(1,2,4,8), num_res_blocks,
+ attn_resolutions, dropout=0.0, resamp_with_conv=True, in_channels,
+ resolution, z_channels, double_z=True, use_linear_attn=False, attn_type="vanilla",
+ **ignore_kwargs):
+ super().__init__()
+ if use_linear_attn: attn_type = "linear"
+ self.ch = ch
+ self.temb_ch = 0
+ self.num_resolutions = len(ch_mult)
+ self.num_res_blocks = num_res_blocks
+ self.resolution = resolution
+ self.in_channels = in_channels
+
+ # downsampling
+ self.conv_in = torch.nn.Conv2d(in_channels,
+ self.ch,
+ kernel_size=3,
+ stride=1,
+ padding=1)
+
+ curr_res = resolution
+ in_ch_mult = (1,)+tuple(ch_mult)
+ self.in_ch_mult = in_ch_mult
+ self.down = nn.ModuleList()
+ for i_level in range(self.num_resolutions):
+ block = nn.ModuleList()
+ attn = nn.ModuleList()
+ block_in = ch*in_ch_mult[i_level]
+ block_out = ch*ch_mult[i_level]
+ for i_block in range(self.num_res_blocks):
+ block.append(ResnetBlock(in_channels=block_in,
+ out_channels=block_out,
+ temb_channels=self.temb_ch,
+ dropout=dropout))
+ block_in = block_out
+ if curr_res in attn_resolutions:
+ attn.append(make_attn(block_in, attn_type=attn_type))
+ down = nn.Module()
+ down.block = block
+ down.attn = attn
+ if i_level != self.num_resolutions-1:
+ down.downsample = Downsample(block_in, resamp_with_conv)
+ curr_res = curr_res // 2
+ self.down.append(down)
+
+ # middle
+ self.mid = nn.Module()
+ self.mid.block_1 = ResnetBlock(in_channels=block_in,
+ out_channels=block_in,
+ temb_channels=self.temb_ch,
+ dropout=dropout)
+ self.mid.attn_1 = make_attn(block_in, attn_type=attn_type)
+ self.mid.block_2 = ResnetBlock(in_channels=block_in,
+ out_channels=block_in,
+ temb_channels=self.temb_ch,
+ dropout=dropout)
+
+ # end
+ self.norm_out = Normalize(block_in)
+ self.conv_out = torch.nn.Conv2d(block_in,
+ 2*z_channels if double_z else z_channels,
+ kernel_size=3,
+ stride=1,
+ padding=1)
+
+ def forward(self, x):
+ # timestep embedding
+ temb = None
+
+ # downsampling
+ hs = [self.conv_in(x)]
+ for i_level in range(self.num_resolutions):
+ for i_block in range(self.num_res_blocks):
+ h = self.down[i_level].block[i_block](hs[-1], temb)
+ if len(self.down[i_level].attn) > 0:
+ h = self.down[i_level].attn[i_block](h)
+ hs.append(h)
+ if i_level != self.num_resolutions-1:
+ hs.append(self.down[i_level].downsample(hs[-1]))
+
+ # middle
+ h = hs[-1]
+ h = self.mid.block_1(h, temb)
+ h = self.mid.attn_1(h)
+ h = self.mid.block_2(h, temb)
+
+ # end
+ h = self.norm_out(h)
+ h = nonlinearity(h)
+ h = self.conv_out(h)
+ return h
+
+
+class Decoder(nn.Module):
+ def __init__(self, *, ch, out_ch, ch_mult=(1,2,4,8), num_res_blocks,
+ attn_resolutions, dropout=0.0, resamp_with_conv=True, in_channels,
+ resolution, z_channels, give_pre_end=False, tanh_out=False, use_linear_attn=False,
+ attn_type="vanilla", **ignorekwargs):
+ super().__init__()
+ if use_linear_attn: attn_type = "linear"
+ self.ch = ch
+ self.temb_ch = 0
+ self.num_resolutions = len(ch_mult)
+ self.num_res_blocks = num_res_blocks
+ self.resolution = resolution
+ self.in_channels = in_channels
+ self.give_pre_end = give_pre_end
+ self.tanh_out = tanh_out
+
+ # compute in_ch_mult, block_in and curr_res at lowest res
+ in_ch_mult = (1,)+tuple(ch_mult)
+ block_in = ch*ch_mult[self.num_resolutions-1]
+ curr_res = resolution // 2**(self.num_resolutions-1)
+ self.z_shape = (1,z_channels,curr_res,curr_res)
+ print("Working with z of shape {} = {} dimensions.".format(
+ self.z_shape, np.prod(self.z_shape)))
+
+ # z to block_in
+ self.conv_in = torch.nn.Conv2d(z_channels,
+ block_in,
+ kernel_size=3,
+ stride=1,
+ padding=1)
+
+ # middle
+ self.mid = nn.Module()
+ self.mid.block_1 = ResnetBlock(in_channels=block_in,
+ out_channels=block_in,
+ temb_channels=self.temb_ch,
+ dropout=dropout)
+ self.mid.attn_1 = make_attn(block_in, attn_type=attn_type)
+ self.mid.block_2 = ResnetBlock(in_channels=block_in,
+ out_channels=block_in,
+ temb_channels=self.temb_ch,
+ dropout=dropout)
+
+ # upsampling
+ self.up = nn.ModuleList()
+ for i_level in reversed(range(self.num_resolutions)):
+ block = nn.ModuleList()
+ attn = nn.ModuleList()
+ block_out = ch*ch_mult[i_level]
+ for i_block in range(self.num_res_blocks+1):
+ block.append(ResnetBlock(in_channels=block_in,
+ out_channels=block_out,
+ temb_channels=self.temb_ch,
+ dropout=dropout))
+ block_in = block_out
+ if curr_res in attn_resolutions:
+ attn.append(make_attn(block_in, attn_type=attn_type))
+ up = nn.Module()
+ up.block = block
+ up.attn = attn
+ if i_level != 0:
+ up.upsample = Upsample(block_in, resamp_with_conv)
+ curr_res = curr_res * 2
+ self.up.insert(0, up) # prepend to get consistent order
+
+ # end
+ self.norm_out = Normalize(block_in)
+ self.conv_out = torch.nn.Conv2d(block_in,
+ out_ch,
+ kernel_size=3,
+ stride=1,
+ padding=1)
+
+ def forward(self, z):
+ #assert z.shape[1:] == self.z_shape[1:]
+ self.last_z_shape = z.shape
+
+ # timestep embedding
+ temb = None
+
+ # z to block_in
+ h = self.conv_in(z)
+
+ # middle
+ h = self.mid.block_1(h, temb)
+ h = self.mid.attn_1(h)
+ h = self.mid.block_2(h, temb)
+
+ # upsampling
+ for i_level in reversed(range(self.num_resolutions)):
+ for i_block in range(self.num_res_blocks+1):
+ h = self.up[i_level].block[i_block](h, temb)
+ if len(self.up[i_level].attn) > 0:
+ h = self.up[i_level].attn[i_block](h)
+ if i_level != 0:
+ h = self.up[i_level].upsample(h)
+
+ # end
+ if self.give_pre_end:
+ return h
+
+ h = self.norm_out(h)
+ h = nonlinearity(h)
+ h = self.conv_out(h)
+ if self.tanh_out:
+ h = torch.tanh(h)
+ return h
+
+
+class SimpleDecoder(nn.Module):
+ def __init__(self, in_channels, out_channels, *args, **kwargs):
+ super().__init__()
+ self.model = nn.ModuleList([nn.Conv2d(in_channels, in_channels, 1),
+ ResnetBlock(in_channels=in_channels,
+ out_channels=2 * in_channels,
+ temb_channels=0, dropout=0.0),
+ ResnetBlock(in_channels=2 * in_channels,
+ out_channels=4 * in_channels,
+ temb_channels=0, dropout=0.0),
+ ResnetBlock(in_channels=4 * in_channels,
+ out_channels=2 * in_channels,
+ temb_channels=0, dropout=0.0),
+ nn.Conv2d(2*in_channels, in_channels, 1),
+ Upsample(in_channels, with_conv=True)])
+ # end
+ self.norm_out = Normalize(in_channels)
+ self.conv_out = torch.nn.Conv2d(in_channels,
+ out_channels,
+ kernel_size=3,
+ stride=1,
+ padding=1)
+
+ def forward(self, x):
+ for i, layer in enumerate(self.model):
+ if i in [1,2,3]:
+ x = layer(x, None)
+ else:
+ x = layer(x)
+
+ h = self.norm_out(x)
+ h = nonlinearity(h)
+ x = self.conv_out(h)
+ return x
+
+
+class UpsampleDecoder(nn.Module):
+ def __init__(self, in_channels, out_channels, ch, num_res_blocks, resolution,
+ ch_mult=(2,2), dropout=0.0):
+ super().__init__()
+ # upsampling
+ self.temb_ch = 0
+ self.num_resolutions = len(ch_mult)
+ self.num_res_blocks = num_res_blocks
+ block_in = in_channels
+ curr_res = resolution // 2 ** (self.num_resolutions - 1)
+ self.res_blocks = nn.ModuleList()
+ self.upsample_blocks = nn.ModuleList()
+ for i_level in range(self.num_resolutions):
+ res_block = []
+ block_out = ch * ch_mult[i_level]
+ for i_block in range(self.num_res_blocks + 1):
+ res_block.append(ResnetBlock(in_channels=block_in,
+ out_channels=block_out,
+ temb_channels=self.temb_ch,
+ dropout=dropout))
+ block_in = block_out
+ self.res_blocks.append(nn.ModuleList(res_block))
+ if i_level != self.num_resolutions - 1:
+ self.upsample_blocks.append(Upsample(block_in, True))
+ curr_res = curr_res * 2
+
+ # end
+ self.norm_out = Normalize(block_in)
+ self.conv_out = torch.nn.Conv2d(block_in,
+ out_channels,
+ kernel_size=3,
+ stride=1,
+ padding=1)
+
+ def forward(self, x):
+ # upsampling
+ h = x
+ for k, i_level in enumerate(range(self.num_resolutions)):
+ for i_block in range(self.num_res_blocks + 1):
+ h = self.res_blocks[i_level][i_block](h, None)
+ if i_level != self.num_resolutions - 1:
+ h = self.upsample_blocks[k](h)
+ h = self.norm_out(h)
+ h = nonlinearity(h)
+ h = self.conv_out(h)
+ return h
+
+
+class LatentRescaler(nn.Module):
+ def __init__(self, factor, in_channels, mid_channels, out_channels, depth=2):
+ super().__init__()
+ # residual block, interpolate, residual block
+ self.factor = factor
+ self.conv_in = nn.Conv2d(in_channels,
+ mid_channels,
+ kernel_size=3,
+ stride=1,
+ padding=1)
+ self.res_block1 = nn.ModuleList([ResnetBlock(in_channels=mid_channels,
+ out_channels=mid_channels,
+ temb_channels=0,
+ dropout=0.0) for _ in range(depth)])
+ self.attn = AttnBlock(mid_channels)
+ self.res_block2 = nn.ModuleList([ResnetBlock(in_channels=mid_channels,
+ out_channels=mid_channels,
+ temb_channels=0,
+ dropout=0.0) for _ in range(depth)])
+
+ self.conv_out = nn.Conv2d(mid_channels,
+ out_channels,
+ kernel_size=1,
+ )
+
+ def forward(self, x):
+ x = self.conv_in(x)
+ for block in self.res_block1:
+ x = block(x, None)
+ x = torch.nn.functional.interpolate(x, size=(int(round(x.shape[2]*self.factor)), int(round(x.shape[3]*self.factor))))
+ x = self.attn(x)
+ for block in self.res_block2:
+ x = block(x, None)
+ x = self.conv_out(x)
+ return x
+
+
+class MergedRescaleEncoder(nn.Module):
+ def __init__(self, in_channels, ch, resolution, out_ch, num_res_blocks,
+ attn_resolutions, dropout=0.0, resamp_with_conv=True,
+ ch_mult=(1,2,4,8), rescale_factor=1.0, rescale_module_depth=1):
+ super().__init__()
+ intermediate_chn = ch * ch_mult[-1]
+ self.encoder = Encoder(in_channels=in_channels, num_res_blocks=num_res_blocks, ch=ch, ch_mult=ch_mult,
+ z_channels=intermediate_chn, double_z=False, resolution=resolution,
+ attn_resolutions=attn_resolutions, dropout=dropout, resamp_with_conv=resamp_with_conv,
+ out_ch=None)
+ self.rescaler = LatentRescaler(factor=rescale_factor, in_channels=intermediate_chn,
+ mid_channels=intermediate_chn, out_channels=out_ch, depth=rescale_module_depth)
+
+ def forward(self, x):
+ x = self.encoder(x)
+ x = self.rescaler(x)
+ return x
+
+
+class MergedRescaleDecoder(nn.Module):
+ def __init__(self, z_channels, out_ch, resolution, num_res_blocks, attn_resolutions, ch, ch_mult=(1,2,4,8),
+ dropout=0.0, resamp_with_conv=True, rescale_factor=1.0, rescale_module_depth=1):
+ super().__init__()
+ tmp_chn = z_channels*ch_mult[-1]
+ self.decoder = Decoder(out_ch=out_ch, z_channels=tmp_chn, attn_resolutions=attn_resolutions, dropout=dropout,
+ resamp_with_conv=resamp_with_conv, in_channels=None, num_res_blocks=num_res_blocks,
+ ch_mult=ch_mult, resolution=resolution, ch=ch)
+ self.rescaler = LatentRescaler(factor=rescale_factor, in_channels=z_channels, mid_channels=tmp_chn,
+ out_channels=tmp_chn, depth=rescale_module_depth)
+
+ def forward(self, x):
+ x = self.rescaler(x)
+ x = self.decoder(x)
+ return x
+
+
+class Upsampler(nn.Module):
+ def __init__(self, in_size, out_size, in_channels, out_channels, ch_mult=2):
+ super().__init__()
+ assert out_size >= in_size
+ num_blocks = int(np.log2(out_size//in_size))+1
+ factor_up = 1.+ (out_size % in_size)
+ print(f"Building {self.__class__.__name__} with in_size: {in_size} --> out_size {out_size} and factor {factor_up}")
+ self.rescaler = LatentRescaler(factor=factor_up, in_channels=in_channels, mid_channels=2*in_channels,
+ out_channels=in_channels)
+ self.decoder = Decoder(out_ch=out_channels, resolution=out_size, z_channels=in_channels, num_res_blocks=2,
+ attn_resolutions=[], in_channels=None, ch=in_channels,
+ ch_mult=[ch_mult for _ in range(num_blocks)])
+
+ def forward(self, x):
+ x = self.rescaler(x)
+ x = self.decoder(x)
+ return x
+
+
+class Resize(nn.Module):
+ def __init__(self, in_channels=None, learned=False, mode="bilinear"):
+ super().__init__()
+ self.with_conv = learned
+ self.mode = mode
+ if self.with_conv:
+ print(f"Note: {self.__class__.__name} uses learned downsampling and will ignore the fixed {mode} mode")
+ raise NotImplementedError()
+ assert in_channels is not None
+ # no asymmetric padding in torch conv, must do it ourselves
+ self.conv = torch.nn.Conv2d(in_channels,
+ in_channels,
+ kernel_size=4,
+ stride=2,
+ padding=1)
+
+ def forward(self, x, scale_factor=1.0):
+ if scale_factor==1.0:
+ return x
+ else:
+ x = torch.nn.functional.interpolate(x, mode=self.mode, align_corners=False, scale_factor=scale_factor)
+ return x
+
+class FirstStagePostProcessor(nn.Module):
+
+ def __init__(self, ch_mult:list, in_channels,
+ pretrained_model:nn.Module=None,
+ reshape=False,
+ n_channels=None,
+ dropout=0.,
+ pretrained_config=None):
+ super().__init__()
+ if pretrained_config is None:
+ assert pretrained_model is not None, 'Either "pretrained_model" or "pretrained_config" must not be None'
+ self.pretrained_model = pretrained_model
+ else:
+ assert pretrained_config is not None, 'Either "pretrained_model" or "pretrained_config" must not be None'
+ self.instantiate_pretrained(pretrained_config)
+
+ self.do_reshape = reshape
+
+ if n_channels is None:
+ n_channels = self.pretrained_model.encoder.ch
+
+ self.proj_norm = Normalize(in_channels,num_groups=in_channels//2)
+ self.proj = nn.Conv2d(in_channels,n_channels,kernel_size=3,
+ stride=1,padding=1)
+
+ blocks = []
+ downs = []
+ ch_in = n_channels
+ for m in ch_mult:
+ blocks.append(ResnetBlock(in_channels=ch_in,out_channels=m*n_channels,dropout=dropout))
+ ch_in = m * n_channels
+ downs.append(Downsample(ch_in, with_conv=False))
+
+ self.model = nn.ModuleList(blocks)
+ self.downsampler = nn.ModuleList(downs)
+
+
+ def instantiate_pretrained(self, config):
+ model = instantiate_from_config(config)
+ self.pretrained_model = model.eval()
+ # self.pretrained_model.train = False
+ for param in self.pretrained_model.parameters():
+ param.requires_grad = False
+
+
+ @torch.no_grad()
+ def encode_with_pretrained(self,x):
+ c = self.pretrained_model.encode(x)
+ if isinstance(c, DiagonalGaussianDistribution):
+ c = c.mode()
+ return c
+
+ def forward(self,x):
+ z_fs = self.encode_with_pretrained(x)
+ z = self.proj_norm(z_fs)
+ z = self.proj(z)
+ z = nonlinearity(z)
+
+ for submodel, downmodel in zip(self.model,self.downsampler):
+ z = submodel(z,temb=None)
+ z = downmodel(z)
+
+ if self.do_reshape:
+ z = rearrange(z,'b c h w -> b (h w) c')
+ return z
+
diff --git a/latent-diffusion/ldm/modules/diffusionmodules/openaimodel.py b/latent-diffusion/ldm/modules/diffusionmodules/openaimodel.py
new file mode 100644
index 0000000000000000000000000000000000000000..34ed43a85c55f74c667df97a2f7272f621499ed2
--- /dev/null
+++ b/latent-diffusion/ldm/modules/diffusionmodules/openaimodel.py
@@ -0,0 +1,961 @@
+from abc import abstractmethod
+from functools import partial
+import math
+from typing import Iterable
+
+import numpy as np
+import torch as th
+import torch.nn as nn
+import torch.nn.functional as F
+
+from ldm.modules.diffusionmodules.util import (
+ checkpoint,
+ conv_nd,
+ linear,
+ avg_pool_nd,
+ zero_module,
+ normalization,
+ timestep_embedding,
+)
+from ldm.modules.attention import SpatialTransformer
+
+
+# dummy replace
+def convert_module_to_f16(x):
+ pass
+
+def convert_module_to_f32(x):
+ pass
+
+
+## go
+class AttentionPool2d(nn.Module):
+ """
+ Adapted from CLIP: https://github.com/openai/CLIP/blob/main/clip/model.py
+ """
+
+ def __init__(
+ self,
+ spacial_dim: int,
+ embed_dim: int,
+ num_heads_channels: int,
+ output_dim: int = None,
+ ):
+ super().__init__()
+ self.positional_embedding = nn.Parameter(th.randn(embed_dim, spacial_dim ** 2 + 1) / embed_dim ** 0.5)
+ self.qkv_proj = conv_nd(1, embed_dim, 3 * embed_dim, 1)
+ self.c_proj = conv_nd(1, embed_dim, output_dim or embed_dim, 1)
+ self.num_heads = embed_dim // num_heads_channels
+ self.attention = QKVAttention(self.num_heads)
+
+ def forward(self, x):
+ b, c, *_spatial = x.shape
+ x = x.reshape(b, c, -1) # NC(HW)
+ x = th.cat([x.mean(dim=-1, keepdim=True), x], dim=-1) # NC(HW+1)
+ x = x + self.positional_embedding[None, :, :].to(x.dtype) # NC(HW+1)
+ x = self.qkv_proj(x)
+ x = self.attention(x)
+ x = self.c_proj(x)
+ return x[:, :, 0]
+
+
+class TimestepBlock(nn.Module):
+ """
+ Any module where forward() takes timestep embeddings as a second argument.
+ """
+
+ @abstractmethod
+ def forward(self, x, emb):
+ """
+ Apply the module to `x` given `emb` timestep embeddings.
+ """
+
+
+class TimestepEmbedSequential(nn.Sequential, TimestepBlock):
+ """
+ A sequential module that passes timestep embeddings to the children that
+ support it as an extra input.
+ """
+
+ def forward(self, x, emb, context=None):
+ for layer in self:
+ if isinstance(layer, TimestepBlock):
+ x = layer(x, emb)
+ elif isinstance(layer, SpatialTransformer):
+ x = layer(x, context)
+ else:
+ x = layer(x)
+ return x
+
+
+class Upsample(nn.Module):
+ """
+ An upsampling layer with an optional convolution.
+ :param channels: channels in the inputs and outputs.
+ :param use_conv: a bool determining if a convolution is applied.
+ :param dims: determines if the signal is 1D, 2D, or 3D. If 3D, then
+ upsampling occurs in the inner-two dimensions.
+ """
+
+ def __init__(self, channels, use_conv, dims=2, out_channels=None, padding=1):
+ super().__init__()
+ self.channels = channels
+ self.out_channels = out_channels or channels
+ self.use_conv = use_conv
+ self.dims = dims
+ if use_conv:
+ self.conv = conv_nd(dims, self.channels, self.out_channels, 3, padding=padding)
+
+ def forward(self, x):
+ assert x.shape[1] == self.channels
+ if self.dims == 3:
+ x = F.interpolate(
+ x, (x.shape[2], x.shape[3] * 2, x.shape[4] * 2), mode="nearest"
+ )
+ else:
+ x = F.interpolate(x, scale_factor=2, mode="nearest")
+ if self.use_conv:
+ x = self.conv(x)
+ return x
+
+class TransposedUpsample(nn.Module):
+ 'Learned 2x upsampling without padding'
+ def __init__(self, channels, out_channels=None, ks=5):
+ super().__init__()
+ self.channels = channels
+ self.out_channels = out_channels or channels
+
+ self.up = nn.ConvTranspose2d(self.channels,self.out_channels,kernel_size=ks,stride=2)
+
+ def forward(self,x):
+ return self.up(x)
+
+
+class Downsample(nn.Module):
+ """
+ A downsampling layer with an optional convolution.
+ :param channels: channels in the inputs and outputs.
+ :param use_conv: a bool determining if a convolution is applied.
+ :param dims: determines if the signal is 1D, 2D, or 3D. If 3D, then
+ downsampling occurs in the inner-two dimensions.
+ """
+
+ def __init__(self, channels, use_conv, dims=2, out_channels=None,padding=1):
+ super().__init__()
+ self.channels = channels
+ self.out_channels = out_channels or channels
+ self.use_conv = use_conv
+ self.dims = dims
+ stride = 2 if dims != 3 else (1, 2, 2)
+ if use_conv:
+ self.op = conv_nd(
+ dims, self.channels, self.out_channels, 3, stride=stride, padding=padding
+ )
+ else:
+ assert self.channels == self.out_channels
+ self.op = avg_pool_nd(dims, kernel_size=stride, stride=stride)
+
+ def forward(self, x):
+ assert x.shape[1] == self.channels
+ return self.op(x)
+
+
+class ResBlock(TimestepBlock):
+ """
+ A residual block that can optionally change the number of channels.
+ :param channels: the number of input channels.
+ :param emb_channels: the number of timestep embedding channels.
+ :param dropout: the rate of dropout.
+ :param out_channels: if specified, the number of out channels.
+ :param use_conv: if True and out_channels is specified, use a spatial
+ convolution instead of a smaller 1x1 convolution to change the
+ channels in the skip connection.
+ :param dims: determines if the signal is 1D, 2D, or 3D.
+ :param use_checkpoint: if True, use gradient checkpointing on this module.
+ :param up: if True, use this block for upsampling.
+ :param down: if True, use this block for downsampling.
+ """
+
+ def __init__(
+ self,
+ channels,
+ emb_channels,
+ dropout,
+ out_channels=None,
+ use_conv=False,
+ use_scale_shift_norm=False,
+ dims=2,
+ use_checkpoint=False,
+ up=False,
+ down=False,
+ ):
+ super().__init__()
+ self.channels = channels
+ self.emb_channels = emb_channels
+ self.dropout = dropout
+ self.out_channels = out_channels or channels
+ self.use_conv = use_conv
+ self.use_checkpoint = use_checkpoint
+ self.use_scale_shift_norm = use_scale_shift_norm
+
+ self.in_layers = nn.Sequential(
+ normalization(channels),
+ nn.SiLU(),
+ conv_nd(dims, channels, self.out_channels, 3, padding=1),
+ )
+
+ self.updown = up or down
+
+ if up:
+ self.h_upd = Upsample(channels, False, dims)
+ self.x_upd = Upsample(channels, False, dims)
+ elif down:
+ self.h_upd = Downsample(channels, False, dims)
+ self.x_upd = Downsample(channels, False, dims)
+ else:
+ self.h_upd = self.x_upd = nn.Identity()
+
+ self.emb_layers = nn.Sequential(
+ nn.SiLU(),
+ linear(
+ emb_channels,
+ 2 * self.out_channels if use_scale_shift_norm else self.out_channels,
+ ),
+ )
+ self.out_layers = nn.Sequential(
+ normalization(self.out_channels),
+ nn.SiLU(),
+ nn.Dropout(p=dropout),
+ zero_module(
+ conv_nd(dims, self.out_channels, self.out_channels, 3, padding=1)
+ ),
+ )
+
+ if self.out_channels == channels:
+ self.skip_connection = nn.Identity()
+ elif use_conv:
+ self.skip_connection = conv_nd(
+ dims, channels, self.out_channels, 3, padding=1
+ )
+ else:
+ self.skip_connection = conv_nd(dims, channels, self.out_channels, 1)
+
+ def forward(self, x, emb):
+ """
+ Apply the block to a Tensor, conditioned on a timestep embedding.
+ :param x: an [N x C x ...] Tensor of features.
+ :param emb: an [N x emb_channels] Tensor of timestep embeddings.
+ :return: an [N x C x ...] Tensor of outputs.
+ """
+ return checkpoint(
+ self._forward, (x, emb), self.parameters(), self.use_checkpoint
+ )
+
+
+ def _forward(self, x, emb):
+ if self.updown:
+ in_rest, in_conv = self.in_layers[:-1], self.in_layers[-1]
+ h = in_rest(x)
+ h = self.h_upd(h)
+ x = self.x_upd(x)
+ h = in_conv(h)
+ else:
+ h = self.in_layers(x)
+ emb_out = self.emb_layers(emb).type(h.dtype)
+ while len(emb_out.shape) < len(h.shape):
+ emb_out = emb_out[..., None]
+ if self.use_scale_shift_norm:
+ out_norm, out_rest = self.out_layers[0], self.out_layers[1:]
+ scale, shift = th.chunk(emb_out, 2, dim=1)
+ h = out_norm(h) * (1 + scale) + shift
+ h = out_rest(h)
+ else:
+ h = h + emb_out
+ h = self.out_layers(h)
+ return self.skip_connection(x) + h
+
+
+class AttentionBlock(nn.Module):
+ """
+ An attention block that allows spatial positions to attend to each other.
+ Originally ported from here, but adapted to the N-d case.
+ https://github.com/hojonathanho/diffusion/blob/1e0dceb3b3495bbe19116a5e1b3596cd0706c543/diffusion_tf/models/unet.py#L66.
+ """
+
+ def __init__(
+ self,
+ channels,
+ num_heads=1,
+ num_head_channels=-1,
+ use_checkpoint=False,
+ use_new_attention_order=False,
+ ):
+ super().__init__()
+ self.channels = channels
+ if num_head_channels == -1:
+ self.num_heads = num_heads
+ else:
+ assert (
+ channels % num_head_channels == 0
+ ), f"q,k,v channels {channels} is not divisible by num_head_channels {num_head_channels}"
+ self.num_heads = channels // num_head_channels
+ self.use_checkpoint = use_checkpoint
+ self.norm = normalization(channels)
+ self.qkv = conv_nd(1, channels, channels * 3, 1)
+ if use_new_attention_order:
+ # split qkv before split heads
+ self.attention = QKVAttention(self.num_heads)
+ else:
+ # split heads before split qkv
+ self.attention = QKVAttentionLegacy(self.num_heads)
+
+ self.proj_out = zero_module(conv_nd(1, channels, channels, 1))
+
+ def forward(self, x):
+ return checkpoint(self._forward, (x,), self.parameters(), True) # TODO: check checkpoint usage, is True # TODO: fix the .half call!!!
+ #return pt_checkpoint(self._forward, x) # pytorch
+
+ def _forward(self, x):
+ b, c, *spatial = x.shape
+ x = x.reshape(b, c, -1)
+ qkv = self.qkv(self.norm(x))
+ h = self.attention(qkv)
+ h = self.proj_out(h)
+ return (x + h).reshape(b, c, *spatial)
+
+
+def count_flops_attn(model, _x, y):
+ """
+ A counter for the `thop` package to count the operations in an
+ attention operation.
+ Meant to be used like:
+ macs, params = thop.profile(
+ model,
+ inputs=(inputs, timestamps),
+ custom_ops={QKVAttention: QKVAttention.count_flops},
+ )
+ """
+ b, c, *spatial = y[0].shape
+ num_spatial = int(np.prod(spatial))
+ # We perform two matmuls with the same number of ops.
+ # The first computes the weight matrix, the second computes
+ # the combination of the value vectors.
+ matmul_ops = 2 * b * (num_spatial ** 2) * c
+ model.total_ops += th.DoubleTensor([matmul_ops])
+
+
+class QKVAttentionLegacy(nn.Module):
+ """
+ A module which performs QKV attention. Matches legacy QKVAttention + input/ouput heads shaping
+ """
+
+ def __init__(self, n_heads):
+ super().__init__()
+ self.n_heads = n_heads
+
+ def forward(self, qkv):
+ """
+ Apply QKV attention.
+ :param qkv: an [N x (H * 3 * C) x T] tensor of Qs, Ks, and Vs.
+ :return: an [N x (H * C) x T] tensor after attention.
+ """
+ bs, width, length = qkv.shape
+ assert width % (3 * self.n_heads) == 0
+ ch = width // (3 * self.n_heads)
+ q, k, v = qkv.reshape(bs * self.n_heads, ch * 3, length).split(ch, dim=1)
+ scale = 1 / math.sqrt(math.sqrt(ch))
+ weight = th.einsum(
+ "bct,bcs->bts", q * scale, k * scale
+ ) # More stable with f16 than dividing afterwards
+ weight = th.softmax(weight.float(), dim=-1).type(weight.dtype)
+ a = th.einsum("bts,bcs->bct", weight, v)
+ return a.reshape(bs, -1, length)
+
+ @staticmethod
+ def count_flops(model, _x, y):
+ return count_flops_attn(model, _x, y)
+
+
+class QKVAttention(nn.Module):
+ """
+ A module which performs QKV attention and splits in a different order.
+ """
+
+ def __init__(self, n_heads):
+ super().__init__()
+ self.n_heads = n_heads
+
+ def forward(self, qkv):
+ """
+ Apply QKV attention.
+ :param qkv: an [N x (3 * H * C) x T] tensor of Qs, Ks, and Vs.
+ :return: an [N x (H * C) x T] tensor after attention.
+ """
+ bs, width, length = qkv.shape
+ assert width % (3 * self.n_heads) == 0
+ ch = width // (3 * self.n_heads)
+ q, k, v = qkv.chunk(3, dim=1)
+ scale = 1 / math.sqrt(math.sqrt(ch))
+ weight = th.einsum(
+ "bct,bcs->bts",
+ (q * scale).view(bs * self.n_heads, ch, length),
+ (k * scale).view(bs * self.n_heads, ch, length),
+ ) # More stable with f16 than dividing afterwards
+ weight = th.softmax(weight.float(), dim=-1).type(weight.dtype)
+ a = th.einsum("bts,bcs->bct", weight, v.reshape(bs * self.n_heads, ch, length))
+ return a.reshape(bs, -1, length)
+
+ @staticmethod
+ def count_flops(model, _x, y):
+ return count_flops_attn(model, _x, y)
+
+
+class UNetModel(nn.Module):
+ """
+ The full UNet model with attention and timestep embedding.
+ :param in_channels: channels in the input Tensor.
+ :param model_channels: base channel count for the model.
+ :param out_channels: channels in the output Tensor.
+ :param num_res_blocks: number of residual blocks per downsample.
+ :param attention_resolutions: a collection of downsample rates at which
+ attention will take place. May be a set, list, or tuple.
+ For example, if this contains 4, then at 4x downsampling, attention
+ will be used.
+ :param dropout: the dropout probability.
+ :param channel_mult: channel multiplier for each level of the UNet.
+ :param conv_resample: if True, use learned convolutions for upsampling and
+ downsampling.
+ :param dims: determines if the signal is 1D, 2D, or 3D.
+ :param num_classes: if specified (as an int), then this model will be
+ class-conditional with `num_classes` classes.
+ :param use_checkpoint: use gradient checkpointing to reduce memory usage.
+ :param num_heads: the number of attention heads in each attention layer.
+ :param num_heads_channels: if specified, ignore num_heads and instead use
+ a fixed channel width per attention head.
+ :param num_heads_upsample: works with num_heads to set a different number
+ of heads for upsampling. Deprecated.
+ :param use_scale_shift_norm: use a FiLM-like conditioning mechanism.
+ :param resblock_updown: use residual blocks for up/downsampling.
+ :param use_new_attention_order: use a different attention pattern for potentially
+ increased efficiency.
+ """
+
+ def __init__(
+ self,
+ image_size,
+ in_channels,
+ model_channels,
+ out_channels,
+ num_res_blocks,
+ attention_resolutions,
+ dropout=0,
+ channel_mult=(1, 2, 4, 8),
+ conv_resample=True,
+ dims=2,
+ num_classes=None,
+ use_checkpoint=False,
+ use_fp16=False,
+ num_heads=-1,
+ num_head_channels=-1,
+ num_heads_upsample=-1,
+ use_scale_shift_norm=False,
+ resblock_updown=False,
+ use_new_attention_order=False,
+ use_spatial_transformer=False, # custom transformer support
+ transformer_depth=1, # custom transformer support
+ context_dim=None, # custom transformer support
+ n_embed=None, # custom support for prediction of discrete ids into codebook of first stage vq model
+ legacy=True,
+ ):
+ super().__init__()
+ if use_spatial_transformer:
+ assert context_dim is not None, 'Fool!! You forgot to include the dimension of your cross-attention conditioning...'
+
+ if context_dim is not None:
+ assert use_spatial_transformer, 'Fool!! You forgot to use the spatial transformer for your cross-attention conditioning...'
+ from omegaconf.listconfig import ListConfig
+ if type(context_dim) == ListConfig:
+ context_dim = list(context_dim)
+
+ if num_heads_upsample == -1:
+ num_heads_upsample = num_heads
+
+ if num_heads == -1:
+ assert num_head_channels != -1, 'Either num_heads or num_head_channels has to be set'
+
+ if num_head_channels == -1:
+ assert num_heads != -1, 'Either num_heads or num_head_channels has to be set'
+
+ self.image_size = image_size
+ self.in_channels = in_channels
+ self.model_channels = model_channels
+ self.out_channels = out_channels
+ self.num_res_blocks = num_res_blocks
+ self.attention_resolutions = attention_resolutions
+ self.dropout = dropout
+ self.channel_mult = channel_mult
+ self.conv_resample = conv_resample
+ self.num_classes = num_classes
+ self.use_checkpoint = use_checkpoint
+ self.dtype = th.float16 if use_fp16 else th.float32
+ self.num_heads = num_heads
+ self.num_head_channels = num_head_channels
+ self.num_heads_upsample = num_heads_upsample
+ self.predict_codebook_ids = n_embed is not None
+
+ time_embed_dim = model_channels * 4
+ self.time_embed = nn.Sequential(
+ linear(model_channels, time_embed_dim),
+ nn.SiLU(),
+ linear(time_embed_dim, time_embed_dim),
+ )
+
+ if self.num_classes is not None:
+ self.label_emb = nn.Embedding(num_classes, time_embed_dim)
+
+ self.input_blocks = nn.ModuleList(
+ [
+ TimestepEmbedSequential(
+ conv_nd(dims, in_channels, model_channels, 3, padding=1)
+ )
+ ]
+ )
+ self._feature_size = model_channels
+ input_block_chans = [model_channels]
+ ch = model_channels
+ ds = 1
+ for level, mult in enumerate(channel_mult):
+ for _ in range(num_res_blocks):
+ layers = [
+ ResBlock(
+ ch,
+ time_embed_dim,
+ dropout,
+ out_channels=mult * model_channels,
+ dims=dims,
+ use_checkpoint=use_checkpoint,
+ use_scale_shift_norm=use_scale_shift_norm,
+ )
+ ]
+ ch = mult * model_channels
+ if ds in attention_resolutions:
+ if num_head_channels == -1:
+ dim_head = ch // num_heads
+ else:
+ num_heads = ch // num_head_channels
+ dim_head = num_head_channels
+ if legacy:
+ num_heads = 1
+ dim_head = ch // num_heads if use_spatial_transformer else num_head_channels
+ layers.append(
+ AttentionBlock(
+ ch,
+ use_checkpoint=use_checkpoint,
+ num_heads=num_heads,
+ num_head_channels=dim_head,
+ use_new_attention_order=use_new_attention_order,
+ ) if not use_spatial_transformer else SpatialTransformer(
+ ch, num_heads, dim_head, depth=transformer_depth, context_dim=context_dim
+ )
+ )
+ self.input_blocks.append(TimestepEmbedSequential(*layers))
+ self._feature_size += ch
+ input_block_chans.append(ch)
+ if level != len(channel_mult) - 1:
+ out_ch = ch
+ self.input_blocks.append(
+ TimestepEmbedSequential(
+ ResBlock(
+ ch,
+ time_embed_dim,
+ dropout,
+ out_channels=out_ch,
+ dims=dims,
+ use_checkpoint=use_checkpoint,
+ use_scale_shift_norm=use_scale_shift_norm,
+ down=True,
+ )
+ if resblock_updown
+ else Downsample(
+ ch, conv_resample, dims=dims, out_channels=out_ch
+ )
+ )
+ )
+ ch = out_ch
+ input_block_chans.append(ch)
+ ds *= 2
+ self._feature_size += ch
+
+ if num_head_channels == -1:
+ dim_head = ch // num_heads
+ else:
+ num_heads = ch // num_head_channels
+ dim_head = num_head_channels
+ if legacy:
+ num_heads = 1
+ dim_head = ch // num_heads if use_spatial_transformer else num_head_channels
+ self.middle_block = TimestepEmbedSequential(
+ ResBlock(
+ ch,
+ time_embed_dim,
+ dropout,
+ dims=dims,
+ use_checkpoint=use_checkpoint,
+ use_scale_shift_norm=use_scale_shift_norm,
+ ),
+ AttentionBlock(
+ ch,
+ use_checkpoint=use_checkpoint,
+ num_heads=num_heads,
+ num_head_channels=dim_head,
+ use_new_attention_order=use_new_attention_order,
+ ) if not use_spatial_transformer else SpatialTransformer(
+ ch, num_heads, dim_head, depth=transformer_depth, context_dim=context_dim
+ ),
+ ResBlock(
+ ch,
+ time_embed_dim,
+ dropout,
+ dims=dims,
+ use_checkpoint=use_checkpoint,
+ use_scale_shift_norm=use_scale_shift_norm,
+ ),
+ )
+ self._feature_size += ch
+
+ self.output_blocks = nn.ModuleList([])
+ for level, mult in list(enumerate(channel_mult))[::-1]:
+ for i in range(num_res_blocks + 1):
+ ich = input_block_chans.pop()
+ layers = [
+ ResBlock(
+ ch + ich,
+ time_embed_dim,
+ dropout,
+ out_channels=model_channels * mult,
+ dims=dims,
+ use_checkpoint=use_checkpoint,
+ use_scale_shift_norm=use_scale_shift_norm,
+ )
+ ]
+ ch = model_channels * mult
+ if ds in attention_resolutions:
+ if num_head_channels == -1:
+ dim_head = ch // num_heads
+ else:
+ num_heads = ch // num_head_channels
+ dim_head = num_head_channels
+ if legacy:
+ num_heads = 1
+ dim_head = ch // num_heads if use_spatial_transformer else num_head_channels
+ layers.append(
+ AttentionBlock(
+ ch,
+ use_checkpoint=use_checkpoint,
+ num_heads=num_heads_upsample,
+ num_head_channels=dim_head,
+ use_new_attention_order=use_new_attention_order,
+ ) if not use_spatial_transformer else SpatialTransformer(
+ ch, num_heads, dim_head, depth=transformer_depth, context_dim=context_dim
+ )
+ )
+ if level and i == num_res_blocks:
+ out_ch = ch
+ layers.append(
+ ResBlock(
+ ch,
+ time_embed_dim,
+ dropout,
+ out_channels=out_ch,
+ dims=dims,
+ use_checkpoint=use_checkpoint,
+ use_scale_shift_norm=use_scale_shift_norm,
+ up=True,
+ )
+ if resblock_updown
+ else Upsample(ch, conv_resample, dims=dims, out_channels=out_ch)
+ )
+ ds //= 2
+ self.output_blocks.append(TimestepEmbedSequential(*layers))
+ self._feature_size += ch
+
+ self.out = nn.Sequential(
+ normalization(ch),
+ nn.SiLU(),
+ zero_module(conv_nd(dims, model_channels, out_channels, 3, padding=1)),
+ )
+ if self.predict_codebook_ids:
+ self.id_predictor = nn.Sequential(
+ normalization(ch),
+ conv_nd(dims, model_channels, n_embed, 1),
+ #nn.LogSoftmax(dim=1) # change to cross_entropy and produce non-normalized logits
+ )
+
+ def convert_to_fp16(self):
+ """
+ Convert the torso of the model to float16.
+ """
+ self.input_blocks.apply(convert_module_to_f16)
+ self.middle_block.apply(convert_module_to_f16)
+ self.output_blocks.apply(convert_module_to_f16)
+
+ def convert_to_fp32(self):
+ """
+ Convert the torso of the model to float32.
+ """
+ self.input_blocks.apply(convert_module_to_f32)
+ self.middle_block.apply(convert_module_to_f32)
+ self.output_blocks.apply(convert_module_to_f32)
+
+ def forward(self, x, timesteps=None, context=None, y=None,**kwargs):
+ """
+ Apply the model to an input batch.
+ :param x: an [N x C x ...] Tensor of inputs.
+ :param timesteps: a 1-D batch of timesteps.
+ :param context: conditioning plugged in via crossattn
+ :param y: an [N] Tensor of labels, if class-conditional.
+ :return: an [N x C x ...] Tensor of outputs.
+ """
+ assert (y is not None) == (
+ self.num_classes is not None
+ ), "must specify y if and only if the model is class-conditional"
+ hs = []
+ t_emb = timestep_embedding(timesteps, self.model_channels, repeat_only=False)
+ emb = self.time_embed(t_emb)
+
+ if self.num_classes is not None:
+ assert y.shape == (x.shape[0],)
+ emb = emb + self.label_emb(y)
+
+ h = x.type(self.dtype)
+ for module in self.input_blocks:
+ h = module(h, emb, context)
+ hs.append(h)
+ h = self.middle_block(h, emb, context)
+ for module in self.output_blocks:
+ h = th.cat([h, hs.pop()], dim=1)
+ h = module(h, emb, context)
+ h = h.type(x.dtype)
+ if self.predict_codebook_ids:
+ return self.id_predictor(h)
+ else:
+ return self.out(h)
+
+
+class EncoderUNetModel(nn.Module):
+ """
+ The half UNet model with attention and timestep embedding.
+ For usage, see UNet.
+ """
+
+ def __init__(
+ self,
+ image_size,
+ in_channels,
+ model_channels,
+ out_channels,
+ num_res_blocks,
+ attention_resolutions,
+ dropout=0,
+ channel_mult=(1, 2, 4, 8),
+ conv_resample=True,
+ dims=2,
+ use_checkpoint=False,
+ use_fp16=False,
+ num_heads=1,
+ num_head_channels=-1,
+ num_heads_upsample=-1,
+ use_scale_shift_norm=False,
+ resblock_updown=False,
+ use_new_attention_order=False,
+ pool="adaptive",
+ *args,
+ **kwargs
+ ):
+ super().__init__()
+
+ if num_heads_upsample == -1:
+ num_heads_upsample = num_heads
+
+ self.in_channels = in_channels
+ self.model_channels = model_channels
+ self.out_channels = out_channels
+ self.num_res_blocks = num_res_blocks
+ self.attention_resolutions = attention_resolutions
+ self.dropout = dropout
+ self.channel_mult = channel_mult
+ self.conv_resample = conv_resample
+ self.use_checkpoint = use_checkpoint
+ self.dtype = th.float16 if use_fp16 else th.float32
+ self.num_heads = num_heads
+ self.num_head_channels = num_head_channels
+ self.num_heads_upsample = num_heads_upsample
+
+ time_embed_dim = model_channels * 4
+ self.time_embed = nn.Sequential(
+ linear(model_channels, time_embed_dim),
+ nn.SiLU(),
+ linear(time_embed_dim, time_embed_dim),
+ )
+
+ self.input_blocks = nn.ModuleList(
+ [
+ TimestepEmbedSequential(
+ conv_nd(dims, in_channels, model_channels, 3, padding=1)
+ )
+ ]
+ )
+ self._feature_size = model_channels
+ input_block_chans = [model_channels]
+ ch = model_channels
+ ds = 1
+ for level, mult in enumerate(channel_mult):
+ for _ in range(num_res_blocks):
+ layers = [
+ ResBlock(
+ ch,
+ time_embed_dim,
+ dropout,
+ out_channels=mult * model_channels,
+ dims=dims,
+ use_checkpoint=use_checkpoint,
+ use_scale_shift_norm=use_scale_shift_norm,
+ )
+ ]
+ ch = mult * model_channels
+ if ds in attention_resolutions:
+ layers.append(
+ AttentionBlock(
+ ch,
+ use_checkpoint=use_checkpoint,
+ num_heads=num_heads,
+ num_head_channels=num_head_channels,
+ use_new_attention_order=use_new_attention_order,
+ )
+ )
+ self.input_blocks.append(TimestepEmbedSequential(*layers))
+ self._feature_size += ch
+ input_block_chans.append(ch)
+ if level != len(channel_mult) - 1:
+ out_ch = ch
+ self.input_blocks.append(
+ TimestepEmbedSequential(
+ ResBlock(
+ ch,
+ time_embed_dim,
+ dropout,
+ out_channels=out_ch,
+ dims=dims,
+ use_checkpoint=use_checkpoint,
+ use_scale_shift_norm=use_scale_shift_norm,
+ down=True,
+ )
+ if resblock_updown
+ else Downsample(
+ ch, conv_resample, dims=dims, out_channels=out_ch
+ )
+ )
+ )
+ ch = out_ch
+ input_block_chans.append(ch)
+ ds *= 2
+ self._feature_size += ch
+
+ self.middle_block = TimestepEmbedSequential(
+ ResBlock(
+ ch,
+ time_embed_dim,
+ dropout,
+ dims=dims,
+ use_checkpoint=use_checkpoint,
+ use_scale_shift_norm=use_scale_shift_norm,
+ ),
+ AttentionBlock(
+ ch,
+ use_checkpoint=use_checkpoint,
+ num_heads=num_heads,
+ num_head_channels=num_head_channels,
+ use_new_attention_order=use_new_attention_order,
+ ),
+ ResBlock(
+ ch,
+ time_embed_dim,
+ dropout,
+ dims=dims,
+ use_checkpoint=use_checkpoint,
+ use_scale_shift_norm=use_scale_shift_norm,
+ ),
+ )
+ self._feature_size += ch
+ self.pool = pool
+ if pool == "adaptive":
+ self.out = nn.Sequential(
+ normalization(ch),
+ nn.SiLU(),
+ nn.AdaptiveAvgPool2d((1, 1)),
+ zero_module(conv_nd(dims, ch, out_channels, 1)),
+ nn.Flatten(),
+ )
+ elif pool == "attention":
+ assert num_head_channels != -1
+ self.out = nn.Sequential(
+ normalization(ch),
+ nn.SiLU(),
+ AttentionPool2d(
+ (image_size // ds), ch, num_head_channels, out_channels
+ ),
+ )
+ elif pool == "spatial":
+ self.out = nn.Sequential(
+ nn.Linear(self._feature_size, 2048),
+ nn.ReLU(),
+ nn.Linear(2048, self.out_channels),
+ )
+ elif pool == "spatial_v2":
+ self.out = nn.Sequential(
+ nn.Linear(self._feature_size, 2048),
+ normalization(2048),
+ nn.SiLU(),
+ nn.Linear(2048, self.out_channels),
+ )
+ else:
+ raise NotImplementedError(f"Unexpected {pool} pooling")
+
+ def convert_to_fp16(self):
+ """
+ Convert the torso of the model to float16.
+ """
+ self.input_blocks.apply(convert_module_to_f16)
+ self.middle_block.apply(convert_module_to_f16)
+
+ def convert_to_fp32(self):
+ """
+ Convert the torso of the model to float32.
+ """
+ self.input_blocks.apply(convert_module_to_f32)
+ self.middle_block.apply(convert_module_to_f32)
+
+ def forward(self, x, timesteps):
+ """
+ Apply the model to an input batch.
+ :param x: an [N x C x ...] Tensor of inputs.
+ :param timesteps: a 1-D batch of timesteps.
+ :return: an [N x K] Tensor of outputs.
+ """
+ emb = self.time_embed(timestep_embedding(timesteps, self.model_channels))
+
+ results = []
+ h = x.type(self.dtype)
+ for module in self.input_blocks:
+ h = module(h, emb)
+ if self.pool.startswith("spatial"):
+ results.append(h.type(x.dtype).mean(dim=(2, 3)))
+ h = self.middle_block(h, emb)
+ if self.pool.startswith("spatial"):
+ results.append(h.type(x.dtype).mean(dim=(2, 3)))
+ h = th.cat(results, axis=-1)
+ return self.out(h)
+ else:
+ h = h.type(x.dtype)
+ return self.out(h)
+
diff --git a/latent-diffusion/ldm/modules/diffusionmodules/util.py b/latent-diffusion/ldm/modules/diffusionmodules/util.py
new file mode 100644
index 0000000000000000000000000000000000000000..a952e6c40308c33edd422da0ce6a60f47e73661b
--- /dev/null
+++ b/latent-diffusion/ldm/modules/diffusionmodules/util.py
@@ -0,0 +1,267 @@
+# adopted from
+# https://github.com/openai/improved-diffusion/blob/main/improved_diffusion/gaussian_diffusion.py
+# and
+# https://github.com/lucidrains/denoising-diffusion-pytorch/blob/7706bdfc6f527f58d33f84b7b522e61e6e3164b3/denoising_diffusion_pytorch/denoising_diffusion_pytorch.py
+# and
+# https://github.com/openai/guided-diffusion/blob/0ba878e517b276c45d1195eb29f6f5f72659a05b/guided_diffusion/nn.py
+#
+# thanks!
+
+
+import os
+import math
+import torch
+import torch.nn as nn
+import numpy as np
+from einops import repeat
+
+from ldm.util import instantiate_from_config
+
+
+def make_beta_schedule(schedule, n_timestep, linear_start=1e-4, linear_end=2e-2, cosine_s=8e-3):
+ if schedule == "linear":
+ betas = (
+ torch.linspace(linear_start ** 0.5, linear_end ** 0.5, n_timestep, dtype=torch.float64) ** 2
+ )
+
+ elif schedule == "cosine":
+ timesteps = (
+ torch.arange(n_timestep + 1, dtype=torch.float64) / n_timestep + cosine_s
+ )
+ alphas = timesteps / (1 + cosine_s) * np.pi / 2
+ alphas = torch.cos(alphas).pow(2)
+ alphas = alphas / alphas[0]
+ betas = 1 - alphas[1:] / alphas[:-1]
+ betas = np.clip(betas, a_min=0, a_max=0.999)
+
+ elif schedule == "sqrt_linear":
+ betas = torch.linspace(linear_start, linear_end, n_timestep, dtype=torch.float64)
+ elif schedule == "sqrt":
+ betas = torch.linspace(linear_start, linear_end, n_timestep, dtype=torch.float64) ** 0.5
+ else:
+ raise ValueError(f"schedule '{schedule}' unknown.")
+ return betas.numpy()
+
+
+def make_ddim_timesteps(ddim_discr_method, num_ddim_timesteps, num_ddpm_timesteps, verbose=True):
+ if ddim_discr_method == 'uniform':
+ c = num_ddpm_timesteps // num_ddim_timesteps
+ ddim_timesteps = np.asarray(list(range(0, num_ddpm_timesteps, c)))
+ elif ddim_discr_method == 'quad':
+ ddim_timesteps = ((np.linspace(0, np.sqrt(num_ddpm_timesteps * .8), num_ddim_timesteps)) ** 2).astype(int)
+ else:
+ raise NotImplementedError(f'There is no ddim discretization method called "{ddim_discr_method}"')
+
+ # assert ddim_timesteps.shape[0] == num_ddim_timesteps
+ # add one to get the final alpha values right (the ones from first scale to data during sampling)
+ steps_out = ddim_timesteps + 1
+ if verbose:
+ print(f'Selected timesteps for ddim sampler: {steps_out}')
+ return steps_out
+
+
+def make_ddim_sampling_parameters(alphacums, ddim_timesteps, eta, verbose=True):
+ # select alphas for computing the variance schedule
+ alphas = alphacums[ddim_timesteps]
+ alphas_prev = np.asarray([alphacums[0]] + alphacums[ddim_timesteps[:-1]].tolist())
+
+ # according the the formula provided in https://arxiv.org/abs/2010.02502
+ sigmas = eta * np.sqrt((1 - alphas_prev) / (1 - alphas) * (1 - alphas / alphas_prev))
+ if verbose:
+ print(f'Selected alphas for ddim sampler: a_t: {alphas}; a_(t-1): {alphas_prev}')
+ print(f'For the chosen value of eta, which is {eta}, '
+ f'this results in the following sigma_t schedule for ddim sampler {sigmas}')
+ return sigmas, alphas, alphas_prev
+
+
+def betas_for_alpha_bar(num_diffusion_timesteps, alpha_bar, max_beta=0.999):
+ """
+ Create a beta schedule that discretizes the given alpha_t_bar function,
+ which defines the cumulative product of (1-beta) over time from t = [0,1].
+ :param num_diffusion_timesteps: the number of betas to produce.
+ :param alpha_bar: a lambda that takes an argument t from 0 to 1 and
+ produces the cumulative product of (1-beta) up to that
+ part of the diffusion process.
+ :param max_beta: the maximum beta to use; use values lower than 1 to
+ prevent singularities.
+ """
+ betas = []
+ for i in range(num_diffusion_timesteps):
+ t1 = i / num_diffusion_timesteps
+ t2 = (i + 1) / num_diffusion_timesteps
+ betas.append(min(1 - alpha_bar(t2) / alpha_bar(t1), max_beta))
+ return np.array(betas)
+
+
+def extract_into_tensor(a, t, x_shape):
+ b, *_ = t.shape
+ out = a.gather(-1, t)
+ return out.reshape(b, *((1,) * (len(x_shape) - 1)))
+
+
+def checkpoint(func, inputs, params, flag):
+ """
+ Evaluate a function without caching intermediate activations, allowing for
+ reduced memory at the expense of extra compute in the backward pass.
+ :param func: the function to evaluate.
+ :param inputs: the argument sequence to pass to `func`.
+ :param params: a sequence of parameters `func` depends on but does not
+ explicitly take as arguments.
+ :param flag: if False, disable gradient checkpointing.
+ """
+ if flag:
+ args = tuple(inputs) + tuple(params)
+ return CheckpointFunction.apply(func, len(inputs), *args)
+ else:
+ return func(*inputs)
+
+
+class CheckpointFunction(torch.autograd.Function):
+ @staticmethod
+ def forward(ctx, run_function, length, *args):
+ ctx.run_function = run_function
+ ctx.input_tensors = list(args[:length])
+ ctx.input_params = list(args[length:])
+
+ with torch.no_grad():
+ output_tensors = ctx.run_function(*ctx.input_tensors)
+ return output_tensors
+
+ @staticmethod
+ def backward(ctx, *output_grads):
+ ctx.input_tensors = [x.detach().requires_grad_(True) for x in ctx.input_tensors]
+ with torch.enable_grad():
+ # Fixes a bug where the first op in run_function modifies the
+ # Tensor storage in place, which is not allowed for detach()'d
+ # Tensors.
+ shallow_copies = [x.view_as(x) for x in ctx.input_tensors]
+ output_tensors = ctx.run_function(*shallow_copies)
+ input_grads = torch.autograd.grad(
+ output_tensors,
+ ctx.input_tensors + ctx.input_params,
+ output_grads,
+ allow_unused=True,
+ )
+ del ctx.input_tensors
+ del ctx.input_params
+ del output_tensors
+ return (None, None) + input_grads
+
+
+def timestep_embedding(timesteps, dim, max_period=10000, repeat_only=False):
+ """
+ Create sinusoidal timestep embeddings.
+ :param timesteps: a 1-D Tensor of N indices, one per batch element.
+ These may be fractional.
+ :param dim: the dimension of the output.
+ :param max_period: controls the minimum frequency of the embeddings.
+ :return: an [N x dim] Tensor of positional embeddings.
+ """
+ if not repeat_only:
+ half = dim // 2
+ freqs = torch.exp(
+ -math.log(max_period) * torch.arange(start=0, end=half, dtype=torch.float32) / half
+ ).to(device=timesteps.device)
+ args = timesteps[:, None].float() * freqs[None]
+ embedding = torch.cat([torch.cos(args), torch.sin(args)], dim=-1)
+ if dim % 2:
+ embedding = torch.cat([embedding, torch.zeros_like(embedding[:, :1])], dim=-1)
+ else:
+ embedding = repeat(timesteps, 'b -> b d', d=dim)
+ return embedding
+
+
+def zero_module(module):
+ """
+ Zero out the parameters of a module and return it.
+ """
+ for p in module.parameters():
+ p.detach().zero_()
+ return module
+
+
+def scale_module(module, scale):
+ """
+ Scale the parameters of a module and return it.
+ """
+ for p in module.parameters():
+ p.detach().mul_(scale)
+ return module
+
+
+def mean_flat(tensor):
+ """
+ Take the mean over all non-batch dimensions.
+ """
+ return tensor.mean(dim=list(range(1, len(tensor.shape))))
+
+
+def normalization(channels):
+ """
+ Make a standard normalization layer.
+ :param channels: number of input channels.
+ :return: an nn.Module for normalization.
+ """
+ return GroupNorm32(32, channels)
+
+
+# PyTorch 1.7 has SiLU, but we support PyTorch 1.5.
+class SiLU(nn.Module):
+ def forward(self, x):
+ return x * torch.sigmoid(x)
+
+
+class GroupNorm32(nn.GroupNorm):
+ def forward(self, x):
+ return super().forward(x.float()).type(x.dtype)
+
+def conv_nd(dims, *args, **kwargs):
+ """
+ Create a 1D, 2D, or 3D convolution module.
+ """
+ if dims == 1:
+ return nn.Conv1d(*args, **kwargs)
+ elif dims == 2:
+ return nn.Conv2d(*args, **kwargs)
+ elif dims == 3:
+ return nn.Conv3d(*args, **kwargs)
+ raise ValueError(f"unsupported dimensions: {dims}")
+
+
+def linear(*args, **kwargs):
+ """
+ Create a linear module.
+ """
+ return nn.Linear(*args, **kwargs)
+
+
+def avg_pool_nd(dims, *args, **kwargs):
+ """
+ Create a 1D, 2D, or 3D average pooling module.
+ """
+ if dims == 1:
+ return nn.AvgPool1d(*args, **kwargs)
+ elif dims == 2:
+ return nn.AvgPool2d(*args, **kwargs)
+ elif dims == 3:
+ return nn.AvgPool3d(*args, **kwargs)
+ raise ValueError(f"unsupported dimensions: {dims}")
+
+
+class HybridConditioner(nn.Module):
+
+ def __init__(self, c_concat_config, c_crossattn_config):
+ super().__init__()
+ self.concat_conditioner = instantiate_from_config(c_concat_config)
+ self.crossattn_conditioner = instantiate_from_config(c_crossattn_config)
+
+ def forward(self, c_concat, c_crossattn):
+ c_concat = self.concat_conditioner(c_concat)
+ c_crossattn = self.crossattn_conditioner(c_crossattn)
+ return {'c_concat': [c_concat], 'c_crossattn': [c_crossattn]}
+
+
+def noise_like(shape, device, repeat=False):
+ repeat_noise = lambda: torch.randn((1, *shape[1:]), device=device).repeat(shape[0], *((1,) * (len(shape) - 1)))
+ noise = lambda: torch.randn(shape, device=device)
+ return repeat_noise() if repeat else noise()
\ No newline at end of file
diff --git a/latent-diffusion/ldm/modules/distributions/__init__.py b/latent-diffusion/ldm/modules/distributions/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/latent-diffusion/ldm/modules/distributions/__pycache__/__init__.cpython-39.pyc b/latent-diffusion/ldm/modules/distributions/__pycache__/__init__.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..b9e123aa7cf5bf4e02a432f75b653715906189db
Binary files /dev/null and b/latent-diffusion/ldm/modules/distributions/__pycache__/__init__.cpython-39.pyc differ
diff --git a/latent-diffusion/ldm/modules/distributions/__pycache__/distributions.cpython-39.pyc b/latent-diffusion/ldm/modules/distributions/__pycache__/distributions.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..aa01d973225c4276f0128704ad4320c5da65a493
Binary files /dev/null and b/latent-diffusion/ldm/modules/distributions/__pycache__/distributions.cpython-39.pyc differ
diff --git a/latent-diffusion/ldm/modules/distributions/distributions.py b/latent-diffusion/ldm/modules/distributions/distributions.py
new file mode 100644
index 0000000000000000000000000000000000000000..f2b8ef901130efc171aa69742ca0244d94d3f2e9
--- /dev/null
+++ b/latent-diffusion/ldm/modules/distributions/distributions.py
@@ -0,0 +1,92 @@
+import torch
+import numpy as np
+
+
+class AbstractDistribution:
+ def sample(self):
+ raise NotImplementedError()
+
+ def mode(self):
+ raise NotImplementedError()
+
+
+class DiracDistribution(AbstractDistribution):
+ def __init__(self, value):
+ self.value = value
+
+ def sample(self):
+ return self.value
+
+ def mode(self):
+ return self.value
+
+
+class DiagonalGaussianDistribution(object):
+ def __init__(self, parameters, deterministic=False):
+ self.parameters = parameters
+ self.mean, self.logvar = torch.chunk(parameters, 2, dim=1)
+ self.logvar = torch.clamp(self.logvar, -30.0, 20.0)
+ self.deterministic = deterministic
+ self.std = torch.exp(0.5 * self.logvar)
+ self.var = torch.exp(self.logvar)
+ if self.deterministic:
+ self.var = self.std = torch.zeros_like(self.mean).to(device=self.parameters.device)
+
+ def sample(self):
+ x = self.mean + self.std * torch.randn(self.mean.shape).to(device=self.parameters.device)
+ return x
+
+ def kl(self, other=None):
+ if self.deterministic:
+ return torch.Tensor([0.])
+ else:
+ if other is None:
+ return 0.5 * torch.sum(torch.pow(self.mean, 2)
+ + self.var - 1.0 - self.logvar,
+ dim=[1, 2, 3])
+ else:
+ return 0.5 * torch.sum(
+ torch.pow(self.mean - other.mean, 2) / other.var
+ + self.var / other.var - 1.0 - self.logvar + other.logvar,
+ dim=[1, 2, 3])
+
+ def nll(self, sample, dims=[1,2,3]):
+ if self.deterministic:
+ return torch.Tensor([0.])
+ logtwopi = np.log(2.0 * np.pi)
+ return 0.5 * torch.sum(
+ logtwopi + self.logvar + torch.pow(sample - self.mean, 2) / self.var,
+ dim=dims)
+
+ def mode(self):
+ return self.mean
+
+
+def normal_kl(mean1, logvar1, mean2, logvar2):
+ """
+ source: https://github.com/openai/guided-diffusion/blob/27c20a8fab9cb472df5d6bdd6c8d11c8f430b924/guided_diffusion/losses.py#L12
+ Compute the KL divergence between two gaussians.
+ Shapes are automatically broadcasted, so batches can be compared to
+ scalars, among other use cases.
+ """
+ tensor = None
+ for obj in (mean1, logvar1, mean2, logvar2):
+ if isinstance(obj, torch.Tensor):
+ tensor = obj
+ break
+ assert tensor is not None, "at least one argument must be a Tensor"
+
+ # Force variances to be Tensors. Broadcasting helps convert scalars to
+ # Tensors, but it does not work for torch.exp().
+ logvar1, logvar2 = [
+ x if isinstance(x, torch.Tensor) else torch.tensor(x).to(tensor)
+ for x in (logvar1, logvar2)
+ ]
+
+ return 0.5 * (
+ -1.0
+ + logvar2
+ - logvar1
+ + torch.exp(logvar1 - logvar2)
+ + ((mean1 - mean2) ** 2) * torch.exp(-logvar2)
+ )
diff --git a/latent-diffusion/ldm/modules/ema.py b/latent-diffusion/ldm/modules/ema.py
new file mode 100644
index 0000000000000000000000000000000000000000..c8c75af43565f6e140287644aaaefa97dd6e67c5
--- /dev/null
+++ b/latent-diffusion/ldm/modules/ema.py
@@ -0,0 +1,76 @@
+import torch
+from torch import nn
+
+
+class LitEma(nn.Module):
+ def __init__(self, model, decay=0.9999, use_num_upates=True):
+ super().__init__()
+ if decay < 0.0 or decay > 1.0:
+ raise ValueError('Decay must be between 0 and 1')
+
+ self.m_name2s_name = {}
+ self.register_buffer('decay', torch.tensor(decay, dtype=torch.float32))
+ self.register_buffer('num_updates', torch.tensor(0,dtype=torch.int) if use_num_upates
+ else torch.tensor(-1,dtype=torch.int))
+
+ for name, p in model.named_parameters():
+ if p.requires_grad:
+ #remove as '.'-character is not allowed in buffers
+ s_name = name.replace('.','')
+ self.m_name2s_name.update({name:s_name})
+ self.register_buffer(s_name,p.clone().detach().data)
+
+ self.collected_params = []
+
+ def forward(self,model):
+ decay = self.decay
+
+ if self.num_updates >= 0:
+ self.num_updates += 1
+ decay = min(self.decay,(1 + self.num_updates) / (10 + self.num_updates))
+
+ one_minus_decay = 1.0 - decay
+
+ with torch.no_grad():
+ m_param = dict(model.named_parameters())
+ shadow_params = dict(self.named_buffers())
+
+ for key in m_param:
+ if m_param[key].requires_grad:
+ sname = self.m_name2s_name[key]
+ shadow_params[sname] = shadow_params[sname].type_as(m_param[key])
+ shadow_params[sname].sub_(one_minus_decay * (shadow_params[sname] - m_param[key]))
+ else:
+ assert not key in self.m_name2s_name
+
+ def copy_to(self, model):
+ m_param = dict(model.named_parameters())
+ shadow_params = dict(self.named_buffers())
+ for key in m_param:
+ if m_param[key].requires_grad:
+ m_param[key].data.copy_(shadow_params[self.m_name2s_name[key]].data)
+ else:
+ assert not key in self.m_name2s_name
+
+ def store(self, parameters):
+ """
+ Save the current parameters for restoring later.
+ Args:
+ parameters: Iterable of `torch.nn.Parameter`; the parameters to be
+ temporarily stored.
+ """
+ self.collected_params = [param.clone() for param in parameters]
+
+ def restore(self, parameters):
+ """
+ Restore the parameters stored with the `store` method.
+ Useful to validate the model with EMA parameters without affecting the
+ original optimization process. Store the parameters before the
+ `copy_to` method. After validation (or model saving), use this to
+ restore the former parameters.
+ Args:
+ parameters: Iterable of `torch.nn.Parameter`; the parameters to be
+ updated with the stored parameters.
+ """
+ for c_param, param in zip(self.collected_params, parameters):
+ param.data.copy_(c_param.data)
diff --git a/latent-diffusion/ldm/modules/encoders/__init__.py b/latent-diffusion/ldm/modules/encoders/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/latent-diffusion/ldm/modules/encoders/__pycache__/__init__.cpython-39.pyc b/latent-diffusion/ldm/modules/encoders/__pycache__/__init__.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..9be86aa0de919c09662c7f181bc54d7718d130b3
Binary files /dev/null and b/latent-diffusion/ldm/modules/encoders/__pycache__/__init__.cpython-39.pyc differ
diff --git a/latent-diffusion/ldm/modules/encoders/__pycache__/modules.cpython-39.pyc b/latent-diffusion/ldm/modules/encoders/__pycache__/modules.cpython-39.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..803bdd48f6c5cf176f5e73f1e014ed4ce72e5c81
Binary files /dev/null and b/latent-diffusion/ldm/modules/encoders/__pycache__/modules.cpython-39.pyc differ
diff --git a/latent-diffusion/ldm/modules/encoders/modules.py b/latent-diffusion/ldm/modules/encoders/modules.py
new file mode 100644
index 0000000000000000000000000000000000000000..506e39ba417922ae61dcd753a50b237420fbd3a8
--- /dev/null
+++ b/latent-diffusion/ldm/modules/encoders/modules.py
@@ -0,0 +1,131 @@
+import torch
+import torch.nn as nn
+from functools import partial
+
+from ldm.modules.x_transformer import Encoder, TransformerWrapper # TODO: can we directly rely on lucidrains code and simply add this as a reuirement? --> test
+
+
+class AbstractEncoder(nn.Module):
+ def __init__(self):
+ super().__init__()
+
+ def encode(self, *args, **kwargs):
+ raise NotImplementedError
+
+
+
+class ClassEmbedder(nn.Module):
+ def __init__(self, embed_dim, n_classes=1000, key='class'):
+ super().__init__()
+ self.key = key
+ self.embedding = nn.Embedding(n_classes, embed_dim)
+
+ def forward(self, batch, key=None):
+ if key is None:
+ key = self.key
+ # this is for use in crossattn
+ c = batch[key][:, None]
+ c = self.embedding(c)
+ return c
+
+
+class TransformerEmbedder(AbstractEncoder):
+ """Some transformer encoder layers"""
+ def __init__(self, n_embed, n_layer, vocab_size, max_seq_len=77, device="cuda"):
+ super().__init__()
+ self.device = device
+ self.transformer = TransformerWrapper(num_tokens=vocab_size, max_seq_len=max_seq_len,
+ attn_layers=Encoder(dim=n_embed, depth=n_layer))
+
+ def forward(self, tokens):
+ tokens = tokens.to(self.device) # meh
+ z = self.transformer(tokens, return_embeddings=True)
+ return z
+
+ def encode(self, x):
+ return self(x)
+
+
+class BERTTokenizer(AbstractEncoder):
+ """ Uses a pretrained BERT tokenizer by huggingface. Vocab size: 30522 (?)"""
+ def __init__(self, device="cuda", vq_interface=True, max_length=77):
+ super().__init__()
+ from transformers import BertTokenizerFast # TODO: add to reuquirements
+ self.tokenizer = BertTokenizerFast.from_pretrained("bert-base-uncased")
+ self.device = device
+ self.vq_interface = vq_interface
+ self.max_length = max_length
+
+ def forward(self, text):
+ batch_encoding = self.tokenizer(text, truncation=True, max_length=self.max_length, return_length=True,
+ return_overflowing_tokens=False, padding="max_length", return_tensors="pt")
+ tokens = batch_encoding["input_ids"].to(self.device)
+ return tokens
+
+ @torch.no_grad()
+ def encode(self, text):
+ tokens = self(text)
+ if not self.vq_interface:
+ return tokens
+ return None, None, [None, None, tokens]
+
+ def decode(self, text):
+ return text
+
+
+class BERTEmbedder(AbstractEncoder):
+ """Uses the BERT tokenizr model and add some transformer encoder layers"""
+ def __init__(self, n_embed, n_layer, vocab_size=30522, max_seq_len=77,
+ device="cuda",use_tokenizer=True, embedding_dropout=0.0):
+ super().__init__()
+ self.use_tknz_fn = use_tokenizer
+ if self.use_tknz_fn:
+ self.tknz_fn = BERTTokenizer(vq_interface=False, max_length=max_seq_len)
+ self.device = device
+ self.transformer = TransformerWrapper(num_tokens=vocab_size, max_seq_len=max_seq_len,
+ attn_layers=Encoder(dim=n_embed, depth=n_layer),
+ emb_dropout=embedding_dropout)
+
+ def forward(self, text):
+ if self.use_tknz_fn:
+ tokens = self.tknz_fn(text)#.to(self.device)
+ else:
+ tokens = text
+ z = self.transformer(tokens, return_embeddings=True)
+ return z
+
+ def encode(self, text):
+ # output of length 77
+ return self(text)
+
+
+class SpatialRescaler(nn.Module):
+ def __init__(self,
+ n_stages=1,
+ method='bilinear',
+ multiplier=0.5,
+ in_channels=3,
+ out_channels=None,
+ bias=False):
+ super().__init__()
+ self.n_stages = n_stages
+ assert self.n_stages >= 0
+ assert method in ['nearest','linear','bilinear','trilinear','bicubic','area']
+ self.multiplier = multiplier
+ self.interpolator = partial(torch.nn.functional.interpolate, mode=method)
+ self.remap_output = out_channels is not None
+ if self.remap_output:
+ print(f'Spatial Rescaler mapping from {in_channels} to {out_channels} channels after resizing.')
+ self.channel_mapper = nn.Conv2d(in_channels,out_channels,1,bias=bias)
+
+ def forward(self,x):
+ for stage in range(self.n_stages):
+ x = self.interpolator(x, scale_factor=self.multiplier)
+
+
+ if self.remap_output:
+ x = self.channel_mapper(x)
+ return x
+
+ def encode(self, x):
+ return self(x)
diff --git a/latent-diffusion/ldm/modules/image_degradation/__init__.py b/latent-diffusion/ldm/modules/image_degradation/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..7836cada81f90ded99c58d5942eea4c3477f58fc
--- /dev/null
+++ b/latent-diffusion/ldm/modules/image_degradation/__init__.py
@@ -0,0 +1,2 @@
+from ldm.modules.image_degradation.bsrgan import degradation_bsrgan_variant as degradation_fn_bsr
+from ldm.modules.image_degradation.bsrgan_light import degradation_bsrgan_variant as degradation_fn_bsr_light
diff --git a/latent-diffusion/ldm/modules/image_degradation/bsrgan.py b/latent-diffusion/ldm/modules/image_degradation/bsrgan.py
new file mode 100644
index 0000000000000000000000000000000000000000..32ef56169978e550090261cddbcf5eb611a6173b
--- /dev/null
+++ b/latent-diffusion/ldm/modules/image_degradation/bsrgan.py
@@ -0,0 +1,730 @@
+# -*- coding: utf-8 -*-
+"""
+# --------------------------------------------
+# Super-Resolution
+# --------------------------------------------
+#
+# Kai Zhang (cskaizhang@gmail.com)
+# https://github.com/cszn
+# From 2019/03--2021/08
+# --------------------------------------------
+"""
+
+import numpy as np
+import cv2
+import torch
+
+from functools import partial
+import random
+from scipy import ndimage
+import scipy
+import scipy.stats as ss
+from scipy.interpolate import interp2d
+from scipy.linalg import orth
+import albumentations
+
+import ldm.modules.image_degradation.utils_image as util
+
+
+def modcrop_np(img, sf):
+ '''
+ Args:
+ img: numpy image, WxH or WxHxC
+ sf: scale factor
+ Return:
+ cropped image
+ '''
+ w, h = img.shape[:2]
+ im = np.copy(img)
+ return im[:w - w % sf, :h - h % sf, ...]
+
+
+"""
+# --------------------------------------------
+# anisotropic Gaussian kernels
+# --------------------------------------------
+"""
+
+
+def analytic_kernel(k):
+ """Calculate the X4 kernel from the X2 kernel (for proof see appendix in paper)"""
+ k_size = k.shape[0]
+ # Calculate the big kernels size
+ big_k = np.zeros((3 * k_size - 2, 3 * k_size - 2))
+ # Loop over the small kernel to fill the big one
+ for r in range(k_size):
+ for c in range(k_size):
+ big_k[2 * r:2 * r + k_size, 2 * c:2 * c + k_size] += k[r, c] * k
+ # Crop the edges of the big kernel to ignore very small values and increase run time of SR
+ crop = k_size // 2
+ cropped_big_k = big_k[crop:-crop, crop:-crop]
+ # Normalize to 1
+ return cropped_big_k / cropped_big_k.sum()
+
+
+def anisotropic_Gaussian(ksize=15, theta=np.pi, l1=6, l2=6):
+ """ generate an anisotropic Gaussian kernel
+ Args:
+ ksize : e.g., 15, kernel size
+ theta : [0, pi], rotation angle range
+ l1 : [0.1,50], scaling of eigenvalues
+ l2 : [0.1,l1], scaling of eigenvalues
+ If l1 = l2, will get an isotropic Gaussian kernel.
+ Returns:
+ k : kernel
+ """
+
+ v = np.dot(np.array([[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]]), np.array([1., 0.]))
+ V = np.array([[v[0], v[1]], [v[1], -v[0]]])
+ D = np.array([[l1, 0], [0, l2]])
+ Sigma = np.dot(np.dot(V, D), np.linalg.inv(V))
+ k = gm_blur_kernel(mean=[0, 0], cov=Sigma, size=ksize)
+
+ return k
+
+
+def gm_blur_kernel(mean, cov, size=15):
+ center = size / 2.0 + 0.5
+ k = np.zeros([size, size])
+ for y in range(size):
+ for x in range(size):
+ cy = y - center + 1
+ cx = x - center + 1
+ k[y, x] = ss.multivariate_normal.pdf([cx, cy], mean=mean, cov=cov)
+
+ k = k / np.sum(k)
+ return k
+
+
+def shift_pixel(x, sf, upper_left=True):
+ """shift pixel for super-resolution with different scale factors
+ Args:
+ x: WxHxC or WxH
+ sf: scale factor
+ upper_left: shift direction
+ """
+ h, w = x.shape[:2]
+ shift = (sf - 1) * 0.5
+ xv, yv = np.arange(0, w, 1.0), np.arange(0, h, 1.0)
+ if upper_left:
+ x1 = xv + shift
+ y1 = yv + shift
+ else:
+ x1 = xv - shift
+ y1 = yv - shift
+
+ x1 = np.clip(x1, 0, w - 1)
+ y1 = np.clip(y1, 0, h - 1)
+
+ if x.ndim == 2:
+ x = interp2d(xv, yv, x)(x1, y1)
+ if x.ndim == 3:
+ for i in range(x.shape[-1]):
+ x[:, :, i] = interp2d(xv, yv, x[:, :, i])(x1, y1)
+
+ return x
+
+
+def blur(x, k):
+ '''
+ x: image, NxcxHxW
+ k: kernel, Nx1xhxw
+ '''
+ n, c = x.shape[:2]
+ p1, p2 = (k.shape[-2] - 1) // 2, (k.shape[-1] - 1) // 2
+ x = torch.nn.functional.pad(x, pad=(p1, p2, p1, p2), mode='replicate')
+ k = k.repeat(1, c, 1, 1)
+ k = k.view(-1, 1, k.shape[2], k.shape[3])
+ x = x.view(1, -1, x.shape[2], x.shape[3])
+ x = torch.nn.functional.conv2d(x, k, bias=None, stride=1, padding=0, groups=n * c)
+ x = x.view(n, c, x.shape[2], x.shape[3])
+
+ return x
+
+
+def gen_kernel(k_size=np.array([15, 15]), scale_factor=np.array([4, 4]), min_var=0.6, max_var=10., noise_level=0):
+ """"
+ # modified version of https://github.com/assafshocher/BlindSR_dataset_generator
+ # Kai Zhang
+ # min_var = 0.175 * sf # variance of the gaussian kernel will be sampled between min_var and max_var
+ # max_var = 2.5 * sf
+ """
+ # Set random eigen-vals (lambdas) and angle (theta) for COV matrix
+ lambda_1 = min_var + np.random.rand() * (max_var - min_var)
+ lambda_2 = min_var + np.random.rand() * (max_var - min_var)
+ theta = np.random.rand() * np.pi # random theta
+ noise = -noise_level + np.random.rand(*k_size) * noise_level * 2
+
+ # Set COV matrix using Lambdas and Theta
+ LAMBDA = np.diag([lambda_1, lambda_2])
+ Q = np.array([[np.cos(theta), -np.sin(theta)],
+ [np.sin(theta), np.cos(theta)]])
+ SIGMA = Q @ LAMBDA @ Q.T
+ INV_SIGMA = np.linalg.inv(SIGMA)[None, None, :, :]
+
+ # Set expectation position (shifting kernel for aligned image)
+ MU = k_size // 2 - 0.5 * (scale_factor - 1) # - 0.5 * (scale_factor - k_size % 2)
+ MU = MU[None, None, :, None]
+
+ # Create meshgrid for Gaussian
+ [X, Y] = np.meshgrid(range(k_size[0]), range(k_size[1]))
+ Z = np.stack([X, Y], 2)[:, :, :, None]
+
+ # Calcualte Gaussian for every pixel of the kernel
+ ZZ = Z - MU
+ ZZ_t = ZZ.transpose(0, 1, 3, 2)
+ raw_kernel = np.exp(-0.5 * np.squeeze(ZZ_t @ INV_SIGMA @ ZZ)) * (1 + noise)
+
+ # shift the kernel so it will be centered
+ # raw_kernel_centered = kernel_shift(raw_kernel, scale_factor)
+
+ # Normalize the kernel and return
+ # kernel = raw_kernel_centered / np.sum(raw_kernel_centered)
+ kernel = raw_kernel / np.sum(raw_kernel)
+ return kernel
+
+
+def fspecial_gaussian(hsize, sigma):
+ hsize = [hsize, hsize]
+ siz = [(hsize[0] - 1.0) / 2.0, (hsize[1] - 1.0) / 2.0]
+ std = sigma
+ [x, y] = np.meshgrid(np.arange(-siz[1], siz[1] + 1), np.arange(-siz[0], siz[0] + 1))
+ arg = -(x * x + y * y) / (2 * std * std)
+ h = np.exp(arg)
+ h[h < scipy.finfo(float).eps * h.max()] = 0
+ sumh = h.sum()
+ if sumh != 0:
+ h = h / sumh
+ return h
+
+
+def fspecial_laplacian(alpha):
+ alpha = max([0, min([alpha, 1])])
+ h1 = alpha / (alpha + 1)
+ h2 = (1 - alpha) / (alpha + 1)
+ h = [[h1, h2, h1], [h2, -4 / (alpha + 1), h2], [h1, h2, h1]]
+ h = np.array(h)
+ return h
+
+
+def fspecial(filter_type, *args, **kwargs):
+ '''
+ python code from:
+ https://github.com/ronaldosena/imagens-medicas-2/blob/40171a6c259edec7827a6693a93955de2bd39e76/Aulas/aula_2_-_uniform_filter/matlab_fspecial.py
+ '''
+ if filter_type == 'gaussian':
+ return fspecial_gaussian(*args, **kwargs)
+ if filter_type == 'laplacian':
+ return fspecial_laplacian(*args, **kwargs)
+
+
+"""
+# --------------------------------------------
+# degradation models
+# --------------------------------------------
+"""
+
+
+def bicubic_degradation(x, sf=3):
+ '''
+ Args:
+ x: HxWxC image, [0, 1]
+ sf: down-scale factor
+ Return:
+ bicubicly downsampled LR image
+ '''
+ x = util.imresize_np(x, scale=1 / sf)
+ return x
+
+
+def srmd_degradation(x, k, sf=3):
+ ''' blur + bicubic downsampling
+ Args:
+ x: HxWxC image, [0, 1]
+ k: hxw, double
+ sf: down-scale factor
+ Return:
+ downsampled LR image
+ Reference:
+ @inproceedings{zhang2018learning,
+ title={Learning a single convolutional super-resolution network for multiple degradations},
+ author={Zhang, Kai and Zuo, Wangmeng and Zhang, Lei},
+ booktitle={IEEE Conference on Computer Vision and Pattern Recognition},
+ pages={3262--3271},
+ year={2018}
+ }
+ '''
+ x = ndimage.filters.convolve(x, np.expand_dims(k, axis=2), mode='wrap') # 'nearest' | 'mirror'
+ x = bicubic_degradation(x, sf=sf)
+ return x
+
+
+def dpsr_degradation(x, k, sf=3):
+ ''' bicubic downsampling + blur
+ Args:
+ x: HxWxC image, [0, 1]
+ k: hxw, double
+ sf: down-scale factor
+ Return:
+ downsampled LR image
+ Reference:
+ @inproceedings{zhang2019deep,
+ title={Deep Plug-and-Play Super-Resolution for Arbitrary Blur Kernels},
+ author={Zhang, Kai and Zuo, Wangmeng and Zhang, Lei},
+ booktitle={IEEE Conference on Computer Vision and Pattern Recognition},
+ pages={1671--1681},
+ year={2019}
+ }
+ '''
+ x = bicubic_degradation(x, sf=sf)
+ x = ndimage.filters.convolve(x, np.expand_dims(k, axis=2), mode='wrap')
+ return x
+
+
+def classical_degradation(x, k, sf=3):
+ ''' blur + downsampling
+ Args:
+ x: HxWxC image, [0, 1]/[0, 255]
+ k: hxw, double
+ sf: down-scale factor
+ Return:
+ downsampled LR image
+ '''
+ x = ndimage.filters.convolve(x, np.expand_dims(k, axis=2), mode='wrap')
+ # x = filters.correlate(x, np.expand_dims(np.flip(k), axis=2))
+ st = 0
+ return x[st::sf, st::sf, ...]
+
+
+def add_sharpening(img, weight=0.5, radius=50, threshold=10):
+ """USM sharpening. borrowed from real-ESRGAN
+ Input image: I; Blurry image: B.
+ 1. K = I + weight * (I - B)
+ 2. Mask = 1 if abs(I - B) > threshold, else: 0
+ 3. Blur mask:
+ 4. Out = Mask * K + (1 - Mask) * I
+ Args:
+ img (Numpy array): Input image, HWC, BGR; float32, [0, 1].
+ weight (float): Sharp weight. Default: 1.
+ radius (float): Kernel size of Gaussian blur. Default: 50.
+ threshold (int):
+ """
+ if radius % 2 == 0:
+ radius += 1
+ blur = cv2.GaussianBlur(img, (radius, radius), 0)
+ residual = img - blur
+ mask = np.abs(residual) * 255 > threshold
+ mask = mask.astype('float32')
+ soft_mask = cv2.GaussianBlur(mask, (radius, radius), 0)
+
+ K = img + weight * residual
+ K = np.clip(K, 0, 1)
+ return soft_mask * K + (1 - soft_mask) * img
+
+
+def add_blur(img, sf=4):
+ wd2 = 4.0 + sf
+ wd = 2.0 + 0.2 * sf
+ if random.random() < 0.5:
+ l1 = wd2 * random.random()
+ l2 = wd2 * random.random()
+ k = anisotropic_Gaussian(ksize=2 * random.randint(2, 11) + 3, theta=random.random() * np.pi, l1=l1, l2=l2)
+ else:
+ k = fspecial('gaussian', 2 * random.randint(2, 11) + 3, wd * random.random())
+ img = ndimage.filters.convolve(img, np.expand_dims(k, axis=2), mode='mirror')
+
+ return img
+
+
+def add_resize(img, sf=4):
+ rnum = np.random.rand()
+ if rnum > 0.8: # up
+ sf1 = random.uniform(1, 2)
+ elif rnum < 0.7: # down
+ sf1 = random.uniform(0.5 / sf, 1)
+ else:
+ sf1 = 1.0
+ img = cv2.resize(img, (int(sf1 * img.shape[1]), int(sf1 * img.shape[0])), interpolation=random.choice([1, 2, 3]))
+ img = np.clip(img, 0.0, 1.0)
+
+ return img
+
+
+# def add_Gaussian_noise(img, noise_level1=2, noise_level2=25):
+# noise_level = random.randint(noise_level1, noise_level2)
+# rnum = np.random.rand()
+# if rnum > 0.6: # add color Gaussian noise
+# img += np.random.normal(0, noise_level / 255.0, img.shape).astype(np.float32)
+# elif rnum < 0.4: # add grayscale Gaussian noise
+# img += np.random.normal(0, noise_level / 255.0, (*img.shape[:2], 1)).astype(np.float32)
+# else: # add noise
+# L = noise_level2 / 255.
+# D = np.diag(np.random.rand(3))
+# U = orth(np.random.rand(3, 3))
+# conv = np.dot(np.dot(np.transpose(U), D), U)
+# img += np.random.multivariate_normal([0, 0, 0], np.abs(L ** 2 * conv), img.shape[:2]).astype(np.float32)
+# img = np.clip(img, 0.0, 1.0)
+# return img
+
+def add_Gaussian_noise(img, noise_level1=2, noise_level2=25):
+ noise_level = random.randint(noise_level1, noise_level2)
+ rnum = np.random.rand()
+ if rnum > 0.6: # add color Gaussian noise
+ img = img + np.random.normal(0, noise_level / 255.0, img.shape).astype(np.float32)
+ elif rnum < 0.4: # add grayscale Gaussian noise
+ img = img + np.random.normal(0, noise_level / 255.0, (*img.shape[:2], 1)).astype(np.float32)
+ else: # add noise
+ L = noise_level2 / 255.
+ D = np.diag(np.random.rand(3))
+ U = orth(np.random.rand(3, 3))
+ conv = np.dot(np.dot(np.transpose(U), D), U)
+ img = img + np.random.multivariate_normal([0, 0, 0], np.abs(L ** 2 * conv), img.shape[:2]).astype(np.float32)
+ img = np.clip(img, 0.0, 1.0)
+ return img
+
+
+def add_speckle_noise(img, noise_level1=2, noise_level2=25):
+ noise_level = random.randint(noise_level1, noise_level2)
+ img = np.clip(img, 0.0, 1.0)
+ rnum = random.random()
+ if rnum > 0.6:
+ img += img * np.random.normal(0, noise_level / 255.0, img.shape).astype(np.float32)
+ elif rnum < 0.4:
+ img += img * np.random.normal(0, noise_level / 255.0, (*img.shape[:2], 1)).astype(np.float32)
+ else:
+ L = noise_level2 / 255.
+ D = np.diag(np.random.rand(3))
+ U = orth(np.random.rand(3, 3))
+ conv = np.dot(np.dot(np.transpose(U), D), U)
+ img += img * np.random.multivariate_normal([0, 0, 0], np.abs(L ** 2 * conv), img.shape[:2]).astype(np.float32)
+ img = np.clip(img, 0.0, 1.0)
+ return img
+
+
+def add_Poisson_noise(img):
+ img = np.clip((img * 255.0).round(), 0, 255) / 255.
+ vals = 10 ** (2 * random.random() + 2.0) # [2, 4]
+ if random.random() < 0.5:
+ img = np.random.poisson(img * vals).astype(np.float32) / vals
+ else:
+ img_gray = np.dot(img[..., :3], [0.299, 0.587, 0.114])
+ img_gray = np.clip((img_gray * 255.0).round(), 0, 255) / 255.
+ noise_gray = np.random.poisson(img_gray * vals).astype(np.float32) / vals - img_gray
+ img += noise_gray[:, :, np.newaxis]
+ img = np.clip(img, 0.0, 1.0)
+ return img
+
+
+def add_JPEG_noise(img):
+ quality_factor = random.randint(30, 95)
+ img = cv2.cvtColor(util.single2uint(img), cv2.COLOR_RGB2BGR)
+ result, encimg = cv2.imencode('.jpg', img, [int(cv2.IMWRITE_JPEG_QUALITY), quality_factor])
+ img = cv2.imdecode(encimg, 1)
+ img = cv2.cvtColor(util.uint2single(img), cv2.COLOR_BGR2RGB)
+ return img
+
+
+def random_crop(lq, hq, sf=4, lq_patchsize=64):
+ h, w = lq.shape[:2]
+ rnd_h = random.randint(0, h - lq_patchsize)
+ rnd_w = random.randint(0, w - lq_patchsize)
+ lq = lq[rnd_h:rnd_h + lq_patchsize, rnd_w:rnd_w + lq_patchsize, :]
+
+ rnd_h_H, rnd_w_H = int(rnd_h * sf), int(rnd_w * sf)
+ hq = hq[rnd_h_H:rnd_h_H + lq_patchsize * sf, rnd_w_H:rnd_w_H + lq_patchsize * sf, :]
+ return lq, hq
+
+
+def degradation_bsrgan(img, sf=4, lq_patchsize=72, isp_model=None):
+ """
+ This is the degradation model of BSRGAN from the paper
+ "Designing a Practical Degradation Model for Deep Blind Image Super-Resolution"
+ ----------
+ img: HXWXC, [0, 1], its size should be large than (lq_patchsizexsf)x(lq_patchsizexsf)
+ sf: scale factor
+ isp_model: camera ISP model
+ Returns
+ -------
+ img: low-quality patch, size: lq_patchsizeXlq_patchsizeXC, range: [0, 1]
+ hq: corresponding high-quality patch, size: (lq_patchsizexsf)X(lq_patchsizexsf)XC, range: [0, 1]
+ """
+ isp_prob, jpeg_prob, scale2_prob = 0.25, 0.9, 0.25
+ sf_ori = sf
+
+ h1, w1 = img.shape[:2]
+ img = img.copy()[:w1 - w1 % sf, :h1 - h1 % sf, ...] # mod crop
+ h, w = img.shape[:2]
+
+ if h < lq_patchsize * sf or w < lq_patchsize * sf:
+ raise ValueError(f'img size ({h1}X{w1}) is too small!')
+
+ hq = img.copy()
+
+ if sf == 4 and random.random() < scale2_prob: # downsample1
+ if np.random.rand() < 0.5:
+ img = cv2.resize(img, (int(1 / 2 * img.shape[1]), int(1 / 2 * img.shape[0])),
+ interpolation=random.choice([1, 2, 3]))
+ else:
+ img = util.imresize_np(img, 1 / 2, True)
+ img = np.clip(img, 0.0, 1.0)
+ sf = 2
+
+ shuffle_order = random.sample(range(7), 7)
+ idx1, idx2 = shuffle_order.index(2), shuffle_order.index(3)
+ if idx1 > idx2: # keep downsample3 last
+ shuffle_order[idx1], shuffle_order[idx2] = shuffle_order[idx2], shuffle_order[idx1]
+
+ for i in shuffle_order:
+
+ if i == 0:
+ img = add_blur(img, sf=sf)
+
+ elif i == 1:
+ img = add_blur(img, sf=sf)
+
+ elif i == 2:
+ a, b = img.shape[1], img.shape[0]
+ # downsample2
+ if random.random() < 0.75:
+ sf1 = random.uniform(1, 2 * sf)
+ img = cv2.resize(img, (int(1 / sf1 * img.shape[1]), int(1 / sf1 * img.shape[0])),
+ interpolation=random.choice([1, 2, 3]))
+ else:
+ k = fspecial('gaussian', 25, random.uniform(0.1, 0.6 * sf))
+ k_shifted = shift_pixel(k, sf)
+ k_shifted = k_shifted / k_shifted.sum() # blur with shifted kernel
+ img = ndimage.filters.convolve(img, np.expand_dims(k_shifted, axis=2), mode='mirror')
+ img = img[0::sf, 0::sf, ...] # nearest downsampling
+ img = np.clip(img, 0.0, 1.0)
+
+ elif i == 3:
+ # downsample3
+ img = cv2.resize(img, (int(1 / sf * a), int(1 / sf * b)), interpolation=random.choice([1, 2, 3]))
+ img = np.clip(img, 0.0, 1.0)
+
+ elif i == 4:
+ # add Gaussian noise
+ img = add_Gaussian_noise(img, noise_level1=2, noise_level2=25)
+
+ elif i == 5:
+ # add JPEG noise
+ if random.random() < jpeg_prob:
+ img = add_JPEG_noise(img)
+
+ elif i == 6:
+ # add processed camera sensor noise
+ if random.random() < isp_prob and isp_model is not None:
+ with torch.no_grad():
+ img, hq = isp_model.forward(img.copy(), hq)
+
+ # add final JPEG compression noise
+ img = add_JPEG_noise(img)
+
+ # random crop
+ img, hq = random_crop(img, hq, sf_ori, lq_patchsize)
+
+ return img, hq
+
+
+# todo no isp_model?
+def degradation_bsrgan_variant(image, sf=4, isp_model=None):
+ """
+ This is the degradation model of BSRGAN from the paper
+ "Designing a Practical Degradation Model for Deep Blind Image Super-Resolution"
+ ----------
+ sf: scale factor
+ isp_model: camera ISP model
+ Returns
+ -------
+ img: low-quality patch, size: lq_patchsizeXlq_patchsizeXC, range: [0, 1]
+ hq: corresponding high-quality patch, size: (lq_patchsizexsf)X(lq_patchsizexsf)XC, range: [0, 1]
+ """
+ image = util.uint2single(image)
+ isp_prob, jpeg_prob, scale2_prob = 0.25, 0.9, 0.25
+ sf_ori = sf
+
+ h1, w1 = image.shape[:2]
+ image = image.copy()[:w1 - w1 % sf, :h1 - h1 % sf, ...] # mod crop
+ h, w = image.shape[:2]
+
+ hq = image.copy()
+
+ if sf == 4 and random.random() < scale2_prob: # downsample1
+ if np.random.rand() < 0.5:
+ image = cv2.resize(image, (int(1 / 2 * image.shape[1]), int(1 / 2 * image.shape[0])),
+ interpolation=random.choice([1, 2, 3]))
+ else:
+ image = util.imresize_np(image, 1 / 2, True)
+ image = np.clip(image, 0.0, 1.0)
+ sf = 2
+
+ shuffle_order = random.sample(range(7), 7)
+ idx1, idx2 = shuffle_order.index(2), shuffle_order.index(3)
+ if idx1 > idx2: # keep downsample3 last
+ shuffle_order[idx1], shuffle_order[idx2] = shuffle_order[idx2], shuffle_order[idx1]
+
+ for i in shuffle_order:
+
+ if i == 0:
+ image = add_blur(image, sf=sf)
+
+ elif i == 1:
+ image = add_blur(image, sf=sf)
+
+ elif i == 2:
+ a, b = image.shape[1], image.shape[0]
+ # downsample2
+ if random.random() < 0.75:
+ sf1 = random.uniform(1, 2 * sf)
+ image = cv2.resize(image, (int(1 / sf1 * image.shape[1]), int(1 / sf1 * image.shape[0])),
+ interpolation=random.choice([1, 2, 3]))
+ else:
+ k = fspecial('gaussian', 25, random.uniform(0.1, 0.6 * sf))
+ k_shifted = shift_pixel(k, sf)
+ k_shifted = k_shifted / k_shifted.sum() # blur with shifted kernel
+ image = ndimage.filters.convolve(image, np.expand_dims(k_shifted, axis=2), mode='mirror')
+ image = image[0::sf, 0::sf, ...] # nearest downsampling
+ image = np.clip(image, 0.0, 1.0)
+
+ elif i == 3:
+ # downsample3
+ image = cv2.resize(image, (int(1 / sf * a), int(1 / sf * b)), interpolation=random.choice([1, 2, 3]))
+ image = np.clip(image, 0.0, 1.0)
+
+ elif i == 4:
+ # add Gaussian noise
+ image = add_Gaussian_noise(image, noise_level1=2, noise_level2=25)
+
+ elif i == 5:
+ # add JPEG noise
+ if random.random() < jpeg_prob:
+ image = add_JPEG_noise(image)
+
+ # elif i == 6:
+ # # add processed camera sensor noise
+ # if random.random() < isp_prob and isp_model is not None:
+ # with torch.no_grad():
+ # img, hq = isp_model.forward(img.copy(), hq)
+
+ # add final JPEG compression noise
+ image = add_JPEG_noise(image)
+ image = util.single2uint(image)
+ example = {"image":image}
+ return example
+
+
+# TODO incase there is a pickle error one needs to replace a += x with a = a + x in add_speckle_noise etc...
+def degradation_bsrgan_plus(img, sf=4, shuffle_prob=0.5, use_sharp=True, lq_patchsize=64, isp_model=None):
+ """
+ This is an extended degradation model by combining
+ the degradation models of BSRGAN and Real-ESRGAN
+ ----------
+ img: HXWXC, [0, 1], its size should be large than (lq_patchsizexsf)x(lq_patchsizexsf)
+ sf: scale factor
+ use_shuffle: the degradation shuffle
+ use_sharp: sharpening the img
+ Returns
+ -------
+ img: low-quality patch, size: lq_patchsizeXlq_patchsizeXC, range: [0, 1]
+ hq: corresponding high-quality patch, size: (lq_patchsizexsf)X(lq_patchsizexsf)XC, range: [0, 1]
+ """
+
+ h1, w1 = img.shape[:2]
+ img = img.copy()[:w1 - w1 % sf, :h1 - h1 % sf, ...] # mod crop
+ h, w = img.shape[:2]
+
+ if h < lq_patchsize * sf or w < lq_patchsize * sf:
+ raise ValueError(f'img size ({h1}X{w1}) is too small!')
+
+ if use_sharp:
+ img = add_sharpening(img)
+ hq = img.copy()
+
+ if random.random() < shuffle_prob:
+ shuffle_order = random.sample(range(13), 13)
+ else:
+ shuffle_order = list(range(13))
+ # local shuffle for noise, JPEG is always the last one
+ shuffle_order[2:6] = random.sample(shuffle_order[2:6], len(range(2, 6)))
+ shuffle_order[9:13] = random.sample(shuffle_order[9:13], len(range(9, 13)))
+
+ poisson_prob, speckle_prob, isp_prob = 0.1, 0.1, 0.1
+
+ for i in shuffle_order:
+ if i == 0:
+ img = add_blur(img, sf=sf)
+ elif i == 1:
+ img = add_resize(img, sf=sf)
+ elif i == 2:
+ img = add_Gaussian_noise(img, noise_level1=2, noise_level2=25)
+ elif i == 3:
+ if random.random() < poisson_prob:
+ img = add_Poisson_noise(img)
+ elif i == 4:
+ if random.random() < speckle_prob:
+ img = add_speckle_noise(img)
+ elif i == 5:
+ if random.random() < isp_prob and isp_model is not None:
+ with torch.no_grad():
+ img, hq = isp_model.forward(img.copy(), hq)
+ elif i == 6:
+ img = add_JPEG_noise(img)
+ elif i == 7:
+ img = add_blur(img, sf=sf)
+ elif i == 8:
+ img = add_resize(img, sf=sf)
+ elif i == 9:
+ img = add_Gaussian_noise(img, noise_level1=2, noise_level2=25)
+ elif i == 10:
+ if random.random() < poisson_prob:
+ img = add_Poisson_noise(img)
+ elif i == 11:
+ if random.random() < speckle_prob:
+ img = add_speckle_noise(img)
+ elif i == 12:
+ if random.random() < isp_prob and isp_model is not None:
+ with torch.no_grad():
+ img, hq = isp_model.forward(img.copy(), hq)
+ else:
+ print('check the shuffle!')
+
+ # resize to desired size
+ img = cv2.resize(img, (int(1 / sf * hq.shape[1]), int(1 / sf * hq.shape[0])),
+ interpolation=random.choice([1, 2, 3]))
+
+ # add final JPEG compression noise
+ img = add_JPEG_noise(img)
+
+ # random crop
+ img, hq = random_crop(img, hq, sf, lq_patchsize)
+
+ return img, hq
+
+
+if __name__ == '__main__':
+ print("hey")
+ img = util.imread_uint('utils/test.png', 3)
+ print(img)
+ img = util.uint2single(img)
+ print(img)
+ img = img[:448, :448]
+ h = img.shape[0] // 4
+ print("resizing to", h)
+ sf = 4
+ deg_fn = partial(degradation_bsrgan_variant, sf=sf)
+ for i in range(20):
+ print(i)
+ img_lq = deg_fn(img)
+ print(img_lq)
+ img_lq_bicubic = albumentations.SmallestMaxSize(max_size=h, interpolation=cv2.INTER_CUBIC)(image=img)["image"]
+ print(img_lq.shape)
+ print("bicubic", img_lq_bicubic.shape)
+ print(img_hq.shape)
+ lq_nearest = cv2.resize(util.single2uint(img_lq), (int(sf * img_lq.shape[1]), int(sf * img_lq.shape[0])),
+ interpolation=0)
+ lq_bicubic_nearest = cv2.resize(util.single2uint(img_lq_bicubic), (int(sf * img_lq.shape[1]), int(sf * img_lq.shape[0])),
+ interpolation=0)
+ img_concat = np.concatenate([lq_bicubic_nearest, lq_nearest, util.single2uint(img_hq)], axis=1)
+ util.imsave(img_concat, str(i) + '.png')
+
+
diff --git a/latent-diffusion/ldm/modules/image_degradation/bsrgan_light.py b/latent-diffusion/ldm/modules/image_degradation/bsrgan_light.py
new file mode 100644
index 0000000000000000000000000000000000000000..9e1f823996bf559e9b015ea9aa2b3cd38dd13af1
--- /dev/null
+++ b/latent-diffusion/ldm/modules/image_degradation/bsrgan_light.py
@@ -0,0 +1,650 @@
+# -*- coding: utf-8 -*-
+import numpy as np
+import cv2
+import torch
+
+from functools import partial
+import random
+from scipy import ndimage
+import scipy
+import scipy.stats as ss
+from scipy.interpolate import interp2d
+from scipy.linalg import orth
+import albumentations
+
+import ldm.modules.image_degradation.utils_image as util
+
+"""
+# --------------------------------------------
+# Super-Resolution
+# --------------------------------------------
+#
+# Kai Zhang (cskaizhang@gmail.com)
+# https://github.com/cszn
+# From 2019/03--2021/08
+# --------------------------------------------
+"""
+
+
+def modcrop_np(img, sf):
+ '''
+ Args:
+ img: numpy image, WxH or WxHxC
+ sf: scale factor
+ Return:
+ cropped image
+ '''
+ w, h = img.shape[:2]
+ im = np.copy(img)
+ return im[:w - w % sf, :h - h % sf, ...]
+
+
+"""
+# --------------------------------------------
+# anisotropic Gaussian kernels
+# --------------------------------------------
+"""
+
+
+def analytic_kernel(k):
+ """Calculate the X4 kernel from the X2 kernel (for proof see appendix in paper)"""
+ k_size = k.shape[0]
+ # Calculate the big kernels size
+ big_k = np.zeros((3 * k_size - 2, 3 * k_size - 2))
+ # Loop over the small kernel to fill the big one
+ for r in range(k_size):
+ for c in range(k_size):
+ big_k[2 * r:2 * r + k_size, 2 * c:2 * c + k_size] += k[r, c] * k
+ # Crop the edges of the big kernel to ignore very small values and increase run time of SR
+ crop = k_size // 2
+ cropped_big_k = big_k[crop:-crop, crop:-crop]
+ # Normalize to 1
+ return cropped_big_k / cropped_big_k.sum()
+
+
+def anisotropic_Gaussian(ksize=15, theta=np.pi, l1=6, l2=6):
+ """ generate an anisotropic Gaussian kernel
+ Args:
+ ksize : e.g., 15, kernel size
+ theta : [0, pi], rotation angle range
+ l1 : [0.1,50], scaling of eigenvalues
+ l2 : [0.1,l1], scaling of eigenvalues
+ If l1 = l2, will get an isotropic Gaussian kernel.
+ Returns:
+ k : kernel
+ """
+
+ v = np.dot(np.array([[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]]), np.array([1., 0.]))
+ V = np.array([[v[0], v[1]], [v[1], -v[0]]])
+ D = np.array([[l1, 0], [0, l2]])
+ Sigma = np.dot(np.dot(V, D), np.linalg.inv(V))
+ k = gm_blur_kernel(mean=[0, 0], cov=Sigma, size=ksize)
+
+ return k
+
+
+def gm_blur_kernel(mean, cov, size=15):
+ center = size / 2.0 + 0.5
+ k = np.zeros([size, size])
+ for y in range(size):
+ for x in range(size):
+ cy = y - center + 1
+ cx = x - center + 1
+ k[y, x] = ss.multivariate_normal.pdf([cx, cy], mean=mean, cov=cov)
+
+ k = k / np.sum(k)
+ return k
+
+
+def shift_pixel(x, sf, upper_left=True):
+ """shift pixel for super-resolution with different scale factors
+ Args:
+ x: WxHxC or WxH
+ sf: scale factor
+ upper_left: shift direction
+ """
+ h, w = x.shape[:2]
+ shift = (sf - 1) * 0.5
+ xv, yv = np.arange(0, w, 1.0), np.arange(0, h, 1.0)
+ if upper_left:
+ x1 = xv + shift
+ y1 = yv + shift
+ else:
+ x1 = xv - shift
+ y1 = yv - shift
+
+ x1 = np.clip(x1, 0, w - 1)
+ y1 = np.clip(y1, 0, h - 1)
+
+ if x.ndim == 2:
+ x = interp2d(xv, yv, x)(x1, y1)
+ if x.ndim == 3:
+ for i in range(x.shape[-1]):
+ x[:, :, i] = interp2d(xv, yv, x[:, :, i])(x1, y1)
+
+ return x
+
+
+def blur(x, k):
+ '''
+ x: image, NxcxHxW
+ k: kernel, Nx1xhxw
+ '''
+ n, c = x.shape[:2]
+ p1, p2 = (k.shape[-2] - 1) // 2, (k.shape[-1] - 1) // 2
+ x = torch.nn.functional.pad(x, pad=(p1, p2, p1, p2), mode='replicate')
+ k = k.repeat(1, c, 1, 1)
+ k = k.view(-1, 1, k.shape[2], k.shape[3])
+ x = x.view(1, -1, x.shape[2], x.shape[3])
+ x = torch.nn.functional.conv2d(x, k, bias=None, stride=1, padding=0, groups=n * c)
+ x = x.view(n, c, x.shape[2], x.shape[3])
+
+ return x
+
+
+def gen_kernel(k_size=np.array([15, 15]), scale_factor=np.array([4, 4]), min_var=0.6, max_var=10., noise_level=0):
+ """"
+ # modified version of https://github.com/assafshocher/BlindSR_dataset_generator
+ # Kai Zhang
+ # min_var = 0.175 * sf # variance of the gaussian kernel will be sampled between min_var and max_var
+ # max_var = 2.5 * sf
+ """
+ # Set random eigen-vals (lambdas) and angle (theta) for COV matrix
+ lambda_1 = min_var + np.random.rand() * (max_var - min_var)
+ lambda_2 = min_var + np.random.rand() * (max_var - min_var)
+ theta = np.random.rand() * np.pi # random theta
+ noise = -noise_level + np.random.rand(*k_size) * noise_level * 2
+
+ # Set COV matrix using Lambdas and Theta
+ LAMBDA = np.diag([lambda_1, lambda_2])
+ Q = np.array([[np.cos(theta), -np.sin(theta)],
+ [np.sin(theta), np.cos(theta)]])
+ SIGMA = Q @ LAMBDA @ Q.T
+ INV_SIGMA = np.linalg.inv(SIGMA)[None, None, :, :]
+
+ # Set expectation position (shifting kernel for aligned image)
+ MU = k_size // 2 - 0.5 * (scale_factor - 1) # - 0.5 * (scale_factor - k_size % 2)
+ MU = MU[None, None, :, None]
+
+ # Create meshgrid for Gaussian
+ [X, Y] = np.meshgrid(range(k_size[0]), range(k_size[1]))
+ Z = np.stack([X, Y], 2)[:, :, :, None]
+
+ # Calcualte Gaussian for every pixel of the kernel
+ ZZ = Z - MU
+ ZZ_t = ZZ.transpose(0, 1, 3, 2)
+ raw_kernel = np.exp(-0.5 * np.squeeze(ZZ_t @ INV_SIGMA @ ZZ)) * (1 + noise)
+
+ # shift the kernel so it will be centered
+ # raw_kernel_centered = kernel_shift(raw_kernel, scale_factor)
+
+ # Normalize the kernel and return
+ # kernel = raw_kernel_centered / np.sum(raw_kernel_centered)
+ kernel = raw_kernel / np.sum(raw_kernel)
+ return kernel
+
+
+def fspecial_gaussian(hsize, sigma):
+ hsize = [hsize, hsize]
+ siz = [(hsize[0] - 1.0) / 2.0, (hsize[1] - 1.0) / 2.0]
+ std = sigma
+ [x, y] = np.meshgrid(np.arange(-siz[1], siz[1] + 1), np.arange(-siz[0], siz[0] + 1))
+ arg = -(x * x + y * y) / (2 * std * std)
+ h = np.exp(arg)
+ h[h < scipy.finfo(float).eps * h.max()] = 0
+ sumh = h.sum()
+ if sumh != 0:
+ h = h / sumh
+ return h
+
+
+def fspecial_laplacian(alpha):
+ alpha = max([0, min([alpha, 1])])
+ h1 = alpha / (alpha + 1)
+ h2 = (1 - alpha) / (alpha + 1)
+ h = [[h1, h2, h1], [h2, -4 / (alpha + 1), h2], [h1, h2, h1]]
+ h = np.array(h)
+ return h
+
+
+def fspecial(filter_type, *args, **kwargs):
+ '''
+ python code from:
+ https://github.com/ronaldosena/imagens-medicas-2/blob/40171a6c259edec7827a6693a93955de2bd39e76/Aulas/aula_2_-_uniform_filter/matlab_fspecial.py
+ '''
+ if filter_type == 'gaussian':
+ return fspecial_gaussian(*args, **kwargs)
+ if filter_type == 'laplacian':
+ return fspecial_laplacian(*args, **kwargs)
+
+
+"""
+# --------------------------------------------
+# degradation models
+# --------------------------------------------
+"""
+
+
+def bicubic_degradation(x, sf=3):
+ '''
+ Args:
+ x: HxWxC image, [0, 1]
+ sf: down-scale factor
+ Return:
+ bicubicly downsampled LR image
+ '''
+ x = util.imresize_np(x, scale=1 / sf)
+ return x
+
+
+def srmd_degradation(x, k, sf=3):
+ ''' blur + bicubic downsampling
+ Args:
+ x: HxWxC image, [0, 1]
+ k: hxw, double
+ sf: down-scale factor
+ Return:
+ downsampled LR image
+ Reference:
+ @inproceedings{zhang2018learning,
+ title={Learning a single convolutional super-resolution network for multiple degradations},
+ author={Zhang, Kai and Zuo, Wangmeng and Zhang, Lei},
+ booktitle={IEEE Conference on Computer Vision and Pattern Recognition},
+ pages={3262--3271},
+ year={2018}
+ }
+ '''
+ x = ndimage.filters.convolve(x, np.expand_dims(k, axis=2), mode='wrap') # 'nearest' | 'mirror'
+ x = bicubic_degradation(x, sf=sf)
+ return x
+
+
+def dpsr_degradation(x, k, sf=3):
+ ''' bicubic downsampling + blur
+ Args:
+ x: HxWxC image, [0, 1]
+ k: hxw, double
+ sf: down-scale factor
+ Return:
+ downsampled LR image
+ Reference:
+ @inproceedings{zhang2019deep,
+ title={Deep Plug-and-Play Super-Resolution for Arbitrary Blur Kernels},
+ author={Zhang, Kai and Zuo, Wangmeng and Zhang, Lei},
+ booktitle={IEEE Conference on Computer Vision and Pattern Recognition},
+ pages={1671--1681},
+ year={2019}
+ }
+ '''
+ x = bicubic_degradation(x, sf=sf)
+ x = ndimage.filters.convolve(x, np.expand_dims(k, axis=2), mode='wrap')
+ return x
+
+
+def classical_degradation(x, k, sf=3):
+ ''' blur + downsampling
+ Args:
+ x: HxWxC image, [0, 1]/[0, 255]
+ k: hxw, double
+ sf: down-scale factor
+ Return:
+ downsampled LR image
+ '''
+ x = ndimage.filters.convolve(x, np.expand_dims(k, axis=2), mode='wrap')
+ # x = filters.correlate(x, np.expand_dims(np.flip(k), axis=2))
+ st = 0
+ return x[st::sf, st::sf, ...]
+
+
+def add_sharpening(img, weight=0.5, radius=50, threshold=10):
+ """USM sharpening. borrowed from real-ESRGAN
+ Input image: I; Blurry image: B.
+ 1. K = I + weight * (I - B)
+ 2. Mask = 1 if abs(I - B) > threshold, else: 0
+ 3. Blur mask:
+ 4. Out = Mask * K + (1 - Mask) * I
+ Args:
+ img (Numpy array): Input image, HWC, BGR; float32, [0, 1].
+ weight (float): Sharp weight. Default: 1.
+ radius (float): Kernel size of Gaussian blur. Default: 50.
+ threshold (int):
+ """
+ if radius % 2 == 0:
+ radius += 1
+ blur = cv2.GaussianBlur(img, (radius, radius), 0)
+ residual = img - blur
+ mask = np.abs(residual) * 255 > threshold
+ mask = mask.astype('float32')
+ soft_mask = cv2.GaussianBlur(mask, (radius, radius), 0)
+
+ K = img + weight * residual
+ K = np.clip(K, 0, 1)
+ return soft_mask * K + (1 - soft_mask) * img
+
+
+def add_blur(img, sf=4):
+ wd2 = 4.0 + sf
+ wd = 2.0 + 0.2 * sf
+
+ wd2 = wd2/4
+ wd = wd/4
+
+ if random.random() < 0.5:
+ l1 = wd2 * random.random()
+ l2 = wd2 * random.random()
+ k = anisotropic_Gaussian(ksize=random.randint(2, 11) + 3, theta=random.random() * np.pi, l1=l1, l2=l2)
+ else:
+ k = fspecial('gaussian', random.randint(2, 4) + 3, wd * random.random())
+ img = ndimage.filters.convolve(img, np.expand_dims(k, axis=2), mode='mirror')
+
+ return img
+
+
+def add_resize(img, sf=4):
+ rnum = np.random.rand()
+ if rnum > 0.8: # up
+ sf1 = random.uniform(1, 2)
+ elif rnum < 0.7: # down
+ sf1 = random.uniform(0.5 / sf, 1)
+ else:
+ sf1 = 1.0
+ img = cv2.resize(img, (int(sf1 * img.shape[1]), int(sf1 * img.shape[0])), interpolation=random.choice([1, 2, 3]))
+ img = np.clip(img, 0.0, 1.0)
+
+ return img
+
+
+# def add_Gaussian_noise(img, noise_level1=2, noise_level2=25):
+# noise_level = random.randint(noise_level1, noise_level2)
+# rnum = np.random.rand()
+# if rnum > 0.6: # add color Gaussian noise
+# img += np.random.normal(0, noise_level / 255.0, img.shape).astype(np.float32)
+# elif rnum < 0.4: # add grayscale Gaussian noise
+# img += np.random.normal(0, noise_level / 255.0, (*img.shape[:2], 1)).astype(np.float32)
+# else: # add noise
+# L = noise_level2 / 255.
+# D = np.diag(np.random.rand(3))
+# U = orth(np.random.rand(3, 3))
+# conv = np.dot(np.dot(np.transpose(U), D), U)
+# img += np.random.multivariate_normal([0, 0, 0], np.abs(L ** 2 * conv), img.shape[:2]).astype(np.float32)
+# img = np.clip(img, 0.0, 1.0)
+# return img
+
+def add_Gaussian_noise(img, noise_level1=2, noise_level2=25):
+ noise_level = random.randint(noise_level1, noise_level2)
+ rnum = np.random.rand()
+ if rnum > 0.6: # add color Gaussian noise
+ img = img + np.random.normal(0, noise_level / 255.0, img.shape).astype(np.float32)
+ elif rnum < 0.4: # add grayscale Gaussian noise
+ img = img + np.random.normal(0, noise_level / 255.0, (*img.shape[:2], 1)).astype(np.float32)
+ else: # add noise
+ L = noise_level2 / 255.
+ D = np.diag(np.random.rand(3))
+ U = orth(np.random.rand(3, 3))
+ conv = np.dot(np.dot(np.transpose(U), D), U)
+ img = img + np.random.multivariate_normal([0, 0, 0], np.abs(L ** 2 * conv), img.shape[:2]).astype(np.float32)
+ img = np.clip(img, 0.0, 1.0)
+ return img
+
+
+def add_speckle_noise(img, noise_level1=2, noise_level2=25):
+ noise_level = random.randint(noise_level1, noise_level2)
+ img = np.clip(img, 0.0, 1.0)
+ rnum = random.random()
+ if rnum > 0.6:
+ img += img * np.random.normal(0, noise_level / 255.0, img.shape).astype(np.float32)
+ elif rnum < 0.4:
+ img += img * np.random.normal(0, noise_level / 255.0, (*img.shape[:2], 1)).astype(np.float32)
+ else:
+ L = noise_level2 / 255.
+ D = np.diag(np.random.rand(3))
+ U = orth(np.random.rand(3, 3))
+ conv = np.dot(np.dot(np.transpose(U), D), U)
+ img += img * np.random.multivariate_normal([0, 0, 0], np.abs(L ** 2 * conv), img.shape[:2]).astype(np.float32)
+ img = np.clip(img, 0.0, 1.0)
+ return img
+
+
+def add_Poisson_noise(img):
+ img = np.clip((img * 255.0).round(), 0, 255) / 255.
+ vals = 10 ** (2 * random.random() + 2.0) # [2, 4]
+ if random.random() < 0.5:
+ img = np.random.poisson(img * vals).astype(np.float32) / vals
+ else:
+ img_gray = np.dot(img[..., :3], [0.299, 0.587, 0.114])
+ img_gray = np.clip((img_gray * 255.0).round(), 0, 255) / 255.
+ noise_gray = np.random.poisson(img_gray * vals).astype(np.float32) / vals - img_gray
+ img += noise_gray[:, :, np.newaxis]
+ img = np.clip(img, 0.0, 1.0)
+ return img
+
+
+def add_JPEG_noise(img):
+ quality_factor = random.randint(80, 95)
+ img = cv2.cvtColor(util.single2uint(img), cv2.COLOR_RGB2BGR)
+ result, encimg = cv2.imencode('.jpg', img, [int(cv2.IMWRITE_JPEG_QUALITY), quality_factor])
+ img = cv2.imdecode(encimg, 1)
+ img = cv2.cvtColor(util.uint2single(img), cv2.COLOR_BGR2RGB)
+ return img
+
+
+def random_crop(lq, hq, sf=4, lq_patchsize=64):
+ h, w = lq.shape[:2]
+ rnd_h = random.randint(0, h - lq_patchsize)
+ rnd_w = random.randint(0, w - lq_patchsize)
+ lq = lq[rnd_h:rnd_h + lq_patchsize, rnd_w:rnd_w + lq_patchsize, :]
+
+ rnd_h_H, rnd_w_H = int(rnd_h * sf), int(rnd_w * sf)
+ hq = hq[rnd_h_H:rnd_h_H + lq_patchsize * sf, rnd_w_H:rnd_w_H + lq_patchsize * sf, :]
+ return lq, hq
+
+
+def degradation_bsrgan(img, sf=4, lq_patchsize=72, isp_model=None):
+ """
+ This is the degradation model of BSRGAN from the paper
+ "Designing a Practical Degradation Model for Deep Blind Image Super-Resolution"
+ ----------
+ img: HXWXC, [0, 1], its size should be large than (lq_patchsizexsf)x(lq_patchsizexsf)
+ sf: scale factor
+ isp_model: camera ISP model
+ Returns
+ -------
+ img: low-quality patch, size: lq_patchsizeXlq_patchsizeXC, range: [0, 1]
+ hq: corresponding high-quality patch, size: (lq_patchsizexsf)X(lq_patchsizexsf)XC, range: [0, 1]
+ """
+ isp_prob, jpeg_prob, scale2_prob = 0.25, 0.9, 0.25
+ sf_ori = sf
+
+ h1, w1 = img.shape[:2]
+ img = img.copy()[:w1 - w1 % sf, :h1 - h1 % sf, ...] # mod crop
+ h, w = img.shape[:2]
+
+ if h < lq_patchsize * sf or w < lq_patchsize * sf:
+ raise ValueError(f'img size ({h1}X{w1}) is too small!')
+
+ hq = img.copy()
+
+ if sf == 4 and random.random() < scale2_prob: # downsample1
+ if np.random.rand() < 0.5:
+ img = cv2.resize(img, (int(1 / 2 * img.shape[1]), int(1 / 2 * img.shape[0])),
+ interpolation=random.choice([1, 2, 3]))
+ else:
+ img = util.imresize_np(img, 1 / 2, True)
+ img = np.clip(img, 0.0, 1.0)
+ sf = 2
+
+ shuffle_order = random.sample(range(7), 7)
+ idx1, idx2 = shuffle_order.index(2), shuffle_order.index(3)
+ if idx1 > idx2: # keep downsample3 last
+ shuffle_order[idx1], shuffle_order[idx2] = shuffle_order[idx2], shuffle_order[idx1]
+
+ for i in shuffle_order:
+
+ if i == 0:
+ img = add_blur(img, sf=sf)
+
+ elif i == 1:
+ img = add_blur(img, sf=sf)
+
+ elif i == 2:
+ a, b = img.shape[1], img.shape[0]
+ # downsample2
+ if random.random() < 0.75:
+ sf1 = random.uniform(1, 2 * sf)
+ img = cv2.resize(img, (int(1 / sf1 * img.shape[1]), int(1 / sf1 * img.shape[0])),
+ interpolation=random.choice([1, 2, 3]))
+ else:
+ k = fspecial('gaussian', 25, random.uniform(0.1, 0.6 * sf))
+ k_shifted = shift_pixel(k, sf)
+ k_shifted = k_shifted / k_shifted.sum() # blur with shifted kernel
+ img = ndimage.filters.convolve(img, np.expand_dims(k_shifted, axis=2), mode='mirror')
+ img = img[0::sf, 0::sf, ...] # nearest downsampling
+ img = np.clip(img, 0.0, 1.0)
+
+ elif i == 3:
+ # downsample3
+ img = cv2.resize(img, (int(1 / sf * a), int(1 / sf * b)), interpolation=random.choice([1, 2, 3]))
+ img = np.clip(img, 0.0, 1.0)
+
+ elif i == 4:
+ # add Gaussian noise
+ img = add_Gaussian_noise(img, noise_level1=2, noise_level2=8)
+
+ elif i == 5:
+ # add JPEG noise
+ if random.random() < jpeg_prob:
+ img = add_JPEG_noise(img)
+
+ elif i == 6:
+ # add processed camera sensor noise
+ if random.random() < isp_prob and isp_model is not None:
+ with torch.no_grad():
+ img, hq = isp_model.forward(img.copy(), hq)
+
+ # add final JPEG compression noise
+ img = add_JPEG_noise(img)
+
+ # random crop
+ img, hq = random_crop(img, hq, sf_ori, lq_patchsize)
+
+ return img, hq
+
+
+# todo no isp_model?
+def degradation_bsrgan_variant(image, sf=4, isp_model=None):
+ """
+ This is the degradation model of BSRGAN from the paper
+ "Designing a Practical Degradation Model for Deep Blind Image Super-Resolution"
+ ----------
+ sf: scale factor
+ isp_model: camera ISP model
+ Returns
+ -------
+ img: low-quality patch, size: lq_patchsizeXlq_patchsizeXC, range: [0, 1]
+ hq: corresponding high-quality patch, size: (lq_patchsizexsf)X(lq_patchsizexsf)XC, range: [0, 1]
+ """
+ image = util.uint2single(image)
+ isp_prob, jpeg_prob, scale2_prob = 0.25, 0.9, 0.25
+ sf_ori = sf
+
+ h1, w1 = image.shape[:2]
+ image = image.copy()[:w1 - w1 % sf, :h1 - h1 % sf, ...] # mod crop
+ h, w = image.shape[:2]
+
+ hq = image.copy()
+
+ if sf == 4 and random.random() < scale2_prob: # downsample1
+ if np.random.rand() < 0.5:
+ image = cv2.resize(image, (int(1 / 2 * image.shape[1]), int(1 / 2 * image.shape[0])),
+ interpolation=random.choice([1, 2, 3]))
+ else:
+ image = util.imresize_np(image, 1 / 2, True)
+ image = np.clip(image, 0.0, 1.0)
+ sf = 2
+
+ shuffle_order = random.sample(range(7), 7)
+ idx1, idx2 = shuffle_order.index(2), shuffle_order.index(3)
+ if idx1 > idx2: # keep downsample3 last
+ shuffle_order[idx1], shuffle_order[idx2] = shuffle_order[idx2], shuffle_order[idx1]
+
+ for i in shuffle_order:
+
+ if i == 0:
+ image = add_blur(image, sf=sf)
+
+ # elif i == 1:
+ # image = add_blur(image, sf=sf)
+
+ if i == 0:
+ pass
+
+ elif i == 2:
+ a, b = image.shape[1], image.shape[0]
+ # downsample2
+ if random.random() < 0.8:
+ sf1 = random.uniform(1, 2 * sf)
+ image = cv2.resize(image, (int(1 / sf1 * image.shape[1]), int(1 / sf1 * image.shape[0])),
+ interpolation=random.choice([1, 2, 3]))
+ else:
+ k = fspecial('gaussian', 25, random.uniform(0.1, 0.6 * sf))
+ k_shifted = shift_pixel(k, sf)
+ k_shifted = k_shifted / k_shifted.sum() # blur with shifted kernel
+ image = ndimage.filters.convolve(image, np.expand_dims(k_shifted, axis=2), mode='mirror')
+ image = image[0::sf, 0::sf, ...] # nearest downsampling
+
+ image = np.clip(image, 0.0, 1.0)
+
+ elif i == 3:
+ # downsample3
+ image = cv2.resize(image, (int(1 / sf * a), int(1 / sf * b)), interpolation=random.choice([1, 2, 3]))
+ image = np.clip(image, 0.0, 1.0)
+
+ elif i == 4:
+ # add Gaussian noise
+ image = add_Gaussian_noise(image, noise_level1=1, noise_level2=2)
+
+ elif i == 5:
+ # add JPEG noise
+ if random.random() < jpeg_prob:
+ image = add_JPEG_noise(image)
+ #
+ # elif i == 6:
+ # # add processed camera sensor noise
+ # if random.random() < isp_prob and isp_model is not None:
+ # with torch.no_grad():
+ # img, hq = isp_model.forward(img.copy(), hq)
+
+ # add final JPEG compression noise
+ image = add_JPEG_noise(image)
+ image = util.single2uint(image)
+ example = {"image": image}
+ return example
+
+
+
+
+if __name__ == '__main__':
+ print("hey")
+ img = util.imread_uint('utils/test.png', 3)
+ img = img[:448, :448]
+ h = img.shape[0] // 4
+ print("resizing to", h)
+ sf = 4
+ deg_fn = partial(degradation_bsrgan_variant, sf=sf)
+ for i in range(20):
+ print(i)
+ img_hq = img
+ img_lq = deg_fn(img)["image"]
+ img_hq, img_lq = util.uint2single(img_hq), util.uint2single(img_lq)
+ print(img_lq)
+ img_lq_bicubic = albumentations.SmallestMaxSize(max_size=h, interpolation=cv2.INTER_CUBIC)(image=img_hq)["image"]
+ print(img_lq.shape)
+ print("bicubic", img_lq_bicubic.shape)
+ print(img_hq.shape)
+ lq_nearest = cv2.resize(util.single2uint(img_lq), (int(sf * img_lq.shape[1]), int(sf * img_lq.shape[0])),
+ interpolation=0)
+ lq_bicubic_nearest = cv2.resize(util.single2uint(img_lq_bicubic),
+ (int(sf * img_lq.shape[1]), int(sf * img_lq.shape[0])),
+ interpolation=0)
+ img_concat = np.concatenate([lq_bicubic_nearest, lq_nearest, util.single2uint(img_hq)], axis=1)
+ util.imsave(img_concat, str(i) + '.png')
diff --git a/latent-diffusion/ldm/modules/image_degradation/utils/test.png b/latent-diffusion/ldm/modules/image_degradation/utils/test.png
new file mode 100644
index 0000000000000000000000000000000000000000..4249b43de0f22707758d13c240268a401642f6e6
Binary files /dev/null and b/latent-diffusion/ldm/modules/image_degradation/utils/test.png differ
diff --git a/latent-diffusion/ldm/modules/image_degradation/utils_image.py b/latent-diffusion/ldm/modules/image_degradation/utils_image.py
new file mode 100644
index 0000000000000000000000000000000000000000..0175f155ad900ae33c3c46ed87f49b352e3faf98
--- /dev/null
+++ b/latent-diffusion/ldm/modules/image_degradation/utils_image.py
@@ -0,0 +1,916 @@
+import os
+import math
+import random
+import numpy as np
+import torch
+import cv2
+from torchvision.utils import make_grid
+from datetime import datetime
+#import matplotlib.pyplot as plt # TODO: check with Dominik, also bsrgan.py vs bsrgan_light.py
+
+
+os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"
+
+
+'''
+# --------------------------------------------
+# Kai Zhang (github: https://github.com/cszn)
+# 03/Mar/2019
+# --------------------------------------------
+# https://github.com/twhui/SRGAN-pyTorch
+# https://github.com/xinntao/BasicSR
+# --------------------------------------------
+'''
+
+
+IMG_EXTENSIONS = ['.jpg', '.JPG', '.jpeg', '.JPEG', '.png', '.PNG', '.ppm', '.PPM', '.bmp', '.BMP', '.tif']
+
+
+def is_image_file(filename):
+ return any(filename.endswith(extension) for extension in IMG_EXTENSIONS)
+
+
+def get_timestamp():
+ return datetime.now().strftime('%y%m%d-%H%M%S')
+
+
+def imshow(x, title=None, cbar=False, figsize=None):
+ plt.figure(figsize=figsize)
+ plt.imshow(np.squeeze(x), interpolation='nearest', cmap='gray')
+ if title:
+ plt.title(title)
+ if cbar:
+ plt.colorbar()
+ plt.show()
+
+
+def surf(Z, cmap='rainbow', figsize=None):
+ plt.figure(figsize=figsize)
+ ax3 = plt.axes(projection='3d')
+
+ w, h = Z.shape[:2]
+ xx = np.arange(0,w,1)
+ yy = np.arange(0,h,1)
+ X, Y = np.meshgrid(xx, yy)
+ ax3.plot_surface(X,Y,Z,cmap=cmap)
+ #ax3.contour(X,Y,Z, zdim='z',offset=-2οΌcmap=cmap)
+ plt.show()
+
+
+'''
+# --------------------------------------------
+# get image pathes
+# --------------------------------------------
+'''
+
+
+def get_image_paths(dataroot):
+ paths = None # return None if dataroot is None
+ if dataroot is not None:
+ paths = sorted(_get_paths_from_images(dataroot))
+ return paths
+
+
+def _get_paths_from_images(path):
+ assert os.path.isdir(path), '{:s} is not a valid directory'.format(path)
+ images = []
+ for dirpath, _, fnames in sorted(os.walk(path)):
+ for fname in sorted(fnames):
+ if is_image_file(fname):
+ img_path = os.path.join(dirpath, fname)
+ images.append(img_path)
+ assert images, '{:s} has no valid image file'.format(path)
+ return images
+
+
+'''
+# --------------------------------------------
+# split large images into small images
+# --------------------------------------------
+'''
+
+
+def patches_from_image(img, p_size=512, p_overlap=64, p_max=800):
+ w, h = img.shape[:2]
+ patches = []
+ if w > p_max and h > p_max:
+ w1 = list(np.arange(0, w-p_size, p_size-p_overlap, dtype=np.int))
+ h1 = list(np.arange(0, h-p_size, p_size-p_overlap, dtype=np.int))
+ w1.append(w-p_size)
+ h1.append(h-p_size)
+# print(w1)
+# print(h1)
+ for i in w1:
+ for j in h1:
+ patches.append(img[i:i+p_size, j:j+p_size,:])
+ else:
+ patches.append(img)
+
+ return patches
+
+
+def imssave(imgs, img_path):
+ """
+ imgs: list, N images of size WxHxC
+ """
+ img_name, ext = os.path.splitext(os.path.basename(img_path))
+
+ for i, img in enumerate(imgs):
+ if img.ndim == 3:
+ img = img[:, :, [2, 1, 0]]
+ new_path = os.path.join(os.path.dirname(img_path), img_name+str('_s{:04d}'.format(i))+'.png')
+ cv2.imwrite(new_path, img)
+
+
+def split_imageset(original_dataroot, taget_dataroot, n_channels=3, p_size=800, p_overlap=96, p_max=1000):
+ """
+ split the large images from original_dataroot into small overlapped images with size (p_size)x(p_size),
+ and save them into taget_dataroot; only the images with larger size than (p_max)x(p_max)
+ will be splitted.
+ Args:
+ original_dataroot:
+ taget_dataroot:
+ p_size: size of small images
+ p_overlap: patch size in training is a good choice
+ p_max: images with smaller size than (p_max)x(p_max) keep unchanged.
+ """
+ paths = get_image_paths(original_dataroot)
+ for img_path in paths:
+ # img_name, ext = os.path.splitext(os.path.basename(img_path))
+ img = imread_uint(img_path, n_channels=n_channels)
+ patches = patches_from_image(img, p_size, p_overlap, p_max)
+ imssave(patches, os.path.join(taget_dataroot,os.path.basename(img_path)))
+ #if original_dataroot == taget_dataroot:
+ #del img_path
+
+'''
+# --------------------------------------------
+# makedir
+# --------------------------------------------
+'''
+
+
+def mkdir(path):
+ if not os.path.exists(path):
+ os.makedirs(path)
+
+
+def mkdirs(paths):
+ if isinstance(paths, str):
+ mkdir(paths)
+ else:
+ for path in paths:
+ mkdir(path)
+
+
+def mkdir_and_rename(path):
+ if os.path.exists(path):
+ new_name = path + '_archived_' + get_timestamp()
+ print('Path already exists. Rename it to [{:s}]'.format(new_name))
+ os.rename(path, new_name)
+ os.makedirs(path)
+
+
+'''
+# --------------------------------------------
+# read image from path
+# opencv is fast, but read BGR numpy image
+# --------------------------------------------
+'''
+
+
+# --------------------------------------------
+# get uint8 image of size HxWxn_channles (RGB)
+# --------------------------------------------
+def imread_uint(path, n_channels=3):
+ # input: path
+ # output: HxWx3(RGB or GGG), or HxWx1 (G)
+ if n_channels == 1:
+ img = cv2.imread(path, 0) # cv2.IMREAD_GRAYSCALE
+ img = np.expand_dims(img, axis=2) # HxWx1
+ elif n_channels == 3:
+ img = cv2.imread(path, cv2.IMREAD_UNCHANGED) # BGR or G
+ if img.ndim == 2:
+ img = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB) # GGG
+ else:
+ img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # RGB
+ return img
+
+
+# --------------------------------------------
+# matlab's imwrite
+# --------------------------------------------
+def imsave(img, img_path):
+ img = np.squeeze(img)
+ if img.ndim == 3:
+ img = img[:, :, [2, 1, 0]]
+ cv2.imwrite(img_path, img)
+
+def imwrite(img, img_path):
+ img = np.squeeze(img)
+ if img.ndim == 3:
+ img = img[:, :, [2, 1, 0]]
+ cv2.imwrite(img_path, img)
+
+
+
+# --------------------------------------------
+# get single image of size HxWxn_channles (BGR)
+# --------------------------------------------
+def read_img(path):
+ # read image by cv2
+ # return: Numpy float32, HWC, BGR, [0,1]
+ img = cv2.imread(path, cv2.IMREAD_UNCHANGED) # cv2.IMREAD_GRAYSCALE
+ img = img.astype(np.float32) / 255.
+ if img.ndim == 2:
+ img = np.expand_dims(img, axis=2)
+ # some images have 4 channels
+ if img.shape[2] > 3:
+ img = img[:, :, :3]
+ return img
+
+
+'''
+# --------------------------------------------
+# image format conversion
+# --------------------------------------------
+# numpy(single) <---> numpy(unit)
+# numpy(single) <---> tensor
+# numpy(unit) <---> tensor
+# --------------------------------------------
+'''
+
+
+# --------------------------------------------
+# numpy(single) [0, 1] <---> numpy(unit)
+# --------------------------------------------
+
+
+def uint2single(img):
+
+ return np.float32(img/255.)
+
+
+def single2uint(img):
+
+ return np.uint8((img.clip(0, 1)*255.).round())
+
+
+def uint162single(img):
+
+ return np.float32(img/65535.)
+
+
+def single2uint16(img):
+
+ return np.uint16((img.clip(0, 1)*65535.).round())
+
+
+# --------------------------------------------
+# numpy(unit) (HxWxC or HxW) <---> tensor
+# --------------------------------------------
+
+
+# convert uint to 4-dimensional torch tensor
+def uint2tensor4(img):
+ if img.ndim == 2:
+ img = np.expand_dims(img, axis=2)
+ return torch.from_numpy(np.ascontiguousarray(img)).permute(2, 0, 1).float().div(255.).unsqueeze(0)
+
+
+# convert uint to 3-dimensional torch tensor
+def uint2tensor3(img):
+ if img.ndim == 2:
+ img = np.expand_dims(img, axis=2)
+ return torch.from_numpy(np.ascontiguousarray(img)).permute(2, 0, 1).float().div(255.)
+
+
+# convert 2/3/4-dimensional torch tensor to uint
+def tensor2uint(img):
+ img = img.data.squeeze().float().clamp_(0, 1).cpu().numpy()
+ if img.ndim == 3:
+ img = np.transpose(img, (1, 2, 0))
+ return np.uint8((img*255.0).round())
+
+
+# --------------------------------------------
+# numpy(single) (HxWxC) <---> tensor
+# --------------------------------------------
+
+
+# convert single (HxWxC) to 3-dimensional torch tensor
+def single2tensor3(img):
+ return torch.from_numpy(np.ascontiguousarray(img)).permute(2, 0, 1).float()
+
+
+# convert single (HxWxC) to 4-dimensional torch tensor
+def single2tensor4(img):
+ return torch.from_numpy(np.ascontiguousarray(img)).permute(2, 0, 1).float().unsqueeze(0)
+
+
+# convert torch tensor to single
+def tensor2single(img):
+ img = img.data.squeeze().float().cpu().numpy()
+ if img.ndim == 3:
+ img = np.transpose(img, (1, 2, 0))
+
+ return img
+
+# convert torch tensor to single
+def tensor2single3(img):
+ img = img.data.squeeze().float().cpu().numpy()
+ if img.ndim == 3:
+ img = np.transpose(img, (1, 2, 0))
+ elif img.ndim == 2:
+ img = np.expand_dims(img, axis=2)
+ return img
+
+
+def single2tensor5(img):
+ return torch.from_numpy(np.ascontiguousarray(img)).permute(2, 0, 1, 3).float().unsqueeze(0)
+
+
+def single32tensor5(img):
+ return torch.from_numpy(np.ascontiguousarray(img)).float().unsqueeze(0).unsqueeze(0)
+
+
+def single42tensor4(img):
+ return torch.from_numpy(np.ascontiguousarray(img)).permute(2, 0, 1, 3).float()
+
+
+# from skimage.io import imread, imsave
+def tensor2img(tensor, out_type=np.uint8, min_max=(0, 1)):
+ '''
+ Converts a torch Tensor into an image Numpy array of BGR channel order
+ Input: 4D(B,(3/1),H,W), 3D(C,H,W), or 2D(H,W), any range, RGB channel order
+ Output: 3D(H,W,C) or 2D(H,W), [0,255], np.uint8 (default)
+ '''
+ tensor = tensor.squeeze().float().cpu().clamp_(*min_max) # squeeze first, then clamp
+ tensor = (tensor - min_max[0]) / (min_max[1] - min_max[0]) # to range [0,1]
+ n_dim = tensor.dim()
+ if n_dim == 4:
+ n_img = len(tensor)
+ img_np = make_grid(tensor, nrow=int(math.sqrt(n_img)), normalize=False).numpy()
+ img_np = np.transpose(img_np[[2, 1, 0], :, :], (1, 2, 0)) # HWC, BGR
+ elif n_dim == 3:
+ img_np = tensor.numpy()
+ img_np = np.transpose(img_np[[2, 1, 0], :, :], (1, 2, 0)) # HWC, BGR
+ elif n_dim == 2:
+ img_np = tensor.numpy()
+ else:
+ raise TypeError(
+ 'Only support 4D, 3D and 2D tensor. But received with dimension: {:d}'.format(n_dim))
+ if out_type == np.uint8:
+ img_np = (img_np * 255.0).round()
+ # Important. Unlike matlab, numpy.unit8() WILL NOT round by default.
+ return img_np.astype(out_type)
+
+
+'''
+# --------------------------------------------
+# Augmentation, flipe and/or rotate
+# --------------------------------------------
+# The following two are enough.
+# (1) augmet_img: numpy image of WxHxC or WxH
+# (2) augment_img_tensor4: tensor image 1xCxWxH
+# --------------------------------------------
+'''
+
+
+def augment_img(img, mode=0):
+ '''Kai Zhang (github: https://github.com/cszn)
+ '''
+ if mode == 0:
+ return img
+ elif mode == 1:
+ return np.flipud(np.rot90(img))
+ elif mode == 2:
+ return np.flipud(img)
+ elif mode == 3:
+ return np.rot90(img, k=3)
+ elif mode == 4:
+ return np.flipud(np.rot90(img, k=2))
+ elif mode == 5:
+ return np.rot90(img)
+ elif mode == 6:
+ return np.rot90(img, k=2)
+ elif mode == 7:
+ return np.flipud(np.rot90(img, k=3))
+
+
+def augment_img_tensor4(img, mode=0):
+ '''Kai Zhang (github: https://github.com/cszn)
+ '''
+ if mode == 0:
+ return img
+ elif mode == 1:
+ return img.rot90(1, [2, 3]).flip([2])
+ elif mode == 2:
+ return img.flip([2])
+ elif mode == 3:
+ return img.rot90(3, [2, 3])
+ elif mode == 4:
+ return img.rot90(2, [2, 3]).flip([2])
+ elif mode == 5:
+ return img.rot90(1, [2, 3])
+ elif mode == 6:
+ return img.rot90(2, [2, 3])
+ elif mode == 7:
+ return img.rot90(3, [2, 3]).flip([2])
+
+
+def augment_img_tensor(img, mode=0):
+ '''Kai Zhang (github: https://github.com/cszn)
+ '''
+ img_size = img.size()
+ img_np = img.data.cpu().numpy()
+ if len(img_size) == 3:
+ img_np = np.transpose(img_np, (1, 2, 0))
+ elif len(img_size) == 4:
+ img_np = np.transpose(img_np, (2, 3, 1, 0))
+ img_np = augment_img(img_np, mode=mode)
+ img_tensor = torch.from_numpy(np.ascontiguousarray(img_np))
+ if len(img_size) == 3:
+ img_tensor = img_tensor.permute(2, 0, 1)
+ elif len(img_size) == 4:
+ img_tensor = img_tensor.permute(3, 2, 0, 1)
+
+ return img_tensor.type_as(img)
+
+
+def augment_img_np3(img, mode=0):
+ if mode == 0:
+ return img
+ elif mode == 1:
+ return img.transpose(1, 0, 2)
+ elif mode == 2:
+ return img[::-1, :, :]
+ elif mode == 3:
+ img = img[::-1, :, :]
+ img = img.transpose(1, 0, 2)
+ return img
+ elif mode == 4:
+ return img[:, ::-1, :]
+ elif mode == 5:
+ img = img[:, ::-1, :]
+ img = img.transpose(1, 0, 2)
+ return img
+ elif mode == 6:
+ img = img[:, ::-1, :]
+ img = img[::-1, :, :]
+ return img
+ elif mode == 7:
+ img = img[:, ::-1, :]
+ img = img[::-1, :, :]
+ img = img.transpose(1, 0, 2)
+ return img
+
+
+def augment_imgs(img_list, hflip=True, rot=True):
+ # horizontal flip OR rotate
+ hflip = hflip and random.random() < 0.5
+ vflip = rot and random.random() < 0.5
+ rot90 = rot and random.random() < 0.5
+
+ def _augment(img):
+ if hflip:
+ img = img[:, ::-1, :]
+ if vflip:
+ img = img[::-1, :, :]
+ if rot90:
+ img = img.transpose(1, 0, 2)
+ return img
+
+ return [_augment(img) for img in img_list]
+
+
+'''
+# --------------------------------------------
+# modcrop and shave
+# --------------------------------------------
+'''
+
+
+def modcrop(img_in, scale):
+ # img_in: Numpy, HWC or HW
+ img = np.copy(img_in)
+ if img.ndim == 2:
+ H, W = img.shape
+ H_r, W_r = H % scale, W % scale
+ img = img[:H - H_r, :W - W_r]
+ elif img.ndim == 3:
+ H, W, C = img.shape
+ H_r, W_r = H % scale, W % scale
+ img = img[:H - H_r, :W - W_r, :]
+ else:
+ raise ValueError('Wrong img ndim: [{:d}].'.format(img.ndim))
+ return img
+
+
+def shave(img_in, border=0):
+ # img_in: Numpy, HWC or HW
+ img = np.copy(img_in)
+ h, w = img.shape[:2]
+ img = img[border:h-border, border:w-border]
+ return img
+
+
+'''
+# --------------------------------------------
+# image processing process on numpy image
+# channel_convert(in_c, tar_type, img_list):
+# rgb2ycbcr(img, only_y=True):
+# bgr2ycbcr(img, only_y=True):
+# ycbcr2rgb(img):
+# --------------------------------------------
+'''
+
+
+def rgb2ycbcr(img, only_y=True):
+ '''same as matlab rgb2ycbcr
+ only_y: only return Y channel
+ Input:
+ uint8, [0, 255]
+ float, [0, 1]
+ '''
+ in_img_type = img.dtype
+ img.astype(np.float32)
+ if in_img_type != np.uint8:
+ img *= 255.
+ # convert
+ if only_y:
+ rlt = np.dot(img, [65.481, 128.553, 24.966]) / 255.0 + 16.0
+ else:
+ rlt = np.matmul(img, [[65.481, -37.797, 112.0], [128.553, -74.203, -93.786],
+ [24.966, 112.0, -18.214]]) / 255.0 + [16, 128, 128]
+ if in_img_type == np.uint8:
+ rlt = rlt.round()
+ else:
+ rlt /= 255.
+ return rlt.astype(in_img_type)
+
+
+def ycbcr2rgb(img):
+ '''same as matlab ycbcr2rgb
+ Input:
+ uint8, [0, 255]
+ float, [0, 1]
+ '''
+ in_img_type = img.dtype
+ img.astype(np.float32)
+ if in_img_type != np.uint8:
+ img *= 255.
+ # convert
+ rlt = np.matmul(img, [[0.00456621, 0.00456621, 0.00456621], [0, -0.00153632, 0.00791071],
+ [0.00625893, -0.00318811, 0]]) * 255.0 + [-222.921, 135.576, -276.836]
+ if in_img_type == np.uint8:
+ rlt = rlt.round()
+ else:
+ rlt /= 255.
+ return rlt.astype(in_img_type)
+
+
+def bgr2ycbcr(img, only_y=True):
+ '''bgr version of rgb2ycbcr
+ only_y: only return Y channel
+ Input:
+ uint8, [0, 255]
+ float, [0, 1]
+ '''
+ in_img_type = img.dtype
+ img.astype(np.float32)
+ if in_img_type != np.uint8:
+ img *= 255.
+ # convert
+ if only_y:
+ rlt = np.dot(img, [24.966, 128.553, 65.481]) / 255.0 + 16.0
+ else:
+ rlt = np.matmul(img, [[24.966, 112.0, -18.214], [128.553, -74.203, -93.786],
+ [65.481, -37.797, 112.0]]) / 255.0 + [16, 128, 128]
+ if in_img_type == np.uint8:
+ rlt = rlt.round()
+ else:
+ rlt /= 255.
+ return rlt.astype(in_img_type)
+
+
+def channel_convert(in_c, tar_type, img_list):
+ # conversion among BGR, gray and y
+ if in_c == 3 and tar_type == 'gray': # BGR to gray
+ gray_list = [cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) for img in img_list]
+ return [np.expand_dims(img, axis=2) for img in gray_list]
+ elif in_c == 3 and tar_type == 'y': # BGR to y
+ y_list = [bgr2ycbcr(img, only_y=True) for img in img_list]
+ return [np.expand_dims(img, axis=2) for img in y_list]
+ elif in_c == 1 and tar_type == 'RGB': # gray/y to BGR
+ return [cv2.cvtColor(img, cv2.COLOR_GRAY2BGR) for img in img_list]
+ else:
+ return img_list
+
+
+'''
+# --------------------------------------------
+# metric, PSNR and SSIM
+# --------------------------------------------
+'''
+
+
+# --------------------------------------------
+# PSNR
+# --------------------------------------------
+def calculate_psnr(img1, img2, border=0):
+ # img1 and img2 have range [0, 255]
+ #img1 = img1.squeeze()
+ #img2 = img2.squeeze()
+ if not img1.shape == img2.shape:
+ raise ValueError('Input images must have the same dimensions.')
+ h, w = img1.shape[:2]
+ img1 = img1[border:h-border, border:w-border]
+ img2 = img2[border:h-border, border:w-border]
+
+ img1 = img1.astype(np.float64)
+ img2 = img2.astype(np.float64)
+ mse = np.mean((img1 - img2)**2)
+ if mse == 0:
+ return float('inf')
+ return 20 * math.log10(255.0 / math.sqrt(mse))
+
+
+# --------------------------------------------
+# SSIM
+# --------------------------------------------
+def calculate_ssim(img1, img2, border=0):
+ '''calculate SSIM
+ the same outputs as MATLAB's
+ img1, img2: [0, 255]
+ '''
+ #img1 = img1.squeeze()
+ #img2 = img2.squeeze()
+ if not img1.shape == img2.shape:
+ raise ValueError('Input images must have the same dimensions.')
+ h, w = img1.shape[:2]
+ img1 = img1[border:h-border, border:w-border]
+ img2 = img2[border:h-border, border:w-border]
+
+ if img1.ndim == 2:
+ return ssim(img1, img2)
+ elif img1.ndim == 3:
+ if img1.shape[2] == 3:
+ ssims = []
+ for i in range(3):
+ ssims.append(ssim(img1[:,:,i], img2[:,:,i]))
+ return np.array(ssims).mean()
+ elif img1.shape[2] == 1:
+ return ssim(np.squeeze(img1), np.squeeze(img2))
+ else:
+ raise ValueError('Wrong input image dimensions.')
+
+
+def ssim(img1, img2):
+ C1 = (0.01 * 255)**2
+ C2 = (0.03 * 255)**2
+
+ img1 = img1.astype(np.float64)
+ img2 = img2.astype(np.float64)
+ kernel = cv2.getGaussianKernel(11, 1.5)
+ window = np.outer(kernel, kernel.transpose())
+
+ mu1 = cv2.filter2D(img1, -1, window)[5:-5, 5:-5] # valid
+ mu2 = cv2.filter2D(img2, -1, window)[5:-5, 5:-5]
+ mu1_sq = mu1**2
+ mu2_sq = mu2**2
+ mu1_mu2 = mu1 * mu2
+ sigma1_sq = cv2.filter2D(img1**2, -1, window)[5:-5, 5:-5] - mu1_sq
+ sigma2_sq = cv2.filter2D(img2**2, -1, window)[5:-5, 5:-5] - mu2_sq
+ sigma12 = cv2.filter2D(img1 * img2, -1, window)[5:-5, 5:-5] - mu1_mu2
+
+ ssim_map = ((2 * mu1_mu2 + C1) * (2 * sigma12 + C2)) / ((mu1_sq + mu2_sq + C1) *
+ (sigma1_sq + sigma2_sq + C2))
+ return ssim_map.mean()
+
+
+'''
+# --------------------------------------------
+# matlab's bicubic imresize (numpy and torch) [0, 1]
+# --------------------------------------------
+'''
+
+
+# matlab 'imresize' function, now only support 'bicubic'
+def cubic(x):
+ absx = torch.abs(x)
+ absx2 = absx**2
+ absx3 = absx**3
+ return (1.5*absx3 - 2.5*absx2 + 1) * ((absx <= 1).type_as(absx)) + \
+ (-0.5*absx3 + 2.5*absx2 - 4*absx + 2) * (((absx > 1)*(absx <= 2)).type_as(absx))
+
+
+def calculate_weights_indices(in_length, out_length, scale, kernel, kernel_width, antialiasing):
+ if (scale < 1) and (antialiasing):
+ # Use a modified kernel to simultaneously interpolate and antialias- larger kernel width
+ kernel_width = kernel_width / scale
+
+ # Output-space coordinates
+ x = torch.linspace(1, out_length, out_length)
+
+ # Input-space coordinates. Calculate the inverse mapping such that 0.5
+ # in output space maps to 0.5 in input space, and 0.5+scale in output
+ # space maps to 1.5 in input space.
+ u = x / scale + 0.5 * (1 - 1 / scale)
+
+ # What is the left-most pixel that can be involved in the computation?
+ left = torch.floor(u - kernel_width / 2)
+
+ # What is the maximum number of pixels that can be involved in the
+ # computation? Note: it's OK to use an extra pixel here; if the
+ # corresponding weights are all zero, it will be eliminated at the end
+ # of this function.
+ P = math.ceil(kernel_width) + 2
+
+ # The indices of the input pixels involved in computing the k-th output
+ # pixel are in row k of the indices matrix.
+ indices = left.view(out_length, 1).expand(out_length, P) + torch.linspace(0, P - 1, P).view(
+ 1, P).expand(out_length, P)
+
+ # The weights used to compute the k-th output pixel are in row k of the
+ # weights matrix.
+ distance_to_center = u.view(out_length, 1).expand(out_length, P) - indices
+ # apply cubic kernel
+ if (scale < 1) and (antialiasing):
+ weights = scale * cubic(distance_to_center * scale)
+ else:
+ weights = cubic(distance_to_center)
+ # Normalize the weights matrix so that each row sums to 1.
+ weights_sum = torch.sum(weights, 1).view(out_length, 1)
+ weights = weights / weights_sum.expand(out_length, P)
+
+ # If a column in weights is all zero, get rid of it. only consider the first and last column.
+ weights_zero_tmp = torch.sum((weights == 0), 0)
+ if not math.isclose(weights_zero_tmp[0], 0, rel_tol=1e-6):
+ indices = indices.narrow(1, 1, P - 2)
+ weights = weights.narrow(1, 1, P - 2)
+ if not math.isclose(weights_zero_tmp[-1], 0, rel_tol=1e-6):
+ indices = indices.narrow(1, 0, P - 2)
+ weights = weights.narrow(1, 0, P - 2)
+ weights = weights.contiguous()
+ indices = indices.contiguous()
+ sym_len_s = -indices.min() + 1
+ sym_len_e = indices.max() - in_length
+ indices = indices + sym_len_s - 1
+ return weights, indices, int(sym_len_s), int(sym_len_e)
+
+
+# --------------------------------------------
+# imresize for tensor image [0, 1]
+# --------------------------------------------
+def imresize(img, scale, antialiasing=True):
+ # Now the scale should be the same for H and W
+ # input: img: pytorch tensor, CHW or HW [0,1]
+ # output: CHW or HW [0,1] w/o round
+ need_squeeze = True if img.dim() == 2 else False
+ if need_squeeze:
+ img.unsqueeze_(0)
+ in_C, in_H, in_W = img.size()
+ out_C, out_H, out_W = in_C, math.ceil(in_H * scale), math.ceil(in_W * scale)
+ kernel_width = 4
+ kernel = 'cubic'
+
+ # Return the desired dimension order for performing the resize. The
+ # strategy is to perform the resize first along the dimension with the
+ # smallest scale factor.
+ # Now we do not support this.
+
+ # get weights and indices
+ weights_H, indices_H, sym_len_Hs, sym_len_He = calculate_weights_indices(
+ in_H, out_H, scale, kernel, kernel_width, antialiasing)
+ weights_W, indices_W, sym_len_Ws, sym_len_We = calculate_weights_indices(
+ in_W, out_W, scale, kernel, kernel_width, antialiasing)
+ # process H dimension
+ # symmetric copying
+ img_aug = torch.FloatTensor(in_C, in_H + sym_len_Hs + sym_len_He, in_W)
+ img_aug.narrow(1, sym_len_Hs, in_H).copy_(img)
+
+ sym_patch = img[:, :sym_len_Hs, :]
+ inv_idx = torch.arange(sym_patch.size(1) - 1, -1, -1).long()
+ sym_patch_inv = sym_patch.index_select(1, inv_idx)
+ img_aug.narrow(1, 0, sym_len_Hs).copy_(sym_patch_inv)
+
+ sym_patch = img[:, -sym_len_He:, :]
+ inv_idx = torch.arange(sym_patch.size(1) - 1, -1, -1).long()
+ sym_patch_inv = sym_patch.index_select(1, inv_idx)
+ img_aug.narrow(1, sym_len_Hs + in_H, sym_len_He).copy_(sym_patch_inv)
+
+ out_1 = torch.FloatTensor(in_C, out_H, in_W)
+ kernel_width = weights_H.size(1)
+ for i in range(out_H):
+ idx = int(indices_H[i][0])
+ for j in range(out_C):
+ out_1[j, i, :] = img_aug[j, idx:idx + kernel_width, :].transpose(0, 1).mv(weights_H[i])
+
+ # process W dimension
+ # symmetric copying
+ out_1_aug = torch.FloatTensor(in_C, out_H, in_W + sym_len_Ws + sym_len_We)
+ out_1_aug.narrow(2, sym_len_Ws, in_W).copy_(out_1)
+
+ sym_patch = out_1[:, :, :sym_len_Ws]
+ inv_idx = torch.arange(sym_patch.size(2) - 1, -1, -1).long()
+ sym_patch_inv = sym_patch.index_select(2, inv_idx)
+ out_1_aug.narrow(2, 0, sym_len_Ws).copy_(sym_patch_inv)
+
+ sym_patch = out_1[:, :, -sym_len_We:]
+ inv_idx = torch.arange(sym_patch.size(2) - 1, -1, -1).long()
+ sym_patch_inv = sym_patch.index_select(2, inv_idx)
+ out_1_aug.narrow(2, sym_len_Ws + in_W, sym_len_We).copy_(sym_patch_inv)
+
+ out_2 = torch.FloatTensor(in_C, out_H, out_W)
+ kernel_width = weights_W.size(1)
+ for i in range(out_W):
+ idx = int(indices_W[i][0])
+ for j in range(out_C):
+ out_2[j, :, i] = out_1_aug[j, :, idx:idx + kernel_width].mv(weights_W[i])
+ if need_squeeze:
+ out_2.squeeze_()
+ return out_2
+
+
+# --------------------------------------------
+# imresize for numpy image [0, 1]
+# --------------------------------------------
+def imresize_np(img, scale, antialiasing=True):
+ # Now the scale should be the same for H and W
+ # input: img: Numpy, HWC or HW [0,1]
+ # output: HWC or HW [0,1] w/o round
+ img = torch.from_numpy(img)
+ need_squeeze = True if img.dim() == 2 else False
+ if need_squeeze:
+ img.unsqueeze_(2)
+
+ in_H, in_W, in_C = img.size()
+ out_C, out_H, out_W = in_C, math.ceil(in_H * scale), math.ceil(in_W * scale)
+ kernel_width = 4
+ kernel = 'cubic'
+
+ # Return the desired dimension order for performing the resize. The
+ # strategy is to perform the resize first along the dimension with the
+ # smallest scale factor.
+ # Now we do not support this.
+
+ # get weights and indices
+ weights_H, indices_H, sym_len_Hs, sym_len_He = calculate_weights_indices(
+ in_H, out_H, scale, kernel, kernel_width, antialiasing)
+ weights_W, indices_W, sym_len_Ws, sym_len_We = calculate_weights_indices(
+ in_W, out_W, scale, kernel, kernel_width, antialiasing)
+ # process H dimension
+ # symmetric copying
+ img_aug = torch.FloatTensor(in_H + sym_len_Hs + sym_len_He, in_W, in_C)
+ img_aug.narrow(0, sym_len_Hs, in_H).copy_(img)
+
+ sym_patch = img[:sym_len_Hs, :, :]
+ inv_idx = torch.arange(sym_patch.size(0) - 1, -1, -1).long()
+ sym_patch_inv = sym_patch.index_select(0, inv_idx)
+ img_aug.narrow(0, 0, sym_len_Hs).copy_(sym_patch_inv)
+
+ sym_patch = img[-sym_len_He:, :, :]
+ inv_idx = torch.arange(sym_patch.size(0) - 1, -1, -1).long()
+ sym_patch_inv = sym_patch.index_select(0, inv_idx)
+ img_aug.narrow(0, sym_len_Hs + in_H, sym_len_He).copy_(sym_patch_inv)
+
+ out_1 = torch.FloatTensor(out_H, in_W, in_C)
+ kernel_width = weights_H.size(1)
+ for i in range(out_H):
+ idx = int(indices_H[i][0])
+ for j in range(out_C):
+ out_1[i, :, j] = img_aug[idx:idx + kernel_width, :, j].transpose(0, 1).mv(weights_H[i])
+
+ # process W dimension
+ # symmetric copying
+ out_1_aug = torch.FloatTensor(out_H, in_W + sym_len_Ws + sym_len_We, in_C)
+ out_1_aug.narrow(1, sym_len_Ws, in_W).copy_(out_1)
+
+ sym_patch = out_1[:, :sym_len_Ws, :]
+ inv_idx = torch.arange(sym_patch.size(1) - 1, -1, -1).long()
+ sym_patch_inv = sym_patch.index_select(1, inv_idx)
+ out_1_aug.narrow(1, 0, sym_len_Ws).copy_(sym_patch_inv)
+
+ sym_patch = out_1[:, -sym_len_We:, :]
+ inv_idx = torch.arange(sym_patch.size(1) - 1, -1, -1).long()
+ sym_patch_inv = sym_patch.index_select(1, inv_idx)
+ out_1_aug.narrow(1, sym_len_Ws + in_W, sym_len_We).copy_(sym_patch_inv)
+
+ out_2 = torch.FloatTensor(out_H, out_W, in_C)
+ kernel_width = weights_W.size(1)
+ for i in range(out_W):
+ idx = int(indices_W[i][0])
+ for j in range(out_C):
+ out_2[:, i, j] = out_1_aug[:, idx:idx + kernel_width, j].mv(weights_W[i])
+ if need_squeeze:
+ out_2.squeeze_()
+
+ return out_2.numpy()
+
+
+if __name__ == '__main__':
+ print('---')
+# img = imread_uint('test.bmp', 3)
+# img = uint2single(img)
+# img_bicubic = imresize_np(img, 1/4)
\ No newline at end of file
diff --git a/latent-diffusion/ldm/modules/losses/__init__.py b/latent-diffusion/ldm/modules/losses/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..876d7c5bd6e3245ee77feb4c482b7a8143604ad5
--- /dev/null
+++ b/latent-diffusion/ldm/modules/losses/__init__.py
@@ -0,0 +1 @@
+from ldm.modules.losses.contperceptual import LPIPSWithDiscriminator
\ No newline at end of file
diff --git a/latent-diffusion/ldm/modules/losses/contperceptual.py b/latent-diffusion/ldm/modules/losses/contperceptual.py
new file mode 100644
index 0000000000000000000000000000000000000000..672c1e32a1389def02461c0781339681060c540e
--- /dev/null
+++ b/latent-diffusion/ldm/modules/losses/contperceptual.py
@@ -0,0 +1,111 @@
+import torch
+import torch.nn as nn
+
+from taming.modules.losses.vqperceptual import * # TODO: taming dependency yes/no?
+
+
+class LPIPSWithDiscriminator(nn.Module):
+ def __init__(self, disc_start, logvar_init=0.0, kl_weight=1.0, pixelloss_weight=1.0,
+ disc_num_layers=3, disc_in_channels=3, disc_factor=1.0, disc_weight=1.0,
+ perceptual_weight=1.0, use_actnorm=False, disc_conditional=False,
+ disc_loss="hinge"):
+
+ super().__init__()
+ assert disc_loss in ["hinge", "vanilla"]
+ self.kl_weight = kl_weight
+ self.pixel_weight = pixelloss_weight
+ self.perceptual_loss = LPIPS().eval()
+ self.perceptual_weight = perceptual_weight
+ # output log variance
+ self.logvar = nn.Parameter(torch.ones(size=()) * logvar_init)
+
+ self.discriminator = NLayerDiscriminator(input_nc=disc_in_channels,
+ n_layers=disc_num_layers,
+ use_actnorm=use_actnorm
+ ).apply(weights_init)
+ self.discriminator_iter_start = disc_start
+ self.disc_loss = hinge_d_loss if disc_loss == "hinge" else vanilla_d_loss
+ self.disc_factor = disc_factor
+ self.discriminator_weight = disc_weight
+ self.disc_conditional = disc_conditional
+
+ def calculate_adaptive_weight(self, nll_loss, g_loss, last_layer=None):
+ if last_layer is not None:
+ nll_grads = torch.autograd.grad(nll_loss, last_layer, retain_graph=True)[0]
+ g_grads = torch.autograd.grad(g_loss, last_layer, retain_graph=True)[0]
+ else:
+ nll_grads = torch.autograd.grad(nll_loss, self.last_layer[0], retain_graph=True)[0]
+ g_grads = torch.autograd.grad(g_loss, self.last_layer[0], retain_graph=True)[0]
+
+ d_weight = torch.norm(nll_grads) / (torch.norm(g_grads) + 1e-4)
+ d_weight = torch.clamp(d_weight, 0.0, 1e4).detach()
+ d_weight = d_weight * self.discriminator_weight
+ return d_weight
+
+ def forward(self, inputs, reconstructions, posteriors, optimizer_idx,
+ global_step, last_layer=None, cond=None, split="train",
+ weights=None):
+ rec_loss = torch.abs(inputs.contiguous() - reconstructions.contiguous())
+ if self.perceptual_weight > 0:
+ p_loss = self.perceptual_loss(inputs.contiguous(), reconstructions.contiguous())
+ rec_loss = rec_loss + self.perceptual_weight * p_loss
+
+ nll_loss = rec_loss / torch.exp(self.logvar) + self.logvar
+ weighted_nll_loss = nll_loss
+ if weights is not None:
+ weighted_nll_loss = weights*nll_loss
+ weighted_nll_loss = torch.sum(weighted_nll_loss) / weighted_nll_loss.shape[0]
+ nll_loss = torch.sum(nll_loss) / nll_loss.shape[0]
+ kl_loss = posteriors.kl()
+ kl_loss = torch.sum(kl_loss) / kl_loss.shape[0]
+
+ # now the GAN part
+ if optimizer_idx == 0:
+ # generator update
+ if cond is None:
+ assert not self.disc_conditional
+ logits_fake = self.discriminator(reconstructions.contiguous())
+ else:
+ assert self.disc_conditional
+ logits_fake = self.discriminator(torch.cat((reconstructions.contiguous(), cond), dim=1))
+ g_loss = -torch.mean(logits_fake)
+
+ if self.disc_factor > 0.0:
+ try:
+ d_weight = self.calculate_adaptive_weight(nll_loss, g_loss, last_layer=last_layer)
+ except RuntimeError:
+ assert not self.training
+ d_weight = torch.tensor(0.0)
+ else:
+ d_weight = torch.tensor(0.0)
+
+ disc_factor = adopt_weight(self.disc_factor, global_step, threshold=self.discriminator_iter_start)
+ loss = weighted_nll_loss + self.kl_weight * kl_loss + d_weight * disc_factor * g_loss
+
+ log = {"{}/total_loss".format(split): loss.clone().detach().mean(), "{}/logvar".format(split): self.logvar.detach(),
+ "{}/kl_loss".format(split): kl_loss.detach().mean(), "{}/nll_loss".format(split): nll_loss.detach().mean(),
+ "{}/rec_loss".format(split): rec_loss.detach().mean(),
+ "{}/d_weight".format(split): d_weight.detach(),
+ "{}/disc_factor".format(split): torch.tensor(disc_factor),
+ "{}/g_loss".format(split): g_loss.detach().mean(),
+ }
+ return loss, log
+
+ if optimizer_idx == 1:
+ # second pass for discriminator update
+ if cond is None:
+ logits_real = self.discriminator(inputs.contiguous().detach())
+ logits_fake = self.discriminator(reconstructions.contiguous().detach())
+ else:
+ logits_real = self.discriminator(torch.cat((inputs.contiguous().detach(), cond), dim=1))
+ logits_fake = self.discriminator(torch.cat((reconstructions.contiguous().detach(), cond), dim=1))
+
+ disc_factor = adopt_weight(self.disc_factor, global_step, threshold=self.discriminator_iter_start)
+ d_loss = disc_factor * self.disc_loss(logits_real, logits_fake)
+
+ log = {"{}/disc_loss".format(split): d_loss.clone().detach().mean(),
+ "{}/logits_real".format(split): logits_real.detach().mean(),
+ "{}/logits_fake".format(split): logits_fake.detach().mean()
+ }
+ return d_loss, log
+
diff --git a/latent-diffusion/ldm/modules/losses/vqperceptual.py b/latent-diffusion/ldm/modules/losses/vqperceptual.py
new file mode 100644
index 0000000000000000000000000000000000000000..f69981769e4bd5462600458c4fcf26620f7e4306
--- /dev/null
+++ b/latent-diffusion/ldm/modules/losses/vqperceptual.py
@@ -0,0 +1,167 @@
+import torch
+from torch import nn
+import torch.nn.functional as F
+from einops import repeat
+
+from taming.modules.discriminator.model import NLayerDiscriminator, weights_init
+from taming.modules.losses.lpips import LPIPS
+from taming.modules.losses.vqperceptual import hinge_d_loss, vanilla_d_loss
+
+
+def hinge_d_loss_with_exemplar_weights(logits_real, logits_fake, weights):
+ assert weights.shape[0] == logits_real.shape[0] == logits_fake.shape[0]
+ loss_real = torch.mean(F.relu(1. - logits_real), dim=[1,2,3])
+ loss_fake = torch.mean(F.relu(1. + logits_fake), dim=[1,2,3])
+ loss_real = (weights * loss_real).sum() / weights.sum()
+ loss_fake = (weights * loss_fake).sum() / weights.sum()
+ d_loss = 0.5 * (loss_real + loss_fake)
+ return d_loss
+
+def adopt_weight(weight, global_step, threshold=0, value=0.):
+ if global_step < threshold:
+ weight = value
+ return weight
+
+
+def measure_perplexity(predicted_indices, n_embed):
+ # src: https://github.com/karpathy/deep-vector-quantization/blob/main/model.py
+ # eval cluster perplexity. when perplexity == num_embeddings then all clusters are used exactly equally
+ encodings = F.one_hot(predicted_indices, n_embed).float().reshape(-1, n_embed)
+ avg_probs = encodings.mean(0)
+ perplexity = (-(avg_probs * torch.log(avg_probs + 1e-10)).sum()).exp()
+ cluster_use = torch.sum(avg_probs > 0)
+ return perplexity, cluster_use
+
+def l1(x, y):
+ return torch.abs(x-y)
+
+
+def l2(x, y):
+ return torch.pow((x-y), 2)
+
+
+class VQLPIPSWithDiscriminator(nn.Module):
+ def __init__(self, disc_start, codebook_weight=1.0, pixelloss_weight=1.0,
+ disc_num_layers=3, disc_in_channels=3, disc_factor=1.0, disc_weight=1.0,
+ perceptual_weight=1.0, use_actnorm=False, disc_conditional=False,
+ disc_ndf=64, disc_loss="hinge", n_classes=None, perceptual_loss="lpips",
+ pixel_loss="l1"):
+ super().__init__()
+ assert disc_loss in ["hinge", "vanilla"]
+ assert perceptual_loss in ["lpips", "clips", "dists"]
+ assert pixel_loss in ["l1", "l2"]
+ self.codebook_weight = codebook_weight
+ self.pixel_weight = pixelloss_weight
+ if perceptual_loss == "lpips":
+ print(f"{self.__class__.__name__}: Running with LPIPS.")
+ self.perceptual_loss = LPIPS().eval()
+ else:
+ raise ValueError(f"Unknown perceptual loss: >> {perceptual_loss} <<")
+ self.perceptual_weight = perceptual_weight
+
+ if pixel_loss == "l1":
+ self.pixel_loss = l1
+ else:
+ self.pixel_loss = l2
+
+ self.discriminator = NLayerDiscriminator(input_nc=disc_in_channels,
+ n_layers=disc_num_layers,
+ use_actnorm=use_actnorm,
+ ndf=disc_ndf
+ ).apply(weights_init)
+ self.discriminator_iter_start = disc_start
+ if disc_loss == "hinge":
+ self.disc_loss = hinge_d_loss
+ elif disc_loss == "vanilla":
+ self.disc_loss = vanilla_d_loss
+ else:
+ raise ValueError(f"Unknown GAN loss '{disc_loss}'.")
+ print(f"VQLPIPSWithDiscriminator running with {disc_loss} loss.")
+ self.disc_factor = disc_factor
+ self.discriminator_weight = disc_weight
+ self.disc_conditional = disc_conditional
+ self.n_classes = n_classes
+
+ def calculate_adaptive_weight(self, nll_loss, g_loss, last_layer=None):
+ if last_layer is not None:
+ nll_grads = torch.autograd.grad(nll_loss, last_layer, retain_graph=True)[0]
+ g_grads = torch.autograd.grad(g_loss, last_layer, retain_graph=True)[0]
+ else:
+ nll_grads = torch.autograd.grad(nll_loss, self.last_layer[0], retain_graph=True)[0]
+ g_grads = torch.autograd.grad(g_loss, self.last_layer[0], retain_graph=True)[0]
+
+ d_weight = torch.norm(nll_grads) / (torch.norm(g_grads) + 1e-4)
+ d_weight = torch.clamp(d_weight, 0.0, 1e4).detach()
+ d_weight = d_weight * self.discriminator_weight
+ return d_weight
+
+ def forward(self, codebook_loss, inputs, reconstructions, optimizer_idx,
+ global_step, last_layer=None, cond=None, split="train", predicted_indices=None):
+ if not exists(codebook_loss):
+ codebook_loss = torch.tensor([0.]).to(inputs.device)
+ #rec_loss = torch.abs(inputs.contiguous() - reconstructions.contiguous())
+ rec_loss = self.pixel_loss(inputs.contiguous(), reconstructions.contiguous())
+ if self.perceptual_weight > 0:
+ p_loss = self.perceptual_loss(inputs.contiguous(), reconstructions.contiguous())
+ rec_loss = rec_loss + self.perceptual_weight * p_loss
+ else:
+ p_loss = torch.tensor([0.0])
+
+ nll_loss = rec_loss
+ #nll_loss = torch.sum(nll_loss) / nll_loss.shape[0]
+ nll_loss = torch.mean(nll_loss)
+
+ # now the GAN part
+ if optimizer_idx == 0:
+ # generator update
+ if cond is None:
+ assert not self.disc_conditional
+ logits_fake = self.discriminator(reconstructions.contiguous())
+ else:
+ assert self.disc_conditional
+ logits_fake = self.discriminator(torch.cat((reconstructions.contiguous(), cond), dim=1))
+ g_loss = -torch.mean(logits_fake)
+
+ try:
+ d_weight = self.calculate_adaptive_weight(nll_loss, g_loss, last_layer=last_layer)
+ except RuntimeError:
+ assert not self.training
+ d_weight = torch.tensor(0.0)
+
+ disc_factor = adopt_weight(self.disc_factor, global_step, threshold=self.discriminator_iter_start)
+ loss = nll_loss + d_weight * disc_factor * g_loss + self.codebook_weight * codebook_loss.mean()
+
+ log = {"{}/total_loss".format(split): loss.clone().detach().mean(),
+ "{}/quant_loss".format(split): codebook_loss.detach().mean(),
+ "{}/nll_loss".format(split): nll_loss.detach().mean(),
+ "{}/rec_loss".format(split): rec_loss.detach().mean(),
+ "{}/p_loss".format(split): p_loss.detach().mean(),
+ "{}/d_weight".format(split): d_weight.detach(),
+ "{}/disc_factor".format(split): torch.tensor(disc_factor),
+ "{}/g_loss".format(split): g_loss.detach().mean(),
+ }
+ if predicted_indices is not None:
+ assert self.n_classes is not None
+ with torch.no_grad():
+ perplexity, cluster_usage = measure_perplexity(predicted_indices, self.n_classes)
+ log[f"{split}/perplexity"] = perplexity
+ log[f"{split}/cluster_usage"] = cluster_usage
+ return loss, log
+
+ if optimizer_idx == 1:
+ # second pass for discriminator update
+ if cond is None:
+ logits_real = self.discriminator(inputs.contiguous().detach())
+ logits_fake = self.discriminator(reconstructions.contiguous().detach())
+ else:
+ logits_real = self.discriminator(torch.cat((inputs.contiguous().detach(), cond), dim=1))
+ logits_fake = self.discriminator(torch.cat((reconstructions.contiguous().detach(), cond), dim=1))
+
+ disc_factor = adopt_weight(self.disc_factor, global_step, threshold=self.discriminator_iter_start)
+ d_loss = disc_factor * self.disc_loss(logits_real, logits_fake)
+
+ log = {"{}/disc_loss".format(split): d_loss.clone().detach().mean(),
+ "{}/logits_real".format(split): logits_real.detach().mean(),
+ "{}/logits_fake".format(split): logits_fake.detach().mean()
+ }
+ return d_loss, log
diff --git a/latent-diffusion/ldm/modules/x_transformer.py b/latent-diffusion/ldm/modules/x_transformer.py
new file mode 100644
index 0000000000000000000000000000000000000000..5fc15bf9cfe0111a910e7de33d04ffdec3877576
--- /dev/null
+++ b/latent-diffusion/ldm/modules/x_transformer.py
@@ -0,0 +1,641 @@
+"""shout-out to https://github.com/lucidrains/x-transformers/tree/main/x_transformers"""
+import torch
+from torch import nn, einsum
+import torch.nn.functional as F
+from functools import partial
+from inspect import isfunction
+from collections import namedtuple
+from einops import rearrange, repeat, reduce
+
+# constants
+
+DEFAULT_DIM_HEAD = 64
+
+Intermediates = namedtuple('Intermediates', [
+ 'pre_softmax_attn',
+ 'post_softmax_attn'
+])
+
+LayerIntermediates = namedtuple('Intermediates', [
+ 'hiddens',
+ 'attn_intermediates'
+])
+
+
+class AbsolutePositionalEmbedding(nn.Module):
+ def __init__(self, dim, max_seq_len):
+ super().__init__()
+ self.emb = nn.Embedding(max_seq_len, dim)
+ self.init_()
+
+ def init_(self):
+ nn.init.normal_(self.emb.weight, std=0.02)
+
+ def forward(self, x):
+ n = torch.arange(x.shape[1], device=x.device)
+ return self.emb(n)[None, :, :]
+
+
+class FixedPositionalEmbedding(nn.Module):
+ def __init__(self, dim):
+ super().__init__()
+ inv_freq = 1. / (10000 ** (torch.arange(0, dim, 2).float() / dim))
+ self.register_buffer('inv_freq', inv_freq)
+
+ def forward(self, x, seq_dim=1, offset=0):
+ t = torch.arange(x.shape[seq_dim], device=x.device).type_as(self.inv_freq) + offset
+ sinusoid_inp = torch.einsum('i , j -> i j', t, self.inv_freq)
+ emb = torch.cat((sinusoid_inp.sin(), sinusoid_inp.cos()), dim=-1)
+ return emb[None, :, :]
+
+
+# helpers
+
+def exists(val):
+ return val is not None
+
+
+def default(val, d):
+ if exists(val):
+ return val
+ return d() if isfunction(d) else d
+
+
+def always(val):
+ def inner(*args, **kwargs):
+ return val
+ return inner
+
+
+def not_equals(val):
+ def inner(x):
+ return x != val
+ return inner
+
+
+def equals(val):
+ def inner(x):
+ return x == val
+ return inner
+
+
+def max_neg_value(tensor):
+ return -torch.finfo(tensor.dtype).max
+
+
+# keyword argument helpers
+
+def pick_and_pop(keys, d):
+ values = list(map(lambda key: d.pop(key), keys))
+ return dict(zip(keys, values))
+
+
+def group_dict_by_key(cond, d):
+ return_val = [dict(), dict()]
+ for key in d.keys():
+ match = bool(cond(key))
+ ind = int(not match)
+ return_val[ind][key] = d[key]
+ return (*return_val,)
+
+
+def string_begins_with(prefix, str):
+ return str.startswith(prefix)
+
+
+def group_by_key_prefix(prefix, d):
+ return group_dict_by_key(partial(string_begins_with, prefix), d)
+
+
+def groupby_prefix_and_trim(prefix, d):
+ kwargs_with_prefix, kwargs = group_dict_by_key(partial(string_begins_with, prefix), d)
+ kwargs_without_prefix = dict(map(lambda x: (x[0][len(prefix):], x[1]), tuple(kwargs_with_prefix.items())))
+ return kwargs_without_prefix, kwargs
+
+
+# classes
+class Scale(nn.Module):
+ def __init__(self, value, fn):
+ super().__init__()
+ self.value = value
+ self.fn = fn
+
+ def forward(self, x, **kwargs):
+ x, *rest = self.fn(x, **kwargs)
+ return (x * self.value, *rest)
+
+
+class Rezero(nn.Module):
+ def __init__(self, fn):
+ super().__init__()
+ self.fn = fn
+ self.g = nn.Parameter(torch.zeros(1))
+
+ def forward(self, x, **kwargs):
+ x, *rest = self.fn(x, **kwargs)
+ return (x * self.g, *rest)
+
+
+class ScaleNorm(nn.Module):
+ def __init__(self, dim, eps=1e-5):
+ super().__init__()
+ self.scale = dim ** -0.5
+ self.eps = eps
+ self.g = nn.Parameter(torch.ones(1))
+
+ def forward(self, x):
+ norm = torch.norm(x, dim=-1, keepdim=True) * self.scale
+ return x / norm.clamp(min=self.eps) * self.g
+
+
+class RMSNorm(nn.Module):
+ def __init__(self, dim, eps=1e-8):
+ super().__init__()
+ self.scale = dim ** -0.5
+ self.eps = eps
+ self.g = nn.Parameter(torch.ones(dim))
+
+ def forward(self, x):
+ norm = torch.norm(x, dim=-1, keepdim=True) * self.scale
+ return x / norm.clamp(min=self.eps) * self.g
+
+
+class Residual(nn.Module):
+ def forward(self, x, residual):
+ return x + residual
+
+
+class GRUGating(nn.Module):
+ def __init__(self, dim):
+ super().__init__()
+ self.gru = nn.GRUCell(dim, dim)
+
+ def forward(self, x, residual):
+ gated_output = self.gru(
+ rearrange(x, 'b n d -> (b n) d'),
+ rearrange(residual, 'b n d -> (b n) d')
+ )
+
+ return gated_output.reshape_as(x)
+
+
+# feedforward
+
+class GEGLU(nn.Module):
+ def __init__(self, dim_in, dim_out):
+ super().__init__()
+ self.proj = nn.Linear(dim_in, dim_out * 2)
+
+ def forward(self, x):
+ x, gate = self.proj(x).chunk(2, dim=-1)
+ return x * F.gelu(gate)
+
+
+class FeedForward(nn.Module):
+ def __init__(self, dim, dim_out=None, mult=4, glu=False, dropout=0.):
+ super().__init__()
+ inner_dim = int(dim * mult)
+ dim_out = default(dim_out, dim)
+ project_in = nn.Sequential(
+ nn.Linear(dim, inner_dim),
+ nn.GELU()
+ ) if not glu else GEGLU(dim, inner_dim)
+
+ self.net = nn.Sequential(
+ project_in,
+ nn.Dropout(dropout),
+ nn.Linear(inner_dim, dim_out)
+ )
+
+ def forward(self, x):
+ return self.net(x)
+
+
+# attention.
+class Attention(nn.Module):
+ def __init__(
+ self,
+ dim,
+ dim_head=DEFAULT_DIM_HEAD,
+ heads=8,
+ causal=False,
+ mask=None,
+ talking_heads=False,
+ sparse_topk=None,
+ use_entmax15=False,
+ num_mem_kv=0,
+ dropout=0.,
+ on_attn=False
+ ):
+ super().__init__()
+ if use_entmax15:
+ raise NotImplementedError("Check out entmax activation instead of softmax activation!")
+ self.scale = dim_head ** -0.5
+ self.heads = heads
+ self.causal = causal
+ self.mask = mask
+
+ inner_dim = dim_head * heads
+
+ self.to_q = nn.Linear(dim, inner_dim, bias=False)
+ self.to_k = nn.Linear(dim, inner_dim, bias=False)
+ self.to_v = nn.Linear(dim, inner_dim, bias=False)
+ self.dropout = nn.Dropout(dropout)
+
+ # talking heads
+ self.talking_heads = talking_heads
+ if talking_heads:
+ self.pre_softmax_proj = nn.Parameter(torch.randn(heads, heads))
+ self.post_softmax_proj = nn.Parameter(torch.randn(heads, heads))
+
+ # explicit topk sparse attention
+ self.sparse_topk = sparse_topk
+
+ # entmax
+ #self.attn_fn = entmax15 if use_entmax15 else F.softmax
+ self.attn_fn = F.softmax
+
+ # add memory key / values
+ self.num_mem_kv = num_mem_kv
+ if num_mem_kv > 0:
+ self.mem_k = nn.Parameter(torch.randn(heads, num_mem_kv, dim_head))
+ self.mem_v = nn.Parameter(torch.randn(heads, num_mem_kv, dim_head))
+
+ # attention on attention
+ self.attn_on_attn = on_attn
+ self.to_out = nn.Sequential(nn.Linear(inner_dim, dim * 2), nn.GLU()) if on_attn else nn.Linear(inner_dim, dim)
+
+ def forward(
+ self,
+ x,
+ context=None,
+ mask=None,
+ context_mask=None,
+ rel_pos=None,
+ sinusoidal_emb=None,
+ prev_attn=None,
+ mem=None
+ ):
+ b, n, _, h, talking_heads, device = *x.shape, self.heads, self.talking_heads, x.device
+ kv_input = default(context, x)
+
+ q_input = x
+ k_input = kv_input
+ v_input = kv_input
+
+ if exists(mem):
+ k_input = torch.cat((mem, k_input), dim=-2)
+ v_input = torch.cat((mem, v_input), dim=-2)
+
+ if exists(sinusoidal_emb):
+ # in shortformer, the query would start at a position offset depending on the past cached memory
+ offset = k_input.shape[-2] - q_input.shape[-2]
+ q_input = q_input + sinusoidal_emb(q_input, offset=offset)
+ k_input = k_input + sinusoidal_emb(k_input)
+
+ q = self.to_q(q_input)
+ k = self.to_k(k_input)
+ v = self.to_v(v_input)
+
+ q, k, v = map(lambda t: rearrange(t, 'b n (h d) -> b h n d', h=h), (q, k, v))
+
+ input_mask = None
+ if any(map(exists, (mask, context_mask))):
+ q_mask = default(mask, lambda: torch.ones((b, n), device=device).bool())
+ k_mask = q_mask if not exists(context) else context_mask
+ k_mask = default(k_mask, lambda: torch.ones((b, k.shape[-2]), device=device).bool())
+ q_mask = rearrange(q_mask, 'b i -> b () i ()')
+ k_mask = rearrange(k_mask, 'b j -> b () () j')
+ input_mask = q_mask * k_mask
+
+ if self.num_mem_kv > 0:
+ mem_k, mem_v = map(lambda t: repeat(t, 'h n d -> b h n d', b=b), (self.mem_k, self.mem_v))
+ k = torch.cat((mem_k, k), dim=-2)
+ v = torch.cat((mem_v, v), dim=-2)
+ if exists(input_mask):
+ input_mask = F.pad(input_mask, (self.num_mem_kv, 0), value=True)
+
+ dots = einsum('b h i d, b h j d -> b h i j', q, k) * self.scale
+ mask_value = max_neg_value(dots)
+
+ if exists(prev_attn):
+ dots = dots + prev_attn
+
+ pre_softmax_attn = dots
+
+ if talking_heads:
+ dots = einsum('b h i j, h k -> b k i j', dots, self.pre_softmax_proj).contiguous()
+
+ if exists(rel_pos):
+ dots = rel_pos(dots)
+
+ if exists(input_mask):
+ dots.masked_fill_(~input_mask, mask_value)
+ del input_mask
+
+ if self.causal:
+ i, j = dots.shape[-2:]
+ r = torch.arange(i, device=device)
+ mask = rearrange(r, 'i -> () () i ()') < rearrange(r, 'j -> () () () j')
+ mask = F.pad(mask, (j - i, 0), value=False)
+ dots.masked_fill_(mask, mask_value)
+ del mask
+
+ if exists(self.sparse_topk) and self.sparse_topk < dots.shape[-1]:
+ top, _ = dots.topk(self.sparse_topk, dim=-1)
+ vk = top[..., -1].unsqueeze(-1).expand_as(dots)
+ mask = dots < vk
+ dots.masked_fill_(mask, mask_value)
+ del mask
+
+ attn = self.attn_fn(dots, dim=-1)
+ post_softmax_attn = attn
+
+ attn = self.dropout(attn)
+
+ if talking_heads:
+ attn = einsum('b h i j, h k -> b k i j', attn, self.post_softmax_proj).contiguous()
+
+ out = einsum('b h i j, b h j d -> b h i d', attn, v)
+ out = rearrange(out, 'b h n d -> b n (h d)')
+
+ intermediates = Intermediates(
+ pre_softmax_attn=pre_softmax_attn,
+ post_softmax_attn=post_softmax_attn
+ )
+
+ return self.to_out(out), intermediates
+
+
+class AttentionLayers(nn.Module):
+ def __init__(
+ self,
+ dim,
+ depth,
+ heads=8,
+ causal=False,
+ cross_attend=False,
+ only_cross=False,
+ use_scalenorm=False,
+ use_rmsnorm=False,
+ use_rezero=False,
+ rel_pos_num_buckets=32,
+ rel_pos_max_distance=128,
+ position_infused_attn=False,
+ custom_layers=None,
+ sandwich_coef=None,
+ par_ratio=None,
+ residual_attn=False,
+ cross_residual_attn=False,
+ macaron=False,
+ pre_norm=True,
+ gate_residual=False,
+ **kwargs
+ ):
+ super().__init__()
+ ff_kwargs, kwargs = groupby_prefix_and_trim('ff_', kwargs)
+ attn_kwargs, _ = groupby_prefix_and_trim('attn_', kwargs)
+
+ dim_head = attn_kwargs.get('dim_head', DEFAULT_DIM_HEAD)
+
+ self.dim = dim
+ self.depth = depth
+ self.layers = nn.ModuleList([])
+
+ self.has_pos_emb = position_infused_attn
+ self.pia_pos_emb = FixedPositionalEmbedding(dim) if position_infused_attn else None
+ self.rotary_pos_emb = always(None)
+
+ assert rel_pos_num_buckets <= rel_pos_max_distance, 'number of relative position buckets must be less than the relative position max distance'
+ self.rel_pos = None
+
+ self.pre_norm = pre_norm
+
+ self.residual_attn = residual_attn
+ self.cross_residual_attn = cross_residual_attn
+
+ norm_class = ScaleNorm if use_scalenorm else nn.LayerNorm
+ norm_class = RMSNorm if use_rmsnorm else norm_class
+ norm_fn = partial(norm_class, dim)
+
+ norm_fn = nn.Identity if use_rezero else norm_fn
+ branch_fn = Rezero if use_rezero else None
+
+ if cross_attend and not only_cross:
+ default_block = ('a', 'c', 'f')
+ elif cross_attend and only_cross:
+ default_block = ('c', 'f')
+ else:
+ default_block = ('a', 'f')
+
+ if macaron:
+ default_block = ('f',) + default_block
+
+ if exists(custom_layers):
+ layer_types = custom_layers
+ elif exists(par_ratio):
+ par_depth = depth * len(default_block)
+ assert 1 < par_ratio <= par_depth, 'par ratio out of range'
+ default_block = tuple(filter(not_equals('f'), default_block))
+ par_attn = par_depth // par_ratio
+ depth_cut = par_depth * 2 // 3 # 2 / 3 attention layer cutoff suggested by PAR paper
+ par_width = (depth_cut + depth_cut // par_attn) // par_attn
+ assert len(default_block) <= par_width, 'default block is too large for par_ratio'
+ par_block = default_block + ('f',) * (par_width - len(default_block))
+ par_head = par_block * par_attn
+ layer_types = par_head + ('f',) * (par_depth - len(par_head))
+ elif exists(sandwich_coef):
+ assert sandwich_coef > 0 and sandwich_coef <= depth, 'sandwich coefficient should be less than the depth'
+ layer_types = ('a',) * sandwich_coef + default_block * (depth - sandwich_coef) + ('f',) * sandwich_coef
+ else:
+ layer_types = default_block * depth
+
+ self.layer_types = layer_types
+ self.num_attn_layers = len(list(filter(equals('a'), layer_types)))
+
+ for layer_type in self.layer_types:
+ if layer_type == 'a':
+ layer = Attention(dim, heads=heads, causal=causal, **attn_kwargs)
+ elif layer_type == 'c':
+ layer = Attention(dim, heads=heads, **attn_kwargs)
+ elif layer_type == 'f':
+ layer = FeedForward(dim, **ff_kwargs)
+ layer = layer if not macaron else Scale(0.5, layer)
+ else:
+ raise Exception(f'invalid layer type {layer_type}')
+
+ if isinstance(layer, Attention) and exists(branch_fn):
+ layer = branch_fn(layer)
+
+ if gate_residual:
+ residual_fn = GRUGating(dim)
+ else:
+ residual_fn = Residual()
+
+ self.layers.append(nn.ModuleList([
+ norm_fn(),
+ layer,
+ residual_fn
+ ]))
+
+ def forward(
+ self,
+ x,
+ context=None,
+ mask=None,
+ context_mask=None,
+ mems=None,
+ return_hiddens=False
+ ):
+ hiddens = []
+ intermediates = []
+ prev_attn = None
+ prev_cross_attn = None
+
+ mems = mems.copy() if exists(mems) else [None] * self.num_attn_layers
+
+ for ind, (layer_type, (norm, block, residual_fn)) in enumerate(zip(self.layer_types, self.layers)):
+ is_last = ind == (len(self.layers) - 1)
+
+ if layer_type == 'a':
+ hiddens.append(x)
+ layer_mem = mems.pop(0)
+
+ residual = x
+
+ if self.pre_norm:
+ x = norm(x)
+
+ if layer_type == 'a':
+ out, inter = block(x, mask=mask, sinusoidal_emb=self.pia_pos_emb, rel_pos=self.rel_pos,
+ prev_attn=prev_attn, mem=layer_mem)
+ elif layer_type == 'c':
+ out, inter = block(x, context=context, mask=mask, context_mask=context_mask, prev_attn=prev_cross_attn)
+ elif layer_type == 'f':
+ out = block(x)
+
+ x = residual_fn(out, residual)
+
+ if layer_type in ('a', 'c'):
+ intermediates.append(inter)
+
+ if layer_type == 'a' and self.residual_attn:
+ prev_attn = inter.pre_softmax_attn
+ elif layer_type == 'c' and self.cross_residual_attn:
+ prev_cross_attn = inter.pre_softmax_attn
+
+ if not self.pre_norm and not is_last:
+ x = norm(x)
+
+ if return_hiddens:
+ intermediates = LayerIntermediates(
+ hiddens=hiddens,
+ attn_intermediates=intermediates
+ )
+
+ return x, intermediates
+
+ return x
+
+
+class Encoder(AttentionLayers):
+ def __init__(self, **kwargs):
+ assert 'causal' not in kwargs, 'cannot set causality on encoder'
+ super().__init__(causal=False, **kwargs)
+
+
+
+class TransformerWrapper(nn.Module):
+ def __init__(
+ self,
+ *,
+ num_tokens,
+ max_seq_len,
+ attn_layers,
+ emb_dim=None,
+ max_mem_len=0.,
+ emb_dropout=0.,
+ num_memory_tokens=None,
+ tie_embedding=False,
+ use_pos_emb=True
+ ):
+ super().__init__()
+ assert isinstance(attn_layers, AttentionLayers), 'attention layers must be one of Encoder or Decoder'
+
+ dim = attn_layers.dim
+ emb_dim = default(emb_dim, dim)
+
+ self.max_seq_len = max_seq_len
+ self.max_mem_len = max_mem_len
+ self.num_tokens = num_tokens
+
+ self.token_emb = nn.Embedding(num_tokens, emb_dim)
+ self.pos_emb = AbsolutePositionalEmbedding(emb_dim, max_seq_len) if (
+ use_pos_emb and not attn_layers.has_pos_emb) else always(0)
+ self.emb_dropout = nn.Dropout(emb_dropout)
+
+ self.project_emb = nn.Linear(emb_dim, dim) if emb_dim != dim else nn.Identity()
+ self.attn_layers = attn_layers
+ self.norm = nn.LayerNorm(dim)
+
+ self.init_()
+
+ self.to_logits = nn.Linear(dim, num_tokens) if not tie_embedding else lambda t: t @ self.token_emb.weight.t()
+
+ # memory tokens (like [cls]) from Memory Transformers paper
+ num_memory_tokens = default(num_memory_tokens, 0)
+ self.num_memory_tokens = num_memory_tokens
+ if num_memory_tokens > 0:
+ self.memory_tokens = nn.Parameter(torch.randn(num_memory_tokens, dim))
+
+ # let funnel encoder know number of memory tokens, if specified
+ if hasattr(attn_layers, 'num_memory_tokens'):
+ attn_layers.num_memory_tokens = num_memory_tokens
+
+ def init_(self):
+ nn.init.normal_(self.token_emb.weight, std=0.02)
+
+ def forward(
+ self,
+ x,
+ return_embeddings=False,
+ mask=None,
+ return_mems=False,
+ return_attn=False,
+ mems=None,
+ **kwargs
+ ):
+ b, n, device, num_mem = *x.shape, x.device, self.num_memory_tokens
+ x = self.token_emb(x)
+ x += self.pos_emb(x)
+ x = self.emb_dropout(x)
+
+ x = self.project_emb(x)
+
+ if num_mem > 0:
+ mem = repeat(self.memory_tokens, 'n d -> b n d', b=b)
+ x = torch.cat((mem, x), dim=1)
+
+ # auto-handle masking after appending memory tokens
+ if exists(mask):
+ mask = F.pad(mask, (num_mem, 0), value=True)
+
+ x, intermediates = self.attn_layers(x, mask=mask, mems=mems, return_hiddens=True, **kwargs)
+ x = self.norm(x)
+
+ mem, x = x[:, :num_mem], x[:, num_mem:]
+
+ out = self.to_logits(x) if not return_embeddings else x
+
+ if return_mems:
+ hiddens = intermediates.hiddens
+ new_mems = list(map(lambda pair: torch.cat(pair, dim=-2), zip(mems, hiddens))) if exists(mems) else hiddens
+ new_mems = list(map(lambda t: t[..., -self.max_mem_len:, :].detach(), new_mems))
+ return out, new_mems
+
+ if return_attn:
+ attn_maps = list(map(lambda t: t.post_softmax_attn, intermediates.attn_intermediates))
+ return out, attn_maps
+
+ return out
+
diff --git a/latent-diffusion/ldm/util.py b/latent-diffusion/ldm/util.py
new file mode 100644
index 0000000000000000000000000000000000000000..51839cb1478d9fecb293277dc83d2693e3d26de4
--- /dev/null
+++ b/latent-diffusion/ldm/util.py
@@ -0,0 +1,86 @@
+import importlib
+
+import torch
+import numpy as np
+
+from inspect import isfunction
+from PIL import Image, ImageDraw, ImageFont
+
+
+def log_txt_as_img(wh, xc, size=10):
+ # wh a tuple of (width, height)
+ # xc a list of captions to plot
+ b = len(xc)
+ txts = list()
+ for bi in range(b):
+ txt = Image.new("RGB", wh, color="white")
+ draw = ImageDraw.Draw(txt)
+ font = ImageFont.truetype('data/DejaVuSans.ttf', size=size)
+ nc = int(40 * (wh[0] / 256))
+ lines = "\n".join(xc[bi][start:start + nc] for start in range(0, len(xc[bi]), nc))
+
+ try:
+ draw.text((0, 0), lines, fill="black", font=font)
+ except UnicodeEncodeError:
+ print("Cant encode string for logging. Skipping.")
+
+ txt = np.array(txt).transpose(2, 0, 1) / 127.5 - 1.0
+ txts.append(txt)
+ txts = np.stack(txts)
+ txts = torch.tensor(txts)
+ return txts
+
+
+def ismap(x):
+ if not isinstance(x, torch.Tensor):
+ return False
+ return (len(x.shape) == 4) and (x.shape[1] > 3)
+
+
+def isimage(x):
+ if not isinstance(x,torch.Tensor):
+ return False
+ return (len(x.shape) == 4) and (x.shape[1] == 3 or x.shape[1] == 1)
+
+
+def exists(x):
+ return x is not None
+
+
+def default(val, d):
+ if exists(val):
+ return val
+ return d() if isfunction(d) else d
+
+
+def mean_flat(tensor):
+ """
+ https://github.com/openai/guided-diffusion/blob/27c20a8fab9cb472df5d6bdd6c8d11c8f430b924/guided_diffusion/nn.py#L86
+ Take the mean over all non-batch dimensions.
+ """
+ return tensor.mean(dim=list(range(1, len(tensor.shape))))
+
+
+def count_params(model, verbose=False):
+ total_params = sum(p.numel() for p in model.parameters())
+ if verbose:
+ print(f"{model.__class__.__name__} has {total_params*1.e-6:.2f} M params.")
+ return total_params
+
+
+def instantiate_from_config(config):
+ if not "target" in config:
+ if config == '__is_first_stage__':
+ return None
+ elif config == "__is_unconditional__":
+ return None
+ raise KeyError("Expected key `target` to instantiate.")
+ return get_obj_from_str(config["target"])(**config.get("params", dict()))
+
+
+def get_obj_from_str(string, reload=False):
+ module, cls = string.rsplit(".", 1)
+ if reload:
+ module_imp = importlib.import_module(module)
+ importlib.reload(module_imp)
+ return getattr(importlib.import_module(module, package=None), cls)
\ No newline at end of file
diff --git a/latent-diffusion/main.py b/latent-diffusion/main.py
new file mode 100644
index 0000000000000000000000000000000000000000..e8e18c18fbb01f2e16d9376ea1bfb51f3b5df601
--- /dev/null
+++ b/latent-diffusion/main.py
@@ -0,0 +1,741 @@
+import argparse, os, sys, datetime, glob, importlib, csv
+import numpy as np
+import time
+import torch
+import torchvision
+import pytorch_lightning as pl
+
+from packaging import version
+from omegaconf import OmegaConf
+from torch.utils.data import random_split, DataLoader, Dataset, Subset
+from functools import partial
+from PIL import Image
+
+from pytorch_lightning import seed_everything
+from pytorch_lightning.trainer import Trainer
+from pytorch_lightning.callbacks import ModelCheckpoint, Callback, LearningRateMonitor
+from pytorch_lightning.utilities.distributed import rank_zero_only
+from pytorch_lightning.utilities import rank_zero_info
+
+from ldm.data.base import Txt2ImgIterableBaseDataset
+from ldm.util import instantiate_from_config
+
+
+def get_parser(**parser_kwargs):
+ def str2bool(v):
+ if isinstance(v, bool):
+ return v
+ if v.lower() in ("yes", "true", "t", "y", "1"):
+ return True
+ elif v.lower() in ("no", "false", "f", "n", "0"):
+ return False
+ else:
+ raise argparse.ArgumentTypeError("Boolean value expected.")
+
+ parser = argparse.ArgumentParser(**parser_kwargs)
+ parser.add_argument(
+ "-n",
+ "--name",
+ type=str,
+ const=True,
+ default="",
+ nargs="?",
+ help="postfix for logdir",
+ )
+ parser.add_argument(
+ "-r",
+ "--resume",
+ type=str,
+ const=True,
+ default="",
+ nargs="?",
+ help="resume from logdir or checkpoint in logdir",
+ )
+ parser.add_argument(
+ "-b",
+ "--base",
+ nargs="*",
+ metavar="base_config.yaml",
+ help="paths to base configs. Loaded from left-to-right. "
+ "Parameters can be overwritten or added with command-line options of the form `--key value`.",
+ default=list(),
+ )
+ parser.add_argument(
+ "-t",
+ "--train",
+ type=str2bool,
+ const=True,
+ default=False,
+ nargs="?",
+ help="train",
+ )
+ parser.add_argument(
+ "--no-test",
+ type=str2bool,
+ const=True,
+ default=False,
+ nargs="?",
+ help="disable test",
+ )
+ parser.add_argument(
+ "-p",
+ "--project",
+ help="name of new or path to existing project"
+ )
+ parser.add_argument(
+ "-d",
+ "--debug",
+ type=str2bool,
+ nargs="?",
+ const=True,
+ default=False,
+ help="enable post-mortem debugging",
+ )
+ parser.add_argument(
+ "-s",
+ "--seed",
+ type=int,
+ default=23,
+ help="seed for seed_everything",
+ )
+ parser.add_argument(
+ "-f",
+ "--postfix",
+ type=str,
+ default="",
+ help="post-postfix for default name",
+ )
+ parser.add_argument(
+ "-l",
+ "--logdir",
+ type=str,
+ default="logs",
+ help="directory for logging dat shit",
+ )
+ parser.add_argument(
+ "--scale_lr",
+ type=str2bool,
+ nargs="?",
+ const=True,
+ default=True,
+ help="scale base-lr by ngpu * batch_size * n_accumulate",
+ )
+ return parser
+
+
+def nondefault_trainer_args(opt):
+ parser = argparse.ArgumentParser()
+ parser = Trainer.add_argparse_args(parser)
+ args = parser.parse_args([])
+ return sorted(k for k in vars(args) if getattr(opt, k) != getattr(args, k))
+
+
+class WrappedDataset(Dataset):
+ """Wraps an arbitrary object with __len__ and __getitem__ into a pytorch dataset"""
+
+ def __init__(self, dataset):
+ self.data = dataset
+
+ def __len__(self):
+ return len(self.data)
+
+ def __getitem__(self, idx):
+ return self.data[idx]
+
+
+def worker_init_fn(_):
+ worker_info = torch.utils.data.get_worker_info()
+
+ dataset = worker_info.dataset
+ worker_id = worker_info.id
+
+ if isinstance(dataset, Txt2ImgIterableBaseDataset):
+ split_size = dataset.num_records // worker_info.num_workers
+ # reset num_records to the true number to retain reliable length information
+ dataset.sample_ids = dataset.valid_ids[worker_id * split_size:(worker_id + 1) * split_size]
+ current_id = np.random.choice(len(np.random.get_state()[1]), 1)
+ return np.random.seed(np.random.get_state()[1][current_id] + worker_id)
+ else:
+ return np.random.seed(np.random.get_state()[1][0] + worker_id)
+
+
+class DataModuleFromConfig(pl.LightningDataModule):
+ def __init__(self, batch_size, train=None, validation=None, test=None, predict=None,
+ wrap=False, num_workers=None, shuffle_test_loader=False, use_worker_init_fn=False,
+ shuffle_val_dataloader=False):
+ super().__init__()
+ self.batch_size = batch_size
+ self.dataset_configs = dict()
+ self.num_workers = num_workers if num_workers is not None else batch_size * 2
+ self.use_worker_init_fn = use_worker_init_fn
+ if train is not None:
+ self.dataset_configs["train"] = train
+ self.train_dataloader = self._train_dataloader
+ if validation is not None:
+ self.dataset_configs["validation"] = validation
+ self.val_dataloader = partial(self._val_dataloader, shuffle=shuffle_val_dataloader)
+ if test is not None:
+ self.dataset_configs["test"] = test
+ self.test_dataloader = partial(self._test_dataloader, shuffle=shuffle_test_loader)
+ if predict is not None:
+ self.dataset_configs["predict"] = predict
+ self.predict_dataloader = self._predict_dataloader
+ self.wrap = wrap
+
+ def prepare_data(self):
+ for data_cfg in self.dataset_configs.values():
+ instantiate_from_config(data_cfg)
+
+ def setup(self, stage=None):
+ self.datasets = dict(
+ (k, instantiate_from_config(self.dataset_configs[k]))
+ for k in self.dataset_configs)
+ if self.wrap:
+ for k in self.datasets:
+ self.datasets[k] = WrappedDataset(self.datasets[k])
+
+ def _train_dataloader(self):
+ is_iterable_dataset = isinstance(self.datasets['train'], Txt2ImgIterableBaseDataset)
+ if is_iterable_dataset or self.use_worker_init_fn:
+ init_fn = worker_init_fn
+ else:
+ init_fn = None
+ return DataLoader(self.datasets["train"], batch_size=self.batch_size,
+ num_workers=self.num_workers, shuffle=False if is_iterable_dataset else True,
+ worker_init_fn=init_fn)
+
+ def _val_dataloader(self, shuffle=False):
+ if isinstance(self.datasets['validation'], Txt2ImgIterableBaseDataset) or self.use_worker_init_fn:
+ init_fn = worker_init_fn
+ else:
+ init_fn = None
+ return DataLoader(self.datasets["validation"],
+ batch_size=self.batch_size,
+ num_workers=self.num_workers,
+ worker_init_fn=init_fn,
+ shuffle=shuffle)
+
+ def _test_dataloader(self, shuffle=False):
+ is_iterable_dataset = isinstance(self.datasets['train'], Txt2ImgIterableBaseDataset)
+ if is_iterable_dataset or self.use_worker_init_fn:
+ init_fn = worker_init_fn
+ else:
+ init_fn = None
+
+ # do not shuffle dataloader for iterable dataset
+ shuffle = shuffle and (not is_iterable_dataset)
+
+ return DataLoader(self.datasets["test"], batch_size=self.batch_size,
+ num_workers=self.num_workers, worker_init_fn=init_fn, shuffle=shuffle)
+
+ def _predict_dataloader(self, shuffle=False):
+ if isinstance(self.datasets['predict'], Txt2ImgIterableBaseDataset) or self.use_worker_init_fn:
+ init_fn = worker_init_fn
+ else:
+ init_fn = None
+ return DataLoader(self.datasets["predict"], batch_size=self.batch_size,
+ num_workers=self.num_workers, worker_init_fn=init_fn)
+
+
+class SetupCallback(Callback):
+ def __init__(self, resume, now, logdir, ckptdir, cfgdir, config, lightning_config):
+ super().__init__()
+ self.resume = resume
+ self.now = now
+ self.logdir = logdir
+ self.ckptdir = ckptdir
+ self.cfgdir = cfgdir
+ self.config = config
+ self.lightning_config = lightning_config
+
+ def on_keyboard_interrupt(self, trainer, pl_module):
+ if trainer.global_rank == 0:
+ print("Summoning checkpoint.")
+ ckpt_path = os.path.join(self.ckptdir, "last.ckpt")
+ trainer.save_checkpoint(ckpt_path)
+
+ def on_pretrain_routine_start(self, trainer, pl_module):
+ if trainer.global_rank == 0:
+ # Create logdirs and save configs
+ os.makedirs(self.logdir, exist_ok=True)
+ os.makedirs(self.ckptdir, exist_ok=True)
+ os.makedirs(self.cfgdir, exist_ok=True)
+
+ if "callbacks" in self.lightning_config:
+ if 'metrics_over_trainsteps_checkpoint' in self.lightning_config['callbacks']:
+ os.makedirs(os.path.join(self.ckptdir, 'trainstep_checkpoints'), exist_ok=True)
+ print("Project config")
+ print(OmegaConf.to_yaml(self.config))
+ OmegaConf.save(self.config,
+ os.path.join(self.cfgdir, "{}-project.yaml".format(self.now)))
+
+ print("Lightning config")
+ print(OmegaConf.to_yaml(self.lightning_config))
+ OmegaConf.save(OmegaConf.create({"lightning": self.lightning_config}),
+ os.path.join(self.cfgdir, "{}-lightning.yaml".format(self.now)))
+
+ else:
+ # ModelCheckpoint callback created log directory --- remove it
+ if not self.resume and os.path.exists(self.logdir):
+ dst, name = os.path.split(self.logdir)
+ dst = os.path.join(dst, "child_runs", name)
+ os.makedirs(os.path.split(dst)[0], exist_ok=True)
+ try:
+ os.rename(self.logdir, dst)
+ except FileNotFoundError:
+ pass
+
+
+class ImageLogger(Callback):
+ def __init__(self, batch_frequency, max_images, clamp=True, increase_log_steps=True,
+ rescale=True, disabled=False, log_on_batch_idx=False, log_first_step=False,
+ log_images_kwargs=None):
+ super().__init__()
+ self.rescale = rescale
+ self.batch_freq = batch_frequency
+ self.max_images = max_images
+ self.logger_log_images = {
+ pl.loggers.TestTubeLogger: self._testtube,
+ }
+ self.log_steps = [2 ** n for n in range(int(np.log2(self.batch_freq)) + 1)]
+ if not increase_log_steps:
+ self.log_steps = [self.batch_freq]
+ self.clamp = clamp
+ self.disabled = disabled
+ self.log_on_batch_idx = log_on_batch_idx
+ self.log_images_kwargs = log_images_kwargs if log_images_kwargs else {}
+ self.log_first_step = log_first_step
+
+ @rank_zero_only
+ def _testtube(self, pl_module, images, batch_idx, split):
+ for k in images:
+ grid = torchvision.utils.make_grid(images[k])
+ grid = (grid + 1.0) / 2.0 # -1,1 -> 0,1; c,h,w
+
+ tag = f"{split}/{k}"
+ pl_module.logger.experiment.add_image(
+ tag, grid,
+ global_step=pl_module.global_step)
+
+ @rank_zero_only
+ def log_local(self, save_dir, split, images,
+ global_step, current_epoch, batch_idx):
+ root = os.path.join(save_dir, "images", split)
+ for k in images:
+ grid = torchvision.utils.make_grid(images[k], nrow=4)
+ if self.rescale:
+ grid = (grid + 1.0) / 2.0 # -1,1 -> 0,1; c,h,w
+ grid = grid.transpose(0, 1).transpose(1, 2).squeeze(-1)
+ grid = grid.numpy()
+ grid = (grid * 255).astype(np.uint8)
+ filename = "{}_gs-{:06}_e-{:06}_b-{:06}.png".format(
+ k,
+ global_step,
+ current_epoch,
+ batch_idx)
+ path = os.path.join(root, filename)
+ os.makedirs(os.path.split(path)[0], exist_ok=True)
+ Image.fromarray(grid).save(path)
+
+ def log_img(self, pl_module, batch, batch_idx, split="train"):
+ check_idx = batch_idx if self.log_on_batch_idx else pl_module.global_step
+ if (self.check_frequency(check_idx) and # batch_idx % self.batch_freq == 0
+ hasattr(pl_module, "log_images") and
+ callable(pl_module.log_images) and
+ self.max_images > 0):
+ logger = type(pl_module.logger)
+
+ is_train = pl_module.training
+ if is_train:
+ pl_module.eval()
+
+ with torch.no_grad():
+ images = pl_module.log_images(batch, split=split, **self.log_images_kwargs)
+
+ for k in images:
+ N = min(images[k].shape[0], self.max_images)
+ images[k] = images[k][:N]
+ if isinstance(images[k], torch.Tensor):
+ images[k] = images[k].detach().cpu()
+ if self.clamp:
+ images[k] = torch.clamp(images[k], -1., 1.)
+
+ self.log_local(pl_module.logger.save_dir, split, images,
+ pl_module.global_step, pl_module.current_epoch, batch_idx)
+
+ logger_log_images = self.logger_log_images.get(logger, lambda *args, **kwargs: None)
+ logger_log_images(pl_module, images, pl_module.global_step, split)
+
+ if is_train:
+ pl_module.train()
+
+ def check_frequency(self, check_idx):
+ if ((check_idx % self.batch_freq) == 0 or (check_idx in self.log_steps)) and (
+ check_idx > 0 or self.log_first_step):
+ try:
+ self.log_steps.pop(0)
+ except IndexError as e:
+ print(e)
+ pass
+ return True
+ return False
+
+ def on_train_batch_end(self, trainer, pl_module, outputs, batch, batch_idx, dataloader_idx):
+ if not self.disabled and (pl_module.global_step > 0 or self.log_first_step):
+ self.log_img(pl_module, batch, batch_idx, split="train")
+
+ def on_validation_batch_end(self, trainer, pl_module, outputs, batch, batch_idx, dataloader_idx):
+ if not self.disabled and pl_module.global_step > 0:
+ self.log_img(pl_module, batch, batch_idx, split="val")
+ if hasattr(pl_module, 'calibrate_grad_norm'):
+ if (pl_module.calibrate_grad_norm and batch_idx % 25 == 0) and batch_idx > 0:
+ self.log_gradients(trainer, pl_module, batch_idx=batch_idx)
+
+
+class CUDACallback(Callback):
+ # see https://github.com/SeanNaren/minGPT/blob/master/mingpt/callback.py
+ def on_train_epoch_start(self, trainer, pl_module):
+ # Reset the memory use counter
+ torch.cuda.reset_peak_memory_stats(trainer.root_gpu)
+ torch.cuda.synchronize(trainer.root_gpu)
+ self.start_time = time.time()
+
+ def on_train_epoch_end(self, trainer, pl_module, outputs):
+ torch.cuda.synchronize(trainer.root_gpu)
+ max_memory = torch.cuda.max_memory_allocated(trainer.root_gpu) / 2 ** 20
+ epoch_time = time.time() - self.start_time
+
+ try:
+ max_memory = trainer.training_type_plugin.reduce(max_memory)
+ epoch_time = trainer.training_type_plugin.reduce(epoch_time)
+
+ rank_zero_info(f"Average Epoch time: {epoch_time:.2f} seconds")
+ rank_zero_info(f"Average Peak memory {max_memory:.2f}MiB")
+ except AttributeError:
+ pass
+
+
+if __name__ == "__main__":
+ # custom parser to specify config files, train, test and debug mode,
+ # postfix, resume.
+ # `--key value` arguments are interpreted as arguments to the trainer.
+ # `nested.key=value` arguments are interpreted as config parameters.
+ # configs are merged from left-to-right followed by command line parameters.
+
+ # model:
+ # base_learning_rate: float
+ # target: path to lightning module
+ # params:
+ # key: value
+ # data:
+ # target: main.DataModuleFromConfig
+ # params:
+ # batch_size: int
+ # wrap: bool
+ # train:
+ # target: path to train dataset
+ # params:
+ # key: value
+ # validation:
+ # target: path to validation dataset
+ # params:
+ # key: value
+ # test:
+ # target: path to test dataset
+ # params:
+ # key: value
+ # lightning: (optional, has sane defaults and can be specified on cmdline)
+ # trainer:
+ # additional arguments to trainer
+ # logger:
+ # logger to instantiate
+ # modelcheckpoint:
+ # modelcheckpoint to instantiate
+ # callbacks:
+ # callback1:
+ # target: importpath
+ # params:
+ # key: value
+
+ now = datetime.datetime.now().strftime("%Y-%m-%dT%H-%M-%S")
+
+ # add cwd for convenience and to make classes in this file available when
+ # running as `python main.py`
+ # (in particular `main.DataModuleFromConfig`)
+ sys.path.append(os.getcwd())
+
+ parser = get_parser()
+ parser = Trainer.add_argparse_args(parser)
+
+ opt, unknown = parser.parse_known_args()
+ if opt.name and opt.resume:
+ raise ValueError(
+ "-n/--name and -r/--resume cannot be specified both."
+ "If you want to resume training in a new log folder, "
+ "use -n/--name in combination with --resume_from_checkpoint"
+ )
+ if opt.resume:
+ if not os.path.exists(opt.resume):
+ raise ValueError("Cannot find {}".format(opt.resume))
+ if os.path.isfile(opt.resume):
+ paths = opt.resume.split("/")
+ # idx = len(paths)-paths[::-1].index("logs")+1
+ # logdir = "/".join(paths[:idx])
+ logdir = "/".join(paths[:-2])
+ ckpt = opt.resume
+ else:
+ assert os.path.isdir(opt.resume), opt.resume
+ logdir = opt.resume.rstrip("/")
+ ckpt = os.path.join(logdir, "checkpoints", "last.ckpt")
+
+ opt.resume_from_checkpoint = ckpt
+ base_configs = sorted(glob.glob(os.path.join(logdir, "configs/*.yaml")))
+ opt.base = base_configs + opt.base
+ _tmp = logdir.split("/")
+ nowname = _tmp[-1]
+ else:
+ if opt.name:
+ name = "_" + opt.name
+ elif opt.base:
+ cfg_fname = os.path.split(opt.base[0])[-1]
+ cfg_name = os.path.splitext(cfg_fname)[0]
+ name = "_" + cfg_name
+ else:
+ name = ""
+ nowname = now + name + opt.postfix
+ logdir = os.path.join(opt.logdir, nowname)
+
+ ckptdir = os.path.join(logdir, "checkpoints")
+ cfgdir = os.path.join(logdir, "configs")
+ seed_everything(opt.seed)
+
+ try:
+ # init and save configs
+ configs = [OmegaConf.load(cfg) for cfg in opt.base]
+ cli = OmegaConf.from_dotlist(unknown)
+ config = OmegaConf.merge(*configs, cli)
+ lightning_config = config.pop("lightning", OmegaConf.create())
+ # merge trainer cli with config
+ trainer_config = lightning_config.get("trainer", OmegaConf.create())
+ # default to ddp
+ trainer_config["accelerator"] = "ddp"
+ for k in nondefault_trainer_args(opt):
+ trainer_config[k] = getattr(opt, k)
+ if not "gpus" in trainer_config:
+ del trainer_config["accelerator"]
+ cpu = True
+ else:
+ gpuinfo = trainer_config["gpus"]
+ print(f"Running on GPUs {gpuinfo}")
+ cpu = False
+ trainer_opt = argparse.Namespace(**trainer_config)
+ lightning_config.trainer = trainer_config
+
+ # model
+ model = instantiate_from_config(config.model)
+
+ # trainer and callbacks
+ trainer_kwargs = dict()
+
+ # default logger configs
+ default_logger_cfgs = {
+ "wandb": {
+ "target": "pytorch_lightning.loggers.WandbLogger",
+ "params": {
+ "name": nowname,
+ "save_dir": logdir,
+ "offline": opt.debug,
+ "id": nowname,
+ }
+ },
+ "testtube": {
+ "target": "pytorch_lightning.loggers.TestTubeLogger",
+ "params": {
+ "name": "testtube",
+ "save_dir": logdir,
+ }
+ },
+ }
+ default_logger_cfg = default_logger_cfgs["testtube"]
+ if "logger" in lightning_config:
+ logger_cfg = lightning_config.logger
+ else:
+ logger_cfg = OmegaConf.create()
+ logger_cfg = OmegaConf.merge(default_logger_cfg, logger_cfg)
+ trainer_kwargs["logger"] = instantiate_from_config(logger_cfg)
+
+ # modelcheckpoint - use TrainResult/EvalResult(checkpoint_on=metric) to
+ # specify which metric is used to determine best models
+ default_modelckpt_cfg = {
+ "target": "pytorch_lightning.callbacks.ModelCheckpoint",
+ "params": {
+ "dirpath": ckptdir,
+ "filename": "{epoch:06}",
+ "verbose": True,
+ "save_last": True,
+ }
+ }
+ if hasattr(model, "monitor"):
+ print(f"Monitoring {model.monitor} as checkpoint metric.")
+ default_modelckpt_cfg["params"]["monitor"] = model.monitor
+ default_modelckpt_cfg["params"]["save_top_k"] = 3
+
+ if "modelcheckpoint" in lightning_config:
+ modelckpt_cfg = lightning_config.modelcheckpoint
+ else:
+ modelckpt_cfg = OmegaConf.create()
+ modelckpt_cfg = OmegaConf.merge(default_modelckpt_cfg, modelckpt_cfg)
+ print(f"Merged modelckpt-cfg: \n{modelckpt_cfg}")
+ if version.parse(pl.__version__) < version.parse('1.4.0'):
+ trainer_kwargs["checkpoint_callback"] = instantiate_from_config(modelckpt_cfg)
+
+ # add callback which sets up log directory
+ default_callbacks_cfg = {
+ "setup_callback": {
+ "target": "main.SetupCallback",
+ "params": {
+ "resume": opt.resume,
+ "now": now,
+ "logdir": logdir,
+ "ckptdir": ckptdir,
+ "cfgdir": cfgdir,
+ "config": config,
+ "lightning_config": lightning_config,
+ }
+ },
+ "image_logger": {
+ "target": "main.ImageLogger",
+ "params": {
+ "batch_frequency": 750,
+ "max_images": 4,
+ "clamp": True
+ }
+ },
+ "learning_rate_logger": {
+ "target": "main.LearningRateMonitor",
+ "params": {
+ "logging_interval": "step",
+ # "log_momentum": True
+ }
+ },
+ "cuda_callback": {
+ "target": "main.CUDACallback"
+ },
+ }
+ if version.parse(pl.__version__) >= version.parse('1.4.0'):
+ default_callbacks_cfg.update({'checkpoint_callback': modelckpt_cfg})
+
+ if "callbacks" in lightning_config:
+ callbacks_cfg = lightning_config.callbacks
+ else:
+ callbacks_cfg = OmegaConf.create()
+
+ if 'metrics_over_trainsteps_checkpoint' in callbacks_cfg:
+ print(
+ 'Caution: Saving checkpoints every n train steps without deleting. This might require some free space.')
+ default_metrics_over_trainsteps_ckpt_dict = {
+ 'metrics_over_trainsteps_checkpoint':
+ {"target": 'pytorch_lightning.callbacks.ModelCheckpoint',
+ 'params': {
+ "dirpath": os.path.join(ckptdir, 'trainstep_checkpoints'),
+ "filename": "{epoch:06}-{step:09}",
+ "verbose": True,
+ 'save_top_k': -1,
+ 'every_n_train_steps': 10000,
+ 'save_weights_only': True
+ }
+ }
+ }
+ default_callbacks_cfg.update(default_metrics_over_trainsteps_ckpt_dict)
+
+ callbacks_cfg = OmegaConf.merge(default_callbacks_cfg, callbacks_cfg)
+ if 'ignore_keys_callback' in callbacks_cfg and hasattr(trainer_opt, 'resume_from_checkpoint'):
+ callbacks_cfg.ignore_keys_callback.params['ckpt_path'] = trainer_opt.resume_from_checkpoint
+ elif 'ignore_keys_callback' in callbacks_cfg:
+ del callbacks_cfg['ignore_keys_callback']
+
+ trainer_kwargs["callbacks"] = [instantiate_from_config(callbacks_cfg[k]) for k in callbacks_cfg]
+
+ trainer = Trainer.from_argparse_args(trainer_opt, **trainer_kwargs)
+ trainer.logdir = logdir ###
+
+ # data
+ data = instantiate_from_config(config.data)
+ # NOTE according to https://pytorch-lightning.readthedocs.io/en/latest/datamodules.html
+ # calling these ourselves should not be necessary but it is.
+ # lightning still takes care of proper multiprocessing though
+ data.prepare_data()
+ data.setup()
+ print("#### Data #####")
+ for k in data.datasets:
+ print(f"{k}, {data.datasets[k].__class__.__name__}, {len(data.datasets[k])}")
+
+ # configure learning rate
+ bs, base_lr = config.data.params.batch_size, config.model.base_learning_rate
+ if not cpu:
+ ngpu = len(lightning_config.trainer.gpus.strip(",").split(','))
+ else:
+ ngpu = 1
+ if 'accumulate_grad_batches' in lightning_config.trainer:
+ accumulate_grad_batches = lightning_config.trainer.accumulate_grad_batches
+ else:
+ accumulate_grad_batches = 1
+ print(f"accumulate_grad_batches = {accumulate_grad_batches}")
+ lightning_config.trainer.accumulate_grad_batches = accumulate_grad_batches
+ if opt.scale_lr:
+ model.learning_rate = accumulate_grad_batches * ngpu * bs * base_lr
+ print(
+ "Setting learning rate to {:.2e} = {} (accumulate_grad_batches) * {} (num_gpus) * {} (batchsize) * {:.2e} (base_lr)".format(
+ model.learning_rate, accumulate_grad_batches, ngpu, bs, base_lr))
+ else:
+ model.learning_rate = base_lr
+ print("++++ NOT USING LR SCALING ++++")
+ print(f"Setting learning rate to {model.learning_rate:.2e}")
+
+
+ # allow checkpointing via USR1
+ def melk(*args, **kwargs):
+ # run all checkpoint hooks
+ if trainer.global_rank == 0:
+ print("Summoning checkpoint.")
+ ckpt_path = os.path.join(ckptdir, "last.ckpt")
+ trainer.save_checkpoint(ckpt_path)
+
+
+ def divein(*args, **kwargs):
+ if trainer.global_rank == 0:
+ import pudb;
+ pudb.set_trace()
+
+
+ import signal
+
+ signal.signal(signal.SIGUSR1, melk)
+ signal.signal(signal.SIGUSR2, divein)
+
+ # run
+ if opt.train:
+ try:
+ trainer.fit(model, data)
+ except Exception:
+ melk()
+ raise
+ if not opt.no_test and not trainer.interrupted:
+ trainer.test(model, data)
+ except Exception:
+ if opt.debug and trainer.global_rank == 0:
+ try:
+ import pudb as debugger
+ except ImportError:
+ import pdb as debugger
+ debugger.post_mortem()
+ raise
+ finally:
+ # move newly created debug project to debug_runs
+ if opt.debug and not opt.resume and trainer.global_rank == 0:
+ dst, name = os.path.split(logdir)
+ dst = os.path.join(dst, "debug_runs", name)
+ os.makedirs(os.path.split(dst)[0], exist_ok=True)
+ os.rename(logdir, dst)
+ if trainer.global_rank == 0:
+ print(trainer.profiler.summary())
diff --git a/latent-diffusion/models/first_stage_models/kl-f16/config.yaml b/latent-diffusion/models/first_stage_models/kl-f16/config.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..661921cf75a0b803c5eca41039dd058e24930452
--- /dev/null
+++ b/latent-diffusion/models/first_stage_models/kl-f16/config.yaml
@@ -0,0 +1,44 @@
+model:
+ base_learning_rate: 4.5e-06
+ target: ldm.models.autoencoder.AutoencoderKL
+ params:
+ monitor: val/rec_loss
+ embed_dim: 16
+ lossconfig:
+ target: ldm.modules.losses.LPIPSWithDiscriminator
+ params:
+ disc_start: 50001
+ kl_weight: 1.0e-06
+ disc_weight: 0.5
+ ddconfig:
+ double_z: true
+ z_channels: 16
+ resolution: 256
+ in_channels: 3
+ out_ch: 3
+ ch: 128
+ ch_mult:
+ - 1
+ - 1
+ - 2
+ - 2
+ - 4
+ num_res_blocks: 2
+ attn_resolutions:
+ - 16
+ dropout: 0.0
+data:
+ target: main.DataModuleFromConfig
+ params:
+ batch_size: 6
+ wrap: true
+ train:
+ target: ldm.data.openimages.FullOpenImagesTrain
+ params:
+ size: 384
+ crop_size: 256
+ validation:
+ target: ldm.data.openimages.FullOpenImagesValidation
+ params:
+ size: 384
+ crop_size: 256
diff --git a/latent-diffusion/models/first_stage_models/kl-f32/config.yaml b/latent-diffusion/models/first_stage_models/kl-f32/config.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..7b642b136aaaf909ccd8766372eeffc4dffec342
--- /dev/null
+++ b/latent-diffusion/models/first_stage_models/kl-f32/config.yaml
@@ -0,0 +1,46 @@
+model:
+ base_learning_rate: 4.5e-06
+ target: ldm.models.autoencoder.AutoencoderKL
+ params:
+ monitor: val/rec_loss
+ embed_dim: 64
+ lossconfig:
+ target: ldm.modules.losses.LPIPSWithDiscriminator
+ params:
+ disc_start: 50001
+ kl_weight: 1.0e-06
+ disc_weight: 0.5
+ ddconfig:
+ double_z: true
+ z_channels: 64
+ resolution: 256
+ in_channels: 3
+ out_ch: 3
+ ch: 128
+ ch_mult:
+ - 1
+ - 1
+ - 2
+ - 2
+ - 4
+ - 4
+ num_res_blocks: 2
+ attn_resolutions:
+ - 16
+ - 8
+ dropout: 0.0
+data:
+ target: main.DataModuleFromConfig
+ params:
+ batch_size: 6
+ wrap: true
+ train:
+ target: ldm.data.openimages.FullOpenImagesTrain
+ params:
+ size: 384
+ crop_size: 256
+ validation:
+ target: ldm.data.openimages.FullOpenImagesValidation
+ params:
+ size: 384
+ crop_size: 256
diff --git a/latent-diffusion/models/first_stage_models/kl-f4/config.yaml b/latent-diffusion/models/first_stage_models/kl-f4/config.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..85cfb3e94e2ffa867ab49af82fcd8a4dc238e2ad
--- /dev/null
+++ b/latent-diffusion/models/first_stage_models/kl-f4/config.yaml
@@ -0,0 +1,41 @@
+model:
+ base_learning_rate: 4.5e-06
+ target: ldm.models.autoencoder.AutoencoderKL
+ params:
+ monitor: val/rec_loss
+ embed_dim: 3
+ lossconfig:
+ target: ldm.modules.losses.LPIPSWithDiscriminator
+ params:
+ disc_start: 50001
+ kl_weight: 1.0e-06
+ disc_weight: 0.5
+ ddconfig:
+ double_z: true
+ z_channels: 3
+ resolution: 256
+ in_channels: 3
+ out_ch: 3
+ ch: 128
+ ch_mult:
+ - 1
+ - 2
+ - 4
+ num_res_blocks: 2
+ attn_resolutions: []
+ dropout: 0.0
+data:
+ target: main.DataModuleFromConfig
+ params:
+ batch_size: 10
+ wrap: true
+ train:
+ target: ldm.data.openimages.FullOpenImagesTrain
+ params:
+ size: 384
+ crop_size: 256
+ validation:
+ target: ldm.data.openimages.FullOpenImagesValidation
+ params:
+ size: 384
+ crop_size: 256
diff --git a/latent-diffusion/models/first_stage_models/kl-f8/config.yaml b/latent-diffusion/models/first_stage_models/kl-f8/config.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..921aa425335aced7a1a53307d39da0eba267efd6
--- /dev/null
+++ b/latent-diffusion/models/first_stage_models/kl-f8/config.yaml
@@ -0,0 +1,42 @@
+model:
+ base_learning_rate: 4.5e-06
+ target: ldm.models.autoencoder.AutoencoderKL
+ params:
+ monitor: val/rec_loss
+ embed_dim: 4
+ lossconfig:
+ target: ldm.modules.losses.LPIPSWithDiscriminator
+ params:
+ disc_start: 50001
+ kl_weight: 1.0e-06
+ disc_weight: 0.5
+ ddconfig:
+ double_z: true
+ z_channels: 4
+ resolution: 256
+ in_channels: 3
+ out_ch: 3
+ ch: 128
+ ch_mult:
+ - 1
+ - 2
+ - 4
+ - 4
+ num_res_blocks: 2
+ attn_resolutions: []
+ dropout: 0.0
+data:
+ target: main.DataModuleFromConfig
+ params:
+ batch_size: 4
+ wrap: true
+ train:
+ target: ldm.data.openimages.FullOpenImagesTrain
+ params:
+ size: 384
+ crop_size: 256
+ validation:
+ target: ldm.data.openimages.FullOpenImagesValidation
+ params:
+ size: 384
+ crop_size: 256
diff --git a/latent-diffusion/models/first_stage_models/vq-f16/config.yaml b/latent-diffusion/models/first_stage_models/vq-f16/config.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..91c74549064bfd158424cba9c79cd2618395fc9f
--- /dev/null
+++ b/latent-diffusion/models/first_stage_models/vq-f16/config.yaml
@@ -0,0 +1,49 @@
+model:
+ base_learning_rate: 4.5e-06
+ target: ldm.models.autoencoder.VQModel
+ params:
+ embed_dim: 8
+ n_embed: 16384
+ ddconfig:
+ double_z: false
+ z_channels: 8
+ resolution: 256
+ in_channels: 3
+ out_ch: 3
+ ch: 128
+ ch_mult:
+ - 1
+ - 1
+ - 2
+ - 2
+ - 4
+ num_res_blocks: 2
+ attn_resolutions:
+ - 16
+ dropout: 0.0
+ lossconfig:
+ target: taming.modules.losses.vqperceptual.VQLPIPSWithDiscriminator
+ params:
+ disc_conditional: false
+ disc_in_channels: 3
+ disc_start: 250001
+ disc_weight: 0.75
+ disc_num_layers: 2
+ codebook_weight: 1.0
+
+data:
+ target: main.DataModuleFromConfig
+ params:
+ batch_size: 14
+ num_workers: 20
+ wrap: true
+ train:
+ target: ldm.data.openimages.FullOpenImagesTrain
+ params:
+ size: 384
+ crop_size: 256
+ validation:
+ target: ldm.data.openimages.FullOpenImagesValidation
+ params:
+ size: 384
+ crop_size: 256
diff --git a/latent-diffusion/models/first_stage_models/vq-f4-noattn/config.yaml b/latent-diffusion/models/first_stage_models/vq-f4-noattn/config.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..f8e499fa2aa891ea18f2cdbdd423c22bc1db6901
--- /dev/null
+++ b/latent-diffusion/models/first_stage_models/vq-f4-noattn/config.yaml
@@ -0,0 +1,46 @@
+model:
+ base_learning_rate: 4.5e-06
+ target: ldm.models.autoencoder.VQModel
+ params:
+ embed_dim: 3
+ n_embed: 8192
+ monitor: val/rec_loss
+
+ ddconfig:
+ attn_type: none
+ double_z: false
+ z_channels: 3
+ resolution: 256
+ in_channels: 3
+ out_ch: 3
+ ch: 128
+ ch_mult:
+ - 1
+ - 2
+ - 4
+ num_res_blocks: 2
+ attn_resolutions: []
+ dropout: 0.0
+ lossconfig:
+ target: taming.modules.losses.vqperceptual.VQLPIPSWithDiscriminator
+ params:
+ disc_conditional: false
+ disc_in_channels: 3
+ disc_start: 11
+ disc_weight: 0.75
+ codebook_weight: 1.0
+
+data:
+ target: main.DataModuleFromConfig
+ params:
+ batch_size: 8
+ num_workers: 12
+ wrap: true
+ train:
+ target: ldm.data.openimages.FullOpenImagesTrain
+ params:
+ crop_size: 256
+ validation:
+ target: ldm.data.openimages.FullOpenImagesValidation
+ params:
+ crop_size: 256
diff --git a/latent-diffusion/models/first_stage_models/vq-f4/config.yaml b/latent-diffusion/models/first_stage_models/vq-f4/config.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..7d8cef3252742d70855d1a0df011a82223c17c4f
--- /dev/null
+++ b/latent-diffusion/models/first_stage_models/vq-f4/config.yaml
@@ -0,0 +1,45 @@
+model:
+ base_learning_rate: 4.5e-06
+ target: ldm.models.autoencoder.VQModel
+ params:
+ embed_dim: 3
+ n_embed: 8192
+ monitor: val/rec_loss
+
+ ddconfig:
+ double_z: false
+ z_channels: 3
+ resolution: 256
+ in_channels: 3
+ out_ch: 3
+ ch: 128
+ ch_mult:
+ - 1
+ - 2
+ - 4
+ num_res_blocks: 2
+ attn_resolutions: []
+ dropout: 0.0
+ lossconfig:
+ target: taming.modules.losses.vqperceptual.VQLPIPSWithDiscriminator
+ params:
+ disc_conditional: false
+ disc_in_channels: 3
+ disc_start: 0
+ disc_weight: 0.75
+ codebook_weight: 1.0
+
+data:
+ target: main.DataModuleFromConfig
+ params:
+ batch_size: 8
+ num_workers: 16
+ wrap: true
+ train:
+ target: ldm.data.openimages.FullOpenImagesTrain
+ params:
+ crop_size: 256
+ validation:
+ target: ldm.data.openimages.FullOpenImagesValidation
+ params:
+ crop_size: 256
diff --git a/latent-diffusion/models/first_stage_models/vq-f8-n256/config.yaml b/latent-diffusion/models/first_stage_models/vq-f8-n256/config.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..8519e13d618fe04792e59fc6eb826c1804fcdc28
--- /dev/null
+++ b/latent-diffusion/models/first_stage_models/vq-f8-n256/config.yaml
@@ -0,0 +1,48 @@
+model:
+ base_learning_rate: 4.5e-06
+ target: ldm.models.autoencoder.VQModel
+ params:
+ embed_dim: 4
+ n_embed: 256
+ monitor: val/rec_loss
+ ddconfig:
+ double_z: false
+ z_channels: 4
+ resolution: 256
+ in_channels: 3
+ out_ch: 3
+ ch: 128
+ ch_mult:
+ - 1
+ - 2
+ - 2
+ - 4
+ num_res_blocks: 2
+ attn_resolutions:
+ - 32
+ dropout: 0.0
+ lossconfig:
+ target: taming.modules.losses.vqperceptual.VQLPIPSWithDiscriminator
+ params:
+ disc_conditional: false
+ disc_in_channels: 3
+ disc_start: 250001
+ disc_weight: 0.75
+ codebook_weight: 1.0
+
+data:
+ target: main.DataModuleFromConfig
+ params:
+ batch_size: 10
+ num_workers: 20
+ wrap: true
+ train:
+ target: ldm.data.openimages.FullOpenImagesTrain
+ params:
+ size: 384
+ crop_size: 256
+ validation:
+ target: ldm.data.openimages.FullOpenImagesValidation
+ params:
+ size: 384
+ crop_size: 256
diff --git a/latent-diffusion/models/first_stage_models/vq-f8/config.yaml b/latent-diffusion/models/first_stage_models/vq-f8/config.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..efd6801ca965baf7119b171de8338bd16e120332
--- /dev/null
+++ b/latent-diffusion/models/first_stage_models/vq-f8/config.yaml
@@ -0,0 +1,48 @@
+model:
+ base_learning_rate: 4.5e-06
+ target: ldm.models.autoencoder.VQModel
+ params:
+ embed_dim: 4
+ n_embed: 16384
+ monitor: val/rec_loss
+ ddconfig:
+ double_z: false
+ z_channels: 4
+ resolution: 256
+ in_channels: 3
+ out_ch: 3
+ ch: 128
+ ch_mult:
+ - 1
+ - 2
+ - 2
+ - 4
+ num_res_blocks: 2
+ attn_resolutions:
+ - 32
+ dropout: 0.0
+ lossconfig:
+ target: taming.modules.losses.vqperceptual.VQLPIPSWithDiscriminator
+ params:
+ disc_conditional: false
+ disc_in_channels: 3
+ disc_num_layers: 2
+ disc_start: 1
+ disc_weight: 0.6
+ codebook_weight: 1.0
+data:
+ target: main.DataModuleFromConfig
+ params:
+ batch_size: 10
+ num_workers: 20
+ wrap: true
+ train:
+ target: ldm.data.openimages.FullOpenImagesTrain
+ params:
+ size: 384
+ crop_size: 256
+ validation:
+ target: ldm.data.openimages.FullOpenImagesValidation
+ params:
+ size: 384
+ crop_size: 256
diff --git a/latent-diffusion/models/ldm/bsr_sr/config.yaml b/latent-diffusion/models/ldm/bsr_sr/config.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..861692a8d10b1764519576fd12200524faa32753
--- /dev/null
+++ b/latent-diffusion/models/ldm/bsr_sr/config.yaml
@@ -0,0 +1,80 @@
+model:
+ base_learning_rate: 1.0e-06
+ target: ldm.models.diffusion.ddpm.LatentDiffusion
+ params:
+ linear_start: 0.0015
+ linear_end: 0.0155
+ log_every_t: 100
+ timesteps: 1000
+ loss_type: l2
+ first_stage_key: image
+ cond_stage_key: LR_image
+ image_size: 64
+ channels: 3
+ concat_mode: true
+ cond_stage_trainable: false
+ unet_config:
+ target: ldm.modules.diffusionmodules.openaimodel.UNetModel
+ params:
+ image_size: 64
+ in_channels: 6
+ out_channels: 3
+ model_channels: 160
+ attention_resolutions:
+ - 16
+ - 8
+ num_res_blocks: 2
+ channel_mult:
+ - 1
+ - 2
+ - 2
+ - 4
+ num_head_channels: 32
+ first_stage_config:
+ target: ldm.models.autoencoder.VQModelInterface
+ params:
+ embed_dim: 3
+ n_embed: 8192
+ monitor: val/rec_loss
+ ddconfig:
+ double_z: false
+ z_channels: 3
+ resolution: 256
+ in_channels: 3
+ out_ch: 3
+ ch: 128
+ ch_mult:
+ - 1
+ - 2
+ - 4
+ num_res_blocks: 2
+ attn_resolutions: []
+ dropout: 0.0
+ lossconfig:
+ target: torch.nn.Identity
+ cond_stage_config:
+ target: torch.nn.Identity
+data:
+ target: main.DataModuleFromConfig
+ params:
+ batch_size: 64
+ wrap: false
+ num_workers: 12
+ train:
+ target: ldm.data.openimages.SuperresOpenImagesAdvancedTrain
+ params:
+ size: 256
+ degradation: bsrgan_light
+ downscale_f: 4
+ min_crop_f: 0.5
+ max_crop_f: 1.0
+ random_crop: true
+ validation:
+ target: ldm.data.openimages.SuperresOpenImagesAdvancedValidation
+ params:
+ size: 256
+ degradation: bsrgan_light
+ downscale_f: 4
+ min_crop_f: 0.5
+ max_crop_f: 1.0
+ random_crop: true
diff --git a/latent-diffusion/models/ldm/celeba256/config.yaml b/latent-diffusion/models/ldm/celeba256/config.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..a12f4e9d399afe23e6bcc824bddc8bad7ee5456d
--- /dev/null
+++ b/latent-diffusion/models/ldm/celeba256/config.yaml
@@ -0,0 +1,70 @@
+model:
+ base_learning_rate: 2.0e-06
+ target: ldm.models.diffusion.ddpm.LatentDiffusion
+ params:
+ linear_start: 0.0015
+ linear_end: 0.0195
+ num_timesteps_cond: 1
+ log_every_t: 200
+ timesteps: 1000
+ first_stage_key: image
+ cond_stage_key: class_label
+ image_size: 64
+ channels: 3
+ cond_stage_trainable: false
+ concat_mode: false
+ monitor: val/loss
+ unet_config:
+ target: ldm.modules.diffusionmodules.openaimodel.UNetModel
+ params:
+ image_size: 64
+ in_channels: 3
+ out_channels: 3
+ model_channels: 224
+ attention_resolutions:
+ - 8
+ - 4
+ - 2
+ num_res_blocks: 2
+ channel_mult:
+ - 1
+ - 2
+ - 3
+ - 4
+ num_head_channels: 32
+ first_stage_config:
+ target: ldm.models.autoencoder.VQModelInterface
+ params:
+ embed_dim: 3
+ n_embed: 8192
+ ddconfig:
+ double_z: false
+ z_channels: 3
+ resolution: 256
+ in_channels: 3
+ out_ch: 3
+ ch: 128
+ ch_mult:
+ - 1
+ - 2
+ - 4
+ num_res_blocks: 2
+ attn_resolutions: []
+ dropout: 0.0
+ lossconfig:
+ target: torch.nn.Identity
+ cond_stage_config: __is_unconditional__
+data:
+ target: main.DataModuleFromConfig
+ params:
+ batch_size: 48
+ num_workers: 5
+ wrap: false
+ train:
+ target: ldm.data.faceshq.CelebAHQTrain
+ params:
+ size: 256
+ validation:
+ target: ldm.data.faceshq.CelebAHQValidation
+ params:
+ size: 256
diff --git a/latent-diffusion/models/ldm/cin256/config.yaml b/latent-diffusion/models/ldm/cin256/config.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..9bc1b4566af8b53a2a20eb2b6dc68445f5fb4eb8
--- /dev/null
+++ b/latent-diffusion/models/ldm/cin256/config.yaml
@@ -0,0 +1,80 @@
+model:
+ base_learning_rate: 1.0e-06
+ target: ldm.models.diffusion.ddpm.LatentDiffusion
+ params:
+ linear_start: 0.0015
+ linear_end: 0.0195
+ num_timesteps_cond: 1
+ log_every_t: 200
+ timesteps: 1000
+ first_stage_key: image
+ cond_stage_key: class_label
+ image_size: 32
+ channels: 4
+ cond_stage_trainable: true
+ conditioning_key: crossattn
+ monitor: val/loss_simple_ema
+ unet_config:
+ target: ldm.modules.diffusionmodules.openaimodel.UNetModel
+ params:
+ image_size: 32
+ in_channels: 4
+ out_channels: 4
+ model_channels: 256
+ attention_resolutions:
+ - 4
+ - 2
+ - 1
+ num_res_blocks: 2
+ channel_mult:
+ - 1
+ - 2
+ - 4
+ num_head_channels: 32
+ use_spatial_transformer: true
+ transformer_depth: 1
+ context_dim: 512
+ first_stage_config:
+ target: ldm.models.autoencoder.VQModelInterface
+ params:
+ embed_dim: 4
+ n_embed: 16384
+ ddconfig:
+ double_z: false
+ z_channels: 4
+ resolution: 256
+ in_channels: 3
+ out_ch: 3
+ ch: 128
+ ch_mult:
+ - 1
+ - 2
+ - 2
+ - 4
+ num_res_blocks: 2
+ attn_resolutions:
+ - 32
+ dropout: 0.0
+ lossconfig:
+ target: torch.nn.Identity
+ cond_stage_config:
+ target: ldm.modules.encoders.modules.ClassEmbedder
+ params:
+ embed_dim: 512
+ key: class_label
+data:
+ target: main.DataModuleFromConfig
+ params:
+ batch_size: 64
+ num_workers: 12
+ wrap: false
+ train:
+ target: ldm.data.imagenet.ImageNetTrain
+ params:
+ config:
+ size: 256
+ validation:
+ target: ldm.data.imagenet.ImageNetValidation
+ params:
+ config:
+ size: 256
diff --git a/latent-diffusion/models/ldm/ffhq256/config.yaml b/latent-diffusion/models/ldm/ffhq256/config.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..0ddfd1b93e8e52c9de2e981f9f4bbaf83e75b38e
--- /dev/null
+++ b/latent-diffusion/models/ldm/ffhq256/config.yaml
@@ -0,0 +1,70 @@
+model:
+ base_learning_rate: 2.0e-06
+ target: ldm.models.diffusion.ddpm.LatentDiffusion
+ params:
+ linear_start: 0.0015
+ linear_end: 0.0195
+ num_timesteps_cond: 1
+ log_every_t: 200
+ timesteps: 1000
+ first_stage_key: image
+ cond_stage_key: class_label
+ image_size: 64
+ channels: 3
+ cond_stage_trainable: false
+ concat_mode: false
+ monitor: val/loss
+ unet_config:
+ target: ldm.modules.diffusionmodules.openaimodel.UNetModel
+ params:
+ image_size: 64
+ in_channels: 3
+ out_channels: 3
+ model_channels: 224
+ attention_resolutions:
+ - 8
+ - 4
+ - 2
+ num_res_blocks: 2
+ channel_mult:
+ - 1
+ - 2
+ - 3
+ - 4
+ num_head_channels: 32
+ first_stage_config:
+ target: ldm.models.autoencoder.VQModelInterface
+ params:
+ embed_dim: 3
+ n_embed: 8192
+ ddconfig:
+ double_z: false
+ z_channels: 3
+ resolution: 256
+ in_channels: 3
+ out_ch: 3
+ ch: 128
+ ch_mult:
+ - 1
+ - 2
+ - 4
+ num_res_blocks: 2
+ attn_resolutions: []
+ dropout: 0.0
+ lossconfig:
+ target: torch.nn.Identity
+ cond_stage_config: __is_unconditional__
+data:
+ target: main.DataModuleFromConfig
+ params:
+ batch_size: 42
+ num_workers: 5
+ wrap: false
+ train:
+ target: ldm.data.faceshq.FFHQTrain
+ params:
+ size: 256
+ validation:
+ target: ldm.data.faceshq.FFHQValidation
+ params:
+ size: 256
diff --git a/latent-diffusion/models/ldm/inpainting_big/config.yaml b/latent-diffusion/models/ldm/inpainting_big/config.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..da5fd5ea508ea0998b75519bc297411946e4a5bb
--- /dev/null
+++ b/latent-diffusion/models/ldm/inpainting_big/config.yaml
@@ -0,0 +1,67 @@
+model:
+ base_learning_rate: 1.0e-06
+ target: ldm.models.diffusion.ddpm.LatentDiffusion
+ params:
+ linear_start: 0.0015
+ linear_end: 0.0205
+ log_every_t: 100
+ timesteps: 1000
+ loss_type: l1
+ first_stage_key: image
+ cond_stage_key: masked_image
+ image_size: 64
+ channels: 3
+ concat_mode: true
+ monitor: val/loss
+ scheduler_config:
+ target: ldm.lr_scheduler.LambdaWarmUpCosineScheduler
+ params:
+ verbosity_interval: 0
+ warm_up_steps: 1000
+ max_decay_steps: 50000
+ lr_start: 0.001
+ lr_max: 0.1
+ lr_min: 0.0001
+ unet_config:
+ target: ldm.modules.diffusionmodules.openaimodel.UNetModel
+ params:
+ image_size: 64
+ in_channels: 7
+ out_channels: 3
+ model_channels: 256
+ attention_resolutions:
+ - 8
+ - 4
+ - 2
+ num_res_blocks: 2
+ channel_mult:
+ - 1
+ - 2
+ - 3
+ - 4
+ num_heads: 8
+ resblock_updown: true
+ first_stage_config:
+ target: ldm.models.autoencoder.VQModelInterface
+ params:
+ embed_dim: 3
+ n_embed: 8192
+ monitor: val/rec_loss
+ ddconfig:
+ attn_type: none
+ double_z: false
+ z_channels: 3
+ resolution: 256
+ in_channels: 3
+ out_ch: 3
+ ch: 128
+ ch_mult:
+ - 1
+ - 2
+ - 4
+ num_res_blocks: 2
+ attn_resolutions: []
+ dropout: 0.0
+ lossconfig:
+ target: ldm.modules.losses.contperceptual.DummyLoss
+ cond_stage_config: __is_first_stage__
diff --git a/latent-diffusion/models/ldm/layout2img-openimages256/config.yaml b/latent-diffusion/models/ldm/layout2img-openimages256/config.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..9e1dc15fe2732c70b918ceba4255aef895031efd
--- /dev/null
+++ b/latent-diffusion/models/ldm/layout2img-openimages256/config.yaml
@@ -0,0 +1,81 @@
+model:
+ base_learning_rate: 2.0e-06
+ target: ldm.models.diffusion.ddpm.LatentDiffusion
+ params:
+ linear_start: 0.0015
+ linear_end: 0.0205
+ log_every_t: 100
+ timesteps: 1000
+ loss_type: l1
+ first_stage_key: image
+ cond_stage_key: coordinates_bbox
+ image_size: 64
+ channels: 3
+ conditioning_key: crossattn
+ cond_stage_trainable: true
+ unet_config:
+ target: ldm.modules.diffusionmodules.openaimodel.UNetModel
+ params:
+ image_size: 64
+ in_channels: 3
+ out_channels: 3
+ model_channels: 128
+ attention_resolutions:
+ - 8
+ - 4
+ - 2
+ num_res_blocks: 2
+ channel_mult:
+ - 1
+ - 2
+ - 3
+ - 4
+ num_head_channels: 32
+ use_spatial_transformer: true
+ transformer_depth: 3
+ context_dim: 512
+ first_stage_config:
+ target: ldm.models.autoencoder.VQModelInterface
+ params:
+ embed_dim: 3
+ n_embed: 8192
+ monitor: val/rec_loss
+ ddconfig:
+ double_z: false
+ z_channels: 3
+ resolution: 256
+ in_channels: 3
+ out_ch: 3
+ ch: 128
+ ch_mult:
+ - 1
+ - 2
+ - 4
+ num_res_blocks: 2
+ attn_resolutions: []
+ dropout: 0.0
+ lossconfig:
+ target: torch.nn.Identity
+ cond_stage_config:
+ target: ldm.modules.encoders.modules.BERTEmbedder
+ params:
+ n_embed: 512
+ n_layer: 16
+ vocab_size: 8192
+ max_seq_len: 92
+ use_tokenizer: false
+ monitor: val/loss_simple_ema
+data:
+ target: main.DataModuleFromConfig
+ params:
+ batch_size: 24
+ wrap: false
+ num_workers: 10
+ train:
+ target: ldm.data.openimages.OpenImagesBBoxTrain
+ params:
+ size: 256
+ validation:
+ target: ldm.data.openimages.OpenImagesBBoxValidation
+ params:
+ size: 256
diff --git a/latent-diffusion/models/ldm/lsun_beds256/config.yaml b/latent-diffusion/models/ldm/lsun_beds256/config.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..1a50c766a5e571545e4f15f897de73f9df49d85c
--- /dev/null
+++ b/latent-diffusion/models/ldm/lsun_beds256/config.yaml
@@ -0,0 +1,70 @@
+model:
+ base_learning_rate: 2.0e-06
+ target: ldm.models.diffusion.ddpm.LatentDiffusion
+ params:
+ linear_start: 0.0015
+ linear_end: 0.0195
+ num_timesteps_cond: 1
+ log_every_t: 200
+ timesteps: 1000
+ first_stage_key: image
+ cond_stage_key: class_label
+ image_size: 64
+ channels: 3
+ cond_stage_trainable: false
+ concat_mode: false
+ monitor: val/loss
+ unet_config:
+ target: ldm.modules.diffusionmodules.openaimodel.UNetModel
+ params:
+ image_size: 64
+ in_channels: 3
+ out_channels: 3
+ model_channels: 224
+ attention_resolutions:
+ - 8
+ - 4
+ - 2
+ num_res_blocks: 2
+ channel_mult:
+ - 1
+ - 2
+ - 3
+ - 4
+ num_head_channels: 32
+ first_stage_config:
+ target: ldm.models.autoencoder.VQModelInterface
+ params:
+ embed_dim: 3
+ n_embed: 8192
+ ddconfig:
+ double_z: false
+ z_channels: 3
+ resolution: 256
+ in_channels: 3
+ out_ch: 3
+ ch: 128
+ ch_mult:
+ - 1
+ - 2
+ - 4
+ num_res_blocks: 2
+ attn_resolutions: []
+ dropout: 0.0
+ lossconfig:
+ target: torch.nn.Identity
+ cond_stage_config: __is_unconditional__
+data:
+ target: main.DataModuleFromConfig
+ params:
+ batch_size: 48
+ num_workers: 5
+ wrap: false
+ train:
+ target: ldm.data.lsun.LSUNBedroomsTrain
+ params:
+ size: 256
+ validation:
+ target: ldm.data.lsun.LSUNBedroomsValidation
+ params:
+ size: 256
diff --git a/latent-diffusion/models/ldm/lsun_churches256/config.yaml b/latent-diffusion/models/ldm/lsun_churches256/config.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..424d0914c9a1b9d4df3a2862ee7764404fe8adc1
--- /dev/null
+++ b/latent-diffusion/models/ldm/lsun_churches256/config.yaml
@@ -0,0 +1,92 @@
+model:
+ base_learning_rate: 5.0e-05
+ target: ldm.models.diffusion.ddpm.LatentDiffusion
+ params:
+ linear_start: 0.0015
+ linear_end: 0.0155
+ num_timesteps_cond: 1
+ log_every_t: 200
+ timesteps: 1000
+ loss_type: l1
+ first_stage_key: image
+ cond_stage_key: image
+ image_size: 32
+ channels: 4
+ cond_stage_trainable: false
+ concat_mode: false
+ scale_by_std: true
+ monitor: val/loss_simple_ema
+ scheduler_config:
+ target: ldm.lr_scheduler.LambdaLinearScheduler
+ params:
+ warm_up_steps:
+ - 10000
+ cycle_lengths:
+ - 10000000000000
+ f_start:
+ - 1.0e-06
+ f_max:
+ - 1.0
+ f_min:
+ - 1.0
+ unet_config:
+ target: ldm.modules.diffusionmodules.openaimodel.UNetModel
+ params:
+ image_size: 32
+ in_channels: 4
+ out_channels: 4
+ model_channels: 192
+ attention_resolutions:
+ - 1
+ - 2
+ - 4
+ - 8
+ num_res_blocks: 2
+ channel_mult:
+ - 1
+ - 2
+ - 2
+ - 4
+ - 4
+ num_heads: 8
+ use_scale_shift_norm: true
+ resblock_updown: true
+ first_stage_config:
+ target: ldm.models.autoencoder.AutoencoderKL
+ params:
+ embed_dim: 4
+ monitor: val/rec_loss
+ ddconfig:
+ double_z: true
+ z_channels: 4
+ resolution: 256
+ in_channels: 3
+ out_ch: 3
+ ch: 128
+ ch_mult:
+ - 1
+ - 2
+ - 4
+ - 4
+ num_res_blocks: 2
+ attn_resolutions: []
+ dropout: 0.0
+ lossconfig:
+ target: torch.nn.Identity
+
+ cond_stage_config: '__is_unconditional__'
+
+data:
+ target: main.DataModuleFromConfig
+ params:
+ batch_size: 96
+ num_workers: 5
+ wrap: false
+ train:
+ target: ldm.data.lsun.LSUNChurchesTrain
+ params:
+ size: 256
+ validation:
+ target: ldm.data.lsun.LSUNChurchesValidation
+ params:
+ size: 256
diff --git a/latent-diffusion/models/ldm/semantic_synthesis256/config.yaml b/latent-diffusion/models/ldm/semantic_synthesis256/config.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..1a721cfffa5f0cd627be56c07cf5306ae4933cd1
--- /dev/null
+++ b/latent-diffusion/models/ldm/semantic_synthesis256/config.yaml
@@ -0,0 +1,59 @@
+model:
+ base_learning_rate: 1.0e-06
+ target: ldm.models.diffusion.ddpm.LatentDiffusion
+ params:
+ linear_start: 0.0015
+ linear_end: 0.0205
+ log_every_t: 100
+ timesteps: 1000
+ loss_type: l1
+ first_stage_key: image
+ cond_stage_key: segmentation
+ image_size: 64
+ channels: 3
+ concat_mode: true
+ cond_stage_trainable: true
+ unet_config:
+ target: ldm.modules.diffusionmodules.openaimodel.UNetModel
+ params:
+ image_size: 64
+ in_channels: 6
+ out_channels: 3
+ model_channels: 128
+ attention_resolutions:
+ - 32
+ - 16
+ - 8
+ num_res_blocks: 2
+ channel_mult:
+ - 1
+ - 4
+ - 8
+ num_heads: 8
+ first_stage_config:
+ target: ldm.models.autoencoder.VQModelInterface
+ params:
+ embed_dim: 3
+ n_embed: 8192
+ ddconfig:
+ double_z: false
+ z_channels: 3
+ resolution: 256
+ in_channels: 3
+ out_ch: 3
+ ch: 128
+ ch_mult:
+ - 1
+ - 2
+ - 4
+ num_res_blocks: 2
+ attn_resolutions: []
+ dropout: 0.0
+ lossconfig:
+ target: torch.nn.Identity
+ cond_stage_config:
+ target: ldm.modules.encoders.modules.SpatialRescaler
+ params:
+ n_stages: 2
+ in_channels: 182
+ out_channels: 3
diff --git a/latent-diffusion/models/ldm/semantic_synthesis512/config.yaml b/latent-diffusion/models/ldm/semantic_synthesis512/config.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..8faded2eec5899064fc464a1b543d3a1b9c0613f
--- /dev/null
+++ b/latent-diffusion/models/ldm/semantic_synthesis512/config.yaml
@@ -0,0 +1,78 @@
+model:
+ base_learning_rate: 1.0e-06
+ target: ldm.models.diffusion.ddpm.LatentDiffusion
+ params:
+ linear_start: 0.0015
+ linear_end: 0.0205
+ log_every_t: 100
+ timesteps: 1000
+ loss_type: l1
+ first_stage_key: image
+ cond_stage_key: segmentation
+ image_size: 128
+ channels: 3
+ concat_mode: true
+ cond_stage_trainable: true
+ unet_config:
+ target: ldm.modules.diffusionmodules.openaimodel.UNetModel
+ params:
+ image_size: 128
+ in_channels: 6
+ out_channels: 3
+ model_channels: 128
+ attention_resolutions:
+ - 32
+ - 16
+ - 8
+ num_res_blocks: 2
+ channel_mult:
+ - 1
+ - 4
+ - 8
+ num_heads: 8
+ first_stage_config:
+ target: ldm.models.autoencoder.VQModelInterface
+ params:
+ embed_dim: 3
+ n_embed: 8192
+ monitor: val/rec_loss
+ ddconfig:
+ double_z: false
+ z_channels: 3
+ resolution: 256
+ in_channels: 3
+ out_ch: 3
+ ch: 128
+ ch_mult:
+ - 1
+ - 2
+ - 4
+ num_res_blocks: 2
+ attn_resolutions: []
+ dropout: 0.0
+ lossconfig:
+ target: torch.nn.Identity
+ cond_stage_config:
+ target: ldm.modules.encoders.modules.SpatialRescaler
+ params:
+ n_stages: 2
+ in_channels: 182
+ out_channels: 3
+data:
+ target: main.DataModuleFromConfig
+ params:
+ batch_size: 8
+ wrap: false
+ num_workers: 10
+ train:
+ target: ldm.data.landscapes.RFWTrain
+ params:
+ size: 768
+ crop_size: 512
+ segmentation_to_float32: true
+ validation:
+ target: ldm.data.landscapes.RFWValidation
+ params:
+ size: 768
+ crop_size: 512
+ segmentation_to_float32: true
diff --git a/latent-diffusion/models/ldm/text2img256/config.yaml b/latent-diffusion/models/ldm/text2img256/config.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..3f54a0151569fafcd0df37a480e5ea920fe7ffb5
--- /dev/null
+++ b/latent-diffusion/models/ldm/text2img256/config.yaml
@@ -0,0 +1,77 @@
+model:
+ base_learning_rate: 2.0e-06
+ target: ldm.models.diffusion.ddpm.LatentDiffusion
+ params:
+ linear_start: 0.0015
+ linear_end: 0.0195
+ num_timesteps_cond: 1
+ log_every_t: 200
+ timesteps: 1000
+ first_stage_key: image
+ cond_stage_key: caption
+ image_size: 64
+ channels: 3
+ cond_stage_trainable: true
+ conditioning_key: crossattn
+ monitor: val/loss_simple_ema
+ unet_config:
+ target: ldm.modules.diffusionmodules.openaimodel.UNetModel
+ params:
+ image_size: 64
+ in_channels: 3
+ out_channels: 3
+ model_channels: 192
+ attention_resolutions:
+ - 8
+ - 4
+ - 2
+ num_res_blocks: 2
+ channel_mult:
+ - 1
+ - 2
+ - 3
+ - 5
+ num_head_channels: 32
+ use_spatial_transformer: true
+ transformer_depth: 1
+ context_dim: 640
+ first_stage_config:
+ target: ldm.models.autoencoder.VQModelInterface
+ params:
+ embed_dim: 3
+ n_embed: 8192
+ ddconfig:
+ double_z: false
+ z_channels: 3
+ resolution: 256
+ in_channels: 3
+ out_ch: 3
+ ch: 128
+ ch_mult:
+ - 1
+ - 2
+ - 4
+ num_res_blocks: 2
+ attn_resolutions: []
+ dropout: 0.0
+ lossconfig:
+ target: torch.nn.Identity
+ cond_stage_config:
+ target: ldm.modules.encoders.modules.BERTEmbedder
+ params:
+ n_embed: 640
+ n_layer: 32
+data:
+ target: main.DataModuleFromConfig
+ params:
+ batch_size: 28
+ num_workers: 10
+ wrap: false
+ train:
+ target: ldm.data.previews.pytorch_dataset.PreviewsTrain
+ params:
+ size: 256
+ validation:
+ target: ldm.data.previews.pytorch_dataset.PreviewsValidation
+ params:
+ size: 256
diff --git a/latent-diffusion/notebook_helpers.py b/latent-diffusion/notebook_helpers.py
new file mode 100644
index 0000000000000000000000000000000000000000..5d0ebd7e1f8095053f34b1d7652b55d165097f0e
--- /dev/null
+++ b/latent-diffusion/notebook_helpers.py
@@ -0,0 +1,270 @@
+from torchvision.datasets.utils import download_url
+from ldm.util import instantiate_from_config
+import torch
+import os
+# todo ?
+from google.colab import files
+from IPython.display import Image as ipyimg
+import ipywidgets as widgets
+from PIL import Image
+from numpy import asarray
+from einops import rearrange, repeat
+import torch, torchvision
+from ldm.models.diffusion.ddim import DDIMSampler
+from ldm.util import ismap
+import time
+from omegaconf import OmegaConf
+
+
+def download_models(mode):
+
+ if mode == "superresolution":
+ # this is the small bsr light model
+ url_conf = 'https://heibox.uni-heidelberg.de/f/31a76b13ea27482981b4/?dl=1'
+ url_ckpt = 'https://heibox.uni-heidelberg.de/f/578df07c8fc04ffbadf3/?dl=1'
+
+ path_conf = 'logs/diffusion/superresolution_bsr/configs/project.yaml'
+ path_ckpt = 'logs/diffusion/superresolution_bsr/checkpoints/last.ckpt'
+
+ download_url(url_conf, path_conf)
+ download_url(url_ckpt, path_ckpt)
+
+ path_conf = path_conf + '/?dl=1' # fix it
+ path_ckpt = path_ckpt + '/?dl=1' # fix it
+ return path_conf, path_ckpt
+
+ else:
+ raise NotImplementedError
+
+
+def load_model_from_config(config, ckpt):
+ print(f"Loading model from {ckpt}")
+ pl_sd = torch.load(ckpt, map_location="cpu")
+ global_step = pl_sd["global_step"]
+ sd = pl_sd["state_dict"]
+ model = instantiate_from_config(config.model)
+ m, u = model.load_state_dict(sd, strict=False)
+ model.cuda()
+ model.eval()
+ return {"model": model}, global_step
+
+
+def get_model(mode):
+ path_conf, path_ckpt = download_models(mode)
+ config = OmegaConf.load(path_conf)
+ model, step = load_model_from_config(config, path_ckpt)
+ return model
+
+
+def get_custom_cond(mode):
+ dest = "data/example_conditioning"
+
+ if mode == "superresolution":
+ uploaded_img = files.upload()
+ filename = next(iter(uploaded_img))
+ name, filetype = filename.split(".") # todo assumes just one dot in name !
+ os.rename(f"{filename}", f"{dest}/{mode}/custom_{name}.{filetype}")
+
+ elif mode == "text_conditional":
+ w = widgets.Text(value='A cake with cream!', disabled=True)
+ display(w)
+
+ with open(f"{dest}/{mode}/custom_{w.value[:20]}.txt", 'w') as f:
+ f.write(w.value)
+
+ elif mode == "class_conditional":
+ w = widgets.IntSlider(min=0, max=1000)
+ display(w)
+ with open(f"{dest}/{mode}/custom.txt", 'w') as f:
+ f.write(w.value)
+
+ else:
+ raise NotImplementedError(f"cond not implemented for mode{mode}")
+
+
+def get_cond_options(mode):
+ path = "data/example_conditioning"
+ path = os.path.join(path, mode)
+ onlyfiles = [f for f in sorted(os.listdir(path))]
+ return path, onlyfiles
+
+
+def select_cond_path(mode):
+ path = "data/example_conditioning" # todo
+ path = os.path.join(path, mode)
+ onlyfiles = [f for f in sorted(os.listdir(path))]
+
+ selected = widgets.RadioButtons(
+ options=onlyfiles,
+ description='Select conditioning:',
+ disabled=False
+ )
+ display(selected)
+ selected_path = os.path.join(path, selected.value)
+ return selected_path
+
+
+def get_cond(mode, selected_path):
+ example = dict()
+ if mode == "superresolution":
+ up_f = 4
+ visualize_cond_img(selected_path)
+
+ c = Image.open(selected_path)
+ c = torch.unsqueeze(torchvision.transforms.ToTensor()(c), 0)
+ c_up = torchvision.transforms.functional.resize(c, size=[up_f * c.shape[2], up_f * c.shape[3]], antialias=True)
+ c_up = rearrange(c_up, '1 c h w -> 1 h w c')
+ c = rearrange(c, '1 c h w -> 1 h w c')
+ c = 2. * c - 1.
+
+ c = c.to(torch.device("cuda"))
+ example["LR_image"] = c
+ example["image"] = c_up
+
+ return example
+
+
+def visualize_cond_img(path):
+ display(ipyimg(filename=path))
+
+
+def run(model, selected_path, task, custom_steps, resize_enabled=False, classifier_ckpt=None, global_step=None):
+
+ example = get_cond(task, selected_path)
+
+ save_intermediate_vid = False
+ n_runs = 1
+ masked = False
+ guider = None
+ ckwargs = None
+ mode = 'ddim'
+ ddim_use_x0_pred = False
+ temperature = 1.
+ eta = 1.
+ make_progrow = True
+ custom_shape = None
+
+ height, width = example["image"].shape[1:3]
+ split_input = height >= 128 and width >= 128
+
+ if split_input:
+ ks = 128
+ stride = 64
+ vqf = 4 #
+ model.split_input_params = {"ks": (ks, ks), "stride": (stride, stride),
+ "vqf": vqf,
+ "patch_distributed_vq": True,
+ "tie_braker": False,
+ "clip_max_weight": 0.5,
+ "clip_min_weight": 0.01,
+ "clip_max_tie_weight": 0.5,
+ "clip_min_tie_weight": 0.01}
+ else:
+ if hasattr(model, "split_input_params"):
+ delattr(model, "split_input_params")
+
+ invert_mask = False
+
+ x_T = None
+ for n in range(n_runs):
+ if custom_shape is not None:
+ x_T = torch.randn(1, custom_shape[1], custom_shape[2], custom_shape[3]).to(model.device)
+ x_T = repeat(x_T, '1 c h w -> b c h w', b=custom_shape[0])
+
+ logs = make_convolutional_sample(example, model,
+ mode=mode, custom_steps=custom_steps,
+ eta=eta, swap_mode=False , masked=masked,
+ invert_mask=invert_mask, quantize_x0=False,
+ custom_schedule=None, decode_interval=10,
+ resize_enabled=resize_enabled, custom_shape=custom_shape,
+ temperature=temperature, noise_dropout=0.,
+ corrector=guider, corrector_kwargs=ckwargs, x_T=x_T, save_intermediate_vid=save_intermediate_vid,
+ make_progrow=make_progrow,ddim_use_x0_pred=ddim_use_x0_pred
+ )
+ return logs
+
+
+@torch.no_grad()
+def convsample_ddim(model, cond, steps, shape, eta=1.0, callback=None, normals_sequence=None,
+ mask=None, x0=None, quantize_x0=False, img_callback=None,
+ temperature=1., noise_dropout=0., score_corrector=None,
+ corrector_kwargs=None, x_T=None, log_every_t=None
+ ):
+
+ ddim = DDIMSampler(model)
+ bs = shape[0] # dont know where this comes from but wayne
+ shape = shape[1:] # cut batch dim
+ print(f"Sampling with eta = {eta}; steps: {steps}")
+ samples, intermediates = ddim.sample(steps, batch_size=bs, shape=shape, conditioning=cond, callback=callback,
+ normals_sequence=normals_sequence, quantize_x0=quantize_x0, eta=eta,
+ mask=mask, x0=x0, temperature=temperature, verbose=False,
+ score_corrector=score_corrector,
+ corrector_kwargs=corrector_kwargs, x_T=x_T)
+
+ return samples, intermediates
+
+
+@torch.no_grad()
+def make_convolutional_sample(batch, model, mode="vanilla", custom_steps=None, eta=1.0, swap_mode=False, masked=False,
+ invert_mask=True, quantize_x0=False, custom_schedule=None, decode_interval=1000,
+ resize_enabled=False, custom_shape=None, temperature=1., noise_dropout=0., corrector=None,
+ corrector_kwargs=None, x_T=None, save_intermediate_vid=False, make_progrow=True,ddim_use_x0_pred=False):
+ log = dict()
+
+ z, c, x, xrec, xc = model.get_input(batch, model.first_stage_key,
+ return_first_stage_outputs=True,
+ force_c_encode=not (hasattr(model, 'split_input_params')
+ and model.cond_stage_key == 'coordinates_bbox'),
+ return_original_cond=True)
+
+ log_every_t = 1 if save_intermediate_vid else None
+
+ if custom_shape is not None:
+ z = torch.randn(custom_shape)
+ print(f"Generating {custom_shape[0]} samples of shape {custom_shape[1:]}")
+
+ z0 = None
+
+ log["input"] = x
+ log["reconstruction"] = xrec
+
+ if ismap(xc):
+ log["original_conditioning"] = model.to_rgb(xc)
+ if hasattr(model, 'cond_stage_key'):
+ log[model.cond_stage_key] = model.to_rgb(xc)
+
+ else:
+ log["original_conditioning"] = xc if xc is not None else torch.zeros_like(x)
+ if model.cond_stage_model:
+ log[model.cond_stage_key] = xc if xc is not None else torch.zeros_like(x)
+ if model.cond_stage_key =='class_label':
+ log[model.cond_stage_key] = xc[model.cond_stage_key]
+
+ with model.ema_scope("Plotting"):
+ t0 = time.time()
+ img_cb = None
+
+ sample, intermediates = convsample_ddim(model, c, steps=custom_steps, shape=z.shape,
+ eta=eta,
+ quantize_x0=quantize_x0, img_callback=img_cb, mask=None, x0=z0,
+ temperature=temperature, noise_dropout=noise_dropout,
+ score_corrector=corrector, corrector_kwargs=corrector_kwargs,
+ x_T=x_T, log_every_t=log_every_t)
+ t1 = time.time()
+
+ if ddim_use_x0_pred:
+ sample = intermediates['pred_x0'][-1]
+
+ x_sample = model.decode_first_stage(sample)
+
+ try:
+ x_sample_noquant = model.decode_first_stage(sample, force_not_quantize=True)
+ log["sample_noquant"] = x_sample_noquant
+ log["sample_diff"] = torch.abs(x_sample_noquant - x_sample)
+ except:
+ pass
+
+ log["sample"] = x_sample
+ log["time"] = t1 - t0
+
+ return log
\ No newline at end of file
diff --git "a/latent-diffusion/outputs/A-drawing-of-a-cute-dog-with-a-weird-hat-that-reads\357\200\272-Beware-humans.png" "b/latent-diffusion/outputs/A-drawing-of-a-cute-dog-with-a-weird-hat-that-reads\357\200\272-Beware-humans.png"
new file mode 100644
index 0000000000000000000000000000000000000000..da980c55514b9453a046c15e04e4718d0941767f
Binary files /dev/null and "b/latent-diffusion/outputs/A-drawing-of-a-cute-dog-with-a-weird-hat-that-reads\357\200\272-Beware-humans.png" differ
diff --git a/latent-diffusion/outputs/Asian-women-having-fun-on-a-park.png b/latent-diffusion/outputs/Asian-women-having-fun-on-a-park.png
new file mode 100644
index 0000000000000000000000000000000000000000..2419f49d0e5ee0d22c5b3f41cbf616c374cb59e8
Binary files /dev/null and b/latent-diffusion/outputs/Asian-women-having-fun-on-a-park.png differ
diff --git a/latent-diffusion/outputs/The-drawing-of-a-dog-wearing-a-funny-hat.png b/latent-diffusion/outputs/The-drawing-of-a-dog-wearing-a-funny-hat.png
new file mode 100644
index 0000000000000000000000000000000000000000..0cbc7ca532ead726816b4d4699f3125ea04688fc
Binary files /dev/null and b/latent-diffusion/outputs/The-drawing-of-a-dog-wearing-a-funny-hat.png differ
diff --git a/latent-diffusion/outputs/a-chalk-pastel-drawing-of-a-cat-wearing-a-funny-hat.png b/latent-diffusion/outputs/a-chalk-pastel-drawing-of-a-cat-wearing-a-funny-hat.png
new file mode 100644
index 0000000000000000000000000000000000000000..5cda114483fc6889ce4b58fa4dced3a25118477b
Binary files /dev/null and b/latent-diffusion/outputs/a-chalk-pastel-drawing-of-a-cat-wearing-a-funny-hat.png differ
diff --git a/latent-diffusion/outputs/a-woman-playing-with-a-dog.png b/latent-diffusion/outputs/a-woman-playing-with-a-dog.png
new file mode 100644
index 0000000000000000000000000000000000000000..3ca8ad71cb0a517fad4c6f49190b67747f03cfae
Binary files /dev/null and b/latent-diffusion/outputs/a-woman-playing-with-a-dog.png differ
diff --git a/latent-diffusion/outputs/a-women-playing-with-a-dog.png b/latent-diffusion/outputs/a-women-playing-with-a-dog.png
new file mode 100644
index 0000000000000000000000000000000000000000..74736d2598aea70fd62718e00aaa39328019a3d6
Binary files /dev/null and b/latent-diffusion/outputs/a-women-playing-with-a-dog.png differ
diff --git a/latent-diffusion/outputs/black.png b/latent-diffusion/outputs/black.png
new file mode 100644
index 0000000000000000000000000000000000000000..bd7329dcdb56a35d61ecdbdb33a5084dc713a79d
Binary files /dev/null and b/latent-diffusion/outputs/black.png differ
diff --git a/latent-diffusion/outputs/chalk-pastel-drawing-of-a-cat-wearing-a-funny-hat.png b/latent-diffusion/outputs/chalk-pastel-drawing-of-a-cat-wearing-a-funny-hat.png
new file mode 100644
index 0000000000000000000000000000000000000000..b86080e59f1603aad512f63711974d6ae855f89d
Binary files /dev/null and b/latent-diffusion/outputs/chalk-pastel-drawing-of-a-cat-wearing-a-funny-hat.png differ
diff --git a/latent-diffusion/outputs/chalk-pastel-drawing-of-a-dog-wearing-a-funny-hat.png b/latent-diffusion/outputs/chalk-pastel-drawing-of-a-dog-wearing-a-funny-hat.png
new file mode 100644
index 0000000000000000000000000000000000000000..79f2168cf9a0b710a2fe9de9c843f3d997ea3d19
Binary files /dev/null and b/latent-diffusion/outputs/chalk-pastel-drawing-of-a-dog-wearing-a-funny-hat.png differ
diff --git a/latent-diffusion/outputs/friendship.png b/latent-diffusion/outputs/friendship.png
new file mode 100644
index 0000000000000000000000000000000000000000..b7f14a465e11ebced0ebc503c3ee1b69a3325932
Binary files /dev/null and b/latent-diffusion/outputs/friendship.png differ
diff --git a/latent-diffusion/scripts/download_first_stages.sh b/latent-diffusion/scripts/download_first_stages.sh
new file mode 100644
index 0000000000000000000000000000000000000000..a8d79e99ccdff0a8d8762f23f3c0642401f32f6c
--- /dev/null
+++ b/latent-diffusion/scripts/download_first_stages.sh
@@ -0,0 +1,41 @@
+#!/bin/bash
+wget -O models/first_stage_models/kl-f4/model.zip https://ommer-lab.com/files/latent-diffusion/kl-f4.zip
+wget -O models/first_stage_models/kl-f8/model.zip https://ommer-lab.com/files/latent-diffusion/kl-f8.zip
+wget -O models/first_stage_models/kl-f16/model.zip https://ommer-lab.com/files/latent-diffusion/kl-f16.zip
+wget -O models/first_stage_models/kl-f32/model.zip https://ommer-lab.com/files/latent-diffusion/kl-f32.zip
+wget -O models/first_stage_models/vq-f4/model.zip https://ommer-lab.com/files/latent-diffusion/vq-f4.zip
+wget -O models/first_stage_models/vq-f4-noattn/model.zip https://ommer-lab.com/files/latent-diffusion/vq-f4-noattn.zip
+wget -O models/first_stage_models/vq-f8/model.zip https://ommer-lab.com/files/latent-diffusion/vq-f8.zip
+wget -O models/first_stage_models/vq-f8-n256/model.zip https://ommer-lab.com/files/latent-diffusion/vq-f8-n256.zip
+wget -O models/first_stage_models/vq-f16/model.zip https://ommer-lab.com/files/latent-diffusion/vq-f16.zip
+
+
+
+cd models/first_stage_models/kl-f4
+unzip -o model.zip
+
+cd ../kl-f8
+unzip -o model.zip
+
+cd ../kl-f16
+unzip -o model.zip
+
+cd ../kl-f32
+unzip -o model.zip
+
+cd ../vq-f4
+unzip -o model.zip
+
+cd ../vq-f4-noattn
+unzip -o model.zip
+
+cd ../vq-f8
+unzip -o model.zip
+
+cd ../vq-f8-n256
+unzip -o model.zip
+
+cd ../vq-f16
+unzip -o model.zip
+
+cd ../..
\ No newline at end of file
diff --git a/latent-diffusion/scripts/download_models.sh b/latent-diffusion/scripts/download_models.sh
new file mode 100644
index 0000000000000000000000000000000000000000..84297d7b8b9a78d241edcd5adaf7d9aa273790de
--- /dev/null
+++ b/latent-diffusion/scripts/download_models.sh
@@ -0,0 +1,49 @@
+#!/bin/bash
+wget -O models/ldm/celeba256/celeba-256.zip https://ommer-lab.com/files/latent-diffusion/celeba.zip
+wget -O models/ldm/ffhq256/ffhq-256.zip https://ommer-lab.com/files/latent-diffusion/ffhq.zip
+wget -O models/ldm/lsun_churches256/lsun_churches-256.zip https://ommer-lab.com/files/latent-diffusion/lsun_churches.zip
+wget -O models/ldm/lsun_beds256/lsun_beds-256.zip https://ommer-lab.com/files/latent-diffusion/lsun_bedrooms.zip
+wget -O models/ldm/text2img256/model.zip https://ommer-lab.com/files/latent-diffusion/text2img.zip
+wget -O models/ldm/cin256/model.zip https://ommer-lab.com/files/latent-diffusion/cin.zip
+wget -O models/ldm/semantic_synthesis512/model.zip https://ommer-lab.com/files/latent-diffusion/semantic_synthesis.zip
+wget -O models/ldm/semantic_synthesis256/model.zip https://ommer-lab.com/files/latent-diffusion/semantic_synthesis256.zip
+wget -O models/ldm/bsr_sr/model.zip https://ommer-lab.com/files/latent-diffusion/sr_bsr.zip
+wget -O models/ldm/layout2img-openimages256/model.zip https://ommer-lab.com/files/latent-diffusion/layout2img_model.zip
+wget -O models/ldm/inpainting_big/model.zip https://ommer-lab.com/files/latent-diffusion/inpainting_big.zip
+
+
+
+cd models/ldm/celeba256
+unzip -o celeba-256.zip
+
+cd ../ffhq256
+unzip -o ffhq-256.zip
+
+cd ../lsun_churches256
+unzip -o lsun_churches-256.zip
+
+cd ../lsun_beds256
+unzip -o lsun_beds-256.zip
+
+cd ../text2img256
+unzip -o model.zip
+
+cd ../cin256
+unzip -o model.zip
+
+cd ../semantic_synthesis512
+unzip -o model.zip
+
+cd ../semantic_synthesis256
+unzip -o model.zip
+
+cd ../bsr_sr
+unzip -o model.zip
+
+cd ../layout2img-openimages256
+unzip -o model.zip
+
+cd ../inpainting_big
+unzip -o model.zip
+
+cd ../..
diff --git a/latent-diffusion/scripts/inpaint.py b/latent-diffusion/scripts/inpaint.py
new file mode 100644
index 0000000000000000000000000000000000000000..d6e6387a9a3b0afa73fae8af25f43a8ba856240e
--- /dev/null
+++ b/latent-diffusion/scripts/inpaint.py
@@ -0,0 +1,98 @@
+import argparse, os, sys, glob
+from omegaconf import OmegaConf
+from PIL import Image
+from tqdm import tqdm
+import numpy as np
+import torch
+from main import instantiate_from_config
+from ldm.models.diffusion.ddim import DDIMSampler
+
+
+def make_batch(image, mask, device):
+ image = np.array(Image.open(image).convert("RGB"))
+ image = image.astype(np.float32)/255.0
+ image = image[None].transpose(0,3,1,2)
+ image = torch.from_numpy(image)
+
+ mask = np.array(Image.open(mask).convert("L"))
+ mask = mask.astype(np.float32)/255.0
+ mask = mask[None,None]
+ mask[mask < 0.5] = 0
+ mask[mask >= 0.5] = 1
+ mask = torch.from_numpy(mask)
+
+ masked_image = (1-mask)*image
+
+ batch = {"image": image, "mask": mask, "masked_image": masked_image}
+ for k in batch:
+ batch[k] = batch[k].to(device=device)
+ batch[k] = batch[k]*2.0-1.0
+ return batch
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ "--indir",
+ type=str,
+ nargs="?",
+ help="dir containing image-mask pairs (`example.png` and `example_mask.png`)",
+ )
+ parser.add_argument(
+ "--outdir",
+ type=str,
+ nargs="?",
+ help="dir to write results to",
+ )
+ parser.add_argument(
+ "--steps",
+ type=int,
+ default=50,
+ help="number of ddim sampling steps",
+ )
+ opt = parser.parse_args()
+
+ masks = sorted(glob.glob(os.path.join(opt.indir, "*_mask.png")))
+ images = [x.replace("_mask.png", ".png") for x in masks]
+ print(f"Found {len(masks)} inputs.")
+
+ config = OmegaConf.load("models/ldm/inpainting_big/config.yaml")
+ model = instantiate_from_config(config.model)
+ model.load_state_dict(torch.load("models/ldm/inpainting_big/last.ckpt")["state_dict"],
+ strict=False)
+
+ device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")
+ model = model.to(device)
+ sampler = DDIMSampler(model)
+
+ os.makedirs(opt.outdir, exist_ok=True)
+ with torch.no_grad():
+ with model.ema_scope():
+ for image, mask in tqdm(zip(images, masks)):
+ outpath = os.path.join(opt.outdir, os.path.split(image)[1])
+ batch = make_batch(image, mask, device=device)
+
+ # encode masked image and concat downsampled mask
+ c = model.cond_stage_model.encode(batch["masked_image"])
+ cc = torch.nn.functional.interpolate(batch["mask"],
+ size=c.shape[-2:])
+ c = torch.cat((c, cc), dim=1)
+
+ shape = (c.shape[1]-1,)+c.shape[2:]
+ samples_ddim, _ = sampler.sample(S=opt.steps,
+ conditioning=c,
+ batch_size=c.shape[0],
+ shape=shape,
+ verbose=False)
+ x_samples_ddim = model.decode_first_stage(samples_ddim)
+
+ image = torch.clamp((batch["image"]+1.0)/2.0,
+ min=0.0, max=1.0)
+ mask = torch.clamp((batch["mask"]+1.0)/2.0,
+ min=0.0, max=1.0)
+ predicted_image = torch.clamp((x_samples_ddim+1.0)/2.0,
+ min=0.0, max=1.0)
+
+ inpainted = (1-mask)*image+mask*predicted_image
+ inpainted = inpainted.cpu().numpy().transpose(0,2,3,1)[0]*255
+ Image.fromarray(inpainted.astype(np.uint8)).save(outpath)
diff --git a/latent-diffusion/scripts/latent_imagenet_diffusion.ipynb b/latent-diffusion/scripts/latent_imagenet_diffusion.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..607f94fc7d3ef6d8d1627017215476d9dfc7ddc4
--- /dev/null
+++ b/latent-diffusion/scripts/latent_imagenet_diffusion.ipynb
@@ -0,0 +1,429 @@
+{
+ "nbformat": 4,
+ "nbformat_minor": 0,
+ "metadata": {
+ "colab": {
+ "name": "latent-imagenet-diffusion.ipynb",
+ "provenance": [],
+ "collapsed_sections": []
+ },
+ "kernelspec": {
+ "name": "python3",
+ "display_name": "Python 3"
+ },
+ "language_info": {
+ "name": "python"
+ },
+ "accelerator": "GPU"
+ },
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "source": [
+ "# Class-Conditional Synthesis with Latent Diffusion Models"
+ ],
+ "metadata": {
+ "id": "NUmmV5ZvrPbP"
+ }
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "Install all the requirements"
+ ],
+ "metadata": {
+ "id": "zh7u8gOx0ivw"
+ }
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "id": "NHgUAp48qwoG",
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "outputId": "411d4df6-d91a-42d4-819e-9cf641c12248",
+ "cellView": "form"
+ },
+ "outputs": [
+ {
+ "output_type": "stream",
+ "name": "stdout",
+ "text": [
+ "Cloning into 'latent-diffusion'...\n",
+ "remote: Enumerating objects: 992, done.\u001B[K\n",
+ "remote: Counting objects: 100% (695/695), done.\u001B[K\n",
+ "remote: Compressing objects: 100% (397/397), done.\u001B[K\n",
+ "remote: Total 992 (delta 375), reused 564 (delta 253), pack-reused 297\u001B[K\n",
+ "Receiving objects: 100% (992/992), 30.78 MiB | 29.43 MiB/s, done.\n",
+ "Resolving deltas: 100% (510/510), done.\n",
+ "Cloning into 'taming-transformers'...\n",
+ "remote: Enumerating objects: 1335, done.\u001B[K\n",
+ "remote: Counting objects: 100% (525/525), done.\u001B[K\n",
+ "remote: Compressing objects: 100% (493/493), done.\u001B[K\n",
+ "remote: Total 1335 (delta 58), reused 481 (delta 30), pack-reused 810\u001B[K\n",
+ "Receiving objects: 100% (1335/1335), 412.35 MiB | 30.53 MiB/s, done.\n",
+ "Resolving deltas: 100% (267/267), done.\n",
+ "Obtaining file:///content/taming-transformers\n",
+ "Requirement already satisfied: torch in /usr/local/lib/python3.7/dist-packages (from taming-transformers==0.0.1) (1.10.0+cu111)\n",
+ "Requirement already satisfied: numpy in /usr/local/lib/python3.7/dist-packages (from taming-transformers==0.0.1) (1.21.5)\n",
+ "Requirement already satisfied: tqdm in /usr/local/lib/python3.7/dist-packages (from taming-transformers==0.0.1) (4.63.0)\n",
+ "Requirement already satisfied: typing-extensions in /usr/local/lib/python3.7/dist-packages (from torch->taming-transformers==0.0.1) (3.10.0.2)\n",
+ "Installing collected packages: taming-transformers\n",
+ " Running setup.py develop for taming-transformers\n",
+ "Successfully installed taming-transformers-0.0.1\n",
+ "\u001B[31mERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.\n",
+ "tensorflow 2.8.0 requires tf-estimator-nightly==2.8.0.dev2021122109, which is not installed.\n",
+ "arviz 0.11.4 requires typing-extensions<4,>=3.7.4.3, but you have typing-extensions 4.1.1 which is incompatible.\u001B[0m\n"
+ ]
+ }
+ ],
+ "source": [
+ "#@title Installation\n",
+ "!git clone https://github.com/CompVis/latent-diffusion.git\n",
+ "!git clone https://github.com/CompVis/taming-transformers\n",
+ "!pip install -e ./taming-transformers\n",
+ "!pip install omegaconf>=2.0.0 pytorch-lightning>=1.0.8 torch-fidelity einops\n",
+ "\n",
+ "import sys\n",
+ "sys.path.append(\".\")\n",
+ "sys.path.append('./taming-transformers')\n",
+ "from taming.models import vqgan "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "Now, download the checkpoint (~1.7 GB). This will usually take 1-2 minutes."
+ ],
+ "metadata": {
+ "id": "fNqCqQDoyZmq"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "#@title Download\n",
+ "%cd latent-diffusion/ \n",
+ "\n",
+ "!mkdir -p models/ldm/cin256-v2/\n",
+ "!wget -O models/ldm/cin256-v2/model.ckpt https://ommer-lab.com/files/latent-diffusion/nitro/cin/model.ckpt "
+ ],
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "cNHvQBhzyXCI",
+ "outputId": "0a79e979-8484-4c62-96d9-7c79b1835162",
+ "cellView": "form"
+ },
+ "execution_count": null,
+ "outputs": [
+ {
+ "output_type": "stream",
+ "name": "stdout",
+ "text": [
+ "/content/latent-diffusion\n",
+ "--2022-04-03 13:04:51-- https://ommer-lab.com/files/latent-diffusion/nitro/cin/model.ckpt\n",
+ "Resolving ommer-lab.com (ommer-lab.com)... 141.84.41.65\n",
+ "Connecting to ommer-lab.com (ommer-lab.com)|141.84.41.65|:443... connected.\n",
+ "HTTP request sent, awaiting response... 200 OK\n",
+ "Length: 1827378153 (1.7G)\n",
+ "Saving to: βmodels/ldm/cin256-v2/model.ckptβ\n",
+ "\n",
+ "models/ldm/cin256-v 100%[===================>] 1.70G 24.9MB/s in 70s \n",
+ "\n",
+ "2022-04-03 13:06:02 (24.9 MB/s) - βmodels/ldm/cin256-v2/model.ckptβ saved [1827378153/1827378153]\n",
+ "\n"
+ ]
+ }
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "Let's also check what type of GPU we've got."
+ ],
+ "metadata": {
+ "id": "ThxmCePqt1mt"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "!nvidia-smi"
+ ],
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "jbL2zJ7Pt7Jl",
+ "outputId": "c8242be9-dba2-4a9f-da44-a294a70bb449"
+ },
+ "execution_count": null,
+ "outputs": [
+ {
+ "output_type": "stream",
+ "name": "stdout",
+ "text": [
+ "Sun Apr 3 13:06:21 2022 \n",
+ "+-----------------------------------------------------------------------------+\n",
+ "| NVIDIA-SMI 460.32.03 Driver Version: 460.32.03 CUDA Version: 11.2 |\n",
+ "|-------------------------------+----------------------+----------------------+\n",
+ "| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |\n",
+ "| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |\n",
+ "| | | MIG M. |\n",
+ "|===============================+======================+======================|\n",
+ "| 0 Tesla K80 Off | 00000000:00:04.0 Off | 0 |\n",
+ "| N/A 66C P8 33W / 149W | 0MiB / 11441MiB | 0% Default |\n",
+ "| | | N/A |\n",
+ "+-------------------------------+----------------------+----------------------+\n",
+ " \n",
+ "+-----------------------------------------------------------------------------+\n",
+ "| Processes: |\n",
+ "| GPU GI CI PID Type Process name GPU Memory |\n",
+ "| ID ID Usage |\n",
+ "|=============================================================================|\n",
+ "| No running processes found |\n",
+ "+-----------------------------------------------------------------------------+\n"
+ ]
+ }
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "Load it."
+ ],
+ "metadata": {
+ "id": "1tWAqdwk0Nrn"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "#@title loading utils\n",
+ "import torch\n",
+ "from omegaconf import OmegaConf\n",
+ "\n",
+ "from ldm.util import instantiate_from_config\n",
+ "\n",
+ "\n",
+ "def load_model_from_config(config, ckpt):\n",
+ " print(f\"Loading model from {ckpt}\")\n",
+ " pl_sd = torch.load(ckpt)#, map_location=\"cpu\")\n",
+ " sd = pl_sd[\"state_dict\"]\n",
+ " model = instantiate_from_config(config.model)\n",
+ " m, u = model.load_state_dict(sd, strict=False)\n",
+ " model.cuda()\n",
+ " model.eval()\n",
+ " return model\n",
+ "\n",
+ "\n",
+ "def get_model():\n",
+ " config = OmegaConf.load(\"configs/latent-diffusion/cin256-v2.yaml\") \n",
+ " model = load_model_from_config(config, \"models/ldm/cin256-v2/model.ckpt\")\n",
+ " return model"
+ ],
+ "metadata": {
+ "id": "fnGwQRhtyBhb",
+ "cellView": "form"
+ },
+ "execution_count": null,
+ "outputs": []
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "from ldm.models.diffusion.ddim import DDIMSampler\n",
+ "\n",
+ "model = get_model()\n",
+ "sampler = DDIMSampler(model)"
+ ],
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "BPnyd-XUKbfE",
+ "outputId": "0fcd10e4-0df2-4ab9-cbf5-f08f4902c954"
+ },
+ "execution_count": null,
+ "outputs": [
+ {
+ "output_type": "stream",
+ "name": "stdout",
+ "text": [
+ "Loading model from models/ldm/cin256-v2/model.ckpt\n",
+ "LatentDiffusion: Running in eps-prediction mode\n",
+ "DiffusionWrapper has 400.92 M params.\n",
+ "making attention of type 'vanilla' with 512 in_channels\n",
+ "Working with z of shape (1, 3, 64, 64) = 12288 dimensions.\n",
+ "making attention of type 'vanilla' with 512 in_channels\n"
+ ]
+ }
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "source": [
+ "And go. Quality, sampling speed and diversity are best controlled via the `scale`, `ddim_steps` and `ddim_eta` variables. As a rule of thumb, higher values of `scale` produce better samples at the cost of a reduced output diversity. Furthermore, increasing `ddim_steps` generally also gives higher quality samples, but returns are diminishing for values > 250. Fast sampling (i e. low values of `ddim_steps`) while retaining good quality can be achieved by using `ddim_eta = 0.0`."
+ ],
+ "metadata": {
+ "id": "iIEAhY8AhUrh"
+ }
+ },
+ {
+ "cell_type": "code",
+ "source": [
+ "import numpy as np \n",
+ "from PIL import Image\n",
+ "from einops import rearrange\n",
+ "from torchvision.utils import make_grid\n",
+ "\n",
+ "\n",
+ "classes = [25, 187, 448, 992] # define classes to be sampled here\n",
+ "n_samples_per_class = 6\n",
+ "\n",
+ "ddim_steps = 20\n",
+ "ddim_eta = 0.0\n",
+ "scale = 3.0 # for unconditional guidance\n",
+ "\n",
+ "\n",
+ "all_samples = list()\n",
+ "\n",
+ "with torch.no_grad():\n",
+ " with model.ema_scope():\n",
+ " uc = model.get_learned_conditioning(\n",
+ " {model.cond_stage_key: torch.tensor(n_samples_per_class*[1000]).to(model.device)}\n",
+ " )\n",
+ " \n",
+ " for class_label in classes:\n",
+ " print(f\"rendering {n_samples_per_class} examples of class '{class_label}' in {ddim_steps} steps and using s={scale:.2f}.\")\n",
+ " xc = torch.tensor(n_samples_per_class*[class_label])\n",
+ " c = model.get_learned_conditioning({model.cond_stage_key: xc.to(model.device)})\n",
+ " \n",
+ " samples_ddim, _ = sampler.sample(S=ddim_steps,\n",
+ " conditioning=c,\n",
+ " batch_size=n_samples_per_class,\n",
+ " shape=[3, 64, 64],\n",
+ " verbose=False,\n",
+ " unconditional_guidance_scale=scale,\n",
+ " unconditional_conditioning=uc, \n",
+ " eta=ddim_eta)\n",
+ "\n",
+ " x_samples_ddim = model.decode_first_stage(samples_ddim)\n",
+ " x_samples_ddim = torch.clamp((x_samples_ddim+1.0)/2.0, \n",
+ " min=0.0, max=1.0)\n",
+ " all_samples.append(x_samples_ddim)\n",
+ "\n",
+ "\n",
+ "# display as grid\n",
+ "grid = torch.stack(all_samples, 0)\n",
+ "grid = rearrange(grid, 'n b c h w -> (n b) c h w')\n",
+ "grid = make_grid(grid, nrow=n_samples_per_class)\n",
+ "\n",
+ "# to image\n",
+ "grid = 255. * rearrange(grid, 'c h w -> h w c').cpu().numpy()\n",
+ "Image.fromarray(grid.astype(np.uint8))"
+ ],
+ "metadata": {
+ "id": "jcbqWX2Ytu9t",
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 1000
+ },
+ "outputId": "3b7adde0-d80e-4c01-82d2-bf988aee7455"
+ },
+ "execution_count": null,
+ "outputs": [
+ {
+ "output_type": "stream",
+ "name": "stdout",
+ "text": [
+ "rendering 6 examples of class '25' in 20 steps and using s=3.00.\n",
+ "Data shape for DDIM sampling is (6, 3, 64, 64), eta 0.0\n",
+ "Running DDIM Sampling with 20 timesteps\n"
+ ]
+ },
+ {
+ "output_type": "stream",
+ "name": "stderr",
+ "text": [
+ "DDIM Sampler: 100%|ββββββββββ| 20/20 [00:37<00:00, 1.89s/it]\n"
+ ]
+ },
+ {
+ "output_type": "stream",
+ "name": "stdout",
+ "text": [
+ "rendering 6 examples of class '187' in 20 steps and using s=3.00.\n",
+ "Data shape for DDIM sampling is (6, 3, 64, 64), eta 0.0\n",
+ "Running DDIM Sampling with 20 timesteps\n"
+ ]
+ },
+ {
+ "output_type": "stream",
+ "name": "stderr",
+ "text": [
+ "DDIM Sampler: 100%|ββββββββββ| 20/20 [00:37<00:00, 1.87s/it]\n"
+ ]
+ },
+ {
+ "output_type": "stream",
+ "name": "stdout",
+ "text": [
+ "rendering 6 examples of class '448' in 20 steps and using s=3.00.\n",
+ "Data shape for DDIM sampling is (6, 3, 64, 64), eta 0.0\n",
+ "Running DDIM Sampling with 20 timesteps\n"
+ ]
+ },
+ {
+ "output_type": "stream",
+ "name": "stderr",
+ "text": [
+ "DDIM Sampler: 100%|ββββββββββ| 20/20 [00:37<00:00, 1.86s/it]\n"
+ ]
+ },
+ {
+ "output_type": "stream",
+ "name": "stdout",
+ "text": [
+ "rendering 6 examples of class '992' in 20 steps and using s=3.00.\n",
+ "Data shape for DDIM sampling is (6, 3, 64, 64), eta 0.0\n",
+ "Running DDIM Sampling with 20 timesteps\n"
+ ]
+ },
+ {
+ "output_type": "stream",
+ "name": "stderr",
+ "text": [
+ "DDIM Sampler: 100%|ββββββββββ| 20/20 [00:37<00:00, 1.86s/it]\n"
+ ]
+ },
+ {
+ "output_type": "execute_result",
+ "data": {
+ "text/plain": [
+ ""
+ ],
+ "image/png": "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0TVjM3P+tDOdoFObBVR06rC0u6na5rc/9Dd//am/fMvNd//gP33N3O37KdGf+Z1+I8h7S40optNPP61MvLV5ZW5h4cTp86zrF168cu/d+3fvrhXlBW50vvUH93z1k/2Pfub5y9PN0WjyyqN7X3nbHuX0+tD95G9+cBjy5ihxpZAOtVFYdeCyGCIprXDRnQfN2TRXVtHQq4up/alffv/3PAhHlhdcibtajVqweCkZxvGBrYEPurc9+tzq3Fw8v1DzPkmHFpwPwgZ4O4EaGOVJMnAnL127/aajocZOLZxr7D7x9KmFpc7+5faH//S9KoyP3HD46G23b10uXcHf9+7v5Wx49uxlycpptj0arReSCdLzT57tvarnsDMsVocbg4mtndu8ctuhA8X506PhoMlkU9zfjY4enK/N9VYvWTtkKvK777r18oV1O2EwIQN1iZba7a8++cTK3HwY8otPH9/eWA/V/O33HHv+eHJ4Xy/N09Lp3r744NHDJ09ebS82zl5aP7u6QXH71v37YptDLkvt5k0vO/zrf/bhT567+qo3veHks0/UTLe50H32a08fveUwmlqRbj5+4sTttx8GgiDUIuKZdRB5LBShJl2WmRDE9QaRdq5MJmmzPj+duihuegbIC86ngcb5+XmlY1cmzL7erGfZEFGjJm+l1uqgUuCDdDwJg7KcbuaTDQepiTO0KWl99wMPPP7E48IOEVQtMIihpiIZBnW484H7n/zKE1maze3efejYjS88/NViAiuH9mxdHW8N14KF7vKuXZMrZ0+fPRXVKXTtlf03jgZDpHj18qX2fOvgjStnX3ymf/l0J5LN0XQ63BAFwnGSJvc+cMeZF44vdecmWb/enouSYnWw2ekdiZrzV89eCIJAg7Rqjbe+7sFPfPSzg8G1PYeWvvLww7ffdai/0Z9b7MwGA13WesHmuK+NxFoNB/0odBnHG6Nye7KJfssl45ffsntx/544DqjhMGQTkiCw8oKp9RNv8wCAoECbQW59JrUoyIFtlgkQB0qzn1y9DN161IhjlsLa6WiSZ2msdRiZ5XbcqddqWqO31oFROgggUBhiEWjJ02kpqshS9lZ5zMZJrRbUarWiSNNiCuA1YmnLsnA6RG99KR4YE1ugjlgUijZBAFACeWEBYUZkURq1sGdg551FcQo9SM1osVYYlQosiNEchhEClNaWzvoS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P/6ZJzbWrs0YNKPd7d2M+3LQsztbo4tvVG9c3E2adHVQLDYju9tNIo5riVqchO4YAKJmUoxobmL2obh59x03fvnxF1585hx5cjZURS4FoxRSy6wIIuCZ06/+xq//87oUAqEeKy6KOPLvfut3rqxfubhxZXv9Ggp0pdVCj0b9LOHRLp977trhGyZGVy9Oz7XTWnT67M6Lp/Ot7cmbjh989crK8ohXVnNQSAjoXWyMDU4IDCEwsURFCIgCBUohkAFQCQSBSOCASAgwUhABSqEUKCO1NEaCFO7otHvXt82/437ZqmUau8ykVU3ENfZSWHIWBWBSG99/T+OlC/288oxonTsweaTX291DzKwsr+tYI6ED6NRr1jrnKwAIIejUzMwe3N694suqIlacPPy5r82/uDzevhhC5V0QRCrhialj7/+WH3740b/Nt1bSZjOE4h0PLH3re244eU81sQhAI7L59HR66o4b3vNP7veBesuDx77w4nOv9J97zW5laEvhvBAStZZMtPcuapQJgVCid957TwTsSQiJAglBaiGFULzHJRAIApjIeyElMwEGBEQhEVFJ411FRByYrJcSAVFopYGMjgQIH5zWyrq9oBJS8ABBCGClna9/4rHe15+/9PZbZh64aXZxX82FTNYh0C4K6W2/09QzEzWC1mAsn3rxSt/TYJxl3t55eLbeTIXisqoS0/Gu7K+txzqSwRWBtallNpTSRHEjJ5lDNgoucmXcaELEzUhJUy+dl2ikkTaUJJRsLfY8hCJ/8O6b//7Tn3rhhTPt9vTC9OSJW06Yte1rm8vrW1cn622DmFWu02w10zS4gpzXkQzl2Me49yxom5rBSAp+5cwaoDzYab9yeXz3rYdFsBE5FYKlQup68KF0ToASIAa98LG/fHljmwIpT54F7H3JQu4NNEFKAQDeByUVCPRMtqKzp6/tX5wR1SgRWhrzd5/7zA9/9z977vTDKJWQMD89MdrYqTVaLh8fWaj3lpLb3nLTIAskVdRZmj6lVp7dTA8kVdz3SZomev+bp/ffmvZe3zixUP3SP1340hNXLnWvgW4waogTZwk5H8Bmp1nLtoqe553u9kwnmpttJlEsCwfBt03CFkwcCyE7kg5OK62qYliQlctXRlnGzZbuxCqJhRChNRfNTSU7vUEU077j8eSUWFvJx9Z2++BBHN8nbjyii6oiCYUF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