Text-to-Image
Diffusers
Safetensors
MageFlowPipeline
ajh
mage-flow
mage-flow-nvfp4-ajh
nvfp4
blackwell
qwen3-vl
quantization
Instructions to use ajh-code/Mage-Flow-NVFP4-AJH with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Diffusers
How to use ajh-code/Mage-Flow-NVFP4-AJH with Diffusers:
pip install -U diffusers transformers accelerate
import torch from diffusers import DiffusionPipeline # switch to "mps" for apple devices pipe = DiffusionPipeline.from_pretrained("ajh-code/Mage-Flow-NVFP4-AJH", torch_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
| #!/usr/bin/env python3 | |
| """Portable single-image Mage-Flow NVFP4 inference entry point.""" | |
| from __future__ import annotations | |
| import argparse | |
| from datetime import datetime, timezone | |
| import gc | |
| import json | |
| import os | |
| from pathlib import Path | |
| import platform | |
| import sys | |
| import time | |
| from typing import Any, Callable | |
| RELEASE_ROOT = Path(__file__).resolve().parent | |
| RUNTIME_ROOT = RELEASE_ROOT / "runtime" | |
| VENDOR_ROOT = RELEASE_ROOT / "vendor" | |
| DEFAULT_MODEL = str(RELEASE_ROOT) | |
| for import_root in (RUNTIME_ROOT, VENDOR_ROOT): | |
| if str(import_root) not in sys.path: | |
| sys.path.insert(0, str(import_root)) | |
| def utc_now() -> str: | |
| return ( | |
| datetime.now(timezone.utc) | |
| .replace(microsecond=0) | |
| .isoformat() | |
| .replace("+00:00", "Z") | |
| ) | |
| def resolve_model(value: str) -> Path: | |
| candidate = Path(value).expanduser() | |
| if candidate.is_dir(): | |
| return candidate.resolve() | |
| from huggingface_hub import snapshot_download | |
| return Path( | |
| snapshot_download( | |
| repo_id=value, | |
| allow_patterns=[ | |
| "model_index.json", | |
| "transformer/config.json", | |
| "transformer/*.safetensors", | |
| "transformer/*.json", | |
| "text_encoder/*", | |
| "vae/config.json", | |
| "vae/*.safetensors", | |
| "scheduler/*", | |
| ], | |
| ) | |
| ).resolve() | |
| def _repo_subpath(repo_dir: Path, relative: str) -> str: | |
| path = (repo_dir / relative).resolve() | |
| if not path.is_relative_to(repo_dir): | |
| raise ValueError(f"model path escapes its snapshot: {relative}") | |
| return str(path) | |
| def _structure_from_config(transformer_config: dict[str, Any]) -> dict[str, Any]: | |
| metadata_keys = { | |
| "_class_name", | |
| "txt_max_length", | |
| "max_sequence_length", | |
| "param_dtype", | |
| "packing", | |
| "schedule_mode", | |
| "static_shift", | |
| "use_time_shift", | |
| "rope_type", | |
| "apply_text_rotary_emb", | |
| "mlp_ratio", | |
| "depth_single_blocks", | |
| "theta", | |
| "qkv_bias", | |
| "guidance_embed", | |
| "vec_in_dim", | |
| "vec_type", | |
| "time_type", | |
| "double_block_type", | |
| "quantization_config", | |
| } | |
| return { | |
| key: value | |
| for key, value in transformer_config.items() | |
| if key not in metadata_keys | |
| } | |
| def load_pipeline( | |
| *, | |
| model: str, | |
| torch: Any, | |
| ) -> tuple[Any, dict[str, Any]]: | |
| import torch.nn as nn | |
| from diffusers import FlowMatchEulerDiscreteScheduler | |
| from mage_flow.models.mage_flow import MageFlowModel, ModelConfig | |
| from mage_flow.models.modules._attn_backend import set_attn_backend | |
| from mage_flow.pipeline import MageFlowPipeline | |
| from quant_text_encoder import load_quantized_text_encoder | |
| from standard_transformer import load_standard_native_transformer | |
| repo_dir = resolve_model(model) | |
| model_index_path = repo_dir / "model_index.json" | |
| transformer_config_path = repo_dir / "transformer" / "config.json" | |
| model_index = json.loads(model_index_path.read_text(encoding="utf-8")) | |
| transformer_config = json.loads( | |
| transformer_config_path.read_text(encoding="utf-8") | |
| ) | |
| structure = _structure_from_config(transformer_config) | |
| config = ModelConfig( | |
| vae_path=_repo_subpath(repo_dir, model_index["_vae_source"]), | |
| txt_enc_path=_repo_subpath(repo_dir, model_index["_text_encoder_path"]), | |
| model_structure=structure, | |
| txt_max_length=transformer_config.get("txt_max_length", 2048), | |
| packing=transformer_config.get("packing", True), | |
| static_shift=transformer_config.get("static_shift", 6.0), | |
| ) | |
| transformer, access_report = load_standard_native_transformer( | |
| repo_dir, | |
| torch.device("cuda:0"), | |
| ) | |
| model = MageFlowModel.__new__(MageFlowModel) | |
| nn.Module.__init__(model) | |
| model.config = config | |
| set_attn_backend(getattr(config, "attn_type", "flash2")) | |
| model.patch_text_encoder_forward() | |
| model.vae = model.load_vae() | |
| model.transformer = transformer | |
| text_encoder_dir = Path( | |
| _repo_subpath(repo_dir, model_index["_text_encoder_path"]) | |
| ) | |
| model.txt_enc, text_report = load_quantized_text_encoder( | |
| text_encoder_dir=text_encoder_dir, | |
| artifact_path=text_encoder_dir / "model.safetensors", | |
| tokenizer_max_length=config.txt_max_length, | |
| dit_structure=structure, | |
| use_packed_text_infer=config.packing, | |
| ) | |
| model.vae.requires_grad_(False).to(torch.bfloat16) | |
| model.txt_enc.requires_grad_(False) | |
| model.eval() | |
| model.scheduler = FlowMatchEulerDiscreteScheduler.from_pretrained( | |
| _repo_subpath(repo_dir, "scheduler") | |
| ) | |
| return ( | |
| MageFlowPipeline(model, device="cuda:0"), | |
| { | |
| "resolved_model": str(repo_dir), | |
| "transformer_access": access_report, | |
| "text_encoder": text_report, | |
| }, | |
| ) | |
| def stage_to_gpu( | |
| module: Any, | |
| operation: Callable[[], Any], | |
| torch: Any, | |
| ) -> tuple[Any, dict[str, Any]]: | |
| torch.cuda.synchronize() | |
| torch.cuda.reset_peak_memory_stats(0) | |
| started = time.perf_counter() | |
| try: | |
| module.to("cuda:0") | |
| value = operation() | |
| torch.cuda.synchronize() | |
| metrics = { | |
| "peak_allocated_bytes": int(torch.cuda.max_memory_allocated(0)), | |
| "peak_reserved_bytes": int(torch.cuda.max_memory_reserved(0)), | |
| } | |
| finally: | |
| module.to("cpu") | |
| torch.cuda.synchronize() | |
| torch.cuda.empty_cache() | |
| metrics["seconds"] = time.perf_counter() - started | |
| return value, metrics | |
| def generate_staged( | |
| *, | |
| pipe: Any, | |
| prompt: str, | |
| negative_prompt: str, | |
| height: int, | |
| width: int, | |
| steps: int, | |
| cfg: float, | |
| seed: int, | |
| static_shift: float, | |
| torch: Any, | |
| ) -> tuple[Any, dict[str, Any], dict[str, Any]]: | |
| from einops import rearrange | |
| from mage_flow.models.modules.mage_latent import encode_noise, resolve_gs_key | |
| from mage_flow.pipeline import ( | |
| _build_pack_ctx, | |
| _decode_one, | |
| _encode_texts_packed, | |
| _get_scheduler, | |
| _lens_to_cu, | |
| _make_divisible_by_16, | |
| _slice_packed, | |
| _template_info, | |
| _velocity, | |
| ) | |
| model = pipe.model | |
| device = torch.device("cuda:0") | |
| template_info = _template_info("mage-flow") | |
| template = template_info.get("template", "{}") | |
| drop_index = int(template_info.get("start_idx", 0)) | |
| stage_metrics: dict[str, Any] = {} | |
| def encode_text() -> tuple[Any, ...]: | |
| verdict = model.txt_enc.screen_text(prompt) | |
| if verdict.violates: | |
| return (verdict,) | |
| text_flat, vec_all, text_lens = _encode_texts_packed( | |
| model, | |
| [prompt, negative_prompt or " "], | |
| template, | |
| drop_index, | |
| device, | |
| ) | |
| positive = _slice_packed( | |
| text_flat, vec_all, text_lens, 0, 1, device | |
| ) | |
| negative = _slice_packed( | |
| text_flat, vec_all, text_lens, 1, 1, device | |
| ) | |
| return (verdict, *positive, *negative) | |
| encoded, stage_metrics["text_encode"] = stage_to_gpu( | |
| model.txt_enc, | |
| encode_text, | |
| torch, | |
| ) | |
| verdict = encoded[0] | |
| if verdict.violates: | |
| raise RuntimeError( | |
| "prompt was refused by Mage content screening: " | |
| f"{verdict.categories} {verdict.reason}" | |
| ) | |
| ( | |
| _verdict, | |
| txt, | |
| txt_cu, | |
| txt_mask, | |
| vec, | |
| neg_txt, | |
| neg_cu, | |
| neg_mask, | |
| neg_vec, | |
| ) = encoded | |
| height = _make_divisible_by_16(height) | |
| width = _make_divisible_by_16(width) | |
| noise = encode_noise( | |
| ( | |
| model.vae.latent_channels, | |
| (height + 15) // 16, | |
| (width + 15) // 16, | |
| ), | |
| key=resolve_gs_key(None), | |
| seed=seed, | |
| device=device, | |
| dtype=torch.bfloat16, | |
| ) | |
| _, _, grid_h, grid_w = noise.shape | |
| image_latent = rearrange(noise, "b c h w -> b (h w) c") | |
| image_ids = torch.zeros(grid_h, grid_w, 3, device=device) | |
| image_ids[..., 1] += torch.arange(grid_h, device=device)[:, None] | |
| image_ids[..., 2] += torch.arange(grid_w, device=device)[None, :] | |
| image_ids = rearrange(image_ids, "h w c -> 1 (h w) c") | |
| image_lens = [grid_h * grid_w] | |
| image_cu = _lens_to_cu(image_lens, device) | |
| context = _build_pack_ctx( | |
| image_ids, | |
| image_cu, | |
| [[(1, grid_h, grid_w)]], | |
| image_lens, | |
| txt, | |
| txt_cu, | |
| txt_mask, | |
| vec, | |
| neg_txt, | |
| neg_cu, | |
| neg_mask, | |
| neg_vec, | |
| cfg, | |
| False, | |
| True, | |
| device, | |
| ) | |
| def denoise() -> Any: | |
| nonlocal image_latent | |
| scheduler = _get_scheduler( | |
| model, | |
| steps, | |
| device, | |
| static_shift, | |
| ) | |
| for step_index, timestep in enumerate(scheduler.timesteps): | |
| prediction = _velocity( | |
| model.transformer, | |
| image_latent, | |
| context, | |
| scheduler.sigmas[step_index].item(), | |
| ) | |
| image_latent = scheduler.step( | |
| prediction, | |
| timestep, | |
| image_latent, | |
| return_dict=False, | |
| )[0] | |
| if int((~torch.isfinite(image_latent)).sum().item()) != 0: | |
| raise RuntimeError("denoising produced non-finite values") | |
| return image_latent.to("cpu") | |
| latent_cpu, stage_metrics["denoise"] = stage_to_gpu( | |
| model.transformer, | |
| denoise, | |
| torch, | |
| ) | |
| def decode() -> Any: | |
| return _decode_one( | |
| model, | |
| latent_cpu.to(device), | |
| height, | |
| width, | |
| device, | |
| ) | |
| image, stage_metrics["decode"] = stage_to_gpu( | |
| model.vae, | |
| decode, | |
| torch, | |
| ) | |
| screening = { | |
| "violates": bool(verdict.violates), | |
| "categories": list(verdict.categories or []), | |
| "reason": str(verdict.reason), | |
| } | |
| return image, stage_metrics, screening | |
| def parse_args() -> argparse.Namespace: | |
| parser = argparse.ArgumentParser(description=__doc__) | |
| parser.add_argument("--prompt", required=True) | |
| parser.add_argument("--negative-prompt", default="") | |
| parser.add_argument("--output", type=Path, default=Path("mage_nvfp4.png")) | |
| parser.add_argument( | |
| "--model", | |
| default=DEFAULT_MODEL, | |
| help=( | |
| "local standard-layout model directory or Hugging Face repo id " | |
| "(default: this downloaded repository)" | |
| ), | |
| ) | |
| parser.add_argument("--height", type=int, default=1024) | |
| parser.add_argument("--width", type=int, default=1024) | |
| parser.add_argument("--steps", type=int, default=20) | |
| parser.add_argument("--cfg", type=float, default=5.0) | |
| parser.add_argument("--seed", type=int, default=1) | |
| parser.add_argument("--static-shift", type=float, default=6.0) | |
| return parser.parse_args() | |
| def main() -> int: | |
| args = parse_args() | |
| output_path = args.output.expanduser().resolve() | |
| report_path = output_path.with_suffix(output_path.suffix + ".json") | |
| if output_path.exists() or report_path.exists(): | |
| raise SystemExit( | |
| f"refusing to overwrite existing output/report: {output_path}" | |
| ) | |
| output_path.parent.mkdir(parents=True, exist_ok=True) | |
| import torch | |
| from packed_nvfp4_linear import close_all_contexts | |
| from torch_ops_native import ( | |
| close_native_contexts, | |
| initialize_native_sm120_op, | |
| ) | |
| if not torch.cuda.is_available() or torch.cuda.device_count() != 1: | |
| raise SystemExit( | |
| "exactly one visible CUDA GPU is required; set CUDA_VISIBLE_DEVICES" | |
| ) | |
| torch.cuda.set_device(0) | |
| properties = torch.cuda.get_device_properties(0) | |
| if (properties.major, properties.minor) != (12, 0): | |
| raise SystemExit( | |
| f"native NVFP4 requires SM120; found {properties.major}.{properties.minor}" | |
| ) | |
| if not initialize_native_sm120_op(allow_python_schema_fallback=False): | |
| raise SystemExit("the packaged native SM120 torch op did not load") | |
| os.environ.setdefault("CUBLAS_WORKSPACE_CONFIG", ":4096:8") | |
| torch.manual_seed(args.seed) | |
| torch.cuda.manual_seed_all(args.seed) | |
| torch.backends.cudnn.benchmark = False | |
| torch.backends.cudnn.deterministic = True | |
| torch.backends.cuda.matmul.allow_tf32 = False | |
| torch.use_deterministic_algorithms(True) | |
| started = time.perf_counter() | |
| pipe = None | |
| try: | |
| pipe, load_report = load_pipeline( | |
| model=args.model, | |
| torch=torch, | |
| ) | |
| image, stages, screening = generate_staged( | |
| pipe=pipe, | |
| prompt=args.prompt, | |
| negative_prompt=args.negative_prompt, | |
| height=args.height, | |
| width=args.width, | |
| steps=args.steps, | |
| cfg=args.cfg, | |
| seed=args.seed, | |
| static_shift=args.static_shift, | |
| torch=torch, | |
| ) | |
| image.save(output_path) | |
| report = { | |
| "schema_version": "mage-flow-nvfp4-portable-generation-v1", | |
| "status": "success", | |
| "completed_at_utc": utc_now(), | |
| "output": str(output_path), | |
| "prompt": args.prompt, | |
| "negative_prompt": args.negative_prompt, | |
| "height": args.height, | |
| "width": args.width, | |
| "steps": args.steps, | |
| "cfg": args.cfg, | |
| "seed": args.seed, | |
| "elapsed_seconds": time.perf_counter() - started, | |
| "stages": stages, | |
| "screening": screening, | |
| "load": load_report, | |
| "environment": { | |
| "python": platform.python_version(), | |
| "torch": torch.__version__, | |
| "torch_cuda": torch.version.cuda, | |
| "gpu": properties.name, | |
| "compute_capability": ( | |
| f"{properties.major}.{properties.minor}" | |
| ), | |
| }, | |
| } | |
| report_path.write_text( | |
| json.dumps(report, indent=2, sort_keys=True) + "\n", | |
| encoding="utf-8", | |
| ) | |
| print(f"saved {output_path}") | |
| print(f"saved {report_path}") | |
| return 0 | |
| finally: | |
| close_native_contexts() | |
| close_all_contexts() | |
| pipe = None | |
| gc.collect() | |
| if __name__ == "__main__": | |
| raise SystemExit(main()) | |