Instructions to use Dirdx/YuE2-3B-MLX-with-Hum-encoder with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- MLX
How to use Dirdx/YuE2-3B-MLX-with-Hum-encoder with MLX:
# Download the model from the Hub pip install huggingface_hub[hf_xet] hf download Dirdx/YuE2-3B-MLX-with-Hum-encoder --local-dir YuE2-3B-MLX-with-Hum-encoder
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- LM Studio
- Atomic Chat
Download convert.py from Dirdx/YuE2-3B-MLX-with-Hum-encoder: direct link, hf CLI and curl.
- Browser
- Download file 4.92 kB
-
https://huggingface.co/Dirdx/YuE2-3B-MLX-with-Hum-encoder/resolve/main/convert.py
- Command line
-
hf download hf://Dirdx/YuE2-3B-MLX-with-Hum-encoder/convert.py
-
curl -L -o convert.py https://huggingface.co/Dirdx/YuE2-3B-MLX-with-Hum-encoder/resolve/main/convert.py
4.92 kB
| #!/usr/bin/env python3 | |
| """Convert m-a-p/YuE2-3B + m-a-p/YuE2-Vae into an MLX package directory. | |
| Output layout (HF-uploadable): | |
| model.safetensors bf16 backbone, or affine-quantized Linear layers (--quantize) | |
| vae.safetensors f32 Oobleck decoder, weight norm folded, MLX conv layout | |
| config.json, vae_config.json, qwen.tiktoken, yue2_generation_config.json | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import json | |
| import re | |
| import shutil | |
| from pathlib import Path | |
| import mlx.core as mx | |
| import mlx.nn as nn | |
| from mlx.utils import tree_flatten | |
| from yue2_model import Yue2Model | |
| TIME_EMBEDDER = {"time_embedder.mlp.0.": "time_embedder.fc1.", "time_embedder.mlp.2.": "time_embedder.fc2."} | |
| CONV_TRANSPOSE = re.compile(r"^layers\.\d+\.layers\.1\.weight_v$") | |
| def resolve(repo_or_dir: str, patterns: list[str]) -> Path: | |
| if Path(repo_or_dir).is_dir(): | |
| return Path(repo_or_dir) | |
| from huggingface_hub import snapshot_download | |
| return Path(snapshot_download(repo_or_dir, allow_patterns=patterns)) | |
| def rename(key: str) -> str: | |
| for old, new in TIME_EMBEDDER.items(): | |
| if key.startswith(old): | |
| return new + key[len(old):] | |
| return key | |
| def fold_weight_norm(weights: dict) -> dict: | |
| """decoder.* (g, v) pairs → single MLX-layout conv weights.""" | |
| out = {} | |
| for key, value in weights.items(): | |
| if not key.startswith("decoder.") or key.endswith("weight_g"): | |
| continue | |
| key = key[len("decoder."):] | |
| if key.endswith("weight_v"): | |
| g = weights["decoder." + key[:-1] + "g"] | |
| norm = mx.sqrt(mx.sum(value.astype(mx.float32) ** 2, axis=(1, 2), keepdims=True)) | |
| w = g * value / norm | |
| # torch Conv1d [out,in,k] → mlx [out,k,in]; ConvTranspose1d [in,out,k] → mlx [out,k,in] | |
| w = w.transpose(1, 2, 0) if CONV_TRANSPOSE.match(key) else w.transpose(0, 2, 1) | |
| out[key[:-2]] = w | |
| else: | |
| out[key] = value | |
| return out | |
| def main() -> None: | |
| parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) | |
| parser.add_argument("--model", default="m-a-p/YuE2-3B", help="HF repo id or local snapshot dir") | |
| parser.add_argument("--vae", default="m-a-p/YuE2-Vae", help="HF repo id or local snapshot dir") | |
| parser.add_argument("--output", type=Path, default=Path.home() / "Desktop" / "Yue2-3B-MLX") | |
| parser.add_argument("-q", "--quantize", action="store_true", help="affine-quantize backbone Linear layers") | |
| parser.add_argument("--bits", type=int, default=8, choices=[4, 8]) | |
| parser.add_argument("--group-size", type=int, default=64) | |
| parser.add_argument("--nar-bits", type=int, choices=[4, 8], help="bits for the NAR path (nar_self_attn/nar_mlp); default 8 (flow matching degrades at 4 bits)") | |
| parser.add_argument("--overwrite", action="store_true") | |
| args = parser.parse_args() | |
| if args.output.exists(): | |
| if not args.overwrite: | |
| raise SystemExit(f"{args.output} exists; pass --overwrite") | |
| shutil.rmtree(args.output) | |
| args.output.mkdir(parents=True) | |
| model_dir = resolve(args.model, ["model.safetensors", "config.json", "qwen.tiktoken", "yue2_generation_config.json"]) | |
| vae_dir = resolve(args.vae, ["model.safetensors", "config.json"]) | |
| cfg = json.loads((model_dir / "config.json").read_text()) | |
| weights = {rename(k): v for k, v in mx.load(str(model_dir / "model.safetensors")).items()} | |
| if args.quantize: | |
| model = Yue2Model(cfg) | |
| model.load_weights(list(weights.items())) | |
| nar_bits = args.nar_bits or 8 | |
| def predicate(path, module): | |
| if not isinstance(module, nn.Linear) or not (path.startswith("model.layers") or path == "lm_head"): | |
| return False | |
| return {"group_size": args.group_size, "bits": nar_bits if ".nar_" in path else args.bits} | |
| nn.quantize(model, args.group_size, args.bits, class_predicate=predicate) | |
| weights = dict(tree_flatten(model.parameters())) | |
| cfg["quantization"] = {"group_size": args.group_size, "bits": args.bits, "nar_bits": nar_bits, "mode": "affine"} | |
| print(f"[write] model.safetensors ({len(weights)} tensors)", flush=True) | |
| mx.save_safetensors(str(args.output / "model.safetensors"), weights, metadata={"format": "mlx"}) | |
| (args.output / "config.json").write_text(json.dumps(cfg, indent=2) + "\n") | |
| vae = fold_weight_norm(mx.load(str(vae_dir / "model.safetensors"))) | |
| print(f"[write] vae.safetensors ({len(vae)} tensors)", flush=True) | |
| mx.save_safetensors(str(args.output / "vae.safetensors"), vae, metadata={"format": "mlx"}) | |
| shutil.copy2(vae_dir / "config.json", args.output / "vae_config.json") | |
| for name in ("qwen.tiktoken", "yue2_generation_config.json"): | |
| shutil.copy2(model_dir / name, args.output / name) | |
| print(f"[done] {args.output}") | |
| if __name__ == "__main__": | |
| main() | |