unsloth/tests
danielhanchen 4f2bfe7f69 flex/moe: flex_moe_bench.py + training-path tuple defensive unpack
Adds tests/flex_moe_bench.py: 2-round median decode throughput bench
comparing flex (FlexMoEInference) and HF generate on the same
(n_prompts, max_new_tokens, precision) workload. Writes
async_task_outputs/qwen3_moe_grpo_bench/bench_decode_{backend}_{precision}.json.

Also defensively unpacks self.mlp(hidden_states) in
Qwen3MoeDecoderLayer_fast_forward's training branch:
unsloth_zoo.temporary_patches.qwen3_moe.sparse_moe_block_forward
returns a plain tensor for transformers 5.x stacked experts, but the
decoder wrapper unpacked a 2-tuple. The inference branch was already
fixed in the previous commit; the training branch hit the same
ValueError under plain HF generate (no _flag_for_generation).

Bench numbers (Qwen3-30B-A3B, 4bit, rank 16 LoRA, bs=8, 64 new tokens,
B200):

| backend | median tok/s | peak VRAM (GB) | median wall (s) |
|---------|--------------|----------------|------------------|
| HF      | 80.5         | 57.2           | 6.36             |
| Flex    | 55.6         | 116.0          | 9.21             |

Flex is correctness-complete but not yet performance-competitive on
MoE decode at bs=8. Two structural reasons:

- MoE decode runs eager (forward_moe_backend uses bincount + Python
  expert loops which are not CUDA-graph capturable), so flex loses
  its main dense-model advantage.
- FlexEngine deep-copies the HF model for the rollout copy, doubling
  weight residency. For Qwen3-30B-A3B at bf16 that is ~60 GB extra.
  The pristine-base third copy is skipped for Qwen3 MoE (see the
  first commit of this series) but the inference deep-copy remains.

Follow-ups (not blockers for correctness):

- torch.compile(dynamic=True) on call_moe_model_with_flex_kwargs to
  recover some of the CUDA-graph throughput without requiring graph
  capture.
- Evaluate flex's scaling vs HF generate at bs=32 / bs=64, where
  paged-KV reuse should dominate per-prompt cost.
- A quantised-only inference copy (4bit forward, fp32 LoRA injection)
  so the flex path fits inside 2x 4bit weight residency (~34 GB)
  instead of the current post-dequantisation footprint.
2026-04-22 12:36:18 +00:00
..
python Add configurable PyTorch mirror via UNSLOTH_PYTORCH_MIRROR env var (#5024) 2026-04-15 11:39:11 +04:00
qlora Revert "[pre-commit.ci] auto fixes from pre-commit.com hooks" 2025-12-01 07:24:58 -08:00
saving Add regression test for shell injection fix in GGML conversion (#4773) 2026-04-02 00:10:47 -07:00
sh Add configurable PyTorch mirror via UNSLOTH_PYTORCH_MIRROR env var (#5024) 2026-04-15 11:39:11 +04:00
studio/install Add ROCm test suite for PR #4720 (#4824) 2026-04-11 04:44:13 -07:00
utils feat: Add cactus QAT scheme support (#4679) 2026-04-15 07:40:03 -07:00
__init__.py Qwen 3, Bug Fixes (#2445) 2025-04-30 22:38:39 -07:00
flex_fastlm_bench.py inference: add AGPLv3 license headers 2026-04-21 13:19:01 +00:00
flex_fastlm_smoke.py inference: add AGPLv3 license headers 2026-04-21 13:19:01 +00:00
flex_lazy_batch_smoke.py [pre-commit.ci] auto fixes from pre-commit.com hooks 2026-04-21 14:58:27 +00:00
flex_lazy_live_smoke.py [pre-commit.ci] auto fixes from pre-commit.com hooks 2026-04-21 14:58:27 +00:00
flex_moe_bench.py flex/moe: flex_moe_bench.py + training-path tuple defensive unpack 2026-04-22 12:36:18 +00:00
flex_moe_smoke.py flex: fix Qwen3 MoE smoke regressions (dtype / MoE MLP / peft patching) 2026-04-22 10:46:44 +00:00
flex_sleep_mode_smoke.py [pre-commit.ci] auto fixes from pre-commit.com hooks 2026-04-21 14:58:27 +00:00
run_all.sh fix: add tokenizers to no-torch deps and TORCH_CONSTRAINT for arm64 macOS py313+ (#4748) 2026-04-01 06:12:17 -07:00
test_cli_export_unpacking.py studio: stream export worker output into the export dialog (#4897) 2026-04-14 08:55:43 -07:00
test_get_model_name.py feat: Add support for OLMo-3 model (#4678) 2026-04-15 07:39:11 -07:00
test_loader_glob_skip.py Add unit tests for HfFileSystem glob skip guard (#4854) 2026-04-06 08:54:36 -07:00
test_model_registry.py Revert "[FIX] Vllm guided decoding params (#3662)" 2025-12-01 05:43:45 -08:00
test_raw_text.py fix: check find() return value before adding offset in try_fix_tokenizer (#4923) 2026-04-09 06:15:46 -07:00