Add multi components recipes - #524
Conversation
There was a problem hiding this comment.
Pull request overview
Adds new multi-component Olive recipes and accompanying docs/scripts for:
- Stable Diffusion 3 Medium (diffusers): export once via Mobius, then optimize specific ONNX components independently.
- Qwen3-VL-2B-Instruct: two flows (export → per-component optimize, and GPTQ quantize decoder → export) plus an ORT GenAI inference script.
Changes:
- Introduces SD3 multi-component optimization config, end-to-end ONNX inference script, and documentation.
- Introduces Qwen3-VL multi-component configs (optimize components; GPTQ quantize-then-export), inference script, and documentation.
- Registers both as recipes via
info.ymland adds local artifact.gitignorerules.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| stabilityai-stable-diffusion-3-medium-diffusers/multi_comp/sd3_optimize_components.json | Olive config to optimize SD3 exported ONNX components with per-component builds. |
| stabilityai-stable-diffusion-3-medium-diffusers/multi_comp/sd3_inference.py | SD3 all-ONNX inference script (tokenizers + transformer + VAE decoder). |
| stabilityai-stable-diffusion-3-medium-diffusers/multi_comp/README.md | Step-by-step instructions for export, per-component optimization, and inference. |
| stabilityai-stable-diffusion-3-medium-diffusers/multi_comp/info.yml | Registers SD3 multi-component recipe metadata. |
| stabilityai-stable-diffusion-3-medium-diffusers/multi_comp/.gitignore | Ignores exported/optimized outputs, cache, and generated images for SD3 flow. |
| stabilityai-stable-diffusion-3-medium-diffusers/LICENSE | Adds model licensing notice and links for SD3 Medium weights. |
| Qwen-Qwen3-VL-2B-Instruct/multi_comp/vlm_quantize_then_export.json | Olive config to GPTQ-quantize the decoder component (Torch stage) prior to export. |
| Qwen-Qwen3-VL-2B-Instruct/multi_comp/vlm_optimize_components.json | Olive config to optimize exported ONNX components with different pipelines per component. |
| Qwen-Qwen3-VL-2B-Instruct/multi_comp/vlm_inference.py | ORT GenAI inference script for text-only and image-conditioned generation. |
| Qwen-Qwen3-VL-2B-Instruct/multi_comp/README.md | Documents both Qwen multi-component flows and ORT GenAI inference requirements. |
| Qwen-Qwen3-VL-2B-Instruct/multi_comp/info.yml | Registers Qwen multi-component recipe metadata. |
| Qwen-Qwen3-VL-2B-Instruct/multi_comp/.gitignore | Ignores exported/optimized outputs, cache, and quantized HF checkpoint for Qwen flow. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| from transformers import CLIPTokenizer, T5TokenizerFast | ||
|
|
||
| MODEL_ID = "stabilityai/stable-diffusion-3-medium-diffusers" | ||
| ONNX_DIR = "exported_sd3_full2" |
| # Pad CLIP outputs to 4096 and concatenate | ||
| clip_l_padded = np.pad(clip_l_hidden, ((0, 0), (0, 0), (0, 4096 - 768))) # [1, 77, 4096] | ||
| clip_g_padded = np.pad(clip_g_hidden, ((0, 0), (0, 0), (0, 4096 - 1280))) # [1, 77, 4096] | ||
| encoder_hidden_states = np.concatenate([clip_l_padded, clip_g_padded, t5_hidden], axis=1) # [1, 410, 4096] |
| # Verify exported model exists | ||
| transformer_path = os.path.join(args.onnx_dir, "transformer", "model.onnx") | ||
| if not os.path.exists(transformer_path): | ||
| print(f"Error: ONNX model not found at {args.onnx_dir}/") | ||
| print( | ||
| "Run: olive capture-onnx-graph --model_name_or_path " | ||
| "stabilityai/stable-diffusion-3-medium-diffusers " | ||
| "--use_mobius_builder --output_path exported_sd3_full2" | ||
| ) | ||
| return |
| - name: qwen3vl-2B-Instruct | ||
| file: vlm_optimize_components.json | ||
| eps: | ||
| - CPUExecutionProvider | ||
| devices: | ||
| - cpu | ||
| - name: qwen3vl-2B-Instruct | ||
| file: vlm_quantize_then_export.json |
| --steps N Number of denoising steps (default: 28) | ||
| --seed N Random seed (default: 42) | ||
| --output PATH Output image path (default: sd3_output.png) | ||
| --onnx_dir DIR Path to exported model directory (default: exported_sd3_full2) |
| complete HF model directory: | ||
|
|
||
| ``` | ||
| out/vlm_decoder_gptq_hf/ |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 12 out of 12 changed files in this pull request and generated 5 comments.
Suppressed comments (6)
stabilityai-stable-diffusion-3-medium-diffusers/multi_comp/sd3_inference.py:20
- The documented export and optimization flow creates
exported_pkg, but the inference default and its recovery command useexported_sd3_full2(and the README repeats that default). As a result, the documented inference command fails immediately after the documented export. Align the constant, recovery command, and README onexported_pkg.
ONNX_DIR = "exported_sd3_full2"
stabilityai-stable-diffusion-3-medium-diffusers/multi_comp/sd3_inference.py:63
- The same CLIP output-contract issue occurs for CLIP-G: SD3 takes pooled projection from output 0 and conditioning from the penultimate hidden state, not output 0 as hidden and output 1 as pooled. Read the exported outputs by name and ensure the penultimate hidden state is exported.
clip_g_hidden = out_g[0] # last_hidden_state [1, 77, 1280]
clip_g_pooled = out_g[1] # text_embeds [1, 1280]
Qwen-Qwen3-VL-2B-Instruct/multi_comp/README.md:138
- This path disagrees with the recipe's
output_dir: "vlm_decoder_gptq_hf", the following export command, and.gitignore; Olive writes the checkpoint at the working-directory root, not underout/. Following this displayed path sends users to a directory that is never created.
out/vlm_decoder_gptq_hf/
Qwen-Qwen3-VL-2B-Instruct/multi_comp/README.md:115
- This URL points to Microsoft's unrelated Apache Spark Mobius repository. The ONNX model builder referenced by Olive is
onnxruntime/mobius, so this link does not provide the promised ORT GenAI examples.
For the `genai_config.json` structure, see the
[Mobius ORT GenAI examples](https://github.com/microsoft/mobius/tree/main/examples) which write the
config automatically.
Qwen-Qwen3-VL-2B-Instruct/multi_comp/vlm_inference.py:55
- Passing the raw text alongside
imagesdoes not insert Qwen's image placeholder tokens. The embedding graph uses those tokens to splice the vision features into the sequence, so this path can ignore the image or fail on incompatible inputs. Build an image/text chat message and apply the tokenizer's chat template before calling the processor, asbuiltin/inference.py:53-87does.
images = og.Images.open(image_path)
inputs = processor(prompt, images=images)
Qwen-Qwen3-VL-2B-Instruct/multi_comp/README.md:99
- MobiusBuilder writes the vision sidecar as
image_processor.json, notvision_processor.json. Since no step creates the listed filename, the setup layout is inaccurate and users cannot match it to the generated GenAI config.
This issue also appears on line 113 of the same file.
vision_processor.json # Vision preprocessing config
| clip_l_hidden = out_l[0] # last_hidden_state [1, 77, 768] | ||
| clip_l_pooled = out_l[1] # text_embeds [1, 768] |
| clip_l_padded = np.pad(clip_l_hidden, ((0, 0), (0, 0), (0, 4096 - 768))) # [1, 77, 4096] | ||
| clip_g_padded = np.pad(clip_g_hidden, ((0, 0), (0, 0), (0, 4096 - 1280))) # [1, 77, 4096] | ||
| encoder_hidden_states = np.concatenate([clip_l_padded, clip_g_padded, t5_hidden], axis=1) # [1, 410, 4096] |
| } | ||
| }, | ||
| "engine": { "host": "local_system", "target": "local_system", "evaluate_input_model": false, "cache_dir": "cache" }, | ||
| "builds": { |
| }, | ||
| "passes": { "to_fp16": { "type": "OnnxFloatToFloat16" }, "dynamic_quant": { "type": "OnnxDynamicQuantization" } }, | ||
| "engine": { "host": "local_system", "target": "local_system", "evaluate_input_model": false, "cache_dir": "cache" }, | ||
| "builds": { |
| }, | ||
| "passes": { "decoder_gptq": { "type": "Gptq", "bits": 4, "group_size": 128, "sym": true, "lm_head": false } }, | ||
| "engine": { "host": "local_gpu", "target": "local_gpu", "evaluate_input_model": false, "cache_dir": "cache" }, | ||
| "builds": { |
Describe your changes
Add and validate multi-component optimization recipes backed by Olive and Mobius:
The non-functional SD3 prototype was removed. Current Mobius SD3 graph construction does not match the released checkpoint architecture or pooled-conditioning contract, so retaining that recipe would be misleading.
Validation
olive runassembled the mixed-quantized HF checkpoint;olive capture-onnx-graph --use_mobius_builderexported all four components. Decoder has 205 group-32 asymmetricMatMulNBitsnodes, vision has 114 group-128 symmetric nodes. Text returnedThe capital of France is Paris.and image inference returnedA cat is shown in the image.The capital of France is Paris.and image inference returnedCat.The capital of France is Paris.and image inference returnedA cat.