feat(vit-gpt2): add CPU image-captioning recipes - #1122
Conversation
|
Independent pre-PR review: APPROVE. Scope is coherent: the nested-config JSON fix is generic and regression-tested; all four CPU recipes parse and retain the auto-config export/optimizer/loader contract; genuine FP16 is evidenced by initializer dtypes; encoder and decoder pass L0-L3 in both CPU precisions; and examples/recipes/README.md is untouched. Coverage annotation: partial because this host exposes CPU runtime only. All 26 required EP/device/precision tuples are nevertheless enumerated, and static analysis is not represented as accelerator runtime validation. |
6ea6dd9 to
c60f91e
Compare
| build_args += ["--no-compile"] | ||
| if rebuild: | ||
| build_args += ["--rebuild"] | ||
| if variant.precision in {"fp32", "fp16"}: |
There was a problem hiding this comment.
Quantized variants are still not pinned to their authored precision here. Because this change also passes --device npu, winml build treats the device as an explicit override; with no --precision, its auto policy resolves to w8a16 and rewrites an authored W8A8 config (for example usyd-community_vitpose-base-simple) to uint16 activations. The result remains labeled W8A8 even though a W8A16 artifact was built. Please pass variant.precision for quantized variants too, or avoid applying a device policy override to authored quantization.
| target_dir = nested_targets[0] | ||
| # A complete target-aware variant takes precedence over the legacy flat | ||
| # layout. Never mix components from the two layouts. | ||
| search_dirs = [target_dir] if target_dir and target_dir.is_dir() else [model_dir] |
There was a problem hiding this comment.
Selecting a target directory here discards every flat variant, even when the target directory only overrides one precision. Existing mixed-layout models such as facebook_dinov2-base have flat FP16/W8A16 recipes plus a target-specific qnn/npu W8A16 recipe; a QNN/NPU run now returns only W8A16 and silently loses the valid FP16 job. Please apply target precedence per precision (without mixing components within a precision) and retain flat precisions that have no target-specific replacement.
| return [] | ||
|
|
||
| ep_dir = _ep_directory_name(ep, device) | ||
| target_dir = model_dir / ep_dir / device if ep_dir and device != "auto" else None |
There was a problem hiding this comment.
An EP-only invocation cannot discover nested recipes: with the default device="auto", this leaves target_dir unset, while the auto-target branch below is disabled whenever ep is provided. For example, run_eval.py --ep cpu now misses the cpu/cpu recipes added here and falls back to generated config, even though CPU has an unambiguous device. Please infer a unique device from the normalized EP (or select a sole matching device directory) before resolving the target path.
c60f91e to
17b8002
Compare
Summary
Rebuilds historical #934 for
nlpconnect/vit-gpt2-image-captioningas a current-main, full-ladder contribution.winml inspect --format jsoncrash when nested Hugging Face configs occur inIOConfigInfo.extra.PretrainedConfigserialization.examples/recipes/README.md.Base and toolchain:
origin/main@e8a1c21e8e4b38a2b6831eade91027a3ad4e4916, winml 0.2.0, Python 3.11.14, ORT 1.24.4, transformers 4.57.6.1. Recipe paths and auto-config diff
examples/recipes/nlpconnect_vit-gpt2-image-captioning/cpu/cpu/image-to-text_fp32_config_encoder.jsonexamples/recipes/nlpconnect_vit-gpt2-image-captioning/cpu/cpu/image-to-text_fp32_config_decoder.jsonexamples/recipes/nlpconnect_vit-gpt2-image-captioning/cpu/cpu/image-to-text_fp16_config_encoder.jsonexamples/recipes/nlpconnect_vit-gpt2-image-captioning/cpu/cpu/image-to-text_fp16_config_decoder.jsonwinml configemitted the encoder/decoder export, optimizer, loader, and null quant/compile sections unchanged. The only recipe delta is an explicit, checkpoint-specific L3 dataset declaration:priyank-m/SROIE_2019_text_recognitiontestimage-> input,text-> labelPrecision remains an explicit build argument (
--precision fp32/--precision fp16); emitted initializer dtypes were verified rather than inferred from filenames.2. Precision and EP coverage
Host provider snapshot:
["AzureExecutionProvider", "CPUExecutionProvider"].All 26 required tuples remain explicit. No accelerator recipe or runtime claim is fabricated.
3. Current-main baseline
Without any recipe, current main auto-expanded the model into both composite halves and built them on CPU FP32:
Result: PASS; encoder and decoder artifacts emitted. L0 is inherited from main, so validation climbed through L3.
Current-main
winml inspect --format jsondid not pass: it crashed withTypeError: Object of type ViTConfig is not JSON serializable. The fix usesjson.dumps(default=...), converts enums and paths, and invokes structuredto_dict()objects without naming this model or architecture. Post-fix inspect emits valid JSON withcomposite.pipeline_tasks=["image-to-text"]and encoder/decoder components.4. Artifact inventory
All four models pass
onnx.checker.check_model;.onnxand.onnx.dataare co-located. Encoder outputencoder_hidden_states [1,197,768]matches the decoder cross-attention input.5. Goal ladder
No higher tier was skipped and the historical decoder-L2 deferral is removed.
6. Performance
CPU FP16 is a storage/compatibility coverage claim, not a speedup claim.
7. Numerical parity
8. L3 evaluation
Both precisions used the same shuffled 20-sample SROIE test subset (seed 42):
The metrics are reported as observed; the checkpoint is a natural-image captioner evaluated on receipt OCR, so this run proves end-to-end task execution and precision consistency rather than dataset suitability.
9. Static all-EP analysis
FP32 encoder: 366 operators / 11 unique. NvTensorRTRTX, QNN GPU/NPU, and OpenVINO CPU/GPU/NPU classify all 366 supported. CPU, DML, MIGraphX, CUDA, and VitisAI have no matching rule data and remain unknown.
FP32 decoder: 803 operators / 22 unique. NvTensorRTRTX and OpenVINO classify 778 supported / 25 unknown; QNN NPU classifies 777 supported / 4 partial / 25 unknown; QNN GPU classifies 764 supported / 16 partial / 1 unsupported / 25 unknown. Rule analysis is static and is not presented as runtime validation.
10. Optimum and fix classification
Optimum covers the user-facing
vision-encoder-decoderimage-to-text path. WinML already provides split encoder and static-KV decoder overrides. The recipes are per-checkpoint deployment declarations, while the inspect failure is a class-wide shared-infrastructure bug: any inspect result containing a nested object withto_dict()could fail JSON output. Therefore the contribution correctly includes a generalized code fix and a no-model-hardcoding regression test.Claimed tiers: Effort L2 / Goal L3 / Outcome L2.
11. Tests
All four recipe files also pass
python -m json.tool;git diff --checkpasses.12. Methodology and historical replacement
This replaces historical #934 with current-main evidence. The old PR edited the production README, covered only FP32, deferred decoder L2, and stopped L3 at the missing-default-dataset error. This rebuild leaves the README untouched, validates genuine FP16, supplies an explicit real dataset, closes both decoder parity and L3, and fixes the generalized inspect failure discovered by current-main diagnostics.
Independent pre-PR review verdict: APPROVE, coverage partial only because the host exposes CPU runtime; all blocked accelerator precision tuples remain enumerated above.