speakerkit-coreml β fp16-safe CoreML conversions for speaker diarization
CoreML conversions of the pyannote community-1 diarization pipeline's neural components, re-converted with fp16-survivable numerical guards so they are correct on the Apple Neural Engine and GPU β not just CPU.
Consumed by the speakerkit crate of the coremlit
workspace (Rust, sync, sans-I/O), feeding the dia diarization pipeline's clustering.
Why these conversions exist
Stock conversions of these models carry numerical guard epsilons below fp16's smallest
subnormal (2^-24). When a graph runs on the ANE (which computes in fp16 regardless of
the declared dtype), those guards round to zero:
- the segmentation model's
softmax β log(epsβ0)tail saturateslog(0)to β β45440, which in the downstream pipeline collapsed an 8-speaker recording to 5 detected speakers (16.6% DER, 100% confusion) while the ONNX reference was frame-perfect; - the embedder's pooling
real_divguards (1e-8) vanish the same way.
Even a naive re-export reproduces the defect: torch.log_softmax still lowers to the
decomposed softmax β log(eps=0) under coremltools 9.0. These conversions use an
explicitly fused x β logsumexp(x) tail and raise every guard constant to 0x1p-24.
Contents
| artifact | form | what it is |
|---|---|---|
pyannote_segmentation.{mlpackage,mlmodelc} |
fp16 | pyannote segmentation-3.0 (PyanNet), fused log-probability tail |
wespeaker.{mlpackage,mlmodelc} |
fp32 weights | WeSpeaker ResNet34-LM speaker embedder, pooling guards raised to 0x1p-24 (otherwise bit-identical numerics to the stock conversion) |
wespeaker_int8.{mlpackage,mlmodelc} |
8-bit palettized | same fixed embedder, k-means per-tensor palettization (~3.7Γ smaller, the production default) |
.mlpackage is the canonical distributable; .mlmodelc is the compiled form the test
suite consumes directly. CHECKSUMS.sha256 covers every file.
Verification (summary)
- Every graph passes a MIL-level fp16-guard audit (every guard's effective floor
β₯
2^-24, constants followed throughcast, unresolvable guards fail the audit). - Segmentation: worst per-window delta vs the ONNX oracle dropped from 45,422 β 0.07 (ANE), argmax agreement 100%; the 8-speaker collapse is fixed at model level.
- Embedder: All-vs-CPU cosine 1.0 on real speech; int8 clusters identically to fp32 on the multi-speaker parity corpus (speaker counts never differ).
- Conversion toolchain pinned in the recipe: coremltools 9.0, torch 2.5.1, onnx 1.22.0, python 3.11.15.
Upstream provenance & licensing
| component | upstream | license |
|---|---|---|
| segmentation | pyannote/segmentation-3.0 (weights via its ONNX export) | MIT (upstream repo is access-gated; the MIT license permits redistribution with attribution β please also respect pyannote's usage conditions and cite their papers) |
| embedder | WeSpeaker ResNet34-LM (voxceleb) | Apache-2.0 (WeSpeaker project) |
These are derivative conversions: same weights, corrected graph numerics. If you are the upstream author of either model and want changes to this redistribution, open a discussion.
- Downloads last month
- 16