Skip to content

transforms.Vad silently returns an empty tensor when the waveform contains one non-finite sample#4216

Description

@Kayvan-Zahiri

馃悰 Describe the bug

A single non-finite sample in the leading region of a waveform makes
torchaudio.transforms.Vad return an empty tensor. The whole signal is discarded, with no
warning and no exception.

The failure is position-dependent: a NaN inside the speech is harmless, a NaN in the
leading silence that Vad scans destroys everything.

import numpy as np, torch, torchaudio

sr = 16000
t = torch.arange(sr * 3) / sr
sig = torch.zeros(sr * 3)
sig[sr:2 * sr] = 0.3 * torch.sin(2 * np.pi * 220 * t[sr:2 * sr]) + 0.05 * torch.randn(sr)

for label, idx in [("clean", None),
                   ("NaN in leading silence (idx 100)", 100),
                   ("NaN inside speech (idx 24000)", 24000)]:
    x = sig.clone()
    if idx is not None:
        x[idx] = float("nan")
    out = torchaudio.transforms.Vad(sr)(x)
    print(f"{label:<34} kept {out.numel()/sr:.2f}s of 3.00s  shape={tuple(out.shape)}")

Output:

clean                              kept 2.10s of 3.00s  shape=(33600,)
NaN in leading silence (idx 100)   kept 0.00s of 3.00s  shape=(0,)
NaN inside speech (idx 24000)      kept 2.10s of 3.00s  shape=(33600,)

Vad locates the first frame whose measure crosses trigger_level. Every comparison
against NaN is False, so once the running measure is poisoned no frame ever triggers and
the function reports that the entire input was silence.

Nothing in torchaudio rejects the input at any stage:

x = torch.full((16000,), float("nan"))
torchaudio.transforms.Vad(16000)(x)             # no error
torchaudio.transforms.MelSpectrogram(16000)(x)  # no error
torchaudio.transforms.Resample(16000, 8000)(x)  # no error

For reference, the amplification through the other transforms on the same one-NaN input
(input non-finite fraction 0.0000625):

MelSpectrogram    NaN fraction out 0.025
Spectrogram       NaN fraction out 0.025
Resample          NaN fraction out 0.002
MFCC              NaN fraction out 1.000     <- DCT spreads it to every coefficient
Loudness          NaN fraction out 1.000

Why this is worth an error rather than documentation

Vad is a preprocessing step, so this fails open in the worst direction: a batch job
receives an empty tensor and silently drops the file instead of raising on it. Non-finite
samples arise from truncated decodes, failed resamples, and division by a zero-energy
normalisation window, so the input is not exotic.

For comparison, librosa raises ParameterError: Audio buffer is not finite everywhere
from stft, melspectrogram, resample and zero_crossing_rate on this input.

A torch.isfinite(waveform).all() check in functional.vad, or more broadly at the
transform boundary, would turn a silent data-loss bug into a clear failure. Happy to open
a PR with a regression test if that is wanted.

Versions

torchaudio 2.11.0, torch 2.11.0, numpy 1.26.4, Python 3.12, macOS, CPU.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions