System Info
transformers 5.7.0, torch 2.11.0, Python 3.12.12, macOS 15.7.1 (arm64). Reproduces on CPU.
Who can help?
@eustlb @ylacombe (audio / Whisper)
Reproduction
Loading whisper-large-v3 the documented way, with no dtype argument, and feeding it the output of its own feature extractor raises:
import torch, io, soundfile as sf
from datasets import load_dataset, Audio
from transformers import WhisperForConditionalGeneration, WhisperFeatureExtractor
model = WhisperForConditionalGeneration.from_pretrained("openai/whisper-large-v3")
fe = WhisperFeatureExtractor.from_pretrained("openai/whisper-large-v3")
ds = load_dataset("hf-internal-testing/librispeech_asr_dummy", "clean", split="validation")
ds = ds.cast_column("audio", Audio(decode=False))
wav, _ = sf.read(io.BytesIO(ds[0]["audio"]["bytes"]), dtype="float32")
feats = fe(wav, sampling_rate=16000, return_tensors="pt").input_features
print(next(model.parameters()).dtype, feats.dtype) # torch.float16 torch.float32
with torch.no_grad():
model.model.encoder(feats)
torch.float16 torch.float32
RuntimeError: Input type (float) and bias type (c10::Half) should be the same
Expected behavior
Either the model and its own feature extractor agree on a dtype, or the mismatch produces an error that names the cause.
What is actually going on
from_pretrained honours config.torch_dtype. Two checkpoints declare float16 and the rest declare float32:
| checkpoint |
config.torch_dtype |
manual model + feature_extractor path |
whisper-tiny |
float32 |
works |
whisper-base |
float32 |
works |
whisper-small |
float32 |
works |
whisper-medium |
float32 |
works |
whisper-large-v2 |
float32 |
works |
whisper-large-v3 |
float16 |
RuntimeError |
whisper-large-v3-turbo |
float16 |
RuntimeError |
WhisperFeatureExtractor always returns float32, so the two newest checkpoints are the only ones where the model's declared dtype and its feature extractor's output disagree. Both fail identically.
Three things make this easy to miss:
pipeline() is unaffected. It casts internally, so the high-level path works and only the manual path breaks. The manual path is what fine-tuning scripts and custom inference loops use.
- It is version-independent and hardware-independent — it follows from the checkpoint config, not from a local setting.
- The error names types, not the cause. "Input type (float) and bias type (c10::Half)" points at the conv layer, several frames from the
from_pretrained call that chose the dtype, so it reads as a user error.
Workarounds
Either forces agreement:
model = WhisperForConditionalGeneration.from_pretrained("openai/whisper-large-v3", dtype=torch.float32)
# or
feats = feats.to(model.dtype)
Possible fixes
I do not want to presume the right one, so listing what seems available:
- Have
WhisperFeatureExtractor accept and honour a dtype, so a processor built from the same checkpoint matches the model.
- Cast
input_features to the encoder's dtype inside WhisperEncoder.forward, which is what pipeline() effectively does today.
- Leave the behaviour and raise a Whisper-specific error naming the checkpoint's declared dtype and the feature dtype.
Happy to open a PR for whichever direction you prefer, with a regression test covering both float16 checkpoints.
System Info
transformers5.7.0,torch2.11.0, Python 3.12.12, macOS 15.7.1 (arm64). Reproduces on CPU.Who can help?
@eustlb @ylacombe (audio / Whisper)
Reproduction
Loading
whisper-large-v3the documented way, with nodtypeargument, and feeding it the output of its own feature extractor raises:Expected behavior
Either the model and its own feature extractor agree on a dtype, or the mismatch produces an error that names the cause.
What is actually going on
from_pretrainedhonoursconfig.torch_dtype. Two checkpoints declarefloat16and the rest declarefloat32:config.torch_dtypemodel+feature_extractorpathwhisper-tinywhisper-basewhisper-smallwhisper-mediumwhisper-large-v2whisper-large-v3whisper-large-v3-turboWhisperFeatureExtractoralways returns float32, so the two newest checkpoints are the only ones where the model's declared dtype and its feature extractor's output disagree. Both fail identically.Three things make this easy to miss:
pipeline()is unaffected. It casts internally, so the high-level path works and only the manual path breaks. The manual path is what fine-tuning scripts and custom inference loops use.from_pretrainedcall that chose the dtype, so it reads as a user error.Workarounds
Either forces agreement:
Possible fixes
I do not want to presume the right one, so listing what seems available:
WhisperFeatureExtractoraccept and honour adtype, so a processor built from the same checkpoint matches the model.input_featuresto the encoder's dtype insideWhisperEncoder.forward, which is whatpipeline()effectively does today.Happy to open a PR for whichever direction you prefer, with a regression test covering both float16 checkpoints.