Skip to content

Whisper adapter - #1944

Open
dipo101 wants to merge 5 commits into
TransformerLensOrg:devfrom
dipo101:whisper-adapter
Open

dipo101 wants to merge 5 commits into
TransformerLensOrg:devfrom
dipo101:whisper-adapter

Conversation

@dipo101

@dipo101 dipo101 commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

Description

Adds WhisperArchitectureAdapter, so WhisperForConditionalGeneration checkpoints load via boot_transformers with hooks on both the audio encoder and the text decoder. This covers tiny through large-v3, large-v3-turbo and distil-whisper.

logits, cache = bridge.run_with_cache(input_features, decoder_input=decoder_ids)
  • Adapter: subclasses the BART-family base. The encoder front end is conv1/conv2 plus sinusoidal embed_positions, the unembed is proj_out, and asymmetric stacks follow the decoder. k_proj has no bias; this is documented and pinned in tests.
  • Shared changes, as agreed in [Proposal] Whisper adapter for TransformerBridge #1938:
    • an AUDIO_SEQ2SEQ_ARCHITECTURES set (loads via AutoModelForSpeechSeq2Seq);
    • a cfg.is_audio_seq2seq flag that keeps the tokenizer and loads WhisperProcessor;
    • audio_input_name="input_features", with decoder_input required.
  • verify_models: Phase 1 supports audio seq2seq. openai/whisper-tiny and openai/whisper-large-v3-turbo (32/4 layers) are verified at P1 = 100%.
  • Tests: unit tests, plus a CI-run tiny random-weight parity test. A slow whisper-tiny test confirms logits match HF exactly.

Part of #1938. generate() and weight processing follow in separate PRs; until then they raise clear errors.

Type of change

  • New feature (non-breaking change which adds functionality)

Checklist:

  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • I have not rewritten tests relating to key interfaces which would affect backward compatibility

Audio encoder + text decoder models (Whisper) fit neither existing audio
path: encoder-only audio models drop the tokenizer and feed `input` as
input_values, and audio-text LMs load as AutoModelForSeq2SeqLM.

- New AUDIO_SEQ2SEQ_ARCHITECTURES set, routed to AutoModelForSpeechSeq2Seq
  and classified as seq2seq.
- Explicit cfg.is_audio_seq2seq flag. skip_tokenizer_for_modality keeps
  the tokenizer for it, and the processor loader runs AutoProcessor after
  the audio feature extractor so bridge.processor ends as the full
  processor (feature extractor + tokenizer). Audio-text LMs are unaffected.
- forward(): the adapter declares the keyword audio goes in under
  (ArchitectureAdapter.audio_input_name); audio seq2seq models take their
  features as `input`, require decoder_input (or labels), and skip the
  shift-from-input_ids that text encoder-decoders use. 1-D decoder ids
  are batched. The input_values branch is untouched.
- enable_compatibility_mode() refuses audio seq2seq with an accurate
  message until encoder weight processing lands.
- n_ctx falls back to max_target_positions before the 2048 default.
So verify_models can run on Whisper:

- build_modality_input builds the [batch, n_mels, 2 * n_frames] log-mel
  window for audio seq2seq.
- The Phase 1 HF reference capture and benchmark_forward_pass pass the
  features under the adapter's audio_input_name plus decoder_start
  decoder ids, the same single-token convention text encoder-decoders use.
- The component benchmark skips the channel-first front-end convs
  (covered end to end by the forward pass), and decoder_embed always
  gets token ids instead of the modality input.
- The encoder-only Phase 8 audio suite skips audio seq2seq.
WhisperForConditionalGeneration (tiny through large-v3, large-v3-turbo,
distil-whisper) loads through boot_transformers with hooks in both the
audio encoder and the text decoder:

    logits, cache = bridge.run_with_cache(input_features, decoder_input=ids)

WhisperArchitectureAdapter subclasses BartFamilyArchitectureAdapter
(pre-LN, per-stack final norms). What differs from the BART base:

- Encoder front end: conv1 / conv2 (channel-first, so their hooks declare
  position on dim 2; hook_out is pre-GELU) and the fixed sinusoidal
  embed_positions table, read whole as [n_frames, d_model], in place of
  token embeddings. Two small seams on the base make this declarative:
  _encoder_embeddings() and unembed_name.
- Unembedding is proj_out, tied to decoder_embed, with no
  final_logits_bias.
- Stacks may be asymmetric (large-v3-turbo 32/4, distil-whisper n/2);
  n_layers follows the decoder, as for Blenderbot.
- k_proj has no bias while q/v/out_proj do; noted in the docstring and
  pinned by the tiny and whisper-tiny tests.

Out of scope here and planned as follow-ups: generate()
(supports_generation=False) and weight processing (compatibility mode
refuses). applicable_phases=[1] follows from that.

Registered in all four places. The model_type fallback and 17 registry
entries are added at status 0 (openai/whisper-*, distil-whisper/*).

Tests:
- unit: mapping, flags, routing, tokenizer carve-out, n_ctx, factory.
- test_whisper_tiny.py (CI, random weights, no download): independent HF
  parity for logits and labels-only loss, hook shapes on both stacks,
  front-end math, pos_slice on the declared axes, an encoder-output patch
  that equals HF fed the patched encoder_outputs, error paths, and the
  Phase 1 benchmarks.
- test_whisper_adapter.py (slow, openai/whisper-tiny): parity against an
  independent eager HF model, the k_proj bias, and hook shapes.

Refs TransformerLensOrg#1938
verify_models on openai/whisper-tiny: P1 at 100% (all 74 components
equivalent to HF, forward-pass logits within tolerance). P2-P4 are not
applicable yet (applicable_phases=[1] until generate() and weight
processing land). The entry, header counts and the verification_history
record are what the tool wrote.

The slow real-weights suite (test_whisper_adapter.py) passes 6/6, and
teacher-forced logits match an independent eager HF model exactly (max
abs diff 0.0 over all 51865 logits at each decoder position).
verify_models on openai/whisper-large-v3-turbo: P1 at 100% (all 242
components equivalent to HF, forward-pass logits within tolerance). This
is the asymmetric case (32 encoder / 4 decoder layers) with the
128-mel-bin front end of the large-v3 family. The entry, header counts and
the verification_history record are what the tool wrote.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant