Files
microsoft--unilm/LatentLM/evaluate_fid_fidelity.py
2026-07-13 13:24:13 +08:00

133 lines
4.7 KiB
Python

import argparse
import json
import os
import numpy as np
import torch
from torchvision import transforms
from torchvision.datasets import ImageFolder
import torch_fidelity
from utils import center_crop_arr, safe_blob_write
def parse_args():
parser = argparse.ArgumentParser(description="Simple example of a training script.")
parser.add_argument(
"--seed",
type=int,
default=0,
help="A seed to use for the random number generator. Can be negative to not set a seed.",
)
parser.add_argument(
"--model",
type=str,
default="Transformer-L",
help="The config of the UNet model to train, leave as None to use standard DDPM configuration.",
)
parser.add_argument(
"--vae",
type=str,
default=None,
)
parser.add_argument("--train_data_dir", type=str, default="/tmp/ILSVRC/Data/CLS-LOC/train", help="A folder containing the training data.")
parser.add_argument(
"--ref_stat_path",
type=str,
default="/mnt/unilm/hangbo/beit3/t2i/assets/fid_stats/imagenet_256_val.npz",
)
parser.add_argument(
"--image_size",
type=int,
default=256,
help=(
"The image_size for input images, all the images in the train/validation dataset will be resized to this"
" image_size"
),
)
parser.add_argument(
"--batch_size", type=int, default=32, help="Batch size (per device) for the training dataloader."
)
parser.add_argument(
"--steps_per_class", type=int, default=50, help="Number of steps per class."
)
parser.add_argument("--use_ema", action="store_true", help="Whether to use Exponential Moving Average for the final model weights.")
parser.add_argument("--ddpm_num_steps", type=int, default=1000)
parser.add_argument("--ddpm_num_inference_steps", type=int, default=250)
parser.add_argument("--ddpm_beta_schedule", type=str, default="cosine", help="The beta schedule to use for DDPM.")
parser.add_argument("--prediction_type", type=str, default="epsilon", help="Whether the model should predict the 'epsilon'/noise error or directly the reconstructed image 'x0'.")
parser.add_argument("--cfg-scale", type=float, default=4.0)
parser.add_argument(
"--checkpoint",
type=str,
default=None,
help=(
"Whether training should be resumed from a previous checkpoint. Use a path saved by"
' `--checkpointing_steps`, or `"latest"` to automatically select the last available checkpoint.'
),
)
args = parser.parse_args()
return args
class ImageDataset(torch.utils.data.Dataset):
def __init__(self, images):
self.images = images
def __len__(self):
return len(self.images)
def __getitem__(self, idx):
return self.images[idx]
class RefImageDataset(torch.utils.data.Dataset):
def __init__(self, dataset):
self.dataset = dataset
def __len__(self):
return len(self.dataset)
def __getitem__(self, idx):
item = self.dataset[idx]
item = np.array(item[0])
item = torch.from_numpy(item).permute(2, 0, 1)
return item
@torch.no_grad()
def main(args):
prefix = "ema" if args.use_ema else "standard"
exp_name = f"{prefix}_{args.steps_per_class}_{args.cfg_scale}_{args.ddpm_beta_schedule}_{args.ddpm_num_inference_steps}"
print(f"Exp_name {exp_name}")
image_path = os.path.join(args.checkpoint, f"images_{exp_name}.npz")
print(f"Computing fidelity metrics from {image_path}...")
images = np.load(image_path)["arr_0"]
images = torch.from_numpy(images).permute(0, 3, 1, 2)
print(images.shape)
dataset = ImageDataset(images)
ref_dataset = ImageFolder(args.train_data_dir, transform=transforms.Lambda(lambda pil_image: center_crop_arr(pil_image, args.image_size)))
ref_dataset = RefImageDataset(ref_dataset)
metrics_dict = torch_fidelity.calculate_metrics(
input1=dataset,
input2=ref_dataset,
batch_size=args.batch_size,
cuda=True,
isc=True,
fid=True,
kid=False,
prc=False,
save_cpu_ram=True,
verbose=True,
)
print(metrics_dict)
# metrics_dict = torch_fidelity.calculate_metrics(
# input1=dataset,
# input2=ref_dataset,
# batch_size=args.batch_size,
# cuda=True,
# prc=True,
# prc_batch_size=args.batch_size,
# save_cpu_ram=True,
# verbose=True,
# )
# print(metrics_dict)
if __name__ == "__main__":
args = parse_args()
main(args)