Voice Activity Detection
Transformers
Safetensors
nemotron3_diarization
audio-frame-classification
speaker-diarization
streaming-sortformer
nemotron
medical
Instructions to use Aduomas/nemotron-3-diarization with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use Aduomas/nemotron-3-diarization with Transformers:
# pip install -U transformers accelerate # Load model directly from transformers import AutoProcessor, AutoModelForAudioFrameClassification processor = AutoProcessor.from_pretrained("Aduomas/nemotron-3-diarization") model = AutoModelForAudioFrameClassification.from_pretrained("Aduomas/nemotron-3-diarization", device_map="auto") - Notebooks
- Google Colab
- Kaggle
File size: 2,012 Bytes
9ded405 142a394 9ded405 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | """Turn Nemotron 3 frame probabilities into speaker segments, replicating Omi's published decoding behaviour.
Omi's output differs from NVIDIA's plain 0.5 threshold by a slightly higher threshold and by bridging short
same-speaker pauses: always below `bridge_s`, and up to `bridge_clear_s` when no other speaker is active inside.
"""
from dataclasses import dataclass
import numpy as np
FRAME_S = 0.01
@dataclass(frozen=True)
class DecoderParams:
threshold: float = 0.5
bridge_s: float = 0.0
bridge_clear_s: float = 0.0
def _runs(active: np.ndarray) -> tuple[np.ndarray, np.ndarray]:
edges = np.diff(np.r_[False, active, False].astype(np.int8))
return np.flatnonzero(edges == 1), np.flatnonzero(edges == -1)
def activity(probs: np.ndarray, params: DecoderParams) -> np.ndarray:
"""Boolean (frames, speakers) activity after thresholding and pause bridging."""
raw = probs > params.threshold
active = raw.copy()
bridge, bridge_clear = round(params.bridge_s / FRAME_S), round(params.bridge_clear_s / FRAME_S)
for speaker in range(raw.shape[1]):
others = np.delete(raw, speaker, axis=1).any(axis=1)
starts, ends = _runs(raw[:, speaker])
for gap_start, gap_end in zip(ends[:-1], starts[1:]):
length = gap_end - gap_start
if length < bridge or (length < bridge_clear and not others[gap_start:gap_end].any()):
active[gap_start:gap_end, speaker] = True
return active
def decode(probs: np.ndarray, params: DecoderParams) -> list[dict]:
"""Segments in seconds; speakers that never activate are dropped, so the count stays automatic."""
active = activity(probs, params)
segments = []
for speaker in range(active.shape[1]):
starts, ends = _runs(active[:, speaker])
segments.extend(
{"start": round(float(s * FRAME_S), 2), "end": round(float(e * FRAME_S), 2), "speaker": f"spk_{speaker}"}
for s, e in zip(starts, ends)
)
return segments
|