| { | |
| "format": "taurscribe-granite-nar-onnx-bundle", | |
| "format_version": 1, | |
| "source_model": "ibm-granite/granite-speech-4.1-2b-nar", | |
| "export_dtype": "int4-matmulnbits-weights", | |
| "fixed_encoder_frames": 800, | |
| "opset": 20, | |
| "execution_provider_preference": [ | |
| "DmlExecutionProvider", | |
| "CPUExecutionProvider" | |
| ], | |
| "graphs": { | |
| "encoder": { | |
| "file": "encoder.onnx", | |
| "inputs": [ | |
| "input_features", | |
| "attention_mask" | |
| ], | |
| "outputs": [ | |
| "bpe_logits", | |
| "hidden_4", | |
| "hidden_8", | |
| "hidden_12", | |
| "hidden_last" | |
| ], | |
| "notes": "Fixed-shape app bucket: pad input_features to 800 frames. Trim bpe_logits to ceil(valid_frames / bpe_pooling_window) before CTC collapse." | |
| }, | |
| "projector": { | |
| "file": "projector.onnx", | |
| "inputs": [ | |
| "multilayer_features" | |
| ], | |
| "outputs": [ | |
| "audio_embeds" | |
| ] | |
| }, | |
| "embed_tokens": { | |
| "file": "embed_tokens.onnx", | |
| "inputs": [ | |
| "token_ids" | |
| ], | |
| "outputs": [ | |
| "text_embeds" | |
| ] | |
| }, | |
| "editor": { | |
| "file": "editor.onnx", | |
| "inputs": [ | |
| "inputs_embeds", | |
| "position_ids" | |
| ], | |
| "outputs": [ | |
| "token_ids" | |
| ], | |
| "notes": "Non-causal bidirectional editor. Host code should pass one flattened sample sequence at a time." | |
| } | |
| }, | |
| "host_pipeline": [ | |
| "Extract Granite log-mel features with the copied preprocessor config and pad/truncate to 800 encoder frames.", | |
| "Run encoder.onnx.", | |
| "Trim padded BPE logits using the valid frame count, argmax, unique-consecutive collapse, and remove blank_token_id.", | |
| "Concatenate hidden_4, hidden_8, hidden_12, and hidden_last, then run projector.onnx.", | |
| "Trim audio embeddings using floor(valid_frames / projector.downsample_rate).", | |
| "Insert blank edit slots around the encoder CTC token IDs.", | |
| "Run embed_tokens.onnx for the slotted token IDs.", | |
| "Concatenate audio embeddings and text embeddings, create monotonic position_ids, then run editor.onnx.", | |
| "Select the text segment logits, argmax, unique-consecutive collapse, remove blank_token_id, and decode with tokenizer.json." | |
| ], | |
| "validation": { | |
| "onnx_checker": "run scripts/granite_nar_export.py validate --model-dir <onnx-bundle>", | |
| "ort_cpu_session_load": "run scripts/granite_nar_export.py validate --model-dir <onnx-bundle>" | |
| }, | |
| "notes": [ | |
| "Fallback is controlled by ONNX Runtime session creation in Rust, not encoded inside the ONNX files.", | |
| "INT4 weight-only MatMulNBits bundle with an editor that returns token_ids instead of full vocabulary logits.", | |
| "Portable bundle: rank-5 attention MatMuls are flattened to rank 3, fixed 800-frame shape chains are baked as constants, and GLU Split nodes are replaced with Slice pairs so the full encoder runs correctly on DirectML.", | |
| "DirectML is preferred on compatible Windows GPUs; ONNX Runtime CPU remains the portable fallback." | |
| ], | |
| "variant": "int4-argmax-dml-static", | |
| "encoder_dml_safe": true | |
| } | |