Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions python/tests/test_transformers.py
Original file line number Diff line number Diff line change
Expand Up @@ -864,6 +864,58 @@ def _get_features(audio):
transcription = processor.decode(token_ids)
assert transcription == expected_transcription

@test_utils.only_on_linux
def test_transformers_whisper_full_context(self, tmp_dir):
import transformers

model_name = "openai/whisper-tiny"
converter = ctranslate2.converters.TransformersConverter(model_name)
output_dir = str(tmp_dir.join("ctranslate2_model"))
output_dir = converter.convert(output_dir)

audio_path = os.path.join(test_utils.get_data_dir(), "audio", "jfk.npy")
audio = np.load(audio_path)

processor = transformers.WhisperProcessor.from_pretrained(model_name)
# Pad after computing the log-Mel spectrogram to match the openai/whisper behavior.
inputs = processor(audio, padding=False, sampling_rate=16000)
features = inputs.input_features[0]
features = np.pad(features, [(0, 0), (0, 3000 - features.shape[-1])])
features = ctranslate2.StorageView.from_array(np.expand_dims(features, 0))

model = ctranslate2.models.Whisper(output_dir)

# Suppress <|endoftext|> so generation always runs until max_length is
# reached, regardless of the actual audio content.
eot_id = processor.tokenizer.convert_tokens_to_ids("<|endoftext|>")

def _generated_length(prompt):
result = model.generate(
features,
[prompt],
beam_size=1,
num_hypotheses=1,
suppress_tokens=[eot_id],
)[0]
return len(result.sequences_ids[0])

no_timestamps_prompt = [
"<|startoftranscript|>",
"<|en|>",
"<|transcribe|>",
"<|notimestamps|>",
]
timestamped_prompt = ["<|startoftranscript|>", "<|en|>", "<|transcribe|>"]

# With the default max_length of 448, decoding can use the entire
# remaining decoder context (448 minus the prompt length), no longer
# capped to half of max_length. This applies to both no-timestamp and
# timestamped decoding, since the previous 224-token cap was not
# actually related to timestamps. The timestamped prompt is one
# token shorter, so it gets one extra position of context.
assert _generated_length(no_timestamps_prompt) == 445
assert _generated_length(timestamped_prompt) == 446

@test_utils.only_on_linux
@test_utils.on_available_devices
@pytest.mark.parametrize(
Expand Down
2 changes: 1 addition & 1 deletion src/models/whisper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ namespace ctranslate2 {
decoding_options.length_penalty = options.length_penalty;
decoding_options.repetition_penalty = options.repetition_penalty;
decoding_options.no_repeat_ngram_size = options.no_repeat_ngram_size;
decoding_options.max_length = std::min(total_max_length / 2, total_max_length - start_step);
decoding_options.max_length = total_max_length - start_step;
decoding_options.sampling_topk = options.sampling_topk;
decoding_options.sampling_temperature = options.sampling_temperature;
decoding_options.num_hypotheses = options.num_hypotheses;
Expand Down
Loading