wARTok / scripts /evaluate_all.py
Zyriix's picture
init opensource code
fd684da verified
Raw History Blame Contribute Delete
6.15 kB
"""Evaluate CIFAR-10 checkpoints with independent per-GPU seeds."""
import argparse
import csv
import hashlib
import io
import json
import os
from pathlib import Path
import subprocess
import sys
import time
ROOT = Path(__file__).resolve().parents[1]
# Method names match configuration prefixes and checkpoint filenames.
CONFIGS = {
"baseline": "baseline_ar.yaml",
"tail_dropout": "tail_dropout_ar.yaml",
"flow_matching": "flow_matching_ar.yaml",
"flow_matching_tail_dropout": "flow_matching_tail_dropout_ar.yaml",
"flow_matching_tied_tail_dropout": "flow_matching_tied_tail_dropout_ar.yaml",
"war": "war_ar.yaml"
}
def sha256(path):
digest = hashlib.sha256()
with open(path, 'rb') as f:
for block in iter(lambda: f.read(8 * 1024 * 1024), b''):
digest.update(block)
return digest.hexdigest()
def check_free(gpus):
output = subprocess.check_output(
['nvidia-smi', '--query-gpu=index,memory.used,utilization.gpu',
'--format=csv,noheader,nounits'], text=True)
devices = {int(row[0]): (int(row[1]), int(row[2]))
for row in csv.reader(io.StringIO(output))}
busy = {gpu: devices.get(gpu) for gpu in gpus
if gpu not in devices or devices[gpu][0] > 100 or devices[gpu][1] > 0}
if busy:
raise RuntimeError(f'Requested GPUs are not free: {busy}')
def save_summary(output, rows):
(output / 'results.json').write_text(json.dumps(rows, indent=2) + '\n')
if rows:
with (output / 'results.csv').open('w', newline='') as f:
writer = csv.DictWriter(f, fieldnames=list(rows[0]))
writer.writeheader()
writer.writerows(rows)
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--gpus', default='0,1,2,3,4,5,6,7')
parser.add_argument('--output', default='outputs/cifar10-nonlegacy')
parser.add_argument('--methods', nargs='+', choices=CONFIGS,
help='Optional subset, e.g. baseline war')
parser.add_argument('--resume', action='store_true', help='Reuse matching completed evaluations')
args = parser.parse_args()
gpus = [int(x) for x in args.gpus.split(',')]
if not gpus or len(gpus) != len(set(gpus)):
parser.error('GPU IDs must be nonempty and distinct')
configs = {key: ROOT / 'configs/cifar10' / name for key, name in CONFIGS.items()}
for config in configs.values():
if not config.is_file():
raise FileNotFoundError(config)
if args.methods:
if set(args.methods) - configs.keys():
parser.error('Unknown method')
configs = {key: path for key, path in configs.items() if key in args.methods}
checkpoints = {key: ROOT / 'checkpoints' / f'{key}.pt' for key in configs}
for checkpoint in checkpoints.values():
if not checkpoint.is_file():
raise FileNotFoundError(f'Place the downloaded checkpoint at {checkpoint}')
reference = ROOT / 'refs/cifar10-32x32_local.npz'
reference_hash = sha256(reference)
if reference_hash != '5493968c4f29b2878f64d6a640351f377e32e86553db56eca8147a0ae50d93f2':
raise ValueError('The CIFAR-10 FID reference checksum does not match')
output = Path(args.output).resolve()
output.mkdir(parents=True, exist_ok=True)
env = os.environ.copy()
env.update(CUDA_VISIBLE_DEVICES=','.join(map(str, gpus)), PYTHONDONTWRITEBYTECODE='1',
WANDB_MODE='disabled', OMP_NUM_THREADS='8', MKL_NUM_THREADS='8', TF_CPP_MIN_LOG_LEVEL='2')
rows = []
for key, config in configs.items():
checkpoint = checkpoints[key]
checkpoint_hash, config_hash = sha256(checkpoint), sha256(config)
case = output / key
result_path = case / 'metrics.json'
if result_path.exists() and not args.resume:
raise FileExistsError(result_path)
if not result_path.exists():
check_free(gpus)
case.mkdir(exist_ok=True)
cmd = [sys.executable, '-m', 'torch.distributed.run', '--standalone',
f'--nproc-per-node={len(gpus)}', 'evaluate.py', '--config', str(config),
'--checkpoint', str(checkpoint), '--num-samples', '50000', '--batch-size', '64',
'--seed', '42', '--no-legacy', '--output', str(case), '--fid-reference', str(reference)]
request = dict(command=cmd, checkpoint_sha256=checkpoint_hash,
config_sha256=config_hash, legacy=False)
(case / 'request.json').write_text(json.dumps(request, indent=2) + '\n')
print(f'START {key}', flush=True)
started = time.monotonic()
with (case / 'run.log').open('w') as log:
subprocess.run(cmd, cwd=ROOT, env=env, stdout=log, stderr=subprocess.STDOUT, check=True)
print(f'DONE {key} in {time.monotonic() - started:.1f}s', flush=True)
result = json.loads(result_path.read_text())
request = json.loads((case / 'request.json').read_text())
if request['checkpoint_sha256'] != checkpoint_hash:
raise ValueError(f'{key}: checkpoint changed since the recorded evaluation')
expected = dict(legacy=False, num_samples=50000, seed=42, world_size=len(gpus),
batch_size=64, ar_ema=True, precision='32-true', decoder='single_step',
config_sha256=config_hash, reference_sha256=reference_hash)
if any(result.get(name) != value for name, value in expected.items()):
raise ValueError(f'{key}: recorded evaluation settings do not match')
row = dict(method=key, nonlegacy_gfid=result['fid'], unique_images=result['unique_images'],
num_samples=result['num_samples'], legacy=False,
checkpoint_sha256=checkpoint_hash, config_sha256=config_hash,
reference_sha256=reference_hash)
rows.append(row)
save_summary(output, rows)
print(f'RESULT {key}: {result["fid"]:.8f}', flush=True)
print(f'COMPLETE: {len(rows)} non-legacy evaluations', flush=True)
if __name__ == '__main__':
main()