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
File size: 4,922 Bytes
be2c293 | 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 | #!/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()
|