SAR Strikes Back: A New Hope for RSVQA
Paper β’ 2501.08131 β’ Published
How to use DimQ1/sortformer-4spk-v2-onnx-fp32-cpu with NeMo:
# tag did not correspond to a valid NeMo domain.
FP32 ONNX export of NVIDIA's Sortformer 4spk-v2 speaker diarization model for CPU inference via ONNX Runtime.
processed_signal β log-mel spectrogram [B, 128, mel_frames]speaker_logits β per-frame sigmoid probabilities [B, diar_frames, 4]Audio (16 kHz mono) β STFT β 128 mel bins
β ConformerEncoder (17 layers, d=512)
β SortformerModules (4 speakers)
β TransformerEncoder (18 layers, d=192)
β Sigmoid β [B, diar_frames, 4] speaker logits
| Metric | Value |
|---|---|
| RTF | 0.037 (27Γ real-time) |
| DER | 17.82% (LibriCSS test set) |
| Size | 469 MB |
Benchmarked on 100-file LibriCSS subset (1954.8 s audio). ORT 1.27.1 with ORT_PARALLEL + memory optimizations.
| Variant | Size | DER | RTF | Link |
|---|---|---|---|---|
| INT8 | 129 MB | 21.64% | 0.034 | sortformer-4spk-v2-onnx-int8-cpu |
| INT4 | 135 MB | 19.11% | 0.043 | sortformer-4spk-v2-onnx-int4-cpu |
Before inference, convert raw 16 kHz mono audio to log-mel spectrogram:
import onnxruntime as ort
import numpy as np
session = ort.InferenceSession("sortformer.onnx", providers=["CPUExecutionProvider"])
# mel: log-mel spectrogram [1, 128, mel_frames]
mel = np.random.randn(1, 128, 500).astype(np.float32) # 5s @ 10ms stride
speaker_logits = session.run(None, {"processed_signal": mel})[0]
# shape: [1, 63, 4]
using var session = new InferenceSession("sortformer.onnx");
var inputs = new List<NamedOnnxValue>
{
NamedOnnxValue.CreateFromTensor("processed_signal", melTensor),
};
using var results = session.Run(inputs);
var logits = results.First().AsTensor<float>();
// logits shape: [1, diar_frames, 4]
Exported from NeMo to ONNX (opset 21) using DiarizationConverter:
python scripts/export_fp32_opset21.py