Skip to content

Add MLX / Apple Silicon (MPS) backend support#345

Open
walkoncross wants to merge 4 commits into
QwenLM:mainfrom
walkoncross:feature/mlx
Open

Add MLX / Apple Silicon (MPS) backend support#345
walkoncross wants to merge 4 commits into
QwenLM:mainfrom
walkoncross:feature/mlx

Conversation

@walkoncross

Copy link
Copy Markdown

What & Why

Enables running Qwen3-TTS on Apple Silicon (and CPU) out of the box. Previously the examples and CLI hard-coded cuda:0 + flash_attention_2, so they could not run on machines without CUDA.

Changes

  • qwen_tts/inference/backend_utils.py (new) — unified device/dtype/attn resolver:
    • default_device() auto-detects cuda → Apple Silicon mpscpu
    • mlx / auto / mps aliases route to the best locally available backend
    • bfloat16 auto-falls back to float16 on MPS; flash_attention_2 auto-disabled off-CUDA
    • synchronize_device() wraps CUDA/MPS sync
  • from_pretrained (model + tokenizer) and cli/demo.py route through the resolver; CLI --device now auto-detects.
  • examples/*.py — drop hard-coded cuda:0 / torch.cuda.synchronize(); unify audio output under outputs/<script-name>/.
  • README — manual-download --local_dir commands now keep the Qwen/ prefix so the downloaded layout matches the default Qwen/<model-name> paths in the scripts.

Scripts keep the Qwen/<model-name> repo-id form, so from_pretrained auto-download on cache miss is preserved.

Verification

Ran on Apple Silicon (torch 2.12, MPS, no CUDA) — all four example scripts exit 0:

  • test_tokenizer_12hz.py, test_model_12hz_base.py (12/12 cases), test_model_12hz_custom_voice.py, test_model_12hz_voice_design.py

Not tested on CUDA hardware — the CUDA path is unchanged by design (resolver is a no-op when CUDA is available), but a maintainer sanity-check on a GPU box is welcome.

- 新增 backend_utils 统一解析设备/dtype/attn:mlx 与 auto 自动映射到
  本机可用后端(Apple Silicon 落到 mps,无则 cpu)
- mps 上 bfloat16 自动降级为 float16,非 CUDA 下自动关闭 flash_attention_2
- from_pretrained(模型/tokenizer) 与 demo CLI 走统一解析,默认设备自动探测
- examples 去除写死的 cuda:0 与 torch.cuda.synchronize,改用跨后端同步
- gitignore 忽略本地模型目录产出的音频

验收:examples/test_model_12hz_base.py 在 mps 上 12 个 case 全部跑通
上次批量替换漏掉了 batch 段(后跟空行而非 t1)的 torch.cuda.synchronize,
在无 CUDA 的 mps 环境会抛 AssertionError。改为跨后端的 synchronize_device。

验收:四个 example 脚本在 mps 上均已实测通过(rc=0)
- 四个 example 脚本的音频输出统一到 outputs/<脚本名>/,目录名由
  __file__ 自动派生,脚本与输出目录一一对应
- 之前 base 用独立长目录名、其余三个直接写仓库根目录,不统一
- gitignore 旧输出目录规则替换为 outputs/

验收:四个脚本在 mps 上均 rc=0,产物落到各自 outputs 子目录
(base 20 / custom 3 / design 3 / tokenizer 9)
- README 手动下载命令原本存到裸 ./<模型名>/,与 examples/finetuning
  脚本里的 Qwen/<模型名> 加载路径对不上,照文档下载后需手动改路径
- 12 条 modelscope/huggingface-cli 命令统一改为 ./Qwen/<模型名>/
- 补充说明:从仓库根目录运行时脚本可直接读到本地权重,无需改路径
- 脚本保持 Qwen/<模型名> repo id 双关写法,不影响缺失时自动下载
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant