GRN / grn /tokenizer /sample.py
hanjian.thu123
[update] app.py
17a8581
Raw
History Blame Contribute Delete
31.2 kB
import os
import tqdm
import json
import re
import torch
import torch.nn.functional as F
import argparse
import time
import datetime
import numpy as np
import hashlib
import random
import torch.nn as nn
from torchvision.models.inception import inception_v3
from torch.profiler import record_function as torch_record_function
from contextlib import nullcontext
import lpips
import cv2
from einops import rearrange
from tqdm import tqdm
from PIL import Image
import os.path as osp
Image.MAX_IMAGE_PIXELS = None
from videovae.modules.commitments import DiagonalGaussianDistribution
import torch.distributed as dist
from torch.multiprocessing import spawn
from torch.nn.parallel import DistributedDataParallel as DDP
import imageio
import random
from skimage.metrics import peak_signal_noise_ratio as psnr_loss
from skimage.metrics import structural_similarity as ssim_loss
from videovae.data import VideoData
from videovae.utils.misc import save_video_grid, shift_dim, data_prefix_manager, rearranged_forward, seed_everything
from videovae.utils.init_models import init_cnn_from_image, load_cnn
from videovae.utils.arguments import MainArgs, add_model_specific_args, init_resolution
from videovae.evaluation import get_fvd_logits, frechet_distance, load_fvd_model
from videovae.evaluation import calculate_frechet_distance
from videovae.evaluation import InceptionV3
from videovae.evaluation import calculate_fvd, calculate_lpips, calculate_psnr, calculate_ssim
torch.set_num_threads(32)
os.environ["NCCL_DEBUG"] = "WARN"
os.environ['PYTORCH_CUDA_ALLOC_CONF'] = 'expandable_segments:True'
def calculate_batch_codebook_usage_percentage(batch_encoding_indices,n_codes):
if isinstance(batch_encoding_indices, list):
all_indices = []
for one_encoding_indices in batch_encoding_indices:
all_indices.append(one_encoding_indices.flatten())
all_indices = torch.cat(all_indices, dim=0)
else:
# Flatten the batch of encoding indices into a single 1D tensor
all_indices = batch_encoding_indices.flatten()
all_indices = all_indices.detach().cpu()
# Obtain the total number of encoding indices in the batch to calculate percentages
total_indices = all_indices.numel()
# Initialize a tensor to store the percentage usage of each code
codebook_usage = torch.zeros(n_codes, dtype=torch.long)
# Count the number of occurrences of each index and get their frequency as percentages
unique_indices, counts = torch.unique(all_indices, return_counts=True)
# Populate the corresponding percentages in the codebook_usage_percentage tensor
codebook_usage[unique_indices.long()] = counts
return codebook_usage
def disabled_train(self, mode=True):
"""Overwrite model.train with this function to make sure train/eval mode
does not change anymore."""
return self
def default_parse_args():
parser = argparse.ArgumentParser()
parser.add_argument('--vqgan_ckpt', type=str, default=None)
parser.add_argument('--sd_ckpt', type=str, default=None)
parser.add_argument('--use_frames', type=int, default=None)
parser.add_argument('--inference_type', type=str, choices=["image", "video", "video_concat"])
parser.add_argument('--save_prediction', action='store_true')
parser.add_argument('--save_dir', type=str, default="results")
parser.add_argument('--intermediate_tensor', action='store_true')
parser.add_argument('--save_z', action='store_true')
parser.add_argument('--save_frames', action='store_true')
parser.add_argument('--image_recon4video', action='store_true')
parser.add_argument('--junke_old', action='store_true')
parser.add_argument('--cal_norm', action='store_true')
parser.add_argument('--save_samples', type=str, default=None)
parser.add_argument('--device', type=str, default="cuda", choices=["cpu", "cuda"])
parser.add_argument('--noise_scale', type=float, default=0.0)
parser = MainArgs.add_main_args(parser)
parser = VideoData.add_data_specific_args(parser)
args, unknown = parser.parse_known_args()
args, parser, vae_model = add_model_specific_args(args, parser)
args = parser.parse_args()
return args, vae_model
def setup(rank, world_size):
os.environ['MASTER_ADDR'] = 'localhost'
os.environ['MASTER_PORT'] = str(12355+int(time.time())%1000)
# dist.init_process_group("nccl", rank=rank, world_size=world_size)
dist.init_process_group("nccl", rank=rank, world_size=world_size, timeout=datetime.timedelta(seconds=30 * 60))
def cleanup():
dist.destroy_process_group()
def main():
args, vae_model = default_parse_args()
assert len(args.dataset_list) == 1
# init data_prefix_manager
data_prefix_manager.set_data_root(args.data_root, username=args.username)
args.default_root_dir = data_prefix_manager(args.default_root_dir)
os.makedirs(args.default_root_dir, exist_ok=True)
print(args.default_root_dir)
# init intermediate_tensor_dir
if args.intermediate_tensor:
random.seed(time.time())
random_folder_name = hashlib.sha256(str(random.random()).encode('utf-8')).hexdigest()[:16]
args.intermediate_tensor_dir = os.path.join(args.default_root_dir, random_folder_name)
print(f"save temporal tensor to {args.intermediate_tensor_dir}")
seed_everything(seed=0, allow_tf32=True) # ALERT: allow_tf32=True may cause accumulate error in conv3d forward >
# init resolution
args.resolution = init_resolution(args.resolution, len(args.dataset_list))
# init profiler
def trace_handler(p):
p.export_chrome_trace(os.path.join(args.default_root_dir, f"trace_step_{p.step_num}_rank_{0}.json"))
tp = None
if args.turn_on_profiler:
tp = torch.profiler.profile(
activities=[
torch.profiler.ProfilerActivity.CPU,
torch.profiler.ProfilerActivity.CUDA,
],
schedule=torch.profiler.schedule(
wait=args.profiler_scheduler_wait_steps,
warmup=3,
active=2,
repeat=1,
),
with_stack=True,
record_shapes=True,
profile_memory=True,
on_trace_ready=trace_handler
)
tp.start()
record_function = torch_record_function
else:
record_function = nullcontext
vae = None
use_vae = None
num_codes = None
if args.vqgan_ckpt:
args.vqgan_ckpt = data_prefix_manager(args.vqgan_ckpt)
if args.tokenizer in ["hbq_tokenizer"]:
vae = vae_model(args)
state_dict = torch.load(args.vqgan_ckpt, map_location=torch.device("cpu"), weights_only=True)
new_state_dict = {}
for key in ['vae', 'ema']:
if (key not in state_dict) or (not state_dict[key]):
continue
if 'quantizer.scale_learnable_parameters' in state_dict[key]:
if len(state_dict[key]['quantizer.scale_learnable_parameters']) == 1:
state_dict[key]['quantizer.scale_learnable_parameters'] = state_dict[key]['quantizer.scale_learnable_parameters'].expand(4)
state_dict[key]['scale_learnable_parameters'] = state_dict[key]['quantizer.scale_learnable_parameters']
del state_dict[key]['quantizer.scale_learnable_parameters']
if 'z_mean' in state_dict[key]:
if state_dict[key]['z_mean'].shape != vae.z_mean.shape:
del state_dict[key]['z_mean']
del state_dict[key]['z_std']
new_state_dict[key] = state_dict[key]
slim_model_path = args.vqgan_ckpt.replace('/checkpoints/', f'/slim_{key}/')
if not osp.exists(slim_model_path):
os.makedirs(os.path.dirname(slim_model_path), exist_ok=True)
torch.save({key: state_dict[key]}, slim_model_path)
print(f'save to {slim_model_path}')
if args.ema == "yes":
print("testing ema weights")
print(vae.load_state_dict(new_state_dict["ema"], strict=False))
else:
print("testing non ema weights")
print(vae.load_state_dict(new_state_dict["vae"], strict=False))
for name, param in vae.named_parameters():
if name.startswith("scale_learnable_"):
try:
print(f"{name}: {param[:32,0,0].cpu().detach().reshape(-1).tolist()}")
except:
print(f"{name}: {param[:32].cpu().detach().reshape(-1).tolist()}")
for name, param in vae.named_buffers():
if name.startswith("scale_learnable_"):
try:
print(f"{name}: {param[:32,0,0].cpu().detach().reshape(-1).tolist()}")
except:
print(f"{name}: {param[:32].cpu().detach().reshape(-1).tolist()}")
if ("scale_wise_std_" in name) or ("scale_wise_mean_" in name):
print(f"{name}: {param[:32,0,0].cpu().detach().reshape(-1).tolist()}")
if ('signal_' in name):
print(f"{name}: {param.cpu().detach().reshape(-1).tolist()}")
if args.tokenizer != 'hbq_tokenizer':
vae.enable_slicing()
# vae.enable_tiling()
else:
raise NotImplementedError
if args.inference_type == "video":
def extract_results(return_dict, world_size):
real_embeddings, fake_embeddings, all_real_videos, all_fake_videos, zs = [], [], [], [], []
if args.intermediate_tensor:
for rank in range(world_size):
real_embeddings.append(return_dict[rank]['real_embeddings'])
fake_embeddings.append(return_dict[rank]['fake_embeddings'])
all_real_videos += return_dict[rank]['all_real_videos']
all_fake_videos += return_dict[rank]['all_fake_videos']
zs.append(return_dict[rank]['zs'])
real_embeddings = torch.cat(real_embeddings, 0).to('cuda:0')
fake_embeddings = torch.cat(fake_embeddings, 0).to('cuda:0')
zs = torch.cat(zs, 0).to('cuda:0')
else:
for rank in range(world_size):
real_embeddings.append(return_dict[rank]['real_embeddings'])
fake_embeddings.append(return_dict[rank]['fake_embeddings'])
all_real_videos.append(return_dict[rank]['all_real_videos'])
all_fake_videos.append(return_dict[rank]['all_fake_videos'])
zs.append(return_dict[rank]['zs'])
real_embeddings = torch.cat(real_embeddings, 0).to('cuda:0')
fake_embeddings = torch.cat(fake_embeddings, 0).to('cuda:0')
all_real_videos = torch.cat(all_real_videos, 0)
all_fake_videos = torch.cat(all_fake_videos, 0)
zs = torch.cat(zs, 0).to('cuda:0')
return real_embeddings, fake_embeddings, all_real_videos, all_fake_videos, zs
def inference(mean=None, std=None, noise_scale=0):
world_size = torch.cuda.device_count()
manager = torch.multiprocessing.Manager()
return_dict = manager.dict()
### multi-process
# try:
# spawn(inference_DDP, args=(world_size, args, vae_model, vae, record_function, tp, use_vae, num_codes, return_dict, mean, std, noise_scale), nprocs=world_size, join=True)
# except Exception as e:
# print(f"Error during spawn {e}")
## single process
world_size = 1
inference_DDP(0, world_size, args, vae_model, vae, record_function, tp, use_vae, num_codes, return_dict, mean=mean, std=std, noise_scale=noise_scale)
real_embeddings, fake_embeddings, all_real_videos, all_fake_videos, zs = extract_results(return_dict, world_size)
return real_embeddings, fake_embeddings, all_real_videos, all_fake_videos, zs
def cal_std(zs):
dims_to_reduce = [i for i in range(zs.dim()) if i != 1]
total_std = zs.std().item()
_mean = zs.mean(dim=dims_to_reduce)
_std = zs.std(dim=dims_to_reduce)
return total_std, _mean, _std
real_embeddings, fake_embeddings, all_real_videos, all_fake_videos, zs = inference()
if args.noise_scale > 0:
total_std, _mean, _std = cal_std(zs)
real_embeddings, fake_embeddings, all_real_videos, all_fake_videos, zs = inference(mean=_mean, std=_std, noise_scale=args.noise_scale)
if args.save_samples:
torch.save(zs.cpu(), args.save_samples)
if args.cal_norm:
total_std, _mean, _std = cal_std(zs)
print(f"{total_std = } {_mean = } {_std = }")
if args.save_prediction:
fname = os.path.join(args.save_dir, args.dataset_list[0], "gt_recon", "mean_std.pth")
torch.save({'_mean': _mean, '_std': _std}, fname)
result_str = video_eval(real_embeddings, fake_embeddings, all_real_videos, all_fake_videos)
else:
world_size = 1 if args.debug else torch.cuda.device_count()
manager = torch.multiprocessing.Manager()
return_dict = manager.dict()
if args.debug:
inference_eval(0, world_size, args, vae_model, vae, record_function, use_vae, num_codes, return_dict)
else:
spawn(inference_eval, args=(world_size, args, vae_model, vae, record_function, use_vae, num_codes, return_dict), nprocs=world_size, join=True)
pred_xs, pred_recs, lpips_alex, lpips_vgg, ssim_value, psnr_value, num_iter, total_usage, total_usage_bit, total_num_token, all_bit_indices_cat = [], [], 0, 0, 0, 0, 0, 0, 0, 0, []
for rank in range(world_size):
pred_xs.append(return_dict[rank]['pred_xs'])
pred_recs.append(return_dict[rank]['pred_recs'])
lpips_alex += return_dict[rank]['lpips_alex']
lpips_vgg += return_dict[rank]['lpips_vgg']
ssim_value += return_dict[rank]['ssim_value']
psnr_value += return_dict[rank]['psnr_value']
num_iter += return_dict[rank]['num_iter']
total_usage += return_dict[rank]['total_usage']
pred_xs = np.concatenate(pred_xs, 0)
pred_recs = np.concatenate(pred_recs, 0)
result_str = image_eval(pred_xs, pred_recs, lpips_alex, lpips_vgg, ssim_value, psnr_value, num_iter, total_usage, num_codes, total_usage_bit, total_num_token)
# result_str = inference_eval(args, vae_model, vae, record_function, use_vae, num_codes)
print(f"noise scale = {args.noise_scale}")
print(result_str)
# save result_str to exp_dir
basename = os.path.basename(args.vqgan_ckpt)
match = re.search(r'model_step_(\d+)\.ckpt', basename)
iter_num = match.group(1) if match else None
data_prefix_manager.set_data_root(args.data_root, username=args.username)
ckpt_dir = os.path.dirname(data_prefix_manager(args.vqgan_ckpt))
use_frames = args.use_frames if args.use_frames else args.sequence_length
save_dir = os.path.join(ckpt_dir, "evaluation", args.dataset_list[0], f"{args.resolution[0][0]}_{args.resolution[0][1]}", f"{use_frames}")
os.makedirs(save_dir, exist_ok=True)
ema_suffix = "_ema" if args.ema == "yes" else ""
result_name = os.path.join(save_dir, f"result_{iter_num}{ema_suffix}.txt")
if (not args.save_prediction) and (args.noise_scale == 0):
with open(result_name, "w") as f:
f.write(result_str)
# print('Usage = %.2f'%((total_usage > 0.).sum() / num_codes))
if args.intermediate_tensor:
os.system(f"rm -rf {args.intermediate_tensor_dir}")
def add_noise(z, mean, std, noise_scale):
if noise_scale > 0:
mean = mean.view(1, mean.shape[0], 1, 1, 1).to(z.device)
std = std.view(1, std.shape[0], 1, 1, 1).to(z.device)
z = (z - mean) / std
noise = torch.randn(z.size()).to(z.device)
z = (z + noise * noise_scale) * std + mean
return z
def inference_DDP(rank, world_size, args, vae_model, vae, record_function, tp, use_vae, num_codes, return_dict, mean=None, std=None, noise_scale=0):
setup(rank, world_size)
# init data_prefix_manager
data_prefix_manager.set_data_root(args.data_root, username=args.username)
for param in vae.parameters():
param.requires_grad = False
vae = vae.eval()
vae = vae.to(f"cuda:{rank}")
# vae = torch.compile(vae)
save_dir = os.path.join(args.save_dir, args.dataset_list[0])
print('generating and saving video to %s...'%save_dir)
os.makedirs(save_dir, exist_ok=True)
data = VideoData(args)
loader = data.val_dataloader()
i3d = load_fvd_model(f"cuda:{rank}")
os.makedirs(os.path.join(save_dir, "gt"), exist_ok=True)
os.makedirs(os.path.join(save_dir, "recons"), exist_ok=True)
zs = []
real_embeddings = []
fake_embeddings = []
all_real_videos = []
all_fake_videos = []
num_videos = len(loader)
loader_iter = iter(loader)
progress_bar = tqdm(total=num_videos, desc=f"Testing {num_videos} batches")
for batch_idx in range(num_videos):
if args.turn_on_profiler and tp:
tp.step()
batch = next(loader_iter)
with torch.no_grad():
input_ = batch['video'] # B C T H W
B = input_.shape[0]
if args.tokenizer in ["hbq_tokenizer"]:
input_ = input_.to(f"cuda:{rank}").to(torch.bfloat16)
with torch.amp.autocast("cuda", dtype=torch.bfloat16):
x_raw, x_recons, z = vae(input_, 0, is_train=False)
batch['video'] = x_raw.to('cpu').to(torch.float32)
x_recons = x_recons.to(torch.float32)
else:
raise NotImplementedError
if args.tokenizer in ["icvivit", "sd"]:
x_recons = rearrange(x_recons, "(b t) c h w -> b c t h w", b=B)
real_videos = torch.clamp(batch['video'] / 2 + 0.5, 0, 1)
if args.junke_old:
fake_videos = torch.clamp(x_recons.detach().cpu() + 0.5, 0, 1)
else:
fake_videos = torch.clamp(x_recons.detach().cpu() / 2 + 0.5, 0, 1)
use_frames = args.use_frames if args.use_frames else args.sequence_length
if args.intermediate_tensor:
folder_name = os.path.join(args.intermediate_tensor_dir, f"{rank}_{batch_idx}")
os.makedirs(folder_name, exist_ok=True)
real_file = os.path.join(folder_name, "real_videos.pt")
fake_file = os.path.join(folder_name, "fake_videos.pt")
real_videos = real_videos[:,:,:use_frames,...]
fake_videos = fake_videos[:,:,:use_frames,...]
torch.save(real_videos.permute(0, 2, 1, 3, 4).squeeze(0), real_file)
torch.save(fake_videos.permute(0, 2, 1, 3, 4).squeeze(0), fake_file)
all_real_videos.append(real_file)
all_fake_videos.append(fake_file)
else:
real_videos = real_videos[:,:,:use_frames,...]
fake_videos = fake_videos[:,:,:use_frames,...]
all_real_videos.append(real_videos.clone())
all_fake_videos.append(fake_videos.clone())
if args.cal_norm or args.save_samples or args.noise_scale > 0:
zs.append(z)
real_embedding = get_fvd_logits(shift_dim(real_videos * 255, 1, -1).byte().data.numpy(), i3d=i3d, device=f"cuda:{rank}").cpu()
real_embeddings.append(real_embedding)
fake_embedding = get_fvd_logits(shift_dim(fake_videos * 255, 1, -1).byte().data.numpy(), i3d=i3d, device=f"cuda:{rank}").cpu()
fake_embeddings.append(fake_embedding)
if args.tokenizer in ['cvivit', "icvivit"] and not use_vae:
batch_codebook_usage = vq_output["batch_usage"]
total_usage += batch_codebook_usage
if args.save_prediction:
video = torch.cat([real_videos[:,:,:fake_videos.shape[2],:,:], fake_videos], dim=-1)
b, c, t, h, w = video.shape
video = video.permute(0, 2, 3, 4, 1).contiguous()
video = (video.squeeze().detach().cpu().numpy() * 255).astype('uint8')
os.makedirs(os.path.join(save_dir, "gt_recon"), exist_ok=True)
this_filename = batch["path"][0].split('/')[-1]
fname = os.path.join(save_dir, "gt_recon", this_filename)
import imageio
imageio.mimsave(fname, video, fps=15)
if args.save_z:
os.makedirs(os.path.join(save_dir, "gt_recon"), exist_ok=True)
this_filename = batch["path"][0].split('/')[-1].split(".")[0]
fname = os.path.join(save_dir, "gt_recon", this_filename+".pt")
torch.save(z, fname)
if args.save_frames:
def convert_to_uint8(image):
return (image.detach().cpu().numpy() * 255).astype(np.uint8)
# artifact_grid_size = 32
assert real_videos.shape == fake_videos.shape, f"shape of gt and predicted videos are not equal"
assert real_videos.shape[0] == fake_videos.shape[0] == 1, f"batch size must be 1, real_videos {real_videos.shape[0]}, fake_videos {fake_videos.shape[0]}"
_real_videos = real_videos.squeeze(0)
_fake_videos = fake_videos.squeeze(0)
# h, w = real_videos.shape[-2:]
# assert (h % artifact_grid_size == 0) and (w % artifact_grid_size == 0), f"height and width of video must be divisible by {artifact_grid_size}"
frame_num = _real_videos.shape[1]
for frame_idx in range(frame_num):
real_image = _real_videos[:,frame_idx,:,:]
fake_image = _fake_videos[:,frame_idx,:,:]
# most_different_top_left, max_difference = find_most_different_patch(real_image, fake_image, artifact_grid_size)
real_image_uint8 = convert_to_uint8(real_image)
predicted_image_uint8 = convert_to_uint8(fake_image)
real_image_bgr = cv2.cvtColor(real_image_uint8.transpose(1, 2, 0), cv2.COLOR_RGB2BGR)
predicted_image_bgr = cv2.cvtColor(predicted_image_uint8.transpose(1, 2, 0), cv2.COLOR_RGB2BGR)
concatenated_image = np.concatenate((real_image_bgr, predicted_image_bgr), axis=1)
fname = os.path.join(save_dir, "gt_recon", f"{this_filename}_{frame_idx}.png")
cv2.imwrite(fname, concatenated_image)
progress_bar.update(1)
real_embeddings = torch.cat(real_embeddings, 0)
fake_embeddings = torch.cat(fake_embeddings, 0)
zs = torch.cat(zs, 0) if len(zs) > 0 else torch.tensor([])
if args.intermediate_tensor:
temp_dict = {
'real_embeddings':real_embeddings.cpu(),
'fake_embeddings':fake_embeddings.cpu(),
'all_real_videos':all_real_videos,
'all_fake_videos':all_fake_videos,
'zs': zs.cpu(),
}
else:
all_real_videos = torch.cat(all_real_videos, 0).permute(0, 2, 1, 3, 4)
all_fake_videos = torch.cat(all_fake_videos, 0).permute(0, 2, 1, 3, 4)
temp_dict = {
'real_embeddings':real_embeddings.cpu(),
'fake_embeddings':fake_embeddings.cpu(),
'all_real_videos':all_real_videos.cpu(),
'all_fake_videos':all_fake_videos.cpu(),
'zs': zs.cpu(),
}
# if dist.is_initialized():
# dist.barrier()
return_dict[rank] = temp_dict
cleanup()
def video_eval(real_embeddings, fake_embeddings, all_real_videos, all_fake_videos):
fake_embeddings = fake_embeddings.to(torch.float64)
real_embeddings = real_embeddings.to(torch.float64)
FVD = frechet_distance(fake_embeddings, real_embeddings)
print(f"FVD: {FVD}") # can't wait to see this number :)
del real_embeddings, fake_embeddings
lpips = calculate_lpips(all_real_videos, all_fake_videos, device="cuda")["value"].values()
psnr = calculate_psnr(all_real_videos, all_fake_videos)["value"].values()
ssim = calculate_ssim(all_real_videos, all_fake_videos)["value"].values()
lpips = np.mean(np.stack(list(lpips)))
ssim = np.mean(np.stack(list(ssim)))
psnr = np.mean(np.stack(list(psnr)))
result_str = f"""
FVD = {FVD:.4f}
LPIPS = {lpips:.4f}
SSIM = {ssim:.4f}
PSNR = {psnr:.3f}
"""
return result_str
def inference_eval(rank, world_size, args, vae_model, vae, record_function, use_vae, num_codes, return_dict):
# Don't remove this setup!!! dist.init_process_group is important for building loader (data.distributed.DistributedSampler)
setup(rank, world_size)
# init data_prefix_manager
data_prefix_manager.set_data_root(args.data_root, username=args.username)
device = torch.device(f"cuda:{rank}")
for param in vae.parameters():
param.requires_grad = False
vae.to(device).eval()
save_dir = os.path.join(args.save_dir, args.dataset_list[0])
print('generating and saving video to %s...'%save_dir)
os.makedirs(save_dir, exist_ok=True)
data = VideoData(args)
loader = data.val_dataloader()
dims = 2048
block_idx = InceptionV3.BLOCK_INDEX_BY_DIM[dims]
inception_model = InceptionV3([block_idx]).to(device)
inception_model.eval()
loader_iter = iter(loader)
pred_xs = []
pred_recs = []
# LPIPS score related
loss_fn_alex = lpips.LPIPS(net='alex').to(device) # best forward scores
loss_fn_vgg = lpips.LPIPS(net='vgg').to(device) # closer to "traditional" perceptual loss, when used for optimization
lpips_alex = 0.0
lpips_vgg = 0.0
# SSIM score related
ssim_value = 0.0
# PSNR score related
psnr_value = 0.0
num_images = len(loader)
print(f"Testing {num_images} files")
num_iter = 0
total_usage = 0.0
total_usage_bit = 0.0
total_num_token = 0
for batch_idx in tqdm(range(num_images)):
batch = next(loader_iter)
with torch.no_grad():
x = batch['video']
if args.tokenizer in ["hbq_tokenizer"]:
x_raw, x_recons, z = vae(x.to(device), 0, is_train=False)
x_recons = x_recons.squeeze(-3).cpu()
else:
raise NotImplementedError
if args.image_recon4video:
# convert back to image format
x = x.squeeze(2)
x_recons = x_recons.squeeze(2)
if args.tokenizer in ["cvivit", "icvivit"] and not use_vae:
# encoding_indices = vq_output["encodings"].detach().cpu()
code_counts = calculate_batch_codebook_usage_percentage(vq_output["encodings"], num_codes)
total_counts += code_counts
batch_codebook_usage = vq_output["batch_usage"]
total_usage += batch_codebook_usage
paths = batch["path"]
assert len(paths) == x.shape[0]
for p, input_ori, recon_ori in zip(paths, x, x_recons):
if os.path.isabs(p):
p = "/".join(p.split("/")[6:])
assert not os.path.isabs(p), f"{p} should not be abspath"
path = os.path.join(save_dir, "input_recon", os.path.basename(p))
os.makedirs(os.path.split(path)[0], exist_ok=True)
input_ori = input_ori.unsqueeze(0).to(device)
input_ = (input_ori + 1) / 2 # [0, 1]
pred_x = inception_model(input_)[0]
pred_x = pred_x.squeeze(3).squeeze(2).cpu().numpy()
recon_ori = recon_ori.unsqueeze(0).to(device)
recon_ = (recon_ori + 1) / 2 # [0, 1]
# recon_ = recon_.permute(1, 2, 0).detach().cpu()
with torch.no_grad():
pred_rec = inception_model(recon_)[0]
pred_rec = pred_rec.squeeze(3).squeeze(2).cpu().numpy()
if args.save_prediction:
if input_.dim() == 4:
input_image = input_.squeeze(0)
if recon_.dim() == 4:
recon_image = recon_.squeeze(0)
input_recon = torch.cat([input_image, recon_image], dim=-1)
input_recon = Image.fromarray((torch.clamp(input_recon.permute(1, 2, 0).detach().cpu(), 0, 1).numpy() * 255).astype(np.uint8))
input_recon.save(path)
pred_xs.append(pred_x)
pred_recs.append(pred_rec)
# calculate lpips
with torch.no_grad():
lpips_alex += loss_fn_alex(input_ori, recon_ori).sum() # [-1, 1]
lpips_vgg += loss_fn_vgg(input_ori, recon_ori).sum() # [-1, 1]
#calculate PSNR and SSIM
rgb_restored = (recon_ * 255.0).permute(0, 2, 3, 1).to("cpu", dtype=torch.uint8).numpy()
rgb_gt = (input_ * 255.0).permute(0, 2, 3, 1).to("cpu", dtype=torch.uint8).numpy()
rgb_restored = rgb_restored.astype(np.float32) / 255.
rgb_gt = rgb_gt.astype(np.float32) / 255.
ssim_temp = 0
psnr_temp = 0
B, _, _, _ = rgb_restored.shape
for i in range(B):
rgb_restored_s, rgb_gt_s = rgb_restored[i], rgb_gt[i]
with torch.no_grad():
ssim_temp += ssim_loss(rgb_restored_s, rgb_gt_s, data_range=1.0, channel_axis=-1)
psnr_temp += psnr_loss(rgb_gt, rgb_restored)
ssim_value += ssim_temp / B
psnr_value += psnr_temp / B
num_iter += 1
pred_xs = np.concatenate(pred_xs, axis=0)
pred_recs = np.concatenate(pred_recs, axis=0)
temp_dict = {
'pred_xs':pred_xs,
'pred_recs':pred_recs,
'lpips_alex':lpips_alex.cpu(),
'lpips_vgg':lpips_vgg.cpu(),
'ssim_value': ssim_value,
'psnr_value': psnr_value,
'num_iter': num_iter,
'total_usage': total_usage,
'total_usage_bit': total_usage_bit,
'total_num_token': total_num_token,
}
return_dict[rank] = temp_dict
# if dist.is_initialized():
# dist.barrier()
cleanup()
def image_eval(pred_xs, pred_recs, lpips_alex, lpips_vgg, ssim_value, psnr_value, num_iter, total_usage, num_codes, total_usage_bit, total_num_token):
mu_x = np.mean(pred_xs, axis=0)
sigma_x = np.cov(pred_xs, rowvar=False)
mu_rec = np.mean(pred_recs, axis=0)
sigma_rec = np.cov(pred_recs, rowvar=False)
fid_value = calculate_frechet_distance(mu_x, sigma_x, mu_rec, sigma_rec)
lpips_alex_value = lpips_alex / num_iter
lpips_vgg_value = lpips_vgg / num_iter
ssim_value = ssim_value / num_iter
psnr_value = psnr_value / num_iter
result_str = f"""
FID = {fid_value:.4f}
LPIPS_VGG: {lpips_vgg_value.item():.4f}
LPIPS_ALEX: {lpips_alex_value.item():.4f}
SSIM: {ssim_value:.4f}
PSNR: {psnr_value:.3f}
"""
return result_str
if __name__ == '__main__':
main()