Instructions to use ProCreations/Image-2.1-Turbo-Calibrated-FP8 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Diffusers
How to use ProCreations/Image-2.1-Turbo-Calibrated-FP8 with Diffusers:
pip install -U diffusers transformers accelerate
import torch from diffusers import DiffusionPipeline # switch to "mps" for apple devices pipe = DiffusionPipeline.from_pretrained("ProCreations/Image-2.1-Turbo-Calibrated-FP8", dtype=torch.bfloat16, device_map="cuda") prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k" image = pipe(prompt).images[0] - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- Draw Things
- DiffusionBee
File size: 9,345 Bytes
ffc54ec | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | """Activation-aware calibrated FP8 (W8A8 E4M3) for Image 2.1 Turbo; no evaluation prompts used.
Per layer: five SmoothQuant exponents x {three weight-clipping factors with round-to-nearest,
GPTQ error-feedback rounding with full-token second moments}. Every candidate is scored with the
actual runtime path (Triton per-token activation quantization + native SM120 FP8 GEMM, FP32
accumulation) on 512 fit rows; the selected candidate is reported on 512 disjoint diagnostic rows.
Layers above 5% diagnostic output NRMSE would stay BF16.
"""
import json, math, shutil, statistics, sys
from pathlib import Path
import torch
from safetensors.torch import load_file, save_file
from diffusers import QwenImage21Transformer2DModel
from common import ROOT, BASE, BASE_REVISION, CALIBRATION, eligible_modules
from fp8_runtime import CalibratedFP8Linear, replace_module, quantize_activation
from hessian_store import hessian
from gptq import gptq_fp8
OUT_ROOT = ROOT / 'fp8' / 'release'
OUT = OUT_ROOT / 'transformer'
CACHE = ROOT / 'fp8' / 'calibrated-layers'
NOTICE = 'Built with Qwen. ProCreations modified Qwen-Image-2.1-Turbo transformer weights through calibrated FP8 quantization, 2026-10-09.'
def split(x):
g = torch.arange(len(x) // 4, device=x.device)
return x[g * 4 + g % 4].contiguous(), x[g * 4 + (g + 1) % 4].contiguous()
def fp8_forward(x, q, scales, smooth):
a, asc = quantize_activation(x, smooth)
return torch._scaled_mm(a, q.T, scale_a=asc, scale_b=scales.T, out_dtype=torch.bfloat16, use_fast_accum=False).float()
def nmse(y, ref):
return ((y - ref).square().mean() / ref.square().mean().clamp_min(1e-12)).item()
def bf16_weight(name):
from quantize_nvfp4 import weight
return weight(name)
@torch.inference_mode()
def calibrate_layer(name, layer_weight):
x = load_file(str(CALIBRATION / (name + '.safetensors')))['activations'].to('cuda')
fit, check = split(x)
H, tokens = hessian(name)
w = layer_weight.float()
amax = fit.float().abs().amax(0).clamp_min(1e-5)
wmax = w.abs().amax(0).clamp_min(1e-5)
ref = torch.nn.functional.linear(fit, layer_weight).float()
candidates, best = [], None
for alpha in [0., .25, .5, .75, 1.]:
smooth = torch.ones_like(amax) if alpha == 0 else (amax.pow(alpha) / wmax.pow(1 - alpha)).clamp(.01, 100.)
smooth = smooth / smooth.log().mean().exp()
ws = w * smooth[None, :]
options = []
for clip in [1., .995, .99]:
scales = (ws.abs().amax(1, keepdim=True) * clip / 448).clamp_min(1e-12)
options.append(({'rounding': 'nearest', 'weight_amax_clip_factor': clip}, scales,
(ws / scales).clamp(-448, 448).to(torch.float8_e4m3fn)))
scales = (ws.abs().amax(1, keepdim=True) / 448).clamp_min(1e-12)
Hz = H / (smooth[:, None] * smooth[None, :])
options.append(({'rounding': 'gptq', 'weight_amax_clip_factor': 1.}, scales, gptq_fp8(ws, Hz, scales)))
for item, scales, q in options:
err = nmse(fp8_forward(fit, q, scales, smooth), ref)
item = {'alpha': alpha, **item, 'fit_nmse': err}
candidates.append(item)
if best is None or err < best[0]:
best = (err, q.clone(), scales.clone(), smooth.clone(), item)
_, q, scales, smooth, item = best
ref_check = torch.nn.functional.linear(check, layer_weight).float()
diag = nmse(fp8_forward(check, q, scales, smooth), ref_check)
# Round-to-nearest reference at the same smoothing, for reporting the GPTQ contribution.
rtn = min((c for c in candidates if c['alpha'] == item['alpha'] and c['rounding'] == 'nearest'), key=lambda c: c['fit_nmse'])
result = {**item, 'diagnostic_nrmse': math.sqrt(diag), 'fit_nrmse': math.sqrt(item['fit_nmse']),
'nearest_fit_nrmse_same_alpha': math.sqrt(rtn['fit_nmse']), 'shape': list(q.shape),
'sample_rows': len(x), 'fit_rows': len(fit), 'diagnostic_rows': len(check),
'hessian_tokens': tokens, 'candidates': candidates}
return result, {'weight': q, 'weight_scale': scales.float(), 'smooth': smooth.float()}
def compute_shard(index, count):
names = json.loads((CALIBRATION / 'manifest.json').read_text())['modules']
for i, name in enumerate(names):
record, saved = CACHE / (name + '.json'), CACHE / (name + '.safetensors')
if i % count != index or (record.exists() and saved.exists()):
continue
result, state = calibrate_layer(name, bf16_weight(name))
save_file({k: v.cpu().contiguous() for k, v in state.items()}, str(saved))
record.write_text(json.dumps(result, indent=2))
print(json.dumps({'event': 'layer', 'shard': index, 'done': i + 1, 'layer': name, 'nrmse': result['diagnostic_nrmse'],
'alpha': result['alpha'], 'rounding': result['rounding']}), flush=True)
@torch.inference_mode()
def main():
CACHE.mkdir(parents=True, exist_ok=True); OUT.mkdir(parents=True, exist_ok=True)
if len(sys.argv) == 3 and sys.argv[1] == '--shard':
return compute_shard(*map(int, sys.argv[2].split('/')))
model = QwenImage21Transformer2DModel.from_pretrained(BASE, subfolder='transformer', torch_dtype=torch.bfloat16).to('cuda').eval()
modules = eligible_modules(model)
results, quantized, held = {}, {}, {}
for i, (name, layer) in enumerate(modules.items()):
record, saved = CACHE / (name + '.json'), CACHE / (name + '.safetensors')
if record.exists() and saved.exists():
result = json.loads(record.read_text()); state = {k: v.cuda() for k, v in load_file(str(saved)).items()}
else:
result, state = calibrate_layer(name, layer.weight)
save_file({k: v.cpu().contiguous() for k, v in state.items()}, str(saved))
record.write_text(json.dumps(result, indent=2))
preserve = not math.isfinite(result['diagnostic_nrmse']) or result['diagnostic_nrmse'] > .05
result['kept_bf16'] = preserve
results[name] = result
if preserve:
held[name] = result
else:
quantized[name] = {'shape': result['shape'], 'alpha': result['alpha'], 'rounding': result['rounding'],
'weight_amax_clip_factor': result['weight_amax_clip_factor']}
replace_module(model, name, CalibratedFP8Linear(state['weight'], state['weight_scale'], state['smooth']))
print(json.dumps({'event': 'quantize', 'done': i + 1, 'total': len(modules), 'layer': name,
'nrmse': result['diagnostic_nrmse'], 'alpha': result['alpha'], 'rounding': result['rounding'],
'nearest_fit': result['nearest_fit_nrmse_same_alpha'], 'fit': result['fit_nrmse']}), flush=True)
model.save_config(OUT)
config = {'format': 'procreations-calibrated-fp8-v1', 'base_model': 'Qwen/Qwen-Image-2.1-Turbo',
'base_revision': BASE_REVISION, 'weight_dtype': 'float8_e4m3fn', 'activation_dtype': 'float8_e4m3fn',
'weight_scaling': 'per-output-channel FP32', 'activation_scaling': 'dynamic per-token FP32',
'weight_rounding': 'per layer: round-to-nearest with clipping search, or GPTQ error feedback (full-token second moments)',
'accumulation': 'FP32, use_fast_accum=False', 'output_dtype': 'bfloat16',
'kernel': 'torch._scaled_mm native CUTLASS SM120, Triton fused smoothing and activation quantization',
'quantized_modules': quantized, 'kept_bf16_modules': list(held), 'modified_notice': NOTICE}
(OUT / 'quantization_config.json').write_text(json.dumps(config, indent=2))
report = OUT_ROOT / 'reports'; report.mkdir(parents=True, exist_ok=True)
(report / 'calibration_search.json').write_text(json.dumps(results, indent=2))
shutil.copy(CALIBRATION / 'manifest.json', report / 'calibration_manifest.json')
state = model.state_dict(); shards, shard, size = [], {}, 0
for n, v in state.items():
nb = v.numel() * v.element_size()
if shard and size + nb > 3_500_000_000:
shards.append(shard); shard, size = {}, 0
shard[n] = v.detach().cpu().contiguous(); size += nb
if shard:
shards.append(shard)
for old in OUT.glob('model-*.safetensors'):
old.unlink()
for i, s in enumerate(shards):
save_file(s, str(OUT / f'model-{i + 1:05d}-of-{len(shards):05d}.safetensors'), metadata={'format': 'pt', 'notice': NOTICE})
total = sum(v.numel() * v.element_size() for v in state.values())
vals = list(results.values())
summary = {'quantized_modules': len(quantized), 'bf16_outliers': list(held), 'transformer_bytes': total,
'mean_diagnostic_nrmse': statistics.mean(v['diagnostic_nrmse'] for v in vals),
'max_diagnostic_nrmse': max(v['diagnostic_nrmse'] for v in vals),
'gptq_selected': sum(v['rounding'] == 'gptq' for v in vals),
'mean_fit_nrmse': statistics.mean(v['fit_nrmse'] for v in vals),
'mean_nearest_fit_nrmse_same_alpha': statistics.mean(v['nearest_fit_nrmse_same_alpha'] for v in vals)}
(report / 'quantization_summary.json').write_text(json.dumps(summary, indent=2))
print('QUANTIZATION_COMPLETE', json.dumps(summary), flush=True)
if __name__ == '__main__':
main()
|