Skip to content

Commit 1af3555

Browse files
committed
test: add native compiler lanes to the full conformance suites
Extend `mode_test/2` to `mode_test/3` with a `lane_tags:` option and run the `*_full` forward-pass conformance suites (ViT-Base, Whisper-tiny) through the native and fusion compilers alongside the evaluator. The full suites pass `lane_tags: false`, so their native and fusion lanes are emitted without the cross-cutting `:native` / `:native_compiled` tags and stay gated behind the suite's own `:vit_full` / `:whisper_full` moduletag. `--only vit_full` now runs all three lanes on the full checkpoint, while `--only native` stays tiny-random only and never pulls a full-size download. Both full forwards lower fully under `native_fallback: :raise` and hold at the pinned 1e-4 reference tolerance in the fusion lane too — `mx::compile` only reassociates f32, so its drift stays well below the approximate `mx::fast::*` kernels (which need 1e-3 ViT / 1e-2 Whisper in the `:fast_kernels_full` variants). The serving and fast-kernels tests remain eval-only.
1 parent c7d6f33 commit 1af3555

3 files changed

Lines changed: 59 additions & 29 deletions

File tree

test/emily/conformance/vit_full_test.exs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ defmodule Emily.Conformance.VitFullTest do
3030
@moduletag capture_log: true
3131
@moduletag timeout: 600_000
3232

33-
test "google/vit-base-patch16-224 forward pass matches pinned logits slice" do
33+
mode_test "google/vit-base-patch16-224 forward pass matches pinned logits slice",
34+
lane_tags: false do
3435
{:ok, %{model: model, params: params, spec: spec}} =
3536
Bumblebee.load_model({:hf, "google/vit-base-patch16-224"})
3637

@@ -42,7 +43,7 @@ defmodule Emily.Conformance.VitFullTest do
4243
"pixel_values" => Nx.broadcast(Nx.tensor(0.5, type: :f32), {1, 224, 224, 3})
4344
}
4445

45-
outputs = Axon.predict(model, params, inputs)
46+
outputs = Axon.predict(model, params, inputs, predict_opts)
4647

4748
assert Nx.shape(outputs.logits) == {1, 1000}
4849

test/emily/conformance/whisper_full_test.exs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ defmodule Emily.Conformance.WhisperFullTest do
3131
@moduletag capture_log: true
3232
@moduletag timeout: 600_000
3333

34-
test "openai/whisper-tiny forward pass matches pinned logits slice" do
34+
mode_test "openai/whisper-tiny forward pass matches pinned logits slice", lane_tags: false do
3535
{:ok, %{model: model, params: params, spec: spec}} =
3636
Bumblebee.load_model({:hf, "openai/whisper-tiny"})
3737

@@ -58,7 +58,7 @@ defmodule Emily.Conformance.WhisperFullTest do
5858
"decoder_attention_mask" => decoder_attention_mask
5959
}
6060

61-
outputs = Axon.predict(model, params, inputs)
61+
outputs = Axon.predict(model, params, inputs, predict_opts)
6262

6363
assert Nx.shape(outputs.logits) == {1, 6, 51_865}
6464

test/support/conformance_helper.ex

Lines changed: 54 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ defmodule Emily.ConformanceHelper do
3030
defmacro __using__(_opts) do
3131
quote do
3232
import Emily.ConformanceHelper,
33-
only: [assert_all_close: 2, assert_all_close: 3, mode_test: 2]
33+
only: [assert_all_close: 2, assert_all_close: 3, mode_test: 2, mode_test: 3]
3434

3535
setup do
3636
Nx.default_backend(Emily.Backend)
@@ -86,36 +86,65 @@ defmodule Emily.ConformanceHelper do
8686
`native_fallback: :raise` makes the native lane a no-fallback gate: an
8787
op that does not lower fails the test rather than silently degrading to
8888
the evaluator, so a red native lane is a concrete op-coverage gap.
89+
90+
## Options
91+
92+
* `:lane_tags` (default `true`) — when `false`, the native and fusion
93+
lanes are emitted *without* the cross-cutting `:native` /
94+
`:native_compiled` tags. The heavyweight `*_full` suites pass
95+
`lane_tags: false` so their compiler lanes stay gated behind the
96+
suite's own `:*_full` moduletag; otherwise `--only native` would
97+
start pulling full-size checkpoints. `--only vit_full` then runs all
98+
three lanes of that suite.
8999
"""
90-
defmacro mode_test(name, do: body) do
91-
quote do
92-
test unquote(name) do
93-
var!(predict_opts) = []
94-
unquote(body)
95-
end
100+
defmacro mode_test(name, opts \\ [], do: body) do
101+
tag_lanes? = Keyword.get(opts, :lane_tags, true)
102+
103+
lanes = [
104+
lane(false, name, "", [], body),
105+
lane(
106+
tag_lanes? && :native,
107+
name,
108+
" [native]",
109+
[compiler: Emily.Compiler, native: true, native_fallback: :raise],
110+
body
111+
),
112+
lane(
113+
tag_lanes? && :native_compiled,
114+
name,
115+
" [native_compiled]",
116+
[compiler: Emily.Compiler, native: true, native_fallback: :raise, native_compiled: true],
117+
body
118+
)
119+
]
96120

97-
@tag :native
98-
test unquote(name) <> " [native]" do
99-
var!(predict_opts) = [
100-
compiler: Emily.Compiler,
101-
native: true,
102-
native_fallback: :raise
103-
]
121+
quote do
122+
(unquote_splicing(lanes))
123+
end
124+
end
104125

105-
unquote(body)
126+
# Build one `mode_test` lane: a `test` that binds `predict_opts` for the
127+
# body, optionally preceded by `@tag tag`. `tag` is `false` to emit no
128+
# lane tag (the `*_full` suites rely on their own `:*_full` moduletag).
129+
defp lane(tag, name, suffix, predict_opts, body) do
130+
name_ast =
131+
if suffix == "", do: name, else: quote(do: unquote(name) <> unquote(suffix))
132+
133+
test =
134+
quote do
135+
test unquote(name_ast) do
136+
var!(predict_opts) = unquote(predict_opts)
137+
unquote(body)
138+
end
106139
end
107140

108-
@tag :native_compiled
109-
test unquote(name) <> " [native_compiled]" do
110-
var!(predict_opts) = [
111-
compiler: Emily.Compiler,
112-
native: true,
113-
native_fallback: :raise,
114-
native_compiled: true
115-
]
116-
117-
unquote(body)
141+
if tag do
142+
quote do
143+
@tag unquote(tag)
144+
unquote(test)
118145
end
146+
else
147+
test
119148
end
120149
end
121150

0 commit comments

Comments
 (0)