Skip to content

Add Apple MLX backend for macOS #30

Add Apple MLX backend for macOS

Add Apple MLX backend for macOS #30

Workflow file for this run

name: CI
on:
push:
pull_request:
jobs:
build:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
name: Linux x86_64
backend: tch
libtorch-url: https://download.pytorch.org/libtorch/cpu/libtorch-cxx11-abi-shared-with-deps-2.7.1%2Bcpu.zip
libtorch-archive: libtorch.zip
- os: ubuntu-24.04-arm
name: Linux ARM64
backend: tch
libtorch-url: https://github.com/second-state/libtorch-releases/releases/download/v2.7.1/libtorch-cxx11-abi-aarch64-2.7.1.tar.gz
libtorch-archive: libtorch.tar.gz
- os: macos-latest
name: macOS ARM64 (tch)
backend: tch
libtorch-url: https://download.pytorch.org/libtorch/cpu/libtorch-macos-arm64-2.7.1.zip
libtorch-archive: libtorch.zip
- os: macos-latest
name: macOS ARM64 (mlx)
backend: mlx
runs-on: ${{ matrix.os }}
name: Build (${{ matrix.name }})
steps:
- uses: actions/checkout@v4
if: matrix.backend == 'tch'
- uses: actions/checkout@v4
if: matrix.backend == 'mlx'
with:
submodules: recursive
- name: Install build tools (Linux)
if: runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install -y nasm pkg-config
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ runner.os }}-${{ runner.arch }}-${{ matrix.backend }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-${{ runner.arch }}-${{ matrix.backend }}-cargo-registry-
- name: Download libtorch
if: matrix.backend == 'tch'
run: curl -Lo ${{ matrix.libtorch-archive }} "${{ matrix.libtorch-url }}"
- name: Extract libtorch
if: matrix.backend == 'tch'
run: |
if [[ "${{ matrix.libtorch-archive }}" == *.zip ]]; then
unzip -q ${{ matrix.libtorch-archive }}
else
tar xzf ${{ matrix.libtorch-archive }}
fi
- name: Set linker rpath-link (Linux only)
if: matrix.backend == 'tch' && runner.os == 'Linux'
run: echo "RUSTFLAGS=-C link-arg=-Wl,-rpath-link,${{ github.workspace }}/libtorch/lib" >> "$GITHUB_ENV"
- name: Cap libtorch CPU ISA to AVX2 (x86_64 only)
if: matrix.backend == 'tch' && runner.arch == 'X64'
run: |
echo "DNNL_MAX_CPU_ISA=AVX2" >> "$GITHUB_ENV"
echo "ATEN_CPU_CAPABILITY=avx2" >> "$GITHUB_ENV"
- name: Build (tch)
if: matrix.backend == 'tch'
env:
LIBTORCH: ${{ github.workspace }}/libtorch
LIBTORCH_BYPASS_VERSION_CHECK: "1"
run: cargo build --release --features build-ffmpeg
- name: Build (mlx)
if: matrix.backend == 'mlx'
run: cargo build --release --no-default-features --features mlx,build-ffmpeg
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install HuggingFace tools
run: pip install huggingface_hub transformers
- name: Set library path (Linux)
if: matrix.backend == 'tch' && runner.os == 'Linux'
run: echo "LD_LIBRARY_PATH=${{ github.workspace }}/libtorch/lib:$LD_LIBRARY_PATH" >> "$GITHUB_ENV"
- name: Set library path (macOS)
if: matrix.backend == 'tch' && runner.os == 'macOS'
run: echo "DYLD_LIBRARY_PATH=${{ github.workspace }}/libtorch/lib:$DYLD_LIBRARY_PATH" >> "$GITHUB_ENV"
- name: Cache 0.6B model weights
uses: actions/cache@v4
with:
path: Qwen3-ASR-0.6B
key: qwen3-asr-0.6b-v1
- name: Download 0.6B model
run: python3 -c "from huggingface_hub import snapshot_download; snapshot_download('Qwen/Qwen3-ASR-0.6B', local_dir='Qwen3-ASR-0.6B')"
- name: Generate 0.6B tokenizer.json
run: |
python3 -c "
from transformers import AutoTokenizer
tok = AutoTokenizer.from_pretrained('Qwen3-ASR-0.6B', trust_remote_code=True)
tok.backend_tokenizer.save('Qwen3-ASR-0.6B/tokenizer.json')
print('Saved tokenizer.json')
"
- name: "[0.6B] Transcribe sample1 (English)"
run: ./target/release/asr Qwen3-ASR-0.6B test_audio/sample1.wav
- name: "[0.6B] Transcribe sample2 (English)"
run: ./target/release/asr Qwen3-ASR-0.6B test_audio/sample2.wav
- name: "[0.6B] Transcribe sample3 (Chinese)"
run: ./target/release/asr Qwen3-ASR-0.6B test_audio/sample3.wav
- name: Cache 1.7B model weights
uses: actions/cache@v4
with:
path: Qwen3-ASR-1.7B
key: qwen3-asr-1.7b-v1
- name: Download 1.7B model
run: python3 -c "from huggingface_hub import snapshot_download; snapshot_download('Qwen/Qwen3-ASR-1.7B', local_dir='Qwen3-ASR-1.7B')"
- name: Generate 1.7B tokenizer.json
run: |
python3 -c "
from transformers import AutoTokenizer
tok = AutoTokenizer.from_pretrained('Qwen3-ASR-1.7B', trust_remote_code=True)
tok.backend_tokenizer.save('Qwen3-ASR-1.7B/tokenizer.json')
print('Saved tokenizer.json')
"
- name: "[1.7B] Transcribe sample1 (English)"
run: ./target/release/asr Qwen3-ASR-1.7B test_audio/sample1.wav
- name: "[1.7B] Transcribe sample2 (English)"
run: ./target/release/asr Qwen3-ASR-1.7B test_audio/sample2.wav
- name: "[1.7B] Transcribe sample3 (Chinese)"
run: ./target/release/asr Qwen3-ASR-1.7B test_audio/sample3.wav
- name: Upload binary
uses: actions/upload-artifact@v4
with:
name: qwen3-asr-${{ matrix.os }}-${{ runner.arch }}-${{ matrix.backend }}.zip
path: target/release/asr