Detección de actividad vocal — Silero VAD

Hay dos modelos de VAD disponibles: Pyannote segmentation para procesamiento offline por lotes con alta precisión, y Silero VAD para detección en streaming de baja latencia. Ambos se ejecutan completamente en el dispositivo.

Pyannote (offline)

Pyannote segmentation-3.0 proporciona VAD de alta precisión utilizando una arquitectura PyanNet. Procesa el audio en ventanas deslizantes de 10 segundos con un paso de 1 segundo, luego agrega las predicciones solapadas y aplica suavizado por histéresis.

Arquitectura

EtapaDetalles
SincNet40 filtros pasa-banda aprendidos (80 en total: 40 cos + 40 sin)
BiLSTM4 capas, hidden=128, bidireccional (salida de 256 dim)
Linear2 capas lineales con LeakyReLU (negative_slope=0.01)
SalidaSoftmax de 7 clases con post-procesamiento por histéresis

Tamaño del modelo: ~1,49M parámetros, ~5,7 MB en disco.

Umbrales por defecto

Uso desde la CLI

# Offline VAD
.build/release/speech vad recording.wav

# JSON output
.build/release/speech vad recording.wav --json

# Custom thresholds
.build/release/speech vad recording.wav --onset 0.6 --offset 0.3

Silero VAD (streaming)

Silero VAD es un modelo ligero de streaming que procesa chunks de 512 muestras (32 ms a 16 kHz). Se ejecuta a 23x el tiempo real en modo release, lo que lo hace adecuado para aplicaciones de audio en vivo.

División de backends: MLX y CoreML ahora usan por defecto exportaciones de Silero v6.2.1: aufklarer/Silero-VAD-v6.2.1-MLX y aufklarer/Silero-VAD-v6.2.1-CoreML. Ambas conservan la misma API de streaming de 32 ms.

Arquitectura

EtapaDetalles
STFTConv1d (de 1 a 258 canales), reflection pad a la derecha de 64
Encoder4x Conv1d + ReLU
LSTMHidden size 128, estado mantenido entre chunks
DecoderConv1d (de 128 a 1) sobre el estado oculto del LSTM, salida sigmoide

Tamaño del modelo: ~309K parámetros, ~1,2 MB en disco.

Máquina de estados en streaming

El procesador VAD en streaming usa una máquina de 4 estados para producir segmentos de voz limpios:

  1. silence — no se detecta voz
  2. pendingSpeech — se cruzó el umbral de onset, esperando la duración mínima de voz
  3. speech — segmento de voz confirmado en curso
  4. pendingSilence — se cruzó el umbral de offset, esperando la duración mínima de silencio

Umbrales por defecto

Uso desde la CLI

# Streaming VAD
.build/release/speech vad-stream recording.wav

# Custom thresholds
.build/release/speech vad-stream recording.wav --onset 0.6 --offset 0.3

# Minimum durations
.build/release/speech vad-stream recording.wav --min-speech 0.5 --min-silence 0.2

# Choose engine
.build/release/speech vad-stream recording.wav --engine coreml

Opciones

OpciónAplica aDescripción
--onsetAmbosUmbral de probabilidad de inicio de voz
--offsetAmbosUmbral de probabilidad de fin de voz
--min-speechStreamingDuración mínima del segmento de voz (segundos)
--min-silenceStreamingDuración mínima de silencio para terminar un segmento (segundos)
--engineStreamingMotor de inferencia: mlx o coreml
--jsonAmbosFormato de salida JSON
Importante

Para aplicaciones en tiempo real, usa speech vad-stream con Silero VAD. El modelo Pyannote requiere el archivo de audio completo y es más adecuado para procesamiento offline por lotes donde la precisión es la prioridad.

Confirma las pausas con Smart Turn

Un VAD solo oye silencio, así que no distingue una frase terminada de una pausa a mitad de frase. Conecta Smart Turn v3.2 a StreamingVADProcessor — o ejecuta speech vad-stream --smart-turn — para confirmar cada pausa antes de cerrar el segmento: una frase terminada cierra el turno de inmediato; una pausa a mitad de frase sigue escuchando.

Descargas de modelos

ModeloBackendTamañoHuggingFace
Silero-VAD-v6.2.1MLX~1,2 MBaufklarer/Silero-VAD-v6.2.1-MLX
Silero-VAD-v6.2.1CoreML~1,2 MBaufklarer/Silero-VAD-v6.2.1-CoreML
Pyannote-Segmentation-3.0MLX~5,7 MBaufklarer/Pyannote-Segmentation-MLX

API Swift

import SpeechVAD

// Offline VAD (Pyannote)
let pyannote = try await PyannoteVADModel.fromPretrained()
let segments = pyannote.detectSpeech(audio: samples, sampleRate: 16000)
for segment in segments {
    print("\(segment.startTime)s - \(segment.endTime)s")
}

// Streaming VAD (Silero)
let silero = try await SileroVADModel.fromPretrained()
let processor = StreamingVADProcessor(model: silero, config: .sileroDefault)
for event in processor.process(samples: audioBuffer) {
    switch event {
    case .speechStarted(let time):
        print("Speech started at \(time)s")
    case .speechEnded(let segment):
        print("Speech: \(segment.startTime)s - \(segment.endTime)s")
    }
}

También disponible en Android y en Linux y Windows mediante Speech Core (ONNX Runtime).