Commit 26fcc88
fix(perf): support composite (dual-encoder) models in winml perf (#866)
## Problem
`winml perf` crashed on composite (dual-encoder) models such as
SigLIP/CLIP:
```
winml perf --ep openvino --device cpu -m google/siglip-base-patch16-224 \
--task zero-shot-image-classification
...
AttributeError: 'WinMLModelForZeroShotImageClassification' object has no attribute 'io_config'
```
`PerfBenchmark` assumed every model exposes a single `io_config` /
`_session`. Composite
models have neither — they orchestrate multiple sub-models (e.g. an
image encoder and a
text encoder), each with its own ONNX session. The failure is
device-independent: the
`(model_type, task)` registry routes SigLIP to the composite class
regardless of `--device`.
## Fix
Benchmark each sub-model **individually** — the same way `--module`
benchmarks each
submodule — instead of timing the aggregate `forward()` pass:
- **`run()`** returns a single `BenchmarkResult` for single-session
models, or a
`{sub_model_name: BenchmarkResult}` mapping for composites.
- **`_run_sub_models()`** iterates `sub_models` and benchmarks each
through the standard
single-session pipeline by spawning a child `PerfBenchmark` with the
already-loaded
sub-model. Every sub-model reuses the existing compile /
input-generation / simple +
monitored loops / result-collection code, so per-sub-model measurement
semantics match
single-model runs exactly (pure-ORT time inside `session.perf()`).
- Each sub-model reports **its own** I/O, task, device, and EP — no
aggregation.
- **`report_composite_results()`** renders a per-sub-model summary table
and writes one
combined JSON nesting each sub-model's full `BenchmarkResult.to_dict()`
under
`components` (`model_id`, `task`, `component_count`, `components`).
This removes the previous aggregate machinery (`_aggregate_io_config`,
`_describe_outputs`, `_probe_composite_outputs`,
`_composite_run_iteration`) and the
composite branches inside the benchmark loops.
`_is_composite` stays duck-typed on `sub_models` (rather than
`isinstance(..., WinMLCompositeModel)`) on purpose: an `isinstance`
check needs a runtime
import of `composite_model`, which imports torch and would blow the
`winml perf --help`
import budget (`tests/cli/test_import_time.py`). Keeping
`WinMLCompositeModel` a
TYPE_CHECKING-only import also lets the unit tests use lightweight
duck-typed fakes.
## Result
```
Sub-model: image-encoder
Device: cpu / OpenVINOExecutionProvider
Task: image-feature-extraction
Inputs: pixel_values [1, 3, 224, 224] float32
Outputs: last_hidden_state [1, 196, 768]
pooler_output [1, 768]
Sub-model: text-encoder
Device: cpu / OpenVINOExecutionProvider
Task: feature-extraction
Inputs: input_ids [1, 64] int32
Outputs: last_hidden_state [1, 64, 768]
pooler_output [1, 768]
Per-Sub-Model Perf
┏━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┓
┃ Sub-Model ┃ Task ┃ Device ┃ Mean (ms) ┃ P90 (ms) ┃ Min (ms) ┃ Max (ms) ┃
┡━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━┩
│ image-encoder │ image-feature-extraction │ cpu / OpenVINOExecutionProvider │ 81.14 │ 104.97 │ 63.49 │ 124.89 │
│ text-encoder │ feature-extraction │ cpu / OpenVINOExecutionProvider │ 39.19 │ 51.89 │ 24.99 │ 109.08 │
└───────────────┴──────────────────────────┴─────────────────────────────────┴───────────┴──────────┴──────────┴──────────┘
```
## Tests
`tests/unit/commands/test_perf_composite.py` is rewritten for the
per-sub-model behavior:
each sub-model produces its own `BenchmarkResult` with its own I/O /
task / device / EP,
every sub-session is compiled and run `warmup + iterations` times, and
`report_composite_results` emits the combined per-component JSON (and
JSON-mode stdout).
Existing `test_perf_cli.py` and `test_perf_optracing_cli.py` still pass
— no regression.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: hualxie <hualxie@microsoft.com>1 parent 58d135e commit 26fcc88
4 files changed
Lines changed: 599 additions & 30 deletions
File tree
- src/winml/modelkit
- commands
- models
- tests/unit/commands
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
19 | 19 | | |
20 | 20 | | |
21 | 21 | | |
22 | | - | |
| 22 | + | |
23 | 23 | | |
24 | 24 | | |
25 | 25 | | |
| |||
34 | 34 | | |
35 | 35 | | |
36 | 36 | | |
| 37 | + | |
37 | 38 | | |
38 | 39 | | |
39 | 40 | | |
| |||
292 | 293 | | |
293 | 294 | | |
294 | 295 | | |
295 | | - | |
| 296 | + | |
296 | 297 | | |
297 | 298 | | |
298 | | - | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
299 | 339 | | |
300 | 340 | | |
301 | 341 | | |
302 | | - | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
303 | 347 | | |
304 | 348 | | |
305 | 349 | | |
306 | 350 | | |
307 | 351 | | |
308 | 352 | | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
309 | 386 | | |
310 | 387 | | |
311 | 388 | | |
312 | 389 | | |
313 | 390 | | |
314 | | - | |
| 391 | + | |
315 | 392 | | |
316 | 393 | | |
317 | 394 | | |
318 | | - | |
319 | | - | |
| 395 | + | |
| 396 | + | |
320 | 397 | | |
321 | | - | |
322 | | - | |
| 398 | + | |
| 399 | + | |
323 | 400 | | |
324 | 401 | | |
325 | 402 | | |
| |||
392 | 469 | | |
393 | 470 | | |
394 | 471 | | |
395 | | - | |
396 | | - | |
397 | 472 | | |
398 | | - | |
| 473 | + | |
399 | 474 | | |
400 | 475 | | |
401 | 476 | | |
| |||
407 | 482 | | |
408 | 483 | | |
409 | 484 | | |
410 | | - | |
411 | 485 | | |
412 | | - | |
413 | 486 | | |
414 | 487 | | |
| 488 | + | |
415 | 489 | | |
416 | 490 | | |
417 | 491 | | |
| |||
429 | 503 | | |
430 | 504 | | |
431 | 505 | | |
432 | | - | |
433 | 506 | | |
434 | | - | |
435 | 507 | | |
436 | 508 | | |
437 | 509 | | |
| |||
445 | 517 | | |
446 | 518 | | |
447 | 519 | | |
448 | | - | |
| 520 | + | |
| 521 | + | |
449 | 522 | | |
450 | 523 | | |
451 | 524 | | |
452 | | - | |
| 525 | + | |
453 | 526 | | |
454 | 527 | | |
455 | 528 | | |
456 | 529 | | |
457 | 530 | | |
458 | | - | |
| 531 | + | |
459 | 532 | | |
460 | 533 | | |
461 | 534 | | |
462 | 535 | | |
463 | 536 | | |
464 | 537 | | |
| 538 | + | |
465 | 539 | | |
466 | 540 | | |
467 | 541 | | |
| |||
488 | 562 | | |
489 | 563 | | |
490 | 564 | | |
491 | | - | |
492 | | - | |
| 565 | + | |
493 | 566 | | |
494 | 567 | | |
495 | 568 | | |
| |||
528 | 601 | | |
529 | 602 | | |
530 | 603 | | |
531 | | - | |
532 | | - | |
533 | | - | |
534 | | - | |
| 604 | + | |
| 605 | + | |
| 606 | + | |
| 607 | + | |
535 | 608 | | |
536 | 609 | | |
537 | 610 | | |
| |||
551 | 624 | | |
552 | 625 | | |
553 | 626 | | |
| 627 | + | |
554 | 628 | | |
555 | 629 | | |
556 | 630 | | |
| |||
574 | 648 | | |
575 | 649 | | |
576 | 650 | | |
577 | | - | |
| 651 | + | |
| 652 | + | |
578 | 653 | | |
579 | 654 | | |
580 | 655 | | |
| |||
670 | 745 | | |
671 | 746 | | |
672 | 747 | | |
673 | | - | |
| 748 | + | |
| 749 | + | |
674 | 750 | | |
675 | 751 | | |
| 752 | + | |
676 | 753 | | |
677 | 754 | | |
678 | 755 | | |
| |||
908 | 985 | | |
909 | 986 | | |
910 | 987 | | |
| 988 | + | |
| 989 | + | |
| 990 | + | |
| 991 | + | |
| 992 | + | |
| 993 | + | |
| 994 | + | |
| 995 | + | |
| 996 | + | |
| 997 | + | |
| 998 | + | |
| 999 | + | |
| 1000 | + | |
| 1001 | + | |
| 1002 | + | |
| 1003 | + | |
| 1004 | + | |
| 1005 | + | |
| 1006 | + | |
| 1007 | + | |
| 1008 | + | |
| 1009 | + | |
| 1010 | + | |
| 1011 | + | |
| 1012 | + | |
| 1013 | + | |
| 1014 | + | |
| 1015 | + | |
| 1016 | + | |
| 1017 | + | |
| 1018 | + | |
| 1019 | + | |
| 1020 | + | |
| 1021 | + | |
| 1022 | + | |
| 1023 | + | |
| 1024 | + | |
| 1025 | + | |
| 1026 | + | |
| 1027 | + | |
| 1028 | + | |
| 1029 | + | |
| 1030 | + | |
| 1031 | + | |
| 1032 | + | |
| 1033 | + | |
| 1034 | + | |
| 1035 | + | |
| 1036 | + | |
| 1037 | + | |
| 1038 | + | |
| 1039 | + | |
| 1040 | + | |
| 1041 | + | |
| 1042 | + | |
| 1043 | + | |
| 1044 | + | |
| 1045 | + | |
| 1046 | + | |
| 1047 | + | |
| 1048 | + | |
| 1049 | + | |
| 1050 | + | |
| 1051 | + | |
| 1052 | + | |
| 1053 | + | |
| 1054 | + | |
| 1055 | + | |
911 | 1056 | | |
912 | 1057 | | |
913 | 1058 | | |
| |||
1260 | 1405 | | |
1261 | 1406 | | |
1262 | 1407 | | |
| 1408 | + | |
1263 | 1409 | | |
1264 | 1410 | | |
1265 | 1411 | | |
| |||
1343 | 1489 | | |
1344 | 1490 | | |
1345 | 1491 | | |
| 1492 | + | |
| 1493 | + | |
| 1494 | + | |
| 1495 | + | |
| 1496 | + | |
| 1497 | + | |
| 1498 | + | |
| 1499 | + | |
| 1500 | + | |
| 1501 | + | |
| 1502 | + | |
| 1503 | + | |
| 1504 | + | |
| 1505 | + | |
| 1506 | + | |
| 1507 | + | |
| 1508 | + | |
| 1509 | + | |
| 1510 | + | |
| 1511 | + | |
1346 | 1512 | | |
1347 | 1513 | | |
1348 | 1514 | | |
| |||
1374 | 1540 | | |
1375 | 1541 | | |
1376 | 1542 | | |
1377 | | - | |
1378 | | - | |
1379 | | - | |
| 1543 | + | |
1380 | 1544 | | |
1381 | 1545 | | |
1382 | 1546 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
164 | 164 | | |
165 | 165 | | |
166 | 166 | | |
| 167 | + | |
167 | 168 | | |
168 | 169 | | |
169 | 170 | | |
| |||
376 | 377 | | |
377 | 378 | | |
378 | 379 | | |
| 380 | + | |
379 | 381 | | |
380 | 382 | | |
381 | 383 | | |
| |||
0 commit comments