Skip to content

Commit 8d87f2e

Browse files
Implement new diarization model: Sortformer (#342)
* implement sortformer * .. * fixes * fix audio saving * formatting
1 parent 7558b8c commit 8d87f2e

5 files changed

Lines changed: 91 additions & 3 deletions

File tree

.github/workflows/test_run.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ jobs:
6060
python -m pip install torch torchaudio --index-url https://download.pytorch.org/whl/cpu
6161
uv pip install --system -c constraints.txt -r requirements.txt
6262
63+
- name: Test with sortformer diarizer
64+
run: |
65+
python diarize.py -a "./tests/assets/test.opus" --whisper-model tiny.en --diarizer sortformer
66+
6367
- name: Test with msdd diarizer
6468
run: |
6569
python diarize.py -a "./tests/assets/test.opus" --whisper-model tiny.en --diarizer msdd

diarization/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
from .msdd.msdd import MSDDDiarizer
2+
from .sortformer.sortformer import SortformerDiarizer
23

3-
__all__ = ["MSDDDiarizer"]
4+
__all__ = ["MSDDDiarizer", "SortformerDiarizer"]
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
from warnings import warn
2+
3+
import torch
4+
5+
from nemo.collections.asr.models import SortformerEncLabelModel
6+
from nemo.collections.asr.parts.mixins.diarization import DiarizeConfig
7+
8+
9+
class SortformerDiarizer:
10+
def __init__(self, device):
11+
self.model: SortformerEncLabelModel = SortformerEncLabelModel.from_pretrained(
12+
"nvidia/diar_streaming_sortformer_4spk-v2", map_location=device
13+
)
14+
15+
self.model.sortformer_modules.chunk_len = 340
16+
self.model.sortformer_modules.chunk_right_context = 40
17+
self.model.sortformer_modules.fifo_len = 40
18+
self.model.sortformer_modules.spkcache_update_period = 300
19+
self.model.sortformer_modules.spkcache_len = 188
20+
self.model.sortformer_modules._check_streaming_parameters()
21+
22+
warn(
23+
"Sortformer supports maximum of 4 speakers only, "
24+
"please use MSDD if your audio has more than 4 speakers",
25+
Warning,
26+
)
27+
28+
self.model.eval()
29+
30+
def diarize(self, audio: torch.Tensor):
31+
with torch.inference_mode():
32+
processed_signal, processed_signal_length = self.model.process_signal(
33+
audio_signal=audio,
34+
audio_signal_length=torch.tensor([audio.shape[-1]]),
35+
)
36+
processed_signal = processed_signal[:, :, : processed_signal_length.max()]
37+
38+
preds = self.model.forward_streaming(processed_signal, processed_signal_length)
39+
preds = preds.cpu()
40+
41+
# TODO: make this tunable
42+
diarize_cfg = DiarizeConfig(
43+
postprocessing_params={
44+
"onset": 0.5,
45+
"offset": 0.5,
46+
"pad_onset": 0.0,
47+
"pad_offset": 0.0,
48+
"min_duration_on": 0.0,
49+
"min_duration_off": 0.0,
50+
}
51+
)
52+
53+
audio_rttm_map_dict = {
54+
"audio": {
55+
"uniq_id": "audio",
56+
"audio_filepath": "tensor_audio",
57+
"offset": 0.0,
58+
"duration": None,
59+
"text": "-",
60+
"label": "infer",
61+
}
62+
}
63+
64+
self.model._diarize_audio_rttm_map = audio_rttm_map_dict
65+
uniq_ids = list(self.model._diarize_audio_rttm_map.keys())
66+
processed_outputs = self.model._diarize_output_processing(preds, uniq_ids, diarize_cfg)
67+
self.model._diarize_audio_rttm_map = {}
68+
69+
labels = []
70+
for label in processed_outputs[0]:
71+
start, end, speaker = label.split()
72+
start, end = float(start), float(end)
73+
start, end = int(start * 1000), int(end * 1000)
74+
labels.append((start, end, int(speaker.split("_")[1])))
75+
76+
labels = sorted(labels, key=lambda x: x[0])
77+
78+
return labels

diarize.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@
8989
parser.add_argument(
9090
"--diarizer",
9191
default="msdd",
92-
choices=["msdd"],
92+
choices=["msdd", "sortformer"],
9393
help="Choose the diarization model to use",
9494
)
9595

@@ -189,6 +189,11 @@
189189

190190
diarizer_model = MSDDDiarizer(device=args.device)
191191

192+
elif args.diarizer == "sortformer":
193+
from diarization import SortformerDiarizer
194+
195+
diarizer_model = SortformerDiarizer(device=args.device)
196+
192197
speaker_ts = diarizer_model.diarize(torch.from_numpy(audio_waveform).unsqueeze(0))
193198
del diarizer_model
194199
torch.cuda.empty_cache()

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
nemo_toolkit[asr]>=2.3.0
1+
nemo_toolkit[asr]>=2.5.0
22
nltk
33
faster-whisper>=1.1.0
44
git+https://github.com/MahmoudAshraf97/demucs.git

0 commit comments

Comments
 (0)