System Info
- transformers 5.7.0
- torch 2.11.0, numpy 1.26.4, soundfile 0.13.1
- Python 3.12, macOS, CPU
Who can help?
AutomaticSpeechRecognitionPipeline / audio pipelines.
Reproduction
Passing a stereo waveform loaded with soundfile silently discards almost all of the
audio. The pipeline logs a warning saying it converted to mono, and then transcribes
about 3 seconds of speech as ' you'.
import io, numpy as np, soundfile as sf
from transformers import pipeline
rng = np.random.default_rng(0)
mono = (rng.standard_normal(16000 * 3) * 0.05).astype(np.float32)
buf = io.BytesIO()
sf.write(buf, np.stack([mono, mono], axis=1), 16000, format="WAV", subtype="FLOAT")
buf.seek(0)
stereo, sr = sf.read(buf, dtype="float32") # soundfile returns (samples, channels)
print("soundfile.read shape :", stereo.shape)
asr = pipeline("automatic-speech-recognition", model="openai/whisper-tiny", device="cpu")
print("mono :", repr(asr(mono.copy())["text"]))
print("stereo :", repr(asr(stereo.copy())["text"]))
print("after pipeline's mean(axis=0):", stereo.mean(axis=0).shape)
Output:
soundfile.read shape : (48000, 2)
UserWarning: We expect a single channel audio input for AutomaticSpeechRecognitionPipeline,
got 2. Taking the mean of the channels for mono conversion.
mono : ' See you in the next video!'
stereo : ' you'
after pipeline's mean(axis=0): (2,)
Expected behavior
The stereo call should transcribe the same as the mono call. Instead 48,000 samples
become 2.
pipelines/automatic_speech_recognition.py:
if inputs.ndim != 1:
logger.warning(
f"We expect a single channel audio input for AutomaticSpeechRecognitionPipeline, "
f"got {inputs.ndim}. Taking the mean of the channels for mono conversion."
)
inputs = inputs.mean(axis=0)
mean(axis=0) assumes channels-first, (channels, samples). soundfile.read and
librosa.load(..., mono=False) both return channels-last, (samples, channels), which is
also what scipy.io.wavfile.read returns. On that layout axis=0 averages across time,
so a 3-second stereo clip collapses to 2 numbers, gets padded back to 30s of silence, and
decodes to ' you'.
(2, N) input works correctly, so whether the pipeline destroys your audio depends on
which loader you used, with no error either way.
Two smaller things in the same three lines:
- The warning interpolates
inputs.ndim, not the channel count, so it always says
"got 2" for any 2-D input regardless of how many channels there are. For the
channels-last case the number that would actually help ("got 48000") never appears.
- A user who reads the warning is told the conversion happened. It did, along the wrong
axis.
Suggested fix: treat the smaller of the two dimensions as the channel axis, which is
unambiguous for any realistic audio since channels are ~1-8 and samples are thousands:
if inputs.ndim != 1:
ch_axis = int(np.argmin(inputs.shape))
logger.warning(
f"We expect a single channel audio input for AutomaticSpeechRecognitionPipeline, "
f"got shape {tuple(inputs.shape)}. Taking the mean over axis {ch_axis} for mono conversion."
)
inputs = inputs.mean(axis=ch_axis)
Raising on ndim > 2 would also be reasonable. Happy to open a PR with tests covering
both layouts if you would like.
System Info
Who can help?
AutomaticSpeechRecognitionPipeline/ audio pipelines.Reproduction
Passing a stereo waveform loaded with
soundfilesilently discards almost all of theaudio. The pipeline logs a warning saying it converted to mono, and then transcribes
about 3 seconds of speech as
' you'.Output:
Expected behavior
The stereo call should transcribe the same as the mono call. Instead 48,000 samples
become 2.
pipelines/automatic_speech_recognition.py:mean(axis=0)assumes channels-first,(channels, samples).soundfile.readandlibrosa.load(..., mono=False)both return channels-last,(samples, channels), which isalso what
scipy.io.wavfile.readreturns. On that layoutaxis=0averages across time,so a 3-second stereo clip collapses to 2 numbers, gets padded back to 30s of silence, and
decodes to
' you'.(2, N)input works correctly, so whether the pipeline destroys your audio depends onwhich loader you used, with no error either way.
Two smaller things in the same three lines:
inputs.ndim, not the channel count, so it always says"got 2" for any 2-D input regardless of how many channels there are. For the
channels-last case the number that would actually help ("got 48000") never appears.
axis.
Suggested fix: treat the smaller of the two dimensions as the channel axis, which is
unambiguous for any realistic audio since channels are ~1-8 and samples are thousands:
Raising on
ndim > 2would also be reasonable. Happy to open a PR with tests coveringboth layouts if you would like.