Spaces:
Runtime error
Runtime error
| # Copyright 2020 Erik Härkönen. All rights reserved. | |
| # This file is licensed to you under the Apache License, Version 2.0 (the "License"); | |
| # you may not use this file except in compliance with the License. You may obtain a copy | |
| # of the License at http://www.apache.org/licenses/LICENSE-2.0 | |
| # Unless required by applicable law or agreed to in writing, software distributed under | |
| # the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS | |
| # OF ANY KIND, either express or implied. See the License for the specific language | |
| # governing permissions and limitations under the License. | |
| import torch, numpy as np | |
| from types import SimpleNamespace | |
| import itertools | |
| import sys | |
| from pathlib import Path | |
| sys.path.insert(0, str(Path(__file__).parent.parent)) | |
| from models import get_instrumented_model | |
| SEED = 1369 | |
| SAMPLES = 100 | |
| B = 10 | |
| torch.backends.cudnn.benchmark = True | |
| has_gpu = torch.cuda.is_available() | |
| device = torch.device('cuda' if has_gpu else 'cpu') | |
| def compare(model, layer, z1, z2): | |
| # Run partial forward | |
| torch.manual_seed(0) | |
| np.random.seed(0) | |
| inst._retained[layer] = None | |
| with torch.no_grad(): | |
| model.partial_forward(z1, layer) | |
| assert inst._retained[layer] is not None, 'Layer not retained (partial)' | |
| feat_partial = inst._retained[layer].cpu().numpy().copy().reshape(-1) | |
| # Run standard forward | |
| torch.manual_seed(0) | |
| np.random.seed(0) | |
| inst._retained[layer] = None | |
| with torch.no_grad(): | |
| model.forward(z2) | |
| assert inst._retained[layer] is not None, 'Layer not retained (full)' | |
| feat_full = inst.retained_features()[layer].cpu().numpy().copy().reshape(-1) | |
| diff = np.sum(np.abs(feat_partial - feat_full)) | |
| return diff | |
| configs = [] | |
| # StyleGAN2 | |
| models = ['StyleGAN2'] | |
| layers = ['convs.0',] | |
| classes = ['cat', 'ffhq'] | |
| configs.append(itertools.product(models, layers, classes)) | |
| # StyleGAN | |
| models = ['StyleGAN'] | |
| layers = [ | |
| 'g_synthesis.blocks.128x128.conv0_up', | |
| 'g_synthesis.blocks.128x128.conv0_up.upscale', | |
| 'g_synthesis.blocks.256x256.conv0_up', | |
| 'g_synthesis.blocks.1024x1024.epi2.style_mod.lin' | |
| ] | |
| classes = ['ffhq'] | |
| configs.append(itertools.product(models, layers, classes)) | |
| # ProGAN | |
| models = ['ProGAN'] | |
| layers = ['layer2', 'layer7'] | |
| classes = ['churchoutdoor', 'bedroom'] | |
| configs.append(itertools.product(models, layers, classes)) | |
| # BigGAN | |
| models = ['BigGAN-512', 'BigGAN-256', 'BigGAN-128'] | |
| layers = ['generator.layers.2.conv_1', 'generator.layers.5.relu', 'generator.layers.10.bn_2'] | |
| classes = ['husky'] | |
| configs.append(itertools.product(models, layers, classes)) | |
| # Run all configurations | |
| for config in configs: | |
| for model_name, layer, outclass in config: | |
| print('Testing', model_name, layer, outclass) | |
| inst = get_instrumented_model(model_name, outclass, layer, device) | |
| model = inst.model | |
| # Test negative | |
| z_dummy = model.sample_latent(B) | |
| z1 = torch.zeros_like(z_dummy).to(device) | |
| z2 = torch.ones_like(z_dummy).to(device) | |
| diff = compare(model, layer, z1, z2) | |
| assert diff > 1e-8, 'Partial and full should differ, but they do not!' | |
| # Test model randomness (should be seeded away) | |
| z1 = model.sample_latent(1) | |
| inst._retained[layer] = None | |
| with torch.no_grad(): | |
| model.forward(z1) | |
| feat1 = inst._retained[layer].reshape(-1) | |
| model.forward(z1) | |
| feat2 = inst._retained[layer].reshape(-1) | |
| diff = torch.sum(torch.abs(feat1 - feat2)) | |
| assert diff < 1e-8, f'Layer {layer} output contains randomness, diff={diff}' | |
| # Test positive | |
| torch.manual_seed(SEED) | |
| np.random.seed(SEED) | |
| latents = model.sample_latent(SAMPLES, seed=SEED) | |
| for i in range(0, SAMPLES, B): | |
| print(f'Layer {layer}: {i}/{SAMPLES}', end='\r') | |
| z = latents[i:i+B] | |
| diff = compare(model, layer, z, z) | |
| assert diff < 1e-8, f'Partial and full forward differ by {diff}' | |
| del model | |
| torch.cuda.empty_cache() |