init opensource code
Browse files- .gitignore +21 -0
- LICENSE +21 -0
- README.md +130 -3
- calc_fid.py +34 -0
- checkpoints/baseline.pt +3 -0
- checkpoints/flow_matching.pt +3 -0
- checkpoints/flow_matching_tail_dropout.pt +3 -0
- checkpoints/flow_matching_tied_tail_dropout.pt +3 -0
- checkpoints/tail_dropout.pt +3 -0
- checkpoints/war.pt +3 -0
- configs/cifar10/baseline_ar.yaml +198 -0
- configs/cifar10/baseline_tokenizer.yaml +198 -0
- configs/cifar10/flow_matching_ar.yaml +198 -0
- configs/cifar10/flow_matching_tail_dropout_ar.yaml +198 -0
- configs/cifar10/flow_matching_tail_dropout_tokenizer.yaml +198 -0
- configs/cifar10/flow_matching_tied_tail_dropout_ar.yaml +198 -0
- configs/cifar10/flow_matching_tied_tail_dropout_tokenizer.yaml +198 -0
- configs/cifar10/flow_matching_tokenizer.yaml +198 -0
- configs/cifar10/tail_dropout_ar.yaml +198 -0
- configs/cifar10/tail_dropout_tokenizer.yaml +198 -0
- configs/cifar10/war_ar.yaml +201 -0
- configs/cifar10/war_tokenizer.yaml +201 -0
- dataset.py +415 -0
- dnnlib/__init__.py +8 -0
- dnnlib/util.py +491 -0
- evaluate.py +181 -0
- evaluator.py +675 -0
- gan_loss.py +1229 -0
- lpips.py +164 -0
- models.py +1013 -0
- refs/cifar10-32x32_local.npz +3 -0
- requirements.txt +15 -0
- scripts/dataset_tools.py +618 -0
- scripts/evaluate_all.py +130 -0
- scripts/export_checkpoint.py +47 -0
- scripts/prepare_cifar10.py +31 -0
- train.py +1209 -0
.gitignore
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
__pycache__/
|
| 2 |
+
*.py[cod]
|
| 3 |
+
.env
|
| 4 |
+
.venv/
|
| 5 |
+
.DS_Store
|
| 6 |
+
*.local.*
|
| 7 |
+
/outputs
|
| 8 |
+
/cache
|
| 9 |
+
/data
|
| 10 |
+
/release
|
| 11 |
+
wandb/
|
| 12 |
+
*.ckpt
|
| 13 |
+
*.pt
|
| 14 |
+
*.pth
|
| 15 |
+
*.npz
|
| 16 |
+
*.pb
|
| 17 |
+
*.log
|
| 18 |
+
|
| 19 |
+
# Model assets distributed on Hugging Face.
|
| 20 |
+
!/checkpoints/*.pt
|
| 21 |
+
!/refs/*.npz
|
LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2025 Bowen Zheng, The Chinese University of Hong Kong, Shenzhen
|
| 4 |
+
|
| 5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 7 |
+
in the Software without restriction, including without limitation the rights
|
| 8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 9 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 10 |
+
furnished to do so, subject to the following conditions:
|
| 11 |
+
|
| 12 |
+
The above copyright notice and this permission notice shall be included in all
|
| 13 |
+
copies or substantial portions of the Software.
|
| 14 |
+
|
| 15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 21 |
+
SOFTWARE.
|
README.md
CHANGED
|
@@ -1,3 +1,130 @@
|
|
| 1 |
-
-
|
| 2 |
-
|
| 3 |
-
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# wAR-Tok: Learning Discrete Autoregressive Priors with Wasserstein Gradient Flow
|
| 2 |
+
|
| 3 |
+
CIFAR-10 implementation of [our paper](https://arxiv.org/abs/2605.06148).
|
| 4 |
+
|
| 5 |
+
## Features
|
| 6 |
+
|
| 7 |
+
- Discrete image tokenization with Wasserstein gradient flow regularization.
|
| 8 |
+
- Transformer encoder and decoder with cross-attention, RMSNorm and GEGLU.
|
| 9 |
+
- Six variants: baseline, tail dropout, flow matching, FM + tail dropout, FM + tied tail dropout, and wAR-Tok.
|
| 10 |
+
- Two-stage training: tokenizer training followed by an autoregressive prior.
|
| 11 |
+
- Mixed precision, multi-GPU training and optional W&B logging.
|
| 12 |
+
|
| 13 |
+
## Quick Start
|
| 14 |
+
|
| 15 |
+
### Installation
|
| 16 |
+
|
| 17 |
+
Use Python 3.12 and CUDA. The training environment uses PyTorch 2.8.0 / CUDA 12.8.
|
| 18 |
+
|
| 19 |
+
```bash
|
| 20 |
+
python -m venv .venv
|
| 21 |
+
source .venv/bin/activate
|
| 22 |
+
pip install -r requirements.txt
|
| 23 |
+
```
|
| 24 |
+
|
| 25 |
+
### Data Preparation
|
| 26 |
+
|
| 27 |
+
```bash
|
| 28 |
+
python scripts/prepare_cifar10.py --download
|
| 29 |
+
```
|
| 30 |
+
|
| 31 |
+
This prepares the CIFAR-10 training split under `data/cifar10`. Download the [FID reference](https://huggingface.co/Zyriix/wARTok/resolve/main/refs/cifar10-32x32_local.npz?download=true) to `refs/cifar10-32x32_local.npz`.
|
| 32 |
+
|
| 33 |
+
### Training
|
| 34 |
+
|
| 35 |
+
The default configuration uses 8 GPUs, global batch size 512 and BF16. Each method has a `*_tokenizer.yaml` and a `*_ar.yaml` in [configs/cifar10](configs/cifar10): train the tokenizer for 400K steps, then the AR prior for 200K steps.
|
| 36 |
+
|
| 37 |
+
**Stage 1: Train the tokenizer**
|
| 38 |
+
|
| 39 |
+
```bash
|
| 40 |
+
python train.py --config=configs/cifar10/war_tokenizer.yaml
|
| 41 |
+
```
|
| 42 |
+
|
| 43 |
+
**Stage 2: Train the AR prior**
|
| 44 |
+
|
| 45 |
+
```bash
|
| 46 |
+
python train.py --config=configs/cifar10/war_ar.yaml \
|
| 47 |
+
ae_ckpt_path=./outputs/war_tokenizer/000/ckpts/last.ckpt
|
| 48 |
+
```
|
| 49 |
+
|
| 50 |
+
The AR configuration defaults to the matching tokenizer's `000/ckpts/last.ckpt`. Set `WANDB_MODE=online` to enable experiment logging.
|
| 51 |
+
|
| 52 |
+
### Evaluation
|
| 53 |
+
|
| 54 |
+
Use the matching tokenizer configuration for reconstruction and the AR configuration for generation. FM reconstruction uses 25 Euler steps; generation uses a single decoder step. Evaluation uses FP32; generation uses AR EMA, temperature 1, CFG 0 and no top-k/top-p filtering.
|
| 55 |
+
|
| 56 |
+
**Reconstruction**
|
| 57 |
+
|
| 58 |
+
```bash
|
| 59 |
+
CUDA_VISIBLE_DEVICES=0 python evaluate.py \
|
| 60 |
+
--config configs/cifar10/war_tokenizer.yaml --checkpoint checkpoints/war.pt \
|
| 61 |
+
--mode reconstruct --data data/cifar10 --num-samples 50000 \
|
| 62 |
+
--output outputs/war-reconstruction --fid-reference refs/cifar10-32x32_local.npz
|
| 63 |
+
```
|
| 64 |
+
|
| 65 |
+
**Generation**
|
| 66 |
+
|
| 67 |
+
```bash
|
| 68 |
+
CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 torchrun --standalone --nproc-per-node=8 evaluate.py \
|
| 69 |
+
--config configs/cifar10/war_ar.yaml --checkpoint checkpoints/war.pt \
|
| 70 |
+
--num-samples 50000 --batch-size 64 --seed 42 --no-legacy \
|
| 71 |
+
--output outputs/war-generation --fid-reference refs/cifar10-32x32_local.npz
|
| 72 |
+
```
|
| 73 |
+
|
| 74 |
+
Non-legacy mode (`--no-legacy`) uses a different seed on each GPU and generally yields [lower gFID scores](#checkpoints), without changing the relative ranking of the methods or the conclusions supported by the results.
|
| 75 |
+
|
| 76 |
+
To evaluate all six checkpoints with `--no-legacy`:
|
| 77 |
+
|
| 78 |
+
```bash
|
| 79 |
+
python scripts/evaluate_all.py --gpus 0,1,2,3,4,5,6,7 \
|
| 80 |
+
--output outputs/cifar10-nonlegacy
|
| 81 |
+
```
|
| 82 |
+
|
| 83 |
+
Use `--methods baseline war` for a subset or `--resume` to reuse completed evaluations.
|
| 84 |
+
|
| 85 |
+
### Exporting Checkpoints
|
| 86 |
+
|
| 87 |
+
```bash
|
| 88 |
+
python scripts/export_checkpoint.py --source path/to/raw-ar.ckpt \
|
| 89 |
+
--config configs/cifar10/war_ar.yaml --output checkpoints/war.pt
|
| 90 |
+
```
|
| 91 |
+
|
| 92 |
+
The export includes tokenizer and raw/EMA AR weights without optimizer states.
|
| 93 |
+
|
| 94 |
+
## Checkpoints
|
| 95 |
+
|
| 96 |
+
Name checkpoints after their configuration prefix (e.g. `baseline_ar.yaml` → `checkpoints/baseline.pt`, `war_ar.yaml` → `checkpoints/war.pt`); each includes the tokenizer and raw/EMA AR weights. Hugging Face repository: [wARTok](https://huggingface.co/Zyriix/wARTok).
|
| 97 |
+
|
| 98 |
+
| Method | rFID | Historical gFID | Non-legacy gFID | Download |
|
| 99 |
+
|---|---:|---:|---:|---|
|
| 100 |
+
| [Baseline](configs/cifar10/baseline_ar.yaml) | 2.3015 | 52.5343 | 49.4191 | [Download](https://huggingface.co/Zyriix/wARTok/resolve/main/checkpoints/baseline.pt?download=true) |
|
| 101 |
+
| [Tail Dropout](configs/cifar10/tail_dropout_ar.yaml) | 3.3567 | 23.3713 | 19.8997 | [Download](https://huggingface.co/Zyriix/wARTok/resolve/main/checkpoints/tail_dropout.pt?download=true) |
|
| 102 |
+
| [FM](configs/cifar10/flow_matching_ar.yaml) | 3.4194 | 38.6309 | 35.8593 | [Download](https://huggingface.co/Zyriix/wARTok/resolve/main/checkpoints/flow_matching.pt?download=true) |
|
| 103 |
+
| [FM + Tail](configs/cifar10/flow_matching_tail_dropout_ar.yaml) | 4.4247 | 22.7613 | 19.0569 | [Download](https://huggingface.co/Zyriix/wARTok/resolve/main/checkpoints/flow_matching_tail_dropout.pt?download=true) |
|
| 104 |
+
| [FM + Tail + Tied](configs/cifar10/flow_matching_tied_tail_dropout_ar.yaml) | 6.4911 | 44.7971 | 41.1334 | [Download](https://huggingface.co/Zyriix/wARTok/resolve/main/checkpoints/flow_matching_tied_tail_dropout.pt?download=true) |
|
| 105 |
+
| [wAR-Tok](configs/cifar10/war_ar.yaml) | 3.0648 | 11.3059 | 7.3749 | [Download](https://huggingface.co/Zyriix/wARTok/resolve/main/checkpoints/war.pt?download=true) |
|
| 106 |
+
|
| 107 |
+
Download the [FID reference](https://huggingface.co/Zyriix/wARTok/resolve/main/refs/cifar10-32x32_local.npz?download=true) to `refs/cifar10-32x32_local.npz`.
|
| 108 |
+
|
| 109 |
+
## Project Structure
|
| 110 |
+
|
| 111 |
+
```text
|
| 112 |
+
wAR/
|
| 113 |
+
├── configs/cifar10/ # Training configurations
|
| 114 |
+
├── checkpoints/ # Downloaded weights
|
| 115 |
+
├── scripts/ # Data preparation and evaluation tools
|
| 116 |
+
├── models.py # Model architectures
|
| 117 |
+
├── train.py # Tokenizer and AR training
|
| 118 |
+
├── evaluate.py # Reconstruction and generation
|
| 119 |
+
├── dataset.py # Data loading
|
| 120 |
+
├── lpips.py # Perceptual loss
|
| 121 |
+
└── calc_fid.py # ADM FID evaluation
|
| 122 |
+
```
|
| 123 |
+
|
| 124 |
+
## References
|
| 125 |
+
|
| 126 |
+
This project builds on [EDM](https://github.com/NVlabs/edm), [ADM](https://github.com/openai/guided-diffusion), and [LPIPS](https://github.com/richzhang/PerceptualSimilarity).
|
| 127 |
+
|
| 128 |
+
## License
|
| 129 |
+
|
| 130 |
+
Project-authored code is covered by [MIT](LICENSE). Third-party components retain their original licenses.
|
calc_fid.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""ADM FID, preserving the input reference archive."""
|
| 2 |
+
import argparse
|
| 3 |
+
import math
|
| 4 |
+
import numpy as np
|
| 5 |
+
import tensorflow.compat.v1 as tf
|
| 6 |
+
from evaluator import Evaluator
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def main():
|
| 10 |
+
parser = argparse.ArgumentParser(description=__doc__)
|
| 11 |
+
parser.add_argument('--ref_batch', required=True)
|
| 12 |
+
parser.add_argument('--sample_batch', required=True)
|
| 13 |
+
parser.add_argument('--batch_size', type=int, default=64)
|
| 14 |
+
parser.add_argument('--write-reference-stats', help='Optional NEW cache file; never overwrites the reference')
|
| 15 |
+
args = parser.parse_args()
|
| 16 |
+
if args.batch_size < 1: parser.error('batch_size must be positive')
|
| 17 |
+
config = tf.ConfigProto(allow_soft_placement=True, intra_op_parallelism_threads=8, inter_op_parallelism_threads=8)
|
| 18 |
+
config.gpu_options.allow_growth = True
|
| 19 |
+
with tf.Session(config=config) as session:
|
| 20 |
+
evaluator = Evaluator(session, batch_size=args.batch_size)
|
| 21 |
+
evaluator.warmup()
|
| 22 |
+
ref_acts = evaluator.read_activations(args.ref_batch)
|
| 23 |
+
ref, spatial = evaluator.read_statistics(args.ref_batch, ref_acts)
|
| 24 |
+
sample_acts = evaluator.read_activations(args.sample_batch)
|
| 25 |
+
sample, _ = evaluator.read_statistics(args.sample_batch, sample_acts)
|
| 26 |
+
fid = sample.frechet_distance(ref)
|
| 27 |
+
if not math.isfinite(fid): raise ValueError(f'Non-finite FID: {fid}')
|
| 28 |
+
if args.write_reference_stats:
|
| 29 |
+
with open(args.write_reference_stats, 'xb') as f:
|
| 30 |
+
np.savez_compressed(f, mu=ref.mu, sigma=ref.sigma, mu_s=spatial.mu, sigma_s=spatial.sigma)
|
| 31 |
+
print(f'FID_RESULT:{fid}')
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
if __name__ == '__main__': main()
|
checkpoints/baseline.pt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:ec76675438aa159dfcddf8b4f153ed5f418fc8d2cb01d2f38f082ad32c3e0d85
|
| 3 |
+
size 887697419
|
checkpoints/flow_matching.pt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:6d9a7c13f0b199b07fec4f500296a7d5f1f815aec2d81f8635e6ee37a2d30e61
|
| 3 |
+
size 887699762
|
checkpoints/flow_matching_tail_dropout.pt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:043dc2f5e32100d2b531007bbdf33c72d57a721d4826672742aa1a85a871a7aa
|
| 3 |
+
size 887699762
|
checkpoints/flow_matching_tied_tail_dropout.pt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:490c18b0542a92a7950a370b26b3a9660597b1e1a0977c8fc593ee0bfceab728
|
| 3 |
+
size 887699762
|
checkpoints/tail_dropout.pt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:8c790a89b69de1d3bb55acc14f72bc46f723bbf13e5d5753a2fef1b8d201e0b3
|
| 3 |
+
size 887697419
|
checkpoints/war.pt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:9c58f2a9520de64e1a29f0e431be15f069b16a88d5a5938da1f36b7b049fbf5c
|
| 3 |
+
size 887697419
|
configs/cifar10/baseline_ar.yaml
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
wandb_project: wAR
|
| 2 |
+
wandb_name: baseline_ar
|
| 3 |
+
data_dir: ./data/cifar10
|
| 4 |
+
xflip: true
|
| 5 |
+
crop_type: center
|
| 6 |
+
image_size: 32
|
| 7 |
+
num_channels: 3
|
| 8 |
+
num_classes: 11
|
| 9 |
+
patch_size: 4
|
| 10 |
+
use_label: false
|
| 11 |
+
patch_dim: 48
|
| 12 |
+
x_len: 64
|
| 13 |
+
diffusion_decoder: false
|
| 14 |
+
train_ae: false
|
| 15 |
+
train_ar: true
|
| 16 |
+
phases: 200000:DO_PRIOR_AR:1
|
| 17 |
+
batch_size: 512
|
| 18 |
+
eval_batch_size: 512
|
| 19 |
+
lr_enc: 0.00015
|
| 20 |
+
lr_dec: 0.00015
|
| 21 |
+
lr_ar: 0.00015
|
| 22 |
+
lr_gan_loss: 0.00015
|
| 23 |
+
weight_decay_enc: 0.0
|
| 24 |
+
weight_decay_dec: 0.0
|
| 25 |
+
weight_decay_ar: 0.0001
|
| 26 |
+
weight_decay_gan: 0.0001
|
| 27 |
+
lr_enc_min: 3.0e-05
|
| 28 |
+
lr_dec_min: 3.0e-05
|
| 29 |
+
lr_ar_min: 3.0e-05
|
| 30 |
+
lr_gan_loss_min: 3.0e-05
|
| 31 |
+
use_tf32: false
|
| 32 |
+
lr_scheduler: none
|
| 33 |
+
drop: 0.0
|
| 34 |
+
ar_drop: 0.1
|
| 35 |
+
grad_clip: 0.0
|
| 36 |
+
seed: 42
|
| 37 |
+
beta1: 0.5
|
| 38 |
+
beta2: 0.95
|
| 39 |
+
ar_beta1: 0.9
|
| 40 |
+
ar_beta2: 0.99
|
| 41 |
+
label_drop_prob: 0.1
|
| 42 |
+
precision: bf16-mixed
|
| 43 |
+
replace_cur_with_ema: false
|
| 44 |
+
num_workers: 4
|
| 45 |
+
devices: 8
|
| 46 |
+
reverse_t: true
|
| 47 |
+
use_noise_query: false
|
| 48 |
+
use_tail_dropout: false
|
| 49 |
+
l2_v_target: false
|
| 50 |
+
tail_dropout_t2k: 1.0
|
| 51 |
+
tied_timestep: false
|
| 52 |
+
time_stages: 200,400,600,800,1000
|
| 53 |
+
k_per_stage: 192,184,72,48,16
|
| 54 |
+
load_ar_model: false
|
| 55 |
+
load_ar_model_ema: false
|
| 56 |
+
prior_G_loss: false
|
| 57 |
+
use_l1_loss: false
|
| 58 |
+
use_l2_loss: false
|
| 59 |
+
use_lpips_loss: false
|
| 60 |
+
use_gan_loss: false
|
| 61 |
+
use_prior_loss: false
|
| 62 |
+
teacher_forcing_ae: false
|
| 63 |
+
disc_adaptive_weight: false
|
| 64 |
+
lpips_weight: 0.1
|
| 65 |
+
gan_G_weight: 0.1
|
| 66 |
+
prior_enc_weight: 1.0
|
| 67 |
+
l1_weight: 0.1
|
| 68 |
+
l2_weight: 1.0
|
| 69 |
+
gan_start: 5000
|
| 70 |
+
prior_start: 0
|
| 71 |
+
tail_dropout_start: 0
|
| 72 |
+
tail_dropout_p: 0.0
|
| 73 |
+
torch_compile: true
|
| 74 |
+
compile_ae: true
|
| 75 |
+
compile_ar: true
|
| 76 |
+
compile_gan: false
|
| 77 |
+
ar_ema_halflife: 2000
|
| 78 |
+
ae_ema_halflife: 0
|
| 79 |
+
ema_sampling: true
|
| 80 |
+
ema_reconstruction: false
|
| 81 |
+
cache_kv: true
|
| 82 |
+
topK: 0.0
|
| 83 |
+
topP: 0.0
|
| 84 |
+
cfg: 0.0
|
| 85 |
+
cfg_schedule: cosine
|
| 86 |
+
cfg_power: 2.75
|
| 87 |
+
temperature: 1.0
|
| 88 |
+
eval_data_dir: ./data/cifar10
|
| 89 |
+
eval_crop_type: center
|
| 90 |
+
eval_fid_ref_path: ./refs/cifar10-32x32_local.npz
|
| 91 |
+
save_dir: ./outputs/baseline_ar
|
| 92 |
+
log_freq: 25
|
| 93 |
+
visualize_freq: 5000
|
| 94 |
+
visualize_img_num: 8
|
| 95 |
+
ckpt_freq: 25000
|
| 96 |
+
eval_freq: 25000
|
| 97 |
+
save_ckpt: true
|
| 98 |
+
ar_ckpt_path: ''
|
| 99 |
+
ae_ckpt_path: ./outputs/baseline_tokenizer/000/ckpts/last.ckpt
|
| 100 |
+
resume_optimizer: false
|
| 101 |
+
cond_emb_dim: 32
|
| 102 |
+
greedy_coding_prob: 0.0
|
| 103 |
+
z_len: 64
|
| 104 |
+
z_dim: 512
|
| 105 |
+
vq_type: VQ
|
| 106 |
+
codebook_size: 1024
|
| 107 |
+
norm_layer: RMSNorm
|
| 108 |
+
ffn_type: geglu
|
| 109 |
+
context_type: cross_attn
|
| 110 |
+
hidden_dim: 512
|
| 111 |
+
Encoder:
|
| 112 |
+
input_dim: 48
|
| 113 |
+
output_dim: 512
|
| 114 |
+
cond_dim: 32
|
| 115 |
+
cond_input_dim: 11
|
| 116 |
+
max_seq_len: 64
|
| 117 |
+
ctx_max_seq_len: 64
|
| 118 |
+
dim: 512
|
| 119 |
+
layer_num: 10
|
| 120 |
+
mlp_ratio: 4.0
|
| 121 |
+
heads: 8
|
| 122 |
+
emb_dropout: 0.0
|
| 123 |
+
drop: 0.0
|
| 124 |
+
l2_norm: false
|
| 125 |
+
context_type: cross_attn
|
| 126 |
+
rope: false
|
| 127 |
+
abs_pos: true
|
| 128 |
+
causal: false
|
| 129 |
+
norm_layer: RMSNorm
|
| 130 |
+
ffn_type: geglu
|
| 131 |
+
Quantizer:
|
| 132 |
+
codebook_size: 1024
|
| 133 |
+
z_dim: 12
|
| 134 |
+
dim: 512
|
| 135 |
+
length: 64
|
| 136 |
+
cond_dim: 32
|
| 137 |
+
cond_affine_norm: false
|
| 138 |
+
vq_beta: 0.25
|
| 139 |
+
use_norm: true
|
| 140 |
+
norm_layer: l2
|
| 141 |
+
ffn_type: geglu
|
| 142 |
+
temperature: 1.0
|
| 143 |
+
Decoder:
|
| 144 |
+
input_dim: 48
|
| 145 |
+
ctx_input_dim: 512
|
| 146 |
+
output_dim: 48
|
| 147 |
+
cond_dim: 32
|
| 148 |
+
cond_input_dim: 11
|
| 149 |
+
max_seq_len: 64
|
| 150 |
+
ctx_max_seq_len: 64
|
| 151 |
+
dim: 512
|
| 152 |
+
layer_num: 10
|
| 153 |
+
heads: 8
|
| 154 |
+
emb_dropout: 0.0
|
| 155 |
+
drop: 0.0
|
| 156 |
+
l2_norm: false
|
| 157 |
+
context_type: cross_attn
|
| 158 |
+
rope: false
|
| 159 |
+
abs_pos: true
|
| 160 |
+
causal: false
|
| 161 |
+
norm_layer: RMSNorm
|
| 162 |
+
ffn_type: geglu
|
| 163 |
+
mlp_ratio: 4.0
|
| 164 |
+
zero_out: true
|
| 165 |
+
query_type: learnable
|
| 166 |
+
ARModel:
|
| 167 |
+
input_dim: 512
|
| 168 |
+
output_dim: 1024
|
| 169 |
+
max_seq_len: 64
|
| 170 |
+
cond_dim: 32
|
| 171 |
+
cond_input_dim: 11
|
| 172 |
+
dim: 512
|
| 173 |
+
layer_num: 13
|
| 174 |
+
heads: 8
|
| 175 |
+
emb_dropout: 0.0
|
| 176 |
+
drop: 0.1
|
| 177 |
+
l2_norm: false
|
| 178 |
+
context_type: none
|
| 179 |
+
rope: false
|
| 180 |
+
abs_pos: true
|
| 181 |
+
causal: true
|
| 182 |
+
out_act: false
|
| 183 |
+
norm_layer: RMSNorm
|
| 184 |
+
ffn_type: geglu
|
| 185 |
+
mlp_ratio: 4.0
|
| 186 |
+
zero_out: false
|
| 187 |
+
temperature: 1.0
|
| 188 |
+
GANLoss:
|
| 189 |
+
disc_loss: vanilla
|
| 190 |
+
disc_dim: 64
|
| 191 |
+
disc_type: patchgan
|
| 192 |
+
image_size: 32
|
| 193 |
+
disc_num_layers: 3
|
| 194 |
+
disc_in_channels: 3
|
| 195 |
+
gen_adv_loss: vanilla
|
| 196 |
+
lecam_loss_weight: 0.001
|
| 197 |
+
norm_type: bn
|
| 198 |
+
aug_prob: 1.0
|
configs/cifar10/baseline_tokenizer.yaml
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
wandb_project: wAR
|
| 2 |
+
wandb_name: baseline_tokenizer
|
| 3 |
+
data_dir: ./data/cifar10
|
| 4 |
+
xflip: true
|
| 5 |
+
crop_type: center
|
| 6 |
+
image_size: 32
|
| 7 |
+
num_channels: 3
|
| 8 |
+
num_classes: 11
|
| 9 |
+
patch_size: 4
|
| 10 |
+
use_label: false
|
| 11 |
+
patch_dim: 48
|
| 12 |
+
x_len: 64
|
| 13 |
+
diffusion_decoder: false
|
| 14 |
+
train_ae: true
|
| 15 |
+
train_ar: false
|
| 16 |
+
phases: 400000:DO_L1-DO_L2-DO_LPIPS:1
|
| 17 |
+
batch_size: 512
|
| 18 |
+
eval_batch_size: 512
|
| 19 |
+
lr_enc: 0.00015
|
| 20 |
+
lr_dec: 0.00015
|
| 21 |
+
lr_ar: 0.00015
|
| 22 |
+
lr_gan_loss: 0.00015
|
| 23 |
+
weight_decay_enc: 0.0
|
| 24 |
+
weight_decay_dec: 0.0
|
| 25 |
+
weight_decay_ar: 0.0
|
| 26 |
+
weight_decay_gan: 0.0001
|
| 27 |
+
lr_enc_min: 3.0e-05
|
| 28 |
+
lr_dec_min: 3.0e-05
|
| 29 |
+
lr_ar_min: 3.0e-05
|
| 30 |
+
lr_gan_loss_min: 3.0e-05
|
| 31 |
+
use_tf32: false
|
| 32 |
+
lr_scheduler: none
|
| 33 |
+
drop: 0.0
|
| 34 |
+
ar_drop: 0.0
|
| 35 |
+
grad_clip: 0.0
|
| 36 |
+
seed: 42
|
| 37 |
+
beta1: 0.5
|
| 38 |
+
beta2: 0.95
|
| 39 |
+
ar_beta1: 0.5
|
| 40 |
+
ar_beta2: 0.95
|
| 41 |
+
label_drop_prob: 0.1
|
| 42 |
+
precision: bf16-mixed
|
| 43 |
+
replace_cur_with_ema: false
|
| 44 |
+
num_workers: 4
|
| 45 |
+
devices: 8
|
| 46 |
+
reverse_t: false
|
| 47 |
+
use_noise_query: false
|
| 48 |
+
use_tail_dropout: false
|
| 49 |
+
l2_v_target: false
|
| 50 |
+
tail_dropout_t2k: 1.0
|
| 51 |
+
tied_timestep: false
|
| 52 |
+
time_stages: 200,400,600,800,1000
|
| 53 |
+
k_per_stage: 192,184,72,48,16
|
| 54 |
+
load_ar_model: false
|
| 55 |
+
load_ar_model_ema: false
|
| 56 |
+
prior_G_loss: false
|
| 57 |
+
use_l1_loss: true
|
| 58 |
+
use_l2_loss: true
|
| 59 |
+
use_lpips_loss: true
|
| 60 |
+
use_gan_loss: false
|
| 61 |
+
use_prior_loss: false
|
| 62 |
+
teacher_forcing_ae: false
|
| 63 |
+
disc_adaptive_weight: false
|
| 64 |
+
lpips_weight: 0.1
|
| 65 |
+
gan_G_weight: 0.1
|
| 66 |
+
prior_enc_weight: 1.0
|
| 67 |
+
l1_weight: 0.1
|
| 68 |
+
l2_weight: 1.0
|
| 69 |
+
gan_start: 5000
|
| 70 |
+
prior_start: 0
|
| 71 |
+
tail_dropout_start: 0
|
| 72 |
+
tail_dropout_p: 0
|
| 73 |
+
torch_compile: true
|
| 74 |
+
compile_ae: true
|
| 75 |
+
compile_ar: true
|
| 76 |
+
compile_gan: false
|
| 77 |
+
ar_ema_halflife: 2500
|
| 78 |
+
ae_ema_halflife: 1000
|
| 79 |
+
ema_sampling: false
|
| 80 |
+
ema_reconstruction: false
|
| 81 |
+
cache_kv: true
|
| 82 |
+
topK: 0.0
|
| 83 |
+
topP: 0.0
|
| 84 |
+
cfg: 0.0
|
| 85 |
+
cfg_schedule: cosine
|
| 86 |
+
cfg_power: 2.75
|
| 87 |
+
temperature: 1.0
|
| 88 |
+
eval_data_dir: ./data/cifar10
|
| 89 |
+
eval_crop_type: center
|
| 90 |
+
eval_fid_ref_path: ./refs/cifar10-32x32_local.npz
|
| 91 |
+
save_dir: ./outputs/baseline_tokenizer
|
| 92 |
+
log_freq: 25
|
| 93 |
+
visualize_freq: 5000
|
| 94 |
+
visualize_img_num: 8
|
| 95 |
+
ckpt_freq: 25000
|
| 96 |
+
eval_freq: 25000
|
| 97 |
+
save_ckpt: true
|
| 98 |
+
ar_ckpt_path: ''
|
| 99 |
+
ae_ckpt_path: ''
|
| 100 |
+
resume_optimizer: false
|
| 101 |
+
cond_emb_dim: 32
|
| 102 |
+
greedy_coding_prob: 0.0
|
| 103 |
+
z_len: 64
|
| 104 |
+
z_dim: 512
|
| 105 |
+
vq_type: VQ
|
| 106 |
+
codebook_size: 1024
|
| 107 |
+
norm_layer: RMSNorm
|
| 108 |
+
ffn_type: geglu
|
| 109 |
+
context_type: cross_attn
|
| 110 |
+
hidden_dim: 512
|
| 111 |
+
Encoder:
|
| 112 |
+
input_dim: 48
|
| 113 |
+
output_dim: 512
|
| 114 |
+
cond_dim: 32
|
| 115 |
+
cond_input_dim: 11
|
| 116 |
+
max_seq_len: 64
|
| 117 |
+
ctx_max_seq_len: 64
|
| 118 |
+
dim: 512
|
| 119 |
+
layer_num: 10
|
| 120 |
+
mlp_ratio: 4.0
|
| 121 |
+
heads: 8
|
| 122 |
+
emb_dropout: 0.0
|
| 123 |
+
drop: 0.0
|
| 124 |
+
l2_norm: false
|
| 125 |
+
context_type: cross_attn
|
| 126 |
+
rope: false
|
| 127 |
+
abs_pos: true
|
| 128 |
+
causal: false
|
| 129 |
+
norm_layer: RMSNorm
|
| 130 |
+
ffn_type: geglu
|
| 131 |
+
Quantizer:
|
| 132 |
+
codebook_size: 1024
|
| 133 |
+
z_dim: 12
|
| 134 |
+
dim: 512
|
| 135 |
+
length: 64
|
| 136 |
+
cond_dim: 32
|
| 137 |
+
cond_affine_norm: false
|
| 138 |
+
vq_beta: 0.25
|
| 139 |
+
use_norm: true
|
| 140 |
+
norm_layer: l2
|
| 141 |
+
ffn_type: geglu
|
| 142 |
+
temperature: 1.0
|
| 143 |
+
Decoder:
|
| 144 |
+
input_dim: 48
|
| 145 |
+
ctx_input_dim: 512
|
| 146 |
+
output_dim: 48
|
| 147 |
+
cond_dim: 32
|
| 148 |
+
cond_input_dim: 11
|
| 149 |
+
max_seq_len: 64
|
| 150 |
+
ctx_max_seq_len: 64
|
| 151 |
+
dim: 512
|
| 152 |
+
layer_num: 10
|
| 153 |
+
heads: 8
|
| 154 |
+
emb_dropout: 0.0
|
| 155 |
+
drop: 0.0
|
| 156 |
+
l2_norm: false
|
| 157 |
+
context_type: cross_attn
|
| 158 |
+
rope: false
|
| 159 |
+
abs_pos: true
|
| 160 |
+
causal: false
|
| 161 |
+
norm_layer: RMSNorm
|
| 162 |
+
ffn_type: geglu
|
| 163 |
+
mlp_ratio: 4.0
|
| 164 |
+
zero_out: true
|
| 165 |
+
query_type: learnable
|
| 166 |
+
ARModel:
|
| 167 |
+
input_dim: 512
|
| 168 |
+
output_dim: 1024
|
| 169 |
+
max_seq_len: 64
|
| 170 |
+
cond_dim: 32
|
| 171 |
+
cond_input_dim: 11
|
| 172 |
+
dim: 512
|
| 173 |
+
layer_num: 6
|
| 174 |
+
heads: 8
|
| 175 |
+
emb_dropout: 0.0
|
| 176 |
+
drop: 0.0
|
| 177 |
+
l2_norm: false
|
| 178 |
+
context_type: none
|
| 179 |
+
rope: false
|
| 180 |
+
abs_pos: true
|
| 181 |
+
causal: true
|
| 182 |
+
out_act: false
|
| 183 |
+
norm_layer: RMSNorm
|
| 184 |
+
ffn_type: geglu
|
| 185 |
+
mlp_ratio: 4
|
| 186 |
+
zero_out: false
|
| 187 |
+
temperature: 1.0
|
| 188 |
+
GANLoss:
|
| 189 |
+
disc_loss: vanilla
|
| 190 |
+
disc_dim: 64
|
| 191 |
+
disc_type: patchgan
|
| 192 |
+
image_size: 32
|
| 193 |
+
disc_num_layers: 3
|
| 194 |
+
disc_in_channels: 3
|
| 195 |
+
gen_adv_loss: vanilla
|
| 196 |
+
lecam_loss_weight: 0.001
|
| 197 |
+
norm_type: bn
|
| 198 |
+
aug_prob: 1.0
|
configs/cifar10/flow_matching_ar.yaml
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
wandb_project: wAR
|
| 2 |
+
wandb_name: flow_matching_ar
|
| 3 |
+
data_dir: ./data/cifar10
|
| 4 |
+
xflip: true
|
| 5 |
+
crop_type: center
|
| 6 |
+
image_size: 32
|
| 7 |
+
num_channels: 3
|
| 8 |
+
num_classes: 11
|
| 9 |
+
patch_size: 4
|
| 10 |
+
use_label: false
|
| 11 |
+
patch_dim: 48
|
| 12 |
+
x_len: 64
|
| 13 |
+
diffusion_decoder: false
|
| 14 |
+
train_ae: false
|
| 15 |
+
train_ar: true
|
| 16 |
+
phases: 200000:DO_PRIOR_AR:1
|
| 17 |
+
batch_size: 512
|
| 18 |
+
eval_batch_size: 512
|
| 19 |
+
lr_enc: 0.00015
|
| 20 |
+
lr_dec: 0.00015
|
| 21 |
+
lr_ar: 0.00015
|
| 22 |
+
lr_gan_loss: 0.00015
|
| 23 |
+
weight_decay_enc: 0.0
|
| 24 |
+
weight_decay_dec: 0.0
|
| 25 |
+
weight_decay_ar: 0.0001
|
| 26 |
+
weight_decay_gan: 0.0001
|
| 27 |
+
lr_enc_min: 3.0e-05
|
| 28 |
+
lr_dec_min: 3.0e-05
|
| 29 |
+
lr_ar_min: 3.0e-05
|
| 30 |
+
lr_gan_loss_min: 3.0e-05
|
| 31 |
+
use_tf32: false
|
| 32 |
+
lr_scheduler: none
|
| 33 |
+
drop: 0.0
|
| 34 |
+
ar_drop: 0.1
|
| 35 |
+
grad_clip: 0.0
|
| 36 |
+
seed: 42
|
| 37 |
+
beta1: 0.5
|
| 38 |
+
beta2: 0.95
|
| 39 |
+
ar_beta1: 0.9
|
| 40 |
+
ar_beta2: 0.99
|
| 41 |
+
label_drop_prob: 0.1
|
| 42 |
+
precision: bf16-mixed
|
| 43 |
+
replace_cur_with_ema: false
|
| 44 |
+
num_workers: 4
|
| 45 |
+
devices: 8
|
| 46 |
+
reverse_t: true
|
| 47 |
+
use_noise_query: true
|
| 48 |
+
use_tail_dropout: false
|
| 49 |
+
l2_v_target: true
|
| 50 |
+
tail_dropout_t2k: 1.0
|
| 51 |
+
tied_timestep: false
|
| 52 |
+
time_stages: 200,400,600,800,1000
|
| 53 |
+
k_per_stage: 192,184,72,48,16
|
| 54 |
+
load_ar_model: false
|
| 55 |
+
load_ar_model_ema: false
|
| 56 |
+
prior_G_loss: false
|
| 57 |
+
use_l1_loss: false
|
| 58 |
+
use_l2_loss: false
|
| 59 |
+
use_lpips_loss: false
|
| 60 |
+
use_gan_loss: false
|
| 61 |
+
use_prior_loss: false
|
| 62 |
+
teacher_forcing_ae: false
|
| 63 |
+
disc_adaptive_weight: false
|
| 64 |
+
lpips_weight: 0.1
|
| 65 |
+
gan_G_weight: 0.1
|
| 66 |
+
prior_enc_weight: 1.0
|
| 67 |
+
l1_weight: 0.1
|
| 68 |
+
l2_weight: 1.0
|
| 69 |
+
gan_start: 5000
|
| 70 |
+
prior_start: 0
|
| 71 |
+
tail_dropout_start: 0
|
| 72 |
+
tail_dropout_p: 0.0
|
| 73 |
+
torch_compile: true
|
| 74 |
+
compile_ae: true
|
| 75 |
+
compile_ar: true
|
| 76 |
+
compile_gan: false
|
| 77 |
+
ar_ema_halflife: 2000
|
| 78 |
+
ae_ema_halflife: 0
|
| 79 |
+
ema_sampling: true
|
| 80 |
+
ema_reconstruction: false
|
| 81 |
+
cache_kv: true
|
| 82 |
+
topK: 0.0
|
| 83 |
+
topP: 0.0
|
| 84 |
+
cfg: 0.0
|
| 85 |
+
cfg_schedule: cosine
|
| 86 |
+
cfg_power: 2.75
|
| 87 |
+
temperature: 1.0
|
| 88 |
+
eval_data_dir: ./data/cifar10
|
| 89 |
+
eval_crop_type: center
|
| 90 |
+
eval_fid_ref_path: ./refs/cifar10-32x32_local.npz
|
| 91 |
+
save_dir: ./outputs/flow_matching_ar
|
| 92 |
+
log_freq: 25
|
| 93 |
+
visualize_freq: 5000
|
| 94 |
+
visualize_img_num: 8
|
| 95 |
+
ckpt_freq: 25000
|
| 96 |
+
eval_freq: 25000
|
| 97 |
+
save_ckpt: true
|
| 98 |
+
ar_ckpt_path: ''
|
| 99 |
+
ae_ckpt_path: ./outputs/flow_matching_tokenizer/000/ckpts/last.ckpt
|
| 100 |
+
resume_optimizer: false
|
| 101 |
+
cond_emb_dim: 32
|
| 102 |
+
greedy_coding_prob: 0.0
|
| 103 |
+
z_len: 64
|
| 104 |
+
z_dim: 512
|
| 105 |
+
vq_type: VQ
|
| 106 |
+
codebook_size: 1024
|
| 107 |
+
norm_layer: RMSNorm
|
| 108 |
+
ffn_type: geglu
|
| 109 |
+
context_type: cross_attn
|
| 110 |
+
hidden_dim: 512
|
| 111 |
+
Encoder:
|
| 112 |
+
input_dim: 48
|
| 113 |
+
output_dim: 512
|
| 114 |
+
cond_dim: 32
|
| 115 |
+
cond_input_dim: 11
|
| 116 |
+
max_seq_len: 64
|
| 117 |
+
ctx_max_seq_len: 64
|
| 118 |
+
dim: 512
|
| 119 |
+
layer_num: 10
|
| 120 |
+
mlp_ratio: 4.0
|
| 121 |
+
heads: 8
|
| 122 |
+
emb_dropout: 0.0
|
| 123 |
+
drop: 0.0
|
| 124 |
+
l2_norm: false
|
| 125 |
+
context_type: cross_attn
|
| 126 |
+
rope: false
|
| 127 |
+
abs_pos: true
|
| 128 |
+
causal: false
|
| 129 |
+
norm_layer: RMSNorm
|
| 130 |
+
ffn_type: geglu
|
| 131 |
+
Quantizer:
|
| 132 |
+
codebook_size: 1024
|
| 133 |
+
z_dim: 12
|
| 134 |
+
dim: 512
|
| 135 |
+
length: 64
|
| 136 |
+
cond_dim: 32
|
| 137 |
+
cond_affine_norm: false
|
| 138 |
+
vq_beta: 0.25
|
| 139 |
+
use_norm: true
|
| 140 |
+
norm_layer: l2
|
| 141 |
+
ffn_type: geglu
|
| 142 |
+
temperature: 1.0
|
| 143 |
+
Decoder:
|
| 144 |
+
input_dim: 48
|
| 145 |
+
ctx_input_dim: 512
|
| 146 |
+
output_dim: 48
|
| 147 |
+
cond_dim: 32
|
| 148 |
+
cond_input_dim: 11
|
| 149 |
+
max_seq_len: 64
|
| 150 |
+
ctx_max_seq_len: 64
|
| 151 |
+
dim: 512
|
| 152 |
+
layer_num: 10
|
| 153 |
+
heads: 8
|
| 154 |
+
emb_dropout: 0.0
|
| 155 |
+
drop: 0.0
|
| 156 |
+
l2_norm: false
|
| 157 |
+
context_type: cross_attn
|
| 158 |
+
rope: false
|
| 159 |
+
abs_pos: true
|
| 160 |
+
causal: false
|
| 161 |
+
norm_layer: RMSNorm
|
| 162 |
+
ffn_type: geglu
|
| 163 |
+
mlp_ratio: 4.0
|
| 164 |
+
zero_out: true
|
| 165 |
+
query_type: noise
|
| 166 |
+
ARModel:
|
| 167 |
+
input_dim: 512
|
| 168 |
+
output_dim: 1024
|
| 169 |
+
max_seq_len: 64
|
| 170 |
+
cond_dim: 32
|
| 171 |
+
cond_input_dim: 11
|
| 172 |
+
dim: 512
|
| 173 |
+
layer_num: 13
|
| 174 |
+
heads: 8
|
| 175 |
+
emb_dropout: 0.0
|
| 176 |
+
drop: 0.1
|
| 177 |
+
l2_norm: false
|
| 178 |
+
context_type: none
|
| 179 |
+
rope: false
|
| 180 |
+
abs_pos: true
|
| 181 |
+
causal: true
|
| 182 |
+
out_act: false
|
| 183 |
+
norm_layer: RMSNorm
|
| 184 |
+
ffn_type: geglu
|
| 185 |
+
mlp_ratio: 4.0
|
| 186 |
+
zero_out: false
|
| 187 |
+
temperature: 1.0
|
| 188 |
+
GANLoss:
|
| 189 |
+
disc_loss: vanilla
|
| 190 |
+
disc_dim: 64
|
| 191 |
+
disc_type: patchgan
|
| 192 |
+
image_size: 32
|
| 193 |
+
disc_num_layers: 3
|
| 194 |
+
disc_in_channels: 3
|
| 195 |
+
gen_adv_loss: vanilla
|
| 196 |
+
lecam_loss_weight: 0.001
|
| 197 |
+
norm_type: bn
|
| 198 |
+
aug_prob: 1.0
|
configs/cifar10/flow_matching_tail_dropout_ar.yaml
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
wandb_project: wAR
|
| 2 |
+
wandb_name: flow_matching_tail_dropout_ar
|
| 3 |
+
data_dir: ./data/cifar10
|
| 4 |
+
xflip: true
|
| 5 |
+
crop_type: center
|
| 6 |
+
image_size: 32
|
| 7 |
+
num_channels: 3
|
| 8 |
+
num_classes: 11
|
| 9 |
+
patch_size: 4
|
| 10 |
+
use_label: false
|
| 11 |
+
patch_dim: 48
|
| 12 |
+
x_len: 64
|
| 13 |
+
diffusion_decoder: false
|
| 14 |
+
train_ae: false
|
| 15 |
+
train_ar: true
|
| 16 |
+
phases: 200000:DO_PRIOR_AR:1
|
| 17 |
+
batch_size: 512
|
| 18 |
+
eval_batch_size: 512
|
| 19 |
+
lr_enc: 0.00015
|
| 20 |
+
lr_dec: 0.00015
|
| 21 |
+
lr_ar: 0.00015
|
| 22 |
+
lr_gan_loss: 0.00015
|
| 23 |
+
weight_decay_enc: 0.0
|
| 24 |
+
weight_decay_dec: 0.0
|
| 25 |
+
weight_decay_ar: 0.0001
|
| 26 |
+
weight_decay_gan: 0.0001
|
| 27 |
+
lr_enc_min: 3.0e-05
|
| 28 |
+
lr_dec_min: 3.0e-05
|
| 29 |
+
lr_ar_min: 3.0e-05
|
| 30 |
+
lr_gan_loss_min: 3.0e-05
|
| 31 |
+
use_tf32: false
|
| 32 |
+
lr_scheduler: none
|
| 33 |
+
drop: 0.0
|
| 34 |
+
ar_drop: 0.1
|
| 35 |
+
grad_clip: 0.0
|
| 36 |
+
seed: 42
|
| 37 |
+
beta1: 0.5
|
| 38 |
+
beta2: 0.95
|
| 39 |
+
ar_beta1: 0.9
|
| 40 |
+
ar_beta2: 0.99
|
| 41 |
+
label_drop_prob: 0.1
|
| 42 |
+
precision: bf16-mixed
|
| 43 |
+
replace_cur_with_ema: false
|
| 44 |
+
num_workers: 4
|
| 45 |
+
devices: 8
|
| 46 |
+
reverse_t: true
|
| 47 |
+
use_noise_query: true
|
| 48 |
+
use_tail_dropout: true
|
| 49 |
+
l2_v_target: true
|
| 50 |
+
tail_dropout_t2k: 1.0
|
| 51 |
+
tied_timestep: false
|
| 52 |
+
time_stages: 200,400,600,800,1000
|
| 53 |
+
k_per_stage: 192,184,72,48,16
|
| 54 |
+
load_ar_model: false
|
| 55 |
+
load_ar_model_ema: false
|
| 56 |
+
prior_G_loss: false
|
| 57 |
+
use_l1_loss: false
|
| 58 |
+
use_l2_loss: false
|
| 59 |
+
use_lpips_loss: false
|
| 60 |
+
use_gan_loss: false
|
| 61 |
+
use_prior_loss: false
|
| 62 |
+
teacher_forcing_ae: false
|
| 63 |
+
disc_adaptive_weight: false
|
| 64 |
+
lpips_weight: 0.1
|
| 65 |
+
gan_G_weight: 0.1
|
| 66 |
+
prior_enc_weight: 1.0
|
| 67 |
+
l1_weight: 0.1
|
| 68 |
+
l2_weight: 1.0
|
| 69 |
+
gan_start: 5000
|
| 70 |
+
prior_start: 0
|
| 71 |
+
tail_dropout_start: 0
|
| 72 |
+
tail_dropout_p: 0.5
|
| 73 |
+
torch_compile: true
|
| 74 |
+
compile_ae: true
|
| 75 |
+
compile_ar: true
|
| 76 |
+
compile_gan: false
|
| 77 |
+
ar_ema_halflife: 2000
|
| 78 |
+
ae_ema_halflife: 0
|
| 79 |
+
ema_sampling: true
|
| 80 |
+
ema_reconstruction: false
|
| 81 |
+
cache_kv: true
|
| 82 |
+
topK: 0.0
|
| 83 |
+
topP: 0.0
|
| 84 |
+
cfg: 0.0
|
| 85 |
+
cfg_schedule: cosine
|
| 86 |
+
cfg_power: 2.75
|
| 87 |
+
temperature: 1.0
|
| 88 |
+
eval_data_dir: ./data/cifar10
|
| 89 |
+
eval_crop_type: center
|
| 90 |
+
eval_fid_ref_path: ./refs/cifar10-32x32_local.npz
|
| 91 |
+
save_dir: ./outputs/flow_matching_tail_dropout_ar
|
| 92 |
+
log_freq: 25
|
| 93 |
+
visualize_freq: 5000
|
| 94 |
+
visualize_img_num: 8
|
| 95 |
+
ckpt_freq: 25000
|
| 96 |
+
eval_freq: 25000
|
| 97 |
+
save_ckpt: true
|
| 98 |
+
ar_ckpt_path: ''
|
| 99 |
+
ae_ckpt_path: ./outputs/flow_matching_tail_dropout_tokenizer/000/ckpts/last.ckpt
|
| 100 |
+
resume_optimizer: false
|
| 101 |
+
cond_emb_dim: 32
|
| 102 |
+
greedy_coding_prob: 0.0
|
| 103 |
+
z_len: 64
|
| 104 |
+
z_dim: 512
|
| 105 |
+
vq_type: VQ
|
| 106 |
+
codebook_size: 1024
|
| 107 |
+
norm_layer: RMSNorm
|
| 108 |
+
ffn_type: geglu
|
| 109 |
+
context_type: cross_attn
|
| 110 |
+
hidden_dim: 512
|
| 111 |
+
Encoder:
|
| 112 |
+
input_dim: 48
|
| 113 |
+
output_dim: 512
|
| 114 |
+
cond_dim: 32
|
| 115 |
+
cond_input_dim: 11
|
| 116 |
+
max_seq_len: 64
|
| 117 |
+
ctx_max_seq_len: 64
|
| 118 |
+
dim: 512
|
| 119 |
+
layer_num: 10
|
| 120 |
+
mlp_ratio: 4.0
|
| 121 |
+
heads: 8
|
| 122 |
+
emb_dropout: 0.0
|
| 123 |
+
drop: 0.0
|
| 124 |
+
l2_norm: false
|
| 125 |
+
context_type: cross_attn
|
| 126 |
+
rope: false
|
| 127 |
+
abs_pos: true
|
| 128 |
+
causal: false
|
| 129 |
+
norm_layer: RMSNorm
|
| 130 |
+
ffn_type: geglu
|
| 131 |
+
Quantizer:
|
| 132 |
+
codebook_size: 1024
|
| 133 |
+
z_dim: 12
|
| 134 |
+
dim: 512
|
| 135 |
+
length: 64
|
| 136 |
+
cond_dim: 32
|
| 137 |
+
cond_affine_norm: false
|
| 138 |
+
vq_beta: 0.25
|
| 139 |
+
use_norm: true
|
| 140 |
+
norm_layer: l2
|
| 141 |
+
ffn_type: geglu
|
| 142 |
+
temperature: 1.0
|
| 143 |
+
Decoder:
|
| 144 |
+
input_dim: 48
|
| 145 |
+
ctx_input_dim: 512
|
| 146 |
+
output_dim: 48
|
| 147 |
+
cond_dim: 32
|
| 148 |
+
cond_input_dim: 11
|
| 149 |
+
max_seq_len: 64
|
| 150 |
+
ctx_max_seq_len: 64
|
| 151 |
+
dim: 512
|
| 152 |
+
layer_num: 10
|
| 153 |
+
heads: 8
|
| 154 |
+
emb_dropout: 0.0
|
| 155 |
+
drop: 0.0
|
| 156 |
+
l2_norm: false
|
| 157 |
+
context_type: cross_attn
|
| 158 |
+
rope: false
|
| 159 |
+
abs_pos: true
|
| 160 |
+
causal: false
|
| 161 |
+
norm_layer: RMSNorm
|
| 162 |
+
ffn_type: geglu
|
| 163 |
+
mlp_ratio: 4.0
|
| 164 |
+
zero_out: true
|
| 165 |
+
query_type: noise
|
| 166 |
+
ARModel:
|
| 167 |
+
input_dim: 512
|
| 168 |
+
output_dim: 1024
|
| 169 |
+
max_seq_len: 64
|
| 170 |
+
cond_dim: 32
|
| 171 |
+
cond_input_dim: 11
|
| 172 |
+
dim: 512
|
| 173 |
+
layer_num: 13
|
| 174 |
+
heads: 8
|
| 175 |
+
emb_dropout: 0.0
|
| 176 |
+
drop: 0.1
|
| 177 |
+
l2_norm: false
|
| 178 |
+
context_type: none
|
| 179 |
+
rope: false
|
| 180 |
+
abs_pos: true
|
| 181 |
+
causal: true
|
| 182 |
+
out_act: false
|
| 183 |
+
norm_layer: RMSNorm
|
| 184 |
+
ffn_type: geglu
|
| 185 |
+
mlp_ratio: 4.0
|
| 186 |
+
zero_out: false
|
| 187 |
+
temperature: 1.0
|
| 188 |
+
GANLoss:
|
| 189 |
+
disc_loss: vanilla
|
| 190 |
+
disc_dim: 64
|
| 191 |
+
disc_type: patchgan
|
| 192 |
+
image_size: 32
|
| 193 |
+
disc_num_layers: 3
|
| 194 |
+
disc_in_channels: 3
|
| 195 |
+
gen_adv_loss: vanilla
|
| 196 |
+
lecam_loss_weight: 0.001
|
| 197 |
+
norm_type: bn
|
| 198 |
+
aug_prob: 1.0
|
configs/cifar10/flow_matching_tail_dropout_tokenizer.yaml
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
wandb_project: wAR
|
| 2 |
+
wandb_name: flow_matching_tail_dropout_tokenizer
|
| 3 |
+
data_dir: ./data/cifar10
|
| 4 |
+
xflip: true
|
| 5 |
+
crop_type: center
|
| 6 |
+
image_size: 32
|
| 7 |
+
num_channels: 3
|
| 8 |
+
num_classes: 11
|
| 9 |
+
patch_size: 4
|
| 10 |
+
use_label: false
|
| 11 |
+
patch_dim: 48
|
| 12 |
+
x_len: 64
|
| 13 |
+
diffusion_decoder: true
|
| 14 |
+
train_ae: true
|
| 15 |
+
train_ar: false
|
| 16 |
+
phases: 400000:DO_L2-DO_LPIPS:1
|
| 17 |
+
batch_size: 512
|
| 18 |
+
eval_batch_size: 512
|
| 19 |
+
lr_enc: 0.00015
|
| 20 |
+
lr_dec: 0.00015
|
| 21 |
+
lr_ar: 0.00015
|
| 22 |
+
lr_gan_loss: 0.00015
|
| 23 |
+
weight_decay_enc: 0.0
|
| 24 |
+
weight_decay_dec: 0.0
|
| 25 |
+
weight_decay_ar: 0.0
|
| 26 |
+
weight_decay_gan: 0.0001
|
| 27 |
+
lr_enc_min: 3.0e-05
|
| 28 |
+
lr_dec_min: 3.0e-05
|
| 29 |
+
lr_ar_min: 3.0e-05
|
| 30 |
+
lr_gan_loss_min: 3.0e-05
|
| 31 |
+
use_tf32: false
|
| 32 |
+
lr_scheduler: none
|
| 33 |
+
drop: 0.0
|
| 34 |
+
ar_drop: 0.0
|
| 35 |
+
grad_clip: 0.0
|
| 36 |
+
seed: 42
|
| 37 |
+
beta1: 0.5
|
| 38 |
+
beta2: 0.95
|
| 39 |
+
ar_beta1: 0.5
|
| 40 |
+
ar_beta2: 0.95
|
| 41 |
+
label_drop_prob: 0.1
|
| 42 |
+
precision: bf16-mixed
|
| 43 |
+
replace_cur_with_ema: false
|
| 44 |
+
num_workers: 4
|
| 45 |
+
devices: 8
|
| 46 |
+
reverse_t: false
|
| 47 |
+
use_noise_query: true
|
| 48 |
+
use_tail_dropout: true
|
| 49 |
+
l2_v_target: true
|
| 50 |
+
tail_dropout_t2k: 1.0
|
| 51 |
+
tied_timestep: false
|
| 52 |
+
time_stages: 200,400,600,800,1000
|
| 53 |
+
k_per_stage: 192,184,72,48,16
|
| 54 |
+
load_ar_model: false
|
| 55 |
+
load_ar_model_ema: false
|
| 56 |
+
prior_G_loss: false
|
| 57 |
+
use_l1_loss: false
|
| 58 |
+
use_l2_loss: true
|
| 59 |
+
use_lpips_loss: true
|
| 60 |
+
use_gan_loss: false
|
| 61 |
+
use_prior_loss: false
|
| 62 |
+
teacher_forcing_ae: false
|
| 63 |
+
disc_adaptive_weight: false
|
| 64 |
+
lpips_weight: 0.1
|
| 65 |
+
gan_G_weight: 0.1
|
| 66 |
+
prior_enc_weight: 1.0
|
| 67 |
+
l1_weight: 0.1
|
| 68 |
+
l2_weight: 1.0
|
| 69 |
+
gan_start: 5000
|
| 70 |
+
prior_start: 0
|
| 71 |
+
tail_dropout_start: 0
|
| 72 |
+
tail_dropout_p: 0.5
|
| 73 |
+
torch_compile: true
|
| 74 |
+
compile_ae: true
|
| 75 |
+
compile_ar: true
|
| 76 |
+
compile_gan: false
|
| 77 |
+
ar_ema_halflife: 2500
|
| 78 |
+
ae_ema_halflife: 1000
|
| 79 |
+
ema_sampling: false
|
| 80 |
+
ema_reconstruction: false
|
| 81 |
+
cache_kv: true
|
| 82 |
+
topK: 0.0
|
| 83 |
+
topP: 0.0
|
| 84 |
+
cfg: 0.0
|
| 85 |
+
cfg_schedule: cosine
|
| 86 |
+
cfg_power: 2.75
|
| 87 |
+
temperature: 1.0
|
| 88 |
+
eval_data_dir: ./data/cifar10
|
| 89 |
+
eval_crop_type: center
|
| 90 |
+
eval_fid_ref_path: ./refs/cifar10-32x32_local.npz
|
| 91 |
+
save_dir: ./outputs/flow_matching_tail_dropout_tokenizer
|
| 92 |
+
log_freq: 25
|
| 93 |
+
visualize_freq: 5000
|
| 94 |
+
visualize_img_num: 8
|
| 95 |
+
ckpt_freq: 25000
|
| 96 |
+
eval_freq: 25000
|
| 97 |
+
save_ckpt: true
|
| 98 |
+
ar_ckpt_path: ''
|
| 99 |
+
ae_ckpt_path: ''
|
| 100 |
+
resume_optimizer: false
|
| 101 |
+
cond_emb_dim: 32
|
| 102 |
+
greedy_coding_prob: 0.0
|
| 103 |
+
z_len: 64
|
| 104 |
+
z_dim: 512
|
| 105 |
+
vq_type: VQ
|
| 106 |
+
codebook_size: 1024
|
| 107 |
+
norm_layer: RMSNorm
|
| 108 |
+
ffn_type: geglu
|
| 109 |
+
context_type: cross_attn
|
| 110 |
+
hidden_dim: 512
|
| 111 |
+
Encoder:
|
| 112 |
+
input_dim: 48
|
| 113 |
+
output_dim: 512
|
| 114 |
+
cond_dim: 32
|
| 115 |
+
cond_input_dim: 11
|
| 116 |
+
max_seq_len: 64
|
| 117 |
+
ctx_max_seq_len: 64
|
| 118 |
+
dim: 512
|
| 119 |
+
layer_num: 10
|
| 120 |
+
mlp_ratio: 4.0
|
| 121 |
+
heads: 8
|
| 122 |
+
emb_dropout: 0.0
|
| 123 |
+
drop: 0.0
|
| 124 |
+
l2_norm: false
|
| 125 |
+
context_type: cross_attn
|
| 126 |
+
rope: false
|
| 127 |
+
abs_pos: true
|
| 128 |
+
causal: false
|
| 129 |
+
norm_layer: RMSNorm
|
| 130 |
+
ffn_type: geglu
|
| 131 |
+
Quantizer:
|
| 132 |
+
codebook_size: 1024
|
| 133 |
+
z_dim: 12
|
| 134 |
+
dim: 512
|
| 135 |
+
length: 64
|
| 136 |
+
cond_dim: 32
|
| 137 |
+
cond_affine_norm: false
|
| 138 |
+
vq_beta: 0.25
|
| 139 |
+
use_norm: true
|
| 140 |
+
norm_layer: l2
|
| 141 |
+
ffn_type: geglu
|
| 142 |
+
temperature: 1.0
|
| 143 |
+
Decoder:
|
| 144 |
+
input_dim: 48
|
| 145 |
+
ctx_input_dim: 512
|
| 146 |
+
output_dim: 48
|
| 147 |
+
cond_dim: 32
|
| 148 |
+
cond_input_dim: 11
|
| 149 |
+
max_seq_len: 64
|
| 150 |
+
ctx_max_seq_len: 64
|
| 151 |
+
dim: 512
|
| 152 |
+
layer_num: 10
|
| 153 |
+
heads: 8
|
| 154 |
+
emb_dropout: 0.0
|
| 155 |
+
drop: 0.0
|
| 156 |
+
l2_norm: false
|
| 157 |
+
context_type: cross_attn
|
| 158 |
+
rope: false
|
| 159 |
+
abs_pos: true
|
| 160 |
+
causal: false
|
| 161 |
+
norm_layer: RMSNorm
|
| 162 |
+
ffn_type: geglu
|
| 163 |
+
mlp_ratio: 4.0
|
| 164 |
+
zero_out: true
|
| 165 |
+
query_type: noise
|
| 166 |
+
ARModel:
|
| 167 |
+
input_dim: 512
|
| 168 |
+
output_dim: 1024
|
| 169 |
+
max_seq_len: 64
|
| 170 |
+
cond_dim: 32
|
| 171 |
+
cond_input_dim: 11
|
| 172 |
+
dim: 512
|
| 173 |
+
layer_num: 6
|
| 174 |
+
heads: 8
|
| 175 |
+
emb_dropout: 0.0
|
| 176 |
+
drop: 0.0
|
| 177 |
+
l2_norm: false
|
| 178 |
+
context_type: none
|
| 179 |
+
rope: false
|
| 180 |
+
abs_pos: true
|
| 181 |
+
causal: true
|
| 182 |
+
out_act: false
|
| 183 |
+
norm_layer: RMSNorm
|
| 184 |
+
ffn_type: geglu
|
| 185 |
+
mlp_ratio: 4
|
| 186 |
+
zero_out: false
|
| 187 |
+
temperature: 1.0
|
| 188 |
+
GANLoss:
|
| 189 |
+
disc_loss: vanilla
|
| 190 |
+
disc_dim: 64
|
| 191 |
+
disc_type: patchgan
|
| 192 |
+
image_size: 32
|
| 193 |
+
disc_num_layers: 3
|
| 194 |
+
disc_in_channels: 3
|
| 195 |
+
gen_adv_loss: vanilla
|
| 196 |
+
lecam_loss_weight: 0.001
|
| 197 |
+
norm_type: bn
|
| 198 |
+
aug_prob: 1.0
|
configs/cifar10/flow_matching_tied_tail_dropout_ar.yaml
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
wandb_project: wAR
|
| 2 |
+
wandb_name: flow_matching_tied_tail_dropout_ar
|
| 3 |
+
data_dir: ./data/cifar10
|
| 4 |
+
xflip: true
|
| 5 |
+
crop_type: center
|
| 6 |
+
image_size: 32
|
| 7 |
+
num_channels: 3
|
| 8 |
+
num_classes: 11
|
| 9 |
+
patch_size: 4
|
| 10 |
+
use_label: false
|
| 11 |
+
patch_dim: 48
|
| 12 |
+
x_len: 64
|
| 13 |
+
diffusion_decoder: false
|
| 14 |
+
train_ae: false
|
| 15 |
+
train_ar: true
|
| 16 |
+
phases: 200000:DO_PRIOR_AR:1
|
| 17 |
+
batch_size: 512
|
| 18 |
+
eval_batch_size: 512
|
| 19 |
+
lr_enc: 0.00015
|
| 20 |
+
lr_dec: 0.00015
|
| 21 |
+
lr_ar: 0.00015
|
| 22 |
+
lr_gan_loss: 0.00015
|
| 23 |
+
weight_decay_enc: 0.0
|
| 24 |
+
weight_decay_dec: 0.0
|
| 25 |
+
weight_decay_ar: 0.0001
|
| 26 |
+
weight_decay_gan: 0.0001
|
| 27 |
+
lr_enc_min: 3.0e-05
|
| 28 |
+
lr_dec_min: 3.0e-05
|
| 29 |
+
lr_ar_min: 3.0e-05
|
| 30 |
+
lr_gan_loss_min: 3.0e-05
|
| 31 |
+
use_tf32: false
|
| 32 |
+
lr_scheduler: none
|
| 33 |
+
drop: 0.0
|
| 34 |
+
ar_drop: 0.1
|
| 35 |
+
grad_clip: 0.0
|
| 36 |
+
seed: 42
|
| 37 |
+
beta1: 0.5
|
| 38 |
+
beta2: 0.95
|
| 39 |
+
ar_beta1: 0.9
|
| 40 |
+
ar_beta2: 0.99
|
| 41 |
+
label_drop_prob: 0.1
|
| 42 |
+
precision: bf16-mixed
|
| 43 |
+
replace_cur_with_ema: false
|
| 44 |
+
num_workers: 4
|
| 45 |
+
devices: 8
|
| 46 |
+
reverse_t: true
|
| 47 |
+
use_noise_query: true
|
| 48 |
+
use_tail_dropout: true
|
| 49 |
+
l2_v_target: true
|
| 50 |
+
tail_dropout_t2k: 1.0
|
| 51 |
+
tied_timestep: true
|
| 52 |
+
time_stages: 200,400,600,800,1000
|
| 53 |
+
k_per_stage: 192,184,72,48,16
|
| 54 |
+
load_ar_model: false
|
| 55 |
+
load_ar_model_ema: false
|
| 56 |
+
prior_G_loss: false
|
| 57 |
+
use_l1_loss: false
|
| 58 |
+
use_l2_loss: false
|
| 59 |
+
use_lpips_loss: false
|
| 60 |
+
use_gan_loss: false
|
| 61 |
+
use_prior_loss: false
|
| 62 |
+
teacher_forcing_ae: false
|
| 63 |
+
disc_adaptive_weight: false
|
| 64 |
+
lpips_weight: 0.1
|
| 65 |
+
gan_G_weight: 0.1
|
| 66 |
+
prior_enc_weight: 1.0
|
| 67 |
+
l1_weight: 0.1
|
| 68 |
+
l2_weight: 1.0
|
| 69 |
+
gan_start: 5000
|
| 70 |
+
prior_start: 0
|
| 71 |
+
tail_dropout_start: 0
|
| 72 |
+
tail_dropout_p: 1.0
|
| 73 |
+
torch_compile: true
|
| 74 |
+
compile_ae: true
|
| 75 |
+
compile_ar: true
|
| 76 |
+
compile_gan: false
|
| 77 |
+
ar_ema_halflife: 2000
|
| 78 |
+
ae_ema_halflife: 0
|
| 79 |
+
ema_sampling: true
|
| 80 |
+
ema_reconstruction: false
|
| 81 |
+
cache_kv: true
|
| 82 |
+
topK: 0.0
|
| 83 |
+
topP: 0.0
|
| 84 |
+
cfg: 0.0
|
| 85 |
+
cfg_schedule: cosine
|
| 86 |
+
cfg_power: 2.75
|
| 87 |
+
temperature: 1.0
|
| 88 |
+
eval_data_dir: ./data/cifar10
|
| 89 |
+
eval_crop_type: center
|
| 90 |
+
eval_fid_ref_path: ./refs/cifar10-32x32_local.npz
|
| 91 |
+
save_dir: ./outputs/flow_matching_tied_tail_dropout_ar
|
| 92 |
+
log_freq: 25
|
| 93 |
+
visualize_freq: 5000
|
| 94 |
+
visualize_img_num: 8
|
| 95 |
+
ckpt_freq: 25000
|
| 96 |
+
eval_freq: 25000
|
| 97 |
+
save_ckpt: true
|
| 98 |
+
ar_ckpt_path: ''
|
| 99 |
+
ae_ckpt_path: ./outputs/flow_matching_tied_tail_dropout_tokenizer/000/ckpts/last.ckpt
|
| 100 |
+
resume_optimizer: false
|
| 101 |
+
cond_emb_dim: 32
|
| 102 |
+
greedy_coding_prob: 0.0
|
| 103 |
+
z_len: 64
|
| 104 |
+
z_dim: 512
|
| 105 |
+
vq_type: VQ
|
| 106 |
+
codebook_size: 1024
|
| 107 |
+
norm_layer: RMSNorm
|
| 108 |
+
ffn_type: geglu
|
| 109 |
+
context_type: cross_attn
|
| 110 |
+
hidden_dim: 512
|
| 111 |
+
Encoder:
|
| 112 |
+
input_dim: 48
|
| 113 |
+
output_dim: 512
|
| 114 |
+
cond_dim: 32
|
| 115 |
+
cond_input_dim: 11
|
| 116 |
+
max_seq_len: 64
|
| 117 |
+
ctx_max_seq_len: 64
|
| 118 |
+
dim: 512
|
| 119 |
+
layer_num: 10
|
| 120 |
+
mlp_ratio: 4.0
|
| 121 |
+
heads: 8
|
| 122 |
+
emb_dropout: 0.0
|
| 123 |
+
drop: 0.0
|
| 124 |
+
l2_norm: false
|
| 125 |
+
context_type: cross_attn
|
| 126 |
+
rope: false
|
| 127 |
+
abs_pos: true
|
| 128 |
+
causal: false
|
| 129 |
+
norm_layer: RMSNorm
|
| 130 |
+
ffn_type: geglu
|
| 131 |
+
Quantizer:
|
| 132 |
+
codebook_size: 1024
|
| 133 |
+
z_dim: 12
|
| 134 |
+
dim: 512
|
| 135 |
+
length: 64
|
| 136 |
+
cond_dim: 32
|
| 137 |
+
cond_affine_norm: false
|
| 138 |
+
vq_beta: 0.25
|
| 139 |
+
use_norm: true
|
| 140 |
+
norm_layer: l2
|
| 141 |
+
ffn_type: geglu
|
| 142 |
+
temperature: 1.0
|
| 143 |
+
Decoder:
|
| 144 |
+
input_dim: 48
|
| 145 |
+
ctx_input_dim: 512
|
| 146 |
+
output_dim: 48
|
| 147 |
+
cond_dim: 32
|
| 148 |
+
cond_input_dim: 11
|
| 149 |
+
max_seq_len: 64
|
| 150 |
+
ctx_max_seq_len: 64
|
| 151 |
+
dim: 512
|
| 152 |
+
layer_num: 10
|
| 153 |
+
heads: 8
|
| 154 |
+
emb_dropout: 0.0
|
| 155 |
+
drop: 0.0
|
| 156 |
+
l2_norm: false
|
| 157 |
+
context_type: cross_attn
|
| 158 |
+
rope: false
|
| 159 |
+
abs_pos: true
|
| 160 |
+
causal: false
|
| 161 |
+
norm_layer: RMSNorm
|
| 162 |
+
ffn_type: geglu
|
| 163 |
+
mlp_ratio: 4.0
|
| 164 |
+
zero_out: true
|
| 165 |
+
query_type: noise
|
| 166 |
+
ARModel:
|
| 167 |
+
input_dim: 512
|
| 168 |
+
output_dim: 1024
|
| 169 |
+
max_seq_len: 64
|
| 170 |
+
cond_dim: 32
|
| 171 |
+
cond_input_dim: 11
|
| 172 |
+
dim: 512
|
| 173 |
+
layer_num: 13
|
| 174 |
+
heads: 8
|
| 175 |
+
emb_dropout: 0.0
|
| 176 |
+
drop: 0.1
|
| 177 |
+
l2_norm: false
|
| 178 |
+
context_type: none
|
| 179 |
+
rope: false
|
| 180 |
+
abs_pos: true
|
| 181 |
+
causal: true
|
| 182 |
+
out_act: false
|
| 183 |
+
norm_layer: RMSNorm
|
| 184 |
+
ffn_type: geglu
|
| 185 |
+
mlp_ratio: 4.0
|
| 186 |
+
zero_out: false
|
| 187 |
+
temperature: 1.0
|
| 188 |
+
GANLoss:
|
| 189 |
+
disc_loss: vanilla
|
| 190 |
+
disc_dim: 64
|
| 191 |
+
disc_type: patchgan
|
| 192 |
+
image_size: 32
|
| 193 |
+
disc_num_layers: 3
|
| 194 |
+
disc_in_channels: 3
|
| 195 |
+
gen_adv_loss: vanilla
|
| 196 |
+
lecam_loss_weight: 0.001
|
| 197 |
+
norm_type: bn
|
| 198 |
+
aug_prob: 1.0
|
configs/cifar10/flow_matching_tied_tail_dropout_tokenizer.yaml
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
wandb_project: wAR
|
| 2 |
+
wandb_name: flow_matching_tied_tail_dropout_tokenizer
|
| 3 |
+
data_dir: ./data/cifar10
|
| 4 |
+
xflip: true
|
| 5 |
+
crop_type: center
|
| 6 |
+
image_size: 32
|
| 7 |
+
num_channels: 3
|
| 8 |
+
num_classes: 11
|
| 9 |
+
patch_size: 4
|
| 10 |
+
use_label: false
|
| 11 |
+
patch_dim: 48
|
| 12 |
+
x_len: 64
|
| 13 |
+
diffusion_decoder: true
|
| 14 |
+
train_ae: true
|
| 15 |
+
train_ar: false
|
| 16 |
+
phases: 400000:DO_L2-DO_LPIPS:1
|
| 17 |
+
batch_size: 512
|
| 18 |
+
eval_batch_size: 512
|
| 19 |
+
lr_enc: 0.00015
|
| 20 |
+
lr_dec: 0.00015
|
| 21 |
+
lr_ar: 0.00015
|
| 22 |
+
lr_gan_loss: 0.00015
|
| 23 |
+
weight_decay_enc: 0.0
|
| 24 |
+
weight_decay_dec: 0.0
|
| 25 |
+
weight_decay_ar: 0.0
|
| 26 |
+
weight_decay_gan: 0.0001
|
| 27 |
+
lr_enc_min: 3.0e-05
|
| 28 |
+
lr_dec_min: 3.0e-05
|
| 29 |
+
lr_ar_min: 3.0e-05
|
| 30 |
+
lr_gan_loss_min: 3.0e-05
|
| 31 |
+
use_tf32: false
|
| 32 |
+
lr_scheduler: none
|
| 33 |
+
drop: 0.0
|
| 34 |
+
ar_drop: 0.0
|
| 35 |
+
grad_clip: 0.0
|
| 36 |
+
seed: 42
|
| 37 |
+
beta1: 0.5
|
| 38 |
+
beta2: 0.95
|
| 39 |
+
ar_beta1: 0.5
|
| 40 |
+
ar_beta2: 0.95
|
| 41 |
+
label_drop_prob: 0.1
|
| 42 |
+
precision: bf16-mixed
|
| 43 |
+
replace_cur_with_ema: false
|
| 44 |
+
num_workers: 4
|
| 45 |
+
devices: 8
|
| 46 |
+
reverse_t: false
|
| 47 |
+
use_noise_query: true
|
| 48 |
+
use_tail_dropout: true
|
| 49 |
+
l2_v_target: true
|
| 50 |
+
tail_dropout_t2k: 1.0
|
| 51 |
+
tied_timestep: true
|
| 52 |
+
time_stages: 200,400,600,800,1000
|
| 53 |
+
k_per_stage: 192,184,72,48,16
|
| 54 |
+
load_ar_model: false
|
| 55 |
+
load_ar_model_ema: false
|
| 56 |
+
prior_G_loss: false
|
| 57 |
+
use_l1_loss: false
|
| 58 |
+
use_l2_loss: true
|
| 59 |
+
use_lpips_loss: true
|
| 60 |
+
use_gan_loss: false
|
| 61 |
+
use_prior_loss: false
|
| 62 |
+
teacher_forcing_ae: false
|
| 63 |
+
disc_adaptive_weight: false
|
| 64 |
+
lpips_weight: 0.1
|
| 65 |
+
gan_G_weight: 0.1
|
| 66 |
+
prior_enc_weight: 1.0
|
| 67 |
+
l1_weight: 0.1
|
| 68 |
+
l2_weight: 1.0
|
| 69 |
+
gan_start: 5000
|
| 70 |
+
prior_start: 0
|
| 71 |
+
tail_dropout_start: 0
|
| 72 |
+
tail_dropout_p: 1.0
|
| 73 |
+
torch_compile: true
|
| 74 |
+
compile_ae: true
|
| 75 |
+
compile_ar: true
|
| 76 |
+
compile_gan: false
|
| 77 |
+
ar_ema_halflife: 2500
|
| 78 |
+
ae_ema_halflife: 1000
|
| 79 |
+
ema_sampling: false
|
| 80 |
+
ema_reconstruction: false
|
| 81 |
+
cache_kv: true
|
| 82 |
+
topK: 0.0
|
| 83 |
+
topP: 0.0
|
| 84 |
+
cfg: 0.0
|
| 85 |
+
cfg_schedule: cosine
|
| 86 |
+
cfg_power: 2.75
|
| 87 |
+
temperature: 1.0
|
| 88 |
+
eval_data_dir: ./data/cifar10
|
| 89 |
+
eval_crop_type: center
|
| 90 |
+
eval_fid_ref_path: ./refs/cifar10-32x32_local.npz
|
| 91 |
+
save_dir: ./outputs/flow_matching_tied_tail_dropout_tokenizer
|
| 92 |
+
log_freq: 25
|
| 93 |
+
visualize_freq: 5000
|
| 94 |
+
visualize_img_num: 8
|
| 95 |
+
ckpt_freq: 25000
|
| 96 |
+
eval_freq: 25000
|
| 97 |
+
save_ckpt: true
|
| 98 |
+
ar_ckpt_path: ''
|
| 99 |
+
ae_ckpt_path: ''
|
| 100 |
+
resume_optimizer: false
|
| 101 |
+
cond_emb_dim: 32
|
| 102 |
+
greedy_coding_prob: 0.0
|
| 103 |
+
z_len: 64
|
| 104 |
+
z_dim: 512
|
| 105 |
+
vq_type: VQ
|
| 106 |
+
codebook_size: 1024
|
| 107 |
+
norm_layer: RMSNorm
|
| 108 |
+
ffn_type: geglu
|
| 109 |
+
context_type: cross_attn
|
| 110 |
+
hidden_dim: 512
|
| 111 |
+
Encoder:
|
| 112 |
+
input_dim: 48
|
| 113 |
+
output_dim: 512
|
| 114 |
+
cond_dim: 32
|
| 115 |
+
cond_input_dim: 11
|
| 116 |
+
max_seq_len: 64
|
| 117 |
+
ctx_max_seq_len: 64
|
| 118 |
+
dim: 512
|
| 119 |
+
layer_num: 10
|
| 120 |
+
mlp_ratio: 4.0
|
| 121 |
+
heads: 8
|
| 122 |
+
emb_dropout: 0.0
|
| 123 |
+
drop: 0.0
|
| 124 |
+
l2_norm: false
|
| 125 |
+
context_type: cross_attn
|
| 126 |
+
rope: false
|
| 127 |
+
abs_pos: true
|
| 128 |
+
causal: false
|
| 129 |
+
norm_layer: RMSNorm
|
| 130 |
+
ffn_type: geglu
|
| 131 |
+
Quantizer:
|
| 132 |
+
codebook_size: 1024
|
| 133 |
+
z_dim: 12
|
| 134 |
+
dim: 512
|
| 135 |
+
length: 64
|
| 136 |
+
cond_dim: 32
|
| 137 |
+
cond_affine_norm: false
|
| 138 |
+
vq_beta: 0.25
|
| 139 |
+
use_norm: true
|
| 140 |
+
norm_layer: l2
|
| 141 |
+
ffn_type: geglu
|
| 142 |
+
temperature: 1.0
|
| 143 |
+
Decoder:
|
| 144 |
+
input_dim: 48
|
| 145 |
+
ctx_input_dim: 512
|
| 146 |
+
output_dim: 48
|
| 147 |
+
cond_dim: 32
|
| 148 |
+
cond_input_dim: 11
|
| 149 |
+
max_seq_len: 64
|
| 150 |
+
ctx_max_seq_len: 64
|
| 151 |
+
dim: 512
|
| 152 |
+
layer_num: 10
|
| 153 |
+
heads: 8
|
| 154 |
+
emb_dropout: 0.0
|
| 155 |
+
drop: 0.0
|
| 156 |
+
l2_norm: false
|
| 157 |
+
context_type: cross_attn
|
| 158 |
+
rope: false
|
| 159 |
+
abs_pos: true
|
| 160 |
+
causal: false
|
| 161 |
+
norm_layer: RMSNorm
|
| 162 |
+
ffn_type: geglu
|
| 163 |
+
mlp_ratio: 4.0
|
| 164 |
+
zero_out: true
|
| 165 |
+
query_type: noise
|
| 166 |
+
ARModel:
|
| 167 |
+
input_dim: 512
|
| 168 |
+
output_dim: 1024
|
| 169 |
+
max_seq_len: 64
|
| 170 |
+
cond_dim: 32
|
| 171 |
+
cond_input_dim: 11
|
| 172 |
+
dim: 512
|
| 173 |
+
layer_num: 6
|
| 174 |
+
heads: 8
|
| 175 |
+
emb_dropout: 0.0
|
| 176 |
+
drop: 0.0
|
| 177 |
+
l2_norm: false
|
| 178 |
+
context_type: none
|
| 179 |
+
rope: false
|
| 180 |
+
abs_pos: true
|
| 181 |
+
causal: true
|
| 182 |
+
out_act: false
|
| 183 |
+
norm_layer: RMSNorm
|
| 184 |
+
ffn_type: geglu
|
| 185 |
+
mlp_ratio: 4
|
| 186 |
+
zero_out: false
|
| 187 |
+
temperature: 1.0
|
| 188 |
+
GANLoss:
|
| 189 |
+
disc_loss: vanilla
|
| 190 |
+
disc_dim: 64
|
| 191 |
+
disc_type: patchgan
|
| 192 |
+
image_size: 32
|
| 193 |
+
disc_num_layers: 3
|
| 194 |
+
disc_in_channels: 3
|
| 195 |
+
gen_adv_loss: vanilla
|
| 196 |
+
lecam_loss_weight: 0.001
|
| 197 |
+
norm_type: bn
|
| 198 |
+
aug_prob: 1.0
|
configs/cifar10/flow_matching_tokenizer.yaml
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
wandb_project: wAR
|
| 2 |
+
wandb_name: flow_matching_tokenizer
|
| 3 |
+
data_dir: ./data/cifar10
|
| 4 |
+
xflip: true
|
| 5 |
+
crop_type: center
|
| 6 |
+
image_size: 32
|
| 7 |
+
num_channels: 3
|
| 8 |
+
num_classes: 11
|
| 9 |
+
patch_size: 4
|
| 10 |
+
use_label: false
|
| 11 |
+
patch_dim: 48
|
| 12 |
+
x_len: 64
|
| 13 |
+
diffusion_decoder: true
|
| 14 |
+
train_ae: true
|
| 15 |
+
train_ar: false
|
| 16 |
+
phases: 400000:DO_L2-DO_LPIPS:1
|
| 17 |
+
batch_size: 512
|
| 18 |
+
eval_batch_size: 512
|
| 19 |
+
lr_enc: 0.00015
|
| 20 |
+
lr_dec: 0.00015
|
| 21 |
+
lr_ar: 0.00015
|
| 22 |
+
lr_gan_loss: 0.00015
|
| 23 |
+
weight_decay_enc: 0.0
|
| 24 |
+
weight_decay_dec: 0.0
|
| 25 |
+
weight_decay_ar: 0.0
|
| 26 |
+
weight_decay_gan: 0.0001
|
| 27 |
+
lr_enc_min: 3.0e-05
|
| 28 |
+
lr_dec_min: 3.0e-05
|
| 29 |
+
lr_ar_min: 3.0e-05
|
| 30 |
+
lr_gan_loss_min: 3.0e-05
|
| 31 |
+
use_tf32: false
|
| 32 |
+
lr_scheduler: none
|
| 33 |
+
drop: 0.0
|
| 34 |
+
ar_drop: 0.0
|
| 35 |
+
grad_clip: 0.0
|
| 36 |
+
seed: 42
|
| 37 |
+
beta1: 0.5
|
| 38 |
+
beta2: 0.95
|
| 39 |
+
ar_beta1: 0.5
|
| 40 |
+
ar_beta2: 0.95
|
| 41 |
+
label_drop_prob: 0.1
|
| 42 |
+
precision: bf16-mixed
|
| 43 |
+
replace_cur_with_ema: false
|
| 44 |
+
num_workers: 4
|
| 45 |
+
devices: 8
|
| 46 |
+
reverse_t: false
|
| 47 |
+
use_noise_query: true
|
| 48 |
+
use_tail_dropout: true
|
| 49 |
+
l2_v_target: true
|
| 50 |
+
tail_dropout_t2k: 1.0
|
| 51 |
+
tied_timestep: false
|
| 52 |
+
time_stages: 200,400,600,800,1000
|
| 53 |
+
k_per_stage: 192,184,72,48,16
|
| 54 |
+
load_ar_model: false
|
| 55 |
+
load_ar_model_ema: false
|
| 56 |
+
prior_G_loss: false
|
| 57 |
+
use_l1_loss: false
|
| 58 |
+
use_l2_loss: true
|
| 59 |
+
use_lpips_loss: true
|
| 60 |
+
use_gan_loss: false
|
| 61 |
+
use_prior_loss: false
|
| 62 |
+
teacher_forcing_ae: false
|
| 63 |
+
disc_adaptive_weight: false
|
| 64 |
+
lpips_weight: 0.1
|
| 65 |
+
gan_G_weight: 0.1
|
| 66 |
+
prior_enc_weight: 1.0
|
| 67 |
+
l1_weight: 0.1
|
| 68 |
+
l2_weight: 1.0
|
| 69 |
+
gan_start: 5000
|
| 70 |
+
prior_start: 0
|
| 71 |
+
tail_dropout_start: 0
|
| 72 |
+
tail_dropout_p: 0
|
| 73 |
+
torch_compile: true
|
| 74 |
+
compile_ae: true
|
| 75 |
+
compile_ar: true
|
| 76 |
+
compile_gan: false
|
| 77 |
+
ar_ema_halflife: 2500
|
| 78 |
+
ae_ema_halflife: 1000
|
| 79 |
+
ema_sampling: false
|
| 80 |
+
ema_reconstruction: false
|
| 81 |
+
cache_kv: true
|
| 82 |
+
topK: 0.0
|
| 83 |
+
topP: 0.0
|
| 84 |
+
cfg: 0.0
|
| 85 |
+
cfg_schedule: cosine
|
| 86 |
+
cfg_power: 2.75
|
| 87 |
+
temperature: 1.0
|
| 88 |
+
eval_data_dir: ./data/cifar10
|
| 89 |
+
eval_crop_type: center
|
| 90 |
+
eval_fid_ref_path: ./refs/cifar10-32x32_local.npz
|
| 91 |
+
save_dir: ./outputs/flow_matching_tokenizer
|
| 92 |
+
log_freq: 25
|
| 93 |
+
visualize_freq: 5000
|
| 94 |
+
visualize_img_num: 8
|
| 95 |
+
ckpt_freq: 25000
|
| 96 |
+
eval_freq: 25000
|
| 97 |
+
save_ckpt: true
|
| 98 |
+
ar_ckpt_path: ''
|
| 99 |
+
ae_ckpt_path: ''
|
| 100 |
+
resume_optimizer: false
|
| 101 |
+
cond_emb_dim: 32
|
| 102 |
+
greedy_coding_prob: 0.0
|
| 103 |
+
z_len: 64
|
| 104 |
+
z_dim: 512
|
| 105 |
+
vq_type: VQ
|
| 106 |
+
codebook_size: 1024
|
| 107 |
+
norm_layer: RMSNorm
|
| 108 |
+
ffn_type: geglu
|
| 109 |
+
context_type: cross_attn
|
| 110 |
+
hidden_dim: 512
|
| 111 |
+
Encoder:
|
| 112 |
+
input_dim: 48
|
| 113 |
+
output_dim: 512
|
| 114 |
+
cond_dim: 32
|
| 115 |
+
cond_input_dim: 11
|
| 116 |
+
max_seq_len: 64
|
| 117 |
+
ctx_max_seq_len: 64
|
| 118 |
+
dim: 512
|
| 119 |
+
layer_num: 10
|
| 120 |
+
mlp_ratio: 4.0
|
| 121 |
+
heads: 8
|
| 122 |
+
emb_dropout: 0.0
|
| 123 |
+
drop: 0.0
|
| 124 |
+
l2_norm: false
|
| 125 |
+
context_type: cross_attn
|
| 126 |
+
rope: false
|
| 127 |
+
abs_pos: true
|
| 128 |
+
causal: false
|
| 129 |
+
norm_layer: RMSNorm
|
| 130 |
+
ffn_type: geglu
|
| 131 |
+
Quantizer:
|
| 132 |
+
codebook_size: 1024
|
| 133 |
+
z_dim: 12
|
| 134 |
+
dim: 512
|
| 135 |
+
length: 64
|
| 136 |
+
cond_dim: 32
|
| 137 |
+
cond_affine_norm: false
|
| 138 |
+
vq_beta: 0.25
|
| 139 |
+
use_norm: true
|
| 140 |
+
norm_layer: l2
|
| 141 |
+
ffn_type: geglu
|
| 142 |
+
temperature: 1.0
|
| 143 |
+
Decoder:
|
| 144 |
+
input_dim: 48
|
| 145 |
+
ctx_input_dim: 512
|
| 146 |
+
output_dim: 48
|
| 147 |
+
cond_dim: 32
|
| 148 |
+
cond_input_dim: 11
|
| 149 |
+
max_seq_len: 64
|
| 150 |
+
ctx_max_seq_len: 64
|
| 151 |
+
dim: 512
|
| 152 |
+
layer_num: 10
|
| 153 |
+
heads: 8
|
| 154 |
+
emb_dropout: 0.0
|
| 155 |
+
drop: 0.0
|
| 156 |
+
l2_norm: false
|
| 157 |
+
context_type: cross_attn
|
| 158 |
+
rope: false
|
| 159 |
+
abs_pos: true
|
| 160 |
+
causal: false
|
| 161 |
+
norm_layer: RMSNorm
|
| 162 |
+
ffn_type: geglu
|
| 163 |
+
mlp_ratio: 4.0
|
| 164 |
+
zero_out: true
|
| 165 |
+
query_type: noise
|
| 166 |
+
ARModel:
|
| 167 |
+
input_dim: 512
|
| 168 |
+
output_dim: 1024
|
| 169 |
+
max_seq_len: 64
|
| 170 |
+
cond_dim: 32
|
| 171 |
+
cond_input_dim: 11
|
| 172 |
+
dim: 512
|
| 173 |
+
layer_num: 6
|
| 174 |
+
heads: 8
|
| 175 |
+
emb_dropout: 0.0
|
| 176 |
+
drop: 0.0
|
| 177 |
+
l2_norm: false
|
| 178 |
+
context_type: none
|
| 179 |
+
rope: false
|
| 180 |
+
abs_pos: true
|
| 181 |
+
causal: true
|
| 182 |
+
out_act: false
|
| 183 |
+
norm_layer: RMSNorm
|
| 184 |
+
ffn_type: geglu
|
| 185 |
+
mlp_ratio: 4
|
| 186 |
+
zero_out: false
|
| 187 |
+
temperature: 1.0
|
| 188 |
+
GANLoss:
|
| 189 |
+
disc_loss: vanilla
|
| 190 |
+
disc_dim: 64
|
| 191 |
+
disc_type: patchgan
|
| 192 |
+
image_size: 32
|
| 193 |
+
disc_num_layers: 3
|
| 194 |
+
disc_in_channels: 3
|
| 195 |
+
gen_adv_loss: vanilla
|
| 196 |
+
lecam_loss_weight: 0.001
|
| 197 |
+
norm_type: bn
|
| 198 |
+
aug_prob: 1.0
|
configs/cifar10/tail_dropout_ar.yaml
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
wandb_project: wAR
|
| 2 |
+
wandb_name: tail_dropout_ar
|
| 3 |
+
data_dir: ./data/cifar10
|
| 4 |
+
xflip: true
|
| 5 |
+
crop_type: center
|
| 6 |
+
image_size: 32
|
| 7 |
+
num_channels: 3
|
| 8 |
+
num_classes: 11
|
| 9 |
+
patch_size: 4
|
| 10 |
+
use_label: false
|
| 11 |
+
patch_dim: 48
|
| 12 |
+
x_len: 64
|
| 13 |
+
diffusion_decoder: false
|
| 14 |
+
train_ae: false
|
| 15 |
+
train_ar: true
|
| 16 |
+
phases: 200000:DO_PRIOR_AR:1
|
| 17 |
+
batch_size: 512
|
| 18 |
+
eval_batch_size: 512
|
| 19 |
+
lr_enc: 0.00015
|
| 20 |
+
lr_dec: 0.00015
|
| 21 |
+
lr_ar: 0.00015
|
| 22 |
+
lr_gan_loss: 0.00015
|
| 23 |
+
weight_decay_enc: 0.0
|
| 24 |
+
weight_decay_dec: 0.0
|
| 25 |
+
weight_decay_ar: 0.0001
|
| 26 |
+
weight_decay_gan: 0.0001
|
| 27 |
+
lr_enc_min: 3.0e-05
|
| 28 |
+
lr_dec_min: 3.0e-05
|
| 29 |
+
lr_ar_min: 3.0e-05
|
| 30 |
+
lr_gan_loss_min: 3.0e-05
|
| 31 |
+
use_tf32: false
|
| 32 |
+
lr_scheduler: none
|
| 33 |
+
drop: 0.0
|
| 34 |
+
ar_drop: 0.1
|
| 35 |
+
grad_clip: 0.0
|
| 36 |
+
seed: 42
|
| 37 |
+
beta1: 0.5
|
| 38 |
+
beta2: 0.95
|
| 39 |
+
ar_beta1: 0.9
|
| 40 |
+
ar_beta2: 0.99
|
| 41 |
+
label_drop_prob: 0.1
|
| 42 |
+
precision: bf16-mixed
|
| 43 |
+
replace_cur_with_ema: false
|
| 44 |
+
num_workers: 4
|
| 45 |
+
devices: 8
|
| 46 |
+
reverse_t: true
|
| 47 |
+
use_noise_query: false
|
| 48 |
+
use_tail_dropout: true
|
| 49 |
+
l2_v_target: false
|
| 50 |
+
tail_dropout_t2k: 1.0
|
| 51 |
+
tied_timestep: false
|
| 52 |
+
time_stages: 200,400,600,800,1000
|
| 53 |
+
k_per_stage: 192,184,72,48,16
|
| 54 |
+
load_ar_model: false
|
| 55 |
+
load_ar_model_ema: false
|
| 56 |
+
prior_G_loss: false
|
| 57 |
+
use_l1_loss: false
|
| 58 |
+
use_l2_loss: false
|
| 59 |
+
use_lpips_loss: false
|
| 60 |
+
use_gan_loss: false
|
| 61 |
+
use_prior_loss: false
|
| 62 |
+
teacher_forcing_ae: false
|
| 63 |
+
disc_adaptive_weight: false
|
| 64 |
+
lpips_weight: 0.1
|
| 65 |
+
gan_G_weight: 0.1
|
| 66 |
+
prior_enc_weight: 1.0
|
| 67 |
+
l1_weight: 0.1
|
| 68 |
+
l2_weight: 1.0
|
| 69 |
+
gan_start: 5000
|
| 70 |
+
prior_start: 0
|
| 71 |
+
tail_dropout_start: 0
|
| 72 |
+
tail_dropout_p: 0.5
|
| 73 |
+
torch_compile: true
|
| 74 |
+
compile_ae: true
|
| 75 |
+
compile_ar: true
|
| 76 |
+
compile_gan: false
|
| 77 |
+
ar_ema_halflife: 2000
|
| 78 |
+
ae_ema_halflife: 0
|
| 79 |
+
ema_sampling: true
|
| 80 |
+
ema_reconstruction: false
|
| 81 |
+
cache_kv: true
|
| 82 |
+
topK: 0.0
|
| 83 |
+
topP: 0.0
|
| 84 |
+
cfg: 0.0
|
| 85 |
+
cfg_schedule: cosine
|
| 86 |
+
cfg_power: 2.75
|
| 87 |
+
temperature: 1.0
|
| 88 |
+
eval_data_dir: ./data/cifar10
|
| 89 |
+
eval_crop_type: center
|
| 90 |
+
eval_fid_ref_path: ./refs/cifar10-32x32_local.npz
|
| 91 |
+
save_dir: ./outputs/tail_dropout_ar
|
| 92 |
+
log_freq: 25
|
| 93 |
+
visualize_freq: 5000
|
| 94 |
+
visualize_img_num: 8
|
| 95 |
+
ckpt_freq: 25000
|
| 96 |
+
eval_freq: 25000
|
| 97 |
+
save_ckpt: true
|
| 98 |
+
ar_ckpt_path: ''
|
| 99 |
+
ae_ckpt_path: ./outputs/tail_dropout_tokenizer/000/ckpts/last.ckpt
|
| 100 |
+
resume_optimizer: false
|
| 101 |
+
cond_emb_dim: 32
|
| 102 |
+
greedy_coding_prob: 0.0
|
| 103 |
+
z_len: 64
|
| 104 |
+
z_dim: 512
|
| 105 |
+
vq_type: VQ
|
| 106 |
+
codebook_size: 1024
|
| 107 |
+
norm_layer: RMSNorm
|
| 108 |
+
ffn_type: geglu
|
| 109 |
+
context_type: cross_attn
|
| 110 |
+
hidden_dim: 512
|
| 111 |
+
Encoder:
|
| 112 |
+
input_dim: 48
|
| 113 |
+
output_dim: 512
|
| 114 |
+
cond_dim: 32
|
| 115 |
+
cond_input_dim: 11
|
| 116 |
+
max_seq_len: 64
|
| 117 |
+
ctx_max_seq_len: 64
|
| 118 |
+
dim: 512
|
| 119 |
+
layer_num: 10
|
| 120 |
+
mlp_ratio: 4.0
|
| 121 |
+
heads: 8
|
| 122 |
+
emb_dropout: 0.0
|
| 123 |
+
drop: 0.0
|
| 124 |
+
l2_norm: false
|
| 125 |
+
context_type: cross_attn
|
| 126 |
+
rope: false
|
| 127 |
+
abs_pos: true
|
| 128 |
+
causal: false
|
| 129 |
+
norm_layer: RMSNorm
|
| 130 |
+
ffn_type: geglu
|
| 131 |
+
Quantizer:
|
| 132 |
+
codebook_size: 1024
|
| 133 |
+
z_dim: 12
|
| 134 |
+
dim: 512
|
| 135 |
+
length: 64
|
| 136 |
+
cond_dim: 32
|
| 137 |
+
cond_affine_norm: false
|
| 138 |
+
vq_beta: 0.25
|
| 139 |
+
use_norm: true
|
| 140 |
+
norm_layer: l2
|
| 141 |
+
ffn_type: geglu
|
| 142 |
+
temperature: 1.0
|
| 143 |
+
Decoder:
|
| 144 |
+
input_dim: 48
|
| 145 |
+
ctx_input_dim: 512
|
| 146 |
+
output_dim: 48
|
| 147 |
+
cond_dim: 32
|
| 148 |
+
cond_input_dim: 11
|
| 149 |
+
max_seq_len: 64
|
| 150 |
+
ctx_max_seq_len: 64
|
| 151 |
+
dim: 512
|
| 152 |
+
layer_num: 10
|
| 153 |
+
heads: 8
|
| 154 |
+
emb_dropout: 0.0
|
| 155 |
+
drop: 0.0
|
| 156 |
+
l2_norm: false
|
| 157 |
+
context_type: cross_attn
|
| 158 |
+
rope: false
|
| 159 |
+
abs_pos: true
|
| 160 |
+
causal: false
|
| 161 |
+
norm_layer: RMSNorm
|
| 162 |
+
ffn_type: geglu
|
| 163 |
+
mlp_ratio: 4.0
|
| 164 |
+
zero_out: true
|
| 165 |
+
query_type: learnable
|
| 166 |
+
ARModel:
|
| 167 |
+
input_dim: 512
|
| 168 |
+
output_dim: 1024
|
| 169 |
+
max_seq_len: 64
|
| 170 |
+
cond_dim: 32
|
| 171 |
+
cond_input_dim: 11
|
| 172 |
+
dim: 512
|
| 173 |
+
layer_num: 13
|
| 174 |
+
heads: 8
|
| 175 |
+
emb_dropout: 0.0
|
| 176 |
+
drop: 0.1
|
| 177 |
+
l2_norm: false
|
| 178 |
+
context_type: none
|
| 179 |
+
rope: false
|
| 180 |
+
abs_pos: true
|
| 181 |
+
causal: true
|
| 182 |
+
out_act: false
|
| 183 |
+
norm_layer: RMSNorm
|
| 184 |
+
ffn_type: geglu
|
| 185 |
+
mlp_ratio: 4.0
|
| 186 |
+
zero_out: false
|
| 187 |
+
temperature: 1.0
|
| 188 |
+
GANLoss:
|
| 189 |
+
disc_loss: vanilla
|
| 190 |
+
disc_dim: 64
|
| 191 |
+
disc_type: patchgan
|
| 192 |
+
image_size: 32
|
| 193 |
+
disc_num_layers: 3
|
| 194 |
+
disc_in_channels: 3
|
| 195 |
+
gen_adv_loss: vanilla
|
| 196 |
+
lecam_loss_weight: 0.001
|
| 197 |
+
norm_type: bn
|
| 198 |
+
aug_prob: 1.0
|
configs/cifar10/tail_dropout_tokenizer.yaml
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
wandb_project: wAR
|
| 2 |
+
wandb_name: tail_dropout_tokenizer
|
| 3 |
+
data_dir: ./data/cifar10
|
| 4 |
+
xflip: true
|
| 5 |
+
crop_type: center
|
| 6 |
+
image_size: 32
|
| 7 |
+
num_channels: 3
|
| 8 |
+
num_classes: 11
|
| 9 |
+
patch_size: 4
|
| 10 |
+
use_label: false
|
| 11 |
+
patch_dim: 48
|
| 12 |
+
x_len: 64
|
| 13 |
+
diffusion_decoder: false
|
| 14 |
+
train_ae: true
|
| 15 |
+
train_ar: false
|
| 16 |
+
phases: 400000:DO_L1-DO_L2-DO_LPIPS:1
|
| 17 |
+
batch_size: 512
|
| 18 |
+
eval_batch_size: 512
|
| 19 |
+
lr_enc: 0.00015
|
| 20 |
+
lr_dec: 0.00015
|
| 21 |
+
lr_ar: 0.00015
|
| 22 |
+
lr_gan_loss: 0.00015
|
| 23 |
+
weight_decay_enc: 0.0
|
| 24 |
+
weight_decay_dec: 0.0
|
| 25 |
+
weight_decay_ar: 0.0
|
| 26 |
+
weight_decay_gan: 0.0001
|
| 27 |
+
lr_enc_min: 3.0e-05
|
| 28 |
+
lr_dec_min: 3.0e-05
|
| 29 |
+
lr_ar_min: 3.0e-05
|
| 30 |
+
lr_gan_loss_min: 3.0e-05
|
| 31 |
+
use_tf32: false
|
| 32 |
+
lr_scheduler: none
|
| 33 |
+
drop: 0.0
|
| 34 |
+
ar_drop: 0.0
|
| 35 |
+
grad_clip: 0.0
|
| 36 |
+
seed: 42
|
| 37 |
+
beta1: 0.5
|
| 38 |
+
beta2: 0.95
|
| 39 |
+
ar_beta1: 0.5
|
| 40 |
+
ar_beta2: 0.95
|
| 41 |
+
label_drop_prob: 0.1
|
| 42 |
+
precision: bf16-mixed
|
| 43 |
+
replace_cur_with_ema: false
|
| 44 |
+
num_workers: 4
|
| 45 |
+
devices: 8
|
| 46 |
+
reverse_t: false
|
| 47 |
+
use_noise_query: false
|
| 48 |
+
use_tail_dropout: true
|
| 49 |
+
l2_v_target: false
|
| 50 |
+
tail_dropout_t2k: 1.0
|
| 51 |
+
tied_timestep: false
|
| 52 |
+
time_stages: 200,400,600,800,1000
|
| 53 |
+
k_per_stage: 192,184,72,48,16
|
| 54 |
+
load_ar_model: false
|
| 55 |
+
load_ar_model_ema: false
|
| 56 |
+
prior_G_loss: false
|
| 57 |
+
use_l1_loss: true
|
| 58 |
+
use_l2_loss: true
|
| 59 |
+
use_lpips_loss: true
|
| 60 |
+
use_gan_loss: false
|
| 61 |
+
use_prior_loss: false
|
| 62 |
+
teacher_forcing_ae: false
|
| 63 |
+
disc_adaptive_weight: false
|
| 64 |
+
lpips_weight: 0.1
|
| 65 |
+
gan_G_weight: 0.1
|
| 66 |
+
prior_enc_weight: 1.0
|
| 67 |
+
l1_weight: 0.1
|
| 68 |
+
l2_weight: 1.0
|
| 69 |
+
gan_start: 5000
|
| 70 |
+
prior_start: 0
|
| 71 |
+
tail_dropout_start: 0
|
| 72 |
+
tail_dropout_p: 0.5
|
| 73 |
+
torch_compile: true
|
| 74 |
+
compile_ae: true
|
| 75 |
+
compile_ar: true
|
| 76 |
+
compile_gan: false
|
| 77 |
+
ar_ema_halflife: 2500
|
| 78 |
+
ae_ema_halflife: 1000
|
| 79 |
+
ema_sampling: false
|
| 80 |
+
ema_reconstruction: false
|
| 81 |
+
cache_kv: true
|
| 82 |
+
topK: 0.0
|
| 83 |
+
topP: 0.0
|
| 84 |
+
cfg: 0.0
|
| 85 |
+
cfg_schedule: cosine
|
| 86 |
+
cfg_power: 2.75
|
| 87 |
+
temperature: 1.0
|
| 88 |
+
eval_data_dir: ./data/cifar10
|
| 89 |
+
eval_crop_type: center
|
| 90 |
+
eval_fid_ref_path: ./refs/cifar10-32x32_local.npz
|
| 91 |
+
save_dir: ./outputs/tail_dropout_tokenizer
|
| 92 |
+
log_freq: 25
|
| 93 |
+
visualize_freq: 5000
|
| 94 |
+
visualize_img_num: 8
|
| 95 |
+
ckpt_freq: 25000
|
| 96 |
+
eval_freq: 25000
|
| 97 |
+
save_ckpt: true
|
| 98 |
+
ar_ckpt_path: ''
|
| 99 |
+
ae_ckpt_path: ''
|
| 100 |
+
resume_optimizer: false
|
| 101 |
+
cond_emb_dim: 32
|
| 102 |
+
greedy_coding_prob: 0.0
|
| 103 |
+
z_len: 64
|
| 104 |
+
z_dim: 512
|
| 105 |
+
vq_type: VQ
|
| 106 |
+
codebook_size: 1024
|
| 107 |
+
norm_layer: RMSNorm
|
| 108 |
+
ffn_type: geglu
|
| 109 |
+
context_type: cross_attn
|
| 110 |
+
hidden_dim: 512
|
| 111 |
+
Encoder:
|
| 112 |
+
input_dim: 48
|
| 113 |
+
output_dim: 512
|
| 114 |
+
cond_dim: 32
|
| 115 |
+
cond_input_dim: 11
|
| 116 |
+
max_seq_len: 64
|
| 117 |
+
ctx_max_seq_len: 64
|
| 118 |
+
dim: 512
|
| 119 |
+
layer_num: 10
|
| 120 |
+
mlp_ratio: 4.0
|
| 121 |
+
heads: 8
|
| 122 |
+
emb_dropout: 0.0
|
| 123 |
+
drop: 0.0
|
| 124 |
+
l2_norm: false
|
| 125 |
+
context_type: cross_attn
|
| 126 |
+
rope: false
|
| 127 |
+
abs_pos: true
|
| 128 |
+
causal: false
|
| 129 |
+
norm_layer: RMSNorm
|
| 130 |
+
ffn_type: geglu
|
| 131 |
+
Quantizer:
|
| 132 |
+
codebook_size: 1024
|
| 133 |
+
z_dim: 12
|
| 134 |
+
dim: 512
|
| 135 |
+
length: 64
|
| 136 |
+
cond_dim: 32
|
| 137 |
+
cond_affine_norm: false
|
| 138 |
+
vq_beta: 0.25
|
| 139 |
+
use_norm: true
|
| 140 |
+
norm_layer: l2
|
| 141 |
+
ffn_type: geglu
|
| 142 |
+
temperature: 1.0
|
| 143 |
+
Decoder:
|
| 144 |
+
input_dim: 48
|
| 145 |
+
ctx_input_dim: 512
|
| 146 |
+
output_dim: 48
|
| 147 |
+
cond_dim: 32
|
| 148 |
+
cond_input_dim: 11
|
| 149 |
+
max_seq_len: 64
|
| 150 |
+
ctx_max_seq_len: 64
|
| 151 |
+
dim: 512
|
| 152 |
+
layer_num: 10
|
| 153 |
+
heads: 8
|
| 154 |
+
emb_dropout: 0.0
|
| 155 |
+
drop: 0.0
|
| 156 |
+
l2_norm: false
|
| 157 |
+
context_type: cross_attn
|
| 158 |
+
rope: false
|
| 159 |
+
abs_pos: true
|
| 160 |
+
causal: false
|
| 161 |
+
norm_layer: RMSNorm
|
| 162 |
+
ffn_type: geglu
|
| 163 |
+
mlp_ratio: 4.0
|
| 164 |
+
zero_out: true
|
| 165 |
+
query_type: learnable
|
| 166 |
+
ARModel:
|
| 167 |
+
input_dim: 512
|
| 168 |
+
output_dim: 1024
|
| 169 |
+
max_seq_len: 64
|
| 170 |
+
cond_dim: 32
|
| 171 |
+
cond_input_dim: 11
|
| 172 |
+
dim: 512
|
| 173 |
+
layer_num: 6
|
| 174 |
+
heads: 8
|
| 175 |
+
emb_dropout: 0.0
|
| 176 |
+
drop: 0.0
|
| 177 |
+
l2_norm: false
|
| 178 |
+
context_type: none
|
| 179 |
+
rope: false
|
| 180 |
+
abs_pos: true
|
| 181 |
+
causal: true
|
| 182 |
+
out_act: false
|
| 183 |
+
norm_layer: RMSNorm
|
| 184 |
+
ffn_type: geglu
|
| 185 |
+
mlp_ratio: 4
|
| 186 |
+
zero_out: false
|
| 187 |
+
temperature: 1.0
|
| 188 |
+
GANLoss:
|
| 189 |
+
disc_loss: vanilla
|
| 190 |
+
disc_dim: 64
|
| 191 |
+
disc_type: patchgan
|
| 192 |
+
image_size: 32
|
| 193 |
+
disc_num_layers: 3
|
| 194 |
+
disc_in_channels: 3
|
| 195 |
+
gen_adv_loss: vanilla
|
| 196 |
+
lecam_loss_weight: 0.001
|
| 197 |
+
norm_type: bn
|
| 198 |
+
aug_prob: 1.0
|
configs/cifar10/war_ar.yaml
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
wandb_project: wAR
|
| 2 |
+
wandb_name: war_ar
|
| 3 |
+
data_dir: ./data/cifar10
|
| 4 |
+
xflip: true
|
| 5 |
+
crop_type: center
|
| 6 |
+
image_size: 32
|
| 7 |
+
num_channels: 3
|
| 8 |
+
num_classes: 11
|
| 9 |
+
patch_size: 4
|
| 10 |
+
use_label: false
|
| 11 |
+
patch_dim: 48
|
| 12 |
+
x_len: 64
|
| 13 |
+
diffusion_decoder: false
|
| 14 |
+
train_ae: false
|
| 15 |
+
train_ar: true
|
| 16 |
+
phases: 200000:DO_PRIOR_AR:1
|
| 17 |
+
batch_size: 512
|
| 18 |
+
eval_batch_size: 512
|
| 19 |
+
lr_enc: 0.00015
|
| 20 |
+
lr_dec: 0.00015
|
| 21 |
+
lr_ar: 0.00015
|
| 22 |
+
lr_gan_loss: 0.00015
|
| 23 |
+
weight_decay_enc: 0.0
|
| 24 |
+
weight_decay_dec: 0.0
|
| 25 |
+
weight_decay_ar: 0.0001
|
| 26 |
+
weight_decay_gan: 0.0001
|
| 27 |
+
lr_enc_min: 3.0e-05
|
| 28 |
+
lr_dec_min: 3.0e-05
|
| 29 |
+
lr_ar_min: 3.0e-05
|
| 30 |
+
lr_gan_loss_min: 3.0e-05
|
| 31 |
+
use_tf32: false
|
| 32 |
+
lr_scheduler: none
|
| 33 |
+
drop: 0.0
|
| 34 |
+
ar_drop: 0.1
|
| 35 |
+
grad_clip: 0.0
|
| 36 |
+
seed: 42
|
| 37 |
+
beta1: 0.5
|
| 38 |
+
beta2: 0.95
|
| 39 |
+
ar_beta1: 0.9
|
| 40 |
+
ar_beta2: 0.99
|
| 41 |
+
label_drop_prob: 0.1
|
| 42 |
+
precision: bf16-mixed
|
| 43 |
+
replace_cur_with_ema: false
|
| 44 |
+
num_workers: 4
|
| 45 |
+
devices: 8
|
| 46 |
+
reverse_t: true
|
| 47 |
+
use_noise_query: false
|
| 48 |
+
use_tail_dropout: false
|
| 49 |
+
l2_v_target: false
|
| 50 |
+
tail_dropout_t2k: 1.0
|
| 51 |
+
tied_timestep: false
|
| 52 |
+
time_stages: 200,400,600,800,1000
|
| 53 |
+
k_per_stage: 192,184,72,48,16
|
| 54 |
+
load_ar_model: false
|
| 55 |
+
load_ar_model_ema: false
|
| 56 |
+
prior_G_loss: false
|
| 57 |
+
use_l1_loss: false
|
| 58 |
+
use_l2_loss: false
|
| 59 |
+
use_lpips_loss: false
|
| 60 |
+
use_gan_loss: false
|
| 61 |
+
use_prior_loss: false
|
| 62 |
+
teacher_forcing_ae: false
|
| 63 |
+
disc_adaptive_weight: false
|
| 64 |
+
lpips_weight: 0.1
|
| 65 |
+
gan_G_weight: 0.1
|
| 66 |
+
prior_enc_weight: 1.0
|
| 67 |
+
l1_weight: 0.1
|
| 68 |
+
l2_weight: 1.0
|
| 69 |
+
gan_start: 5000
|
| 70 |
+
prior_start: 0
|
| 71 |
+
tail_dropout_start: 0
|
| 72 |
+
tail_dropout_p: 0.0
|
| 73 |
+
torch_compile: true
|
| 74 |
+
compile_ae: true
|
| 75 |
+
compile_ar: true
|
| 76 |
+
compile_gan: false
|
| 77 |
+
ar_ema_halflife: 2000
|
| 78 |
+
ae_ema_halflife: 0
|
| 79 |
+
ema_sampling: true
|
| 80 |
+
ema_reconstruction: false
|
| 81 |
+
cache_kv: true
|
| 82 |
+
topK: 0.0
|
| 83 |
+
topP: 0.0
|
| 84 |
+
cfg: 0.0
|
| 85 |
+
cfg_schedule: cosine
|
| 86 |
+
cfg_power: 2.75
|
| 87 |
+
temperature: 1.0
|
| 88 |
+
eval_data_dir: ./data/cifar10
|
| 89 |
+
eval_crop_type: center
|
| 90 |
+
eval_fid_ref_path: ./refs/cifar10-32x32_local.npz
|
| 91 |
+
save_dir: ./outputs/war_ar
|
| 92 |
+
log_freq: 25
|
| 93 |
+
visualize_freq: 5000
|
| 94 |
+
visualize_img_num: 8
|
| 95 |
+
ckpt_freq: 25000
|
| 96 |
+
eval_freq: 25000
|
| 97 |
+
save_ckpt: true
|
| 98 |
+
ar_ckpt_path: ''
|
| 99 |
+
ae_ckpt_path: ./outputs/war_tokenizer/000/ckpts/last.ckpt
|
| 100 |
+
resume_optimizer: false
|
| 101 |
+
cond_emb_dim: 32
|
| 102 |
+
greedy_coding_prob: 0.0
|
| 103 |
+
z_len: 64
|
| 104 |
+
z_dim: 512
|
| 105 |
+
vq_type: VQ
|
| 106 |
+
codebook_size: 1024
|
| 107 |
+
norm_layer: RMSNorm
|
| 108 |
+
ffn_type: geglu
|
| 109 |
+
context_type: cross_attn
|
| 110 |
+
hidden_dim: 512
|
| 111 |
+
Encoder:
|
| 112 |
+
input_dim: 48
|
| 113 |
+
output_dim: 512
|
| 114 |
+
cond_dim: 32
|
| 115 |
+
cond_input_dim: 11
|
| 116 |
+
max_seq_len: 64
|
| 117 |
+
ctx_max_seq_len: 64
|
| 118 |
+
dim: 512
|
| 119 |
+
layer_num: 10
|
| 120 |
+
mlp_ratio: 4.0
|
| 121 |
+
heads: 8
|
| 122 |
+
emb_dropout: 0.0
|
| 123 |
+
drop: 0.0
|
| 124 |
+
l2_norm: false
|
| 125 |
+
context_type: cross_attn
|
| 126 |
+
rope: false
|
| 127 |
+
abs_pos: true
|
| 128 |
+
causal: false
|
| 129 |
+
norm_layer: RMSNorm
|
| 130 |
+
ffn_type: geglu
|
| 131 |
+
Quantizer:
|
| 132 |
+
codebook_size: 1024
|
| 133 |
+
z_dim: 12
|
| 134 |
+
dim: 512
|
| 135 |
+
length: 64
|
| 136 |
+
cond_dim: 32
|
| 137 |
+
cond_affine_norm: false
|
| 138 |
+
vq_beta: 0.25
|
| 139 |
+
use_norm: true
|
| 140 |
+
norm_layer: l2
|
| 141 |
+
ffn_type: geglu
|
| 142 |
+
temperature: 0.05
|
| 143 |
+
Decoder:
|
| 144 |
+
input_dim: 48
|
| 145 |
+
ctx_input_dim: 512
|
| 146 |
+
output_dim: 48
|
| 147 |
+
cond_dim: 32
|
| 148 |
+
cond_input_dim: 11
|
| 149 |
+
max_seq_len: 64
|
| 150 |
+
ctx_max_seq_len: 64
|
| 151 |
+
dim: 512
|
| 152 |
+
layer_num: 10
|
| 153 |
+
heads: 8
|
| 154 |
+
emb_dropout: 0.0
|
| 155 |
+
drop: 0.0
|
| 156 |
+
l2_norm: false
|
| 157 |
+
context_type: cross_attn
|
| 158 |
+
rope: false
|
| 159 |
+
abs_pos: true
|
| 160 |
+
causal: false
|
| 161 |
+
norm_layer: RMSNorm
|
| 162 |
+
ffn_type: geglu
|
| 163 |
+
mlp_ratio: 4.0
|
| 164 |
+
zero_out: true
|
| 165 |
+
query_type: learnable
|
| 166 |
+
ARModel:
|
| 167 |
+
input_dim: 512
|
| 168 |
+
output_dim: 1024
|
| 169 |
+
max_seq_len: 64
|
| 170 |
+
cond_dim: 32
|
| 171 |
+
cond_input_dim: 11
|
| 172 |
+
dim: 512
|
| 173 |
+
layer_num: 13
|
| 174 |
+
heads: 8
|
| 175 |
+
emb_dropout: 0.0
|
| 176 |
+
drop: 0.1
|
| 177 |
+
l2_norm: false
|
| 178 |
+
context_type: none
|
| 179 |
+
rope: false
|
| 180 |
+
abs_pos: true
|
| 181 |
+
causal: true
|
| 182 |
+
out_act: false
|
| 183 |
+
norm_layer: RMSNorm
|
| 184 |
+
ffn_type: geglu
|
| 185 |
+
mlp_ratio: 4.0
|
| 186 |
+
zero_out: false
|
| 187 |
+
temperature: 1.0
|
| 188 |
+
GANLoss:
|
| 189 |
+
disc_loss: vanilla
|
| 190 |
+
disc_dim: 64
|
| 191 |
+
disc_type: patchgan
|
| 192 |
+
image_size: 32
|
| 193 |
+
disc_num_layers: 3
|
| 194 |
+
disc_in_channels: 3
|
| 195 |
+
gen_adv_loss: vanilla
|
| 196 |
+
lecam_loss_weight: 0.001
|
| 197 |
+
norm_type: bn
|
| 198 |
+
aug_prob: 1.0
|
| 199 |
+
prior_ar_temp_low: 0.1
|
| 200 |
+
prior_ar_temp_high: 1.0
|
| 201 |
+
prior_ar_temp_schedule: constant
|
configs/cifar10/war_tokenizer.yaml
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
wandb_project: wAR
|
| 2 |
+
wandb_name: war_tokenizer
|
| 3 |
+
data_dir: ./data/cifar10
|
| 4 |
+
xflip: true
|
| 5 |
+
crop_type: center
|
| 6 |
+
image_size: 32
|
| 7 |
+
num_channels: 3
|
| 8 |
+
num_classes: 11
|
| 9 |
+
patch_size: 4
|
| 10 |
+
use_label: false
|
| 11 |
+
patch_dim: 48
|
| 12 |
+
x_len: 64
|
| 13 |
+
diffusion_decoder: false
|
| 14 |
+
train_ae: true
|
| 15 |
+
train_ar: true
|
| 16 |
+
phases: 400000:DO_L1-DO_L2-DO_LPIPS-DO_PRIOR_ENC-DO_PRIOR_AR:1
|
| 17 |
+
batch_size: 512
|
| 18 |
+
eval_batch_size: 512
|
| 19 |
+
lr_enc: 0.00015
|
| 20 |
+
lr_dec: 0.00015
|
| 21 |
+
lr_ar: 0.00015
|
| 22 |
+
lr_gan_loss: 0.00015
|
| 23 |
+
weight_decay_enc: 0.0
|
| 24 |
+
weight_decay_dec: 0.0
|
| 25 |
+
weight_decay_ar: 0.0
|
| 26 |
+
weight_decay_gan: 0.0001
|
| 27 |
+
lr_enc_min: 3.0e-05
|
| 28 |
+
lr_dec_min: 3.0e-05
|
| 29 |
+
lr_ar_min: 3.0e-05
|
| 30 |
+
lr_gan_loss_min: 3.0e-05
|
| 31 |
+
use_tf32: false
|
| 32 |
+
lr_scheduler: none
|
| 33 |
+
drop: 0.0
|
| 34 |
+
ar_drop: 0.0
|
| 35 |
+
grad_clip: 0.0
|
| 36 |
+
seed: 42
|
| 37 |
+
beta1: 0.5
|
| 38 |
+
beta2: 0.95
|
| 39 |
+
ar_beta1: 0.5
|
| 40 |
+
ar_beta2: 0.95
|
| 41 |
+
label_drop_prob: 0.1
|
| 42 |
+
precision: bf16-mixed
|
| 43 |
+
replace_cur_with_ema: false
|
| 44 |
+
num_workers: 4
|
| 45 |
+
devices: 8
|
| 46 |
+
reverse_t: true
|
| 47 |
+
use_noise_query: false
|
| 48 |
+
use_tail_dropout: false
|
| 49 |
+
l2_v_target: false
|
| 50 |
+
tail_dropout_t2k: 1.0
|
| 51 |
+
tied_timestep: false
|
| 52 |
+
time_stages: 200,400,600,800,1000
|
| 53 |
+
k_per_stage: 192,184,72,48,16
|
| 54 |
+
load_ar_model: false
|
| 55 |
+
load_ar_model_ema: false
|
| 56 |
+
prior_G_loss: false
|
| 57 |
+
use_l1_loss: true
|
| 58 |
+
use_l2_loss: true
|
| 59 |
+
use_lpips_loss: true
|
| 60 |
+
use_gan_loss: false
|
| 61 |
+
use_prior_loss: true
|
| 62 |
+
teacher_forcing_ae: false
|
| 63 |
+
disc_adaptive_weight: false
|
| 64 |
+
lpips_weight: 0.1
|
| 65 |
+
gan_G_weight: 0.1
|
| 66 |
+
prior_enc_weight: 1.0
|
| 67 |
+
l1_weight: 0.1
|
| 68 |
+
l2_weight: 1.0
|
| 69 |
+
gan_start: 5000
|
| 70 |
+
prior_start: 0
|
| 71 |
+
tail_dropout_start: 0
|
| 72 |
+
tail_dropout_p: 0.0
|
| 73 |
+
torch_compile: true
|
| 74 |
+
compile_ae: true
|
| 75 |
+
compile_ar: true
|
| 76 |
+
compile_gan: false
|
| 77 |
+
ar_ema_halflife: 0
|
| 78 |
+
ae_ema_halflife: 0
|
| 79 |
+
ema_sampling: false
|
| 80 |
+
ema_reconstruction: false
|
| 81 |
+
cache_kv: true
|
| 82 |
+
topK: 0.0
|
| 83 |
+
topP: 0.0
|
| 84 |
+
cfg: 0.0
|
| 85 |
+
cfg_schedule: cosine
|
| 86 |
+
cfg_power: 2.75
|
| 87 |
+
temperature: 1.0
|
| 88 |
+
eval_data_dir: ./data/cifar10
|
| 89 |
+
eval_crop_type: center
|
| 90 |
+
eval_fid_ref_path: ./refs/cifar10-32x32_local.npz
|
| 91 |
+
save_dir: ./outputs/war_tokenizer
|
| 92 |
+
log_freq: 25
|
| 93 |
+
visualize_freq: 5000
|
| 94 |
+
visualize_img_num: 8
|
| 95 |
+
ckpt_freq: 25000
|
| 96 |
+
eval_freq: 25000
|
| 97 |
+
save_ckpt: true
|
| 98 |
+
ar_ckpt_path: ''
|
| 99 |
+
ae_ckpt_path: ''
|
| 100 |
+
resume_optimizer: false
|
| 101 |
+
cond_emb_dim: 32
|
| 102 |
+
greedy_coding_prob: 0.0
|
| 103 |
+
z_len: 64
|
| 104 |
+
z_dim: 512
|
| 105 |
+
vq_type: VQ
|
| 106 |
+
codebook_size: 1024
|
| 107 |
+
norm_layer: RMSNorm
|
| 108 |
+
ffn_type: geglu
|
| 109 |
+
context_type: cross_attn
|
| 110 |
+
hidden_dim: 512
|
| 111 |
+
Encoder:
|
| 112 |
+
input_dim: 48
|
| 113 |
+
output_dim: 512
|
| 114 |
+
cond_dim: 32
|
| 115 |
+
cond_input_dim: 11
|
| 116 |
+
max_seq_len: 64
|
| 117 |
+
ctx_max_seq_len: 64
|
| 118 |
+
dim: 512
|
| 119 |
+
layer_num: 10
|
| 120 |
+
mlp_ratio: 4.0
|
| 121 |
+
heads: 8
|
| 122 |
+
emb_dropout: 0.0
|
| 123 |
+
drop: 0.0
|
| 124 |
+
l2_norm: false
|
| 125 |
+
context_type: cross_attn
|
| 126 |
+
rope: false
|
| 127 |
+
abs_pos: true
|
| 128 |
+
causal: false
|
| 129 |
+
norm_layer: RMSNorm
|
| 130 |
+
ffn_type: geglu
|
| 131 |
+
Quantizer:
|
| 132 |
+
codebook_size: 1024
|
| 133 |
+
z_dim: 12
|
| 134 |
+
dim: 512
|
| 135 |
+
length: 64
|
| 136 |
+
cond_dim: 32
|
| 137 |
+
cond_affine_norm: false
|
| 138 |
+
vq_beta: 0.25
|
| 139 |
+
use_norm: true
|
| 140 |
+
norm_layer: l2
|
| 141 |
+
ffn_type: geglu
|
| 142 |
+
temperature: 0.05
|
| 143 |
+
Decoder:
|
| 144 |
+
input_dim: 48
|
| 145 |
+
ctx_input_dim: 512
|
| 146 |
+
output_dim: 48
|
| 147 |
+
cond_dim: 32
|
| 148 |
+
cond_input_dim: 11
|
| 149 |
+
max_seq_len: 64
|
| 150 |
+
ctx_max_seq_len: 64
|
| 151 |
+
dim: 512
|
| 152 |
+
layer_num: 10
|
| 153 |
+
heads: 8
|
| 154 |
+
emb_dropout: 0.0
|
| 155 |
+
drop: 0.0
|
| 156 |
+
l2_norm: false
|
| 157 |
+
context_type: cross_attn
|
| 158 |
+
rope: false
|
| 159 |
+
abs_pos: true
|
| 160 |
+
causal: false
|
| 161 |
+
norm_layer: RMSNorm
|
| 162 |
+
ffn_type: geglu
|
| 163 |
+
mlp_ratio: 4.0
|
| 164 |
+
zero_out: true
|
| 165 |
+
query_type: learnable
|
| 166 |
+
ARModel:
|
| 167 |
+
input_dim: 512
|
| 168 |
+
output_dim: 1024
|
| 169 |
+
max_seq_len: 64
|
| 170 |
+
cond_dim: 32
|
| 171 |
+
cond_input_dim: 11
|
| 172 |
+
dim: 512
|
| 173 |
+
layer_num: 4
|
| 174 |
+
heads: 8
|
| 175 |
+
emb_dropout: 0.0
|
| 176 |
+
drop: 0.0
|
| 177 |
+
l2_norm: false
|
| 178 |
+
context_type: none
|
| 179 |
+
rope: false
|
| 180 |
+
abs_pos: true
|
| 181 |
+
causal: true
|
| 182 |
+
out_act: false
|
| 183 |
+
norm_layer: RMSNorm
|
| 184 |
+
ffn_type: geglu
|
| 185 |
+
mlp_ratio: 4
|
| 186 |
+
zero_out: false
|
| 187 |
+
temperature: 1.0
|
| 188 |
+
GANLoss:
|
| 189 |
+
disc_loss: vanilla
|
| 190 |
+
disc_dim: 64
|
| 191 |
+
disc_type: patchgan
|
| 192 |
+
image_size: 32
|
| 193 |
+
disc_num_layers: 3
|
| 194 |
+
disc_in_channels: 3
|
| 195 |
+
gen_adv_loss: vanilla
|
| 196 |
+
lecam_loss_weight: 0.001
|
| 197 |
+
norm_type: bn
|
| 198 |
+
aug_prob: 1.0
|
| 199 |
+
prior_ar_temp_low: 0.1
|
| 200 |
+
prior_ar_temp_high: 1.0
|
| 201 |
+
prior_ar_temp_schedule: constant
|
dataset.py
ADDED
|
@@ -0,0 +1,415 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Modified work Copyright 2025 Bowen Zheng
|
| 4 |
+
# The Chinese University of Hongkong, Shenzhen
|
| 5 |
+
#
|
| 6 |
+
# This work is licensed under a Creative Commons
|
| 7 |
+
# Attribution-NonCommercial-ShareAlike 4.0 International License.
|
| 8 |
+
# You should have received a copy of the license along with this
|
| 9 |
+
# work. If not, see http://creativecommons.org/licenses/by-nc-sa/4.0/
|
| 10 |
+
|
| 11 |
+
import os
|
| 12 |
+
import sys
|
| 13 |
+
import math
|
| 14 |
+
import subprocess
|
| 15 |
+
import numpy as np
|
| 16 |
+
import zipfile
|
| 17 |
+
import PIL.Image
|
| 18 |
+
import json
|
| 19 |
+
import torch
|
| 20 |
+
import dnnlib
|
| 21 |
+
from pathlib import Path
|
| 22 |
+
|
| 23 |
+
try:
|
| 24 |
+
import pyspng
|
| 25 |
+
except ImportError:
|
| 26 |
+
pyspng = None
|
| 27 |
+
|
| 28 |
+
#----------------------------------------------------------------------------
|
| 29 |
+
# Simple augmentations (center crop / random crop) adapted from ADM
|
| 30 |
+
|
| 31 |
+
def center_crop_arr(pil_image, image_size):
|
| 32 |
+
"""
|
| 33 |
+
Center cropping implementation from ADM.
|
| 34 |
+
https://github.com/openai/guided-diffusion/blob/8fb3ad9197f16bbc40620447b2742e13458d2831/guided_diffusion/image_datasets.py#L126
|
| 35 |
+
"""
|
| 36 |
+
while min(*pil_image.size) >= 2 * image_size:
|
| 37 |
+
pil_image = pil_image.resize(
|
| 38 |
+
tuple(x // 2 for x in pil_image.size), resample=PIL.Image.BOX
|
| 39 |
+
)
|
| 40 |
+
|
| 41 |
+
scale = image_size / min(*pil_image.size)
|
| 42 |
+
pil_image = pil_image.resize(
|
| 43 |
+
tuple(round(x * scale) for x in pil_image.size), resample=PIL.Image.BICUBIC
|
| 44 |
+
)
|
| 45 |
+
|
| 46 |
+
arr = np.array(pil_image)
|
| 47 |
+
crop_y = (arr.shape[0] - image_size) // 2
|
| 48 |
+
crop_x = (arr.shape[1] - image_size) // 2
|
| 49 |
+
return PIL.Image.fromarray(arr[crop_y: crop_y + image_size, crop_x: crop_x + image_size])
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
def random_crop_arr(pil_image, image_size, min_crop_frac=0.8, max_crop_frac=1.0, rng=None):
|
| 53 |
+
min_smaller_dim_size = math.ceil(image_size / max_crop_frac)
|
| 54 |
+
max_smaller_dim_size = math.ceil(image_size / min_crop_frac)
|
| 55 |
+
# Use an explicit RNG when provided (e.g., deterministic per-sample cropping).
|
| 56 |
+
# Otherwise fall back to the global NumPy RNG (which can be controlled via seeding).
|
| 57 |
+
rng = np.random if rng is None else rng
|
| 58 |
+
smaller_dim_size = rng.randint(min_smaller_dim_size, max_smaller_dim_size + 1)
|
| 59 |
+
|
| 60 |
+
# Repeated BOX downsampling preserves the original crop preprocessing.
|
| 61 |
+
while min(*pil_image.size) >= 2 * smaller_dim_size:
|
| 62 |
+
pil_image = pil_image.resize(
|
| 63 |
+
tuple(x // 2 for x in pil_image.size), resample=PIL.Image.BOX
|
| 64 |
+
)
|
| 65 |
+
|
| 66 |
+
scale = smaller_dim_size / min(*pil_image.size)
|
| 67 |
+
pil_image = pil_image.resize(
|
| 68 |
+
tuple(round(x * scale) for x in pil_image.size), resample=PIL.Image.BICUBIC
|
| 69 |
+
)
|
| 70 |
+
|
| 71 |
+
arr = np.array(pil_image)
|
| 72 |
+
crop_y = rng.randint(0, arr.shape[0] - image_size + 1)
|
| 73 |
+
crop_x = rng.randint(0, arr.shape[1] - image_size + 1)
|
| 74 |
+
return PIL.Image.fromarray(arr[crop_y: crop_y + image_size, crop_x: crop_x + image_size])
|
| 75 |
+
|
| 76 |
+
class Dataset(torch.utils.data.Dataset):
|
| 77 |
+
def __init__(self,
|
| 78 |
+
name, # Name of the dataset.
|
| 79 |
+
raw_shape, # Shape of the raw image data (NCHW).
|
| 80 |
+
max_size = None, # Artificially limit the size of the dataset. None = no limit. Applied before xflip.
|
| 81 |
+
use_label = False, # Enable conditioning labels? False = label dimension is zero.
|
| 82 |
+
xflip = False, # Artificially double the size of the dataset via x-flips. Applied after max_size.
|
| 83 |
+
random_seed = 0, # Random seed to use when applying max_size.
|
| 84 |
+
):
|
| 85 |
+
self._name = name
|
| 86 |
+
self._raw_shape = list(raw_shape)
|
| 87 |
+
self._use_label = use_label
|
| 88 |
+
self._raw_labels = None
|
| 89 |
+
self._label_shape = None
|
| 90 |
+
|
| 91 |
+
# Apply max_size.
|
| 92 |
+
self._raw_idx = np.arange(self._raw_shape[0], dtype=np.int64)
|
| 93 |
+
if (max_size is not None) and (self._raw_idx.size > max_size):
|
| 94 |
+
np.random.RandomState(random_seed % (1 << 31)).shuffle(self._raw_idx)
|
| 95 |
+
self._raw_idx = np.sort(self._raw_idx[:max_size])
|
| 96 |
+
|
| 97 |
+
# Apply xflip.
|
| 98 |
+
self._xflip = np.zeros(self._raw_idx.size, dtype=np.uint8)
|
| 99 |
+
if xflip:
|
| 100 |
+
self._raw_idx = np.tile(self._raw_idx, 2)
|
| 101 |
+
self._xflip = np.concatenate([self._xflip, np.ones_like(self._xflip)])
|
| 102 |
+
|
| 103 |
+
def _get_raw_labels(self):
|
| 104 |
+
if self._raw_labels is None:
|
| 105 |
+
self._raw_labels = self._load_raw_labels() if self._use_label else None
|
| 106 |
+
if self._raw_labels is None:
|
| 107 |
+
self._raw_labels = np.zeros([self._raw_shape[0], 0], dtype=np.float32)
|
| 108 |
+
assert isinstance(self._raw_labels, np.ndarray)
|
| 109 |
+
assert self._raw_labels.shape[0] == self._raw_shape[0]
|
| 110 |
+
assert self._raw_labels.dtype in [np.float32, np.int64]
|
| 111 |
+
if self._raw_labels.dtype == np.int64:
|
| 112 |
+
assert self._raw_labels.ndim == 1
|
| 113 |
+
assert np.all(self._raw_labels >= 0)
|
| 114 |
+
return self._raw_labels
|
| 115 |
+
|
| 116 |
+
def close(self): # to be overridden by subclass
|
| 117 |
+
pass
|
| 118 |
+
|
| 119 |
+
def _load_raw_image(self, raw_idx): # to be overridden by subclass
|
| 120 |
+
raise NotImplementedError
|
| 121 |
+
|
| 122 |
+
def _load_raw_labels(self): # to be overridden by subclass
|
| 123 |
+
raise NotImplementedError
|
| 124 |
+
|
| 125 |
+
def __getstate__(self):
|
| 126 |
+
return dict(self.__dict__, _raw_labels=None)
|
| 127 |
+
|
| 128 |
+
def __del__(self):
|
| 129 |
+
try:
|
| 130 |
+
self.close()
|
| 131 |
+
except:
|
| 132 |
+
pass
|
| 133 |
+
|
| 134 |
+
def __len__(self):
|
| 135 |
+
return self._raw_idx.size
|
| 136 |
+
|
| 137 |
+
def __getitem__(self, idx):
|
| 138 |
+
raw_idx = self._raw_idx[idx]
|
| 139 |
+
image = self._load_raw_image(raw_idx)
|
| 140 |
+
assert isinstance(image, np.ndarray)
|
| 141 |
+
assert list(image.shape) == self.image_shape
|
| 142 |
+
assert image.dtype == np.uint8
|
| 143 |
+
if self._xflip[idx]:
|
| 144 |
+
assert image.ndim == 3 # CHW
|
| 145 |
+
image = image[:, :, ::-1]
|
| 146 |
+
return image.copy(), self.get_label(idx)
|
| 147 |
+
|
| 148 |
+
def get_label(self, idx):
|
| 149 |
+
label = self._get_raw_labels()[self._raw_idx[idx]]
|
| 150 |
+
if label.dtype == np.int64:
|
| 151 |
+
onehot = np.zeros(self.label_shape, dtype=np.float32)
|
| 152 |
+
onehot[label] = 1
|
| 153 |
+
label = onehot
|
| 154 |
+
return label.copy()
|
| 155 |
+
|
| 156 |
+
def get_details(self, idx):
|
| 157 |
+
d = dnnlib.EasyDict()
|
| 158 |
+
d.raw_idx = int(self._raw_idx[idx])
|
| 159 |
+
d.xflip = (int(self._xflip[idx]) != 0)
|
| 160 |
+
d.raw_label = self._get_raw_labels()[d.raw_idx].copy()
|
| 161 |
+
return d
|
| 162 |
+
|
| 163 |
+
@property
|
| 164 |
+
def name(self):
|
| 165 |
+
return self._name
|
| 166 |
+
|
| 167 |
+
@property
|
| 168 |
+
def image_shape(self):
|
| 169 |
+
return list(self._raw_shape[1:])
|
| 170 |
+
|
| 171 |
+
@property
|
| 172 |
+
def num_channels(self):
|
| 173 |
+
assert len(self.image_shape) == 3 # CHW
|
| 174 |
+
return self.image_shape[0]
|
| 175 |
+
|
| 176 |
+
@property
|
| 177 |
+
def resolution(self):
|
| 178 |
+
assert len(self.image_shape) == 3 # CHW
|
| 179 |
+
assert self.image_shape[1] == self.image_shape[2]
|
| 180 |
+
return self.image_shape[1]
|
| 181 |
+
|
| 182 |
+
@property
|
| 183 |
+
def label_shape(self):
|
| 184 |
+
if self._label_shape is None:
|
| 185 |
+
raw_labels = self._get_raw_labels()
|
| 186 |
+
if raw_labels.dtype == np.int64:
|
| 187 |
+
self._label_shape = [int(np.max(raw_labels)) + 1]
|
| 188 |
+
else:
|
| 189 |
+
self._label_shape = raw_labels.shape[1:]
|
| 190 |
+
return list(self._label_shape)
|
| 191 |
+
|
| 192 |
+
@property
|
| 193 |
+
def label_dim(self):
|
| 194 |
+
assert len(self.label_shape) == 1
|
| 195 |
+
return self.label_shape[0]
|
| 196 |
+
|
| 197 |
+
@property
|
| 198 |
+
def has_labels(self):
|
| 199 |
+
return any(x != 0 for x in self.label_shape)
|
| 200 |
+
|
| 201 |
+
@property
|
| 202 |
+
def has_onehot_labels(self):
|
| 203 |
+
return self._get_raw_labels().dtype == np.int64
|
| 204 |
+
|
| 205 |
+
# ------------------------------------------------------------------------
|
| 206 |
+
# Simple augmentations (center crop / random crop) as Dataset helpers,
|
| 207 |
+
def _center_crop_arr(self, pil_image, image_size):
|
| 208 |
+
"""
|
| 209 |
+
Center cropping implementation from ADM.
|
| 210 |
+
https://github.com/openai/guided-diffusion/blob/8fb3ad9197f16bbc40620447b2742e13458d2831/guided_diffusion/image_datasets.py#L126
|
| 211 |
+
"""
|
| 212 |
+
while min(*pil_image.size) >= 2 * image_size:
|
| 213 |
+
pil_image = pil_image.resize(
|
| 214 |
+
tuple(x // 2 for x in pil_image.size), resample=PIL.Image.BOX
|
| 215 |
+
)
|
| 216 |
+
|
| 217 |
+
scale = image_size / min(*pil_image.size)
|
| 218 |
+
pil_image = pil_image.resize(
|
| 219 |
+
tuple(round(x * scale) for x in pil_image.size), resample=PIL.Image.BICUBIC
|
| 220 |
+
)
|
| 221 |
+
|
| 222 |
+
arr = np.array(pil_image)
|
| 223 |
+
crop_y = (arr.shape[0] - image_size) // 2
|
| 224 |
+
crop_x = (arr.shape[1] - image_size) // 2
|
| 225 |
+
return PIL.Image.fromarray(arr[crop_y: crop_y + image_size, crop_x: crop_x + image_size])
|
| 226 |
+
|
| 227 |
+
def _random_crop_arr(self, pil_image, image_size, min_crop_frac=0.8, max_crop_frac=1.0, rng=None):
|
| 228 |
+
min_smaller_dim_size = math.ceil(image_size / max_crop_frac)
|
| 229 |
+
max_smaller_dim_size = math.ceil(image_size / min_crop_frac)
|
| 230 |
+
rng = np.random if rng is None else rng
|
| 231 |
+
smaller_dim_size = rng.randint(min_smaller_dim_size, max_smaller_dim_size + 1)
|
| 232 |
+
|
| 233 |
+
# Repeated BOX downsampling preserves the original crop preprocessing.
|
| 234 |
+
while min(*pil_image.size) >= 2 * smaller_dim_size:
|
| 235 |
+
pil_image = pil_image.resize(
|
| 236 |
+
tuple(x // 2 for x in pil_image.size), resample=PIL.Image.BOX
|
| 237 |
+
)
|
| 238 |
+
|
| 239 |
+
scale = smaller_dim_size / min(*pil_image.size)
|
| 240 |
+
pil_image = pil_image.resize(
|
| 241 |
+
tuple(round(x * scale) for x in pil_image.size), resample=PIL.Image.BICUBIC
|
| 242 |
+
)
|
| 243 |
+
|
| 244 |
+
arr = np.array(pil_image)
|
| 245 |
+
crop_y = rng.randint(0, arr.shape[0] - image_size + 1)
|
| 246 |
+
crop_x = rng.randint(0, arr.shape[1] - image_size + 1)
|
| 247 |
+
return PIL.Image.fromarray(arr[crop_y: crop_y + image_size, crop_x: crop_x + image_size])
|
| 248 |
+
|
| 249 |
+
class ImageFolderDataset(Dataset):
|
| 250 |
+
def __init__(self,
|
| 251 |
+
path, # Path to directory or zip.
|
| 252 |
+
resolution = None, # Ensure specific resolution, None = highest available.
|
| 253 |
+
use_pyspng = True, # Use pyspng if available?
|
| 254 |
+
crop_type = None, # None / 'center' / 'random'
|
| 255 |
+
deterministic_crop = False, # If True and crop_type=='random', crop depends only on (crop_seed, raw_idx).
|
| 256 |
+
crop_seed = 0,
|
| 257 |
+
**super_kwargs, # Additional arguments for the Dataset base class.
|
| 258 |
+
):
|
| 259 |
+
self._path = path
|
| 260 |
+
self._use_pyspng = use_pyspng
|
| 261 |
+
self._zipfile = None
|
| 262 |
+
self._crop_type = crop_type
|
| 263 |
+
self._resolution = resolution
|
| 264 |
+
self._deterministic_crop = bool(deterministic_crop)
|
| 265 |
+
self._crop_seed = int(crop_seed)
|
| 266 |
+
|
| 267 |
+
# If labels are requested and no dataset.json is present, try to
|
| 268 |
+
# create it in-place using dataset_tools.py (labels-only mode).
|
| 269 |
+
use_label = bool(super_kwargs.get('use_label', False))
|
| 270 |
+
if use_label:
|
| 271 |
+
self._ensure_dataset_json()
|
| 272 |
+
|
| 273 |
+
if os.path.isdir(self._path):
|
| 274 |
+
self._type = 'dir'
|
| 275 |
+
self._all_fnames = {os.path.relpath(os.path.join(root, fname), start=self._path) for root, _dirs, files in os.walk(self._path) for fname in files}
|
| 276 |
+
elif self._file_ext(self._path) == '.zip':
|
| 277 |
+
self._type = 'zip'
|
| 278 |
+
self._all_fnames = set(self._get_zipfile().namelist())
|
| 279 |
+
else:
|
| 280 |
+
raise IOError('Path must point to a directory or zip')
|
| 281 |
+
|
| 282 |
+
PIL.Image.init()
|
| 283 |
+
self._image_fnames = sorted(fname for fname in self._all_fnames if self._file_ext(fname) in PIL.Image.EXTENSION)
|
| 284 |
+
if len(self._image_fnames) == 0:
|
| 285 |
+
raise IOError('No image files found in the specified path')
|
| 286 |
+
|
| 287 |
+
name = os.path.splitext(os.path.basename(self._path))[0]
|
| 288 |
+
raw_shape = [len(self._image_fnames)] + list(self._load_raw_image(0).shape)
|
| 289 |
+
if resolution is not None and (raw_shape[2] != resolution or raw_shape[3] != resolution):
|
| 290 |
+
raise IOError('Image files do not match the specified resolution')
|
| 291 |
+
super().__init__(name=name, raw_shape=raw_shape, **super_kwargs)
|
| 292 |
+
|
| 293 |
+
@staticmethod
|
| 294 |
+
def _file_ext(fname):
|
| 295 |
+
return os.path.splitext(fname)[1].lower()
|
| 296 |
+
|
| 297 |
+
def _get_zipfile(self):
|
| 298 |
+
assert self._type == 'zip'
|
| 299 |
+
if self._zipfile is None:
|
| 300 |
+
self._zipfile = zipfile.ZipFile(self._path)
|
| 301 |
+
return self._zipfile
|
| 302 |
+
|
| 303 |
+
def _open_file(self, fname):
|
| 304 |
+
if self._type == 'dir':
|
| 305 |
+
return open(os.path.join(self._path, fname), 'rb')
|
| 306 |
+
if self._type == 'zip':
|
| 307 |
+
return self._get_zipfile().open(fname, 'r')
|
| 308 |
+
return None
|
| 309 |
+
|
| 310 |
+
def close(self):
|
| 311 |
+
try:
|
| 312 |
+
if self._zipfile is not None:
|
| 313 |
+
self._zipfile.close()
|
| 314 |
+
finally:
|
| 315 |
+
self._zipfile = None
|
| 316 |
+
|
| 317 |
+
def __getstate__(self):
|
| 318 |
+
return dict(super().__getstate__(), _zipfile=None)
|
| 319 |
+
|
| 320 |
+
def _ensure_dataset_json(self):
|
| 321 |
+
"""Ensure dataset.json with labels exists for this dataset path.
|
| 322 |
+
|
| 323 |
+
If missing, call dataset_tools.py in labels-only mode to generate it.
|
| 324 |
+
"""
|
| 325 |
+
# Directory: check for dataset.json at root.
|
| 326 |
+
if os.path.isdir(self._path):
|
| 327 |
+
json_path = os.path.join(self._path, 'dataset.json')
|
| 328 |
+
if os.path.isfile(json_path):
|
| 329 |
+
return
|
| 330 |
+
# Zip: check if dataset.json is inside archive.
|
| 331 |
+
elif self._file_ext(self._path) == '.zip':
|
| 332 |
+
try:
|
| 333 |
+
with zipfile.ZipFile(self._path, mode='r') as z:
|
| 334 |
+
if 'dataset.json' in z.namelist():
|
| 335 |
+
return
|
| 336 |
+
except Exception:
|
| 337 |
+
return
|
| 338 |
+
else:
|
| 339 |
+
return
|
| 340 |
+
|
| 341 |
+
# Use the dataset preparation tool bundled with this package.
|
| 342 |
+
project_root = Path(__file__).resolve().parent
|
| 343 |
+
tools_path = project_root / 'scripts' / 'dataset_tools.py'
|
| 344 |
+
if not tools_path.is_file():
|
| 345 |
+
print(f"Warning: dataset_tools.py not found at {tools_path}, cannot auto-generate dataset.json labels.")
|
| 346 |
+
return
|
| 347 |
+
|
| 348 |
+
cmd = [
|
| 349 |
+
sys.executable,
|
| 350 |
+
str(tools_path),
|
| 351 |
+
'--source', str(self._path),
|
| 352 |
+
'--dest', str(self._path),
|
| 353 |
+
'--labels-only',
|
| 354 |
+
]
|
| 355 |
+
try:
|
| 356 |
+
subprocess.run(cmd, check=True)
|
| 357 |
+
except Exception as e:
|
| 358 |
+
print(f"Warning: failed to generate dataset.json via dataset_tools.py: {e}")
|
| 359 |
+
|
| 360 |
+
def _load_raw_image(self, raw_idx):
|
| 361 |
+
fname = self._image_fnames[raw_idx]
|
| 362 |
+
|
| 363 |
+
# If no crop augmentation is requested, keep original fast path
|
| 364 |
+
# (optionally using pyspng for PNGs).
|
| 365 |
+
if self._crop_type is None:
|
| 366 |
+
with self._open_file(fname) as f:
|
| 367 |
+
if self._use_pyspng and pyspng is not None and self._file_ext(fname) == '.png':
|
| 368 |
+
image = pyspng.load(f.read())
|
| 369 |
+
else:
|
| 370 |
+
image = np.array(PIL.Image.open(f))
|
| 371 |
+
else:
|
| 372 |
+
# Use PIL path so we can apply center/random crop.
|
| 373 |
+
if self._resolution is None:
|
| 374 |
+
raise ValueError("resolution must be set when using crop_type for ImageFolderDataset.")
|
| 375 |
+
with self._open_file(fname) as f:
|
| 376 |
+
pil_img = PIL.Image.open(f).convert("RGB")
|
| 377 |
+
if self._crop_type == 'center':
|
| 378 |
+
pil_img = self._center_crop_arr(pil_img, self._resolution)
|
| 379 |
+
elif self._crop_type == 'random':
|
| 380 |
+
rng = None
|
| 381 |
+
if self._deterministic_crop:
|
| 382 |
+
# Make cropping independent of call order / other RNG consumers.
|
| 383 |
+
# Note: this fixes the crop for a given raw_idx across epochs.
|
| 384 |
+
seed = (self._crop_seed + int(raw_idx)) % (1 << 31)
|
| 385 |
+
rng = np.random.RandomState(seed)
|
| 386 |
+
pil_img = self._random_crop_arr(pil_img, self._resolution, rng=rng)
|
| 387 |
+
else:
|
| 388 |
+
raise ValueError(f"Unknown crop_type: {self._crop_type}")
|
| 389 |
+
image = np.array(pil_img)
|
| 390 |
+
|
| 391 |
+
# Normalize channel count to 3 (RGB) where possible.
|
| 392 |
+
if image.ndim == 2:
|
| 393 |
+
image = np.stack([image] * 3, axis=-1) # HW => HWC (3-channel grayscale)
|
| 394 |
+
elif image.ndim == 3:
|
| 395 |
+
if image.shape[2] == 1:
|
| 396 |
+
image = np.repeat(image, 3, axis=2)
|
| 397 |
+
elif image.shape[2] > 3:
|
| 398 |
+
image = image[:, :, :3]
|
| 399 |
+
|
| 400 |
+
image = image.transpose(2, 0, 1) # HWC => CHW
|
| 401 |
+
return image
|
| 402 |
+
|
| 403 |
+
def _load_raw_labels(self):
|
| 404 |
+
fname = 'dataset.json'
|
| 405 |
+
if fname not in self._all_fnames:
|
| 406 |
+
return None
|
| 407 |
+
with self._open_file(fname) as f:
|
| 408 |
+
labels = json.load(f)['labels']
|
| 409 |
+
if labels is None:
|
| 410 |
+
return None
|
| 411 |
+
labels = dict(labels)
|
| 412 |
+
labels = [labels[fname.replace('\\', '/')] for fname in self._image_fnames]
|
| 413 |
+
labels = np.array(labels)
|
| 414 |
+
labels = labels.astype({1: np.int64, 2: np.float32}[labels.ndim])
|
| 415 |
+
return labels
|
dnnlib/__init__.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# This work is licensed under a Creative Commons
|
| 4 |
+
# Attribution-NonCommercial-ShareAlike 4.0 International License.
|
| 5 |
+
# You should have received a copy of the license along with this
|
| 6 |
+
# work. If not, see http://creativecommons.org/licenses/by-nc-sa/4.0/
|
| 7 |
+
|
| 8 |
+
from .util import EasyDict, make_cache_dir_path
|
dnnlib/util.py
ADDED
|
@@ -0,0 +1,491 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# This work is licensed under a Creative Commons
|
| 4 |
+
# Attribution-NonCommercial-ShareAlike 4.0 International License.
|
| 5 |
+
# You should have received a copy of the license along with this
|
| 6 |
+
# work. If not, see http://creativecommons.org/licenses/by-nc-sa/4.0/
|
| 7 |
+
|
| 8 |
+
"""Miscellaneous utility classes and functions."""
|
| 9 |
+
|
| 10 |
+
import ctypes
|
| 11 |
+
import fnmatch
|
| 12 |
+
import importlib
|
| 13 |
+
import inspect
|
| 14 |
+
import numpy as np
|
| 15 |
+
import os
|
| 16 |
+
import shutil
|
| 17 |
+
import sys
|
| 18 |
+
import types
|
| 19 |
+
import io
|
| 20 |
+
import pickle
|
| 21 |
+
import re
|
| 22 |
+
import requests
|
| 23 |
+
import html
|
| 24 |
+
import hashlib
|
| 25 |
+
import glob
|
| 26 |
+
import tempfile
|
| 27 |
+
import urllib
|
| 28 |
+
import urllib.request
|
| 29 |
+
import uuid
|
| 30 |
+
|
| 31 |
+
from distutils.util import strtobool
|
| 32 |
+
from typing import Any, List, Tuple, Union, Optional
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
# Util classes
|
| 36 |
+
# ------------------------------------------------------------------------------------------
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
class EasyDict(dict):
|
| 40 |
+
"""Convenience class that behaves like a dict but allows access with the attribute syntax."""
|
| 41 |
+
|
| 42 |
+
def __getattr__(self, name: str) -> Any:
|
| 43 |
+
try:
|
| 44 |
+
return self[name]
|
| 45 |
+
except KeyError:
|
| 46 |
+
raise AttributeError(name)
|
| 47 |
+
|
| 48 |
+
def __setattr__(self, name: str, value: Any) -> None:
|
| 49 |
+
self[name] = value
|
| 50 |
+
|
| 51 |
+
def __delattr__(self, name: str) -> None:
|
| 52 |
+
del self[name]
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
class Logger(object):
|
| 56 |
+
"""Redirect stderr to stdout, optionally print stdout to a file, and optionally force flushing on both stdout and the file."""
|
| 57 |
+
|
| 58 |
+
def __init__(self, file_name: Optional[str] = None, file_mode: str = "w", should_flush: bool = True):
|
| 59 |
+
self.file = None
|
| 60 |
+
|
| 61 |
+
if file_name is not None:
|
| 62 |
+
self.file = open(file_name, file_mode)
|
| 63 |
+
|
| 64 |
+
self.should_flush = should_flush
|
| 65 |
+
self.stdout = sys.stdout
|
| 66 |
+
self.stderr = sys.stderr
|
| 67 |
+
|
| 68 |
+
sys.stdout = self
|
| 69 |
+
sys.stderr = self
|
| 70 |
+
|
| 71 |
+
def __enter__(self) -> "Logger":
|
| 72 |
+
return self
|
| 73 |
+
|
| 74 |
+
def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
|
| 75 |
+
self.close()
|
| 76 |
+
|
| 77 |
+
def write(self, text: Union[str, bytes]) -> None:
|
| 78 |
+
"""Write text to stdout (and a file) and optionally flush."""
|
| 79 |
+
if isinstance(text, bytes):
|
| 80 |
+
text = text.decode()
|
| 81 |
+
if len(text) == 0: # workaround for a bug in VSCode debugger: sys.stdout.write(''); sys.stdout.flush() => crash
|
| 82 |
+
return
|
| 83 |
+
|
| 84 |
+
if self.file is not None:
|
| 85 |
+
self.file.write(text)
|
| 86 |
+
|
| 87 |
+
self.stdout.write(text)
|
| 88 |
+
|
| 89 |
+
if self.should_flush:
|
| 90 |
+
self.flush()
|
| 91 |
+
|
| 92 |
+
def flush(self) -> None:
|
| 93 |
+
"""Flush written text to both stdout and a file, if open."""
|
| 94 |
+
if self.file is not None:
|
| 95 |
+
self.file.flush()
|
| 96 |
+
|
| 97 |
+
self.stdout.flush()
|
| 98 |
+
|
| 99 |
+
def close(self) -> None:
|
| 100 |
+
"""Flush, close possible files, and remove stdout/stderr mirroring."""
|
| 101 |
+
self.flush()
|
| 102 |
+
|
| 103 |
+
# if using multiple loggers, prevent closing in wrong order
|
| 104 |
+
if sys.stdout is self:
|
| 105 |
+
sys.stdout = self.stdout
|
| 106 |
+
if sys.stderr is self:
|
| 107 |
+
sys.stderr = self.stderr
|
| 108 |
+
|
| 109 |
+
if self.file is not None:
|
| 110 |
+
self.file.close()
|
| 111 |
+
self.file = None
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
# Cache directories
|
| 115 |
+
# ------------------------------------------------------------------------------------------
|
| 116 |
+
|
| 117 |
+
_dnnlib_cache_dir = None
|
| 118 |
+
|
| 119 |
+
def set_cache_dir(path: str) -> None:
|
| 120 |
+
global _dnnlib_cache_dir
|
| 121 |
+
_dnnlib_cache_dir = path
|
| 122 |
+
|
| 123 |
+
def make_cache_dir_path(*paths: str) -> str:
|
| 124 |
+
if _dnnlib_cache_dir is not None:
|
| 125 |
+
return os.path.join(_dnnlib_cache_dir, *paths)
|
| 126 |
+
if 'DNNLIB_CACHE_DIR' in os.environ:
|
| 127 |
+
return os.path.join(os.environ['DNNLIB_CACHE_DIR'], *paths)
|
| 128 |
+
if 'HOME' in os.environ:
|
| 129 |
+
return os.path.join(os.environ['HOME'], '.cache', 'dnnlib', *paths)
|
| 130 |
+
if 'USERPROFILE' in os.environ:
|
| 131 |
+
return os.path.join(os.environ['USERPROFILE'], '.cache', 'dnnlib', *paths)
|
| 132 |
+
return os.path.join(tempfile.gettempdir(), '.cache', 'dnnlib', *paths)
|
| 133 |
+
|
| 134 |
+
# Small util functions
|
| 135 |
+
# ------------------------------------------------------------------------------------------
|
| 136 |
+
|
| 137 |
+
|
| 138 |
+
def format_time(seconds: Union[int, float]) -> str:
|
| 139 |
+
"""Convert the seconds to human readable string with days, hours, minutes and seconds."""
|
| 140 |
+
s = int(np.rint(seconds))
|
| 141 |
+
|
| 142 |
+
if s < 60:
|
| 143 |
+
return "{0}s".format(s)
|
| 144 |
+
elif s < 60 * 60:
|
| 145 |
+
return "{0}m {1:02}s".format(s // 60, s % 60)
|
| 146 |
+
elif s < 24 * 60 * 60:
|
| 147 |
+
return "{0}h {1:02}m {2:02}s".format(s // (60 * 60), (s // 60) % 60, s % 60)
|
| 148 |
+
else:
|
| 149 |
+
return "{0}d {1:02}h {2:02}m".format(s // (24 * 60 * 60), (s // (60 * 60)) % 24, (s // 60) % 60)
|
| 150 |
+
|
| 151 |
+
|
| 152 |
+
def format_time_brief(seconds: Union[int, float]) -> str:
|
| 153 |
+
"""Convert the seconds to human readable string with days, hours, minutes and seconds."""
|
| 154 |
+
s = int(np.rint(seconds))
|
| 155 |
+
|
| 156 |
+
if s < 60:
|
| 157 |
+
return "{0}s".format(s)
|
| 158 |
+
elif s < 60 * 60:
|
| 159 |
+
return "{0}m {1:02}s".format(s // 60, s % 60)
|
| 160 |
+
elif s < 24 * 60 * 60:
|
| 161 |
+
return "{0}h {1:02}m".format(s // (60 * 60), (s // 60) % 60)
|
| 162 |
+
else:
|
| 163 |
+
return "{0}d {1:02}h".format(s // (24 * 60 * 60), (s // (60 * 60)) % 24)
|
| 164 |
+
|
| 165 |
+
|
| 166 |
+
def ask_yes_no(question: str) -> bool:
|
| 167 |
+
"""Ask the user the question until the user inputs a valid answer."""
|
| 168 |
+
while True:
|
| 169 |
+
try:
|
| 170 |
+
print("{0} [y/n]".format(question))
|
| 171 |
+
return strtobool(input().lower())
|
| 172 |
+
except ValueError:
|
| 173 |
+
pass
|
| 174 |
+
|
| 175 |
+
|
| 176 |
+
def tuple_product(t: Tuple) -> Any:
|
| 177 |
+
"""Calculate the product of the tuple elements."""
|
| 178 |
+
result = 1
|
| 179 |
+
|
| 180 |
+
for v in t:
|
| 181 |
+
result *= v
|
| 182 |
+
|
| 183 |
+
return result
|
| 184 |
+
|
| 185 |
+
|
| 186 |
+
_str_to_ctype = {
|
| 187 |
+
"uint8": ctypes.c_ubyte,
|
| 188 |
+
"uint16": ctypes.c_uint16,
|
| 189 |
+
"uint32": ctypes.c_uint32,
|
| 190 |
+
"uint64": ctypes.c_uint64,
|
| 191 |
+
"int8": ctypes.c_byte,
|
| 192 |
+
"int16": ctypes.c_int16,
|
| 193 |
+
"int32": ctypes.c_int32,
|
| 194 |
+
"int64": ctypes.c_int64,
|
| 195 |
+
"float32": ctypes.c_float,
|
| 196 |
+
"float64": ctypes.c_double
|
| 197 |
+
}
|
| 198 |
+
|
| 199 |
+
|
| 200 |
+
def get_dtype_and_ctype(type_obj: Any) -> Tuple[np.dtype, Any]:
|
| 201 |
+
"""Given a type name string (or an object having a __name__ attribute), return matching Numpy and ctypes types that have the same size in bytes."""
|
| 202 |
+
type_str = None
|
| 203 |
+
|
| 204 |
+
if isinstance(type_obj, str):
|
| 205 |
+
type_str = type_obj
|
| 206 |
+
elif hasattr(type_obj, "__name__"):
|
| 207 |
+
type_str = type_obj.__name__
|
| 208 |
+
elif hasattr(type_obj, "name"):
|
| 209 |
+
type_str = type_obj.name
|
| 210 |
+
else:
|
| 211 |
+
raise RuntimeError("Cannot infer type name from input")
|
| 212 |
+
|
| 213 |
+
assert type_str in _str_to_ctype.keys()
|
| 214 |
+
|
| 215 |
+
my_dtype = np.dtype(type_str)
|
| 216 |
+
my_ctype = _str_to_ctype[type_str]
|
| 217 |
+
|
| 218 |
+
assert my_dtype.itemsize == ctypes.sizeof(my_ctype)
|
| 219 |
+
|
| 220 |
+
return my_dtype, my_ctype
|
| 221 |
+
|
| 222 |
+
|
| 223 |
+
def is_pickleable(obj: Any) -> bool:
|
| 224 |
+
try:
|
| 225 |
+
with io.BytesIO() as stream:
|
| 226 |
+
pickle.dump(obj, stream)
|
| 227 |
+
return True
|
| 228 |
+
except:
|
| 229 |
+
return False
|
| 230 |
+
|
| 231 |
+
|
| 232 |
+
# Functionality to import modules/objects by name, and call functions by name
|
| 233 |
+
# ------------------------------------------------------------------------------------------
|
| 234 |
+
|
| 235 |
+
def get_module_from_obj_name(obj_name: str) -> Tuple[types.ModuleType, str]:
|
| 236 |
+
"""Searches for the underlying module behind the name to some python object.
|
| 237 |
+
Returns the module and the object name (original name with module part removed)."""
|
| 238 |
+
|
| 239 |
+
# allow convenience shorthands, substitute them by full names
|
| 240 |
+
obj_name = re.sub("^np.", "numpy.", obj_name)
|
| 241 |
+
obj_name = re.sub("^tf.", "tensorflow.", obj_name)
|
| 242 |
+
|
| 243 |
+
# list alternatives for (module_name, local_obj_name)
|
| 244 |
+
parts = obj_name.split(".")
|
| 245 |
+
name_pairs = [(".".join(parts[:i]), ".".join(parts[i:])) for i in range(len(parts), 0, -1)]
|
| 246 |
+
|
| 247 |
+
# try each alternative in turn
|
| 248 |
+
for module_name, local_obj_name in name_pairs:
|
| 249 |
+
try:
|
| 250 |
+
module = importlib.import_module(module_name) # may raise ImportError
|
| 251 |
+
get_obj_from_module(module, local_obj_name) # may raise AttributeError
|
| 252 |
+
return module, local_obj_name
|
| 253 |
+
except:
|
| 254 |
+
pass
|
| 255 |
+
|
| 256 |
+
# maybe some of the modules themselves contain errors?
|
| 257 |
+
for module_name, _local_obj_name in name_pairs:
|
| 258 |
+
try:
|
| 259 |
+
importlib.import_module(module_name) # may raise ImportError
|
| 260 |
+
except ImportError:
|
| 261 |
+
if not str(sys.exc_info()[1]).startswith("No module named '" + module_name + "'"):
|
| 262 |
+
raise
|
| 263 |
+
|
| 264 |
+
# maybe the requested attribute is missing?
|
| 265 |
+
for module_name, local_obj_name in name_pairs:
|
| 266 |
+
try:
|
| 267 |
+
module = importlib.import_module(module_name) # may raise ImportError
|
| 268 |
+
get_obj_from_module(module, local_obj_name) # may raise AttributeError
|
| 269 |
+
except ImportError:
|
| 270 |
+
pass
|
| 271 |
+
|
| 272 |
+
# we are out of luck, but we have no idea why
|
| 273 |
+
raise ImportError(obj_name)
|
| 274 |
+
|
| 275 |
+
|
| 276 |
+
def get_obj_from_module(module: types.ModuleType, obj_name: str) -> Any:
|
| 277 |
+
"""Traverses the object name and returns the last (rightmost) python object."""
|
| 278 |
+
if obj_name == '':
|
| 279 |
+
return module
|
| 280 |
+
obj = module
|
| 281 |
+
for part in obj_name.split("."):
|
| 282 |
+
obj = getattr(obj, part)
|
| 283 |
+
return obj
|
| 284 |
+
|
| 285 |
+
|
| 286 |
+
def get_obj_by_name(name: str) -> Any:
|
| 287 |
+
"""Finds the python object with the given name."""
|
| 288 |
+
module, obj_name = get_module_from_obj_name(name)
|
| 289 |
+
return get_obj_from_module(module, obj_name)
|
| 290 |
+
|
| 291 |
+
|
| 292 |
+
def call_func_by_name(*args, func_name: str = None, **kwargs) -> Any:
|
| 293 |
+
"""Finds the python object with the given name and calls it as a function."""
|
| 294 |
+
assert func_name is not None
|
| 295 |
+
func_obj = get_obj_by_name(func_name)
|
| 296 |
+
assert callable(func_obj)
|
| 297 |
+
return func_obj(*args, **kwargs)
|
| 298 |
+
|
| 299 |
+
|
| 300 |
+
def construct_class_by_name(*args, class_name: str = None, **kwargs) -> Any:
|
| 301 |
+
"""Finds the python class with the given name and constructs it with the given arguments."""
|
| 302 |
+
return call_func_by_name(*args, func_name=class_name, **kwargs)
|
| 303 |
+
|
| 304 |
+
|
| 305 |
+
def get_module_dir_by_obj_name(obj_name: str) -> str:
|
| 306 |
+
"""Get the directory path of the module containing the given object name."""
|
| 307 |
+
module, _ = get_module_from_obj_name(obj_name)
|
| 308 |
+
return os.path.dirname(inspect.getfile(module))
|
| 309 |
+
|
| 310 |
+
|
| 311 |
+
def is_top_level_function(obj: Any) -> bool:
|
| 312 |
+
"""Determine whether the given object is a top-level function, i.e., defined at module scope using 'def'."""
|
| 313 |
+
return callable(obj) and obj.__name__ in sys.modules[obj.__module__].__dict__
|
| 314 |
+
|
| 315 |
+
|
| 316 |
+
def get_top_level_function_name(obj: Any) -> str:
|
| 317 |
+
"""Return the fully-qualified name of a top-level function."""
|
| 318 |
+
assert is_top_level_function(obj)
|
| 319 |
+
module = obj.__module__
|
| 320 |
+
if module == '__main__':
|
| 321 |
+
module = os.path.splitext(os.path.basename(sys.modules[module].__file__))[0]
|
| 322 |
+
return module + "." + obj.__name__
|
| 323 |
+
|
| 324 |
+
|
| 325 |
+
# File system helpers
|
| 326 |
+
# ------------------------------------------------------------------------------------------
|
| 327 |
+
|
| 328 |
+
def list_dir_recursively_with_ignore(dir_path: str, ignores: List[str] = None, add_base_to_relative: bool = False) -> List[Tuple[str, str]]:
|
| 329 |
+
"""List all files recursively in a given directory while ignoring given file and directory names.
|
| 330 |
+
Returns list of tuples containing both absolute and relative paths."""
|
| 331 |
+
assert os.path.isdir(dir_path)
|
| 332 |
+
base_name = os.path.basename(os.path.normpath(dir_path))
|
| 333 |
+
|
| 334 |
+
if ignores is None:
|
| 335 |
+
ignores = []
|
| 336 |
+
|
| 337 |
+
result = []
|
| 338 |
+
|
| 339 |
+
for root, dirs, files in os.walk(dir_path, topdown=True):
|
| 340 |
+
for ignore_ in ignores:
|
| 341 |
+
dirs_to_remove = [d for d in dirs if fnmatch.fnmatch(d, ignore_)]
|
| 342 |
+
|
| 343 |
+
# dirs need to be edited in-place
|
| 344 |
+
for d in dirs_to_remove:
|
| 345 |
+
dirs.remove(d)
|
| 346 |
+
|
| 347 |
+
files = [f for f in files if not fnmatch.fnmatch(f, ignore_)]
|
| 348 |
+
|
| 349 |
+
absolute_paths = [os.path.join(root, f) for f in files]
|
| 350 |
+
relative_paths = [os.path.relpath(p, dir_path) for p in absolute_paths]
|
| 351 |
+
|
| 352 |
+
if add_base_to_relative:
|
| 353 |
+
relative_paths = [os.path.join(base_name, p) for p in relative_paths]
|
| 354 |
+
|
| 355 |
+
assert len(absolute_paths) == len(relative_paths)
|
| 356 |
+
result += zip(absolute_paths, relative_paths)
|
| 357 |
+
|
| 358 |
+
return result
|
| 359 |
+
|
| 360 |
+
|
| 361 |
+
def copy_files_and_create_dirs(files: List[Tuple[str, str]]) -> None:
|
| 362 |
+
"""Takes in a list of tuples of (src, dst) paths and copies files.
|
| 363 |
+
Will create all necessary directories."""
|
| 364 |
+
for file in files:
|
| 365 |
+
target_dir_name = os.path.dirname(file[1])
|
| 366 |
+
|
| 367 |
+
# will create all intermediate-level directories
|
| 368 |
+
if not os.path.exists(target_dir_name):
|
| 369 |
+
os.makedirs(target_dir_name)
|
| 370 |
+
|
| 371 |
+
shutil.copyfile(file[0], file[1])
|
| 372 |
+
|
| 373 |
+
|
| 374 |
+
# URL helpers
|
| 375 |
+
# ------------------------------------------------------------------------------------------
|
| 376 |
+
|
| 377 |
+
def is_url(obj: Any, allow_file_urls: bool = False) -> bool:
|
| 378 |
+
"""Determine whether the given object is a valid URL string."""
|
| 379 |
+
if not isinstance(obj, str) or not "://" in obj:
|
| 380 |
+
return False
|
| 381 |
+
if allow_file_urls and obj.startswith('file://'):
|
| 382 |
+
return True
|
| 383 |
+
try:
|
| 384 |
+
res = requests.compat.urlparse(obj)
|
| 385 |
+
if not res.scheme or not res.netloc or not "." in res.netloc:
|
| 386 |
+
return False
|
| 387 |
+
res = requests.compat.urlparse(requests.compat.urljoin(obj, "/"))
|
| 388 |
+
if not res.scheme or not res.netloc or not "." in res.netloc:
|
| 389 |
+
return False
|
| 390 |
+
except:
|
| 391 |
+
return False
|
| 392 |
+
return True
|
| 393 |
+
|
| 394 |
+
|
| 395 |
+
def open_url(url: str, cache_dir: str = None, num_attempts: int = 10, verbose: bool = True, return_filename: bool = False, cache: bool = True) -> Any:
|
| 396 |
+
"""Download the given URL and return a binary-mode file object to access the data."""
|
| 397 |
+
assert num_attempts >= 1
|
| 398 |
+
assert not (return_filename and (not cache))
|
| 399 |
+
|
| 400 |
+
# Doesn't look like an URL scheme so interpret it as a local filename.
|
| 401 |
+
if not re.match('^[a-z]+://', url):
|
| 402 |
+
return url if return_filename else open(url, "rb")
|
| 403 |
+
|
| 404 |
+
# Handle file URLs. This code handles unusual file:// patterns that
|
| 405 |
+
# arise on Windows:
|
| 406 |
+
#
|
| 407 |
+
# file:///c:/foo.txt
|
| 408 |
+
#
|
| 409 |
+
# which would translate to a local '/c:/foo.txt' filename that's
|
| 410 |
+
# invalid. Drop the forward slash for such pathnames.
|
| 411 |
+
#
|
| 412 |
+
# If you touch this code path, you should test it on both Linux and
|
| 413 |
+
# Windows.
|
| 414 |
+
#
|
| 415 |
+
# Some internet resources suggest using urllib.request.url2pathname() but
|
| 416 |
+
# but that converts forward slashes to backslashes and this causes
|
| 417 |
+
# its own set of problems.
|
| 418 |
+
if url.startswith('file://'):
|
| 419 |
+
filename = urllib.parse.urlparse(url).path
|
| 420 |
+
if re.match(r'^/[a-zA-Z]:', filename):
|
| 421 |
+
filename = filename[1:]
|
| 422 |
+
return filename if return_filename else open(filename, "rb")
|
| 423 |
+
|
| 424 |
+
assert is_url(url)
|
| 425 |
+
|
| 426 |
+
# Lookup from cache.
|
| 427 |
+
if cache_dir is None:
|
| 428 |
+
cache_dir = make_cache_dir_path('downloads')
|
| 429 |
+
|
| 430 |
+
url_md5 = hashlib.md5(url.encode("utf-8")).hexdigest()
|
| 431 |
+
if cache:
|
| 432 |
+
cache_files = glob.glob(os.path.join(cache_dir, url_md5 + "_*"))
|
| 433 |
+
if len(cache_files) == 1:
|
| 434 |
+
filename = cache_files[0]
|
| 435 |
+
return filename if return_filename else open(filename, "rb")
|
| 436 |
+
|
| 437 |
+
# Download.
|
| 438 |
+
url_name = None
|
| 439 |
+
url_data = None
|
| 440 |
+
with requests.Session() as session:
|
| 441 |
+
if verbose:
|
| 442 |
+
print("Downloading %s ..." % url, end="", flush=True)
|
| 443 |
+
for attempts_left in reversed(range(num_attempts)):
|
| 444 |
+
try:
|
| 445 |
+
with session.get(url) as res:
|
| 446 |
+
res.raise_for_status()
|
| 447 |
+
if len(res.content) == 0:
|
| 448 |
+
raise IOError("No data received")
|
| 449 |
+
|
| 450 |
+
if len(res.content) < 8192:
|
| 451 |
+
content_str = res.content.decode("utf-8")
|
| 452 |
+
if "download_warning" in res.headers.get("Set-Cookie", ""):
|
| 453 |
+
links = [html.unescape(link) for link in content_str.split('"') if "export=download" in link]
|
| 454 |
+
if len(links) == 1:
|
| 455 |
+
url = requests.compat.urljoin(url, links[0])
|
| 456 |
+
raise IOError("Google Drive virus checker nag")
|
| 457 |
+
if "Google Drive - Quota exceeded" in content_str:
|
| 458 |
+
raise IOError("Google Drive download quota exceeded -- please try again later")
|
| 459 |
+
|
| 460 |
+
match = re.search(r'filename="([^"]*)"', res.headers.get("Content-Disposition", ""))
|
| 461 |
+
url_name = match[1] if match else url
|
| 462 |
+
url_data = res.content
|
| 463 |
+
if verbose:
|
| 464 |
+
print(" done")
|
| 465 |
+
break
|
| 466 |
+
except KeyboardInterrupt:
|
| 467 |
+
raise
|
| 468 |
+
except:
|
| 469 |
+
if not attempts_left:
|
| 470 |
+
if verbose:
|
| 471 |
+
print(" failed")
|
| 472 |
+
raise
|
| 473 |
+
if verbose:
|
| 474 |
+
print(".", end="", flush=True)
|
| 475 |
+
|
| 476 |
+
# Save to cache.
|
| 477 |
+
if cache:
|
| 478 |
+
safe_name = re.sub(r"[^0-9a-zA-Z-._]", "_", url_name)
|
| 479 |
+
safe_name = safe_name[:min(len(safe_name), 128)]
|
| 480 |
+
cache_file = os.path.join(cache_dir, url_md5 + "_" + safe_name)
|
| 481 |
+
temp_file = os.path.join(cache_dir, "tmp_" + uuid.uuid4().hex + "_" + url_md5 + "_" + safe_name)
|
| 482 |
+
os.makedirs(cache_dir, exist_ok=True)
|
| 483 |
+
with open(temp_file, "wb") as f:
|
| 484 |
+
f.write(url_data)
|
| 485 |
+
os.replace(temp_file, cache_file) # atomic
|
| 486 |
+
if return_filename:
|
| 487 |
+
return cache_file
|
| 488 |
+
|
| 489 |
+
# Return data as file object.
|
| 490 |
+
assert not return_filename
|
| 491 |
+
return io.BytesIO(url_data)
|
evaluate.py
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Pure evaluation: no optimizers, training steps, or EMA updates."""
|
| 2 |
+
import argparse
|
| 3 |
+
import json
|
| 4 |
+
import hashlib
|
| 5 |
+
import os
|
| 6 |
+
from pathlib import Path
|
| 7 |
+
import subprocess
|
| 8 |
+
import sys
|
| 9 |
+
import numpy as np
|
| 10 |
+
import torch
|
| 11 |
+
from torch.utils.data import DataLoader, Subset
|
| 12 |
+
from torchvision.utils import save_image
|
| 13 |
+
from tqdm import tqdm
|
| 14 |
+
from dataset import ImageFolderDataset
|
| 15 |
+
from omegaconf import OmegaConf
|
| 16 |
+
import torch.nn.functional as F
|
| 17 |
+
from models import Encoder, Decoder, ARModel
|
| 18 |
+
from train import (seed_everything, patchify, img_unint8_to_norm, DiTiScheduler,
|
| 19 |
+
reconstruction, sampling, euler_recon_loop, euler_sample_loop,
|
| 20 |
+
img_norm_to_uint8, unpatchify)
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def state_dict(state):
|
| 24 |
+
return {k.removeprefix('_orig_mod.'): v for k, v in state.items()}
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def load_models(config, checkpoint, device='cuda', ema=True, need_ar=True):
|
| 28 |
+
state = torch.load(checkpoint, map_location='cpu', weights_only=True, mmap=True)
|
| 29 |
+
enc, dec = Encoder(config), Decoder(config)
|
| 30 |
+
enc.load_state_dict(state_dict(state['enc']), strict=True)
|
| 31 |
+
dec.load_state_dict(state_dict(state['dec']), strict=True)
|
| 32 |
+
ar = None
|
| 33 |
+
if need_ar:
|
| 34 |
+
ar = ARModel(config)
|
| 35 |
+
key = 'ar_model_ema' if ema else 'ar_model'
|
| 36 |
+
if state.get(key) is None:
|
| 37 |
+
raise ValueError(f'Checkpoint has no {key}; select a matching AR checkpoint')
|
| 38 |
+
ar.load_state_dict(state_dict(state[key]), strict=True)
|
| 39 |
+
for model in (enc, dec, ar):
|
| 40 |
+
if model is not None:
|
| 41 |
+
model.to(device).eval().requires_grad_(False)
|
| 42 |
+
return enc, dec, ar
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
def scheduler(config):
|
| 46 |
+
if config.get('time_stages') and config.get('k_per_stage'):
|
| 47 |
+
return DiTiScheduler(1000, config.z_len, config.time_stages,
|
| 48 |
+
config.k_per_stage, config.reverse_t)
|
| 49 |
+
return None
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
def labels_for(config, batch_size, device):
|
| 53 |
+
if config.use_label:
|
| 54 |
+
raise ValueError('The released CIFAR-10 protocols are unconditional')
|
| 55 |
+
return F.one_hot(torch.full((batch_size,), config.num_classes-1,
|
| 56 |
+
device=device, dtype=torch.long), config.num_classes).float()
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
@torch.no_grad()
|
| 60 |
+
def decode_batch(config, enc, dec, ar, x, labels, mode, diti=None):
|
| 61 |
+
"""x is a patchified batch; its shape also defines unconditional generation."""
|
| 62 |
+
t = torch.ones(x.shape[0], device=x.device) if config.use_noise_query else None
|
| 63 |
+
# wARTok draws reconstruction noise before the generation branch, even for AR-only eval.
|
| 64 |
+
noise_recon = torch.randn_like(x) if config.use_noise_query else None
|
| 65 |
+
if mode == 'reconstruct':
|
| 66 |
+
if config.use_noise_query and config.diffusion_decoder:
|
| 67 |
+
result, _ = euler_recon_loop(enc, dec, x, labels, config=config, diti_scheduler=diti)
|
| 68 |
+
else:
|
| 69 |
+
result, _ = reconstruction(enc, dec, x, labels, query_tokens=noise_recon, t=t)
|
| 70 |
+
if config.l2_v_target:
|
| 71 |
+
result = noise_recon - result
|
| 72 |
+
elif mode == 'generate':
|
| 73 |
+
kwargs = dict(bz=x.shape[0], class_label=labels, temperature=config.temperature,
|
| 74 |
+
topK=config.topK, topP=config.topP, cfg=config.cfg,
|
| 75 |
+
cfg_schedule=config.cfg_schedule, cfg_power=config.cfg_power,
|
| 76 |
+
cache_kv=config.cache_kv, config=config)
|
| 77 |
+
if config.use_noise_query and config.diffusion_decoder:
|
| 78 |
+
result = euler_sample_loop(enc, dec, ar, **kwargs, diti_scheduler=diti)
|
| 79 |
+
else:
|
| 80 |
+
noise = torch.randn_like(x) if config.use_noise_query else None
|
| 81 |
+
result = sampling(enc, dec, ar, **kwargs, t=t, query_tokens=noise)
|
| 82 |
+
if config.l2_v_target:
|
| 83 |
+
result = noise - result
|
| 84 |
+
else:
|
| 85 |
+
raise ValueError(mode)
|
| 86 |
+
return img_norm_to_uint8(unpatchify(result, config.image_size, config.patch_size))
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
def build_parser():
|
| 90 |
+
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
| 91 |
+
parser.add_argument('--config', required=True)
|
| 92 |
+
parser.add_argument('--checkpoint', required=True)
|
| 93 |
+
parser.add_argument('--mode', choices=['generate', 'reconstruct'], default='generate')
|
| 94 |
+
parser.add_argument('--data', help='Required for reconstruction; use the CIFAR-10 training split')
|
| 95 |
+
parser.add_argument('--output', required=True)
|
| 96 |
+
parser.add_argument('--num-samples', type=int, default=50000)
|
| 97 |
+
parser.add_argument('--batch-size', type=int, default=64, help='Per process batch size (original evaluation: 64)')
|
| 98 |
+
parser.add_argument('--seed', type=int, default=42)
|
| 99 |
+
parser.add_argument('--legacy', action=argparse.BooleanOptionalAction, default=True,
|
| 100 |
+
help='Use the same seed on every rank (wARTok behavior); --no-legacy uses seed + rank')
|
| 101 |
+
parser.add_argument('--device', default='cuda')
|
| 102 |
+
parser.add_argument('--no-ema', action='store_true')
|
| 103 |
+
parser.add_argument('--fid-reference')
|
| 104 |
+
return parser
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
def main():
|
| 108 |
+
parser = build_parser()
|
| 109 |
+
args = parser.parse_args()
|
| 110 |
+
if args.num_samples < 1 or args.batch_size < 1:
|
| 111 |
+
parser.error('sample count and batch size must be positive')
|
| 112 |
+
world = int(os.environ.get('WORLD_SIZE', 1)); rank = int(os.environ.get('RANK', 0))
|
| 113 |
+
if world > 1:
|
| 114 |
+
if args.device != 'cuda': parser.error('distributed evaluation requires CUDA')
|
| 115 |
+
torch.cuda.set_device(int(os.environ['LOCAL_RANK']))
|
| 116 |
+
# Ranks exchange files, not CUDA tensors; CPU barriers avoid requiring GPU P2P.
|
| 117 |
+
torch.distributed.init_process_group('gloo')
|
| 118 |
+
c = OmegaConf.load(args.config)
|
| 119 |
+
torch.backends.cuda.matmul.allow_tf32 = bool(c.use_tf32)
|
| 120 |
+
torch.backends.cudnn.allow_tf32 = bool(c.use_tf32)
|
| 121 |
+
seed_everything(args.seed)
|
| 122 |
+
enc, dec, ar = load_models(c, args.checkpoint, args.device, not args.no_ema,
|
| 123 |
+
args.mode == 'generate')
|
| 124 |
+
diti = scheduler(c)
|
| 125 |
+
# Strided partition, without DistributedSampler padding: exactly N images globally.
|
| 126 |
+
indices = list(range(rank, args.num_samples, world))
|
| 127 |
+
loader = None
|
| 128 |
+
if args.mode == 'reconstruct':
|
| 129 |
+
if not args.data: parser.error('--data is required for reconstruction')
|
| 130 |
+
dataset = ImageFolderDataset(path=args.data, resolution=c.image_size,
|
| 131 |
+
use_label=False, xflip=False, crop_type=c.eval_crop_type)
|
| 132 |
+
if args.num_samples > len(dataset): parser.error('num-samples exceeds dataset size')
|
| 133 |
+
loader = iter(DataLoader(Subset(dataset, indices), batch_size=args.batch_size, shuffle=False))
|
| 134 |
+
# A fixed evaluation seed is explicit; historical training-loop RNG was not checkpointed.
|
| 135 |
+
seed_everything(args.seed + (0 if args.legacy else rank))
|
| 136 |
+
samples = []
|
| 137 |
+
with torch.inference_mode():
|
| 138 |
+
for start in tqdm(range(0, len(indices), args.batch_size), desc=args.mode, disable=rank != 0):
|
| 139 |
+
n = min(args.batch_size, len(indices)-start)
|
| 140 |
+
if loader is None:
|
| 141 |
+
x = torch.empty(n, c.x_len, c.patch_dim, device=args.device)
|
| 142 |
+
else:
|
| 143 |
+
images, _ = next(loader)
|
| 144 |
+
x = patchify(img_unint8_to_norm(images.to(args.device)), c.patch_size)
|
| 145 |
+
labels = labels_for(c, n, args.device)
|
| 146 |
+
images = decode_batch(c, enc, dec, ar, x, labels, args.mode, diti)
|
| 147 |
+
samples.append(images.permute(0,2,3,1).cpu().numpy())
|
| 148 |
+
arr = np.concatenate(samples) if samples else np.empty((0,c.image_size,c.image_size,3),dtype=np.uint8)
|
| 149 |
+
out = Path(args.output); out.mkdir(parents=True, exist_ok=True)
|
| 150 |
+
if world > 1:
|
| 151 |
+
np.savez(out/f'rank-{rank}.npz', images=arr, indices=np.asarray(indices))
|
| 152 |
+
torch.distributed.barrier()
|
| 153 |
+
if rank == 0:
|
| 154 |
+
if world > 1:
|
| 155 |
+
arr = np.empty((args.num_samples,c.image_size,c.image_size,3),dtype=np.uint8)
|
| 156 |
+
for r in range(world):
|
| 157 |
+
with np.load(out/f'rank-{r}.npz') as shard: arr[shard['indices']]=shard['images']
|
| 158 |
+
assert len(arr) == args.num_samples
|
| 159 |
+
path = out/'samples.npz'; np.savez_compressed(path, arr)
|
| 160 |
+
save_image(torch.from_numpy(arr[:64]).permute(0,3,1,2).float()/255, out/'preview.png',nrow=8)
|
| 161 |
+
report = dict(mode=args.mode, num_samples=len(arr),
|
| 162 |
+
unique_images=len({hashlib.sha256(im.tobytes()).digest() for im in arr}), seed=args.seed,
|
| 163 |
+
world_size=world, batch_size=args.batch_size, legacy=args.legacy, rank_seed_mode='shared' if args.legacy else 'independent', config=args.config,
|
| 164 |
+
checkpoint=args.checkpoint, ar_ema=(not args.no_ema) if args.mode == 'generate' else None,
|
| 165 |
+
decoder='euler25' if c.use_noise_query and c.diffusion_decoder else 'single_step',
|
| 166 |
+
precision='32-true', fid=None, torch_version=torch.__version__,
|
| 167 |
+
config_sha256=hashlib.sha256(Path(args.config).read_bytes()).hexdigest())
|
| 168 |
+
if args.fid_reference:
|
| 169 |
+
report['reference_sha256']=hashlib.sha256(Path(args.fid_reference).read_bytes()).hexdigest()
|
| 170 |
+
result = subprocess.run([sys.executable, str(Path(__file__).with_name('calc_fid.py')),
|
| 171 |
+
'--ref_batch', args.fid_reference, '--sample_batch', str(path), '--batch_size','64'],
|
| 172 |
+
text=True, check=True, stdout=subprocess.PIPE)
|
| 173 |
+
print(result.stdout)
|
| 174 |
+
report['fid']=float(next(line.split(':',1)[1] for line in result.stdout.splitlines() if line.startswith('FID_RESULT:')))
|
| 175 |
+
(out/'metrics.json').write_text(json.dumps(report,indent=2)+'\n')
|
| 176 |
+
print(json.dumps(report, indent=2))
|
| 177 |
+
if world > 1:
|
| 178 |
+
torch.distributed.barrier(); torch.distributed.destroy_process_group()
|
| 179 |
+
|
| 180 |
+
|
| 181 |
+
if __name__ == '__main__': main()
|
evaluator.py
ADDED
|
@@ -0,0 +1,675 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import argparse
|
| 2 |
+
import io
|
| 3 |
+
import os
|
| 4 |
+
import random
|
| 5 |
+
import warnings
|
| 6 |
+
import zipfile
|
| 7 |
+
from abc import ABC, abstractmethod
|
| 8 |
+
from contextlib import contextmanager
|
| 9 |
+
from functools import partial
|
| 10 |
+
from multiprocessing import cpu_count
|
| 11 |
+
from multiprocessing.pool import ThreadPool
|
| 12 |
+
from typing import Iterable, Optional, Tuple, Union
|
| 13 |
+
|
| 14 |
+
import numpy as np
|
| 15 |
+
import requests
|
| 16 |
+
import tensorflow.compat.v1 as tf
|
| 17 |
+
from scipy import linalg
|
| 18 |
+
from tqdm.auto import tqdm
|
| 19 |
+
|
| 20 |
+
INCEPTION_V3_URL = "https://openaipublic.blob.core.windows.net/diffusion/jul-2021/ref_batches/classify_image_graph_def.pb"
|
| 21 |
+
INCEPTION_V3_PATH = "classify_image_graph_def.pb"
|
| 22 |
+
|
| 23 |
+
FID_POOL_NAME = "pool_3:0"
|
| 24 |
+
FID_SPATIAL_NAME = "mixed_6/conv:0"
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def main():
|
| 28 |
+
parser = argparse.ArgumentParser()
|
| 29 |
+
parser.add_argument("ref_batch", help="path to reference batch npz file")
|
| 30 |
+
parser.add_argument("sample_batch", help="path to sample batch npz file")
|
| 31 |
+
args = parser.parse_args()
|
| 32 |
+
|
| 33 |
+
config = tf.ConfigProto(
|
| 34 |
+
allow_soft_placement=True # allows DecodeJpeg to run on CPU in Inception graph
|
| 35 |
+
)
|
| 36 |
+
config.gpu_options.allow_growth = True
|
| 37 |
+
evaluator = Evaluator(tf.Session(config=config))
|
| 38 |
+
|
| 39 |
+
print("warming up TensorFlow...")
|
| 40 |
+
# This will cause TF to print a bunch of verbose stuff now rather
|
| 41 |
+
# than after the next print(), to help prevent confusion.
|
| 42 |
+
evaluator.warmup()
|
| 43 |
+
|
| 44 |
+
print("computing reference batch activations...")
|
| 45 |
+
ref_acts = evaluator.read_activations(args.ref_batch)
|
| 46 |
+
print("computing/reading reference batch statistics...")
|
| 47 |
+
ref_stats, ref_stats_spatial = evaluator.read_statistics(args.ref_batch, ref_acts)
|
| 48 |
+
|
| 49 |
+
print("computing sample batch activations...")
|
| 50 |
+
sample_acts = evaluator.read_activations(args.sample_batch)
|
| 51 |
+
print("computing/reading sample batch statistics...")
|
| 52 |
+
sample_stats, sample_stats_spatial = evaluator.read_statistics(args.sample_batch, sample_acts)
|
| 53 |
+
|
| 54 |
+
print("Computing evaluations...")
|
| 55 |
+
print("Inception Score:", evaluator.compute_inception_score(sample_acts[0]))
|
| 56 |
+
print("FID:", sample_stats.frechet_distance(ref_stats))
|
| 57 |
+
print("sFID:", sample_stats_spatial.frechet_distance(ref_stats_spatial))
|
| 58 |
+
prec, recall = evaluator.compute_prec_recall(ref_acts[0], sample_acts[0])
|
| 59 |
+
print("Precision:", prec)
|
| 60 |
+
print("Recall:", recall)
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
class InvalidFIDException(Exception):
|
| 64 |
+
pass
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
class FIDStatistics:
|
| 68 |
+
def __init__(self, mu: np.ndarray, sigma: np.ndarray):
|
| 69 |
+
self.mu = mu
|
| 70 |
+
self.sigma = sigma
|
| 71 |
+
|
| 72 |
+
def frechet_distance(self, other, eps=1e-6):
|
| 73 |
+
"""
|
| 74 |
+
Compute the Frechet distance between two sets of statistics.
|
| 75 |
+
"""
|
| 76 |
+
# https://github.com/bioinf-jku/TTUR/blob/73ab375cdf952a12686d9aa7978567771084da42/fid.py#L132
|
| 77 |
+
mu1, sigma1 = self.mu, self.sigma
|
| 78 |
+
mu2, sigma2 = other.mu, other.sigma
|
| 79 |
+
|
| 80 |
+
mu1 = np.atleast_1d(mu1)
|
| 81 |
+
mu2 = np.atleast_1d(mu2)
|
| 82 |
+
|
| 83 |
+
sigma1 = np.atleast_2d(sigma1)
|
| 84 |
+
sigma2 = np.atleast_2d(sigma2)
|
| 85 |
+
|
| 86 |
+
assert (
|
| 87 |
+
mu1.shape == mu2.shape
|
| 88 |
+
), f"Training and test mean vectors have different lengths: {mu1.shape}, {mu2.shape}"
|
| 89 |
+
assert (
|
| 90 |
+
sigma1.shape == sigma2.shape
|
| 91 |
+
), f"Training and test covariances have different dimensions: {sigma1.shape}, {sigma2.shape}"
|
| 92 |
+
|
| 93 |
+
diff = mu1 - mu2
|
| 94 |
+
|
| 95 |
+
# product might be almost singular
|
| 96 |
+
covmean, _ = linalg.sqrtm(sigma1.dot(sigma2), disp=False)
|
| 97 |
+
if not np.isfinite(covmean).all():
|
| 98 |
+
msg = (
|
| 99 |
+
"fid calculation produces singular product; adding %s to diagonal of cov estimates"
|
| 100 |
+
% eps
|
| 101 |
+
)
|
| 102 |
+
warnings.warn(msg)
|
| 103 |
+
offset = np.eye(sigma1.shape[0]) * eps
|
| 104 |
+
covmean = linalg.sqrtm((sigma1 + offset).dot(sigma2 + offset))
|
| 105 |
+
|
| 106 |
+
# numerical error might give slight imaginary component
|
| 107 |
+
if np.iscomplexobj(covmean):
|
| 108 |
+
if not np.allclose(np.diagonal(covmean).imag, 0, atol=1e-3):
|
| 109 |
+
m = np.max(np.abs(covmean.imag))
|
| 110 |
+
raise ValueError("Imaginary component {}".format(m))
|
| 111 |
+
covmean = covmean.real
|
| 112 |
+
|
| 113 |
+
tr_covmean = np.trace(covmean)
|
| 114 |
+
|
| 115 |
+
return diff.dot(diff) + np.trace(sigma1) + np.trace(sigma2) - 2 * tr_covmean
|
| 116 |
+
|
| 117 |
+
|
| 118 |
+
class Evaluator:
|
| 119 |
+
def __init__(
|
| 120 |
+
self,
|
| 121 |
+
session,
|
| 122 |
+
batch_size=64,
|
| 123 |
+
softmax_batch_size=512,
|
| 124 |
+
):
|
| 125 |
+
self.sess = session
|
| 126 |
+
self.batch_size = batch_size
|
| 127 |
+
self.softmax_batch_size = softmax_batch_size
|
| 128 |
+
self.manifold_estimator = ManifoldEstimator(session)
|
| 129 |
+
with self.sess.graph.as_default():
|
| 130 |
+
self.image_input = tf.placeholder(tf.float32, shape=[None, None, None, 3])
|
| 131 |
+
self.softmax_input = tf.placeholder(tf.float32, shape=[None, 2048])
|
| 132 |
+
self.pool_features, self.spatial_features = _create_feature_graph(self.image_input)
|
| 133 |
+
self.softmax = _create_softmax_graph(self.softmax_input)
|
| 134 |
+
|
| 135 |
+
def warmup(self):
|
| 136 |
+
self.compute_activations(np.zeros([1, 8, 64, 64, 3]))
|
| 137 |
+
|
| 138 |
+
def read_activations(self, npz_path: Union[str, np.ndarray]) -> Tuple[np.ndarray, np.ndarray]:
|
| 139 |
+
if isinstance(npz_path, str):
|
| 140 |
+
# Archives contain either images (arr_0) or precomputed FID statistics.
|
| 141 |
+
with np.load(npz_path) as obj:
|
| 142 |
+
keys = set(obj.files)
|
| 143 |
+
|
| 144 |
+
# Statistics-only archives do not require feature extraction.
|
| 145 |
+
if "mu" in keys and "sigma" in keys and "arr_0" not in keys:
|
| 146 |
+
dummy = np.zeros((0, 1), dtype=np.float32)
|
| 147 |
+
return dummy, dummy
|
| 148 |
+
|
| 149 |
+
# Image archives store the image batch in arr_0.
|
| 150 |
+
with open_npz_array(npz_path, "arr_0") as reader:
|
| 151 |
+
return self.compute_activations(reader.read_batches(self.batch_size))
|
| 152 |
+
elif isinstance(npz_path, np.ndarray):
|
| 153 |
+
# If npz_path is a numpy array, split it into batches manually
|
| 154 |
+
batches = np.array_split(npz_path, range(self.batch_size, npz_path.shape[0], self.batch_size))
|
| 155 |
+
return self.compute_activations(batches)
|
| 156 |
+
else:
|
| 157 |
+
raise ValueError("npz_path must be either a file path (str) or a numpy array (np.ndarray)")
|
| 158 |
+
|
| 159 |
+
|
| 160 |
+
def compute_activations(self, batches: Iterable[np.ndarray]) -> Tuple[np.ndarray, np.ndarray]:
|
| 161 |
+
"""
|
| 162 |
+
Compute image features for downstream evals.
|
| 163 |
+
|
| 164 |
+
:param batches: a iterator over NHWC numpy arrays in [0, 255].
|
| 165 |
+
:return: a tuple of numpy arrays of shape [N x X], where X is a feature
|
| 166 |
+
dimension. The tuple is (pool_3, spatial).
|
| 167 |
+
"""
|
| 168 |
+
preds = []
|
| 169 |
+
spatial_preds = []
|
| 170 |
+
for batch in tqdm(batches):
|
| 171 |
+
batch = batch.astype(np.float32)
|
| 172 |
+
pred, spatial_pred = self.sess.run(
|
| 173 |
+
[self.pool_features, self.spatial_features], {self.image_input: batch}
|
| 174 |
+
)
|
| 175 |
+
preds.append(pred.reshape([pred.shape[0], -1]))
|
| 176 |
+
spatial_preds.append(spatial_pred.reshape([spatial_pred.shape[0], -1]))
|
| 177 |
+
return (
|
| 178 |
+
np.concatenate(preds, axis=0),
|
| 179 |
+
np.concatenate(spatial_preds, axis=0),
|
| 180 |
+
)
|
| 181 |
+
|
| 182 |
+
def read_statistics(
|
| 183 |
+
self, npz_path: Union[str, np.ndarray], activations: Tuple[np.ndarray, np.ndarray]
|
| 184 |
+
) -> Tuple[FIDStatistics, FIDStatistics]:
|
| 185 |
+
if isinstance(npz_path, str):
|
| 186 |
+
obj = np.load(npz_path)
|
| 187 |
+
if "mu" in list(obj.keys()):
|
| 188 |
+
return FIDStatistics(obj["mu"], obj["sigma"]), FIDStatistics(
|
| 189 |
+
obj["mu_s"], obj["sigma_s"]
|
| 190 |
+
)
|
| 191 |
+
elif isinstance(npz_path, np.ndarray):
|
| 192 |
+
obj = npz_path
|
| 193 |
+
else:
|
| 194 |
+
raise ValueError("npz_path must be either a file path (str) or a numpy array (np.ndarray)")
|
| 195 |
+
return tuple(self.compute_statistics(x) for x in activations)
|
| 196 |
+
|
| 197 |
+
def compute_statistics(self, activations: np.ndarray) -> FIDStatistics:
|
| 198 |
+
mu = np.mean(activations, axis=0)
|
| 199 |
+
sigma = np.cov(activations, rowvar=False)
|
| 200 |
+
return FIDStatistics(mu, sigma)
|
| 201 |
+
|
| 202 |
+
def compute_inception_score(self, activations: np.ndarray, split_size: int = 5000) -> float:
|
| 203 |
+
softmax_out = []
|
| 204 |
+
for i in range(0, len(activations), self.softmax_batch_size):
|
| 205 |
+
acts = activations[i : i + self.softmax_batch_size]
|
| 206 |
+
softmax_out.append(self.sess.run(self.softmax, feed_dict={self.softmax_input: acts}))
|
| 207 |
+
preds = np.concatenate(softmax_out, axis=0)
|
| 208 |
+
# https://github.com/openai/improved-gan/blob/4f5d1ec5c16a7eceb206f42bfc652693601e1d5c/inception_score/model.py#L46
|
| 209 |
+
scores = []
|
| 210 |
+
for i in range(0, len(preds), split_size):
|
| 211 |
+
part = preds[i : i + split_size]
|
| 212 |
+
kl = part * (np.log(part) - np.log(np.expand_dims(np.mean(part, 0), 0)))
|
| 213 |
+
kl = np.mean(np.sum(kl, 1))
|
| 214 |
+
scores.append(np.exp(kl))
|
| 215 |
+
return float(np.mean(scores))
|
| 216 |
+
|
| 217 |
+
def compute_prec_recall(
|
| 218 |
+
self, activations_ref: np.ndarray, activations_sample: np.ndarray
|
| 219 |
+
) -> Tuple[float, float]:
|
| 220 |
+
radii_1 = self.manifold_estimator.manifold_radii(activations_ref)
|
| 221 |
+
radii_2 = self.manifold_estimator.manifold_radii(activations_sample)
|
| 222 |
+
pr = self.manifold_estimator.evaluate_pr(
|
| 223 |
+
activations_ref, radii_1, activations_sample, radii_2
|
| 224 |
+
)
|
| 225 |
+
return (float(pr[0][0]), float(pr[1][0]))
|
| 226 |
+
|
| 227 |
+
|
| 228 |
+
class ManifoldEstimator:
|
| 229 |
+
"""
|
| 230 |
+
A helper for comparing manifolds of feature vectors.
|
| 231 |
+
|
| 232 |
+
Adapted from https://github.com/kynkaat/improved-precision-and-recall-metric/blob/f60f25e5ad933a79135c783fcda53de30f42c9b9/precision_recall.py#L57
|
| 233 |
+
"""
|
| 234 |
+
|
| 235 |
+
def __init__(
|
| 236 |
+
self,
|
| 237 |
+
session,
|
| 238 |
+
row_batch_size=10000,
|
| 239 |
+
col_batch_size=10000,
|
| 240 |
+
nhood_sizes=(3,),
|
| 241 |
+
clamp_to_percentile=None,
|
| 242 |
+
eps=1e-5,
|
| 243 |
+
):
|
| 244 |
+
"""
|
| 245 |
+
Estimate the manifold of given feature vectors.
|
| 246 |
+
|
| 247 |
+
:param session: the TensorFlow session.
|
| 248 |
+
:param row_batch_size: row batch size to compute pairwise distances
|
| 249 |
+
(parameter to trade-off between memory usage and performance).
|
| 250 |
+
:param col_batch_size: column batch size to compute pairwise distances.
|
| 251 |
+
:param nhood_sizes: number of neighbors used to estimate the manifold.
|
| 252 |
+
:param clamp_to_percentile: prune hyperspheres that have radius larger than
|
| 253 |
+
the given percentile.
|
| 254 |
+
:param eps: small number for numerical stability.
|
| 255 |
+
"""
|
| 256 |
+
self.distance_block = DistanceBlock(session)
|
| 257 |
+
self.row_batch_size = row_batch_size
|
| 258 |
+
self.col_batch_size = col_batch_size
|
| 259 |
+
self.nhood_sizes = nhood_sizes
|
| 260 |
+
self.num_nhoods = len(nhood_sizes)
|
| 261 |
+
self.clamp_to_percentile = clamp_to_percentile
|
| 262 |
+
self.eps = eps
|
| 263 |
+
|
| 264 |
+
def warmup(self):
|
| 265 |
+
feats, radii = (
|
| 266 |
+
np.zeros([1, 2048], dtype=np.float32),
|
| 267 |
+
np.zeros([1, 1], dtype=np.float32),
|
| 268 |
+
)
|
| 269 |
+
self.evaluate_pr(feats, radii, feats, radii)
|
| 270 |
+
|
| 271 |
+
def manifold_radii(self, features: np.ndarray) -> np.ndarray:
|
| 272 |
+
num_images = len(features)
|
| 273 |
+
|
| 274 |
+
# Estimate manifold of features by calculating distances to k-NN of each sample.
|
| 275 |
+
radii = np.zeros([num_images, self.num_nhoods], dtype=np.float32)
|
| 276 |
+
distance_batch = np.zeros([self.row_batch_size, num_images], dtype=np.float32)
|
| 277 |
+
seq = np.arange(max(self.nhood_sizes) + 1, dtype=np.int32)
|
| 278 |
+
|
| 279 |
+
for begin1 in range(0, num_images, self.row_batch_size):
|
| 280 |
+
end1 = min(begin1 + self.row_batch_size, num_images)
|
| 281 |
+
row_batch = features[begin1:end1]
|
| 282 |
+
|
| 283 |
+
for begin2 in range(0, num_images, self.col_batch_size):
|
| 284 |
+
end2 = min(begin2 + self.col_batch_size, num_images)
|
| 285 |
+
col_batch = features[begin2:end2]
|
| 286 |
+
|
| 287 |
+
# Compute distances between batches.
|
| 288 |
+
distance_batch[
|
| 289 |
+
0 : end1 - begin1, begin2:end2
|
| 290 |
+
] = self.distance_block.pairwise_distances(row_batch, col_batch)
|
| 291 |
+
|
| 292 |
+
# Find the k-nearest neighbor from the current batch.
|
| 293 |
+
radii[begin1:end1, :] = np.concatenate(
|
| 294 |
+
[
|
| 295 |
+
x[:, self.nhood_sizes]
|
| 296 |
+
for x in _numpy_partition(distance_batch[0 : end1 - begin1, :], seq, axis=1)
|
| 297 |
+
],
|
| 298 |
+
axis=0,
|
| 299 |
+
)
|
| 300 |
+
|
| 301 |
+
if self.clamp_to_percentile is not None:
|
| 302 |
+
max_distances = np.percentile(radii, self.clamp_to_percentile, axis=0)
|
| 303 |
+
radii[radii > max_distances] = 0
|
| 304 |
+
return radii
|
| 305 |
+
|
| 306 |
+
def evaluate(self, features: np.ndarray, radii: np.ndarray, eval_features: np.ndarray):
|
| 307 |
+
"""
|
| 308 |
+
Evaluate if new feature vectors are at the manifold.
|
| 309 |
+
"""
|
| 310 |
+
num_eval_images = eval_features.shape[0]
|
| 311 |
+
num_ref_images = radii.shape[0]
|
| 312 |
+
distance_batch = np.zeros([self.row_batch_size, num_ref_images], dtype=np.float32)
|
| 313 |
+
batch_predictions = np.zeros([num_eval_images, self.num_nhoods], dtype=np.int32)
|
| 314 |
+
max_realism_score = np.zeros([num_eval_images], dtype=np.float32)
|
| 315 |
+
nearest_indices = np.zeros([num_eval_images], dtype=np.int32)
|
| 316 |
+
|
| 317 |
+
for begin1 in range(0, num_eval_images, self.row_batch_size):
|
| 318 |
+
end1 = min(begin1 + self.row_batch_size, num_eval_images)
|
| 319 |
+
feature_batch = eval_features[begin1:end1]
|
| 320 |
+
|
| 321 |
+
for begin2 in range(0, num_ref_images, self.col_batch_size):
|
| 322 |
+
end2 = min(begin2 + self.col_batch_size, num_ref_images)
|
| 323 |
+
ref_batch = features[begin2:end2]
|
| 324 |
+
|
| 325 |
+
distance_batch[
|
| 326 |
+
0 : end1 - begin1, begin2:end2
|
| 327 |
+
] = self.distance_block.pairwise_distances(feature_batch, ref_batch)
|
| 328 |
+
|
| 329 |
+
# From the minibatch of new feature vectors, determine if they are in the estimated manifold.
|
| 330 |
+
# If a feature vector is inside a hypersphere of some reference sample, then
|
| 331 |
+
# the new sample lies at the estimated manifold.
|
| 332 |
+
# The radii of the hyperspheres are determined from distances of neighborhood size k.
|
| 333 |
+
samples_in_manifold = distance_batch[0 : end1 - begin1, :, None] <= radii
|
| 334 |
+
batch_predictions[begin1:end1] = np.any(samples_in_manifold, axis=1).astype(np.int32)
|
| 335 |
+
|
| 336 |
+
max_realism_score[begin1:end1] = np.max(
|
| 337 |
+
radii[:, 0] / (distance_batch[0 : end1 - begin1, :] + self.eps), axis=1
|
| 338 |
+
)
|
| 339 |
+
nearest_indices[begin1:end1] = np.argmin(distance_batch[0 : end1 - begin1, :], axis=1)
|
| 340 |
+
|
| 341 |
+
return {
|
| 342 |
+
"fraction": float(np.mean(batch_predictions)),
|
| 343 |
+
"batch_predictions": batch_predictions,
|
| 344 |
+
"max_realisim_score": max_realism_score,
|
| 345 |
+
"nearest_indices": nearest_indices,
|
| 346 |
+
}
|
| 347 |
+
|
| 348 |
+
def evaluate_pr(
|
| 349 |
+
self,
|
| 350 |
+
features_1: np.ndarray,
|
| 351 |
+
radii_1: np.ndarray,
|
| 352 |
+
features_2: np.ndarray,
|
| 353 |
+
radii_2: np.ndarray,
|
| 354 |
+
) -> Tuple[np.ndarray, np.ndarray]:
|
| 355 |
+
"""
|
| 356 |
+
Evaluate precision and recall efficiently.
|
| 357 |
+
|
| 358 |
+
:param features_1: [N1 x D] feature vectors for reference batch.
|
| 359 |
+
:param radii_1: [N1 x K1] radii for reference vectors.
|
| 360 |
+
:param features_2: [N2 x D] feature vectors for the other batch.
|
| 361 |
+
:param radii_2: [N x K2] radii for other vectors.
|
| 362 |
+
:return: a tuple of arrays for (precision, recall):
|
| 363 |
+
- precision: an np.ndarray of length K1
|
| 364 |
+
- recall: an np.ndarray of length K2
|
| 365 |
+
"""
|
| 366 |
+
features_1_status = np.zeros([len(features_1), radii_2.shape[1]], dtype=np.bool)
|
| 367 |
+
features_2_status = np.zeros([len(features_2), radii_1.shape[1]], dtype=np.bool)
|
| 368 |
+
for begin_1 in range(0, len(features_1), self.row_batch_size):
|
| 369 |
+
end_1 = begin_1 + self.row_batch_size
|
| 370 |
+
batch_1 = features_1[begin_1:end_1]
|
| 371 |
+
for begin_2 in range(0, len(features_2), self.col_batch_size):
|
| 372 |
+
end_2 = begin_2 + self.col_batch_size
|
| 373 |
+
batch_2 = features_2[begin_2:end_2]
|
| 374 |
+
batch_1_in, batch_2_in = self.distance_block.less_thans(
|
| 375 |
+
batch_1, radii_1[begin_1:end_1], batch_2, radii_2[begin_2:end_2]
|
| 376 |
+
)
|
| 377 |
+
features_1_status[begin_1:end_1] |= batch_1_in
|
| 378 |
+
features_2_status[begin_2:end_2] |= batch_2_in
|
| 379 |
+
return (
|
| 380 |
+
np.mean(features_2_status.astype(np.float64), axis=0),
|
| 381 |
+
np.mean(features_1_status.astype(np.float64), axis=0),
|
| 382 |
+
)
|
| 383 |
+
|
| 384 |
+
|
| 385 |
+
class DistanceBlock:
|
| 386 |
+
"""
|
| 387 |
+
Calculate pairwise distances between vectors.
|
| 388 |
+
|
| 389 |
+
Adapted from https://github.com/kynkaat/improved-precision-and-recall-metric/blob/f60f25e5ad933a79135c783fcda53de30f42c9b9/precision_recall.py#L34
|
| 390 |
+
"""
|
| 391 |
+
|
| 392 |
+
def __init__(self, session):
|
| 393 |
+
self.session = session
|
| 394 |
+
|
| 395 |
+
# Initialize TF graph to calculate pairwise distances.
|
| 396 |
+
with session.graph.as_default():
|
| 397 |
+
self._features_batch1 = tf.placeholder(tf.float32, shape=[None, None])
|
| 398 |
+
self._features_batch2 = tf.placeholder(tf.float32, shape=[None, None])
|
| 399 |
+
distance_block_16 = _batch_pairwise_distances(
|
| 400 |
+
tf.cast(self._features_batch1, tf.float16),
|
| 401 |
+
tf.cast(self._features_batch2, tf.float16),
|
| 402 |
+
)
|
| 403 |
+
self.distance_block = tf.cond(
|
| 404 |
+
tf.reduce_all(tf.math.is_finite(distance_block_16)),
|
| 405 |
+
lambda: tf.cast(distance_block_16, tf.float32),
|
| 406 |
+
lambda: _batch_pairwise_distances(self._features_batch1, self._features_batch2),
|
| 407 |
+
)
|
| 408 |
+
|
| 409 |
+
# Extra logic for less thans.
|
| 410 |
+
self._radii1 = tf.placeholder(tf.float32, shape=[None, None])
|
| 411 |
+
self._radii2 = tf.placeholder(tf.float32, shape=[None, None])
|
| 412 |
+
dist32 = tf.cast(self.distance_block, tf.float32)[..., None]
|
| 413 |
+
self._batch_1_in = tf.math.reduce_any(dist32 <= self._radii2, axis=1)
|
| 414 |
+
self._batch_2_in = tf.math.reduce_any(dist32 <= self._radii1[:, None], axis=0)
|
| 415 |
+
|
| 416 |
+
def pairwise_distances(self, U, V):
|
| 417 |
+
"""
|
| 418 |
+
Evaluate pairwise distances between two batches of feature vectors.
|
| 419 |
+
"""
|
| 420 |
+
return self.session.run(
|
| 421 |
+
self.distance_block,
|
| 422 |
+
feed_dict={self._features_batch1: U, self._features_batch2: V},
|
| 423 |
+
)
|
| 424 |
+
|
| 425 |
+
def less_thans(self, batch_1, radii_1, batch_2, radii_2):
|
| 426 |
+
return self.session.run(
|
| 427 |
+
[self._batch_1_in, self._batch_2_in],
|
| 428 |
+
feed_dict={
|
| 429 |
+
self._features_batch1: batch_1,
|
| 430 |
+
self._features_batch2: batch_2,
|
| 431 |
+
self._radii1: radii_1,
|
| 432 |
+
self._radii2: radii_2,
|
| 433 |
+
},
|
| 434 |
+
)
|
| 435 |
+
|
| 436 |
+
|
| 437 |
+
def _batch_pairwise_distances(U, V):
|
| 438 |
+
"""
|
| 439 |
+
Compute pairwise distances between two batches of feature vectors.
|
| 440 |
+
"""
|
| 441 |
+
with tf.variable_scope("pairwise_dist_block"):
|
| 442 |
+
# Squared norms of each row in U and V.
|
| 443 |
+
norm_u = tf.reduce_sum(tf.square(U), 1)
|
| 444 |
+
norm_v = tf.reduce_sum(tf.square(V), 1)
|
| 445 |
+
|
| 446 |
+
# norm_u as a column and norm_v as a row vectors.
|
| 447 |
+
norm_u = tf.reshape(norm_u, [-1, 1])
|
| 448 |
+
norm_v = tf.reshape(norm_v, [1, -1])
|
| 449 |
+
|
| 450 |
+
# Pairwise squared Euclidean distances.
|
| 451 |
+
D = tf.maximum(norm_u - 2 * tf.matmul(U, V, False, True) + norm_v, 0.0)
|
| 452 |
+
|
| 453 |
+
return D
|
| 454 |
+
|
| 455 |
+
|
| 456 |
+
class NpzArrayReader(ABC):
|
| 457 |
+
@abstractmethod
|
| 458 |
+
def read_batch(self, batch_size: int) -> Optional[np.ndarray]:
|
| 459 |
+
pass
|
| 460 |
+
|
| 461 |
+
@abstractmethod
|
| 462 |
+
def remaining(self) -> int:
|
| 463 |
+
pass
|
| 464 |
+
|
| 465 |
+
def read_batches(self, batch_size: int) -> Iterable[np.ndarray]:
|
| 466 |
+
def gen_fn():
|
| 467 |
+
while True:
|
| 468 |
+
batch = self.read_batch(batch_size)
|
| 469 |
+
if batch is None:
|
| 470 |
+
break
|
| 471 |
+
yield batch
|
| 472 |
+
|
| 473 |
+
rem = self.remaining()
|
| 474 |
+
num_batches = rem // batch_size + int(rem % batch_size != 0)
|
| 475 |
+
return BatchIterator(gen_fn, num_batches)
|
| 476 |
+
|
| 477 |
+
|
| 478 |
+
class BatchIterator:
|
| 479 |
+
def __init__(self, gen_fn, length):
|
| 480 |
+
self.gen_fn = gen_fn
|
| 481 |
+
self.length = length
|
| 482 |
+
|
| 483 |
+
def __len__(self):
|
| 484 |
+
return self.length
|
| 485 |
+
|
| 486 |
+
def __iter__(self):
|
| 487 |
+
return self.gen_fn()
|
| 488 |
+
|
| 489 |
+
|
| 490 |
+
class StreamingNpzArrayReader(NpzArrayReader):
|
| 491 |
+
def __init__(self, arr_f, shape, dtype):
|
| 492 |
+
self.arr_f = arr_f
|
| 493 |
+
self.shape = shape
|
| 494 |
+
self.dtype = dtype
|
| 495 |
+
self.idx = 0
|
| 496 |
+
|
| 497 |
+
def read_batch(self, batch_size: int) -> Optional[np.ndarray]:
|
| 498 |
+
if self.idx >= self.shape[0]:
|
| 499 |
+
return None
|
| 500 |
+
|
| 501 |
+
bs = min(batch_size, self.shape[0] - self.idx)
|
| 502 |
+
self.idx += bs
|
| 503 |
+
|
| 504 |
+
if self.dtype.itemsize == 0:
|
| 505 |
+
return np.ndarray([bs, *self.shape[1:]], dtype=self.dtype)
|
| 506 |
+
|
| 507 |
+
read_count = bs * np.prod(self.shape[1:])
|
| 508 |
+
read_size = int(read_count * self.dtype.itemsize)
|
| 509 |
+
data = _read_bytes(self.arr_f, read_size, "array data")
|
| 510 |
+
return np.frombuffer(data, dtype=self.dtype).reshape([bs, *self.shape[1:]])
|
| 511 |
+
|
| 512 |
+
def remaining(self) -> int:
|
| 513 |
+
return max(0, self.shape[0] - self.idx)
|
| 514 |
+
|
| 515 |
+
|
| 516 |
+
class MemoryNpzArrayReader(NpzArrayReader):
|
| 517 |
+
def __init__(self, arr):
|
| 518 |
+
self.arr = arr
|
| 519 |
+
self.idx = 0
|
| 520 |
+
|
| 521 |
+
@classmethod
|
| 522 |
+
def load(cls, path: str, arr_name: str):
|
| 523 |
+
with open(path, "rb") as f:
|
| 524 |
+
arr = np.load(f)[arr_name]
|
| 525 |
+
return cls(arr)
|
| 526 |
+
|
| 527 |
+
def read_batch(self, batch_size: int) -> Optional[np.ndarray]:
|
| 528 |
+
if self.idx >= self.arr.shape[0]:
|
| 529 |
+
return None
|
| 530 |
+
|
| 531 |
+
res = self.arr[self.idx : self.idx + batch_size]
|
| 532 |
+
self.idx += batch_size
|
| 533 |
+
return res
|
| 534 |
+
|
| 535 |
+
def remaining(self) -> int:
|
| 536 |
+
return max(0, self.arr.shape[0] - self.idx)
|
| 537 |
+
|
| 538 |
+
|
| 539 |
+
@contextmanager
|
| 540 |
+
def open_npz_array(path: str, arr_name: str) -> NpzArrayReader:
|
| 541 |
+
with _open_npy_file(path, arr_name) as arr_f:
|
| 542 |
+
version = np.lib.format.read_magic(arr_f)
|
| 543 |
+
if version == (1, 0):
|
| 544 |
+
header = np.lib.format.read_array_header_1_0(arr_f)
|
| 545 |
+
elif version == (2, 0):
|
| 546 |
+
header = np.lib.format.read_array_header_2_0(arr_f)
|
| 547 |
+
else:
|
| 548 |
+
yield MemoryNpzArrayReader.load(path, arr_name)
|
| 549 |
+
return
|
| 550 |
+
shape, fortran, dtype = header
|
| 551 |
+
if fortran or dtype.hasobject:
|
| 552 |
+
yield MemoryNpzArrayReader.load(path, arr_name)
|
| 553 |
+
else:
|
| 554 |
+
yield StreamingNpzArrayReader(arr_f, shape, dtype)
|
| 555 |
+
|
| 556 |
+
|
| 557 |
+
def _read_bytes(fp, size, error_template="ran out of data"):
|
| 558 |
+
"""
|
| 559 |
+
Copied from: https://github.com/numpy/numpy/blob/fb215c76967739268de71aa4bda55dd1b062bc2e/numpy/lib/format.py#L788-L886
|
| 560 |
+
|
| 561 |
+
Read from file-like object until size bytes are read.
|
| 562 |
+
Raises ValueError if not EOF is encountered before size bytes are read.
|
| 563 |
+
Non-blocking objects only supported if they derive from io objects.
|
| 564 |
+
Required as e.g. ZipExtFile in python 2.6 can return less data than
|
| 565 |
+
requested.
|
| 566 |
+
"""
|
| 567 |
+
data = bytes()
|
| 568 |
+
while True:
|
| 569 |
+
# io files (default in python3) return None or raise on
|
| 570 |
+
# would-block, python2 file will truncate, probably nothing can be
|
| 571 |
+
# done about that. note that regular files can't be non-blocking
|
| 572 |
+
try:
|
| 573 |
+
r = fp.read(size - len(data))
|
| 574 |
+
data += r
|
| 575 |
+
if len(r) == 0 or len(data) == size:
|
| 576 |
+
break
|
| 577 |
+
except io.BlockingIOError:
|
| 578 |
+
pass
|
| 579 |
+
if len(data) != size:
|
| 580 |
+
msg = "EOF: reading %s, expected %d bytes got %d"
|
| 581 |
+
raise ValueError(msg % (error_template, size, len(data)))
|
| 582 |
+
else:
|
| 583 |
+
return data
|
| 584 |
+
|
| 585 |
+
|
| 586 |
+
@contextmanager
|
| 587 |
+
def _open_npy_file(path: str, arr_name: str):
|
| 588 |
+
with open(path, "rb") as f:
|
| 589 |
+
with zipfile.ZipFile(f, "r") as zip_f:
|
| 590 |
+
if f"{arr_name}.npy" not in zip_f.namelist():
|
| 591 |
+
raise ValueError(f"missing {arr_name} in npz file")
|
| 592 |
+
with zip_f.open(f"{arr_name}.npy", "r") as arr_f:
|
| 593 |
+
yield arr_f
|
| 594 |
+
|
| 595 |
+
|
| 596 |
+
def _download_inception_model():
|
| 597 |
+
if os.path.exists(INCEPTION_V3_PATH):
|
| 598 |
+
return
|
| 599 |
+
print("downloading InceptionV3 model...")
|
| 600 |
+
with requests.get(INCEPTION_V3_URL, stream=True) as r:
|
| 601 |
+
r.raise_for_status()
|
| 602 |
+
tmp_path = INCEPTION_V3_PATH + ".tmp"
|
| 603 |
+
with open(tmp_path, "wb") as f:
|
| 604 |
+
for chunk in tqdm(r.iter_content(chunk_size=8192)):
|
| 605 |
+
f.write(chunk)
|
| 606 |
+
os.rename(tmp_path, INCEPTION_V3_PATH)
|
| 607 |
+
|
| 608 |
+
|
| 609 |
+
def _create_feature_graph(input_batch):
|
| 610 |
+
_download_inception_model()
|
| 611 |
+
prefix = f"{random.randrange(2**32)}_{random.randrange(2**32)}"
|
| 612 |
+
with open(INCEPTION_V3_PATH, "rb") as f:
|
| 613 |
+
graph_def = tf.GraphDef()
|
| 614 |
+
graph_def.ParseFromString(f.read())
|
| 615 |
+
pool3, spatial = tf.import_graph_def(
|
| 616 |
+
graph_def,
|
| 617 |
+
input_map={f"ExpandDims:0": input_batch},
|
| 618 |
+
return_elements=[FID_POOL_NAME, FID_SPATIAL_NAME],
|
| 619 |
+
name=prefix,
|
| 620 |
+
)
|
| 621 |
+
_update_shapes(pool3)
|
| 622 |
+
spatial = spatial[..., :7]
|
| 623 |
+
return pool3, spatial
|
| 624 |
+
|
| 625 |
+
|
| 626 |
+
def _create_softmax_graph(input_batch):
|
| 627 |
+
_download_inception_model()
|
| 628 |
+
prefix = f"{random.randrange(2**32)}_{random.randrange(2**32)}"
|
| 629 |
+
with open(INCEPTION_V3_PATH, "rb") as f:
|
| 630 |
+
graph_def = tf.GraphDef()
|
| 631 |
+
graph_def.ParseFromString(f.read())
|
| 632 |
+
(matmul,) = tf.import_graph_def(
|
| 633 |
+
graph_def, return_elements=[f"softmax/logits/MatMul"], name=prefix
|
| 634 |
+
)
|
| 635 |
+
w = matmul.inputs[1]
|
| 636 |
+
logits = tf.matmul(input_batch, w)
|
| 637 |
+
return tf.nn.softmax(logits)
|
| 638 |
+
|
| 639 |
+
|
| 640 |
+
def _update_shapes(pool3):
|
| 641 |
+
# https://github.com/bioinf-jku/TTUR/blob/73ab375cdf952a12686d9aa7978567771084da42/fid.py#L50-L63
|
| 642 |
+
ops = pool3.graph.get_operations()
|
| 643 |
+
for op in ops:
|
| 644 |
+
for o in op.outputs:
|
| 645 |
+
shape = o.get_shape()
|
| 646 |
+
if shape._dims is not None: # pylint: disable=protected-access
|
| 647 |
+
shape = [s for s in shape] # TF 2.x
|
| 648 |
+
new_shape = []
|
| 649 |
+
for j, s in enumerate(shape):
|
| 650 |
+
if s == 1 and j == 0:
|
| 651 |
+
new_shape.append(None)
|
| 652 |
+
else:
|
| 653 |
+
new_shape.append(s)
|
| 654 |
+
o.__dict__["_shape_val"] = tf.TensorShape(new_shape)
|
| 655 |
+
return pool3
|
| 656 |
+
|
| 657 |
+
|
| 658 |
+
def _numpy_partition(arr, kth, **kwargs):
|
| 659 |
+
num_workers = min(cpu_count(), len(arr))
|
| 660 |
+
chunk_size = len(arr) // num_workers
|
| 661 |
+
extra = len(arr) % num_workers
|
| 662 |
+
|
| 663 |
+
start_idx = 0
|
| 664 |
+
batches = []
|
| 665 |
+
for i in range(num_workers):
|
| 666 |
+
size = chunk_size + (1 if i < extra else 0)
|
| 667 |
+
batches.append(arr[start_idx : start_idx + size])
|
| 668 |
+
start_idx += size
|
| 669 |
+
|
| 670 |
+
with ThreadPool(num_workers) as pool:
|
| 671 |
+
return list(pool.map(partial(np.partition, kth=kth, **kwargs), batches))
|
| 672 |
+
|
| 673 |
+
|
| 674 |
+
if __name__ == "__main__":
|
| 675 |
+
main()
|
gan_loss.py
ADDED
|
@@ -0,0 +1,1229 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Single-file GAN loss module with discriminators and perceptual loss.
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
import functools
|
| 6 |
+
import hashlib
|
| 7 |
+
import math
|
| 8 |
+
import os
|
| 9 |
+
import random
|
| 10 |
+
from collections import namedtuple
|
| 11 |
+
from typing import List, Tuple
|
| 12 |
+
|
| 13 |
+
import numpy as np
|
| 14 |
+
import requests
|
| 15 |
+
import torch
|
| 16 |
+
import torch.nn as nn
|
| 17 |
+
import torch.nn.functional as F
|
| 18 |
+
from torch.nn.utils.spectral_norm import SpectralNorm
|
| 19 |
+
from torchvision import models
|
| 20 |
+
from torchvision.transforms import RandomCrop
|
| 21 |
+
from tqdm import tqdm
|
| 22 |
+
|
| 23 |
+
###############################################################################
|
| 24 |
+
# PatchGAN discriminator and ActNorm
|
| 25 |
+
###############################################################################
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
class NLayerDiscriminator(nn.Module):
|
| 29 |
+
"""Defines a PatchGAN discriminator as in Pix2Pix.
|
| 30 |
+
|
| 31 |
+
Reference:
|
| 32 |
+
https://github.com/junyanz/pytorch-CycleGAN-and-pix2pix/blob/master/models/networks.py
|
| 33 |
+
"""
|
| 34 |
+
|
| 35 |
+
def __init__(self, input_nc=3, ndf=64, n_layers=3, use_actnorm=False):
|
| 36 |
+
"""Construct a PatchGAN discriminator.
|
| 37 |
+
|
| 38 |
+
Args:
|
| 39 |
+
input_nc (int): number of channels in input images.
|
| 40 |
+
ndf (int): number of filters in the last conv layer.
|
| 41 |
+
n_layers (int): number of conv layers in the discriminator.
|
| 42 |
+
use_actnorm (bool): whether to use ActNorm instead of BatchNorm.
|
| 43 |
+
"""
|
| 44 |
+
super().__init__()
|
| 45 |
+
if not use_actnorm:
|
| 46 |
+
norm_layer = nn.BatchNorm2d
|
| 47 |
+
else:
|
| 48 |
+
norm_layer = ActNorm
|
| 49 |
+
|
| 50 |
+
if isinstance(norm_layer, functools.partial):
|
| 51 |
+
# no need to use bias as BatchNorm2d has affine parameters
|
| 52 |
+
use_bias = norm_layer.func != nn.BatchNorm2d
|
| 53 |
+
else:
|
| 54 |
+
use_bias = norm_layer != nn.BatchNorm2d
|
| 55 |
+
|
| 56 |
+
kw = 4
|
| 57 |
+
padw = 1
|
| 58 |
+
sequence = [
|
| 59 |
+
nn.Conv2d(input_nc, ndf, kernel_size=kw, stride=2, padding=padw),
|
| 60 |
+
nn.LeakyReLU(0.2, True),
|
| 61 |
+
]
|
| 62 |
+
nf_mult = 1
|
| 63 |
+
nf_mult_prev = 1
|
| 64 |
+
# gradually increase the number of filters
|
| 65 |
+
for n in range(1, n_layers):
|
| 66 |
+
nf_mult_prev = nf_mult
|
| 67 |
+
nf_mult = min(2 ** n, 8)
|
| 68 |
+
sequence += [
|
| 69 |
+
nn.Conv2d(
|
| 70 |
+
ndf * nf_mult_prev,
|
| 71 |
+
ndf * nf_mult,
|
| 72 |
+
kernel_size=kw,
|
| 73 |
+
stride=2,
|
| 74 |
+
padding=padw,
|
| 75 |
+
bias=use_bias,
|
| 76 |
+
),
|
| 77 |
+
norm_layer(ndf * nf_mult),
|
| 78 |
+
nn.LeakyReLU(0.2, True),
|
| 79 |
+
]
|
| 80 |
+
|
| 81 |
+
nf_mult_prev = nf_mult
|
| 82 |
+
nf_mult = min(2 ** n_layers, 8)
|
| 83 |
+
sequence += [
|
| 84 |
+
nn.Conv2d(
|
| 85 |
+
ndf * nf_mult_prev,
|
| 86 |
+
ndf * nf_mult,
|
| 87 |
+
kernel_size=kw,
|
| 88 |
+
stride=1,
|
| 89 |
+
padding=padw,
|
| 90 |
+
bias=use_bias,
|
| 91 |
+
),
|
| 92 |
+
norm_layer(ndf * nf_mult),
|
| 93 |
+
nn.LeakyReLU(0.2, True),
|
| 94 |
+
]
|
| 95 |
+
|
| 96 |
+
# output 1 channel prediction map
|
| 97 |
+
sequence += [
|
| 98 |
+
nn.Conv2d(
|
| 99 |
+
ndf * nf_mult,
|
| 100 |
+
1,
|
| 101 |
+
kernel_size=kw,
|
| 102 |
+
stride=1,
|
| 103 |
+
padding=padw,
|
| 104 |
+
)
|
| 105 |
+
]
|
| 106 |
+
self.main = nn.Sequential(*sequence)
|
| 107 |
+
|
| 108 |
+
self.apply(self._init_weights)
|
| 109 |
+
|
| 110 |
+
def _init_weights(self, module):
|
| 111 |
+
if isinstance(module, nn.Conv2d):
|
| 112 |
+
nn.init.normal_(module.weight.data, 0.0, 0.02)
|
| 113 |
+
elif isinstance(module, nn.BatchNorm2d):
|
| 114 |
+
nn.init.normal_(module.weight.data, 1.0, 0.02)
|
| 115 |
+
nn.init.constant_(module.bias.data, 0)
|
| 116 |
+
|
| 117 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 118 |
+
"""Standard forward."""
|
| 119 |
+
return self.main(x)
|
| 120 |
+
|
| 121 |
+
|
| 122 |
+
class ActNorm(nn.Module):
|
| 123 |
+
def __init__(self, num_features, logdet=False, affine=True, allow_reverse_init=False):
|
| 124 |
+
assert affine
|
| 125 |
+
super().__init__()
|
| 126 |
+
self.logdet = logdet
|
| 127 |
+
self.loc = nn.Parameter(torch.zeros(1, num_features, 1, 1))
|
| 128 |
+
self.scale = nn.Parameter(torch.ones(1, num_features, 1, 1))
|
| 129 |
+
self.allow_reverse_init = allow_reverse_init
|
| 130 |
+
|
| 131 |
+
self.register_buffer("initialized", torch.tensor(0, dtype=torch.uint8))
|
| 132 |
+
|
| 133 |
+
def initialize(self, x: torch.Tensor):
|
| 134 |
+
with torch.no_grad():
|
| 135 |
+
flatten = x.permute(1, 0, 2, 3).contiguous().view(x.shape[1], -1)
|
| 136 |
+
mean = (
|
| 137 |
+
flatten.mean(1)
|
| 138 |
+
.unsqueeze(1)
|
| 139 |
+
.unsqueeze(2)
|
| 140 |
+
.unsqueeze(3)
|
| 141 |
+
.permute(1, 0, 2, 3)
|
| 142 |
+
)
|
| 143 |
+
std = (
|
| 144 |
+
flatten.std(1)
|
| 145 |
+
.unsqueeze(1)
|
| 146 |
+
.unsqueeze(2)
|
| 147 |
+
.unsqueeze(3)
|
| 148 |
+
.permute(1, 0, 2, 3)
|
| 149 |
+
)
|
| 150 |
+
|
| 151 |
+
self.loc.data.copy_(-mean)
|
| 152 |
+
self.scale.data.copy_(1 / (std + 1e-6))
|
| 153 |
+
|
| 154 |
+
def forward(self, x: torch.Tensor, reverse: bool = False):
|
| 155 |
+
if reverse:
|
| 156 |
+
return self.reverse(x)
|
| 157 |
+
if len(x.shape) == 2:
|
| 158 |
+
x = x[:, :, None, None]
|
| 159 |
+
squeeze = True
|
| 160 |
+
else:
|
| 161 |
+
squeeze = False
|
| 162 |
+
|
| 163 |
+
_, _, height, width = x.shape
|
| 164 |
+
|
| 165 |
+
if self.training and self.initialized.item() == 0:
|
| 166 |
+
self.initialize(x)
|
| 167 |
+
self.initialized.fill_(1)
|
| 168 |
+
|
| 169 |
+
h = self.scale * (x + self.loc)
|
| 170 |
+
|
| 171 |
+
if squeeze:
|
| 172 |
+
h = h.squeeze(-1).squeeze(-1)
|
| 173 |
+
|
| 174 |
+
if self.logdet:
|
| 175 |
+
log_abs = torch.log(torch.abs(self.scale))
|
| 176 |
+
logdet = height * width * torch.sum(log_abs)
|
| 177 |
+
logdet = logdet * torch.ones(x.shape[0]).to(x)
|
| 178 |
+
return h, logdet
|
| 179 |
+
|
| 180 |
+
return h
|
| 181 |
+
|
| 182 |
+
def reverse(self, y: torch.Tensor):
|
| 183 |
+
if self.training and self.initialized.item() == 0:
|
| 184 |
+
if not self.allow_reverse_init:
|
| 185 |
+
raise RuntimeError(
|
| 186 |
+
"Initializing ActNorm in reverse direction is disabled by default. "
|
| 187 |
+
"Use allow_reverse_init=True to enable."
|
| 188 |
+
)
|
| 189 |
+
else:
|
| 190 |
+
self.initialize(y)
|
| 191 |
+
self.initialized.fill_(1)
|
| 192 |
+
|
| 193 |
+
if len(y.shape) == 2:
|
| 194 |
+
y = y[:, :, None, None]
|
| 195 |
+
squeeze = True
|
| 196 |
+
else:
|
| 197 |
+
squeeze = False
|
| 198 |
+
|
| 199 |
+
h = y / self.scale - self.loc
|
| 200 |
+
|
| 201 |
+
if squeeze:
|
| 202 |
+
h = h.squeeze(-1).squeeze(-1)
|
| 203 |
+
return h
|
| 204 |
+
|
| 205 |
+
|
| 206 |
+
###############################################################################
|
| 207 |
+
# StyleGAN-like image discriminator
|
| 208 |
+
###############################################################################
|
| 209 |
+
|
| 210 |
+
try:
|
| 211 |
+
from kornia.filters import filter2d
|
| 212 |
+
except Exception:
|
| 213 |
+
filter2d = None
|
| 214 |
+
|
| 215 |
+
|
| 216 |
+
def leaky_relu(p: float = 0.2):
|
| 217 |
+
return nn.LeakyReLU(p, inplace=True)
|
| 218 |
+
|
| 219 |
+
|
| 220 |
+
def exists(val):
|
| 221 |
+
return val is not None
|
| 222 |
+
|
| 223 |
+
|
| 224 |
+
class Blur(nn.Module):
|
| 225 |
+
def __init__(self):
|
| 226 |
+
super().__init__()
|
| 227 |
+
f = torch.Tensor([1, 2, 1])
|
| 228 |
+
self.register_buffer("f", f)
|
| 229 |
+
|
| 230 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 231 |
+
if filter2d is None:
|
| 232 |
+
return x
|
| 233 |
+
f = self.f
|
| 234 |
+
f = f[None, None, :] * f[None, :, None]
|
| 235 |
+
return filter2d(x, f, normalized=True)
|
| 236 |
+
|
| 237 |
+
|
| 238 |
+
class DiscriminatorBlock(nn.Module):
|
| 239 |
+
def __init__(self, input_channels, filters, downsample=True):
|
| 240 |
+
super().__init__()
|
| 241 |
+
self.conv_res = nn.Conv2d(input_channels, filters, 1, stride=(2 if downsample else 1))
|
| 242 |
+
|
| 243 |
+
self.net = nn.Sequential(
|
| 244 |
+
nn.Conv2d(input_channels, filters, 3, padding=1),
|
| 245 |
+
leaky_relu(),
|
| 246 |
+
nn.Conv2d(filters, filters, 3, padding=1),
|
| 247 |
+
leaky_relu(),
|
| 248 |
+
)
|
| 249 |
+
|
| 250 |
+
self.downsample = (
|
| 251 |
+
nn.Sequential(
|
| 252 |
+
Blur(),
|
| 253 |
+
nn.Conv2d(filters, filters, 3, padding=1, stride=2),
|
| 254 |
+
)
|
| 255 |
+
if downsample
|
| 256 |
+
else None
|
| 257 |
+
)
|
| 258 |
+
|
| 259 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 260 |
+
res = self.conv_res(x)
|
| 261 |
+
x = self.net(x)
|
| 262 |
+
if exists(self.downsample):
|
| 263 |
+
x = self.downsample(x)
|
| 264 |
+
x = (x + res) * (1 / math.sqrt(2))
|
| 265 |
+
return x
|
| 266 |
+
|
| 267 |
+
|
| 268 |
+
class StyleGANDiscriminator(nn.Module):
|
| 269 |
+
def __init__(self, input_nc=3, ndf=64, n_layers=3, channel_multiplier=1, image_size=256):
|
| 270 |
+
super().__init__()
|
| 271 |
+
channels = {
|
| 272 |
+
4: 512,
|
| 273 |
+
8: 512,
|
| 274 |
+
16: 512,
|
| 275 |
+
32: 512,
|
| 276 |
+
64: 256 * channel_multiplier,
|
| 277 |
+
128: 128 * channel_multiplier,
|
| 278 |
+
256: 64 * channel_multiplier,
|
| 279 |
+
512: 32 * channel_multiplier,
|
| 280 |
+
1024: 16 * channel_multiplier,
|
| 281 |
+
}
|
| 282 |
+
|
| 283 |
+
log_size = int(math.log(image_size, 2))
|
| 284 |
+
in_channel = channels[image_size]
|
| 285 |
+
|
| 286 |
+
blocks = [nn.Conv2d(input_nc, in_channel, 3, padding=1), leaky_relu()]
|
| 287 |
+
for i in range(log_size, 2, -1):
|
| 288 |
+
out_channel = channels[2 ** (i - 1)]
|
| 289 |
+
blocks.append(DiscriminatorBlock(in_channel, out_channel))
|
| 290 |
+
in_channel = out_channel
|
| 291 |
+
self.blocks = nn.ModuleList(blocks)
|
| 292 |
+
|
| 293 |
+
self.final_conv = nn.Sequential(
|
| 294 |
+
nn.Conv2d(in_channel, channels[4], 3, padding=1),
|
| 295 |
+
leaky_relu(),
|
| 296 |
+
)
|
| 297 |
+
self.final_linear = nn.Sequential(
|
| 298 |
+
nn.Linear(channels[4] * 4 * 4, channels[4]),
|
| 299 |
+
leaky_relu(),
|
| 300 |
+
nn.Linear(channels[4], 1),
|
| 301 |
+
)
|
| 302 |
+
|
| 303 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 304 |
+
for block in self.blocks:
|
| 305 |
+
x = block(x)
|
| 306 |
+
x = self.final_conv(x)
|
| 307 |
+
x = x.view(x.shape[0], -1)
|
| 308 |
+
x = self.final_linear(x)
|
| 309 |
+
return x
|
| 310 |
+
|
| 311 |
+
|
| 312 |
+
###############################################################################
|
| 313 |
+
# DiffAug (data augmentation for discriminator)
|
| 314 |
+
###############################################################################
|
| 315 |
+
|
| 316 |
+
|
| 317 |
+
class DiffAug(object):
|
| 318 |
+
def __init__(self, prob: float = 1.0, cutout: float = 0.2):
|
| 319 |
+
self.grids = {}
|
| 320 |
+
self.prob = abs(prob)
|
| 321 |
+
self.using_cutout = prob > 0
|
| 322 |
+
self.cutout = cutout
|
| 323 |
+
self.img_channels = -1
|
| 324 |
+
self.last_blur_radius = -1
|
| 325 |
+
self.last_blur_kernel_h = None
|
| 326 |
+
self.last_blur_kernel_w = None
|
| 327 |
+
|
| 328 |
+
def get_grids(self, B, x, y, dev):
|
| 329 |
+
if (B, x, y) in self.grids:
|
| 330 |
+
return self.grids[(B, x, y)]
|
| 331 |
+
|
| 332 |
+
self.grids[(B, x, y)] = ret = torch.meshgrid(
|
| 333 |
+
torch.arange(B, dtype=torch.long, device=dev),
|
| 334 |
+
torch.arange(x, dtype=torch.long, device=dev),
|
| 335 |
+
torch.arange(y, dtype=torch.long, device=dev),
|
| 336 |
+
indexing="ij",
|
| 337 |
+
)
|
| 338 |
+
return ret
|
| 339 |
+
|
| 340 |
+
def aug(self, BCHW: torch.Tensor, warmup_blur_schedule: float = 0) -> torch.Tensor:
|
| 341 |
+
# warmup blurring
|
| 342 |
+
if BCHW.dtype != torch.float32:
|
| 343 |
+
BCHW = BCHW.float()
|
| 344 |
+
if warmup_blur_schedule > 0:
|
| 345 |
+
self.img_channels = BCHW.shape[1]
|
| 346 |
+
sigma0 = (BCHW.shape[-2] * 0.5) ** 0.5
|
| 347 |
+
sigma = sigma0 * warmup_blur_schedule
|
| 348 |
+
blur_radius = math.floor(sigma * 3) # 3-sigma is enough for Gaussian
|
| 349 |
+
if blur_radius >= 1:
|
| 350 |
+
if self.last_blur_radius != blur_radius:
|
| 351 |
+
self.last_blur_radius = blur_radius
|
| 352 |
+
gaussian = torch.arange(
|
| 353 |
+
-blur_radius, blur_radius + 1, dtype=torch.float32, device=BCHW.device
|
| 354 |
+
)
|
| 355 |
+
gaussian = gaussian.mul_(1 / sigma).square_().neg_().exp2_()
|
| 356 |
+
gaussian.div_(gaussian.sum()) # normalize
|
| 357 |
+
self.last_blur_kernel_h = (
|
| 358 |
+
gaussian.view(1, 1, 2 * blur_radius + 1, 1)
|
| 359 |
+
.repeat(self.img_channels, 1, 1, 1)
|
| 360 |
+
.contiguous()
|
| 361 |
+
)
|
| 362 |
+
self.last_blur_kernel_w = (
|
| 363 |
+
gaussian.view(1, 1, 1, 2 * blur_radius + 1)
|
| 364 |
+
.repeat(self.img_channels, 1, 1, 1)
|
| 365 |
+
.contiguous()
|
| 366 |
+
)
|
| 367 |
+
|
| 368 |
+
BCHW = F.pad(BCHW, [blur_radius, blur_radius, blur_radius, blur_radius], mode="reflect")
|
| 369 |
+
BCHW = F.conv2d(
|
| 370 |
+
input=BCHW, weight=self.last_blur_kernel_h, bias=None, groups=self.img_channels
|
| 371 |
+
)
|
| 372 |
+
BCHW = F.conv2d(
|
| 373 |
+
input=BCHW, weight=self.last_blur_kernel_w, bias=None, groups=self.img_channels
|
| 374 |
+
)
|
| 375 |
+
|
| 376 |
+
if self.prob < 1e-6:
|
| 377 |
+
return BCHW
|
| 378 |
+
trans, color, cut = torch.rand(3) <= self.prob
|
| 379 |
+
trans, color, cut = trans.item(), color.item(), cut.item()
|
| 380 |
+
B, dev = BCHW.shape[0], BCHW.device
|
| 381 |
+
rand01 = torch.rand(7, B, 1, 1, device=dev) if (trans or color or cut) else None
|
| 382 |
+
|
| 383 |
+
raw_h, raw_w = BCHW.shape[-2:]
|
| 384 |
+
if trans:
|
| 385 |
+
ratio = 0.125
|
| 386 |
+
delta_h = round(raw_h * ratio)
|
| 387 |
+
delta_w = round(raw_w * ratio)
|
| 388 |
+
translation_h = rand01[0].mul(delta_h + delta_h + 1).floor().long() - delta_h
|
| 389 |
+
translation_w = rand01[1].mul(delta_w + delta_w + 1).floor().long() - delta_w
|
| 390 |
+
|
| 391 |
+
grid_B, grid_h, grid_w = self.get_grids(B, raw_h, raw_w, dev)
|
| 392 |
+
grid_h = (grid_h + translation_h).add_(1).clamp_(0, raw_h + 1)
|
| 393 |
+
grid_w = (grid_w + translation_w).add_(1).clamp_(0, raw_w + 1)
|
| 394 |
+
bchw_pad = F.pad(BCHW, [1, 1, 1, 1, 0, 0, 0, 0])
|
| 395 |
+
BCHW = (
|
| 396 |
+
bchw_pad.permute(0, 2, 3, 1)
|
| 397 |
+
.contiguous()[grid_B, grid_h, grid_w]
|
| 398 |
+
.permute(0, 3, 1, 2)
|
| 399 |
+
.contiguous()
|
| 400 |
+
)
|
| 401 |
+
|
| 402 |
+
if color:
|
| 403 |
+
BCHW = BCHW.add(rand01[2].unsqueeze(-1).sub(0.5))
|
| 404 |
+
bchw_mean = BCHW.mean(dim=1, keepdim=True)
|
| 405 |
+
BCHW = BCHW.sub(bchw_mean).mul(rand01[3].unsqueeze(-1).mul(2)).add_(bchw_mean)
|
| 406 |
+
bchw_mean = BCHW.mean(dim=(1, 2, 3), keepdim=True)
|
| 407 |
+
BCHW = BCHW.sub(bchw_mean).mul(rand01[4].unsqueeze(-1).add(0.5)).add_(bchw_mean)
|
| 408 |
+
|
| 409 |
+
if self.using_cutout and cut:
|
| 410 |
+
ratio = self.cutout
|
| 411 |
+
cutout_h = round(raw_h * ratio)
|
| 412 |
+
cutout_w = round(raw_w * ratio)
|
| 413 |
+
offset_h = rand01[5].mul(raw_h + (1 - cutout_h % 2)).floor().long()
|
| 414 |
+
offset_w = rand01[6].mul(raw_w + (1 - cutout_w % 2)).floor().long()
|
| 415 |
+
|
| 416 |
+
grid_B, grid_h, grid_w = self.get_grids(B, cutout_h, cutout_w, dev)
|
| 417 |
+
grid_h = (grid_h + offset_h).sub_(cutout_h // 2).clamp(min=0, max=raw_h - 1)
|
| 418 |
+
grid_w = (grid_w + offset_w).sub_(cutout_w // 2).clamp(min=0, max=raw_w - 1)
|
| 419 |
+
mask = torch.ones(B, raw_h, raw_w, dtype=BCHW.dtype, device=dev)
|
| 420 |
+
mask[grid_B, grid_h, grid_w] = 0
|
| 421 |
+
BCHW = BCHW.mul(mask.unsqueeze(1))
|
| 422 |
+
|
| 423 |
+
return BCHW
|
| 424 |
+
|
| 425 |
+
|
| 426 |
+
###############################################################################
|
| 427 |
+
# LPIPS perceptual similarity loss
|
| 428 |
+
###############################################################################
|
| 429 |
+
|
| 430 |
+
URL_MAP = {
|
| 431 |
+
"vgg_lpips": "https://heibox.uni-heidelberg.de/f/607503859c864bc1b30b/?dl=1",
|
| 432 |
+
}
|
| 433 |
+
|
| 434 |
+
CKPT_MAP = {
|
| 435 |
+
"vgg_lpips": "vgg.pth",
|
| 436 |
+
}
|
| 437 |
+
|
| 438 |
+
MD5_MAP = {
|
| 439 |
+
"vgg_lpips": "d507d7349b931f0638a25a48a722f98a",
|
| 440 |
+
}
|
| 441 |
+
|
| 442 |
+
|
| 443 |
+
def download(url, local_path, chunk_size=1024):
|
| 444 |
+
os.makedirs(os.path.split(local_path)[0], exist_ok=True)
|
| 445 |
+
with requests.get(url, stream=True) as r:
|
| 446 |
+
total_size = int(r.headers.get("content-length", 0))
|
| 447 |
+
with tqdm(total=total_size, unit="B", unit_scale=True) as pbar:
|
| 448 |
+
with open(local_path, "wb") as f:
|
| 449 |
+
for data in r.iter_content(chunk_size=chunk_size):
|
| 450 |
+
if data:
|
| 451 |
+
f.write(data)
|
| 452 |
+
pbar.update(chunk_size)
|
| 453 |
+
|
| 454 |
+
|
| 455 |
+
def md5_hash(path):
|
| 456 |
+
with open(path, "rb") as f:
|
| 457 |
+
content = f.read()
|
| 458 |
+
return hashlib.md5(content).hexdigest()
|
| 459 |
+
|
| 460 |
+
|
| 461 |
+
def get_ckpt_path(name, root, check=False):
|
| 462 |
+
assert name in URL_MAP
|
| 463 |
+
path = os.path.join(root, CKPT_MAP[name])
|
| 464 |
+
if not os.path.exists(path) or (check and not md5_hash(path) == MD5_MAP[name]):
|
| 465 |
+
print(f"Downloading {name} model from {URL_MAP[name]} to {path}")
|
| 466 |
+
download(URL_MAP[name], path)
|
| 467 |
+
md5 = md5_hash(path)
|
| 468 |
+
assert md5 == MD5_MAP[name], md5
|
| 469 |
+
return path
|
| 470 |
+
|
| 471 |
+
|
| 472 |
+
class ScalingLayer(nn.Module):
|
| 473 |
+
def __init__(self):
|
| 474 |
+
super().__init__()
|
| 475 |
+
self.register_buffer("shift", torch.Tensor([-.030, -.088, -.188])[None, :, None, None])
|
| 476 |
+
self.register_buffer("scale", torch.Tensor([.458, .448, .450])[None, :, None, None])
|
| 477 |
+
|
| 478 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 479 |
+
return (x - self.shift) / self.scale
|
| 480 |
+
|
| 481 |
+
|
| 482 |
+
class NetLinLayer(nn.Module):
|
| 483 |
+
"""A single linear layer which does a 1x1 conv."""
|
| 484 |
+
|
| 485 |
+
def __init__(self, chn_in, chn_out=1, use_dropout=False):
|
| 486 |
+
super().__init__()
|
| 487 |
+
layers = [nn.Dropout()] if use_dropout else []
|
| 488 |
+
layers += [nn.Conv2d(chn_in, chn_out, 1, stride=1, padding=0, bias=False)]
|
| 489 |
+
self.model = nn.Sequential(*layers)
|
| 490 |
+
|
| 491 |
+
|
| 492 |
+
class VGG16Features(nn.Module):
|
| 493 |
+
def __init__(self, requires_grad=False, pretrained=True):
|
| 494 |
+
super().__init__()
|
| 495 |
+
vgg_pretrained_features = models.vgg16(pretrained=pretrained).features
|
| 496 |
+
self.slice1 = nn.Sequential()
|
| 497 |
+
self.slice2 = nn.Sequential()
|
| 498 |
+
self.slice3 = nn.Sequential()
|
| 499 |
+
self.slice4 = nn.Sequential()
|
| 500 |
+
self.slice5 = nn.Sequential()
|
| 501 |
+
for x in range(4):
|
| 502 |
+
self.slice1.add_module(str(x), vgg_pretrained_features[x])
|
| 503 |
+
for x in range(4, 9):
|
| 504 |
+
self.slice2.add_module(str(x), vgg_pretrained_features[x])
|
| 505 |
+
for x in range(9, 16):
|
| 506 |
+
self.slice3.add_module(str(x), vgg_pretrained_features[x])
|
| 507 |
+
for x in range(16, 23):
|
| 508 |
+
self.slice4.add_module(str(x), vgg_pretrained_features[x])
|
| 509 |
+
for x in range(23, 30):
|
| 510 |
+
self.slice5.add_module(str(x), vgg_pretrained_features[x])
|
| 511 |
+
if not requires_grad:
|
| 512 |
+
for param in self.parameters():
|
| 513 |
+
param.requires_grad = False
|
| 514 |
+
|
| 515 |
+
def forward(self, x: torch.Tensor):
|
| 516 |
+
h = self.slice1(x)
|
| 517 |
+
h_relu1_2 = h
|
| 518 |
+
h = self.slice2(h)
|
| 519 |
+
h_relu2_2 = h
|
| 520 |
+
h = self.slice3(h)
|
| 521 |
+
h_relu3_3 = h
|
| 522 |
+
h = self.slice4(h)
|
| 523 |
+
h_relu4_3 = h
|
| 524 |
+
h = self.slice5(h)
|
| 525 |
+
h_relu5_3 = h
|
| 526 |
+
vgg_outputs = namedtuple(
|
| 527 |
+
"VggOutputs", ["relu1_2", "relu2_2", "relu3_3", "relu4_3", "relu5_3"]
|
| 528 |
+
)
|
| 529 |
+
out = vgg_outputs(h_relu1_2, h_relu2_2, h_relu3_3, h_relu4_3, h_relu5_3)
|
| 530 |
+
return out
|
| 531 |
+
|
| 532 |
+
|
| 533 |
+
def normalize_tensor(x, eps: float = 1e-10):
|
| 534 |
+
norm_factor = torch.sqrt(torch.sum(x ** 2, dim=1, keepdim=True))
|
| 535 |
+
return x / (norm_factor + eps)
|
| 536 |
+
|
| 537 |
+
|
| 538 |
+
def spatial_average(x, keepdim: bool = True):
|
| 539 |
+
return x.mean([2, 3], keepdim=keepdim)
|
| 540 |
+
|
| 541 |
+
|
| 542 |
+
class LPIPS(nn.Module):
|
| 543 |
+
"""Learned perceptual image patch similarity."""
|
| 544 |
+
|
| 545 |
+
def __init__(self, use_dropout: bool = True):
|
| 546 |
+
super().__init__()
|
| 547 |
+
self.scaling_layer = ScalingLayer()
|
| 548 |
+
self.chns = [64, 128, 256, 512, 512] # VGG16 feature sizes
|
| 549 |
+
self.net = VGG16Features(pretrained=True, requires_grad=False)
|
| 550 |
+
self.lin0 = NetLinLayer(self.chns[0], use_dropout=use_dropout)
|
| 551 |
+
self.lin1 = NetLinLayer(self.chns[1], use_dropout=use_dropout)
|
| 552 |
+
self.lin2 = NetLinLayer(self.chns[2], use_dropout=use_dropout)
|
| 553 |
+
self.lin3 = NetLinLayer(self.chns[3], use_dropout=use_dropout)
|
| 554 |
+
self.lin4 = NetLinLayer(self.chns[4], use_dropout=use_dropout)
|
| 555 |
+
self.load_from_pretrained()
|
| 556 |
+
for param in self.parameters():
|
| 557 |
+
param.requires_grad = False
|
| 558 |
+
|
| 559 |
+
def load_from_pretrained(self, name: str = "vgg_lpips"):
|
| 560 |
+
ckpt = get_ckpt_path(
|
| 561 |
+
name, os.path.join(os.path.dirname(os.path.abspath(__file__)), "cache")
|
| 562 |
+
)
|
| 563 |
+
self.load_state_dict(torch.load(ckpt, map_location=torch.device("cpu")), strict=False)
|
| 564 |
+
print(f"loaded pretrained LPIPS loss from {ckpt}")
|
| 565 |
+
|
| 566 |
+
def forward(self, x: torch.Tensor, y: torch.Tensor) -> torch.Tensor:
|
| 567 |
+
x_in, y_in = self.scaling_layer(x), self.scaling_layer(y)
|
| 568 |
+
outs0, outs1 = self.net(x_in), self.net(y_in)
|
| 569 |
+
feats0, feats1, diffs = {}, {}, {}
|
| 570 |
+
lins = [self.lin0, self.lin1, self.lin2, self.lin3, self.lin4]
|
| 571 |
+
for kk in range(len(self.chns)):
|
| 572 |
+
feats0[kk], feats1[kk] = normalize_tensor(outs0[kk]), normalize_tensor(outs1[kk])
|
| 573 |
+
diffs[kk] = (feats0[kk] - feats1[kk]) ** 2
|
| 574 |
+
|
| 575 |
+
res = [spatial_average(lins[kk].model(diffs[kk]), keepdim=True) for kk in range(len(self.chns))]
|
| 576 |
+
val = res[0]
|
| 577 |
+
for l in range(1, len(self.chns)):
|
| 578 |
+
val += res[l]
|
| 579 |
+
return val
|
| 580 |
+
|
| 581 |
+
|
| 582 |
+
###############################################################################
|
| 583 |
+
# DINO-based discriminator (DINODiscriminator)
|
| 584 |
+
###############################################################################
|
| 585 |
+
|
| 586 |
+
|
| 587 |
+
class MLPNoDrop(nn.Module):
|
| 588 |
+
def __init__(self, in_features, hidden_features=None, out_features=None, fused_if_available=True):
|
| 589 |
+
super().__init__()
|
| 590 |
+
try:
|
| 591 |
+
from flash_attn.ops.fused_dense import fused_mlp_func as _fused_mlp_func
|
| 592 |
+
except Exception:
|
| 593 |
+
_fused_mlp_func = None
|
| 594 |
+
|
| 595 |
+
self.fused_mlp_func = (
|
| 596 |
+
_fused_mlp_func if (torch.cuda.is_available() and fused_if_available) else None
|
| 597 |
+
)
|
| 598 |
+
out_features = out_features or in_features
|
| 599 |
+
hidden_features = hidden_features or in_features
|
| 600 |
+
self.fc1 = nn.Linear(in_features, hidden_features)
|
| 601 |
+
self.act = nn.GELU(approximate="tanh")
|
| 602 |
+
self.fc2 = nn.Linear(hidden_features, out_features)
|
| 603 |
+
|
| 604 |
+
def forward(self, x):
|
| 605 |
+
if self.fused_mlp_func is not None:
|
| 606 |
+
return self.fused_mlp_func(
|
| 607 |
+
x=x,
|
| 608 |
+
weight1=self.fc1.weight,
|
| 609 |
+
weight2=self.fc2.weight,
|
| 610 |
+
bias1=self.fc1.bias,
|
| 611 |
+
bias2=self.fc2.bias,
|
| 612 |
+
activation="gelu_approx",
|
| 613 |
+
save_pre_act=self.training,
|
| 614 |
+
return_residual=False,
|
| 615 |
+
checkpoint_lvl=0,
|
| 616 |
+
heuristic=0,
|
| 617 |
+
process_group=None,
|
| 618 |
+
)
|
| 619 |
+
else:
|
| 620 |
+
return self.fc2(self.act(self.fc1(x)))
|
| 621 |
+
|
| 622 |
+
|
| 623 |
+
class SelfAttentionNoDrop(nn.Module):
|
| 624 |
+
def __init__(self, block_idx, embed_dim=768, num_heads=12, flash_if_available=True):
|
| 625 |
+
super().__init__()
|
| 626 |
+
assert embed_dim % num_heads == 0
|
| 627 |
+
self.block_idx = block_idx
|
| 628 |
+
self.num_heads = num_heads
|
| 629 |
+
self.head_dim = embed_dim // num_heads
|
| 630 |
+
self.scale = 1 / math.sqrt(self.head_dim)
|
| 631 |
+
self.qkv = nn.Linear(embed_dim, embed_dim * 3, bias=True)
|
| 632 |
+
self.proj = nn.Linear(embed_dim, embed_dim, bias=True)
|
| 633 |
+
|
| 634 |
+
try:
|
| 635 |
+
from flash_attn import flash_attn_qkvpacked_func as _flash_attn_qkvpacked_func
|
| 636 |
+
except Exception:
|
| 637 |
+
_flash_attn_qkvpacked_func = None
|
| 638 |
+
|
| 639 |
+
self.using_flash_attn = (
|
| 640 |
+
torch.cuda.is_available() and flash_if_available and _flash_attn_qkvpacked_func is not None
|
| 641 |
+
)
|
| 642 |
+
self._flash_attn_qkvpacked_func = _flash_attn_qkvpacked_func
|
| 643 |
+
|
| 644 |
+
def forward(self, x):
|
| 645 |
+
B, L, C = x.shape
|
| 646 |
+
qkv = self.qkv(x).view(B, L, 3, self.num_heads, self.head_dim)
|
| 647 |
+
if self.using_flash_attn and qkv.dtype != torch.float32:
|
| 648 |
+
oup = self._flash_attn_qkvpacked_func(qkv, softmax_scale=self.scale).view(B, L, C)
|
| 649 |
+
else:
|
| 650 |
+
q, k, v = qkv.permute(2, 0, 3, 1, 4).unbind(dim=0) # BHLc
|
| 651 |
+
scale = self.scale
|
| 652 |
+
attn = q.mul(scale) @ k.transpose(-2, -1)
|
| 653 |
+
attn = attn.softmax(dim=-1)
|
| 654 |
+
oup = (attn @ v).transpose(1, 2).reshape(B, L, C)
|
| 655 |
+
return self.proj(oup)
|
| 656 |
+
|
| 657 |
+
|
| 658 |
+
class SABlockNoDrop(nn.Module):
|
| 659 |
+
def __init__(self, block_idx, embed_dim, num_heads, mlp_ratio, norm_eps):
|
| 660 |
+
super().__init__()
|
| 661 |
+
self.norm1 = nn.LayerNorm(embed_dim, eps=norm_eps)
|
| 662 |
+
self.attn = SelfAttentionNoDrop(
|
| 663 |
+
block_idx=block_idx,
|
| 664 |
+
embed_dim=embed_dim,
|
| 665 |
+
num_heads=num_heads,
|
| 666 |
+
flash_if_available=True,
|
| 667 |
+
)
|
| 668 |
+
self.norm2 = nn.LayerNorm(embed_dim, eps=norm_eps)
|
| 669 |
+
self.mlp = MLPNoDrop(
|
| 670 |
+
in_features=embed_dim,
|
| 671 |
+
hidden_features=round(embed_dim * mlp_ratio),
|
| 672 |
+
fused_if_available=True,
|
| 673 |
+
)
|
| 674 |
+
|
| 675 |
+
def forward(self, x):
|
| 676 |
+
x = x + self.attn(self.norm1(x))
|
| 677 |
+
x = x + self.mlp(self.norm2(x))
|
| 678 |
+
return x
|
| 679 |
+
|
| 680 |
+
|
| 681 |
+
class ResidualBlock(nn.Module):
|
| 682 |
+
def __init__(self, fn):
|
| 683 |
+
super().__init__()
|
| 684 |
+
self.fn = fn
|
| 685 |
+
self.ratio = 1 / np.sqrt(2)
|
| 686 |
+
|
| 687 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 688 |
+
return (self.fn(x).add(x)).mul_(self.ratio)
|
| 689 |
+
|
| 690 |
+
|
| 691 |
+
class SpectralConv1d(nn.Conv1d):
|
| 692 |
+
def __init__(self, *args, **kwargs):
|
| 693 |
+
super().__init__(*args, **kwargs)
|
| 694 |
+
SpectralNorm.apply(self, name="weight", n_power_iterations=1, dim=0, eps=1e-12)
|
| 695 |
+
|
| 696 |
+
|
| 697 |
+
class BatchNormLocal(nn.Module):
|
| 698 |
+
def __init__(self, num_features: int, affine: bool = True, virtual_bs: int = 8, eps: float = 1e-6):
|
| 699 |
+
super().__init__()
|
| 700 |
+
self.virtual_bs = virtual_bs
|
| 701 |
+
self.eps = eps
|
| 702 |
+
self.affine = affine
|
| 703 |
+
|
| 704 |
+
if self.affine:
|
| 705 |
+
self.weight = nn.Parameter(torch.ones(num_features))
|
| 706 |
+
self.bias = nn.Parameter(torch.zeros(num_features))
|
| 707 |
+
|
| 708 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 709 |
+
shape = x.size()
|
| 710 |
+
x = x.float()
|
| 711 |
+
|
| 712 |
+
# Reshape batch into groups.
|
| 713 |
+
G = int(np.ceil(x.size(0) / self.virtual_bs))
|
| 714 |
+
x = x.view(G, -1, x.size(-2), x.size(-1))
|
| 715 |
+
|
| 716 |
+
# Calculate stats.
|
| 717 |
+
mean = x.mean([1, 3], keepdim=True)
|
| 718 |
+
var = x.var([1, 3], keepdim=True, unbiased=False)
|
| 719 |
+
x = (x - mean) / (torch.sqrt(var + self.eps))
|
| 720 |
+
|
| 721 |
+
if self.affine:
|
| 722 |
+
x = x * self.weight[None, :, None] + self.bias[None, :, None]
|
| 723 |
+
|
| 724 |
+
return x.view(shape)
|
| 725 |
+
|
| 726 |
+
|
| 727 |
+
def make_block(channels: int, kernel_size: int, norm_type: str, norm_eps: float, using_spec_norm: bool):
|
| 728 |
+
if norm_type == "bn":
|
| 729 |
+
norm = BatchNormLocal(channels, eps=norm_eps)
|
| 730 |
+
elif norm_type == "sbn":
|
| 731 |
+
norm = nn.SyncBatchNorm(channels, eps=norm_eps, process_group=None)
|
| 732 |
+
elif norm_type in {"lbn", "hbn"}:
|
| 733 |
+
# Fallback to SyncBatchNorm without a custom local machine group.
|
| 734 |
+
norm = nn.SyncBatchNorm(channels, eps=norm_eps, process_group=None)
|
| 735 |
+
elif norm_type == "gn":
|
| 736 |
+
norm = nn.GroupNorm(num_groups=32, num_channels=channels, eps=norm_eps, affine=True)
|
| 737 |
+
else:
|
| 738 |
+
raise NotImplementedError
|
| 739 |
+
|
| 740 |
+
conv_cls = SpectralConv1d if using_spec_norm else nn.Conv1d
|
| 741 |
+
return nn.Sequential(
|
| 742 |
+
conv_cls(channels, channels, kernel_size=kernel_size, padding=kernel_size // 2, padding_mode="circular"),
|
| 743 |
+
norm,
|
| 744 |
+
nn.LeakyReLU(negative_slope=0.2, inplace=True),
|
| 745 |
+
)
|
| 746 |
+
|
| 747 |
+
|
| 748 |
+
class PatchEmbed(nn.Module):
|
| 749 |
+
def __init__(self, img_size=224, patch_size=16, in_chans=3, embed_dim=768, norm_layer=None, flatten=True):
|
| 750 |
+
super().__init__()
|
| 751 |
+
self.img_size = img_size
|
| 752 |
+
self.patch_size = patch_size
|
| 753 |
+
self.num_patches = (img_size // patch_size) ** 2
|
| 754 |
+
self.flatten = flatten
|
| 755 |
+
|
| 756 |
+
self.proj = nn.Conv2d(in_chans, embed_dim, kernel_size=patch_size, stride=patch_size)
|
| 757 |
+
self.norm = norm_layer(embed_dim) if norm_layer else nn.Identity()
|
| 758 |
+
|
| 759 |
+
def forward(self, x):
|
| 760 |
+
x = self.proj(x).flatten(2).transpose(1, 2) # BCHW => BCL => BLC
|
| 761 |
+
return self.norm(x)
|
| 762 |
+
|
| 763 |
+
|
| 764 |
+
class FrozenDINOSmallNoDrop(nn.Module):
|
| 765 |
+
"""
|
| 766 |
+
Frozen DINO ViT without any dropout or droppath layers (eval-only),
|
| 767 |
+
based on timm.create_model('vit_small_patch16_224', pretrained=False, num_classes=0).
|
| 768 |
+
"""
|
| 769 |
+
|
| 770 |
+
def __init__(
|
| 771 |
+
self,
|
| 772 |
+
depth=12,
|
| 773 |
+
key_depths=(2, 5, 8, 11),
|
| 774 |
+
norm_eps=1e-6,
|
| 775 |
+
patch_size=16,
|
| 776 |
+
in_chans=3,
|
| 777 |
+
num_classes=0,
|
| 778 |
+
embed_dim=384,
|
| 779 |
+
num_heads=6,
|
| 780 |
+
mlp_ratio=4.0,
|
| 781 |
+
):
|
| 782 |
+
super().__init__()
|
| 783 |
+
self.num_classes = num_classes
|
| 784 |
+
self.num_features = self.embed_dim = embed_dim
|
| 785 |
+
|
| 786 |
+
self.img_size = 224
|
| 787 |
+
self.patch_embed = PatchEmbed(
|
| 788 |
+
img_size=self.img_size,
|
| 789 |
+
patch_size=patch_size,
|
| 790 |
+
in_chans=in_chans,
|
| 791 |
+
embed_dim=embed_dim,
|
| 792 |
+
)
|
| 793 |
+
self.patch_size = patch_size
|
| 794 |
+
self.patch_nums = self.img_size // patch_size
|
| 795 |
+
|
| 796 |
+
# x \in [-1, 1]
|
| 797 |
+
m = torch.tensor((0.485, 0.456, 0.406))
|
| 798 |
+
s = torch.tensor((0.229, 0.224, 0.225))
|
| 799 |
+
self.register_buffer("x_scale", (0.5 / s).reshape(1, 3, 1, 1))
|
| 800 |
+
self.register_buffer("x_shift", ((0.5 - m) / s).reshape(1, 3, 1, 1))
|
| 801 |
+
self.crop = RandomCrop(self.img_size)
|
| 802 |
+
|
| 803 |
+
self.cls_token = nn.Parameter(torch.zeros(1, 1, embed_dim))
|
| 804 |
+
self.dist_token = None
|
| 805 |
+
self.pos_embed = nn.Parameter(
|
| 806 |
+
torch.zeros(1, self.patch_nums * self.patch_nums + 1, embed_dim)
|
| 807 |
+
) # +1: for cls
|
| 808 |
+
|
| 809 |
+
self.key_depths = set(d for d in key_depths if d < depth)
|
| 810 |
+
self.blocks = nn.Sequential(
|
| 811 |
+
*[
|
| 812 |
+
SABlockNoDrop(
|
| 813 |
+
block_idx=i,
|
| 814 |
+
embed_dim=embed_dim,
|
| 815 |
+
num_heads=num_heads,
|
| 816 |
+
mlp_ratio=mlp_ratio,
|
| 817 |
+
norm_eps=norm_eps,
|
| 818 |
+
)
|
| 819 |
+
for i in range(max(depth, 1 + max(self.key_depths)))
|
| 820 |
+
]
|
| 821 |
+
)
|
| 822 |
+
self.norm = nn.LayerNorm(embed_dim, eps=norm_eps)
|
| 823 |
+
|
| 824 |
+
# eval mode only
|
| 825 |
+
self.eval()
|
| 826 |
+
for p in self.parameters():
|
| 827 |
+
p.requires_grad_(False)
|
| 828 |
+
|
| 829 |
+
def inter_pos_embed(self, patch_nums=(14, 14)):
|
| 830 |
+
if patch_nums[0] == self.patch_nums and patch_nums[1] == self.patch_nums:
|
| 831 |
+
return self.pos_embed
|
| 832 |
+
pe_cls, pe_grid = self.pos_embed[:, :1], self.pos_embed[0, 1:]
|
| 833 |
+
pe_grid = pe_grid.reshape(1, self.patch_nums, self.patch_nums, -1).permute(0, 3, 1, 2)
|
| 834 |
+
pe_grid = F.interpolate(
|
| 835 |
+
pe_grid, size=(patch_nums[0], patch_nums[1]), mode="bilinear", align_corners=False
|
| 836 |
+
)
|
| 837 |
+
pe_grid = pe_grid.permute(0, 2, 3, 1).reshape(1, patch_nums[0] * patch_nums[1], -1)
|
| 838 |
+
return torch.cat([pe_cls, pe_grid], dim=1)
|
| 839 |
+
|
| 840 |
+
def forward(self, x, grad_ckpt: bool = False):
|
| 841 |
+
with torch.cuda.amp.autocast(enabled=False):
|
| 842 |
+
x = (self.x_scale * x.float()).add_(self.x_shift)
|
| 843 |
+
H, W = x.shape[-2], x.shape[-1]
|
| 844 |
+
if H > self.img_size and W > self.img_size and random.random() <= 0.5:
|
| 845 |
+
x = self.crop(x)
|
| 846 |
+
else:
|
| 847 |
+
x = F.interpolate(
|
| 848 |
+
x,
|
| 849 |
+
size=(self.img_size, self.img_size),
|
| 850 |
+
mode="area" if H > self.img_size else "bicubic",
|
| 851 |
+
)
|
| 852 |
+
|
| 853 |
+
x = self.patch_embed(x)
|
| 854 |
+
|
| 855 |
+
with torch.cuda.amp.autocast(enabled=False):
|
| 856 |
+
x = torch.cat((self.cls_token.expand(x.shape[0], -1, -1), x.float()), dim=1)
|
| 857 |
+
x = x + self.pos_embed
|
| 858 |
+
activations = [(x[:, 1:] + x[:, :1]).transpose_(1, 2)]
|
| 859 |
+
for i, b in enumerate(self.blocks):
|
| 860 |
+
if not grad_ckpt:
|
| 861 |
+
x = b(x)
|
| 862 |
+
else:
|
| 863 |
+
x = torch.utils.checkpoint.checkpoint(b, x, use_reentrant=False)
|
| 864 |
+
if i in self.key_depths:
|
| 865 |
+
activations.append((x[:, 1:].float() + x[:, :1].float()).transpose_(1, 2))
|
| 866 |
+
return activations
|
| 867 |
+
|
| 868 |
+
|
| 869 |
+
class DinoDisc(nn.Module):
|
| 870 |
+
def __init__(
|
| 871 |
+
self,
|
| 872 |
+
dino_ckpt_path="https://dl.fbaipublicfiles.com/dino/dino_deitsmall16_pretrain/dino_deitsmall16_pretrain.pth",
|
| 873 |
+
device="cuda",
|
| 874 |
+
ks=9,
|
| 875 |
+
depth=12,
|
| 876 |
+
key_depths=(2, 5, 8, 11),
|
| 877 |
+
norm_type="bn",
|
| 878 |
+
using_spec_norm=True,
|
| 879 |
+
norm_eps=1e-6,
|
| 880 |
+
):
|
| 881 |
+
super().__init__()
|
| 882 |
+
# load state
|
| 883 |
+
state = torch.hub.load_state_dict_from_url(dino_ckpt_path, map_location="cpu")
|
| 884 |
+
for k in sorted(state.keys()):
|
| 885 |
+
if ".attn.qkv.bias" in k:
|
| 886 |
+
bias = state[k]
|
| 887 |
+
C = bias.numel() // 3
|
| 888 |
+
bias[C : 2 * C].zero_() # zero out k_bias
|
| 889 |
+
|
| 890 |
+
key_depths = tuple(d for d in key_depths if d < depth)
|
| 891 |
+
d = FrozenDINOSmallNoDrop(depth=depth, key_depths=key_depths, norm_eps=norm_eps)
|
| 892 |
+
missing, unexpected = d.load_state_dict(state, strict=False)
|
| 893 |
+
missing = [
|
| 894 |
+
m
|
| 895 |
+
for m in missing
|
| 896 |
+
if all(x not in m for x in {"x_scale", "x_shift"})
|
| 897 |
+
]
|
| 898 |
+
if torch.cuda.is_available():
|
| 899 |
+
assert len(missing) == 0, f"missing keys: {missing}"
|
| 900 |
+
assert len(unexpected) == 0, f"unexpected keys: {unexpected}"
|
| 901 |
+
|
| 902 |
+
self.dino_proxy: Tuple[FrozenDINOSmallNoDrop] = (d.to(device=device),)
|
| 903 |
+
dino_C = self.dino_proxy[0].embed_dim
|
| 904 |
+
|
| 905 |
+
self.heads = nn.ModuleList(
|
| 906 |
+
[
|
| 907 |
+
nn.Sequential(
|
| 908 |
+
make_block(
|
| 909 |
+
dino_C,
|
| 910 |
+
kernel_size=1,
|
| 911 |
+
norm_type=norm_type,
|
| 912 |
+
norm_eps=norm_eps,
|
| 913 |
+
using_spec_norm=using_spec_norm,
|
| 914 |
+
),
|
| 915 |
+
ResidualBlock(
|
| 916 |
+
make_block(
|
| 917 |
+
dino_C,
|
| 918 |
+
kernel_size=ks,
|
| 919 |
+
norm_type=norm_type,
|
| 920 |
+
norm_eps=norm_eps,
|
| 921 |
+
using_spec_norm=using_spec_norm,
|
| 922 |
+
)
|
| 923 |
+
),
|
| 924 |
+
(
|
| 925 |
+
SpectralConv1d
|
| 926 |
+
if using_spec_norm
|
| 927 |
+
else nn.Conv1d
|
| 928 |
+
)(dino_C, 1, kernel_size=1, padding=0),
|
| 929 |
+
)
|
| 930 |
+
for _ in range(len(key_depths) + 1)
|
| 931 |
+
]
|
| 932 |
+
)
|
| 933 |
+
|
| 934 |
+
def reinit(
|
| 935 |
+
self,
|
| 936 |
+
dino_ckpt_path="https://dl.fbaipublicfiles.com/dino/dino_deitsmall16_pretrain/dino_deitsmall16_pretrain.pth",
|
| 937 |
+
device="cuda",
|
| 938 |
+
ks=9,
|
| 939 |
+
depth=12,
|
| 940 |
+
key_depths=(2, 5, 8, 11),
|
| 941 |
+
norm_type="bn",
|
| 942 |
+
using_spec_norm=True,
|
| 943 |
+
norm_eps=1e-6,
|
| 944 |
+
):
|
| 945 |
+
dino_C = self.dino_proxy[0].embed_dim
|
| 946 |
+
heads = nn.ModuleList(
|
| 947 |
+
[
|
| 948 |
+
nn.Sequential(
|
| 949 |
+
make_block(
|
| 950 |
+
dino_C,
|
| 951 |
+
kernel_size=1,
|
| 952 |
+
norm_type=norm_type,
|
| 953 |
+
norm_eps=norm_eps,
|
| 954 |
+
using_spec_norm=using_spec_norm,
|
| 955 |
+
),
|
| 956 |
+
ResidualBlock(
|
| 957 |
+
make_block(
|
| 958 |
+
dino_C,
|
| 959 |
+
kernel_size=ks,
|
| 960 |
+
norm_type=norm_type,
|
| 961 |
+
norm_eps=norm_eps,
|
| 962 |
+
using_spec_norm=using_spec_norm,
|
| 963 |
+
)
|
| 964 |
+
),
|
| 965 |
+
(
|
| 966 |
+
SpectralConv1d
|
| 967 |
+
if using_spec_norm
|
| 968 |
+
else nn.Conv1d
|
| 969 |
+
)(dino_C, 1, kernel_size=1, padding=0),
|
| 970 |
+
)
|
| 971 |
+
for _ in range(len(key_depths) + 1)
|
| 972 |
+
]
|
| 973 |
+
)
|
| 974 |
+
|
| 975 |
+
self.heads.load_state_dict(heads.state_dict())
|
| 976 |
+
|
| 977 |
+
def forward(self, x_in_pm1: torch.Tensor, grad_ckpt: bool = False) -> torch.Tensor:
|
| 978 |
+
# x_in_pm1: image tensor normalized to [-1, 1]
|
| 979 |
+
dino_grad_ckpt = grad_ckpt and x_in_pm1.requires_grad
|
| 980 |
+
FrozenDINOSmallNoDrop.forward
|
| 981 |
+
activations: List[torch.Tensor] = self.dino_proxy[0](
|
| 982 |
+
x_in_pm1.float(), grad_ckpt=dino_grad_ckpt
|
| 983 |
+
)
|
| 984 |
+
B = x_in_pm1.shape[0]
|
| 985 |
+
return torch.cat(
|
| 986 |
+
[
|
| 987 |
+
(
|
| 988 |
+
h(act)
|
| 989 |
+
if not grad_ckpt
|
| 990 |
+
else torch.utils.checkpoint.checkpoint(h, act, use_reentrant=False)
|
| 991 |
+
).view(B, -1)
|
| 992 |
+
for h, act in zip(self.heads, activations)
|
| 993 |
+
],
|
| 994 |
+
dim=1,
|
| 995 |
+
)
|
| 996 |
+
|
| 997 |
+
|
| 998 |
+
###############################################################################
|
| 999 |
+
# GAN loss helpers
|
| 1000 |
+
###############################################################################
|
| 1001 |
+
|
| 1002 |
+
|
| 1003 |
+
def hinge_d_loss(logits_real: torch.Tensor, logits_fake: torch.Tensor) -> torch.Tensor:
|
| 1004 |
+
loss_real = torch.mean(F.relu(1.0 - logits_real))
|
| 1005 |
+
loss_fake = torch.mean(F.relu(1.0 + logits_fake))
|
| 1006 |
+
d_loss = 0.5 * (loss_real + loss_fake)
|
| 1007 |
+
return d_loss
|
| 1008 |
+
|
| 1009 |
+
|
| 1010 |
+
def vanilla_d_loss(logits_real: torch.Tensor, logits_fake: torch.Tensor) -> torch.Tensor:
|
| 1011 |
+
loss_real = torch.mean(F.softplus(-logits_real))
|
| 1012 |
+
loss_fake = torch.mean(F.softplus(logits_fake))
|
| 1013 |
+
d_loss = loss_real + loss_fake
|
| 1014 |
+
return d_loss
|
| 1015 |
+
|
| 1016 |
+
|
| 1017 |
+
def non_saturating_d_loss(logits_real: torch.Tensor, logits_fake: torch.Tensor) -> torch.Tensor:
|
| 1018 |
+
loss_real = torch.mean(
|
| 1019 |
+
F.binary_cross_entropy_with_logits(torch.ones_like(logits_real), logits_real)
|
| 1020 |
+
)
|
| 1021 |
+
loss_fake = torch.mean(
|
| 1022 |
+
F.binary_cross_entropy_with_logits(torch.zeros_like(logits_fake), logits_fake)
|
| 1023 |
+
)
|
| 1024 |
+
d_loss = 0.5 * (loss_real + loss_fake)
|
| 1025 |
+
return d_loss
|
| 1026 |
+
|
| 1027 |
+
|
| 1028 |
+
def hinge_gen_loss(logit_fake: torch.Tensor) -> torch.Tensor:
|
| 1029 |
+
return -torch.mean(logit_fake)
|
| 1030 |
+
|
| 1031 |
+
def vanilla_gen_loss(logit_fake: torch.Tensor) -> torch.Tensor:
|
| 1032 |
+
return torch.mean(F.softplus(-logit_fake))
|
| 1033 |
+
|
| 1034 |
+
def non_saturating_gen_loss(logit_fake: torch.Tensor) -> torch.Tensor:
|
| 1035 |
+
return torch.mean(
|
| 1036 |
+
F.binary_cross_entropy_with_logits(torch.ones_like(logit_fake), logit_fake)
|
| 1037 |
+
)
|
| 1038 |
+
|
| 1039 |
+
|
| 1040 |
+
def adopt_weight(weight: float, global_step: int, threshold: int = 0, value: float = 0.0):
|
| 1041 |
+
if global_step < threshold:
|
| 1042 |
+
weight = value
|
| 1043 |
+
return weight
|
| 1044 |
+
|
| 1045 |
+
|
| 1046 |
+
class LeCAM_EMA(object):
|
| 1047 |
+
def __init__(self, init: float = 0.0, decay: float = 0.999):
|
| 1048 |
+
self.logits_real_ema = init
|
| 1049 |
+
self.logits_fake_ema = init
|
| 1050 |
+
self.decay = decay
|
| 1051 |
+
|
| 1052 |
+
def update(self, logits_real: torch.Tensor, logits_fake: torch.Tensor):
|
| 1053 |
+
self.logits_real_ema = (
|
| 1054 |
+
self.logits_real_ema * self.decay
|
| 1055 |
+
+ torch.mean(logits_real).item() * (1 - self.decay)
|
| 1056 |
+
)
|
| 1057 |
+
self.logits_fake_ema = (
|
| 1058 |
+
self.logits_fake_ema * self.decay
|
| 1059 |
+
+ torch.mean(logits_fake).item() * (1 - self.decay)
|
| 1060 |
+
)
|
| 1061 |
+
|
| 1062 |
+
|
| 1063 |
+
def lecam_reg(real_pred: torch.Tensor, fake_pred: torch.Tensor, lecam_ema: LeCAM_EMA):
|
| 1064 |
+
reg = torch.mean(F.relu(real_pred - lecam_ema.logits_fake_ema).pow(2)) + torch.mean(
|
| 1065 |
+
F.relu(lecam_ema.logits_real_ema - fake_pred).pow(2)
|
| 1066 |
+
)
|
| 1067 |
+
return reg
|
| 1068 |
+
|
| 1069 |
+
|
| 1070 |
+
###############################################################################
|
| 1071 |
+
# Combined GAN loss (generator + discriminator) with perceptual & VQ terms
|
| 1072 |
+
###############################################################################
|
| 1073 |
+
|
| 1074 |
+
|
| 1075 |
+
class GANLoss(nn.Module):
|
| 1076 |
+
"""
|
| 1077 |
+
Combined loss used for training VQ-style autoencoders with GAN objectives.
|
| 1078 |
+
|
| 1079 |
+
This is functionally similar to the original `VQLoss` but packaged so it can
|
| 1080 |
+
live in a single file together with its discriminators and LPIPS.
|
| 1081 |
+
"""
|
| 1082 |
+
|
| 1083 |
+
def __init__(
|
| 1084 |
+
self,
|
| 1085 |
+
disc_loss: str = "hinge",
|
| 1086 |
+
disc_dim: int = 64,
|
| 1087 |
+
disc_type: str = "patchgan",
|
| 1088 |
+
image_size: int = 256,
|
| 1089 |
+
disc_num_layers: int = 3,
|
| 1090 |
+
disc_in_channels: int = 3,
|
| 1091 |
+
disc_adaptive_weight: bool = False,
|
| 1092 |
+
gen_adv_loss: str = "hinge",
|
| 1093 |
+
reconstruction_loss: str = "l2",
|
| 1094 |
+
reconstruction_weight: float = 1.0,
|
| 1095 |
+
codebook_weight: float = 1.0,
|
| 1096 |
+
perceptual_weight: float = 1.0,
|
| 1097 |
+
lecam_loss_weight: float = None,
|
| 1098 |
+
norm_type: str = "bn",
|
| 1099 |
+
aug_prob: float = 1.0,
|
| 1100 |
+
):
|
| 1101 |
+
super().__init__()
|
| 1102 |
+
# discriminator type & architecture
|
| 1103 |
+
assert disc_type in ["patchgan", "stylegan", "dinodisc"]
|
| 1104 |
+
assert disc_loss in ["hinge", "vanilla", "non-saturating"]
|
| 1105 |
+
self.disc_type = disc_type
|
| 1106 |
+
if disc_type == "patchgan":
|
| 1107 |
+
self.discriminator = NLayerDiscriminator(
|
| 1108 |
+
input_nc=disc_in_channels,
|
| 1109 |
+
n_layers=disc_num_layers,
|
| 1110 |
+
ndf=disc_dim,
|
| 1111 |
+
)
|
| 1112 |
+
elif disc_type == "stylegan":
|
| 1113 |
+
self.discriminator = StyleGANDiscriminator(
|
| 1114 |
+
input_nc=disc_in_channels,
|
| 1115 |
+
image_size=image_size,
|
| 1116 |
+
)
|
| 1117 |
+
elif disc_type == "dinodisc":
|
| 1118 |
+
self.discriminator = DinoDisc(norm_type=norm_type) # default 224 otherwise crop
|
| 1119 |
+
self.daug = DiffAug(prob=aug_prob, cutout=0.2)
|
| 1120 |
+
else:
|
| 1121 |
+
raise ValueError(f"Unknown GAN discriminator type '{disc_type}'.")
|
| 1122 |
+
|
| 1123 |
+
if disc_loss == "hinge":
|
| 1124 |
+
self.disc_loss = hinge_d_loss
|
| 1125 |
+
elif disc_loss == "vanilla":
|
| 1126 |
+
self.disc_loss = vanilla_d_loss
|
| 1127 |
+
elif disc_loss == "non-saturating":
|
| 1128 |
+
self.disc_loss = non_saturating_d_loss
|
| 1129 |
+
else:
|
| 1130 |
+
raise ValueError(f"Unknown GAN discriminator loss '{disc_loss}'.")
|
| 1131 |
+
|
| 1132 |
+
|
| 1133 |
+
# generator adversarial loss
|
| 1134 |
+
if gen_adv_loss == "hinge":
|
| 1135 |
+
self.gen_adv_loss = hinge_gen_loss
|
| 1136 |
+
elif gen_adv_loss == "non-saturating":
|
| 1137 |
+
self.gen_adv_loss = non_saturating_gen_loss
|
| 1138 |
+
elif gen_adv_loss == 'vanilla':
|
| 1139 |
+
self.gen_adv_loss = vanilla_gen_loss
|
| 1140 |
+
else:
|
| 1141 |
+
raise ValueError(f"Unknown GAN generator loss '{gen_adv_loss}'.")
|
| 1142 |
+
|
| 1143 |
+
# perceptual loss
|
| 1144 |
+
self.perceptual_loss = LPIPS().eval()
|
| 1145 |
+
self.perceptual_weight = perceptual_weight
|
| 1146 |
+
|
| 1147 |
+
# reconstruction loss
|
| 1148 |
+
if reconstruction_loss == "l1":
|
| 1149 |
+
self.rec_loss = F.l1_loss
|
| 1150 |
+
elif reconstruction_loss == "l2":
|
| 1151 |
+
self.rec_loss = F.mse_loss
|
| 1152 |
+
else:
|
| 1153 |
+
raise ValueError(f"Unknown rec loss '{reconstruction_loss}'.")
|
| 1154 |
+
self.rec_weight = reconstruction_weight
|
| 1155 |
+
|
| 1156 |
+
# codebook loss weight (used externally when aggregating)
|
| 1157 |
+
self.codebook_weight = codebook_weight
|
| 1158 |
+
|
| 1159 |
+
# LeCAM regularization
|
| 1160 |
+
self.lecam_loss_weight = lecam_loss_weight
|
| 1161 |
+
if self.lecam_loss_weight is not None:
|
| 1162 |
+
self.lecam_ema = LeCAM_EMA()
|
| 1163 |
+
|
| 1164 |
+
def calculate_adaptive_weight(self, nll_loss, g_loss, last_layer):
|
| 1165 |
+
with fabric.no_backward_sync(last_layer):
|
| 1166 |
+
nll_grads = torch.autograd.grad(nll_loss, last_layer, retain_graph=True)[0]
|
| 1167 |
+
g_grads = torch.autograd.grad(g_loss, last_layer, retain_graph=True)[0]
|
| 1168 |
+
|
| 1169 |
+
d_weight = torch.norm(nll_grads) / (torch.norm(g_grads) + 1e-4)
|
| 1170 |
+
d_weight = torch.clamp(d_weight, 0.0, 1e4).detach()
|
| 1171 |
+
return d_weight.detach()
|
| 1172 |
+
|
| 1173 |
+
def forward(
|
| 1174 |
+
self,
|
| 1175 |
+
x,
|
| 1176 |
+
x_hat,
|
| 1177 |
+
global_step,
|
| 1178 |
+
loss='G'
|
| 1179 |
+
):
|
| 1180 |
+
"""
|
| 1181 |
+
Args are kept compatible with the original `VQLoss` for drop-in usage.
|
| 1182 |
+
|
| 1183 |
+
optimizer_idx = 0: generator (autoencoder) update
|
| 1184 |
+
optimizer_idx = 1: discriminator update
|
| 1185 |
+
"""
|
| 1186 |
+
# generator update
|
| 1187 |
+
if loss == 'G':
|
| 1188 |
+
# discriminator loss (for generator)
|
| 1189 |
+
if self.disc_type == "dinodisc":
|
| 1190 |
+
if fade_blur_schedule < 1e-6:
|
| 1191 |
+
fade_blur_schedule = 0.0
|
| 1192 |
+
logits_fake = self.discriminator(
|
| 1193 |
+
self.daug.aug(x_hat.contiguous(), fade_blur_schedule)
|
| 1194 |
+
)
|
| 1195 |
+
else:
|
| 1196 |
+
logits_fake = self.discriminator(x_hat.contiguous())
|
| 1197 |
+
generator_adv_loss = self.gen_adv_loss(logits_fake)
|
| 1198 |
+
|
| 1199 |
+
loss = generator_adv_loss
|
| 1200 |
+
return (loss,{'gen_G_loss_vanilla':generator_adv_loss.item()})
|
| 1201 |
+
|
| 1202 |
+
# discriminator update
|
| 1203 |
+
if loss == 'D':
|
| 1204 |
+
if self.disc_type == "dinodisc":
|
| 1205 |
+
logits_fake = self.discriminator(
|
| 1206 |
+
self.daug.aug(x_hat.contiguous().detach(), 0.)
|
| 1207 |
+
)
|
| 1208 |
+
logits_real = self.discriminator(
|
| 1209 |
+
self.daug.aug(x.contiguous().detach(), 0.)
|
| 1210 |
+
)
|
| 1211 |
+
else:
|
| 1212 |
+
logits_fake = self.discriminator(x_hat.contiguous().detach())
|
| 1213 |
+
logits_real = self.discriminator(x.contiguous().detach())
|
| 1214 |
+
|
| 1215 |
+
|
| 1216 |
+
|
| 1217 |
+
if self.lecam_loss_weight is not None:
|
| 1218 |
+
self.lecam_ema.update(logits_real, logits_fake)
|
| 1219 |
+
lecam_loss = self.lecam_loss_weight * lecam_reg(logits_real, logits_fake, self.lecam_ema)
|
| 1220 |
+
non_saturate_d = self.disc_loss(logits_real, logits_fake)
|
| 1221 |
+
d_adversarial_loss = lecam_loss + non_saturate_d
|
| 1222 |
+
|
| 1223 |
+
else:
|
| 1224 |
+
d_adversarial_loss = self.disc_weight * self.disc_loss(logits_real, logits_fake)
|
| 1225 |
+
|
| 1226 |
+
logits_real_log = logits_real.detach()
|
| 1227 |
+
logits_fake_log = logits_fake.detach()
|
| 1228 |
+
|
| 1229 |
+
return (d_adversarial_loss, { "disc_loss":non_saturate_d.item(), "lecam_loss": lecam_loss.item(), "prob_real":logits_real_log.sigmoid().mean().item(), "prob_fake":logits_fake_log.sigmoid().mean().item()})
|
lpips.py
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Stripped version of https://github.com/richzhang/PerceptualSimilarity/tree/master/models"""
|
| 2 |
+
|
| 3 |
+
import os, hashlib
|
| 4 |
+
import requests
|
| 5 |
+
from tqdm import tqdm
|
| 6 |
+
|
| 7 |
+
import torch
|
| 8 |
+
import torch.nn as nn
|
| 9 |
+
from torchvision import models
|
| 10 |
+
from collections import namedtuple
|
| 11 |
+
|
| 12 |
+
URL_MAP = {
|
| 13 |
+
"vgg_lpips": "https://heibox.uni-heidelberg.de/f/607503859c864bc1b30b/?dl=1"
|
| 14 |
+
}
|
| 15 |
+
|
| 16 |
+
CKPT_MAP = {
|
| 17 |
+
"vgg_lpips": "vgg.pth"
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
MD5_MAP = {
|
| 21 |
+
"vgg_lpips": "d507d7349b931f0638a25a48a722f98a"
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
def download(url, local_path, chunk_size=1024):
|
| 25 |
+
os.makedirs(os.path.split(local_path)[0], exist_ok=True)
|
| 26 |
+
with requests.get(url, stream=True) as r:
|
| 27 |
+
total_size = int(r.headers.get("content-length", 0))
|
| 28 |
+
with tqdm(total=total_size, unit="B", unit_scale=True) as pbar:
|
| 29 |
+
with open(local_path, "wb") as f:
|
| 30 |
+
for data in r.iter_content(chunk_size=chunk_size):
|
| 31 |
+
if data:
|
| 32 |
+
f.write(data)
|
| 33 |
+
pbar.update(chunk_size)
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def md5_hash(path):
|
| 37 |
+
with open(path, "rb") as f:
|
| 38 |
+
content = f.read()
|
| 39 |
+
return hashlib.md5(content).hexdigest()
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
def get_ckpt_path(name, root, check=False):
|
| 43 |
+
assert name in URL_MAP
|
| 44 |
+
path = os.path.join(root, CKPT_MAP[name])
|
| 45 |
+
if not os.path.exists(path) or (check and not md5_hash(path) == MD5_MAP[name]):
|
| 46 |
+
print("Downloading {} model from {} to {}".format(name, URL_MAP[name], path))
|
| 47 |
+
download(URL_MAP[name], path)
|
| 48 |
+
md5 = md5_hash(path)
|
| 49 |
+
assert md5 == MD5_MAP[name], md5
|
| 50 |
+
return path
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
class LPIPS(nn.Module):
|
| 54 |
+
# Learned perceptual metric
|
| 55 |
+
def __init__(self, use_dropout=True):
|
| 56 |
+
super().__init__()
|
| 57 |
+
self.scaling_layer = ScalingLayer()
|
| 58 |
+
self.chns = [64, 128, 256, 512, 512] # vg16 features
|
| 59 |
+
self.net = vgg16(pretrained=True, requires_grad=False)
|
| 60 |
+
self.lin0 = NetLinLayer(self.chns[0], use_dropout=use_dropout)
|
| 61 |
+
self.lin1 = NetLinLayer(self.chns[1], use_dropout=use_dropout)
|
| 62 |
+
self.lin2 = NetLinLayer(self.chns[2], use_dropout=use_dropout)
|
| 63 |
+
self.lin3 = NetLinLayer(self.chns[3], use_dropout=use_dropout)
|
| 64 |
+
self.lin4 = NetLinLayer(self.chns[4], use_dropout=use_dropout)
|
| 65 |
+
self.load_from_pretrained()
|
| 66 |
+
for param in self.parameters():
|
| 67 |
+
param.requires_grad = False
|
| 68 |
+
|
| 69 |
+
def load_from_pretrained(self, name="vgg_lpips"):
|
| 70 |
+
ckpt = get_ckpt_path(name, os.path.join(os.path.dirname(os.path.abspath(__file__)), "cache"))
|
| 71 |
+
self.load_state_dict(torch.load(ckpt, map_location=torch.device("cpu")), strict=False)
|
| 72 |
+
print("loaded pretrained LPIPS loss from {}".format(ckpt))
|
| 73 |
+
|
| 74 |
+
@classmethod
|
| 75 |
+
def from_pretrained(cls, name="vgg_lpips"):
|
| 76 |
+
if name != "vgg_lpips":
|
| 77 |
+
raise NotImplementedError
|
| 78 |
+
model = cls()
|
| 79 |
+
ckpt = get_ckpt_path(name, os.path.join(os.path.dirname(os.path.abspath(__file__)), "cache"))
|
| 80 |
+
model.load_state_dict(torch.load(ckpt, map_location=torch.device("cpu")), strict=False)
|
| 81 |
+
return model
|
| 82 |
+
|
| 83 |
+
def forward(self, input, target):
|
| 84 |
+
in0_input, in1_input = (self.scaling_layer(input), self.scaling_layer(target))
|
| 85 |
+
outs0, outs1 = self.net(in0_input), self.net(in1_input)
|
| 86 |
+
feats0, feats1, diffs = {}, {}, {}
|
| 87 |
+
lins = [self.lin0, self.lin1, self.lin2, self.lin3, self.lin4]
|
| 88 |
+
for kk in range(len(self.chns)):
|
| 89 |
+
feats0[kk], feats1[kk] = normalize_tensor(outs0[kk]), normalize_tensor(outs1[kk])
|
| 90 |
+
diffs[kk] = (feats0[kk] - feats1[kk]) ** 2
|
| 91 |
+
|
| 92 |
+
res = [spatial_average(lins[kk].model(diffs[kk]), keepdim=True) for kk in range(len(self.chns))]
|
| 93 |
+
val = res[0]
|
| 94 |
+
for l in range(1, len(self.chns)):
|
| 95 |
+
val += res[l]
|
| 96 |
+
return val
|
| 97 |
+
|
| 98 |
+
|
| 99 |
+
class ScalingLayer(nn.Module):
|
| 100 |
+
def __init__(self):
|
| 101 |
+
super(ScalingLayer, self).__init__()
|
| 102 |
+
self.register_buffer('shift', torch.Tensor([-.030, -.088, -.188])[None, :, None, None])
|
| 103 |
+
self.register_buffer('scale', torch.Tensor([.458, .448, .450])[None, :, None, None])
|
| 104 |
+
|
| 105 |
+
def forward(self, inp):
|
| 106 |
+
return (inp - self.shift) / self.scale
|
| 107 |
+
|
| 108 |
+
|
| 109 |
+
class NetLinLayer(nn.Module):
|
| 110 |
+
""" A single linear layer which does a 1x1 conv """
|
| 111 |
+
def __init__(self, chn_in, chn_out=1, use_dropout=False):
|
| 112 |
+
super(NetLinLayer, self).__init__()
|
| 113 |
+
layers = [nn.Dropout(), ] if (use_dropout) else []
|
| 114 |
+
layers += [nn.Conv2d(chn_in, chn_out, 1, stride=1, padding=0, bias=False), ]
|
| 115 |
+
self.model = nn.Sequential(*layers)
|
| 116 |
+
|
| 117 |
+
|
| 118 |
+
class vgg16(torch.nn.Module):
|
| 119 |
+
def __init__(self, requires_grad=False, pretrained=True):
|
| 120 |
+
super(vgg16, self).__init__()
|
| 121 |
+
vgg_pretrained_features = models.vgg16(pretrained=pretrained).features
|
| 122 |
+
self.slice1 = torch.nn.Sequential()
|
| 123 |
+
self.slice2 = torch.nn.Sequential()
|
| 124 |
+
self.slice3 = torch.nn.Sequential()
|
| 125 |
+
self.slice4 = torch.nn.Sequential()
|
| 126 |
+
self.slice5 = torch.nn.Sequential()
|
| 127 |
+
self.N_slices = 5
|
| 128 |
+
for x in range(4):
|
| 129 |
+
self.slice1.add_module(str(x), vgg_pretrained_features[x])
|
| 130 |
+
for x in range(4, 9):
|
| 131 |
+
self.slice2.add_module(str(x), vgg_pretrained_features[x])
|
| 132 |
+
for x in range(9, 16):
|
| 133 |
+
self.slice3.add_module(str(x), vgg_pretrained_features[x])
|
| 134 |
+
for x in range(16, 23):
|
| 135 |
+
self.slice4.add_module(str(x), vgg_pretrained_features[x])
|
| 136 |
+
for x in range(23, 30):
|
| 137 |
+
self.slice5.add_module(str(x), vgg_pretrained_features[x])
|
| 138 |
+
if not requires_grad:
|
| 139 |
+
for param in self.parameters():
|
| 140 |
+
param.requires_grad = False
|
| 141 |
+
|
| 142 |
+
def forward(self, X):
|
| 143 |
+
h = self.slice1(X)
|
| 144 |
+
h_relu1_2 = h
|
| 145 |
+
h = self.slice2(h)
|
| 146 |
+
h_relu2_2 = h
|
| 147 |
+
h = self.slice3(h)
|
| 148 |
+
h_relu3_3 = h
|
| 149 |
+
h = self.slice4(h)
|
| 150 |
+
h_relu4_3 = h
|
| 151 |
+
h = self.slice5(h)
|
| 152 |
+
h_relu5_3 = h
|
| 153 |
+
vgg_outputs = namedtuple("VggOutputs", ['relu1_2', 'relu2_2', 'relu3_3', 'relu4_3', 'relu5_3'])
|
| 154 |
+
out = vgg_outputs(h_relu1_2, h_relu2_2, h_relu3_3, h_relu4_3, h_relu5_3)
|
| 155 |
+
return out
|
| 156 |
+
|
| 157 |
+
|
| 158 |
+
def normalize_tensor(x,eps=1e-10):
|
| 159 |
+
norm_factor = torch.sqrt(torch.sum(x**2,dim=1,keepdim=True))
|
| 160 |
+
return x/(norm_factor+eps)
|
| 161 |
+
|
| 162 |
+
|
| 163 |
+
def spatial_average(x, keepdim=True):
|
| 164 |
+
return x.mean([2,3],keepdim=keepdim)
|
models.py
ADDED
|
@@ -0,0 +1,1013 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import math
|
| 2 |
+
from math import pi
|
| 3 |
+
|
| 4 |
+
import torch
|
| 5 |
+
import torch.nn as nn
|
| 6 |
+
from torch import einsum, broadcast_tensors, Tensor
|
| 7 |
+
import torch.nn.functional as F
|
| 8 |
+
from torch.nn import Module
|
| 9 |
+
from torch.amp import autocast
|
| 10 |
+
from torch import nn
|
| 11 |
+
from einops import rearrange, repeat
|
| 12 |
+
import einops
|
| 13 |
+
import numpy as np
|
| 14 |
+
import os
|
| 15 |
+
import copy
|
| 16 |
+
|
| 17 |
+
# Well Inited Linear
|
| 18 |
+
def weight_init(shape, mode, fan_in, fan_out):
|
| 19 |
+
if mode == 'xavier_uniform': return np.sqrt(6 / (fan_in + fan_out)) * (torch.rand(*shape) * 2 - 1)
|
| 20 |
+
if mode == 'xavier_normal': return np.sqrt(2 / (fan_in + fan_out)) * torch.randn(*shape)
|
| 21 |
+
if mode == 'kaiming_uniform': return np.sqrt(3 / fan_in) * (torch.rand(*shape) * 2 - 1)
|
| 22 |
+
if mode == 'kaiming_normal': return np.sqrt(1 / fan_in) * torch.randn(*shape)
|
| 23 |
+
if mode == 'uniform': return torch.rand() * 2 - 1
|
| 24 |
+
raise ValueError(f'Invalid init mode "{mode}"')
|
| 25 |
+
|
| 26 |
+
class Linear(torch.nn.Module):
|
| 27 |
+
def __init__(self, in_features, out_features, bias=True, init_mode='kaiming_uniform', init_weight=1, init_bias=0):
|
| 28 |
+
super().__init__()
|
| 29 |
+
self.in_features = in_features
|
| 30 |
+
self.out_features = out_features
|
| 31 |
+
init_kwargs = dict(mode=init_mode, fan_in=in_features, fan_out=out_features)
|
| 32 |
+
self.weight = torch.nn.Parameter(weight_init([out_features, in_features], **init_kwargs) * init_weight)
|
| 33 |
+
self.bias = torch.nn.Parameter(weight_init([out_features], **init_kwargs) * init_bias) if bias else None
|
| 34 |
+
|
| 35 |
+
def forward(self, x):
|
| 36 |
+
x = x @ self.weight.to(x.dtype).t()
|
| 37 |
+
if self.bias is not None:
|
| 38 |
+
x = x.add_(self.bias.to(x.dtype))
|
| 39 |
+
return x
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
class AdaRMSNorm(nn.Module):
|
| 43 |
+
def __init__(self,dim, cond_dim=None, elementwise_affine=True, cond_based_affine=True, centering=False, eps=None):
|
| 44 |
+
super(AdaRMSNorm, self).__init__()
|
| 45 |
+
self.dim = dim
|
| 46 |
+
self.eps = eps
|
| 47 |
+
self.cond_based_affine = cond_based_affine
|
| 48 |
+
self.elementwise_affine = elementwise_affine
|
| 49 |
+
self.centering = centering
|
| 50 |
+
assert not(cond_dim is None and cond_based_affine), 'cond_dim must be provided if cond_based_affine is True'
|
| 51 |
+
if elementwise_affine:
|
| 52 |
+
if cond_based_affine and cond_dim is not None:
|
| 53 |
+
self.affine = Linear(cond_dim, dim, init_weight=1e-5)
|
| 54 |
+
else:
|
| 55 |
+
self.weight = nn.Parameter(torch.ones(self.dim))
|
| 56 |
+
else:
|
| 57 |
+
self.register_parameter("weight", None)
|
| 58 |
+
|
| 59 |
+
def forward(self, x, cond_emb=None):
|
| 60 |
+
eps = torch.finfo(x.dtype).eps if self.eps is None else self.eps
|
| 61 |
+
rms = torch.rsqrt(torch.square(x).mean(dim=-1, keepdim=True) + eps)
|
| 62 |
+
out = ((x - x.mean(dim=-1, keepdim=True)) * rms) if self.centering else (x * rms)
|
| 63 |
+
if self.elementwise_affine:
|
| 64 |
+
if self.cond_based_affine:
|
| 65 |
+
out = out.mul(1. + self.affine(cond_emb).unsqueeze(1))
|
| 66 |
+
else:
|
| 67 |
+
out = out.mul(self.weight)
|
| 68 |
+
return out
|
| 69 |
+
|
| 70 |
+
class AdaLN(nn.Module):
|
| 71 |
+
def __init__(self,dim, cond_dim=None, elementwise_affine=True, cond_based_affine=True, bias=False):
|
| 72 |
+
super(AdaLN, self).__init__()
|
| 73 |
+
self.norm = nn.LayerNorm(dim, elementwise_affine=elementwise_affine and not cond_based_affine)
|
| 74 |
+
self.cond_based_affine = cond_based_affine
|
| 75 |
+
self.bias = bias
|
| 76 |
+
assert not(cond_dim is None and cond_based_affine), 'cond_dim must be provided if cond_based_affine is True'
|
| 77 |
+
self.affine = Linear(cond_dim, 2 * dim if bias else dim, init_weight=1e-5) if cond_based_affine and cond_dim is not None else None
|
| 78 |
+
def forward(self, x, cond_emb=None):
|
| 79 |
+
x = self.norm(x)
|
| 80 |
+
if self.cond_based_affine:
|
| 81 |
+
if self.bias:
|
| 82 |
+
shift, scale = self.affine(cond_emb).unsqueeze(1).chunk(2, dim=-1)
|
| 83 |
+
x = x.mul(1. + scale).add_(shift)
|
| 84 |
+
else:
|
| 85 |
+
scale = self.affine(cond_emb).unsqueeze(1)
|
| 86 |
+
x = x.mul(1. + scale)
|
| 87 |
+
return x
|
| 88 |
+
|
| 89 |
+
class TimestepEmbedder(nn.Module):
|
| 90 |
+
"""
|
| 91 |
+
Embeds scalar timesteps into vector representations.
|
| 92 |
+
"""
|
| 93 |
+
def __init__(self, hidden_size, frequency_embedding_size=256):
|
| 94 |
+
super().__init__()
|
| 95 |
+
self.mlp = nn.Sequential(
|
| 96 |
+
Linear(frequency_embedding_size, hidden_size, init_weight=1e-5),
|
| 97 |
+
nn.SiLU(),
|
| 98 |
+
Linear(hidden_size, hidden_size, init_weight=1e-5),
|
| 99 |
+
)
|
| 100 |
+
self.frequency_embedding_size = frequency_embedding_size
|
| 101 |
+
|
| 102 |
+
@staticmethod
|
| 103 |
+
def timestep_embedding(t, dim, max_period=10000):
|
| 104 |
+
"""
|
| 105 |
+
Create sinusoidal timestep embeddings.
|
| 106 |
+
:param t: a 1-D Tensor of N indices, one per batch element.
|
| 107 |
+
These may be fractional.
|
| 108 |
+
:param dim: the dimension of the output.
|
| 109 |
+
:param max_period: controls the minimum frequency of the embeddings.
|
| 110 |
+
:return: an (N, D) Tensor of positional embeddings.
|
| 111 |
+
"""
|
| 112 |
+
# https://github.com/openai/glide-text2im/blob/main/glide_text2im/nn.py
|
| 113 |
+
half = dim // 2
|
| 114 |
+
freqs = torch.exp(
|
| 115 |
+
-math.log(max_period) * torch.arange(start=0, end=half, dtype=torch.float32) / half
|
| 116 |
+
).to(device=t.device)
|
| 117 |
+
args = t[:, None].float() * freqs[None]
|
| 118 |
+
embedding = torch.cat([torch.cos(args), torch.sin(args)], dim=-1)
|
| 119 |
+
if dim % 2:
|
| 120 |
+
embedding = torch.cat([embedding, torch.zeros_like(embedding[:, :1])], dim=-1)
|
| 121 |
+
return embedding
|
| 122 |
+
|
| 123 |
+
def forward(self, t):
|
| 124 |
+
t_freq = self.timestep_embedding(t, self.frequency_embedding_size)
|
| 125 |
+
t_emb = self.mlp(t_freq)
|
| 126 |
+
return t_emb
|
| 127 |
+
|
| 128 |
+
# ROPE
|
| 129 |
+
def exists(val):
|
| 130 |
+
return val is not None
|
| 131 |
+
|
| 132 |
+
def default(val, d):
|
| 133 |
+
return val if exists(val) else d
|
| 134 |
+
|
| 135 |
+
def broadcat(tensors, dim = -1):
|
| 136 |
+
broadcasted_tensors = broadcast_tensors(*tensors)
|
| 137 |
+
return torch.cat(broadcasted_tensors, dim = dim)
|
| 138 |
+
|
| 139 |
+
def slice_at_dim(t, dim_slice: slice, *, dim):
|
| 140 |
+
dim += (t.ndim if dim < 0 else 0)
|
| 141 |
+
colons = [slice(None)] * t.ndim
|
| 142 |
+
colons[dim] = dim_slice
|
| 143 |
+
return t[tuple(colons)]
|
| 144 |
+
|
| 145 |
+
def rotate_half(x):
|
| 146 |
+
x = rearrange(x, '... (d r) -> ... d r', r = 2)
|
| 147 |
+
x1, x2 = x.unbind(dim = -1)
|
| 148 |
+
x = torch.stack((-x2, x1), dim = -1)
|
| 149 |
+
return rearrange(x, '... d r -> ... (d r)')
|
| 150 |
+
|
| 151 |
+
def apply_rotary_emb(
|
| 152 |
+
freqs,
|
| 153 |
+
t,
|
| 154 |
+
start_index = 0,
|
| 155 |
+
scale = 1.,
|
| 156 |
+
seq_dim = -2,
|
| 157 |
+
freqs_seq_dim = None
|
| 158 |
+
):
|
| 159 |
+
dtype = t.dtype
|
| 160 |
+
with torch.amp.autocast('cuda',enabled=False):
|
| 161 |
+
freqs = freqs.float()
|
| 162 |
+
t = t.float()
|
| 163 |
+
if not exists(freqs_seq_dim):
|
| 164 |
+
if freqs.ndim == 2 or t.ndim == 3:
|
| 165 |
+
freqs_seq_dim = 0
|
| 166 |
+
|
| 167 |
+
if t.ndim == 3 or exists(freqs_seq_dim):
|
| 168 |
+
seq_len = t.shape[seq_dim]
|
| 169 |
+
freqs = slice_at_dim(freqs, slice(-seq_len, None), dim = freqs_seq_dim)
|
| 170 |
+
|
| 171 |
+
rot_dim = freqs.shape[-1]
|
| 172 |
+
end_index = start_index + rot_dim
|
| 173 |
+
|
| 174 |
+
assert rot_dim <= t.shape[-1], f'feature dimension {t.shape[-1]} is not of sufficient size to rotate in all the positions {rot_dim}'
|
| 175 |
+
|
| 176 |
+
# Split t into three parts: left, middle (to be transformed), and right
|
| 177 |
+
t_left = t[..., :start_index]
|
| 178 |
+
t_middle = t[..., start_index:end_index]
|
| 179 |
+
t_right = t[..., end_index:]
|
| 180 |
+
|
| 181 |
+
# Apply rotary embeddings without modifying t in place
|
| 182 |
+
t_transformed = (t_middle * freqs.cos() * scale) + (rotate_half(t_middle) * freqs.sin() * scale)
|
| 183 |
+
|
| 184 |
+
out = torch.cat((t_left, t_transformed, t_right), dim=-1)
|
| 185 |
+
|
| 186 |
+
return out.type(dtype)
|
| 187 |
+
|
| 188 |
+
def apply_learned_rotations(rotations, t, start_index = 0, freq_ranges = None):
|
| 189 |
+
if exists(freq_ranges):
|
| 190 |
+
rotations = einsum('..., f -> ... f', rotations, freq_ranges)
|
| 191 |
+
rotations = rearrange(rotations, '... r f -> ... (r f)')
|
| 192 |
+
|
| 193 |
+
rotations = repeat(rotations, '... n -> ... (n r)', r = 2)
|
| 194 |
+
return apply_rotary_emb(rotations, t, start_index = start_index)
|
| 195 |
+
|
| 196 |
+
class RotaryEmbedding(Module):
|
| 197 |
+
def __init__(
|
| 198 |
+
self,
|
| 199 |
+
dim,
|
| 200 |
+
custom_freqs= None,
|
| 201 |
+
freqs_for= 'lang',
|
| 202 |
+
theta = 10000,
|
| 203 |
+
max_freq = 10,
|
| 204 |
+
num_freqs = 1,
|
| 205 |
+
learned_freq = False,
|
| 206 |
+
use_xpos = True,
|
| 207 |
+
xpos_scale_base = 512,
|
| 208 |
+
interpolate_factor = 1.,
|
| 209 |
+
theta_rescale_factor = 1.,
|
| 210 |
+
seq_before_head_dim = False,
|
| 211 |
+
cache_if_possible = True,
|
| 212 |
+
cache_max_seq_len = 8192
|
| 213 |
+
):
|
| 214 |
+
super().__init__()
|
| 215 |
+
theta *= theta_rescale_factor ** (dim / (dim - 2))
|
| 216 |
+
|
| 217 |
+
self.freqs_for = freqs_for
|
| 218 |
+
|
| 219 |
+
if exists(custom_freqs):
|
| 220 |
+
freqs = custom_freqs
|
| 221 |
+
elif freqs_for == 'lang':
|
| 222 |
+
freqs = 1. / (theta ** (torch.arange(0, dim, 2)[:(dim // 2)].float() / dim))
|
| 223 |
+
elif freqs_for == 'pixel':
|
| 224 |
+
freqs = torch.linspace(1., max_freq / 2, dim // 2) * pi
|
| 225 |
+
elif freqs_for == 'constant':
|
| 226 |
+
freqs = torch.ones(num_freqs).float()
|
| 227 |
+
|
| 228 |
+
self.cache_if_possible = cache_if_possible
|
| 229 |
+
self.cache_max_seq_len = cache_max_seq_len
|
| 230 |
+
|
| 231 |
+
self.register_buffer('cached_freqs', torch.zeros(cache_max_seq_len, dim), persistent = False)
|
| 232 |
+
self.cached_freqs_seq_len = 0
|
| 233 |
+
|
| 234 |
+
self.freqs = nn.Parameter(freqs, requires_grad = learned_freq)
|
| 235 |
+
|
| 236 |
+
self.learned_freq = learned_freq
|
| 237 |
+
|
| 238 |
+
|
| 239 |
+
# dummy for device
|
| 240 |
+
self.register_buffer('dummy', torch.tensor(0), persistent = False)
|
| 241 |
+
|
| 242 |
+
# default sequence dimension
|
| 243 |
+
self.seq_before_head_dim = seq_before_head_dim
|
| 244 |
+
self.default_seq_dim = -3 if seq_before_head_dim else -2
|
| 245 |
+
|
| 246 |
+
# interpolation factors
|
| 247 |
+
assert interpolate_factor >= 1.
|
| 248 |
+
self.interpolate_factor = interpolate_factor
|
| 249 |
+
|
| 250 |
+
# xpos
|
| 251 |
+
self.use_xpos = use_xpos
|
| 252 |
+
|
| 253 |
+
if not use_xpos:
|
| 254 |
+
return
|
| 255 |
+
|
| 256 |
+
scale = (torch.arange(0, dim, 2) + 0.4 * dim) / (1.4 * dim)
|
| 257 |
+
self.scale_base = xpos_scale_base
|
| 258 |
+
|
| 259 |
+
self.register_buffer('scale', scale, persistent = False)
|
| 260 |
+
self.register_buffer('cached_scales', torch.zeros(cache_max_seq_len, dim), persistent = False)
|
| 261 |
+
self.cached_scales_seq_len = 0
|
| 262 |
+
|
| 263 |
+
|
| 264 |
+
|
| 265 |
+
@property
|
| 266 |
+
def device(self):
|
| 267 |
+
return self.dummy.device
|
| 268 |
+
|
| 269 |
+
def get_seq_pos(self, seq_len, device, dtype, offset = 0):
|
| 270 |
+
return (torch.arange(seq_len, device = device, dtype = dtype) + offset) / self.interpolate_factor
|
| 271 |
+
|
| 272 |
+
def rotate_queries_or_keys(self, t, seq_dim = None, offset = 0, scale = None):
|
| 273 |
+
seq_dim = default(seq_dim, self.default_seq_dim)
|
| 274 |
+
|
| 275 |
+
assert not self.use_xpos or exists(scale), 'you must use `.rotate_queries_and_keys` method instead and pass in both queries and keys, for length extrapolatable rotary embeddings'
|
| 276 |
+
|
| 277 |
+
device, dtype, seq_len = t.device, t.dtype, t.shape[seq_dim]
|
| 278 |
+
|
| 279 |
+
seq = self.get_seq_pos(seq_len, device = device, dtype = dtype, offset = offset)
|
| 280 |
+
|
| 281 |
+
freqs = self.forward(seq, seq_len = seq_len, offset = offset)
|
| 282 |
+
|
| 283 |
+
if seq_dim == -3:
|
| 284 |
+
freqs = rearrange(freqs, 'n d -> n 1 d')
|
| 285 |
+
|
| 286 |
+
return self.apply_rotary_emb(freqs, t, scale = default(scale, 1.), seq_dim = seq_dim)
|
| 287 |
+
|
| 288 |
+
def rotate_queries_with_cached_keys(self, q, k, seq_dim = None, offset = 0):
|
| 289 |
+
dtype, device, seq_dim = q.dtype, q.device, default(seq_dim, self.default_seq_dim)
|
| 290 |
+
|
| 291 |
+
q_len, k_len = q.shape[seq_dim], k.shape[seq_dim]
|
| 292 |
+
assert q_len <= k_len
|
| 293 |
+
|
| 294 |
+
q_scale = k_scale = 1.
|
| 295 |
+
|
| 296 |
+
if self.use_xpos:
|
| 297 |
+
seq = self.get_seq_pos(k_len, dtype = dtype, device = device)
|
| 298 |
+
|
| 299 |
+
q_scale = self.get_scale(seq[-q_len:]).type(dtype)
|
| 300 |
+
k_scale = self.get_scale(seq).type(dtype)
|
| 301 |
+
|
| 302 |
+
rotated_q = self.rotate_queries_or_keys(q, seq_dim = seq_dim, scale = q_scale, offset = k_len - q_len + offset)
|
| 303 |
+
rotated_k = self.rotate_queries_or_keys(k, seq_dim = seq_dim, scale = k_scale ** -1)
|
| 304 |
+
|
| 305 |
+
rotated_q = rotated_q.type(q.dtype)
|
| 306 |
+
rotated_k = rotated_k.type(k.dtype)
|
| 307 |
+
|
| 308 |
+
return rotated_q, rotated_k
|
| 309 |
+
|
| 310 |
+
def rotate_queries_and_keys(self, q, k, seq_dim = None, offset = 0):
|
| 311 |
+
seq_dim = default(seq_dim, self.default_seq_dim)
|
| 312 |
+
|
| 313 |
+
device, dtype, seq_len = q.device, q.dtype, q.shape[seq_dim]
|
| 314 |
+
|
| 315 |
+
seq = self.get_seq_pos(seq_len, dtype = dtype, device = device, offset = offset)
|
| 316 |
+
|
| 317 |
+
freqs = self.forward(seq, seq_len = seq_len, offset = offset)
|
| 318 |
+
scale = self.get_scale(seq, seq_len = seq_len, offset = offset).to(dtype)
|
| 319 |
+
|
| 320 |
+
if seq_dim == -3:
|
| 321 |
+
freqs = rearrange(freqs, 'n d -> n 1 d')
|
| 322 |
+
scale = rearrange(scale, 'n d -> n 1 d')
|
| 323 |
+
|
| 324 |
+
rotated_q = apply_rotary_emb(freqs, q, scale = scale, seq_dim = seq_dim)
|
| 325 |
+
rotated_k = apply_rotary_emb(freqs, k, scale = scale ** -1, seq_dim = seq_dim)
|
| 326 |
+
|
| 327 |
+
rotated_q = rotated_q.type(q.dtype)
|
| 328 |
+
rotated_k = rotated_k.type(k.dtype)
|
| 329 |
+
|
| 330 |
+
return rotated_q, rotated_k
|
| 331 |
+
|
| 332 |
+
def get_scale(
|
| 333 |
+
self,
|
| 334 |
+
t: Tensor,
|
| 335 |
+
seq_len= None,
|
| 336 |
+
offset = 0
|
| 337 |
+
):
|
| 338 |
+
|
| 339 |
+
should_cache = (
|
| 340 |
+
self.cache_if_possible and
|
| 341 |
+
exists(seq_len) and
|
| 342 |
+
(offset + seq_len) <= self.cache_max_seq_len
|
| 343 |
+
)
|
| 344 |
+
|
| 345 |
+
if (
|
| 346 |
+
should_cache and \
|
| 347 |
+
exists(self.cached_scales) and \
|
| 348 |
+
(seq_len + offset) <= self.cached_scales_seq_len
|
| 349 |
+
):
|
| 350 |
+
return self.cached_scales[offset:(offset + seq_len)]
|
| 351 |
+
|
| 352 |
+
scale = 1.
|
| 353 |
+
if self.use_xpos:
|
| 354 |
+
power = (t - len(t) // 2) / self.scale_base
|
| 355 |
+
scale = self.scale ** rearrange(power, 'n -> n 1')
|
| 356 |
+
scale = repeat(scale, 'n d -> n (d r)', r = 2)
|
| 357 |
+
|
| 358 |
+
if should_cache and offset == 0:
|
| 359 |
+
self.cached_scales[:seq_len] = scale.detach()
|
| 360 |
+
self.cached_scales_seq_len = seq_len
|
| 361 |
+
|
| 362 |
+
return scale
|
| 363 |
+
|
| 364 |
+
def get_axial_freqs(self, *dims):
|
| 365 |
+
Colon = slice(None)
|
| 366 |
+
all_freqs = []
|
| 367 |
+
|
| 368 |
+
for ind, dim in enumerate(dims):
|
| 369 |
+
if self.freqs_for == 'pixel':
|
| 370 |
+
pos = torch.linspace(-1, 1, steps = dim, device = self.device)
|
| 371 |
+
else:
|
| 372 |
+
pos = torch.arange(dim, device = self.device)
|
| 373 |
+
|
| 374 |
+
freqs = self.forward(pos, seq_len = dim)
|
| 375 |
+
|
| 376 |
+
all_axis = [None] * len(dims)
|
| 377 |
+
all_axis[ind] = Colon
|
| 378 |
+
|
| 379 |
+
new_axis_slice = (Ellipsis, *all_axis, Colon)
|
| 380 |
+
all_freqs.append(freqs[new_axis_slice])
|
| 381 |
+
|
| 382 |
+
all_freqs = broadcast_tensors(*all_freqs)
|
| 383 |
+
return torch.cat(all_freqs, dim = -1)
|
| 384 |
+
|
| 385 |
+
def forward(
|
| 386 |
+
self,
|
| 387 |
+
t,
|
| 388 |
+
seq_len = None,
|
| 389 |
+
offset = 0
|
| 390 |
+
):
|
| 391 |
+
dtype = t.dtype
|
| 392 |
+
with torch.amp.autocast('cuda',enabled=False):
|
| 393 |
+
t = t.float()
|
| 394 |
+
freqs = self.freqs.float()
|
| 395 |
+
|
| 396 |
+
should_cache = (
|
| 397 |
+
self.cache_if_possible and
|
| 398 |
+
not self.learned_freq and
|
| 399 |
+
exists(seq_len) and
|
| 400 |
+
self.freqs_for != 'pixel' and
|
| 401 |
+
(offset + seq_len) <= self.cache_max_seq_len
|
| 402 |
+
)
|
| 403 |
+
|
| 404 |
+
if (
|
| 405 |
+
should_cache and \
|
| 406 |
+
exists(self.cached_freqs) and \
|
| 407 |
+
(offset + seq_len) <= self.cached_freqs_seq_len
|
| 408 |
+
):
|
| 409 |
+
return self.cached_freqs[offset:(offset + seq_len)].detach()
|
| 410 |
+
|
| 411 |
+
|
| 412 |
+
freqs = einsum('..., f -> ... f', t, freqs)
|
| 413 |
+
freqs = repeat(freqs, '... n -> ... (n r)', r = 2)
|
| 414 |
+
|
| 415 |
+
if should_cache and offset == 0:
|
| 416 |
+
self.cached_freqs[:seq_len] = freqs.detach()
|
| 417 |
+
self.cached_freqs_seq_len = seq_len
|
| 418 |
+
|
| 419 |
+
return freqs.type(dtype)
|
| 420 |
+
|
| 421 |
+
# DropPath & FFN
|
| 422 |
+
def drop_path(x, drop_prob: float = 0., training: bool = False, scale_by_keep: bool = True): # taken from timm
|
| 423 |
+
if drop_prob == 0. or not training: return x
|
| 424 |
+
keep_prob = 1 - drop_prob
|
| 425 |
+
shape = (x.shape[0],) + (1,) * (x.ndim - 1) # work with diff dim tensors, not just 2D ConvNets
|
| 426 |
+
random_tensor = x.new_empty(shape).bernoulli_(keep_prob)
|
| 427 |
+
if keep_prob > 0.0 and scale_by_keep:
|
| 428 |
+
random_tensor.div_(keep_prob)
|
| 429 |
+
return x * random_tensor
|
| 430 |
+
|
| 431 |
+
class DropPath(nn.Module): # taken from timm
|
| 432 |
+
def __init__(self, drop_prob: float = 0., scale_by_keep: bool = True):
|
| 433 |
+
super(DropPath, self).__init__()
|
| 434 |
+
self.drop_prob = drop_prob
|
| 435 |
+
self.scale_by_keep = scale_by_keep
|
| 436 |
+
|
| 437 |
+
def forward(self, x):
|
| 438 |
+
return drop_path(x, self.drop_prob, self.training, self.scale_by_keep)
|
| 439 |
+
|
| 440 |
+
def extra_repr(self):
|
| 441 |
+
return f'(drop_prob=...)'
|
| 442 |
+
|
| 443 |
+
class FFN(nn.Module):
|
| 444 |
+
def __init__(self, in_features, hidden_features=None, out_features=None, drop=0., ffn_type='geglu'):
|
| 445 |
+
super().__init__()
|
| 446 |
+
out_features = out_features or in_features
|
| 447 |
+
hidden_features = hidden_features or in_features
|
| 448 |
+
self.ffn_type = ffn_type
|
| 449 |
+
if self.ffn_type == 'geglu':
|
| 450 |
+
self.fc1 = Linear(in_features, 2*hidden_features)
|
| 451 |
+
self.act = nn.GELU(approximate='tanh')
|
| 452 |
+
self.fc2 = Linear(hidden_features, out_features)
|
| 453 |
+
elif self.ffn_type == 'ffn':
|
| 454 |
+
self.fc1 = Linear(in_features, hidden_features)
|
| 455 |
+
self.act = nn.GELU(approximate='tanh')
|
| 456 |
+
self.fc2 = Linear(hidden_features, out_features)
|
| 457 |
+
self.drop = nn.Dropout(drop, inplace=True) if drop > 0 else nn.Identity()
|
| 458 |
+
|
| 459 |
+
def forward(self, x):
|
| 460 |
+
if self.ffn_type == 'geglu':
|
| 461 |
+
gate, value = self.fc1(x).chunk(2, dim=-1)
|
| 462 |
+
return self.drop(self.fc2(self.act(value)*gate))
|
| 463 |
+
elif self.ffn_type == 'ffn':
|
| 464 |
+
return self.drop(self.fc2(self.act(self.fc1(x))))
|
| 465 |
+
|
| 466 |
+
|
| 467 |
+
class Attention(nn.Module):
|
| 468 |
+
def __init__(
|
| 469 |
+
self, block_idx, embed_dim=768, num_heads=12,
|
| 470 |
+
attn_drop=0., proj_drop=0., attn_l2_norm=False,
|
| 471 |
+
rope=False
|
| 472 |
+
):
|
| 473 |
+
super().__init__()
|
| 474 |
+
assert embed_dim % num_heads == 0
|
| 475 |
+
self.block_idx = block_idx
|
| 476 |
+
self.num_heads = num_heads
|
| 477 |
+
self.head_dim = embed_dim // num_heads
|
| 478 |
+
self.attn_l2_norm = attn_l2_norm
|
| 479 |
+
self.rope = RotaryEmbedding(embed_dim//num_heads) if rope else None
|
| 480 |
+
|
| 481 |
+
if self.attn_l2_norm:
|
| 482 |
+
self.scale = 1
|
| 483 |
+
self.scale_mul_1H11 = nn.Parameter(torch.full(size=(1, self.num_heads, 1, 1), fill_value=4.0).log(), requires_grad=True)
|
| 484 |
+
self.max_scale_mul = torch.log(torch.tensor(100)).item()
|
| 485 |
+
else:
|
| 486 |
+
self.scale = 0.25 / math.sqrt(self.head_dim)
|
| 487 |
+
|
| 488 |
+
self.to_q = Linear(embed_dim, embed_dim, bias=False)
|
| 489 |
+
self.to_kv = Linear(embed_dim, embed_dim * 2, bias=False)
|
| 490 |
+
|
| 491 |
+
self.register_buffer('zero_k_bias', torch.zeros(embed_dim))
|
| 492 |
+
|
| 493 |
+
self.proj = Linear(embed_dim, embed_dim)
|
| 494 |
+
self.proj_drop = nn.Dropout(proj_drop, inplace=True) if proj_drop > 0 else nn.Identity()
|
| 495 |
+
self.attn_drop: float = attn_drop
|
| 496 |
+
|
| 497 |
+
def forward(self, x, context_emb=None, causal=False, attn_bias=None, cache_kv=False, past_kvs=None):
|
| 498 |
+
B, L, C = x.shape
|
| 499 |
+
|
| 500 |
+
q = self.to_q(x)
|
| 501 |
+
q = einops.rearrange(q, 'b l (h d) -> b l h d', h=self.num_heads)
|
| 502 |
+
|
| 503 |
+
kv = self.to_kv(x) if context_emb is None else self.to_kv(context_emb)
|
| 504 |
+
kv = einops.rearrange(kv, 'b l (h d) -> b l h d', h=self.num_heads)
|
| 505 |
+
k, v = kv.chunk(2, dim=-1)
|
| 506 |
+
|
| 507 |
+
if self.rope is not None:
|
| 508 |
+
past_len = 0
|
| 509 |
+
if past_kvs is not None:
|
| 510 |
+
past_len = past_kvs[0].shape[2]
|
| 511 |
+
q, k = self.rope.rotate_queries_and_keys(q, k, offset=past_len)
|
| 512 |
+
|
| 513 |
+
q = q.permute(0, 2, 1, 3) # [B, H, L, D]
|
| 514 |
+
k = k.permute(0, 2, 1, 3) # [B, H, L, D]
|
| 515 |
+
v = v.permute(0, 2, 1, 3) # [B, H, L, D]
|
| 516 |
+
|
| 517 |
+
if past_kvs is not None:
|
| 518 |
+
past_keys, past_values = past_kvs
|
| 519 |
+
k = torch.cat((past_keys, k), dim=2)
|
| 520 |
+
v = torch.cat((past_values, v), dim=2)
|
| 521 |
+
|
| 522 |
+
dropout_p = self.attn_drop if self.training else 0.0
|
| 523 |
+
oup = F.scaled_dot_product_attention(
|
| 524 |
+
query=q,
|
| 525 |
+
key=k,
|
| 526 |
+
value=v,
|
| 527 |
+
scale=self.scale,
|
| 528 |
+
is_causal=causal and past_kvs is None,
|
| 529 |
+
dropout_p=dropout_p,
|
| 530 |
+
attn_mask=attn_bias
|
| 531 |
+
).transpose(1, 2).reshape(B, L, -1)
|
| 532 |
+
|
| 533 |
+
out = self.proj_drop(self.proj(oup))
|
| 534 |
+
if not cache_kv:
|
| 535 |
+
return out
|
| 536 |
+
else:
|
| 537 |
+
return out, (k,v)
|
| 538 |
+
|
| 539 |
+
class TransformerLayer(nn.Module):
|
| 540 |
+
def __init__(
|
| 541 |
+
self, block_idx, embed_dim, cond_dim,
|
| 542 |
+
num_heads, mlp_ratio=8/3, drop=0., attn_drop=0., drop_path=0., attn_l2_norm=False, cross_attn=False, rope=False,
|
| 543 |
+
ffn_type='geglu', norm_layer=AdaRMSNorm
|
| 544 |
+
):
|
| 545 |
+
super(TransformerLayer, self).__init__()
|
| 546 |
+
self.block_idx = block_idx
|
| 547 |
+
self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()
|
| 548 |
+
|
| 549 |
+
self.adaln_1 = norm_layer(embed_dim, cond_dim)
|
| 550 |
+
self.attn1 = Attention(block_idx=block_idx, embed_dim=embed_dim, num_heads=num_heads, attn_drop=attn_drop, proj_drop=drop, attn_l2_norm=attn_l2_norm, rope=rope)
|
| 551 |
+
self.gate1 = Linear(cond_dim, embed_dim, init_weight=1e-5)
|
| 552 |
+
|
| 553 |
+
if cross_attn:
|
| 554 |
+
self.has_cross_attn = True
|
| 555 |
+
self.adaln_2 = norm_layer(embed_dim, cond_dim)
|
| 556 |
+
self.adaln_ctx = norm_layer(embed_dim, cond_dim)
|
| 557 |
+
|
| 558 |
+
self.attn2 = Attention(block_idx=block_idx, embed_dim=embed_dim, num_heads=num_heads, attn_drop=attn_drop, proj_drop=drop, attn_l2_norm=attn_l2_norm, rope=rope)
|
| 559 |
+
self.gate2 = Linear(cond_dim, embed_dim, init_weight=1e-5)
|
| 560 |
+
else:
|
| 561 |
+
self.has_cross_attn = False
|
| 562 |
+
|
| 563 |
+
self.adaln_mlp = norm_layer(embed_dim, cond_dim)
|
| 564 |
+
mlp_ratio = eval(mlp_ratio) if isinstance(mlp_ratio, str) else mlp_ratio
|
| 565 |
+
self.ffn = FFN(in_features=embed_dim, hidden_features=round(embed_dim * mlp_ratio), drop=drop, ffn_type=ffn_type)
|
| 566 |
+
self.gate_mlp = Linear(cond_dim, embed_dim, init_weight=1e-5)
|
| 567 |
+
|
| 568 |
+
def forward(self, x,context_emb=None, cond_emb=None, causal=False, attn_mask=None, cache_kv=False, past_kvs=None):
|
| 569 |
+
# If we are in "concat" mode, `context_emb` is None and masking should apply to self-attention.
|
| 570 |
+
# If we are in "cross_attn" mode, masking should apply to cross-attention (see below).
|
| 571 |
+
self_attn_mask = attn_mask if (attn_mask is not None and context_emb is None) else None
|
| 572 |
+
|
| 573 |
+
attn_out1 = self.attn1(
|
| 574 |
+
self.adaln_1(x, cond_emb),
|
| 575 |
+
context_emb=None,
|
| 576 |
+
causal=causal,
|
| 577 |
+
attn_bias=self_attn_mask,
|
| 578 |
+
cache_kv=cache_kv,
|
| 579 |
+
past_kvs=past_kvs,
|
| 580 |
+
)
|
| 581 |
+
if cache_kv:
|
| 582 |
+
attn_out1, new_kvs = attn_out1[0], attn_out1[1]
|
| 583 |
+
|
| 584 |
+
x = x + self.gate1(cond_emb).unsqueeze(1) * self.drop_path(attn_out1)
|
| 585 |
+
if context_emb is not None and self.has_cross_attn:
|
| 586 |
+
x = x + self.gate2(cond_emb).unsqueeze(1) * self.drop_path(self.attn2(self.adaln_2(x, cond_emb), context_emb=self.adaln_ctx(context_emb,cond_emb), causal=False, attn_bias=attn_mask))
|
| 587 |
+
x = x + self.gate_mlp(cond_emb).unsqueeze(1) * self.drop_path(self.ffn(self.adaln_mlp(x, cond_emb)))
|
| 588 |
+
|
| 589 |
+
if cache_kv:
|
| 590 |
+
return x, new_kvs
|
| 591 |
+
else:
|
| 592 |
+
return x
|
| 593 |
+
|
| 594 |
+
class Transformer(nn.Module):
|
| 595 |
+
def __init__(
|
| 596 |
+
self,
|
| 597 |
+
layer_num,
|
| 598 |
+
input_dim, dim, output_dim, max_seq_len, heads,
|
| 599 |
+
cond_input_dim, cond_dim,
|
| 600 |
+
context_type='none', ctx_input_dim=None, ctx_max_seq_len=None,
|
| 601 |
+
emb_dropout=0., drop=0.,
|
| 602 |
+
rope=False, abs_pos=False,
|
| 603 |
+
l2_norm=False, causal=False,
|
| 604 |
+
zero_out=False,
|
| 605 |
+
query_type='learnable', # 'learnable', 'noise', 'none'
|
| 606 |
+
out_act=True,
|
| 607 |
+
ffn_type='geglu', # ffn or geglu
|
| 608 |
+
norm_layer='RMSNorm', # LayerNorm or RMSNorm
|
| 609 |
+
mlp_ratio=8/3, **params
|
| 610 |
+
):
|
| 611 |
+
super(Transformer, self).__init__()
|
| 612 |
+
self.input_dim = input_dim
|
| 613 |
+
self.output_dim = output_dim
|
| 614 |
+
|
| 615 |
+
|
| 616 |
+
|
| 617 |
+
self.query_type = query_type
|
| 618 |
+
|
| 619 |
+
self.cond_input_dim = cond_input_dim
|
| 620 |
+
self.dim = dim
|
| 621 |
+
self.causal = causal
|
| 622 |
+
self.cross_attn = context_type=='cross_attn'
|
| 623 |
+
norm_layer = AdaRMSNorm if norm_layer=="RMSNorm" else AdaLN
|
| 624 |
+
self.layers = nn.ModuleList([
|
| 625 |
+
TransformerLayer(block_idx=i, embed_dim=dim,
|
| 626 |
+
cond_dim=cond_dim, num_heads=heads, mlp_ratio=mlp_ratio,
|
| 627 |
+
drop=drop, attn_drop=drop, attn_l2_norm=l2_norm, rope=rope, cross_attn=self.cross_attn,
|
| 628 |
+
ffn_type=ffn_type, norm_layer=norm_layer)
|
| 629 |
+
for i in range(layer_num)
|
| 630 |
+
])
|
| 631 |
+
|
| 632 |
+
out_weight = 1e-5 if zero_out else 1
|
| 633 |
+
scale = np.sqrt(dim)
|
| 634 |
+
self.adaln_out = norm_layer(dim, cond_dim)
|
| 635 |
+
|
| 636 |
+
self.out_activate = nn.GELU(approximate='tanh') if out_act else None
|
| 637 |
+
self.out = Linear(dim, output_dim,init_weight=out_weight)
|
| 638 |
+
|
| 639 |
+
if self.query_type!='noise':
|
| 640 |
+
self.cond_proj = nn.Sequential(Linear(cond_input_dim, cond_dim),norm_layer(cond_dim, cond_based_affine=False), nn.GELU(approximate='tanh'))
|
| 641 |
+
else:
|
| 642 |
+
self.cond_proj = Linear(cond_input_dim, cond_dim)
|
| 643 |
+
self.cond_norm_act = nn.Sequential(norm_layer(cond_dim, cond_based_affine=False), nn.GELU(approximate='tanh'))
|
| 644 |
+
self.max_seq_len = max_seq_len
|
| 645 |
+
self.context_type = context_type # "concat, cross_attn, none"
|
| 646 |
+
if abs_pos:
|
| 647 |
+
if context_type == 'none':
|
| 648 |
+
self.abs_pos = nn.Embedding(max_seq_len, dim)
|
| 649 |
+
elif context_type == 'concat':
|
| 650 |
+
ctx_max_seq_len = default(ctx_max_seq_len, max_seq_len)
|
| 651 |
+
self.abs_pos = nn.Embedding(max_seq_len + ctx_max_seq_len, dim)
|
| 652 |
+
elif context_type == 'cross_attn':
|
| 653 |
+
ctx_max_seq_len = default(ctx_max_seq_len, max_seq_len)
|
| 654 |
+
self.abs_pos = nn.Embedding(max_seq_len, dim)
|
| 655 |
+
self.ctx_pos = nn.Embedding(ctx_max_seq_len, dim)
|
| 656 |
+
else:
|
| 657 |
+
raise ValueError(f"Invalid context_type: {context_type}")
|
| 658 |
+
else:
|
| 659 |
+
self.abs_pos = None
|
| 660 |
+
|
| 661 |
+
if context_type == 'concat':
|
| 662 |
+
self.input_layer = Linear(input_dim, dim)
|
| 663 |
+
self.learnable_query_param = nn.Parameter(torch.zeros(1, max_seq_len, input_dim).normal_(0, 1)) if self.query_type == 'learnable' else None
|
| 664 |
+
ctx_input_dim = default(ctx_input_dim, input_dim)
|
| 665 |
+
self.ctx_input_dim = ctx_input_dim
|
| 666 |
+
self.ctx_input_layer = Linear(ctx_input_dim, dim)
|
| 667 |
+
elif context_type == 'cross_attn':
|
| 668 |
+
self.input_layer = Linear(input_dim, dim)
|
| 669 |
+
ctx_input_dim = default(ctx_input_dim, input_dim)
|
| 670 |
+
self.ctx_input_dim = ctx_input_dim
|
| 671 |
+
self.learnable_query_param = nn.Parameter(torch.zeros(1, max_seq_len, input_dim).normal_(0, 1)) if self.query_type == 'learnable' else None
|
| 672 |
+
self.ctx_input_layer = Linear(ctx_input_dim, dim)
|
| 673 |
+
else:
|
| 674 |
+
self.input_layer = Linear(input_dim, dim)
|
| 675 |
+
|
| 676 |
+
if self.query_type == 'noise':
|
| 677 |
+
self.t_embedder = TimestepEmbedder(cond_input_dim)
|
| 678 |
+
self.t_proj = Linear(cond_input_dim,cond_dim)
|
| 679 |
+
|
| 680 |
+
def forward(self, x, condition, attn_mask=None, cache_kv=False, past_kvs=None, query_tokens=None, t=None):
|
| 681 |
+
|
| 682 |
+
# Inject time embedding if using noise query
|
| 683 |
+
if self.query_type == 'noise':
|
| 684 |
+
cond_emb = self.cond_proj(condition)
|
| 685 |
+
if t is not None:
|
| 686 |
+
t_emb = self.t_embedder(t)
|
| 687 |
+
t_emb = self.t_proj(t_emb)
|
| 688 |
+
cond_emb = cond_emb + t_emb
|
| 689 |
+
cond_emb = self.cond_norm_act(cond_emb)
|
| 690 |
+
else:
|
| 691 |
+
cond_emb = self.cond_proj(condition)
|
| 692 |
+
if self.context_type == 'none':
|
| 693 |
+
x, context_emb = self.input_layer(x.contiguous()), None
|
| 694 |
+
elif self.context_type == 'concat':
|
| 695 |
+
B = x.size(0)
|
| 696 |
+
if query_tokens is None:
|
| 697 |
+
if self.query_type == 'learnable':
|
| 698 |
+
query_tokens = self.learnable_query_param.expand(B, -1, -1)
|
| 699 |
+
else:
|
| 700 |
+
# Should be provided for noise query, or error if not available
|
| 701 |
+
raise ValueError(f"query_tokens is required when query_type is '{self.query_type}'.")
|
| 702 |
+
|
| 703 |
+
query_tokens = self.input_layer(query_tokens.contiguous())
|
| 704 |
+
x = self.ctx_input_layer(x.contiguous())
|
| 705 |
+
x = torch.cat((query_tokens,x), dim=1)
|
| 706 |
+
x, context_emb = x, None
|
| 707 |
+
else:
|
| 708 |
+
# cross_attn: x is context (keys/values), query_tokens are queries
|
| 709 |
+
B = x.size(0)
|
| 710 |
+
if query_tokens is None:
|
| 711 |
+
if self.query_type == 'learnable':
|
| 712 |
+
query_tokens = self.learnable_query_param.expand(B, -1, -1)
|
| 713 |
+
else:
|
| 714 |
+
raise ValueError(f"query_tokens is required when query_type is '{self.query_type}'.")
|
| 715 |
+
|
| 716 |
+
x, context_emb = self.input_layer(query_tokens.contiguous()), self.ctx_input_layer(x.contiguous())
|
| 717 |
+
|
| 718 |
+
if self.abs_pos is not None:
|
| 719 |
+
if self.context_type == 'none':
|
| 720 |
+
pos_ids = torch.arange(x.size(1), device=x.device)
|
| 721 |
+
if past_kvs is not None:
|
| 722 |
+
pos_ids = pos_ids + past_kvs[0][0].shape[2]
|
| 723 |
+
x = x + self.abs_pos(pos_ids)
|
| 724 |
+
elif self.context_type == 'concat':
|
| 725 |
+
pos_ids = torch.arange(x.size(1), device=x.device)
|
| 726 |
+
x = x + self.abs_pos(pos_ids)
|
| 727 |
+
elif self.context_type == 'cross_attn':
|
| 728 |
+
pos_ids = torch.arange(x.size(1), device=x.device)
|
| 729 |
+
x = x + self.abs_pos(pos_ids)
|
| 730 |
+
if context_emb is not None and self.ctx_pos is not None:
|
| 731 |
+
context_emb = context_emb + self.ctx_pos(torch.arange(context_emb.size(1), device=context_emb.device))
|
| 732 |
+
|
| 733 |
+
kv_caches = []
|
| 734 |
+
for i,layer in enumerate(self.layers):
|
| 735 |
+
layer_output = layer(x, context_emb, cond_emb, self.causal, attn_mask, cache_kv, past_kvs[i] if past_kvs is not None else None)
|
| 736 |
+
if cache_kv:
|
| 737 |
+
x, new_kvs = layer_output[0], layer_output[1]
|
| 738 |
+
kv_caches.append(new_kvs)
|
| 739 |
+
else:
|
| 740 |
+
x = layer_output
|
| 741 |
+
if self.context_type == 'concat':
|
| 742 |
+
x = x[:, :self.max_seq_len]
|
| 743 |
+
out = self.adaln_out(x, cond_emb)
|
| 744 |
+
if self.out_activate is not None:
|
| 745 |
+
out = self.out_activate(out)
|
| 746 |
+
out = self.out(out)
|
| 747 |
+
|
| 748 |
+
if cache_kv:
|
| 749 |
+
return out, kv_caches
|
| 750 |
+
else:
|
| 751 |
+
return out
|
| 752 |
+
|
| 753 |
+
|
| 754 |
+
class Encoder(nn.Module):
|
| 755 |
+
def __init__(self, config) -> None:
|
| 756 |
+
super().__init__()
|
| 757 |
+
self.enc = Transformer(**config["Encoder"])
|
| 758 |
+
if config["vq_type"] == "HGQ":
|
| 759 |
+
self.quantizer = HGQ(**config["Quantizer"])
|
| 760 |
+
elif config["vq_type"] == "VQ":
|
| 761 |
+
self.quantizer = VQ(**config["Quantizer"])
|
| 762 |
+
else:
|
| 763 |
+
raise ValueError(f"Invalid quantizer type: {config['vq_type']}")
|
| 764 |
+
def forward(self, x, labels, training=True):
|
| 765 |
+
h = self.enc(x, labels)
|
| 766 |
+
quant, idx, one_hot, vqloss = self.quantizer(h, labels, training=training)
|
| 767 |
+
return quant, idx, one_hot, vqloss
|
| 768 |
+
|
| 769 |
+
|
| 770 |
+
class Decoder(nn.Module):
|
| 771 |
+
def __init__(self, config) -> None:
|
| 772 |
+
super().__init__()
|
| 773 |
+
self.dec = Transformer(**config["Decoder"])
|
| 774 |
+
|
| 775 |
+
|
| 776 |
+
def forward(self, quant, labels, attn_mask=None, query_tokens=None, t=None):
|
| 777 |
+
x_hat = self.dec(quant, labels, attn_mask=attn_mask, query_tokens=query_tokens, t=t)
|
| 778 |
+
return x_hat
|
| 779 |
+
|
| 780 |
+
|
| 781 |
+
class ARModel(nn.Module):
|
| 782 |
+
def __init__(self, config) -> None:
|
| 783 |
+
super().__init__()
|
| 784 |
+
self.bos = nn.Parameter(torch.zeros(1, 1, config["ARModel"]["input_dim"]).normal_(0,1))
|
| 785 |
+
self.semantic_emb = nn.Embedding(config["Quantizer"]["codebook_size"], config["ARModel"]["input_dim"])
|
| 786 |
+
self.ar_model = Transformer(**config["ARModel"])
|
| 787 |
+
|
| 788 |
+
self.temperature = config["ARModel"]["temperature"]
|
| 789 |
+
self.max_length = config["ARModel"]["max_seq_len"]
|
| 790 |
+
|
| 791 |
+
|
| 792 |
+
def forward(self,idx,labels, temperature=None):
|
| 793 |
+
bos = self.bos.expand(idx.shape[0], -1, -1)
|
| 794 |
+
shift_input = torch.cat([bos, self.semantic_emb(idx)[:,:-1]],dim=1)
|
| 795 |
+
logits = self.ar_model(shift_input, labels)
|
| 796 |
+
|
| 797 |
+
if temperature is not None:
|
| 798 |
+
logits = logits / temperature
|
| 799 |
+
elif self.temperature is not None:
|
| 800 |
+
logits = logits / self.temperature
|
| 801 |
+
return logits
|
| 802 |
+
|
| 803 |
+
@torch.no_grad()
|
| 804 |
+
@torch._dynamo.disable
|
| 805 |
+
def sampling(self, bz, class_label=None, temperature=1.0, topK=None, topP=None, cfg=16.0, cfg_schedule='cosine', cfg_power=2.75, cache_kv=False):
|
| 806 |
+
cfg = 0. if class_label is None else cfg
|
| 807 |
+
if cfg>0. :
|
| 808 |
+
num_classes = class_label.shape[1]
|
| 809 |
+
uncond_class_label = F.one_hot(torch.full((bz,), num_classes - 1, device=class_label.device, dtype=torch.long), num_classes=num_classes).float()
|
| 810 |
+
quant_input = self.bos.expand(bz, -1, -1)
|
| 811 |
+
quant_output = []
|
| 812 |
+
past_kvs, uncond_past_kvs = None, None
|
| 813 |
+
for step in range(self.max_length):
|
| 814 |
+
ar_out = self.ar_model(quant_input, class_label, cache_kv=cache_kv, past_kvs=past_kvs)
|
| 815 |
+
if cache_kv:
|
| 816 |
+
logits, past_kvs = ar_out
|
| 817 |
+
else:
|
| 818 |
+
logits = ar_out
|
| 819 |
+
logits = logits[:,-1]
|
| 820 |
+
if cfg>0.:
|
| 821 |
+
if cfg_schedule == 'constant':
|
| 822 |
+
cfg_scale = cfg
|
| 823 |
+
elif cfg_schedule == 'linear':
|
| 824 |
+
cfg_scale = 1.0 * (1-step/self.max_length) + cfg * (step/self.max_length)
|
| 825 |
+
elif cfg_schedule == 'cosine':
|
| 826 |
+
cfg_scale = (1 - math.cos(
|
| 827 |
+
((step / self.max_length) ** cfg_power) * math.pi)) * 1/2
|
| 828 |
+
cfg_scale = (cfg - 1) * cfg_scale + 1
|
| 829 |
+
else:
|
| 830 |
+
raise ValueError(f"Invalid cfg_schedule: {cfg_schedule}")
|
| 831 |
+
uncond_ar_out = self.ar_model(quant_input, uncond_class_label, cache_kv=cache_kv, past_kvs=uncond_past_kvs)
|
| 832 |
+
if cache_kv:
|
| 833 |
+
uncond_logits, uncond_past_kvs = uncond_ar_out
|
| 834 |
+
else:
|
| 835 |
+
uncond_logits = uncond_ar_out
|
| 836 |
+
uncond_logits = uncond_logits[:,-1]
|
| 837 |
+
logits = cfg_scale * logits + (1 - cfg_scale) * uncond_logits
|
| 838 |
+
logits = logits / temperature
|
| 839 |
+
|
| 840 |
+
if topK is not None and topK>0.:
|
| 841 |
+
top_logits, top_indices = logits.topk(topK, dim=-1)
|
| 842 |
+
logits = torch.full_like(logits, float('-inf'))
|
| 843 |
+
logits.scatter_(dim=-1, index=top_indices, src=top_logits)
|
| 844 |
+
if topP is not None and 0.<topP<1.:
|
| 845 |
+
sorted_logits, sorted_indices = torch.sort(logits, dim=-1, descending=True)
|
| 846 |
+
probs_sum = sorted_logits.softmax(dim=-1).cumsum(dim=-1)
|
| 847 |
+
mask = probs_sum > topP
|
| 848 |
+
mask[..., 1:] = mask[...,:-1].clone()
|
| 849 |
+
mask[...,0] = False
|
| 850 |
+
sorted_logits[mask] = float('-inf')
|
| 851 |
+
logits = torch.full_like(logits, float('-inf'))
|
| 852 |
+
logits.scatter_(dim=-1, index=sorted_indices, src=sorted_logits)
|
| 853 |
+
next_idx = torch.multinomial(F.softmax(logits, dim=-1), 1)
|
| 854 |
+
quant_output.append(next_idx)
|
| 855 |
+
if not cache_kv:
|
| 856 |
+
quant_input = torch.cat((quant_input, self.semantic_emb(next_idx)), dim=1)
|
| 857 |
+
else:
|
| 858 |
+
quant_input = self.semantic_emb(next_idx)
|
| 859 |
+
quant_output = torch.cat(quant_output, dim=1)
|
| 860 |
+
return quant_output
|
| 861 |
+
|
| 862 |
+
|
| 863 |
+
|
| 864 |
+
# deterministic Hard-Gumbel Softmax Quantizer
|
| 865 |
+
class HGQ(nn.Module):
|
| 866 |
+
def __init__(self, codebook_size, dim, z_dim, cond_dim, cond_based_affine=False, norm_layer='RMSNorm',temperature=1.0, **params):
|
| 867 |
+
super().__init__()
|
| 868 |
+
self.codebook_size = codebook_size # codebook size (K)
|
| 869 |
+
self.dim = dim # embedding dimension (D)
|
| 870 |
+
self.z_dim = z_dim
|
| 871 |
+
# Initialize embedding table
|
| 872 |
+
self.proj_in = Linear(dim, z_dim)
|
| 873 |
+
self.codebook = nn.Embedding(codebook_size, z_dim)
|
| 874 |
+
self.codebook.weight.data.uniform_(-1e-4, 1e-4)
|
| 875 |
+
self.norm_layer = norm_layer
|
| 876 |
+
if norm_layer == 'RMSNorm':
|
| 877 |
+
self.z_norm = AdaRMSNorm(z_dim, cond_dim, elementwise_affine=True, cond_based_affine=cond_based_affine)
|
| 878 |
+
self.code_norm = AdaRMSNorm(z_dim, cond_dim, elementwise_affine=True, cond_based_affine=cond_based_affine)
|
| 879 |
+
elif norm_layer == 'LN':
|
| 880 |
+
self.z_norm = AdaLN(z_dim, cond_dim, elementwise_affine=True, cond_based_affine=cond_based_affine)
|
| 881 |
+
self.code_norm = AdaLN(z_dim, cond_dim, elementwise_affine=True, cond_based_affine=cond_based_affine)
|
| 882 |
+
|
| 883 |
+
self.out_proj = Linear(z_dim, dim, bias=False)
|
| 884 |
+
self.total_cnt = 0
|
| 885 |
+
self.book_cnt = torch.zeros(codebook_size)
|
| 886 |
+
self.temperature=temperature
|
| 887 |
+
self.float()
|
| 888 |
+
|
| 889 |
+
def forward(self, x, labels=None, training=True, log_usage=False, indices=None):
|
| 890 |
+
B, L, D = x.shape
|
| 891 |
+
x = x.float()
|
| 892 |
+
z = self.proj_in(x)
|
| 893 |
+
|
| 894 |
+
if self.norm_layer != 'none':
|
| 895 |
+
if self.norm_layer=='l2':
|
| 896 |
+
z= F.normalize(z, dim=-1)
|
| 897 |
+
codes= F.normalize(self.codebook.weight, dim=-1)
|
| 898 |
+
elif self.norm_layer=='RMSNorm':
|
| 899 |
+
z= self.z_norm(z, labels)
|
| 900 |
+
codes= self.code_norm(self.codebook.weight, labels)
|
| 901 |
+
elif self.norm_layer=='LN':
|
| 902 |
+
z= self.z_norm(z, labels)
|
| 903 |
+
codes= self.code_norm(self.codebook.weight, labels)
|
| 904 |
+
else:
|
| 905 |
+
raise ValueError(f"Invalid norm layer: {self.norm_layer}")
|
| 906 |
+
|
| 907 |
+
logits = torch.einsum('bld,nd->bln', z, codes)
|
| 908 |
+
prob = F.softmax(logits/self.temperature, dim=-1)
|
| 909 |
+
|
| 910 |
+
indices = torch.argmax(prob, dim=-1) if indices is None else indices
|
| 911 |
+
one_hot_ng = F.one_hot(indices, prob.shape[-1]).view(B, L, -1).to(z.device).to(z.dtype)
|
| 912 |
+
one_hot = prob + (one_hot_ng - prob).detach()
|
| 913 |
+
|
| 914 |
+
quant = torch.einsum('bln,nd->bld', one_hot, codes)
|
| 915 |
+
loss = 0.
|
| 916 |
+
quant_out = self.out_proj(quant)
|
| 917 |
+
|
| 918 |
+
return quant_out, indices, one_hot, loss
|
| 919 |
+
|
| 920 |
+
def get_codes_w_onehot(self, one_hot, labels=None, **params):
|
| 921 |
+
codes = self.codebook.weight
|
| 922 |
+
quant = torch.einsum('bln,nd->bld', one_hot, codes)
|
| 923 |
+
|
| 924 |
+
if self.norm_layer != 'none':
|
| 925 |
+
if self.norm_layer=='l2':
|
| 926 |
+
quant= F.normalize(quant, dim=-1)
|
| 927 |
+
elif self.norm_layer=='RMSNorm':
|
| 928 |
+
quant= self.code_norm(quant, labels)
|
| 929 |
+
elif self.norm_layer=='LN':
|
| 930 |
+
quant= self.code_norm(quant, labels)
|
| 931 |
+
else:
|
| 932 |
+
raise ValueError(f"Invalid norm layer: {self.norm_layer}")
|
| 933 |
+
return self.out_proj(quant)
|
| 934 |
+
def get_codes_w_indices(self, indices, labels=None, **params):
|
| 935 |
+
codes = self.codebook(indices)
|
| 936 |
+
if self.norm_layer != 'none':
|
| 937 |
+
if self.norm_layer=='l2':
|
| 938 |
+
codes= F.normalize(codes, dim=-1)
|
| 939 |
+
elif self.norm_layer=='RMSNorm':
|
| 940 |
+
codes= self.code_norm(codes, labels)
|
| 941 |
+
elif self.norm_layer=='LN':
|
| 942 |
+
codes= self.code_norm(codes, labels)
|
| 943 |
+
else:
|
| 944 |
+
raise ValueError(f"Invalid norm layer: {self.norm_layer}")
|
| 945 |
+
return self.out_proj(codes)
|
| 946 |
+
|
| 947 |
+
|
| 948 |
+
class VQ(torch.nn.Module):
|
| 949 |
+
def __init__(self,
|
| 950 |
+
codebook_size: int = 1024,
|
| 951 |
+
dim: int = 256,
|
| 952 |
+
z_dim: int = 256,
|
| 953 |
+
beta: float = 0.25,
|
| 954 |
+
use_norm: bool = False,
|
| 955 |
+
temperature=1.0, **params
|
| 956 |
+
):
|
| 957 |
+
super().__init__()
|
| 958 |
+
self.codebook_size = codebook_size
|
| 959 |
+
self.dim = dim
|
| 960 |
+
self.z_dim = z_dim
|
| 961 |
+
self.beta = beta
|
| 962 |
+
self.total_cnt = 0
|
| 963 |
+
self.book_cnt = torch.zeros(codebook_size)
|
| 964 |
+
self.proj_in = Linear(dim, z_dim)
|
| 965 |
+
self.embedding = torch.nn.Embedding(codebook_size, z_dim)
|
| 966 |
+
self.embedding.weight.data.uniform_(-1.0 / codebook_size, 1.0 / codebook_size)
|
| 967 |
+
self.use_norm = use_norm
|
| 968 |
+
self.proj_out = Linear(z_dim, dim)
|
| 969 |
+
self.register_buffer('ema_vocab_hit_SV', torch.full((1, self.codebook_size), fill_value=0.0))
|
| 970 |
+
self.record_hit = 0
|
| 971 |
+
self.temperature=temperature
|
| 972 |
+
self.float()
|
| 973 |
+
|
| 974 |
+
|
| 975 |
+
def forward(self, x: torch.Tensor, labels=None, training=True):
|
| 976 |
+
x=x.float()
|
| 977 |
+
z = self.proj_in(x)
|
| 978 |
+
|
| 979 |
+
if self.use_norm:
|
| 980 |
+
z = F.normalize(z, dim=-1)
|
| 981 |
+
embedding = F.normalize(self.embedding.weight, dim=-1)
|
| 982 |
+
dist = -1 * torch.einsum('bld,nd->bln', z, embedding)
|
| 983 |
+
else:
|
| 984 |
+
embedding = self.embedding.weight
|
| 985 |
+
|
| 986 |
+
dist = torch.sum(z**2, dim=-1, keepdim=True) + \
|
| 987 |
+
torch.sum(embedding**2, dim=1) - 2 * \
|
| 988 |
+
torch.einsum('bld,nd->bln', z, embedding)
|
| 989 |
+
|
| 990 |
+
indices = torch.argmin(dist, dim=-1) # num_ele
|
| 991 |
+
ste_prob = (-dist/self.temperature).softmax(dim=-1)
|
| 992 |
+
one_hot_ng = F.one_hot(indices, dist.shape[-1]).view(x.shape[0], x.shape[1], -1).to(z.device).to(z.dtype)
|
| 993 |
+
one_hot = ste_prob + (one_hot_ng - ste_prob).detach()
|
| 994 |
+
|
| 995 |
+
quant = embedding[indices]
|
| 996 |
+
|
| 997 |
+
loss = self.beta * torch.mean((quant.detach() - z) **2) + torch.mean((quant - z.detach()) **2) if training else 0.
|
| 998 |
+
|
| 999 |
+
|
| 1000 |
+
# preserve gradients
|
| 1001 |
+
quant = z + (quant - z).detach()
|
| 1002 |
+
quant = self.proj_out(quant)
|
| 1003 |
+
|
| 1004 |
+
return quant, indices, one_hot, loss
|
| 1005 |
+
def get_codes_w_onehot(self, one_hot, labels=None, **params):
|
| 1006 |
+
codes = self.embedding.weight
|
| 1007 |
+
quant = torch.einsum('bln,nd->bld', one_hot, codes)
|
| 1008 |
+
quant = F.normalize(quant, dim=-1) if self.use_norm else quant
|
| 1009 |
+
return self.proj_out(quant)
|
| 1010 |
+
def get_codes_w_indices(self, indices):
|
| 1011 |
+
quant = self.embedding(indices)
|
| 1012 |
+
quant = F.normalize(quant, dim=-1) if self.use_norm else quant
|
| 1013 |
+
return self.proj_out(quant)
|
refs/cifar10-32x32_local.npz
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:5493968c4f29b2878f64d6a640351f377e32e86553db56eca8147a0ae50d93f2
|
| 3 |
+
size 63557107
|
requirements.txt
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
torch==2.8.0
|
| 2 |
+
torchvision==0.23.0
|
| 3 |
+
lightning==2.5.5
|
| 4 |
+
omegaconf==2.3.0
|
| 5 |
+
einops==0.8.1
|
| 6 |
+
numpy==2.1.3
|
| 7 |
+
scipy==1.16.3
|
| 8 |
+
Pillow==11.1.0
|
| 9 |
+
PyYAML==6.0.3
|
| 10 |
+
wandb==0.23.0
|
| 11 |
+
tqdm==4.67.1
|
| 12 |
+
requests==2.32.5
|
| 13 |
+
click==8.3.0
|
| 14 |
+
setuptools==80.9.0
|
| 15 |
+
tensorflow==2.19.1
|
scripts/dataset_tools.py
ADDED
|
@@ -0,0 +1,618 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# This work is licensed under a Creative Commons
|
| 4 |
+
# Attribution-NonCommercial-ShareAlike 4.0 International License.
|
| 5 |
+
# You should have received a copy of the license along with this
|
| 6 |
+
# work. If not, see http://creativecommons.org/licenses/by-nc-sa/4.0/
|
| 7 |
+
|
| 8 |
+
"""Tool for creating ZIP/PNG based datasets."""
|
| 9 |
+
|
| 10 |
+
import functools
|
| 11 |
+
import gzip
|
| 12 |
+
import io
|
| 13 |
+
import json
|
| 14 |
+
import os
|
| 15 |
+
import pickle
|
| 16 |
+
import re
|
| 17 |
+
import sys
|
| 18 |
+
import tarfile
|
| 19 |
+
import zipfile
|
| 20 |
+
from pathlib import Path
|
| 21 |
+
from typing import Callable, Optional, Tuple, Union
|
| 22 |
+
import click
|
| 23 |
+
import numpy as np
|
| 24 |
+
import PIL.Image
|
| 25 |
+
from tqdm import tqdm
|
| 26 |
+
|
| 27 |
+
#----------------------------------------------------------------------------
|
| 28 |
+
# Parse a 'M,N' or 'MxN' integer tuple.
|
| 29 |
+
# Example: '4x2' returns (4,2)
|
| 30 |
+
|
| 31 |
+
def parse_tuple(s: str) -> Tuple[int, int]:
|
| 32 |
+
m = re.match(r'^(\d+)[x,](\d+)$', s)
|
| 33 |
+
if m:
|
| 34 |
+
return int(m.group(1)), int(m.group(2))
|
| 35 |
+
raise click.ClickException(f'cannot parse tuple {s}')
|
| 36 |
+
|
| 37 |
+
#----------------------------------------------------------------------------
|
| 38 |
+
|
| 39 |
+
def maybe_min(a: int, b: Optional[int]) -> int:
|
| 40 |
+
if b is not None:
|
| 41 |
+
return min(a, b)
|
| 42 |
+
return a
|
| 43 |
+
|
| 44 |
+
#----------------------------------------------------------------------------
|
| 45 |
+
|
| 46 |
+
def file_ext(name: Union[str, Path]) -> str:
|
| 47 |
+
return str(name).split('.')[-1]
|
| 48 |
+
|
| 49 |
+
#----------------------------------------------------------------------------
|
| 50 |
+
|
| 51 |
+
def is_image_ext(fname: Union[str, Path]) -> bool:
|
| 52 |
+
ext = file_ext(fname).lower()
|
| 53 |
+
return f'.{ext}' in PIL.Image.EXTENSION
|
| 54 |
+
|
| 55 |
+
#----------------------------------------------------------------------------
|
| 56 |
+
|
| 57 |
+
def open_image_folder(source_dir, *, max_images: Optional[int]):
|
| 58 |
+
input_images = [str(f) for f in sorted(Path(source_dir).rglob('*')) if is_image_ext(f) and os.path.isfile(f)]
|
| 59 |
+
arch_fnames = {fname: os.path.relpath(fname, source_dir).replace('\\', '/') for fname in input_images}
|
| 60 |
+
max_idx = maybe_min(len(input_images), max_images)
|
| 61 |
+
|
| 62 |
+
# Load labels.
|
| 63 |
+
labels = dict()
|
| 64 |
+
meta_fname = os.path.join(source_dir, 'dataset.json')
|
| 65 |
+
if os.path.isfile(meta_fname):
|
| 66 |
+
with open(meta_fname, 'r') as file:
|
| 67 |
+
data = json.load(file)['labels']
|
| 68 |
+
if data is not None:
|
| 69 |
+
labels = {x[0]: x[1] for x in data}
|
| 70 |
+
|
| 71 |
+
# No labels available => determine from top-level directory names.
|
| 72 |
+
if len(labels) == 0:
|
| 73 |
+
toplevel_names = {arch_fname: arch_fname.split('/')[0] if '/' in arch_fname else '' for arch_fname in arch_fnames.values()}
|
| 74 |
+
toplevel_indices = {toplevel_name: idx for idx, toplevel_name in enumerate(sorted(set(toplevel_names.values())))}
|
| 75 |
+
if len(toplevel_indices) > 1:
|
| 76 |
+
labels = {arch_fname: toplevel_indices[toplevel_name] for arch_fname, toplevel_name in toplevel_names.items()}
|
| 77 |
+
|
| 78 |
+
def iterate_images():
|
| 79 |
+
for idx, fname in enumerate(input_images):
|
| 80 |
+
img = np.array(PIL.Image.open(fname))
|
| 81 |
+
yield dict(img=img, label=labels.get(arch_fnames.get(fname)))
|
| 82 |
+
if idx >= max_idx - 1:
|
| 83 |
+
break
|
| 84 |
+
return max_idx, iterate_images()
|
| 85 |
+
|
| 86 |
+
#----------------------------------------------------------------------------
|
| 87 |
+
|
| 88 |
+
def open_image_zip(source, *, max_images: Optional[int]):
|
| 89 |
+
with zipfile.ZipFile(source, mode='r') as z:
|
| 90 |
+
input_images = [str(f) for f in sorted(z.namelist()) if is_image_ext(f)]
|
| 91 |
+
max_idx = maybe_min(len(input_images), max_images)
|
| 92 |
+
|
| 93 |
+
# Load labels.
|
| 94 |
+
labels = dict()
|
| 95 |
+
if 'dataset.json' in z.namelist():
|
| 96 |
+
with z.open('dataset.json', 'r') as file:
|
| 97 |
+
data = json.load(file)['labels']
|
| 98 |
+
if data is not None:
|
| 99 |
+
labels = {x[0]: x[1] for x in data}
|
| 100 |
+
|
| 101 |
+
def iterate_images():
|
| 102 |
+
with zipfile.ZipFile(source, mode='r') as z:
|
| 103 |
+
for idx, fname in enumerate(input_images):
|
| 104 |
+
with z.open(fname, 'r') as file:
|
| 105 |
+
img = np.array(PIL.Image.open(file))
|
| 106 |
+
yield dict(img=img, label=labels.get(fname))
|
| 107 |
+
if idx >= max_idx - 1:
|
| 108 |
+
break
|
| 109 |
+
return max_idx, iterate_images()
|
| 110 |
+
|
| 111 |
+
#----------------------------------------------------------------------------
|
| 112 |
+
|
| 113 |
+
def open_lmdb(lmdb_dir: str, *, max_images: Optional[int]):
|
| 114 |
+
import cv2 # pyright: ignore [reportMissingImports] # pip install opencv-python
|
| 115 |
+
import lmdb # pyright: ignore [reportMissingImports] # pip install lmdb
|
| 116 |
+
|
| 117 |
+
with lmdb.open(lmdb_dir, readonly=True, lock=False).begin(write=False) as txn:
|
| 118 |
+
max_idx = maybe_min(txn.stat()['entries'], max_images)
|
| 119 |
+
|
| 120 |
+
def iterate_images():
|
| 121 |
+
with lmdb.open(lmdb_dir, readonly=True, lock=False).begin(write=False) as txn:
|
| 122 |
+
for idx, (_key, value) in enumerate(txn.cursor()):
|
| 123 |
+
try:
|
| 124 |
+
try:
|
| 125 |
+
img = cv2.imdecode(np.frombuffer(value, dtype=np.uint8), 1)
|
| 126 |
+
if img is None:
|
| 127 |
+
raise IOError('cv2.imdecode failed')
|
| 128 |
+
img = img[:, :, ::-1] # BGR => RGB
|
| 129 |
+
except IOError:
|
| 130 |
+
img = np.array(PIL.Image.open(io.BytesIO(value)))
|
| 131 |
+
yield dict(img=img, label=None)
|
| 132 |
+
if idx >= max_idx - 1:
|
| 133 |
+
break
|
| 134 |
+
except:
|
| 135 |
+
print(sys.exc_info()[1])
|
| 136 |
+
|
| 137 |
+
return max_idx, iterate_images()
|
| 138 |
+
|
| 139 |
+
#----------------------------------------------------------------------------
|
| 140 |
+
|
| 141 |
+
def open_cifar10(tarball: str, *, max_images: Optional[int]):
|
| 142 |
+
images = []
|
| 143 |
+
labels = []
|
| 144 |
+
|
| 145 |
+
with tarfile.open(tarball, 'r:gz') as tar:
|
| 146 |
+
for batch in range(1, 6):
|
| 147 |
+
member = tar.getmember(f'cifar-10-batches-py/data_batch_{batch}')
|
| 148 |
+
with tar.extractfile(member) as file:
|
| 149 |
+
data = pickle.load(file, encoding='latin1')
|
| 150 |
+
images.append(data['data'].reshape(-1, 3, 32, 32))
|
| 151 |
+
labels.append(data['labels'])
|
| 152 |
+
|
| 153 |
+
images = np.concatenate(images)
|
| 154 |
+
labels = np.concatenate(labels)
|
| 155 |
+
images = images.transpose([0, 2, 3, 1]) # NCHW -> NHWC
|
| 156 |
+
assert images.shape == (50000, 32, 32, 3) and images.dtype == np.uint8
|
| 157 |
+
assert labels.shape == (50000,) and labels.dtype in [np.int32, np.int64]
|
| 158 |
+
assert np.min(images) == 0 and np.max(images) == 255
|
| 159 |
+
assert np.min(labels) == 0 and np.max(labels) == 9
|
| 160 |
+
|
| 161 |
+
max_idx = maybe_min(len(images), max_images)
|
| 162 |
+
|
| 163 |
+
def iterate_images():
|
| 164 |
+
for idx, img in enumerate(images):
|
| 165 |
+
yield dict(img=img, label=int(labels[idx]))
|
| 166 |
+
if idx >= max_idx - 1:
|
| 167 |
+
break
|
| 168 |
+
|
| 169 |
+
return max_idx, iterate_images()
|
| 170 |
+
|
| 171 |
+
#----------------------------------------------------------------------------
|
| 172 |
+
|
| 173 |
+
def open_mnist(images_gz: str, *, max_images: Optional[int]):
|
| 174 |
+
labels_gz = images_gz.replace('-images-idx3-ubyte.gz', '-labels-idx1-ubyte.gz')
|
| 175 |
+
assert labels_gz != images_gz
|
| 176 |
+
images = []
|
| 177 |
+
labels = []
|
| 178 |
+
|
| 179 |
+
with gzip.open(images_gz, 'rb') as f:
|
| 180 |
+
images = np.frombuffer(f.read(), np.uint8, offset=16)
|
| 181 |
+
with gzip.open(labels_gz, 'rb') as f:
|
| 182 |
+
labels = np.frombuffer(f.read(), np.uint8, offset=8)
|
| 183 |
+
|
| 184 |
+
images = images.reshape(-1, 28, 28)
|
| 185 |
+
images = np.pad(images, [(0,0), (2,2), (2,2)], 'constant', constant_values=0)
|
| 186 |
+
assert images.shape == (60000, 32, 32) and images.dtype == np.uint8
|
| 187 |
+
assert labels.shape == (60000,) and labels.dtype == np.uint8
|
| 188 |
+
assert np.min(images) == 0 and np.max(images) == 255
|
| 189 |
+
assert np.min(labels) == 0 and np.max(labels) == 9
|
| 190 |
+
|
| 191 |
+
max_idx = maybe_min(len(images), max_images)
|
| 192 |
+
|
| 193 |
+
def iterate_images():
|
| 194 |
+
for idx, img in enumerate(images):
|
| 195 |
+
yield dict(img=img, label=int(labels[idx]))
|
| 196 |
+
if idx >= max_idx - 1:
|
| 197 |
+
break
|
| 198 |
+
|
| 199 |
+
return max_idx, iterate_images()
|
| 200 |
+
|
| 201 |
+
#----------------------------------------------------------------------------
|
| 202 |
+
|
| 203 |
+
def make_transform(
|
| 204 |
+
transform: Optional[str],
|
| 205 |
+
output_width: Optional[int],
|
| 206 |
+
output_height: Optional[int]
|
| 207 |
+
) -> Callable[[np.ndarray], Optional[np.ndarray]]:
|
| 208 |
+
def scale(width, height, img):
|
| 209 |
+
w = img.shape[1]
|
| 210 |
+
h = img.shape[0]
|
| 211 |
+
if width == w and height == h:
|
| 212 |
+
return img
|
| 213 |
+
img = PIL.Image.fromarray(img)
|
| 214 |
+
ww = width if width is not None else w
|
| 215 |
+
hh = height if height is not None else h
|
| 216 |
+
img = img.resize((ww, hh), PIL.Image.Resampling.LANCZOS)
|
| 217 |
+
return np.array(img)
|
| 218 |
+
|
| 219 |
+
def center_crop(width, height, img):
|
| 220 |
+
crop = np.min(img.shape[:2])
|
| 221 |
+
img = img[(img.shape[0] - crop) // 2 : (img.shape[0] + crop) // 2, (img.shape[1] - crop) // 2 : (img.shape[1] + crop) // 2]
|
| 222 |
+
if img.ndim == 2:
|
| 223 |
+
img = img[:, :, np.newaxis].repeat(3, axis=2)
|
| 224 |
+
img = PIL.Image.fromarray(img, 'RGB')
|
| 225 |
+
img = img.resize((width, height), PIL.Image.Resampling.LANCZOS)
|
| 226 |
+
return np.array(img)
|
| 227 |
+
|
| 228 |
+
def center_crop_wide(width, height, img):
|
| 229 |
+
ch = int(np.round(width * img.shape[0] / img.shape[1]))
|
| 230 |
+
if img.shape[1] < width or ch < height:
|
| 231 |
+
return None
|
| 232 |
+
|
| 233 |
+
img = img[(img.shape[0] - ch) // 2 : (img.shape[0] + ch) // 2]
|
| 234 |
+
if img.ndim == 2:
|
| 235 |
+
img = img[:, :, np.newaxis].repeat(3, axis=2)
|
| 236 |
+
img = PIL.Image.fromarray(img, 'RGB')
|
| 237 |
+
img = img.resize((width, height), PIL.Image.Resampling.LANCZOS)
|
| 238 |
+
img = np.array(img)
|
| 239 |
+
|
| 240 |
+
canvas = np.zeros([width, width, 3], dtype=np.uint8)
|
| 241 |
+
canvas[(width - height) // 2 : (width + height) // 2, :] = img
|
| 242 |
+
return canvas
|
| 243 |
+
|
| 244 |
+
if transform is None:
|
| 245 |
+
return functools.partial(scale, output_width, output_height)
|
| 246 |
+
if transform == 'center-crop':
|
| 247 |
+
if output_width is None or output_height is None:
|
| 248 |
+
raise click.ClickException('must specify --resolution=WxH when using ' + transform + 'transform')
|
| 249 |
+
return functools.partial(center_crop, output_width, output_height)
|
| 250 |
+
if transform == 'center-crop-wide':
|
| 251 |
+
if output_width is None or output_height is None:
|
| 252 |
+
raise click.ClickException('must specify --resolution=WxH when using ' + transform + ' transform')
|
| 253 |
+
return functools.partial(center_crop_wide, output_width, output_height)
|
| 254 |
+
assert False, 'unknown transform'
|
| 255 |
+
|
| 256 |
+
#----------------------------------------------------------------------------
|
| 257 |
+
|
| 258 |
+
def open_dataset(source, *, max_images: Optional[int]):
|
| 259 |
+
if os.path.isdir(source):
|
| 260 |
+
if source.rstrip('/').endswith('_lmdb'):
|
| 261 |
+
return open_lmdb(source, max_images=max_images)
|
| 262 |
+
else:
|
| 263 |
+
return open_image_folder(source, max_images=max_images)
|
| 264 |
+
elif os.path.isfile(source):
|
| 265 |
+
if os.path.basename(source) == 'cifar-10-python.tar.gz':
|
| 266 |
+
return open_cifar10(source, max_images=max_images)
|
| 267 |
+
elif os.path.basename(source) == 'train-images-idx3-ubyte.gz':
|
| 268 |
+
return open_mnist(source, max_images=max_images)
|
| 269 |
+
elif file_ext(source) == 'zip':
|
| 270 |
+
return open_image_zip(source, max_images=max_images)
|
| 271 |
+
else:
|
| 272 |
+
assert False, 'unknown archive type'
|
| 273 |
+
else:
|
| 274 |
+
raise click.ClickException(f'Missing input file or directory: {source}')
|
| 275 |
+
|
| 276 |
+
#----------------------------------------------------------------------------
|
| 277 |
+
|
| 278 |
+
def create_labels_only(source: str) -> None:
|
| 279 |
+
"""Create a StyleGAN-style dataset.json with image->class labels in-place.
|
| 280 |
+
|
| 281 |
+
- For directories: writes dataset.json under the source root.
|
| 282 |
+
- For ZIP files: writes dataset.json inside the ZIP archive.
|
| 283 |
+
- Labels are inferred from an existing dataset.json if present, otherwise
|
| 284 |
+
from top-level directory names (ImageNet-style). If labels cannot be
|
| 285 |
+
determined for all images, labels is set to None.
|
| 286 |
+
"""
|
| 287 |
+
def _maybe_load_imagenet_val_labels(rel_fnames):
|
| 288 |
+
"""Try to infer ImageNet val labels from LOC_val_solution.csv + LOC_synset_mapping.txt.
|
| 289 |
+
|
| 290 |
+
rel_fnames are relative paths within `source` (for dirs) or within the zip.
|
| 291 |
+
This function returns a mapping {rel_fname: class_idx} or an empty dict if
|
| 292 |
+
the required metadata files are not found or parsing fails.
|
| 293 |
+
"""
|
| 294 |
+
root = Path(__file__).resolve().parent
|
| 295 |
+
val_csv = root / 'LOC_val_solution.csv'
|
| 296 |
+
synset_map = root / 'LOC_synset_mapping.txt'
|
| 297 |
+
if not (val_csv.is_file() and synset_map.is_file()):
|
| 298 |
+
return {}
|
| 299 |
+
|
| 300 |
+
# Build synset -> class index mapping, consistent with train (sorted by synset).
|
| 301 |
+
synsets = []
|
| 302 |
+
with open(synset_map, 'r') as f:
|
| 303 |
+
for line in f:
|
| 304 |
+
line = line.strip()
|
| 305 |
+
if not line:
|
| 306 |
+
continue
|
| 307 |
+
syn = line.split()[0]
|
| 308 |
+
synsets.append(syn)
|
| 309 |
+
synsets = sorted(set(synsets))
|
| 310 |
+
class_to_idx = {syn: idx for idx, syn in enumerate(synsets)}
|
| 311 |
+
|
| 312 |
+
# Build image_id -> synset mapping from LOC_val_solution.csv
|
| 313 |
+
img_to_syn = {}
|
| 314 |
+
with open(val_csv, 'r') as f:
|
| 315 |
+
# Skip header
|
| 316 |
+
header = f.readline()
|
| 317 |
+
for line in f:
|
| 318 |
+
line = line.strip()
|
| 319 |
+
if not line:
|
| 320 |
+
continue
|
| 321 |
+
parts = line.split(',', 1)
|
| 322 |
+
if len(parts) != 2:
|
| 323 |
+
continue
|
| 324 |
+
image_id, pred_str = parts
|
| 325 |
+
pred_str = pred_str.strip()
|
| 326 |
+
if not pred_str:
|
| 327 |
+
continue
|
| 328 |
+
syn = pred_str.split()[0]
|
| 329 |
+
img_to_syn[image_id] = syn
|
| 330 |
+
|
| 331 |
+
labels = {}
|
| 332 |
+
for rel in rel_fnames:
|
| 333 |
+
base = os.path.basename(rel)
|
| 334 |
+
stem, _ext = os.path.splitext(base)
|
| 335 |
+
syn = img_to_syn.get(stem, None)
|
| 336 |
+
if syn is None:
|
| 337 |
+
continue
|
| 338 |
+
cls_idx = class_to_idx.get(syn, None)
|
| 339 |
+
if cls_idx is None:
|
| 340 |
+
continue
|
| 341 |
+
labels[rel] = cls_idx
|
| 342 |
+
return labels
|
| 343 |
+
|
| 344 |
+
# Directory source: infer labels based on folder structure or metadata.
|
| 345 |
+
if os.path.isdir(source):
|
| 346 |
+
input_images = [
|
| 347 |
+
str(f) for f in sorted(Path(source).rglob('*'))
|
| 348 |
+
if is_image_ext(f) and os.path.isfile(f)
|
| 349 |
+
]
|
| 350 |
+
arch_fnames = {
|
| 351 |
+
fname: os.path.relpath(fname, source).replace('\\', '/')
|
| 352 |
+
for fname in input_images
|
| 353 |
+
}
|
| 354 |
+
|
| 355 |
+
labels = dict()
|
| 356 |
+
meta_fname = os.path.join(source, 'dataset.json')
|
| 357 |
+
if os.path.isfile(meta_fname):
|
| 358 |
+
with open(meta_fname, 'r') as file:
|
| 359 |
+
data = json.load(file).get('labels', None)
|
| 360 |
+
if data is not None:
|
| 361 |
+
labels = {x[0]: x[1] for x in data}
|
| 362 |
+
|
| 363 |
+
# No labels available => determine from top-level directory names (train-style),
|
| 364 |
+
# or fall back to ImageNet val metadata if available.
|
| 365 |
+
if len(labels) == 0:
|
| 366 |
+
toplevel_names = {
|
| 367 |
+
arch_fname: arch_fname.split('/')[0] if '/' in arch_fname else ''
|
| 368 |
+
for arch_fname in arch_fnames.values()
|
| 369 |
+
}
|
| 370 |
+
unique_toplevel = sorted(set(toplevel_names.values()))
|
| 371 |
+
if len(unique_toplevel) > 1:
|
| 372 |
+
toplevel_indices = {
|
| 373 |
+
toplevel_name: idx
|
| 374 |
+
for idx, toplevel_name in enumerate(unique_toplevel)
|
| 375 |
+
}
|
| 376 |
+
labels = {
|
| 377 |
+
arch_fname: toplevel_indices[toplevel_names[arch_fname]]
|
| 378 |
+
for arch_fname in arch_fnames.values()
|
| 379 |
+
}
|
| 380 |
+
else:
|
| 381 |
+
# Likely a flat ImageNet val-style directory; try metadata-based labels.
|
| 382 |
+
labels = _maybe_load_imagenet_val_labels(list(arch_fnames.values()))
|
| 383 |
+
|
| 384 |
+
labels_list = []
|
| 385 |
+
all_labeled = True
|
| 386 |
+
for arch_fname in arch_fnames.values():
|
| 387 |
+
lbl = labels.get(arch_fname, None)
|
| 388 |
+
if lbl is None:
|
| 389 |
+
all_labeled = False
|
| 390 |
+
labels_list.append([arch_fname, lbl])
|
| 391 |
+
|
| 392 |
+
metadata = {'labels': labels_list if all_labeled else None}
|
| 393 |
+
with open(meta_fname, 'w') as f:
|
| 394 |
+
json.dump(metadata, f)
|
| 395 |
+
return
|
| 396 |
+
|
| 397 |
+
# ZIP source: write dataset.json inside the archive.
|
| 398 |
+
if os.path.isfile(source) and file_ext(source) == 'zip':
|
| 399 |
+
with zipfile.ZipFile(source, mode='r') as z:
|
| 400 |
+
namelist = z.namelist()
|
| 401 |
+
if 'dataset.json' in namelist:
|
| 402 |
+
return
|
| 403 |
+
input_images = [f for f in sorted(namelist) if is_image_ext(f)]
|
| 404 |
+
|
| 405 |
+
labels = dict()
|
| 406 |
+
# Determine from top-level directory names inside zip, or fall back to
|
| 407 |
+
# ImageNet val metadata if available.
|
| 408 |
+
toplevel_names = {
|
| 409 |
+
fname: fname.split('/')[0] if '/' in fname else ''
|
| 410 |
+
for fname in input_images
|
| 411 |
+
}
|
| 412 |
+
unique_toplevel = sorted(set(toplevel_names.values()))
|
| 413 |
+
if len(unique_toplevel) > 1:
|
| 414 |
+
toplevel_indices = {
|
| 415 |
+
toplevel_name: idx
|
| 416 |
+
for idx, toplevel_name in enumerate(unique_toplevel)
|
| 417 |
+
}
|
| 418 |
+
labels = {
|
| 419 |
+
fname: toplevel_indices[toplevel_names[fname]]
|
| 420 |
+
for fname in input_images
|
| 421 |
+
}
|
| 422 |
+
else:
|
| 423 |
+
# Flat layout: try ImageNet val metadata (filenames like ILSVRC2012_val_*.JPEG).
|
| 424 |
+
labels = _maybe_load_imagenet_val_labels(input_images)
|
| 425 |
+
|
| 426 |
+
labels_list = []
|
| 427 |
+
all_labeled = True
|
| 428 |
+
for fname in input_images:
|
| 429 |
+
lbl = labels.get(fname, None)
|
| 430 |
+
if lbl is None:
|
| 431 |
+
all_labeled = False
|
| 432 |
+
labels_list.append([fname, lbl])
|
| 433 |
+
|
| 434 |
+
metadata = {'labels': labels_list if all_labeled else None}
|
| 435 |
+
|
| 436 |
+
# Append dataset.json to the zip.
|
| 437 |
+
with zipfile.ZipFile(source, mode='a') as z:
|
| 438 |
+
z.writestr('dataset.json', json.dumps(metadata))
|
| 439 |
+
return
|
| 440 |
+
|
| 441 |
+
raise click.ClickException(
|
| 442 |
+
f'labels-only currently supports directory or zip sources, got: {source}'
|
| 443 |
+
)
|
| 444 |
+
|
| 445 |
+
#----------------------------------------------------------------------------
|
| 446 |
+
|
| 447 |
+
def open_dest(dest: str) -> Tuple[str, Callable[[str, Union[bytes, str]], None], Callable[[], None]]:
|
| 448 |
+
dest_ext = file_ext(dest)
|
| 449 |
+
|
| 450 |
+
if dest_ext == 'zip':
|
| 451 |
+
if os.path.dirname(dest) != '':
|
| 452 |
+
os.makedirs(os.path.dirname(dest), exist_ok=True)
|
| 453 |
+
zf = zipfile.ZipFile(file=dest, mode='w', compression=zipfile.ZIP_STORED)
|
| 454 |
+
def zip_write_bytes(fname: str, data: Union[bytes, str]):
|
| 455 |
+
zf.writestr(fname, data)
|
| 456 |
+
return '', zip_write_bytes, zf.close
|
| 457 |
+
else:
|
| 458 |
+
# If the output folder already exists, check that is is
|
| 459 |
+
# empty.
|
| 460 |
+
#
|
| 461 |
+
# Note: creating the output directory is not strictly
|
| 462 |
+
# necessary as folder_write_bytes() also mkdirs, but it's better
|
| 463 |
+
# to give an error message earlier in case the dest folder
|
| 464 |
+
# somehow cannot be created.
|
| 465 |
+
if os.path.isdir(dest) and len(os.listdir(dest)) != 0:
|
| 466 |
+
raise click.ClickException('--dest folder must be empty')
|
| 467 |
+
os.makedirs(dest, exist_ok=True)
|
| 468 |
+
|
| 469 |
+
def folder_write_bytes(fname: str, data: Union[bytes, str]):
|
| 470 |
+
os.makedirs(os.path.dirname(fname), exist_ok=True)
|
| 471 |
+
with open(fname, 'wb') as fout:
|
| 472 |
+
if isinstance(data, str):
|
| 473 |
+
data = data.encode('utf8')
|
| 474 |
+
fout.write(data)
|
| 475 |
+
return dest, folder_write_bytes, lambda: None
|
| 476 |
+
|
| 477 |
+
#----------------------------------------------------------------------------
|
| 478 |
+
|
| 479 |
+
@click.command()
|
| 480 |
+
@click.option('--source', help='Input directory or archive name', metavar='PATH', type=str, required=True)
|
| 481 |
+
@click.option('--dest', help='Output directory or archive name', metavar='PATH', type=str, required=True)
|
| 482 |
+
@click.option('--max-images', help='Maximum number of images to output', metavar='INT', type=int)
|
| 483 |
+
@click.option('--transform', help='Input crop/resize mode', metavar='MODE', type=click.Choice(['center-crop', 'center-crop-wide']))
|
| 484 |
+
@click.option('--resolution', help='Output resolution (e.g., 512x512)', metavar='WxH', type=parse_tuple)
|
| 485 |
+
@click.option('--labels-only', is_flag=True, help='Only generate dataset.json labels at source root; do not copy or re-encode images.')
|
| 486 |
+
|
| 487 |
+
def main(
|
| 488 |
+
source: str,
|
| 489 |
+
dest: str,
|
| 490 |
+
max_images: Optional[int],
|
| 491 |
+
transform: Optional[str],
|
| 492 |
+
resolution: Optional[Tuple[int, int]],
|
| 493 |
+
labels_only: bool,
|
| 494 |
+
):
|
| 495 |
+
"""Convert an image dataset into a dataset archive usable with StyleGAN2 ADA PyTorch,
|
| 496 |
+
or only generate dataset.json labels in-place.
|
| 497 |
+
|
| 498 |
+
The input dataset format is guessed from the --source argument:
|
| 499 |
+
|
| 500 |
+
\b
|
| 501 |
+
--source *_lmdb/ Load LSUN dataset
|
| 502 |
+
--source cifar-10-python.tar.gz Load CIFAR-10 dataset
|
| 503 |
+
--source train-images-idx3-ubyte.gz Load MNIST dataset
|
| 504 |
+
--source path/ Recursively load all images from path/
|
| 505 |
+
--source dataset.zip Recursively load all images from dataset.zip
|
| 506 |
+
|
| 507 |
+
Specifying the output format and path:
|
| 508 |
+
|
| 509 |
+
\b
|
| 510 |
+
--dest /path/to/dir Save output files under /path/to/dir
|
| 511 |
+
--dest /path/to/dataset.zip Save output files into /path/to/dataset.zip
|
| 512 |
+
|
| 513 |
+
The output dataset format can be either an image folder or an uncompressed zip archive.
|
| 514 |
+
Zip archives makes it easier to move datasets around file servers and clusters, and may
|
| 515 |
+
offer better training performance on network file systems.
|
| 516 |
+
|
| 517 |
+
Images within the dataset archive will be stored as uncompressed PNG.
|
| 518 |
+
Uncompresed PNGs can be efficiently decoded in the training loop.
|
| 519 |
+
|
| 520 |
+
Class labels are stored in a file called 'dataset.json' that is stored at the
|
| 521 |
+
dataset root folder. This file has the following structure:
|
| 522 |
+
|
| 523 |
+
\b
|
| 524 |
+
{
|
| 525 |
+
"labels": [
|
| 526 |
+
["00000/img00000000.png",6],
|
| 527 |
+
["00000/img00000001.png",9],
|
| 528 |
+
... repeated for every image in the datase
|
| 529 |
+
["00049/img00049999.png",1]
|
| 530 |
+
]
|
| 531 |
+
}
|
| 532 |
+
|
| 533 |
+
If the 'dataset.json' file cannot be found, class labels are determined from
|
| 534 |
+
top-level directory names.
|
| 535 |
+
|
| 536 |
+
Image scale/crop and resolution requirements:
|
| 537 |
+
|
| 538 |
+
Output images must be square-shaped and they must all have the same power-of-two
|
| 539 |
+
dimensions.
|
| 540 |
+
|
| 541 |
+
To scale arbitrary input image size to a specific width and height, use the
|
| 542 |
+
--resolution option. Output resolution will be either the original
|
| 543 |
+
input resolution (if resolution was not specified) or the one specified with
|
| 544 |
+
--resolution option.
|
| 545 |
+
|
| 546 |
+
Use the --transform=center-crop or --transform=center-crop-wide options to apply a
|
| 547 |
+
center crop transform on the input image. These options should be used with the
|
| 548 |
+
--resolution option. For example:
|
| 549 |
+
|
| 550 |
+
\b
|
| 551 |
+
python scripts/dataset_tools.py --source data/cat_lmdb --dest data/cat_png \\
|
| 552 |
+
--transform=center-crop-wide --resolution=512x384
|
| 553 |
+
"""
|
| 554 |
+
|
| 555 |
+
# Labels-only mode: just write dataset.json next to the original data.
|
| 556 |
+
if labels_only:
|
| 557 |
+
PIL.Image.init()
|
| 558 |
+
create_labels_only(source)
|
| 559 |
+
return
|
| 560 |
+
|
| 561 |
+
PIL.Image.init()
|
| 562 |
+
|
| 563 |
+
if dest == '':
|
| 564 |
+
raise click.ClickException('--dest output filename or directory must not be an empty string')
|
| 565 |
+
|
| 566 |
+
num_files, input_iter = open_dataset(source, max_images=max_images)
|
| 567 |
+
archive_root_dir, save_bytes, close_dest = open_dest(dest)
|
| 568 |
+
|
| 569 |
+
if resolution is None: resolution = (None, None)
|
| 570 |
+
transform_image = make_transform(transform, *resolution)
|
| 571 |
+
|
| 572 |
+
dataset_attrs = None
|
| 573 |
+
|
| 574 |
+
labels = []
|
| 575 |
+
for idx, image in tqdm(enumerate(input_iter), total=num_files):
|
| 576 |
+
idx_str = f'{idx:08d}'
|
| 577 |
+
archive_fname = f'{idx_str[:5]}/img{idx_str}.png'
|
| 578 |
+
|
| 579 |
+
# Apply crop and resize.
|
| 580 |
+
img = transform_image(image['img'])
|
| 581 |
+
if img is None:
|
| 582 |
+
continue
|
| 583 |
+
|
| 584 |
+
# Error check to require uniform image attributes across
|
| 585 |
+
# the whole dataset.
|
| 586 |
+
channels = img.shape[2] if img.ndim == 3 else 1
|
| 587 |
+
cur_image_attrs = {'width': img.shape[1], 'height': img.shape[0], 'channels': channels}
|
| 588 |
+
if dataset_attrs is None:
|
| 589 |
+
dataset_attrs = cur_image_attrs
|
| 590 |
+
width = dataset_attrs['width']
|
| 591 |
+
height = dataset_attrs['height']
|
| 592 |
+
if width != height:
|
| 593 |
+
raise click.ClickException(f'Image dimensions after scale and crop are required to be square. Got {width}x{height}')
|
| 594 |
+
if dataset_attrs['channels'] not in [1, 3]:
|
| 595 |
+
raise click.ClickException('Input images must be stored as RGB or grayscale')
|
| 596 |
+
if width != 2 ** int(np.floor(np.log2(width))):
|
| 597 |
+
raise click.ClickException('Image width/height after scale and crop are required to be power-of-two')
|
| 598 |
+
elif dataset_attrs != cur_image_attrs:
|
| 599 |
+
err = [f' dataset {k}/cur image {k}: {dataset_attrs[k]}/{cur_image_attrs[k]}' for k in dataset_attrs.keys()]
|
| 600 |
+
raise click.ClickException(f'Image {archive_fname} attributes must be equal across all images of the dataset. Got:\n' + '\n'.join(err))
|
| 601 |
+
|
| 602 |
+
# Save the image as an uncompressed PNG.
|
| 603 |
+
img = PIL.Image.fromarray(img, {1: 'L', 3: 'RGB'}[channels])
|
| 604 |
+
image_bits = io.BytesIO()
|
| 605 |
+
img.save(image_bits, format='png', compress_level=0, optimize=False)
|
| 606 |
+
save_bytes(os.path.join(archive_root_dir, archive_fname), image_bits.getbuffer())
|
| 607 |
+
labels.append([archive_fname, image['label']] if image['label'] is not None else None)
|
| 608 |
+
|
| 609 |
+
metadata = {'labels': labels if all(x is not None for x in labels) else None}
|
| 610 |
+
save_bytes(os.path.join(archive_root_dir, 'dataset.json'), json.dumps(metadata))
|
| 611 |
+
close_dest()
|
| 612 |
+
|
| 613 |
+
#----------------------------------------------------------------------------
|
| 614 |
+
|
| 615 |
+
if __name__ == "__main__":
|
| 616 |
+
main()
|
| 617 |
+
|
| 618 |
+
#----------------------------------------------------------------------------
|
scripts/evaluate_all.py
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Evaluate CIFAR-10 checkpoints with independent per-GPU seeds."""
|
| 2 |
+
import argparse
|
| 3 |
+
import csv
|
| 4 |
+
import hashlib
|
| 5 |
+
import io
|
| 6 |
+
import json
|
| 7 |
+
import os
|
| 8 |
+
from pathlib import Path
|
| 9 |
+
import subprocess
|
| 10 |
+
import sys
|
| 11 |
+
import time
|
| 12 |
+
|
| 13 |
+
ROOT = Path(__file__).resolve().parents[1]
|
| 14 |
+
|
| 15 |
+
# Method names match configuration prefixes and checkpoint filenames.
|
| 16 |
+
CONFIGS = {
|
| 17 |
+
"baseline": "baseline_ar.yaml",
|
| 18 |
+
"tail_dropout": "tail_dropout_ar.yaml",
|
| 19 |
+
"flow_matching": "flow_matching_ar.yaml",
|
| 20 |
+
"flow_matching_tail_dropout": "flow_matching_tail_dropout_ar.yaml",
|
| 21 |
+
"flow_matching_tied_tail_dropout": "flow_matching_tied_tail_dropout_ar.yaml",
|
| 22 |
+
"war": "war_ar.yaml"
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def sha256(path):
|
| 27 |
+
digest = hashlib.sha256()
|
| 28 |
+
with open(path, 'rb') as f:
|
| 29 |
+
for block in iter(lambda: f.read(8 * 1024 * 1024), b''):
|
| 30 |
+
digest.update(block)
|
| 31 |
+
return digest.hexdigest()
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def check_free(gpus):
|
| 35 |
+
output = subprocess.check_output(
|
| 36 |
+
['nvidia-smi', '--query-gpu=index,memory.used,utilization.gpu',
|
| 37 |
+
'--format=csv,noheader,nounits'], text=True)
|
| 38 |
+
devices = {int(row[0]): (int(row[1]), int(row[2]))
|
| 39 |
+
for row in csv.reader(io.StringIO(output))}
|
| 40 |
+
busy = {gpu: devices.get(gpu) for gpu in gpus
|
| 41 |
+
if gpu not in devices or devices[gpu][0] > 100 or devices[gpu][1] > 0}
|
| 42 |
+
if busy:
|
| 43 |
+
raise RuntimeError(f'Requested GPUs are not free: {busy}')
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
def save_summary(output, rows):
|
| 47 |
+
(output / 'results.json').write_text(json.dumps(rows, indent=2) + '\n')
|
| 48 |
+
if rows:
|
| 49 |
+
with (output / 'results.csv').open('w', newline='') as f:
|
| 50 |
+
writer = csv.DictWriter(f, fieldnames=list(rows[0]))
|
| 51 |
+
writer.writeheader()
|
| 52 |
+
writer.writerows(rows)
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
def main():
|
| 56 |
+
parser = argparse.ArgumentParser(description=__doc__)
|
| 57 |
+
parser.add_argument('--gpus', default='0,1,2,3,4,5,6,7')
|
| 58 |
+
parser.add_argument('--output', default='outputs/cifar10-nonlegacy')
|
| 59 |
+
parser.add_argument('--methods', nargs='+', choices=CONFIGS,
|
| 60 |
+
help='Optional subset, e.g. baseline war')
|
| 61 |
+
parser.add_argument('--resume', action='store_true', help='Reuse matching completed evaluations')
|
| 62 |
+
args = parser.parse_args()
|
| 63 |
+
gpus = [int(x) for x in args.gpus.split(',')]
|
| 64 |
+
if not gpus or len(gpus) != len(set(gpus)):
|
| 65 |
+
parser.error('GPU IDs must be nonempty and distinct')
|
| 66 |
+
configs = {key: ROOT / 'configs/cifar10' / name for key, name in CONFIGS.items()}
|
| 67 |
+
for config in configs.values():
|
| 68 |
+
if not config.is_file():
|
| 69 |
+
raise FileNotFoundError(config)
|
| 70 |
+
if args.methods:
|
| 71 |
+
if set(args.methods) - configs.keys():
|
| 72 |
+
parser.error('Unknown method')
|
| 73 |
+
configs = {key: path for key, path in configs.items() if key in args.methods}
|
| 74 |
+
checkpoints = {key: ROOT / 'checkpoints' / f'{key}.pt' for key in configs}
|
| 75 |
+
for checkpoint in checkpoints.values():
|
| 76 |
+
if not checkpoint.is_file():
|
| 77 |
+
raise FileNotFoundError(f'Place the downloaded checkpoint at {checkpoint}')
|
| 78 |
+
reference = ROOT / 'refs/cifar10-32x32_local.npz'
|
| 79 |
+
reference_hash = sha256(reference)
|
| 80 |
+
if reference_hash != '5493968c4f29b2878f64d6a640351f377e32e86553db56eca8147a0ae50d93f2':
|
| 81 |
+
raise ValueError('The CIFAR-10 FID reference checksum does not match')
|
| 82 |
+
output = Path(args.output).resolve()
|
| 83 |
+
output.mkdir(parents=True, exist_ok=True)
|
| 84 |
+
env = os.environ.copy()
|
| 85 |
+
env.update(CUDA_VISIBLE_DEVICES=','.join(map(str, gpus)), PYTHONDONTWRITEBYTECODE='1',
|
| 86 |
+
WANDB_MODE='disabled', OMP_NUM_THREADS='8', MKL_NUM_THREADS='8', TF_CPP_MIN_LOG_LEVEL='2')
|
| 87 |
+
rows = []
|
| 88 |
+
for key, config in configs.items():
|
| 89 |
+
checkpoint = checkpoints[key]
|
| 90 |
+
checkpoint_hash, config_hash = sha256(checkpoint), sha256(config)
|
| 91 |
+
case = output / key
|
| 92 |
+
result_path = case / 'metrics.json'
|
| 93 |
+
if result_path.exists() and not args.resume:
|
| 94 |
+
raise FileExistsError(result_path)
|
| 95 |
+
if not result_path.exists():
|
| 96 |
+
check_free(gpus)
|
| 97 |
+
case.mkdir(exist_ok=True)
|
| 98 |
+
cmd = [sys.executable, '-m', 'torch.distributed.run', '--standalone',
|
| 99 |
+
f'--nproc-per-node={len(gpus)}', 'evaluate.py', '--config', str(config),
|
| 100 |
+
'--checkpoint', str(checkpoint), '--num-samples', '50000', '--batch-size', '64',
|
| 101 |
+
'--seed', '42', '--no-legacy', '--output', str(case), '--fid-reference', str(reference)]
|
| 102 |
+
request = dict(command=cmd, checkpoint_sha256=checkpoint_hash,
|
| 103 |
+
config_sha256=config_hash, legacy=False)
|
| 104 |
+
(case / 'request.json').write_text(json.dumps(request, indent=2) + '\n')
|
| 105 |
+
print(f'START {key}', flush=True)
|
| 106 |
+
started = time.monotonic()
|
| 107 |
+
with (case / 'run.log').open('w') as log:
|
| 108 |
+
subprocess.run(cmd, cwd=ROOT, env=env, stdout=log, stderr=subprocess.STDOUT, check=True)
|
| 109 |
+
print(f'DONE {key} in {time.monotonic() - started:.1f}s', flush=True)
|
| 110 |
+
result = json.loads(result_path.read_text())
|
| 111 |
+
request = json.loads((case / 'request.json').read_text())
|
| 112 |
+
if request['checkpoint_sha256'] != checkpoint_hash:
|
| 113 |
+
raise ValueError(f'{key}: checkpoint changed since the recorded evaluation')
|
| 114 |
+
expected = dict(legacy=False, num_samples=50000, seed=42, world_size=len(gpus),
|
| 115 |
+
batch_size=64, ar_ema=True, precision='32-true', decoder='single_step',
|
| 116 |
+
config_sha256=config_hash, reference_sha256=reference_hash)
|
| 117 |
+
if any(result.get(name) != value for name, value in expected.items()):
|
| 118 |
+
raise ValueError(f'{key}: recorded evaluation settings do not match')
|
| 119 |
+
row = dict(method=key, nonlegacy_gfid=result['fid'], unique_images=result['unique_images'],
|
| 120 |
+
num_samples=result['num_samples'], legacy=False,
|
| 121 |
+
checkpoint_sha256=checkpoint_hash, config_sha256=config_hash,
|
| 122 |
+
reference_sha256=reference_hash)
|
| 123 |
+
rows.append(row)
|
| 124 |
+
save_summary(output, rows)
|
| 125 |
+
print(f'RESULT {key}: {result["fid"]:.8f}', flush=True)
|
| 126 |
+
print(f'COMPLETE: {len(rows)} non-legacy evaluations', flush=True)
|
| 127 |
+
|
| 128 |
+
|
| 129 |
+
if __name__ == '__main__':
|
| 130 |
+
main()
|
scripts/export_checkpoint.py
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Export inference states without optimizer, paths, or experiment tracker metadata."""
|
| 2 |
+
import argparse
|
| 3 |
+
import hashlib
|
| 4 |
+
import json
|
| 5 |
+
from pathlib import Path
|
| 6 |
+
import sys
|
| 7 |
+
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
| 8 |
+
import torch
|
| 9 |
+
from omegaconf import OmegaConf
|
| 10 |
+
from models import Encoder, Decoder, ARModel
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
def sha256(path):
|
| 14 |
+
digest=hashlib.sha256()
|
| 15 |
+
with open(path,'rb') as f:
|
| 16 |
+
for block in iter(lambda:f.read(8*1024*1024),b''): digest.update(block)
|
| 17 |
+
return digest.hexdigest()
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
def export(source, config, output):
|
| 21 |
+
source_state=torch.load(source, map_location='cpu', weights_only=True, mmap=True)
|
| 22 |
+
c=OmegaConf.load(config)
|
| 23 |
+
states={key:{name.removeprefix('_orig_mod.'): tensor for name,tensor in source_state[key].items()}
|
| 24 |
+
for key in ('enc','dec','ar_model','ar_model_ema')}
|
| 25 |
+
for cls,key in ((Encoder,'enc'),(Decoder,'dec'),(ARModel,'ar_model'),(ARModel,'ar_model_ema')):
|
| 26 |
+
# Assignment checks all keys/shapes without allocating a second model's storage.
|
| 27 |
+
with torch.device('meta'): model=cls(c)
|
| 28 |
+
model.load_state_dict(states[key],strict=True,assign=True)
|
| 29 |
+
del model
|
| 30 |
+
out=Path(output); out.parent.mkdir(parents=True,exist_ok=True)
|
| 31 |
+
if out.exists(): raise FileExistsError(out)
|
| 32 |
+
torch.save(dict(format_version=1,**states),out)
|
| 33 |
+
saved=torch.load(out,map_location='cpu',weights_only=True,mmap=True)
|
| 34 |
+
for key,state in states.items():
|
| 35 |
+
for name,tensor in state.items():
|
| 36 |
+
if not torch.equal(tensor,saved[key][name]): raise AssertionError((key,name))
|
| 37 |
+
return dict(filename=out.name,sha256=sha256(out),bytes=out.stat().st_size)
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
def main():
|
| 41 |
+
p=argparse.ArgumentParser(description=__doc__)
|
| 42 |
+
p.add_argument('--source',required=True); p.add_argument('--config',required=True); p.add_argument('--output',required=True)
|
| 43 |
+
a=p.parse_args(); result=export(a.source,a.config,a.output)
|
| 44 |
+
Path(a.output+'.json').write_text(json.dumps(result,indent=2)+'\n'); print(json.dumps(result))
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
if __name__=='__main__': main()
|
scripts/prepare_cifar10.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Convert the official CIFAR-10 training split into the wARTok PNG layout."""
|
| 2 |
+
import argparse
|
| 3 |
+
import json
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
import numpy as np
|
| 6 |
+
from PIL import Image
|
| 7 |
+
from torchvision.datasets import CIFAR10
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def main():
|
| 11 |
+
p=argparse.ArgumentParser(description=__doc__)
|
| 12 |
+
p.add_argument('--download-dir',default='./data/downloads')
|
| 13 |
+
p.add_argument('--output',default='./data/cifar10')
|
| 14 |
+
p.add_argument('--download',action='store_true')
|
| 15 |
+
p.add_argument('--reference-images',help='Optional NPZ of the same 50K training images for ADM statistics')
|
| 16 |
+
a=p.parse_args(); out=Path(a.output)
|
| 17 |
+
if out.exists() and any(out.iterdir()): p.error('output must be empty to prevent mixing splits')
|
| 18 |
+
ds=CIFAR10(a.download_dir,train=True,download=a.download)
|
| 19 |
+
assert len(ds)==50000
|
| 20 |
+
labels=[]
|
| 21 |
+
for i,(image,label) in enumerate(ds):
|
| 22 |
+
name=f'{i//1000:05d}/img{i:08d}.png'
|
| 23 |
+
path=out/name; path.parent.mkdir(parents=True,exist_ok=True)
|
| 24 |
+
image.save(path); labels.append([name,label])
|
| 25 |
+
(out/'dataset.json').write_text(json.dumps({'labels':labels}))
|
| 26 |
+
if a.reference_images:
|
| 27 |
+
with open(a.reference_images,'xb') as f: np.savez_compressed(f,ds.data)
|
| 28 |
+
print(f'Wrote {len(ds)} training images to {out}')
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
if __name__=='__main__': main()
|
train.py
ADDED
|
@@ -0,0 +1,1209 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import itertools
|
| 2 |
+
import math
|
| 3 |
+
import os
|
| 4 |
+
import random
|
| 5 |
+
import subprocess
|
| 6 |
+
import sys
|
| 7 |
+
from pathlib import Path
|
| 8 |
+
from typing import Iterable, Iterator, List, NamedTuple
|
| 9 |
+
os.environ.setdefault("WANDB_MODE", "disabled")
|
| 10 |
+
import wandb
|
| 11 |
+
import numpy as np
|
| 12 |
+
import torch
|
| 13 |
+
from torch import nn
|
| 14 |
+
import torch.nn.functional as F
|
| 15 |
+
import torchvision.utils
|
| 16 |
+
from einops import rearrange
|
| 17 |
+
from lightning import Fabric
|
| 18 |
+
from wandb.integration.lightning.fabric import WandbLogger
|
| 19 |
+
from dataset import ImageFolderDataset
|
| 20 |
+
from gan_loss import GANLoss
|
| 21 |
+
from lpips import LPIPS
|
| 22 |
+
from models import ARModel, Encoder, Decoder, Linear
|
| 23 |
+
from tqdm import tqdm
|
| 24 |
+
from omegaconf import OmegaConf
|
| 25 |
+
from torch.utils.data import DataLoader
|
| 26 |
+
import copy
|
| 27 |
+
import torch.distributed as dist
|
| 28 |
+
from glob import glob
|
| 29 |
+
try:
|
| 30 |
+
from thop import profile
|
| 31 |
+
from thop.vision.basic_hooks import count_linear
|
| 32 |
+
except ImportError:
|
| 33 |
+
profile = None
|
| 34 |
+
count_linear = None
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
torch.backends.cudnn.benchmark = True
|
| 38 |
+
torch.backends.cudnn.deterministic = False
|
| 39 |
+
|
| 40 |
+
# Phase utils
|
| 41 |
+
class Target(NamedTuple):
|
| 42 |
+
DO_AE: bool = False
|
| 43 |
+
DO_L2: bool = False
|
| 44 |
+
DO_L1: bool = False
|
| 45 |
+
DO_LPIPS: bool = False
|
| 46 |
+
DO_GAN_G: bool = False
|
| 47 |
+
DO_GAN_D: bool = False
|
| 48 |
+
DO_PRIOR_ENC: bool = False
|
| 49 |
+
DO_PRIOR_AR: bool = False
|
| 50 |
+
|
| 51 |
+
class Phase(NamedTuple):
|
| 52 |
+
num_steps: int
|
| 53 |
+
targets: List[Target]
|
| 54 |
+
internal_steps: List[int]
|
| 55 |
+
|
| 56 |
+
# Parse phases such as "1000:DO_L2-DO_PRIOR_AR:1 7000:DO_PRIOR_AR:1".
|
| 57 |
+
def parse_phases(phases_str):
|
| 58 |
+
phases = [] # list of Phase objects
|
| 59 |
+
for phase_str in phases_str.split(' '):
|
| 60 |
+
num_steps, targets_str, internal_steps_str = phase_str.split(':')
|
| 61 |
+
num_steps = int(num_steps)
|
| 62 |
+
targets = [Target(**{k: True for obj in target_str.split(',') for k in obj.split('-') }) for target_str in targets_str.split(',')]
|
| 63 |
+
internal_steps = [int(step) for step in internal_steps_str.split(',')]
|
| 64 |
+
phases.append(Phase(num_steps, targets, internal_steps))
|
| 65 |
+
return phases
|
| 66 |
+
|
| 67 |
+
def get_phase(global_step, phases, phase_step_accum, config):
|
| 68 |
+
target=None
|
| 69 |
+
for phase_idx, phase_step in enumerate(phase_step_accum):
|
| 70 |
+
if global_step <= phase_step:
|
| 71 |
+
internel_step = (global_step - phase_step_accum[phase_idx-1]) if phase_idx > 0 else global_step
|
| 72 |
+
internel_accumulate = list(itertools.accumulate(phases[phase_idx].internal_steps))
|
| 73 |
+
internel_step = internel_step % internel_accumulate[-1]
|
| 74 |
+
|
| 75 |
+
for inner_idx in range(len(internel_accumulate)):
|
| 76 |
+
if internel_step < internel_accumulate[inner_idx]:
|
| 77 |
+
target = phases[phase_idx].targets[inner_idx]
|
| 78 |
+
break
|
| 79 |
+
if target is not None:
|
| 80 |
+
break
|
| 81 |
+
|
| 82 |
+
DO_AE = any([target.DO_L2, target.DO_L1, target.DO_LPIPS, target.DO_GAN_G])
|
| 83 |
+
|
| 84 |
+
# assert inconsistency configuration
|
| 85 |
+
assert not (DO_AE and not config.train_ae), f"train_ae={config.train_ae} is inconsistent with DO_AE={DO_AE} in phases"
|
| 86 |
+
assert not (target.DO_PRIOR_AR and not config.train_ar), f"train_ar={config.train_ar} is inconsistent with DO_PRIOR_AR={target.DO_PRIOR_AR} in phases"
|
| 87 |
+
assert not ((target.DO_GAN_G or target.DO_GAN_D) and not config.use_gan_loss), f"use_gan_loss={config.use_gan_loss} is inconsistent with DO_GAN_G or DO_GAN_D={(target.DO_GAN_G or target.DO_GAN_D)} in phases"
|
| 88 |
+
assert not (target.DO_PRIOR_ENC and not config.use_prior_loss), f"use_prior_loss={config.use_prior_loss} is inconsistent with DO_PRIOR_ENC={target.DO_PRIOR_ENC} in phases"
|
| 89 |
+
assert not (target.DO_LPIPS and not config.use_lpips_loss), f"use_lpips_loss={config.use_lpips_loss} is inconsistent with DO_LPIPS={target.DO_LPIPS} in phases"
|
| 90 |
+
|
| 91 |
+
# update target with global_step
|
| 92 |
+
target = Target(DO_L1=target.DO_L1,
|
| 93 |
+
DO_L2=target.DO_L2,
|
| 94 |
+
DO_LPIPS=target.DO_LPIPS,
|
| 95 |
+
DO_GAN_G=target.DO_GAN_G and (global_step >= config.gan_start),
|
| 96 |
+
DO_GAN_D=target.DO_GAN_D and (global_step >= config.gan_start),
|
| 97 |
+
DO_PRIOR_ENC=target.DO_PRIOR_ENC and (global_step >= config.prior_start),
|
| 98 |
+
DO_PRIOR_AR=target.DO_PRIOR_AR,
|
| 99 |
+
DO_AE=DO_AE)
|
| 100 |
+
return phase_idx, inner_idx, target, internel_step
|
| 101 |
+
|
| 102 |
+
class InfiniteIterator(Iterator):
|
| 103 |
+
def __init__(self, iterable: Iterable):
|
| 104 |
+
self.iterable = iterable
|
| 105 |
+
self._it = iter(iterable)
|
| 106 |
+
|
| 107 |
+
def __iter__(self):
|
| 108 |
+
return self
|
| 109 |
+
|
| 110 |
+
def __next__(self):
|
| 111 |
+
try:
|
| 112 |
+
return next(self._it)
|
| 113 |
+
except StopIteration:
|
| 114 |
+
self._it = iter(self.iterable)
|
| 115 |
+
return next(self._it)
|
| 116 |
+
|
| 117 |
+
# Image Processing Utils
|
| 118 |
+
def patchify(x, patch_size):
|
| 119 |
+
x = rearrange(x, 'b c (h p1) (w p2) -> b (h w) (p1 p2 c)', p1=patch_size, p2=patch_size)
|
| 120 |
+
return x
|
| 121 |
+
|
| 122 |
+
def unpatchify(x, image_size, patch_size):
|
| 123 |
+
x = rearrange(x, 'b (h w) (p1 p2 c) -> b c (h p1) (w p2)', p1=patch_size, p2=patch_size, h=image_size//patch_size, w=image_size//patch_size)
|
| 124 |
+
return x
|
| 125 |
+
|
| 126 |
+
def img_unint8_to_norm(x):
|
| 127 |
+
return x.float() / 127.5 - 1.0
|
| 128 |
+
|
| 129 |
+
def img_denormalize(x):
|
| 130 |
+
return x.clamp(-1,1) * 0.5 + 0.5
|
| 131 |
+
|
| 132 |
+
def img_norm_to_uint8(x):
|
| 133 |
+
return torch.clamp(127.5 * x + 128.0, 0, 255).byte()
|
| 134 |
+
|
| 135 |
+
# -----------------------------
|
| 136 |
+
# Tail-dropout + noise-query utils
|
| 137 |
+
# -----------------------------
|
| 138 |
+
|
| 139 |
+
def _get_decoder_context_type(dec: nn.Module) -> str:
|
| 140 |
+
# `dec` is Decoder, `dec.dec` is Transformer
|
| 141 |
+
ctx = getattr(getattr(dec, "dec", None), "context_type", None)
|
| 142 |
+
return ctx if ctx is not None else "none"
|
| 143 |
+
|
| 144 |
+
def _get_decoder_query_len(dec: nn.Module) -> int:
|
| 145 |
+
return int(getattr(getattr(dec, "dec", None), "max_seq_len", 0))
|
| 146 |
+
|
| 147 |
+
def _t_to_k(t: torch.Tensor, K: int, t2k: float = 1.0) -> torch.Tensor:
|
| 148 |
+
"""
|
| 149 |
+
Map t in [0,1] to discrete k in [0, K-1].
|
| 150 |
+
"""
|
| 151 |
+
if K <= 1:
|
| 152 |
+
return torch.zeros_like(t, dtype=torch.long)
|
| 153 |
+
t_tmp = (t2k * t).clamp(0.0, 1.0)
|
| 154 |
+
k = torch.floor(t_tmp * K).to(torch.long).clamp(0, K - 1)
|
| 155 |
+
return k
|
| 156 |
+
|
| 157 |
+
class DiTiScheduler:
|
| 158 |
+
"""
|
| 159 |
+
Piecewise linear time scheduler from Selftok, adapted for wARTok.
|
| 160 |
+
"""
|
| 161 |
+
def __init__(
|
| 162 |
+
self,
|
| 163 |
+
n_timesteps: int,
|
| 164 |
+
K: int,
|
| 165 |
+
stages: str | List[int],
|
| 166 |
+
k_per_stage: str | List[int],
|
| 167 |
+
reverse_t: bool = False,
|
| 168 |
+
):
|
| 169 |
+
self.n_timesteps = n_timesteps
|
| 170 |
+
self.K = K
|
| 171 |
+
self.reverse_t = reverse_t
|
| 172 |
+
|
| 173 |
+
if isinstance(stages, str):
|
| 174 |
+
stages = [int(s.strip()) for s in stages.split(',')]
|
| 175 |
+
if isinstance(k_per_stage, str):
|
| 176 |
+
k_per_stage = [int(k.strip()) for k in k_per_stage.split(',')]
|
| 177 |
+
self.stages = stages
|
| 178 |
+
|
| 179 |
+
# Scaling logic: if sum(k_per_stage) != K, scale it
|
| 180 |
+
total_k = sum(k_per_stage)
|
| 181 |
+
if total_k != K:
|
| 182 |
+
print(f"[DiTiScheduler] Warning: sum(k_per_stage)={total_k} does not match K={K}. Scaling k_per_stage...")
|
| 183 |
+
scale_factor = K / total_k
|
| 184 |
+
scaled_k = [int(k * scale_factor) for k in k_per_stage]
|
| 185 |
+
# Fix rounding errors to ensure sum is exactly K
|
| 186 |
+
diff = K - sum(scaled_k)
|
| 187 |
+
if diff != 0:
|
| 188 |
+
scaled_k[-1] += diff
|
| 189 |
+
k_per_stage = scaled_k
|
| 190 |
+
print(f"[DiTiScheduler] Scaled k_per_stage: {k_per_stage}")
|
| 191 |
+
|
| 192 |
+
self.k_per_stage = k_per_stage
|
| 193 |
+
|
| 194 |
+
self.t_to_idx = torch.zeros(n_timesteps).long()
|
| 195 |
+
|
| 196 |
+
# Precompute lookup table
|
| 197 |
+
current_stage = 0
|
| 198 |
+
sum_indices = 0
|
| 199 |
+
# stages should be cumulative, e.g., 200, 400, 600...
|
| 200 |
+
|
| 201 |
+
for t in range(n_timesteps):
|
| 202 |
+
# Check if we moved to next stage
|
| 203 |
+
if current_stage < len(self.stages) and t >= self.stages[current_stage]:
|
| 204 |
+
sum_indices += self.k_per_stage[current_stage]
|
| 205 |
+
current_stage += 1
|
| 206 |
+
|
| 207 |
+
if current_stage >= len(self.stages):
|
| 208 |
+
idx = self.K - 1
|
| 209 |
+
else:
|
| 210 |
+
prev_stage_t = self.stages[current_stage - 1] if current_stage > 0 else 0
|
| 211 |
+
current_stage_t = self.stages[current_stage]
|
| 212 |
+
|
| 213 |
+
current_steps = float(current_stage_t - prev_stage_t)
|
| 214 |
+
current_k = float(self.k_per_stage[current_stage])
|
| 215 |
+
|
| 216 |
+
t_adj = t - prev_stage_t
|
| 217 |
+
idx = int(float(t_adj) / current_steps * current_k + sum_indices)
|
| 218 |
+
|
| 219 |
+
self.t_to_idx[t] = idx
|
| 220 |
+
|
| 221 |
+
def to_indices(self, t: torch.Tensor) -> torch.Tensor:
|
| 222 |
+
"""
|
| 223 |
+
Convert t in [0, 1] to indices [0, K-1] using the lookup table.
|
| 224 |
+
"""
|
| 225 |
+
if self.reverse_t:
|
| 226 |
+
t = 1.0-t
|
| 227 |
+
device = t.device
|
| 228 |
+
# Map [0, 1] to [0, n_timesteps]
|
| 229 |
+
t_idx = (t * self.n_timesteps).long().clamp(0, self.n_timesteps - 1)
|
| 230 |
+
# Move the lookup table to the input device.
|
| 231 |
+
return self.t_to_idx.to(device)[t_idx].clamp(0, self.K - 1)
|
| 232 |
+
|
| 233 |
+
|
| 234 |
+
def build_taildrop_attn_mask(
|
| 235 |
+
*,
|
| 236 |
+
t: torch.Tensor,
|
| 237 |
+
context_len: int,
|
| 238 |
+
query_len: int,
|
| 239 |
+
context_type: str,
|
| 240 |
+
t2k: float = 1.0,
|
| 241 |
+
device=None,
|
| 242 |
+
diti_scheduler: DiTiScheduler = None,
|
| 243 |
+
) -> torch.Tensor | None:
|
| 244 |
+
"""
|
| 245 |
+
Build a boolean attention mask (True for keep, False for masked).
|
| 246 |
+
|
| 247 |
+
- cross_attn: returns (B, 1, query_len, context_len)
|
| 248 |
+
- concat: returns (B, 1, total_len, total_len) where total_len = query_len + context_len
|
| 249 |
+
"""
|
| 250 |
+
device = device or t.device
|
| 251 |
+
B = t.shape[0]
|
| 252 |
+
if context_len <= 0:
|
| 253 |
+
return None
|
| 254 |
+
|
| 255 |
+
if diti_scheduler is not None:
|
| 256 |
+
k = diti_scheduler.to_indices(t) # (B,)
|
| 257 |
+
else:
|
| 258 |
+
k = _t_to_k(t, context_len, t2k=t2k) # (B,)
|
| 259 |
+
|
| 260 |
+
keep = (torch.arange(context_len, device=device)[None, :] <= k[:, None]) # (B, context_len)
|
| 261 |
+
|
| 262 |
+
|
| 263 |
+
if context_type == "cross_attn":
|
| 264 |
+
# (B, 1, query_len, context_len)
|
| 265 |
+
return keep[:, None, :].unsqueeze(1).expand(B, 1, query_len, context_len)
|
| 266 |
+
|
| 267 |
+
if context_type == "concat":
|
| 268 |
+
total_len = query_len + context_len
|
| 269 |
+
keep_total = torch.cat(
|
| 270 |
+
[torch.ones((B, query_len), device=device, dtype=torch.bool), keep],
|
| 271 |
+
dim=1,
|
| 272 |
+
) # (B, total_len)
|
| 273 |
+
# (B, 1, total_len, total_len)
|
| 274 |
+
return keep_total[:, None, :].unsqueeze(1).expand(B, 1, total_len, total_len)
|
| 275 |
+
|
| 276 |
+
return None
|
| 277 |
+
|
| 278 |
+
def make_noise_image_patch_query(x: torch.Tensor, t: torch.Tensor, query_len: int) -> torch.Tensor:
|
| 279 |
+
"""
|
| 280 |
+
Replace dummy query with a noised version of the (clean) image patches x.
|
| 281 |
+
x: (B, L, D)
|
| 282 |
+
t: (B,)
|
| 283 |
+
Returns noised patches, noise, and velocity, each of shape (B, L, D).
|
| 284 |
+
"""
|
| 285 |
+
B, L, D = x.shape
|
| 286 |
+
noise = torch.randn_like(x)
|
| 287 |
+
t = t.view(B, 1, 1).to(x.dtype)
|
| 288 |
+
x_noised = (1.0 - t) * x + t * noise
|
| 289 |
+
return x_noised, noise, noise-x
|
| 290 |
+
|
| 291 |
+
# Seed utils
|
| 292 |
+
def seed_everything(seed):
|
| 293 |
+
# manually call these to ensure reproducibility
|
| 294 |
+
random.seed(seed)
|
| 295 |
+
np.random.seed(seed)
|
| 296 |
+
torch.manual_seed(seed)
|
| 297 |
+
torch.cuda.manual_seed_all(seed)
|
| 298 |
+
os.environ['PYTHONHASHSEED'] = str(seed)
|
| 299 |
+
# fabric seed everything
|
| 300 |
+
Fabric.seed_everything(seed, workers=True)
|
| 301 |
+
|
| 302 |
+
def worker_init_fn(worker_id):
|
| 303 |
+
worker_seed = torch.initial_seed() % 2**32
|
| 304 |
+
np.random.seed(worker_seed)
|
| 305 |
+
random.seed(worker_seed)
|
| 306 |
+
|
| 307 |
+
|
| 308 |
+
def make_worker_init_fn(base_seed: int):
|
| 309 |
+
base_seed = int(base_seed) % (2**32)
|
| 310 |
+
|
| 311 |
+
def _init(worker_id: int):
|
| 312 |
+
rank = dist.get_rank() if dist.is_available() and dist.is_initialized() else 0
|
| 313 |
+
worker_seed = (base_seed + worker_id + 1000 * rank) % (2**32)
|
| 314 |
+
np.random.seed(worker_seed)
|
| 315 |
+
random.seed(worker_seed)
|
| 316 |
+
torch.manual_seed(worker_seed)
|
| 317 |
+
|
| 318 |
+
return _init
|
| 319 |
+
|
| 320 |
+
|
| 321 |
+
# FID Utils
|
| 322 |
+
def adm_fid_evaluator(sample_cached_path, gt_cache_path, config, fabric):
|
| 323 |
+
if not os.path.exists(gt_cache_path):
|
| 324 |
+
raise FileNotFoundError(f"Ground-truth cache not found: {gt_cache_path}")
|
| 325 |
+
if not os.path.exists(sample_cached_path):
|
| 326 |
+
raise FileNotFoundError(f"Sample cache not found: {sample_cached_path}")
|
| 327 |
+
|
| 328 |
+
fid_script = str(Path(__file__).with_name('calc_fid.py'))
|
| 329 |
+
env = os.environ.copy()
|
| 330 |
+
cmd = [sys.executable,fid_script,"--ref_batch",gt_cache_path,"--sample_batch",sample_cached_path,"--batch_size",str(config.eval_batch_size),]
|
| 331 |
+
fabric.print(f"Running FID evaluation via {fid_script}...")
|
| 332 |
+
|
| 333 |
+
FID = None
|
| 334 |
+
process = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.STDOUT,text=True,bufsize=1,env=env,)
|
| 335 |
+
assert process.stdout is not None
|
| 336 |
+
for line in process.stdout:
|
| 337 |
+
line = line.rstrip("\n")
|
| 338 |
+
if line:
|
| 339 |
+
fabric.print(line, flush=True)
|
| 340 |
+
if line.startswith("FID_RESULT:"):
|
| 341 |
+
try:
|
| 342 |
+
FID = float(line.split("FID_RESULT:")[1].strip())
|
| 343 |
+
except ValueError:
|
| 344 |
+
pass
|
| 345 |
+
retcode = process.wait()
|
| 346 |
+
if retcode != 0 or FID is None or not math.isfinite(FID):
|
| 347 |
+
raise RuntimeError(f"FID evaluation failed: exit={retcode}, result={FID}")
|
| 348 |
+
|
| 349 |
+
return FID
|
| 350 |
+
|
| 351 |
+
|
| 352 |
+
# Training Utils
|
| 353 |
+
@torch.no_grad()
|
| 354 |
+
@torch._dynamo.disable
|
| 355 |
+
def ema_update(model, ema_model, ema_rate):
|
| 356 |
+
if model is None or ema_model is None:
|
| 357 |
+
return
|
| 358 |
+
|
| 359 |
+
for p,ema_p in zip(model.parameters(),ema_model.parameters()):
|
| 360 |
+
ema_p.copy_(p.detach().lerp(ema_p, ema_rate))
|
| 361 |
+
|
| 362 |
+
|
| 363 |
+
|
| 364 |
+
@torch.no_grad()
|
| 365 |
+
@torch._dynamo.disable
|
| 366 |
+
def sampling(enc, dec, ar_model, bz, class_label=None, temperature=1.0, topK=0, topP=0., cfg=0.0, cfg_schedule=None, cfg_power=None, cache_kv=False, config=None,t=None,query_tokens=None, **params):
|
| 367 |
+
token_ids = ar_model.sampling(bz, class_label, temperature, topK, topP, cfg, cfg_schedule, cfg_power, cache_kv)
|
| 368 |
+
quant = enc.quantizer.get_codes_w_indices(token_ids)
|
| 369 |
+
decoded = dec(quant, class_label, attn_mask=None, query_tokens=query_tokens,t=t)
|
| 370 |
+
return decoded
|
| 371 |
+
|
| 372 |
+
@torch.no_grad()
|
| 373 |
+
@torch._dynamo.disable
|
| 374 |
+
def reconstruction(enc, dec, x, labels, return_idx: bool = False, query_tokens=None,t=None):
|
| 375 |
+
quant, idx, _, _ = enc(x,labels, training=False)
|
| 376 |
+
decoded = dec(quant, labels, attn_mask=None, query_tokens=query_tokens, t=t)
|
| 377 |
+
return decoded, idx
|
| 378 |
+
|
| 379 |
+
@torch.no_grad()
|
| 380 |
+
@torch._dynamo.disable
|
| 381 |
+
def euler_sample_loop(enc, dec, ar_model, bz, class_label=None, temperature=1.0, topK=None, topP=None, cfg=1.0, cfg_schedule=None, cfg_power=None, cache_kv=False, config=None, diti_scheduler=None):
|
| 382 |
+
"""
|
| 383 |
+
Euler solver for Flow Matching with dynamic token masking (DiTi).
|
| 384 |
+
"""
|
| 385 |
+
if config is None:
|
| 386 |
+
raise ValueError("config is required for euler_sample_loop")
|
| 387 |
+
# Derive device / shape from config to avoid relying on outer-scope globals.
|
| 388 |
+
device = next(dec.parameters()).device
|
| 389 |
+
patch_dim = config.patch_dim
|
| 390 |
+
token_ids = ar_model.sampling(bz, class_label, temperature, topK, topP, cfg, cfg_schedule, cfg_power, cache_kv)
|
| 391 |
+
quant = enc.quantizer.get_codes_w_indices(token_ids)
|
| 392 |
+
query_len = config.x_len
|
| 393 |
+
|
| 394 |
+
num_steps = 25
|
| 395 |
+
x = torch.randn((bz, query_len, patch_dim), device=device)
|
| 396 |
+
context_len = quant.shape[1]
|
| 397 |
+
timesteps = torch.linspace(1.0, 0.0, num_steps + 1, device=device)
|
| 398 |
+
dt = 1.0 / num_steps
|
| 399 |
+
|
| 400 |
+
for i in range(num_steps):
|
| 401 |
+
t_curr = timesteps[i]
|
| 402 |
+
t_tensor = torch.full((bz,), t_curr, device=device)
|
| 403 |
+
|
| 404 |
+
attn_bias = None
|
| 405 |
+
if config.use_tail_dropout and config.tied_timestep:
|
| 406 |
+
if diti_scheduler is not None:
|
| 407 |
+
attn_bias = build_taildrop_attn_mask(
|
| 408 |
+
t=t_tensor, context_len=context_len, query_len=query_len,
|
| 409 |
+
context_type=config.context_type, device=device, diti_scheduler=diti_scheduler,
|
| 410 |
+
)
|
| 411 |
+
else:
|
| 412 |
+
attn_bias = build_taildrop_attn_mask(
|
| 413 |
+
t=t_tensor, context_len=context_len, query_len=query_len,
|
| 414 |
+
context_type=config.context_type, t2k=config.tail_dropout_t2k, device=device,
|
| 415 |
+
)
|
| 416 |
+
decoded = dec(quant, class_label, attn_mask=attn_bias, query_tokens=x, t=t_tensor)
|
| 417 |
+
if config.l2_v_target:
|
| 418 |
+
v_pred = decoded
|
| 419 |
+
x = x - v_pred * dt
|
| 420 |
+
else:
|
| 421 |
+
x0_pred = decoded
|
| 422 |
+
t_frac = dt/t_tensor
|
| 423 |
+
t_frac = t_frac[:,None,None]
|
| 424 |
+
x = x * (1-t_frac) + x0_pred * t_frac
|
| 425 |
+
return x
|
| 426 |
+
|
| 427 |
+
@torch.no_grad()
|
| 428 |
+
@torch._dynamo.disable
|
| 429 |
+
def euler_recon_loop(enc, dec, x, class_label=None, config=None, diti_scheduler=None):
|
| 430 |
+
"""
|
| 431 |
+
Euler solver for Flow Matching with dynamic token masking (DiTi).
|
| 432 |
+
"""
|
| 433 |
+
if config is None:
|
| 434 |
+
raise ValueError("config is required for euler_recon_loop")
|
| 435 |
+
# Derive device / shape from config to avoid relying on outer-scope globals.
|
| 436 |
+
device = next(dec.parameters()).device
|
| 437 |
+
B = x.shape[0]
|
| 438 |
+
|
| 439 |
+
quant, idx, _, _ = enc(x,class_label, training=False)
|
| 440 |
+
context_len = quant.shape[1]
|
| 441 |
+
query_len = x.shape[1]
|
| 442 |
+
|
| 443 |
+
num_steps = 25
|
| 444 |
+
timesteps = torch.linspace(1.0, 0.0, num_steps + 1, device=device)
|
| 445 |
+
dt = 1.0 / num_steps
|
| 446 |
+
xt = torch.randn_like(x)
|
| 447 |
+
for i in range(num_steps):
|
| 448 |
+
t_tensor = torch.full((B,), timesteps[i], device=device)
|
| 449 |
+
attn_bias = None
|
| 450 |
+
if config.use_tail_dropout and config.tied_timestep:
|
| 451 |
+
if diti_scheduler is not None:
|
| 452 |
+
attn_bias = build_taildrop_attn_mask(
|
| 453 |
+
t=t_tensor, context_len=context_len, query_len=query_len,
|
| 454 |
+
context_type=config.context_type, device=device, diti_scheduler=diti_scheduler,
|
| 455 |
+
)
|
| 456 |
+
else:
|
| 457 |
+
attn_bias = build_taildrop_attn_mask(
|
| 458 |
+
t=t_tensor, context_len=context_len, query_len=query_len,
|
| 459 |
+
context_type=config.context_type, t2k=config.tail_dropout_t2k, device=device,
|
| 460 |
+
)
|
| 461 |
+
decoded = dec(quant, class_label, attn_mask=attn_bias, query_tokens=xt, t=t_tensor)
|
| 462 |
+
if config.l2_v_target:
|
| 463 |
+
v_pred = decoded
|
| 464 |
+
xt = xt - v_pred * dt
|
| 465 |
+
else:
|
| 466 |
+
x0_pred = decoded
|
| 467 |
+
t_frac = dt/t_tensor
|
| 468 |
+
t_frac = t_frac[:,None,None]
|
| 469 |
+
xt = xt * (1-t_frac) + x0_pred * t_frac
|
| 470 |
+
return xt, idx
|
| 471 |
+
|
| 472 |
+
def toogle_train_eval(model, train=True):
|
| 473 |
+
if model is None: return
|
| 474 |
+
if train:
|
| 475 |
+
model.train()
|
| 476 |
+
else:
|
| 477 |
+
model.eval()
|
| 478 |
+
|
| 479 |
+
def toogle_require_grad(model, grads=True):
|
| 480 |
+
if model is None:
|
| 481 |
+
return
|
| 482 |
+
model.requires_grad_(grads)
|
| 483 |
+
|
| 484 |
+
def zero_nan_gradients(model):
|
| 485 |
+
for name, param in model.named_parameters():
|
| 486 |
+
if param.grad is not None:
|
| 487 |
+
param.grad.nan_to_num_(nan=0.0, posinf=1e5, neginf=-1e5)
|
| 488 |
+
|
| 489 |
+
# Model Prams and GFLOPS Utils
|
| 490 |
+
def print_model_info(fabric,model, inputs, name="Model"):
|
| 491 |
+
if model is None: return
|
| 492 |
+
if profile is None:
|
| 493 |
+
fabric.print(f"[{name}] thop not installed, skipping GFLOPS calculation.")
|
| 494 |
+
params = sum(p.numel() for p in model.parameters())
|
| 495 |
+
fabric.print(f"[{name}] Params: {params/1e6:.2f}M")
|
| 496 |
+
return
|
| 497 |
+
|
| 498 |
+
# Move inputs to device
|
| 499 |
+
device = next(model.parameters()).device
|
| 500 |
+
inputs = tuple(i.to(device) if isinstance(i, torch.Tensor) else i for i in inputs)
|
| 501 |
+
|
| 502 |
+
try:
|
| 503 |
+
model_copy = copy.deepcopy(model)
|
| 504 |
+
model_copy.eval()
|
| 505 |
+
custom_ops = {}
|
| 506 |
+
if count_linear is not None:
|
| 507 |
+
custom_ops[Linear] = count_linear
|
| 508 |
+
|
| 509 |
+
macs, params = profile(model_copy, inputs=inputs, custom_ops=custom_ops, verbose=False)
|
| 510 |
+
gflops = macs * 2 / 1e9
|
| 511 |
+
fabric.print(f"[{name}] Params: {params/1e6:.2f}M, GFLOPS: {gflops:.2f}")
|
| 512 |
+
del model_copy
|
| 513 |
+
except Exception as e:
|
| 514 |
+
fabric.print(f"[{name}] Failed to calculate GFLOPS: {e}")
|
| 515 |
+
params = sum(p.numel() for p in model.parameters())
|
| 516 |
+
fabric.print(f"[{name}] Params: {params/1e6:.2f}M")
|
| 517 |
+
|
| 518 |
+
def print_model_stats(fabric,config, enc, dec, ar_model):
|
| 519 |
+
x_len = int(config.x_len)
|
| 520 |
+
patch_dim = int(config.patch_dim)
|
| 521 |
+
num_classes = int(config.num_classes)
|
| 522 |
+
z_len = int(config.z_len)
|
| 523 |
+
z_dim = int(config.z_dim)
|
| 524 |
+
codebook_size = int(config.codebook_size)
|
| 525 |
+
|
| 526 |
+
x_dummy = torch.randn(1, x_len, patch_dim)
|
| 527 |
+
label_dummy = torch.zeros(1, num_classes)
|
| 528 |
+
|
| 529 |
+
print_model_info(fabric,enc, (x_dummy, label_dummy), "Encoder")
|
| 530 |
+
|
| 531 |
+
z_dummy = torch.randn(1, z_len, z_dim)
|
| 532 |
+
# If Decoder uses noise query, it requires query_tokens (and optionally t) at forward time.
|
| 533 |
+
query_type = getattr(getattr(dec, "dec", None), "query_type", "learnable")
|
| 534 |
+
if query_type == "noise":
|
| 535 |
+
query_len = int(getattr(config, "x_len", z_len))
|
| 536 |
+
query_dummy = torch.randn(1, query_len, patch_dim)
|
| 537 |
+
t_dummy = torch.zeros(1)
|
| 538 |
+
print_model_info(fabric, dec, (z_dummy, label_dummy, None, query_dummy, t_dummy), "Decoder")
|
| 539 |
+
else:
|
| 540 |
+
print_model_info(fabric,dec, (z_dummy, label_dummy), "Decoder")
|
| 541 |
+
|
| 542 |
+
if ar_model is not None:
|
| 543 |
+
idx_dummy = torch.randint(0, codebook_size, (1, z_len))
|
| 544 |
+
print_model_info(fabric,ar_model, (idx_dummy, label_dummy), "ARModel")
|
| 545 |
+
|
| 546 |
+
|
| 547 |
+
def train(config):
|
| 548 |
+
if config.use_tf32:
|
| 549 |
+
torch.backends.cuda.matmul.allow_tf32 = True
|
| 550 |
+
torch.backends.cudnn.allow_tf32 = True
|
| 551 |
+
# Parse devices
|
| 552 |
+
devices_value = config.devices
|
| 553 |
+
if isinstance(devices_value, str) and "," in devices_value:
|
| 554 |
+
devices_for_fabric = [int(d.strip()) for d in devices_value.split(',')]
|
| 555 |
+
num_devices = len(devices_for_fabric)
|
| 556 |
+
else:
|
| 557 |
+
try:
|
| 558 |
+
num_devices = int(devices_value)
|
| 559 |
+
devices_for_fabric = num_devices
|
| 560 |
+
except (TypeError, ValueError):
|
| 561 |
+
raise ValueError(f"Invalid value for devices: {devices_value}. Expected an integer or comma-separated string like '0,1,2'.")
|
| 562 |
+
|
| 563 |
+
if config.batch_size % num_devices or config.batch_size < num_devices:
|
| 564 |
+
raise ValueError("Global batch_size must be divisible by the number of devices")
|
| 565 |
+
if config.eval_data_dir is not None and not Path(config.eval_fid_ref_path).is_file():
|
| 566 |
+
raise FileNotFoundError("Prepare eval_fid_ref_path before training, or set eval_data_dir=null to disable periodic evaluation")
|
| 567 |
+
|
| 568 |
+
# prepare seed and save dir
|
| 569 |
+
if config.seed is not None:
|
| 570 |
+
seed = int(config.seed) if config.seed is not None else 0
|
| 571 |
+
seed_everything(seed)
|
| 572 |
+
dl_generator = torch.Generator()
|
| 573 |
+
dl_generator.manual_seed(seed)
|
| 574 |
+
worker_init = make_worker_init_fn(seed)
|
| 575 |
+
|
| 576 |
+
if "EXPERIMENT_SAVE_DIR" in os.environ:
|
| 577 |
+
save_dir = os.environ["EXPERIMENT_SAVE_DIR"]
|
| 578 |
+
else:
|
| 579 |
+
experiment_index = len(glob(f"{config.save_dir}/*"))
|
| 580 |
+
save_dir = config.save_dir+f"/{experiment_index:03d}"
|
| 581 |
+
os.environ["EXPERIMENT_SAVE_DIR"] = save_dir
|
| 582 |
+
logger = WandbLogger(project=config.wandb_project, save_dir=save_dir, name=config.wandb_name)
|
| 583 |
+
|
| 584 |
+
# initialize fabric
|
| 585 |
+
fabric = Fabric(accelerator="gpu", devices=devices_for_fabric, precision=config.precision, loggers=logger)
|
| 586 |
+
fabric.launch()
|
| 587 |
+
fabric.print(config)
|
| 588 |
+
fabric.print(f"Global seed set to {config.seed}")
|
| 589 |
+
|
| 590 |
+
# Initialize DiTi Scheduler if config provided
|
| 591 |
+
diti_scheduler = None
|
| 592 |
+
if getattr(config, "time_stages", None) and getattr(config, "k_per_stage", None):
|
| 593 |
+
fabric.print("Initializing DiTi Scheduler for piecewise linear time-to-k mapping...")
|
| 594 |
+
diti_scheduler = DiTiScheduler(
|
| 595 |
+
n_timesteps=1000,
|
| 596 |
+
K=int(config.z_len),
|
| 597 |
+
stages=config.time_stages,
|
| 598 |
+
k_per_stage=config.k_per_stage,
|
| 599 |
+
reverse_t=config.reverse_t
|
| 600 |
+
)
|
| 601 |
+
|
| 602 |
+
# Models and optimizers
|
| 603 |
+
enc = Encoder(config).to(fabric.device) # always initialize encoder
|
| 604 |
+
dec = Decoder(config).to(fabric.device)
|
| 605 |
+
if not config.train_ae:
|
| 606 |
+
enc = enc.requires_grad_(False)
|
| 607 |
+
dec = dec.requires_grad_(False)
|
| 608 |
+
ar_model = ARModel(config).to(fabric.device) if config.train_ar else None
|
| 609 |
+
gan_loss = GANLoss(**config.GANLoss).to(fabric.device) if config.use_gan_loss else None
|
| 610 |
+
perceptual_loss = LPIPS().to(fabric.device).eval().requires_grad_(False) if config.use_lpips_loss else None
|
| 611 |
+
|
| 612 |
+
|
| 613 |
+
# Load Ckpt
|
| 614 |
+
if config.ae_ckpt_path != "":
|
| 615 |
+
fabric.print(f'resume ae from ckpt {config.ae_ckpt_path}')
|
| 616 |
+
|
| 617 |
+
ckpt_states = fabric.load(config.ae_ckpt_path)
|
| 618 |
+
if enc is not None and ckpt_states.get('enc', None) is not None:
|
| 619 |
+
enc.load_state_dict({k.split('_orig_mod.')[-1]: v for k, v in ckpt_states['enc'].items() })
|
| 620 |
+
fabric.print("loaded enc")
|
| 621 |
+
if dec is not None and ckpt_states.get('dec', None) is not None:
|
| 622 |
+
dec.load_state_dict({k.split('_orig_mod.')[-1]: v for k, v in ckpt_states['dec'].items() })
|
| 623 |
+
fabric.print("loaded dec")
|
| 624 |
+
|
| 625 |
+
if gan_loss is not None and ckpt_states.get('gan_loss', None) is not None:
|
| 626 |
+
gan_loss.load_state_dict({k.split('_orig_mod.')[-1]: v for k, v in ckpt_states['gan_loss'].items() })
|
| 627 |
+
|
| 628 |
+
if config.ar_ckpt_path!="":
|
| 629 |
+
fabric.print(f'resume ar from ckpt {config.ar_ckpt_path}')
|
| 630 |
+
ar_ckpt_states = fabric.load(config.ar_ckpt_path)
|
| 631 |
+
if config.load_ar_model and ar_model is not None and ar_ckpt_states.get('ar_model', None) is not None:
|
| 632 |
+
ar_model.load_state_dict({k.split('_orig_mod.')[-1]: v for k, v in ar_ckpt_states['ar_model'].items() } )
|
| 633 |
+
fabric.print("loaded ar")
|
| 634 |
+
|
| 635 |
+
# for ema
|
| 636 |
+
ae_ema_rate = math.pow(0.5,1/config.ae_ema_halflife) if config.ae_ema_halflife>0 else 0.
|
| 637 |
+
ar_ema_rate = math.pow(0.5,1/config.ar_ema_halflife) if config.ar_ema_halflife>0 else 0.
|
| 638 |
+
enc_ema = copy.deepcopy(enc).requires_grad_(False).eval() if ae_ema_rate>0 else None
|
| 639 |
+
dec_ema = copy.deepcopy(dec).requires_grad_(False).eval() if ae_ema_rate>0 else None
|
| 640 |
+
freeze_ar_model = copy.deepcopy(ar_model).requires_grad_(False).eval() if config.train_ar else None
|
| 641 |
+
ar_model_ema = copy.deepcopy(ar_model).requires_grad_(False).eval() if config.train_ar and ar_ema_rate>0 else None
|
| 642 |
+
|
| 643 |
+
if config.ae_ckpt_path != "":
|
| 644 |
+
fabric.print(f'resume ae ema from ckpt {config.ae_ckpt_path}')
|
| 645 |
+
ckpt_states = fabric.load(config.ae_ckpt_path)
|
| 646 |
+
if enc_ema is not None and ckpt_states.get('enc_ema', None) is not None:
|
| 647 |
+
enc_ema.load_state_dict({k.split('_orig_mod.')[-1]: v for k, v in ckpt_states['enc_ema'].items() })
|
| 648 |
+
if dec_ema is not None and ckpt_states.get('dec_ema', None) is not None:
|
| 649 |
+
dec_ema.load_state_dict({k.split('_orig_mod.')[-1]: v for k, v in ckpt_states['dec_ema'].items() })
|
| 650 |
+
print("loaded ae ema")
|
| 651 |
+
|
| 652 |
+
if config.ar_ckpt_path!="" and config.load_ar_model_ema and ar_model_ema is not None and ar_ckpt_states.get('ar_model_ema', None) is not None:
|
| 653 |
+
ar_model_ema.load_state_dict({k.split('_orig_mod.')[-1]: v for k, v in ar_ckpt_states['ar_model_ema'].items() })
|
| 654 |
+
print("loaded ar ema")
|
| 655 |
+
if config.ar_ckpt_path!="" and config.load_ar_model_ema and freeze_ar_model is not None and ar_ckpt_states.get('freeze_ar_model', None) is not None:
|
| 656 |
+
freeze_ar_model.load_state_dict({k.split('_orig_mod.')[-1]: v for k, v in ar_ckpt_states['freeze_ar_model'].items() })
|
| 657 |
+
print("loaded frozen ar")
|
| 658 |
+
|
| 659 |
+
# for inference
|
| 660 |
+
enc_raw = enc
|
| 661 |
+
dec_raw = dec
|
| 662 |
+
ar_model_raw = ar_model
|
| 663 |
+
enc_ema_raw = enc_ema
|
| 664 |
+
dec_ema_raw = dec_ema
|
| 665 |
+
ar_model_ema_raw = ar_model_ema
|
| 666 |
+
|
| 667 |
+
if fabric.is_global_zero:
|
| 668 |
+
fabric.print("Calculating model stats...")
|
| 669 |
+
print_model_stats(fabric,config, enc_raw, dec_raw, ar_model_raw)
|
| 670 |
+
root_dir = Path(save_dir)
|
| 671 |
+
root_dir.mkdir(exist_ok=True, parents=True)
|
| 672 |
+
OmegaConf.save(config, root_dir / "config.yaml", resolve=True)
|
| 673 |
+
img_dir = Path(save_dir+ "/images")
|
| 674 |
+
img_dir.mkdir(exist_ok=True, parents=True)
|
| 675 |
+
ckpt_dir = Path(save_dir+ "/ckpts")
|
| 676 |
+
ckpt_dir.mkdir(exist_ok=True, parents=True)
|
| 677 |
+
|
| 678 |
+
fabric.barrier()
|
| 679 |
+
|
| 680 |
+
if config.torch_compile:
|
| 681 |
+
if enc is not None and config.compile_ae:
|
| 682 |
+
enc = torch.compile(enc)
|
| 683 |
+
if enc_ema is not None and config.compile_ae:
|
| 684 |
+
enc_ema = torch.compile(enc_ema)
|
| 685 |
+
if dec is not None and config.compile_ae:
|
| 686 |
+
dec = torch.compile(dec)
|
| 687 |
+
if dec_ema is not None and config.compile_ae:
|
| 688 |
+
dec_ema = torch.compile(dec_ema)
|
| 689 |
+
if ar_model is not None and config.compile_ar:
|
| 690 |
+
ar_model = torch.compile(ar_model)
|
| 691 |
+
if ar_model_ema is not None and config.compile_ar:
|
| 692 |
+
ar_model_ema = torch.compile(ar_model_ema)
|
| 693 |
+
if freeze_ar_model is not None and config.compile_ar:
|
| 694 |
+
freeze_ar_model= torch.compile(freeze_ar_model)
|
| 695 |
+
if gan_loss is not None and config.compile_gan:
|
| 696 |
+
gan_loss = torch.compile(gan_loss)
|
| 697 |
+
|
| 698 |
+
opt_enc = torch.optim.AdamW(enc.parameters() , lr=config.lr_enc, betas=(config.beta1, config.beta2), weight_decay=config.weight_decay_enc) if config.train_ae else None
|
| 699 |
+
opt_ar = torch.optim.AdamW(ar_model.parameters(), lr=config.lr_ar, betas=(config.ar_beta1, config.ar_beta2), weight_decay=config.weight_decay_ar) if config.train_ar else None
|
| 700 |
+
opt_dec = torch.optim.AdamW(dec.parameters(), lr=config.lr_dec, betas=(config.beta1, config.beta2), weight_decay=config.weight_decay_dec) if config.train_ae else None
|
| 701 |
+
opt_gan_loss = torch.optim.AdamW(gan_loss.parameters(), lr=config.lr_gan_loss, betas=(config.beta1, config.beta2), weight_decay=config.weight_decay_gan) if config.use_gan_loss else None
|
| 702 |
+
if config.resume_optimizer:
|
| 703 |
+
if config.train_ae:
|
| 704 |
+
fabric.print("resumed AE optimizer")
|
| 705 |
+
opt_enc.load_state_dict(ckpt_states['opt_enc'])
|
| 706 |
+
opt_dec.load_state_dict(ckpt_states['opt_dec'])
|
| 707 |
+
if config.train_ar:
|
| 708 |
+
fabric.print("resumed AR optimizer")
|
| 709 |
+
ar_optimizer_states = ar_ckpt_states if config.ar_ckpt_path else ckpt_states
|
| 710 |
+
opt_ar.load_state_dict(ar_optimizer_states['opt_ar'])
|
| 711 |
+
if config.use_gan_loss:
|
| 712 |
+
fabric.print("resumed GAN optimizer")
|
| 713 |
+
opt_gan_loss.load_state_dict(ckpt_states['opt_gan_loss'])
|
| 714 |
+
|
| 715 |
+
# Datasets
|
| 716 |
+
dataset = ImageFolderDataset(path=config['data_dir'],
|
| 717 |
+
resolution=config.image_size,
|
| 718 |
+
use_label=config.use_label,
|
| 719 |
+
max_size=None,
|
| 720 |
+
xflip=config.xflip,
|
| 721 |
+
crop_type=config.crop_type,
|
| 722 |
+
deterministic_crop=bool(getattr(config, "deterministic_crop", False)),
|
| 723 |
+
crop_seed=int(config.seed) if config.seed is not None else 0,
|
| 724 |
+
)
|
| 725 |
+
train_loader = DataLoader(
|
| 726 |
+
dataset,
|
| 727 |
+
batch_size=config.batch_size//num_devices,
|
| 728 |
+
shuffle=True,
|
| 729 |
+
num_workers=config.num_workers,
|
| 730 |
+
pin_memory=True,
|
| 731 |
+
drop_last=True,
|
| 732 |
+
persistent_workers=config.num_workers > 0,
|
| 733 |
+
worker_init_fn=worker_init,
|
| 734 |
+
generator=dl_generator,
|
| 735 |
+
)
|
| 736 |
+
eval_loader=None
|
| 737 |
+
if config.eval_data_dir is not None:
|
| 738 |
+
eval_dataset = ImageFolderDataset(path=config['eval_data_dir'],
|
| 739 |
+
resolution=config.image_size,
|
| 740 |
+
use_label=config.use_label,
|
| 741 |
+
max_size=None,
|
| 742 |
+
xflip=False,
|
| 743 |
+
crop_type=config.eval_crop_type,
|
| 744 |
+
deterministic_crop=bool(getattr(config, "deterministic_crop", False)),
|
| 745 |
+
crop_seed=int(config.seed) if config.seed is not None else 0,
|
| 746 |
+
)
|
| 747 |
+
eval_loader = DataLoader(
|
| 748 |
+
eval_dataset,
|
| 749 |
+
batch_size=config.batch_size//num_devices,
|
| 750 |
+
shuffle=False,
|
| 751 |
+
pin_memory=True,
|
| 752 |
+
drop_last=False,
|
| 753 |
+
worker_init_fn=worker_init,
|
| 754 |
+
generator=dl_generator,
|
| 755 |
+
)
|
| 756 |
+
|
| 757 |
+
# Setup Model, Optimizer, DataLoader with Fabric
|
| 758 |
+
if config.train_ae:
|
| 759 |
+
enc, opt_enc = fabric.setup(enc, opt_enc)
|
| 760 |
+
dec, opt_dec = fabric.setup(dec, opt_dec)
|
| 761 |
+
if enc_ema is not None:
|
| 762 |
+
enc_ema = enc_ema.to(fabric.device)
|
| 763 |
+
if dec_ema is not None:
|
| 764 |
+
dec_ema = dec_ema.to(fabric.device)
|
| 765 |
+
if config.train_ar:
|
| 766 |
+
ar_model, opt_ar = fabric.setup(ar_model, opt_ar)
|
| 767 |
+
if ar_model_ema is not None:
|
| 768 |
+
ar_model_ema = ar_model_ema.to(fabric.device)
|
| 769 |
+
if freeze_ar_model is not None:
|
| 770 |
+
freeze_ar_model = freeze_ar_model.to(fabric.device)
|
| 771 |
+
if config.use_gan_loss:
|
| 772 |
+
gan_loss, opt_gan_loss = fabric.setup(gan_loss, opt_gan_loss)
|
| 773 |
+
|
| 774 |
+
train_loader = fabric.setup_dataloaders(train_loader)
|
| 775 |
+
train_loader = InfiniteIterator(train_loader)
|
| 776 |
+
if eval_loader is not None:
|
| 777 |
+
eval_loader = fabric.setup_dataloaders(eval_loader)
|
| 778 |
+
|
| 779 |
+
|
| 780 |
+
if config.train_ar:
|
| 781 |
+
ar_model.mark_forward_method('sampling')
|
| 782 |
+
|
| 783 |
+
global_step = 0
|
| 784 |
+
|
| 785 |
+
phases = parse_phases(config.phases)
|
| 786 |
+
fabric.print("Training Phases: ", phases)
|
| 787 |
+
total_phase_steps = sum(phase.num_steps for phase in phases)
|
| 788 |
+
total_phase = len(phases)
|
| 789 |
+
|
| 790 |
+
prev_phase_idx=-1
|
| 791 |
+
phase_step_accum = list(itertools.accumulate([phase.num_steps for phase in phases]))
|
| 792 |
+
pbar = tqdm(total=total_phase_steps, disable=not fabric.is_global_zero, dynamic_ncols=True, file=sys.stdout)
|
| 793 |
+
pbar.set_description(f"Total Steps {total_phase_steps}")
|
| 794 |
+
data_buffer = []
|
| 795 |
+
while global_step < total_phase_steps:
|
| 796 |
+
# Assign gradient and optimizer based on current phase and target
|
| 797 |
+
phase_idx, inner_idx, target, internel_step = get_phase(global_step, phases, phase_step_accum, config)
|
| 798 |
+
if not any(target):
|
| 799 |
+
phase_idx, inner_idx, target, internel_step = get_phase(global_step+1, phases, phase_step_accum, config)
|
| 800 |
+
if phase_idx != prev_phase_idx:
|
| 801 |
+
if config.lr_scheduler != 'none':
|
| 802 |
+
scheduler_enc = torch.optim.lr_scheduler.CosineAnnealingLR(opt_enc, T_max=phases[phase_idx].num_steps/len(phases[phase_idx].internal_steps),eta_min=config.lr_enc_min) if config.train_ae else None
|
| 803 |
+
scheduler_dec = torch.optim.lr_scheduler.CosineAnnealingLR(opt_dec, T_max=phases[phase_idx].num_steps/len(phases[phase_idx].internal_steps),eta_min=config.lr_dec_min) if config.train_ae else None
|
| 804 |
+
scheduler_ar = torch.optim.lr_scheduler.CosineAnnealingLR(opt_ar, T_max=phases[phase_idx].num_steps/len(phases[phase_idx].internal_steps),eta_min=config.lr_ar_min) if config.train_ar else None
|
| 805 |
+
scheduler_gan_loss = torch.optim.lr_scheduler.CosineAnnealingLR(opt_gan_loss, T_max=phases[phase_idx].num_steps/len(phases[phase_idx].internal_steps),eta_min=config.lr_gan_loss_min) if config.use_gan_loss else None
|
| 806 |
+
else:
|
| 807 |
+
scheduler_enc = None
|
| 808 |
+
scheduler_dec = None
|
| 809 |
+
scheduler_ar = None
|
| 810 |
+
scheduler_gan_loss = None
|
| 811 |
+
|
| 812 |
+
|
| 813 |
+
enc_grad = target.DO_AE or target.DO_PRIOR_ENC
|
| 814 |
+
dec_grad = target.DO_AE
|
| 815 |
+
prior_grad = target.DO_PRIOR_AR
|
| 816 |
+
disc_grad = target.DO_GAN_D
|
| 817 |
+
toogle_require_grad(enc, enc_grad)
|
| 818 |
+
toogle_require_grad(dec, dec_grad)
|
| 819 |
+
toogle_require_grad(ar_model, prior_grad)
|
| 820 |
+
toogle_require_grad(gan_loss, disc_grad)
|
| 821 |
+
opts = []
|
| 822 |
+
if enc_grad:
|
| 823 |
+
opts.append((enc, opt_enc, scheduler_enc))
|
| 824 |
+
if dec_grad:
|
| 825 |
+
opts.append((dec, opt_dec, scheduler_dec))
|
| 826 |
+
if prior_grad:
|
| 827 |
+
opts.append((ar_model, opt_ar, scheduler_ar))
|
| 828 |
+
if disc_grad:
|
| 829 |
+
opts.append((gan_loss, opt_gan_loss, scheduler_gan_loss))
|
| 830 |
+
|
| 831 |
+
# input
|
| 832 |
+
# Clear buffer at start of cycle
|
| 833 |
+
if internel_step == 0:
|
| 834 |
+
data_buffer = []
|
| 835 |
+
|
| 836 |
+
if inner_idx == 0:
|
| 837 |
+
batch = next(train_loader)
|
| 838 |
+
data_buffer.append(batch)
|
| 839 |
+
else:
|
| 840 |
+
if len(data_buffer) > 0:
|
| 841 |
+
batch = data_buffer.pop(0)
|
| 842 |
+
else:
|
| 843 |
+
batch = next(train_loader)
|
| 844 |
+
|
| 845 |
+
imgs, labels = batch if isinstance(batch, (list, tuple)) and len(batch) == 2 else (batch, None)
|
| 846 |
+
imgs = img_unint8_to_norm(imgs)
|
| 847 |
+
|
| 848 |
+
# no labels or drop labels
|
| 849 |
+
uncond_labels = F.one_hot(torch.full((imgs.shape[0],), config.num_classes - 1, device=fabric.device, dtype=torch.long), num_classes=config.num_classes).float()
|
| 850 |
+
|
| 851 |
+
if labels is None or len(labels)==0 or not config.use_label:
|
| 852 |
+
labels = uncond_labels
|
| 853 |
+
elif config.label_drop_prob > 0:
|
| 854 |
+
labels = torch.where(torch.rand(imgs.shape[0], device=fabric.device) < config.label_drop_prob, uncond_labels, labels)
|
| 855 |
+
|
| 856 |
+
x = patchify(imgs, config.patch_size)
|
| 857 |
+
|
| 858 |
+
|
| 859 |
+
# forward, build need computation graph for gradient calculation
|
| 860 |
+
with torch.set_grad_enabled(enc_grad):
|
| 861 |
+
quant, idx, one_hot, vqloss = enc(x, labels, training=enc_grad)
|
| 862 |
+
|
| 863 |
+
if target.DO_AE:
|
| 864 |
+
|
| 865 |
+
# For Diffusion/FM decoder
|
| 866 |
+
t_fm,xt,noise,v = None,None,None,None
|
| 867 |
+
if config.use_noise_query:
|
| 868 |
+
t_fm = torch.rand((x.shape[0],), device=fabric.device)
|
| 869 |
+
xt, noise, v = make_noise_image_patch_query(x, t_fm, config.z_len)
|
| 870 |
+
|
| 871 |
+
# For Tail Dropout
|
| 872 |
+
attn_bias = None
|
| 873 |
+
if config.use_tail_dropout and global_step>config.tail_dropout_start:
|
| 874 |
+
if config.tied_timestep:
|
| 875 |
+
t_tail_drop = t_fm
|
| 876 |
+
else:
|
| 877 |
+
t_tail_drop = torch.rand((x.shape[0],), device=fabric.device)
|
| 878 |
+
no_drop_t = torch.ones_like(t_tail_drop)
|
| 879 |
+
t_tail_drop = torch.where(torch.rand_like(t_tail_drop)<=config.tail_dropout_p,t_tail_drop,no_drop_t)
|
| 880 |
+
attn_bias = build_taildrop_attn_mask(t=t_tail_drop,context_len=int(quant.shape[1]),query_len=config.x_len,
|
| 881 |
+
context_type=config.context_type,t2k=config.tail_dropout_t2k,
|
| 882 |
+
device=fabric.device,
|
| 883 |
+
diti_scheduler=diti_scheduler,
|
| 884 |
+
) if config.use_tail_dropout else None
|
| 885 |
+
|
| 886 |
+
decoded = dec(quant, labels, attn_mask=attn_bias, query_tokens=xt, t=t_fm)
|
| 887 |
+
|
| 888 |
+
v_hat = decoded if config.l2_v_target else None
|
| 889 |
+
x_hat = xt - decoded * t_fm[:,None,None] if config.l2_v_target else decoded
|
| 890 |
+
|
| 891 |
+
imgs_hat = unpatchify(x_hat, config.image_size, config.patch_size)
|
| 892 |
+
|
| 893 |
+
l2_target = v if config.l2_v_target else x
|
| 894 |
+
l2_input = v_hat if config.l2_v_target else x_hat
|
| 895 |
+
|
| 896 |
+
if target.DO_PRIOR_ENC or target.DO_PRIOR_AR:
|
| 897 |
+
with torch.set_grad_enabled(prior_grad):
|
| 898 |
+
ar_logits = ar_model(idx,labels)
|
| 899 |
+
|
| 900 |
+
if target.DO_PRIOR_ENC:
|
| 901 |
+
with torch.no_grad():
|
| 902 |
+
ema_ar_logits = freeze_ar_model(idx,labels)
|
| 903 |
+
with torch.amp.autocast('cuda',enabled=False):
|
| 904 |
+
ar_logits_detach = ar_logits.detach().float()
|
| 905 |
+
temp_low = config.prior_ar_temp_low
|
| 906 |
+
temp_high = config.prior_ar_temp_high
|
| 907 |
+
steps = config.z_len
|
| 908 |
+
if config.prior_ar_temp_schedule == 'cosine':
|
| 909 |
+
t = torch.linspace(0, 1, steps, device=fabric.device)
|
| 910 |
+
temp = temp_low + 0.5 * (temp_high - temp_low) * (1 - torch.cos(math.pi * t))
|
| 911 |
+
elif config.prior_ar_temp_schedule == 'linear':
|
| 912 |
+
temp = torch.linspace(temp_low, temp_high, steps, device=fabric.device)
|
| 913 |
+
elif config.prior_ar_temp_schedule == 'constant':
|
| 914 |
+
temp = torch.full((steps,), temp_low, device=fabric.device)
|
| 915 |
+
else:
|
| 916 |
+
raise NotImplementedError(f"Unknown schedule: {config.prior_ar_temp_schedule}")
|
| 917 |
+
|
| 918 |
+
b, n = ema_ar_logits.shape[0], ema_ar_logits.shape[1]
|
| 919 |
+
temp = temp.view(1, n, 1).expand(b, n, 1)
|
| 920 |
+
|
| 921 |
+
ema_ar_logits = ema_ar_logits.detach().float() / temp
|
| 922 |
+
prior_ema_ar_loss = F.cross_entropy(ema_ar_logits.reshape(-1, ema_ar_logits.shape[-1]).float(), idx.reshape(-1))
|
| 923 |
+
|
| 924 |
+
ema_ar_log_probs= torch.log_softmax(ema_ar_logits, dim=-1)
|
| 925 |
+
ar_log_probs = torch.log_softmax(ar_logits_detach, dim=-1)
|
| 926 |
+
entropy_ar_log_probs = -(ar_log_probs.exp() * ar_log_probs).sum(dim=-1)
|
| 927 |
+
entropy_ema_ar_log_probs = -(ema_ar_log_probs.exp() * ema_ar_log_probs).sum(dim=-1)
|
| 928 |
+
log_diff = ar_log_probs - ema_ar_log_probs
|
| 929 |
+
|
| 930 |
+
|
| 931 |
+
# caculate the loss
|
| 932 |
+
l2_loss = config.l2_weight * F.mse_loss(l2_input, l2_target) if target.DO_L2 else 0.
|
| 933 |
+
l1_loss = config.l1_weight * F.l1_loss(x_hat, x) if target.DO_L1 else 0.
|
| 934 |
+
lpips_loss = config.lpips_weight * perceptual_loss(imgs_hat, imgs).mean() if target.DO_LPIPS else 0.
|
| 935 |
+
ae_loss = l2_loss + l1_loss + lpips_loss
|
| 936 |
+
|
| 937 |
+
gan_G_loss, gan_G_loss_dict = gan_loss(imgs_hat, imgs, global_step=global_step, loss='G') if target.DO_GAN_G else (0., {})
|
| 938 |
+
gan_D_loss, gan_D_loss_dict = gan_loss(imgs_hat, imgs, global_step=global_step, loss='D') if target.DO_GAN_D else (0., {})
|
| 939 |
+
gan_G_loss_weight = (config.gan_G_weight * min(1., gan_loss.calculate_adaptive_weight(ae_loss,gan_G_loss,dec.dec.out.weight))) if target.DO_GAN_G and config.disc_adaptive_weight else config.gan_G_weight
|
| 940 |
+
gan_G_loss = gan_G_loss * gan_G_loss_weight
|
| 941 |
+
gan_D_loss = gan_D_loss * config.gan_G_weight
|
| 942 |
+
correct_tokens = (ar_logits.argmax(dim=-1) == idx).detach().float().sum().item() if target.DO_PRIOR_AR else 0.
|
| 943 |
+
total_tokens = torch.tensor(idx.numel()).item() if target.DO_PRIOR_AR else 0.
|
| 944 |
+
correct_token_rate = correct_tokens / total_tokens if target.DO_PRIOR_AR else 0.
|
| 945 |
+
prior_enc_loss = config.prior_enc_weight * (one_hot * log_diff.detach()).mean() if target.DO_PRIOR_ENC else 0.
|
| 946 |
+
prior_ar_loss = F.cross_entropy(ar_logits.reshape(-1, ar_logits.shape[-1]).float(), idx.reshape(-1)) if target.DO_PRIOR_AR else 0.
|
| 947 |
+
|
| 948 |
+
loss = ae_loss + prior_enc_loss + prior_ar_loss + gan_G_loss + gan_D_loss + vqloss
|
| 949 |
+
|
| 950 |
+
# backward and optimization
|
| 951 |
+
fabric.backward(loss)
|
| 952 |
+
|
| 953 |
+
for model, opt, scheduler in opts:
|
| 954 |
+
if model is not None and opt is not None:
|
| 955 |
+
zero_nan_gradients(model)
|
| 956 |
+
if config.grad_clip>0:
|
| 957 |
+
fabric.clip_gradients(model, opt, max_norm=config.grad_clip)
|
| 958 |
+
opt.step()
|
| 959 |
+
opt.zero_grad(set_to_none=True)
|
| 960 |
+
if scheduler is not None:
|
| 961 |
+
scheduler.step()
|
| 962 |
+
if config.train_ae:
|
| 963 |
+
if enc_grad:
|
| 964 |
+
ema_update(enc, enc_ema, ae_ema_rate)
|
| 965 |
+
if dec_grad:
|
| 966 |
+
ema_update(dec, dec_ema, ae_ema_rate)
|
| 967 |
+
if config.use_gan_loss and disc_grad:
|
| 968 |
+
ema_update(gan_loss, gan_loss_ema, ae_ema_rate)
|
| 969 |
+
if config.train_ar and prior_grad:
|
| 970 |
+
ema_update(ar_model, ar_model_ema, ar_ema_rate)
|
| 971 |
+
|
| 972 |
+
#visualization
|
| 973 |
+
if (global_step + 1) % config.visualize_freq == 0:
|
| 974 |
+
grid = x[:config.visualize_img_num]
|
| 975 |
+
if not config.ema_reconstruction:
|
| 976 |
+
if config.train_ae:
|
| 977 |
+
toogle_train_eval(enc_raw,train=False)
|
| 978 |
+
toogle_train_eval(dec_raw,train=False)
|
| 979 |
+
eval_enc = enc_raw
|
| 980 |
+
eval_dec = dec_raw
|
| 981 |
+
else:
|
| 982 |
+
eval_enc = enc_ema_raw
|
| 983 |
+
eval_dec = dec_ema_raw
|
| 984 |
+
if not config.ema_sampling:
|
| 985 |
+
if config.train_ar:
|
| 986 |
+
toogle_train_eval(ar_model_raw,train=False)
|
| 987 |
+
eval_ar = ar_model_raw
|
| 988 |
+
else:
|
| 989 |
+
eval_ar = ar_model_ema_raw
|
| 990 |
+
with torch.no_grad():
|
| 991 |
+
noise_t = torch.ones((x.shape[0],), device=fabric.device) if config.use_noise_query else None
|
| 992 |
+
if config.train_ae:
|
| 993 |
+
noise_recon = torch.randn_like(x) if config.use_noise_query else None
|
| 994 |
+
if config.use_noise_query and config.diffusion_decoder:
|
| 995 |
+
all_recon_images,_ = euler_recon_loop(eval_enc, eval_dec, x, labels, config=config, diti_scheduler=diti_scheduler)
|
| 996 |
+
else:
|
| 997 |
+
decoded_recon,_ = reconstruction(eval_enc, eval_dec, x, labels, query_tokens=noise_recon, t=noise_t)
|
| 998 |
+
all_recon_images = decoded_recon if not config.l2_v_target else noise_recon-decoded_recon
|
| 999 |
+
grid = torch.cat([grid, all_recon_images[:config.visualize_img_num]], dim=0)
|
| 1000 |
+
|
| 1001 |
+
if config.train_ar:
|
| 1002 |
+
noise_sample = torch.randn_like(x) if config.use_noise_query else None
|
| 1003 |
+
if config.use_noise_query and config.diffusion_decoder:
|
| 1004 |
+
all_sample_images = euler_sample_loop(eval_enc, eval_dec, eval_ar, bz=x.shape[0],
|
| 1005 |
+
class_label=labels,temperature=config.temperature,
|
| 1006 |
+
topK=config.topK, topP=config.topP,
|
| 1007 |
+
cfg=config.cfg, cfg_schedule=config.cfg_schedule, cfg_power=config.cfg_power,
|
| 1008 |
+
cache_kv=config.cache_kv, config=config, diti_scheduler=diti_scheduler)
|
| 1009 |
+
else:
|
| 1010 |
+
decoded_sample = sampling(eval_enc, eval_dec, eval_ar, bz=x.shape[0],
|
| 1011 |
+
class_label=labels,temperature=config.temperature,
|
| 1012 |
+
topK=config.topK, topP=config.topP,
|
| 1013 |
+
cfg=config.cfg, cfg_schedule=config.cfg_schedule, cfg_power=config.cfg_power,
|
| 1014 |
+
cache_kv=config.cache_kv, config=config, t=noise_t ,query_tokens=noise_sample)
|
| 1015 |
+
all_sample_images = decoded_sample if not config.l2_v_target else noise_sample-decoded_sample
|
| 1016 |
+
grid = torch.cat([grid, all_sample_images[:config.visualize_img_num]], dim=0)
|
| 1017 |
+
grid = img_denormalize(unpatchify(grid, config.image_size, config.patch_size))
|
| 1018 |
+
grid = torchvision.utils.make_grid(grid, nrow=config.visualize_img_num, normalize=False)
|
| 1019 |
+
fabric.log_dict({"visualization":wandb.Image(grid),'global_step':global_step+1})
|
| 1020 |
+
if not config.ema_reconstruction and config.train_ae:
|
| 1021 |
+
toogle_train_eval(enc_raw,train=True)
|
| 1022 |
+
toogle_train_eval(dec_raw,train=True)
|
| 1023 |
+
if not config.ema_sampling and config.train_ar:
|
| 1024 |
+
toogle_train_eval(ar_model_raw,train=True)
|
| 1025 |
+
|
| 1026 |
+
# eval and save ckpt
|
| 1027 |
+
rFID = 0.0
|
| 1028 |
+
gFID = 0.0
|
| 1029 |
+
if eval_loader is not None and (global_step + 1) % config.eval_freq == 0:
|
| 1030 |
+
|
| 1031 |
+
sample_cached_path = os.path.join(save_dir, "sample_images.npz")
|
| 1032 |
+
recon_cached_path = os.path.join(save_dir, "recon_images.npz")
|
| 1033 |
+
gt_cache_path = config.eval_fid_ref_path
|
| 1034 |
+
|
| 1035 |
+
samples_buf = []
|
| 1036 |
+
recons_buf = []
|
| 1037 |
+
if not config.ema_reconstruction:
|
| 1038 |
+
if config.train_ae:
|
| 1039 |
+
toogle_train_eval(enc_raw,train=False)
|
| 1040 |
+
toogle_train_eval(dec_raw,train=False)
|
| 1041 |
+
eval_enc = enc_raw
|
| 1042 |
+
eval_dec = dec_raw
|
| 1043 |
+
else:
|
| 1044 |
+
eval_enc = enc_ema_raw
|
| 1045 |
+
eval_dec = dec_ema_raw
|
| 1046 |
+
|
| 1047 |
+
if not config.ema_sampling:
|
| 1048 |
+
if config.train_ar:
|
| 1049 |
+
toogle_train_eval(ar_model_raw, train=False)
|
| 1050 |
+
eval_ar = ar_model_raw
|
| 1051 |
+
else:
|
| 1052 |
+
eval_ar = ar_model_ema_raw
|
| 1053 |
+
|
| 1054 |
+
|
| 1055 |
+
with torch.no_grad():
|
| 1056 |
+
|
| 1057 |
+
fabric.barrier()
|
| 1058 |
+
for i, batch in enumerate(tqdm(eval_loader,disable=not fabric.is_global_zero,dynamic_ncols=True,file=sys.stdout,desc="Evaluating")):
|
| 1059 |
+
imgs, labels = batch if isinstance(batch, (list, tuple)) and len(batch) == 2 else (batch, None)
|
| 1060 |
+
x = img_unint8_to_norm(imgs)
|
| 1061 |
+
x = patchify(x, config.patch_size)
|
| 1062 |
+
uncond_labels = F.one_hot(torch.full((imgs.shape[0],), config.num_classes - 1, device=fabric.device, dtype=torch.long), num_classes=config.num_classes).float()
|
| 1063 |
+
noise_t = torch.ones((labels.shape[0],), device=fabric.device) if config.use_noise_query else None
|
| 1064 |
+
|
| 1065 |
+
if labels is None or len(labels)==0 or not config.use_label:
|
| 1066 |
+
labels = uncond_labels
|
| 1067 |
+
idx = None
|
| 1068 |
+
noise_recon = torch.randn_like(x) if config.use_noise_query else None
|
| 1069 |
+
|
| 1070 |
+
if config.train_ae:
|
| 1071 |
+
if config.use_noise_query and config.diffusion_decoder:
|
| 1072 |
+
recon_images, idx = euler_recon_loop(eval_enc, eval_dec, x, labels, config=config, diti_scheduler=diti_scheduler)
|
| 1073 |
+
else:
|
| 1074 |
+
decoded_recon, idx = reconstruction(eval_enc, eval_dec, x, labels, query_tokens=noise_recon,t = noise_t)
|
| 1075 |
+
recon_images = decoded_recon if not config.l2_v_target else noise_recon-decoded_recon
|
| 1076 |
+
|
| 1077 |
+
recon_images = img_norm_to_uint8(unpatchify(recon_images, config.image_size, config.patch_size))
|
| 1078 |
+
if fabric.world_size>1:
|
| 1079 |
+
recon_images = fabric.all_gather(recon_images)
|
| 1080 |
+
recon_images = recon_images.flatten(0,1)
|
| 1081 |
+
recons_buf.append(recon_images.permute(0,2,3,1).cpu().numpy())
|
| 1082 |
+
if config.train_ar:
|
| 1083 |
+
if config.use_noise_query and config.diffusion_decoder:
|
| 1084 |
+
sample_images = euler_sample_loop(eval_enc, eval_dec, eval_ar, bz=x.shape[0],
|
| 1085 |
+
class_label=labels,temperature=config.temperature,
|
| 1086 |
+
topK=config.topK, topP=config.topP,
|
| 1087 |
+
cfg=config.cfg, cfg_schedule=config.cfg_schedule, cfg_power=config.cfg_power,
|
| 1088 |
+
cache_kv=config.cache_kv, config=config, diti_scheduler=diti_scheduler)
|
| 1089 |
+
else:
|
| 1090 |
+
noise_sample = torch.randn_like(x) if config.use_noise_query else None
|
| 1091 |
+
decoded_sample = sampling(eval_enc, eval_dec, eval_ar,
|
| 1092 |
+
bz=x.shape[0], class_label=labels,temperature=config.temperature,
|
| 1093 |
+
topK=config.topK, topP=config.topP, cfg=config.cfg, cfg_schedule=config.cfg_schedule,
|
| 1094 |
+
cfg_power=config.cfg_power, cache_kv=config.cache_kv, config=config,t=noise_t,query_tokens=noise_sample)
|
| 1095 |
+
sample_images = decoded_sample if not config.l2_v_target else noise_sample-decoded_sample
|
| 1096 |
+
|
| 1097 |
+
sample_images = img_norm_to_uint8(unpatchify(sample_images, config.image_size, config.patch_size))
|
| 1098 |
+
if fabric.world_size>1:
|
| 1099 |
+
sample_images = fabric.all_gather(sample_images)
|
| 1100 |
+
sample_images = sample_images.flatten(0,1)
|
| 1101 |
+
samples_buf.append(sample_images.permute(0,2,3,1).cpu().numpy())
|
| 1102 |
+
|
| 1103 |
+
|
| 1104 |
+
fabric.barrier()
|
| 1105 |
+
if fabric.is_global_zero:
|
| 1106 |
+
if config.train_ar:
|
| 1107 |
+
np.savez_compressed(sample_cached_path, np.concatenate(samples_buf,axis=0))
|
| 1108 |
+
if config.train_ae:
|
| 1109 |
+
np.savez_compressed(recon_cached_path, np.concatenate(recons_buf,axis=0))
|
| 1110 |
+
|
| 1111 |
+
if config.train_ar:
|
| 1112 |
+
gFID = adm_fid_evaluator(sample_cached_path, gt_cache_path, config, fabric)
|
| 1113 |
+
if config.train_ae:
|
| 1114 |
+
rFID = adm_fid_evaluator(recon_cached_path, gt_cache_path, config, fabric)
|
| 1115 |
+
fabric.barrier()
|
| 1116 |
+
|
| 1117 |
+
|
| 1118 |
+
if not config.ema_reconstruction and config.train_ae:
|
| 1119 |
+
toogle_train_eval(enc_raw,train=True)
|
| 1120 |
+
toogle_train_eval(dec_raw,train=True)
|
| 1121 |
+
if not config.ema_sampling and config.train_ar:
|
| 1122 |
+
toogle_train_eval(ar_model_raw,train=True)
|
| 1123 |
+
|
| 1124 |
+
# metrics
|
| 1125 |
+
if (global_step +1) % config.log_freq == 0:
|
| 1126 |
+
# current learning rates
|
| 1127 |
+
lr_enc = opt_enc.param_groups[0]['lr'] if opt_enc is not None else 0.
|
| 1128 |
+
lr_dec = opt_dec.param_groups[0]['lr'] if opt_dec is not None else 0.
|
| 1129 |
+
lr_ar = opt_ar.param_groups[0]['lr'] if opt_ar is not None else 0.
|
| 1130 |
+
lr_gan_loss = opt_gan_loss.param_groups[0]['lr'] if opt_gan_loss is not None else 0.
|
| 1131 |
+
metrics = {
|
| 1132 |
+
'Phase':phase_idx,
|
| 1133 |
+
'ae_loss/l1_loss':l1_loss,
|
| 1134 |
+
'ae_loss/l2_loss':l2_loss,
|
| 1135 |
+
'ae_loss/lpips_loss':lpips_loss,
|
| 1136 |
+
'ae_loss/loss':ae_loss,
|
| 1137 |
+
'ae_loss/vqloss': vqloss,
|
| 1138 |
+
'ae_loss/gan_G_loss':gan_G_loss,
|
| 1139 |
+
'ae_loss/gan_D_loss':gan_D_loss,
|
| 1140 |
+
'prior_loss/logq-logp':log_diff.mean() if target.DO_PRIOR_ENC else 0.,
|
| 1141 |
+
'prior_loss/logq':ar_log_probs.mean() if target.DO_PRIOR_ENC else 0.,
|
| 1142 |
+
'prior_loss/logp':ema_ar_log_probs.mean() if target.DO_PRIOR_ENC else 0.,
|
| 1143 |
+
'prior_loss/entropy_q':entropy_ar_log_probs.mean() if target.DO_PRIOR_ENC else 0.,
|
| 1144 |
+
'prior_loss/entropy_p':entropy_ema_ar_log_probs.mean() if target.DO_PRIOR_ENC else 0.,
|
| 1145 |
+
'prior_loss/ar_loss':prior_ar_loss,
|
| 1146 |
+
'prior_loss/ema_ar_loss':prior_ema_ar_loss if target.DO_PRIOR_ENC else 0.,
|
| 1147 |
+
'prior_loss/correct_token_rate': correct_token_rate,
|
| 1148 |
+
'FID/rFID':rFID,
|
| 1149 |
+
'FID/gFID':gFID,
|
| 1150 |
+
'lr/lr_enc': lr_enc,
|
| 1151 |
+
'lr/lr_dec': lr_dec,
|
| 1152 |
+
'lr/lr_ar': lr_ar,
|
| 1153 |
+
'lr/lr_gan_loss': lr_gan_loss,
|
| 1154 |
+
}
|
| 1155 |
+
gan_loss_dict = {**gan_G_loss_dict, **gan_D_loss_dict, 'gan_G_loss_weight':gan_G_loss_weight}
|
| 1156 |
+
metrics.update(gan_loss_dict)
|
| 1157 |
+
metrics = {k: fabric.all_reduce(v).item() if isinstance(v, torch.Tensor) else v for k, v in metrics.items() }
|
| 1158 |
+
metrics_logger = {k: v for k, v in metrics.items() if v!=0. }
|
| 1159 |
+
metrics_4f = {k: f"{v:.4f}" if k!='Phase' else int(v) for k, v in metrics.items() }
|
| 1160 |
+
fabric.log_dict(metrics_logger,step=global_step+1)
|
| 1161 |
+
pbar.set_postfix(metrics_4f)
|
| 1162 |
+
pbar.update(config.log_freq)
|
| 1163 |
+
|
| 1164 |
+
if config.save_ckpt and (global_step==0 or (global_step+1) % config.ckpt_freq == 0):
|
| 1165 |
+
ckpt_name = f'Phase={phase_idx}-Step={global_step+1}-rFID={rFID:.4f}-gFID={gFID:.4f}' if rFID is not None and gFID is not None else "_".join([f'{k}={v:.4f}' for k, v in metrics.items()])
|
| 1166 |
+
ckpt_path = f'{save_dir}/ckpts/{ckpt_name}.ckpt'
|
| 1167 |
+
fabric.save(ckpt_path, {'enc':enc,
|
| 1168 |
+
'ar_model':ar_model,
|
| 1169 |
+
'freeze_ar_model': freeze_ar_model,
|
| 1170 |
+
'dec':dec,
|
| 1171 |
+
'gan_loss':gan_loss,
|
| 1172 |
+
'enc_ema':enc_ema,
|
| 1173 |
+
'dec_ema':dec_ema,
|
| 1174 |
+
'ar_model_ema':ar_model_ema,
|
| 1175 |
+
'opt_enc':opt_enc,
|
| 1176 |
+
'opt_ar':opt_ar,
|
| 1177 |
+
'opt_dec':opt_dec,
|
| 1178 |
+
'opt_gan_loss':opt_gan_loss})
|
| 1179 |
+
global_step += 1
|
| 1180 |
+
prev_phase_idx = phase_idx
|
| 1181 |
+
if config.save_ckpt:
|
| 1182 |
+
ckpt_path = f'{save_dir}/ckpts/last.ckpt'
|
| 1183 |
+
fabric.save(ckpt_path, {'enc':enc,
|
| 1184 |
+
'ar_model':ar_model,
|
| 1185 |
+
'dec':dec,
|
| 1186 |
+
'gan_loss':gan_loss,
|
| 1187 |
+
'freeze_ar_model':freeze_ar_model,
|
| 1188 |
+
'enc_ema':enc_ema,
|
| 1189 |
+
'dec_ema':dec_ema,
|
| 1190 |
+
'ar_model_ema':ar_model_ema,
|
| 1191 |
+
'opt_enc':opt_enc,
|
| 1192 |
+
'opt_ar':opt_ar,
|
| 1193 |
+
'opt_dec':opt_dec,
|
| 1194 |
+
'opt_gan_loss':opt_gan_loss})
|
| 1195 |
+
|
| 1196 |
+
logger.finalize("Training completed")
|
| 1197 |
+
|
| 1198 |
+
if __name__ == "__main__":
|
| 1199 |
+
OmegaConf.register_new_resolver("eval", eval)
|
| 1200 |
+
cli_conf = OmegaConf.from_cli()
|
| 1201 |
+
|
| 1202 |
+
config_path = cli_conf.get("--config")
|
| 1203 |
+
conf = OmegaConf.load(config_path)
|
| 1204 |
+
if cli_conf is not None:
|
| 1205 |
+
for k, v in cli_conf.items():
|
| 1206 |
+
OmegaConf.update(conf, k, v)
|
| 1207 |
+
|
| 1208 |
+
train(conf)
|
| 1209 |
+
|