Skip to main content

gguf2mlx — convert GGUF to MLX without guessing

PyPI CI Python 3.10+ License: Apache-2.0

GGUF → HF-style safetensors that MLX-LM and mlx-vlm can load. Explicit architecture contracts, no silent precision downgrade, fail-closed when a layout is not supported.

Quick start · Supported models · Vision · Docs


Why this exists

GGUF is a distribution format; MLX-LM and mlx-vlm expect a Hugging Face-style directory with config.json, tokenizer assets and safetensors weights. gguf2mlx bridges that gap for explicitly supported architectures by reading GGUF metadata and tensors, rebuilding the MLX-compatible layout, and failing closed when a model layout is not actually supported — no silent "Llama fallback".

Use it when a model ships GGUF but no MLX checkpoint, or when you need an inspectable HF-style directory on an M1–M4 Mac. If the original Hugging Face weights are available, prefer mlx_lm.convert — it avoids inheriting the source GGUF's quantization error.

Conversion itself only needs numpy, gguf and safetensors, so it runs fine on Linux servers and CI; MLX is required only for --quantize.

Important: the default output is FP16/BF16 safetensors. --quantize re-quantizes from that FP16 copy. To keep the bytes that are already in the GGUF, use --quant-source preserve, which re-expresses the source blocks as MLX affine weights for llama, qwen2, qwen3 and mistral (see Preserve GGUF quantization).

Install

pip install gguf2mlx            # installs MLX + MLX-LM on Apple Silicon
pipx install gguf2mlx           # isolated CLI
uv tool install gguf2mlx        # or with uv

Extras: [vlm]/[publish] add Hugging Face Hub, [all] everything, [dev] the test/lint toolchain.

Quick start

# GGUF -> FP16 MLX-LM directory
gguf2mlx --input model.gguf --output ./mlx-model

# GGUF -> 4-bit MLX-LM output
gguf2mlx --input model-Q4_K_M.gguf --output ./mlx-model-4bit \
  --quantize --q-bits 4 --q-group-size 64

# Bounded-memory direct quantization (no FP16 staging directory)
gguf2mlx --input model-Q4_K_M.gguf --output ./mlx-model-4bit \
  --quantize --direct-quant --q-bits 4 --q-group-size 64 --q-mode affine

# Reuse the GGUF blocks instead of quantizing the FP16 copy again
gguf2mlx convert --input model-Q4_K_M.gguf --output ./mlx-model-preserved \
  --quant-source preserve

# Inspect metadata without writing weights
gguf2mlx --input model.gguf --skip-weights

# Smaller shards (payload bytes, not source bytes)
gguf2mlx --input model.gguf --output ./mlx-model --max-shard-gb 2

# Package / verify a directory as a .mlx bundle
gguf2mlx package --model-dir ./mlx-model --output ./mlx-model.mlx
gguf2mlx verify --bundle ./mlx-model.mlx

Load the result:

from mlx_lm import load, generate
model, tok = load("./mlx-model")
print(generate(model, tok, prompt="Hello from MLX", max_tokens=32))

See How conversion works for streaming, sharding and offline tokenizer reconstruction.

Is the output trustworthy?

Every conversion writes conversion_report.json and gates on weight fidelity: each written tensor is compared position-wise against an independent decode of the source GGUF, with a per-dtype relative-L2 tolerance. Fused or permuted tensors are reported as transformed rather than silently counted as verified.

# Re-audit an existing artifact against the GGUF it came from
gguf2mlx verify --model-dir ./mlx-model --weights --source model.gguf

# Load it with mlx_lm and require finite logits from one forward pass
gguf2mlx verify --model-dir ./mlx-model --load

# Skip the (roughly 2x) audit cost
gguf2mlx convert --input model.gguf --output ./mlx-model --no-weight-audit

Perplexity is recorded but never gated: cross-runtime PPL mixes quantization noise with conversion error, so it cannot prove a converter correct. Nightly, the pinned load matrix converts real GGUF models and proves each one loads and runs.

Preserve GGUF quantization

--quant-source preserve re-expresses the GGUF blocks that are already there as MLX affine groups (w = scale * code + bias) on the 32-value group grid the blocks use, instead of decoding to FP16 and quantizing again. The integer codes are kept; only the fp16 rounding of the scale and bias is new. Measured against gguf.quants.dequantize, per-tensor relative L2 is 2.0-2.4e-4 for Q4_K, 0.0 (bit-exact) for Q8_0, and 2.2e-4 for Q6_K when a 32-value group's two 16-value sub-block scales agree.

Q6_K has a structural limit: its sub-block scales are 16 values wide, so when they disagree inside a 32-value group it cannot be represented exactly. Those tensors are flagged exact: false and kept in FP16 rather than silently requantized, and conversion_report.json records the decision plus per-tensor max abs error, relative L2 and an aggregate 1e-3 gate. Modules end up with mixed 4/6/8-bit widths, which mlx-lm loads via per-module quantization entries.

Preserve fails closed: llama, qwen2, qwen3 and mistral are supported, and any other architecture errors out naming the arch instead of falling back to requantization. --preserve-source-quant still works as a deprecated alias.

gguf2mlx convert --input model-Q8_0.gguf --output ./mlx-model-q8 --quant-source preserve

Publish to the Hugging Face Hub

gguf2mlx publish downloads a hosted GGUF, converts it, and uploads the result with a provenance record and the source license files. Split GGUFs are merged; a partial shard set is rejected before anything is downloaded, and the destination repository is only created once conversion produced weights.

pip install "gguf2mlx[publish]"
gguf2mlx publish --source bartowski/Model-GGUF --gguf Model-Q8_0.gguf \
  --dest my-org/Model-MLX --source-revision main
# add --quantize --q-bits 4 --q-group-size 64 for affine 4-bit (needs MLX)

The reusable publish-mlx.yml workflow is a thin shell around the same module: float16 runs on ubuntu-latest, and only quantize: true needs a macOS Apple Silicon runner. Details: Publishing.

Supported models

Conversion is adapter-based, not "any GGUF". Rows marked ⚠️ convert but still need opt-in real-checkpoint validation.

Family GGUF architecture IDs Convert End-to-end evidence
Llama llama, mistral ✅ + preserve synthetic direct-quant; SmolLM2-135M HF parity
Qwen qwen2, dense qwen3 ✅ + preserve synthetic direct-quant
Qwen3.5 family qwen35 + aliases ✅ portable fixtures
Qwen MoE qwen2moe, qwen3moe ✅ real GGUF: Qwen1.5-MoE, Qwen3-30B-A3B
DeepSeek deepseek2, deepseek3 ✅ real GGUF: V2 Lite Q2_K
GLM glm4moe, glm-dsa ✅ / ⚠️ experimental none
Gemma gemma, gemma2, gemma3, text gemma4 ✅ portable fixtures
Phi phi3 (Phi-3, Phi-4) ✅ synthetic GGUF
StableLM stablelm ✅ none
LLaVA / Qwen2-VL / MiniCPM-V mmproj pairs ✅ Qwen2-VL-2B real-image acceptance

preserve in the Convert column means --quant-source preserve is available (Q4_K, Q6_K, Q8_0). Other architectures convert, but must requantize.

Inspection-only (recognized via metadata, rejected on conversion): arctic, bert, bitnet, bloom, dbrx, falcon, gpt2, gptneox, mpt, olmo, phi, phi2, t5 and others — full list in the support matrix.

Vision-language models

Three explicit adapters emit directories for mlx-vlm: LLaVA-1.5, Qwen2-VL, and MiniCPM-V 4.7 1B. Language weights and the projector come from GGUF; hybrid mode takes only the vision tower from a matching HF checkpoint. Qwen2.5-VL, Qwen3-VL full VLM, LLaVA-NeXT and SigLIP layouts are not supported by these adapters.

pip install "gguf2mlx[vlm]"
gguf2mlx convert --type vlm \
  --input qwen2-vl.gguf --mmproj qwen2-vl-mmproj.gguf \
  --hf-model Qwen/Qwen2-VL-2B-Instruct --output ./qwen2-vl-mlx

Flags, hybrid/offline paths, quantization policy and the Q4_K --preserve-source-quant mode: VLM conversion. Native acceptance results: Qwen2-VL report.

Qwen3-VL text-only extraction is a separate --type text-encoder contract (BF16 by default, mRoPE preserved, vision tensors skipped): see text conditioning.

Limits worth knowing before you start

  • --quantize is a second quantization. Use --quant-source preserve to keep the original blocks; for Q6_K tensors whose sub-block scales disagree, that still means FP16.
  • Conversion cannot restore precision lost in the source GGUF.
  • Tokenizer fidelity depends on GGUF metadata; embedded HF tokenizer JSON is preserved when present, otherwise reconstructed from the header.
  • Mixed-precision MoE output is experimental and needs a JANG-compatible runtime; use uniform output when interoperability is unverified.
  • No universal speed claim versus llama.cpp — measure on your hardware.

Documentation

Quality gates · Support matrix · How conversion works · VLM conversion · Text conditioning · Publishing · .mlx bundles · Capabilities · Benchmarks · FAQ · Roadmap · Validation logs · Development

Development

git clone https://github.com/barrontang/gguf2mlx.git && cd gguf2mlx
uv sync --all-extras
pytest -q                                   # portable suite
GGUF2MLX_RUN_E2E=1 pytest tests/test_e2e.py # Apple Silicon, real GGUF
ruff check src/ tests/ benchmarks/

CI runs Python 3.10/3.12/3.13 with an 80% coverage floor; a separate macOS workflow runs the native VLM suites. Details and opt-in fixture paths are in Development.

Contributing

New architecture adapters must ship with a tensor manifest and a load test. When requesting a family, include the exact GGUF architecture, model name, quantization type, tokenizer type, and a public fixture URL.

License

Apache-2.0. The traffic-tracking dashboard that used to live here was GPL-3.0 and now lives in its own repository.

Metadata

Release files for gguf2mlx 2.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for gguf2mlx 2.2.0
File Size Uploaded Provenance
gguf2mlx-2.2.0.tar.gz 240.0 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for gguf2mlx 2.2.0
File Interpreter ABI Platform
gguf2mlx-2.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 344.4 kB

Release files / gguf2mlx-2.2.0.tar.gz

Download URL gguf2mlx-2.2.0.tar.gz
Size 240.0 kB
Tags Source
SHA-256 checksum
How to use checksums
404401b5ff8f7df86a8eeb1b2420b7fc2fc536c28a9ccc7e741f30a4e406c173
BLAKE2b-256 checksum
How to use checksums
ee5cfeaebcb16548280a321381485b627e616499f6b6ef013b1ac580b398666b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 21, 2026.

Transparency log

Release files / gguf2mlx-2.2.0-py3-none-any.whl

Download URL gguf2mlx-2.2.0-py3-none-any.whl
Size 104.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6ba5081229e7b33e182737ee9679a08e65c26190db3e14617db4d4ce45d6e475
BLAKE2b-256 checksum
How to use checksums
c6fcfdac4462f654d5b0cdab69914a01f24cf5e191e66e406e9c1e1320e7728e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 21, 2026.

Transparency log

Security for gguf2mlx 2.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for gguf2mlx-2.2.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 21, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page