MLX-native speaker embedding model for Apple Silicon, converted from
Wespeaker/wespeaker-voxceleb-resnet34-LM.
The existing
mlx-community conversion has
two bugs that produce incorrect embeddings (cosine similarity ≈ 0 vs ONNX reference):
-
Conv2d bias: MLX nn.Conv2d defaults to bias=True, but WeSpeaker uses bias=False (standard ResNet with BatchNorm). This creates 36 extra uninitialized parameters.
-
Pooling dimension ordering (critical): The TSTP pooling flattens in the wrong order. PyTorch flattens as (C, F') but the MLX version flattens as (F', C). Both produce shape (B, 5120) — the FC layer accepts it without error — but the values are scrambled.
This conversion fixes both issues and is verified against the ONNX reference.
Tested on 4 speakers from a 93-minute Chinese business meeting.
1import mlx.core as mx
2import numpy as np
3from resnet_embedding import ResNet34Embedding
4
5# Load model
6model = ResNet34Embedding()
7weights = np.load("weights.npz")
8for key in weights.files:
9 path = key.split(".")
10 module = model
11 for attr in path[:-1]:
12 if attr.isdigit():
13 module = module[int(attr)]
14 elif attr == "layers":
15 module = module.layers
16 else:
17 module = getattr(module, attr)
18 setattr(module, path[-1], mx.array(weights[key]))
19model.eval()
20
21# Extract embedding from fbank features (T, 80)
22embedding = model(mx.array(fbank[np.newaxis, :, :])) # → (1, 256)
Converted directly from the
official PyTorch weights using
convert.py:
1pip install torch numpy huggingface_hub
2python convert.py --model Wespeaker/wespeaker-voxceleb-resnet34-LM --output weights.npz
Apache 2.0 (same as the original WeSpeaker model).
1@inproceedings{wang2023wespeaker,
2 title={Wespeaker: A research and production oriented speaker embedding learning toolkit},
3 author={Wang, Hongji and Liang, Chengdong and Wang, Shuai and Chen, Zhengyang and Zhang, Binbin and Xiang, Xu and Deng, Yanlei and Qian, Yanmin},
4 booktitle={ICASSP 2023},
5 year={2023}
6}