Text-to-Image
MLX
MiniMax H3
Safetensors
English
apple-silicon
macos
image-to-image
image-editing
image-generation
Instructions to use devin-lai/MiniMax-H3-Image-mlx with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- MLX
How to use devin-lai/MiniMax-H3-Image-mlx with MLX:
# Download the model from the Hub pip install huggingface_hub[hf_xet] hf download devin-lai/MiniMax-H3-Image-mlx --local-dir MiniMax-H3-Image-mlx
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- LM Studio
- Atomic Chat
Download experiments/run_suite.py from devin-lai/MiniMax-H3-Image-mlx: direct link, hf CLI and curl.
- Browser
- Download file 4.39 kB
-
https://huggingface.co/devin-lai/MiniMax-H3-Image-mlx/resolve/main/experiments/run_suite.py
- Command line
-
hf download hf://devin-lai/MiniMax-H3-Image-mlx/experiments/run_suite.py
-
curl -L -o run_suite.py https://huggingface.co/devin-lai/MiniMax-H3-Image-mlx/resolve/main/experiments/run_suite.py
4.39 kB
| """Matched image and performance trials. Run from the repository root.""" | |
| from __future__ import annotations | |
| import argparse | |
| import gc | |
| import json | |
| import logging | |
| import statistics | |
| from pathlib import Path | |
| from h3_mlx.runtime import Pipeline | |
| PROFILES = { | |
| "native": {}, | |
| "fused": {"mlp_chunk": 0, "kernel": "metal-qk", "threads": 256, "vae_batch": 8}, | |
| "chunked": {"mlp_chunk": 1024}, | |
| "wide-mlp": {"mlp_chunk": 0}, | |
| "tuned": {"mlp_chunk": 0, "kernel": "metal", "threads": 256, "vae_batch": 8}, | |
| "q8": {"bits": 8, "mlp_chunk": 0, "vae_batch": 8}, | |
| "q4": {"bits": 4, "mlp_chunk": 0, "vae_batch": 8}, | |
| "q8-g32": {"bits": 8, "group_size": 32, "mlp_chunk": 0, "vae_batch": 8}, | |
| "preview": {"mlp_chunk": 0, "kernel": "metal", "threads": 256, "vae_batch": 8}, | |
| "stream": {"dit_cache_gb": 0}, | |
| } | |
| def main(): | |
| p = argparse.ArgumentParser(description=__doc__) | |
| p.add_argument("--model", required=True) | |
| p.add_argument("--text-encoder", required=True) | |
| p.add_argument( | |
| "--profiles", | |
| nargs="+", | |
| choices=PROFILES, | |
| default=["native", "tuned", "q8", "q4", "preview"], | |
| ) | |
| p.add_argument("--cases", nargs="+", default=["product", "portrait"]) | |
| p.add_argument("--case-file", default="experiments/cases.json") | |
| p.add_argument("--output", default="outputs/suite") | |
| p.add_argument( | |
| "--repeat", | |
| type=int, | |
| default=2, | |
| help="First trial includes model loading; later trials reuse resident models", | |
| ) | |
| p.add_argument("--save-trace", action="store_true") | |
| a = p.parse_args() | |
| if a.repeat < 1: | |
| p.error("repeat must be positive") | |
| logging.basicConfig( | |
| level=logging.INFO, format="%(asctime)s %(message)s", datefmt="%H:%M:%S" | |
| ) | |
| cases = [c for c in json.loads(Path(a.case_file).read_text()) if c["id"] in a.cases] | |
| if {c["id"] for c in cases} != set(a.cases): | |
| p.error("Requested case not found in case file") | |
| root = Path(a.output) | |
| root.mkdir(parents=True, exist_ok=True) | |
| ledger = root / "trials.jsonl" | |
| for name in a.profiles: | |
| logging.info("PROFILE %s", name) | |
| pipeline = Pipeline(a.model, a.text_encoder, **PROFILES[name]) | |
| try: | |
| for c in cases: | |
| for trial in range(a.repeat): | |
| output = root / c["id"] / f"{name}-{trial}.png" | |
| _, row = pipeline.generate( | |
| c["prompt"], | |
| width=c["width"], | |
| height=c["height"], | |
| seed=c["seed"], | |
| output=output, | |
| steps=[0, 2, 4] if name == "preview" else None, | |
| save_trace=a.save_trace, | |
| images=c.get("images", ()), | |
| ) | |
| row.update( | |
| profile=name, | |
| case=c["id"], | |
| trial=trial, | |
| sample_type="resident" | |
| if row["dit_was_resident"] | |
| else "load_included", | |
| ) | |
| with ledger.open("a") as h: | |
| h.write(json.dumps(row) + "\n") | |
| finally: | |
| pipeline.clear() | |
| del pipeline | |
| gc.collect() | |
| rows = [json.loads(line) for line in ledger.read_text().splitlines()] | |
| summary = [] | |
| for profile in a.profiles: | |
| for case in a.cases: | |
| group = [r for r in rows if r["profile"] == profile and r["case"] == case] | |
| resident = [ | |
| r["timings"]["total_s"] for r in group if r["sample_type"] == "resident" | |
| ] | |
| summary.append( | |
| { | |
| "profile": profile, | |
| "case": case, | |
| "samples": len(group), | |
| "resident_samples": len(resident), | |
| "resident_median_s": statistics.median(resident) | |
| if resident | |
| else None, | |
| "load_included_s": [ | |
| r["timings"]["total_s"] | |
| for r in group | |
| if r["sample_type"] == "load_included" | |
| ], | |
| } | |
| ) | |
| (root / "summary.json").write_text(json.dumps(summary, indent=2) + "\n") | |
| if __name__ == "__main__": | |
| main() | |