"""Compare paired BF16 and INT4 runs without ranking them.""" import argparse import csv import html import json import math import os import statistics from pathlib import Path import numpy as np from PIL import Image from scripts.integrity import sha256, validate_pair from scripts.provenance import validate_roles def load_records(root): rows = [json.loads(line) for line in (Path(root) / 'records.jsonl').read_text(encoding='utf-8').splitlines() if line] records = {} for row in rows: key = (row['case_id'], row['seed']) if key in records: raise ValueError(f'Duplicate record: {key}') if sha256(Path(root) / row['image']) != row['image_sha256']: raise ValueError(f'Image hash mismatch: {key}') records[key] = row if not records: raise ValueError('Empty benchmark run') return records def compare_pixels(left, right): with Image.open(left) as image_a, Image.open(right) as image_b: if image_a.size != image_b.size: raise ValueError('Image dimensions differ') image_a, image_b = image_a.convert('RGBA'), image_b.convert('RGBA') array_a = np.asarray(image_a, dtype=np.float32) / 255 array_b = np.asarray(image_b, dtype=np.float32) / 255 composite_a = array_a[..., :3] * array_a[..., 3:] + 1 - array_a[..., 3:] composite_b = array_b[..., :3] * array_b[..., 3:] + 1 - array_b[..., 3:] mse = float(np.mean((composite_a - composite_b) ** 2)) return {'rgb_mae_white': float(np.mean(np.abs(composite_a - composite_b))), 'rgb_psnr_white_db': None if mse == 0 else -10 * math.log10(mse), 'alpha_mae': float(np.mean(np.abs(array_a[..., 3] - array_b[..., 3])))} def summary_from(rows, baseline_env, quantized_env, sample): return {'pairs': len(rows), 'cases': len({row['case_id'] for row in rows}), 'bf16_mean_seconds': statistics.mean(row['bf16_seconds'] for row in rows), 'int4_mean_seconds': statistics.mean(row['int4_seconds'] for row in rows), 'bf16_max_allocated_gib': max(row['bf16_peak_allocated_gib'] for row in rows), 'int4_max_allocated_gib': max(row['int4_peak_allocated_gib'] for row in rows), 'width': sample['width'], 'height': sample['height'], 'steps': sample['steps'], 'warmup': baseline_env['warmup'], 'bf16_weight_bytes': sum(item['size'] for item in baseline_env['model_identity']['files'] if item['path'].endswith('.safetensors')), 'int4_weight_bytes': sum(item['size'] for item in quantized_env['model_identity']['files'] if item['path'].endswith('.safetensors'))} def main(): parser = argparse.ArgumentParser() parser.add_argument('--baseline', default='artifacts/eval/bf16') parser.add_argument('--quantized', default='artifacts/eval/int4') parser.add_argument('--output', default='artifacts/eval') args = parser.parse_args() base, quant, out = Path(args.baseline), Path(args.quantized), Path(args.output) baseline, quantized = load_records(base), load_records(quant) if baseline.keys() != quantized.keys(): raise ValueError('Benchmark cases or seeds do not match') baseline_env = json.loads((base / 'environment.json').read_text(encoding='utf-8')) quantized_env = json.loads((quant / 'environment.json').read_text(encoding='utf-8')) validate_roles(baseline_env['model_identity'], quantized_env['model_identity']) for key in ('benchmark_sha256', 'runtime_helper_sha256', 'device_helper_sha256'): if baseline_env.get(key) != quantized_env.get(key): raise ValueError(f'Benchmark implementation mismatch: {key}') for key in ('gpu', 'cuda', 'packages', 'offload', 'warmup', 'generator_device', 'cases_sha256'): if baseline_env[key] != quantized_env[key]: raise ValueError(f'Runtime mismatch: {key}') rows = [] for key in baseline: left, right = baseline[key], quantized[key] validate_pair(left, right) rows.append({'case_id': key[0], 'seed': key[1], 'bf16_seconds': left['seconds'], 'int4_seconds': right['seconds'], 'bf16_peak_allocated_gib': left['peak_allocated_bytes'] / 2**30, 'int4_peak_allocated_gib': right['peak_allocated_bytes'] / 2**30, **compare_pixels(base / left['image'], quant / right['image'])}) summary = summary_from(rows, baseline_env, quantized_env, next(iter(baseline.values()))) out.mkdir(parents=True, exist_ok=True) (out / 'summary.json').write_text(json.dumps(summary, indent=2), encoding='utf-8') with (out / 'comparison.csv').open('w', encoding='utf-8', newline='') as handle: writer = csv.DictWriter(handle, fieldnames=list(rows[0])) writer.writeheader() writer.writerows(rows) lines = ['# Informal release evaluation: BF16 / INT4', '', 'This community comparison is reference material. It is not an official evaluation.', '', f'{len(rows)} paired outputs on {baseline_env["gpu"]}; {summary["width"]}×{summary["height"]}, ' f'{summary["steps"]} steps, offload={baseline_env["offload"]}, CFG=1, KV cache enabled.', '', ('Warmup excluded. ' if baseline_env['warmup'] else 'No warmup performed. ') + 'Pixel metrics measure drift. They are not a semantic quality score. ' 'The suite is small and does not establish a ranking.', '', '| Case | Seed | BF16 s | INT4 s | BF16 peak GiB | INT4 peak GiB | RGB MAE |', '|---|---:|---:|---:|---:|---:|---:|'] gallery = ['BF16 / INT4', '', '

BF16 / INT4

Left: BF16. Right: saved INT4. Same settings and seeds.

'] for row in rows: lines.append(f'| {row["case_id"]} | {row["seed"]} | {row["bf16_seconds"]:.2f} | ' f'{row["int4_seconds"]:.2f} | {row["bf16_peak_allocated_gib"]:.2f} | ' f'{row["int4_peak_allocated_gib"]:.2f} | {row["rgb_mae_white"]:.4f} |') key = (row['case_id'], row['seed']) left = Path(os.path.relpath(base / baseline[key]['image'], out)).as_posix() right = Path(os.path.relpath(quant / quantized[key]['image'], out)).as_posix() gallery.append(f'

{html.escape(row["case_id"])} seed {row["seed"]}

' f'
{html.escape(baseline[key]["prompt"])}
' f'BF16' f'INT4
') lines.extend(['', '## Summary', '', f'Mean latency: BF16 {summary["bf16_mean_seconds"]:.2f}s; INT4 {summary["int4_mean_seconds"]:.2f}s.', f'Maximum allocated CUDA memory: BF16 {summary["bf16_max_allocated_gib"]:.2f} GiB; ' f'INT4 {summary["int4_max_allocated_gib"]:.2f} GiB.', '', 'Raw records: comparison.csv, bf16/records.jsonl, int4/records.jsonl.', 'Visual notes belong in qualitative.md and are written after inspecting the images.', '']) (out / 'report.md').write_text('\n'.join(lines) + '\n', encoding='utf-8') (out / 'comparison.html').write_text('\n'.join(gallery), encoding='utf-8') print(json.dumps(summary, indent=2)) if __name__ == '__main__': main()