Skip to content

Commit bd35cac

Browse files
authored
Merge pull request #186 from ausimian/feat/expr-compiler-whisper-native-gate
Gate the native Whisper speech_to_text serving end-to-end
2 parents ebd9456 + 8c7eca6 commit bd35cac

2 files changed

Lines changed: 50 additions & 0 deletions

File tree

RELEASE.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,18 @@
185185

186186
### Fixed
187187

188+
- **A tuple-returning `cond` hard-crashed the native compiler instead of
189+
lowering.** A `cond`/`if` whose branches return a tuple (multi-output) hit a
190+
`FunctionClauseError` in the lowerer — and because that isn't an
191+
`ArgumentError`, it escaped the graceful-fallback rescue and faulted rather
192+
than degrading to the evaluator. It now lowers to one `where`-chain per leaf
193+
(same wholesale-select semantics as a single-output `cond`), projected by
194+
`:elem`; a nested/non-tensor container raises cleanly (graceful fallback).
195+
Surfaced by a Whisper `speech_to_text` serving — with this, plus the native
196+
`fft` and `indexed_put` lowering above, the **full Whisper serving
197+
(featurizer STFT + encoder/decoder + autoregressive decode loop) compiles
198+
fully native end-to-end**, gated by `whisper_full_test.exs`.
199+
188200
- **Dilated window reductions (`window_dilations > 1`) returned wrong values.**
189201
`window_sum`/`window_max`/`window_min`/`window_product` with a dilated kernel
190202
silently produced garbage for windows past the first stride positions, on both

test/emily/conformance/whisper_full_test.exs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,44 @@ defmodule Emily.Conformance.WhisperFullTest do
8484
)
8585
end
8686

87+
test "speech_to_text serving lowers fully native — featurizer + decode loop, no fallback" do
88+
repo = {:hf, "openai/whisper-tiny"}
89+
{:ok, whisper} = Bumblebee.load_model(repo)
90+
{:ok, featurizer} = Bumblebee.load_featurizer(repo)
91+
{:ok, tokenizer} = Bumblebee.load_tokenizer(repo)
92+
{:ok, generation_config} = Bumblebee.load_generation_config(repo)
93+
94+
# The gate is "does the whole graph lower", not transcription quality —
95+
# cap the decode loop so it stays fast.
96+
generation_config = Bumblebee.configure(generation_config, max_new_tokens: 4)
97+
98+
# `native_fallback: :raise` makes this a no-fallback gate over the ENTIRE
99+
# serving graph — the mel featurizer's STFT (`fft`), the encoder/decoder
100+
# forward, and the autoregressive decode loop (the multi-output `cond` in
101+
# the encoder attention, `indexed_put` cache writes, dynamic slices). Any
102+
# op the Expr compiler can't lower raises here rather than silently
103+
# degrading. The `mode_test` forward pass above never reaches these: it
104+
# feeds pre-computed mel features through a single `Axon.predict`, so it
105+
# exercises neither the featurizer nor the generation loop.
106+
serving =
107+
Bumblebee.Audio.speech_to_text_whisper(whisper, featurizer, tokenizer, generation_config,
108+
defn_options: [compiler: Emily.Compiler, native: true, native_fallback: :raise]
109+
)
110+
111+
# ~1 s of deterministic synthetic audio. The featurizer pads it to
112+
# Whisper's 30 s window, so the encoder still runs the full 1500-position
113+
# path (the shape that surfaced the multi-output cond).
114+
audio = Nx.sin(Nx.iota({16_000}, type: :f32) |> Nx.multiply(0.02))
115+
116+
%{chunks: chunks} = Nx.Serving.run(serving, audio)
117+
118+
# Reaching here is the gate: the full path lowered native with zero
119+
# fallback. The output is only sanity-checked (synthetic audio decodes to
120+
# arbitrary tokens; the transcription itself is not pinned).
121+
assert is_list(chunks) and chunks != []
122+
assert Enum.all?(chunks, &is_binary(&1.text))
123+
end
124+
87125
@tag :fast_kernels_full
88126
test "Whisper-tiny with fused MLX kernels matches the pinned argmax within widened tolerance" do
89127
{:ok, %{model: model, params: params}} =

0 commit comments

Comments
 (0)