@camstack/addon-pipeline 1.2.333 → 1.2.335
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/THIRD_PARTY_MODELS.md +3 -8
- package/dist/audio-analyzer/index.js +2 -2
- package/dist/audio-analyzer/index.mjs +2 -2
- package/dist/{default-detection-model-CDffuH2m.mjs → custom-model-catalog-Buehc666.mjs} +518 -179
- package/dist/{default-detection-model-Biwf5-ML.js → custom-model-catalog-CL-xJa8w.js} +529 -178
- package/dist/detection-pipeline/index.js +186 -120
- package/dist/detection-pipeline/index.mjs +135 -69
- package/dist/{dist-DJV7Z6Bb.js → dist-C5DlS_lW.js} +214 -22
- package/dist/{dist-BsT15i7i.mjs → dist-CPhDwlSN.mjs} +203 -23
- package/dist/motion-wasm/index.js +1 -1
- package/dist/motion-wasm/index.mjs +1 -1
- package/dist/{node-CkmucLYG.js → node-BUafKArW.js} +1 -1
- package/dist/{node-Crsi_8ea.mjs → node-DYfEOwjW.mjs} +1 -1
- package/dist/pipeline-runner/index.js +248 -44
- package/dist/pipeline-runner/index.mjs +226 -22
- package/dist/{process-memory-BJb7Ihdp.js → process-memory-DWOQCbg5.js} +1 -1
- package/dist/{process-memory-1mAUV8S1.mjs → process-memory-WPRYnN8c.mjs} +1 -1
- package/dist/recorder/index.js +2 -2
- package/dist/recorder/index.mjs +2 -2
- package/dist/{segment-demux-js-mK9IBGLf.js → segment-demux-js-DWIgUPW1.js} +1 -1
- package/dist/{segment-demux-js-B_tboBcJ.mjs → segment-demux-js-Kz4EnmOr.mjs} +1 -1
- package/dist/stream-broker/_stub.js +1 -1
- package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-a3HMFtd5.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-RPk9F8CY.mjs} +2 -2
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-1Y-WK-Zy.mjs +26 -0
- package/dist/stream-broker/demux-worker-child.js +1 -1
- package/dist/stream-broker/demux-worker-child.mjs +1 -1
- package/dist/stream-broker/{hostInit-DChPnZ5C.mjs → hostInit-DXXdQdLd.mjs} +2 -2
- package/dist/stream-broker/index.js +3 -3
- package/dist/stream-broker/index.mjs +3 -3
- package/dist/stream-broker/remoteEntry.js +1 -1
- package/package.json +1 -1
- package/python/inference_pool.py +52 -2
- package/python/postprocessors/test_yolo_seg_root.py +109 -0
- package/python/postprocessors/yolo.py +52 -13
- package/python/postprocessors/yolo_seg.py +79 -156
- package/python/test_inference_pool_ov_precision.py +98 -0
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DPbj3ML4.mjs +0 -26
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const require_dist = require("./dist-
|
|
1
|
+
const require_dist = require("./dist-C5DlS_lW.js");
|
|
2
2
|
const require_worker_protocol = require("./worker-protocol-C-G8qmye.js");
|
|
3
3
|
let node_crypto = require("node:crypto");
|
|
4
4
|
//#region src/detection-pipeline/registry/effective-confidence.ts
|
|
@@ -290,7 +290,7 @@ var ovFormat = (url, sizeMB) => {
|
|
|
290
290
|
var ovPrecisionVariant = (baseId, ovDir, baseName, precision, sizeMB, legacy = false) => ({
|
|
291
291
|
id: `${baseId}-${precision}`,
|
|
292
292
|
name: `${baseName} (${precision.toUpperCase()})`,
|
|
293
|
-
description: `${baseName} — OpenVINO ${precision.toUpperCase()} variant for Intel iGPU/NPU; scale by hardware`,
|
|
293
|
+
description: precision === "int8" ? `${baseName} — OpenVINO INT8 variant for Intel iGPU/CPU; scale by hardware. On the Intel NPU it loses recall — use the base model there` : `${baseName} — OpenVINO ${precision.toUpperCase()} variant for Intel iGPU/NPU; scale by hardware`,
|
|
294
294
|
inputSize: {
|
|
295
295
|
width: 640,
|
|
296
296
|
height: 640
|
|
@@ -326,9 +326,11 @@ var YOLOV9_TIER_NAME = {
|
|
|
326
326
|
};
|
|
327
327
|
/**
|
|
328
328
|
* The Ultralytics YOLOv9 family (COCO-pretrained Ultralytics weights,
|
|
329
|
-
* re-exported by CamStack — not trained by us) — the NPU-detection line.
|
|
330
|
-
*
|
|
331
|
-
* on the
|
|
329
|
+
* re-exported by CamStack — not trained by us) — the default NPU-detection line.
|
|
330
|
+
* It runs on the Intel NPU ("AI Boost"), and its INT8 builds are as accurate
|
|
331
|
+
* there as on the CPU. YOLO26 runs on the NPU too since OpenVINO 2025.4
|
|
332
|
+
* (measured 2026-10-07): its base IRs match the CPU, its INT8 IRs lose recall
|
|
333
|
+
* there (see `yolo26Reduced`). Empirically: the yolov9t-320-int8 export = ~298 fps on the
|
|
332
334
|
* NPU vs yolo26n = 103 on the iGPU (~2.9×). t/s/m/c × {320,640}; each size ships
|
|
333
335
|
* a base entry (onnx + coreml + openvino **fp16**) + an OpenVINO **int8** entry
|
|
334
336
|
* (the NPU/iGPU-optimal config). CoreML (fp16) runs on the Mac ANE — the
|
|
@@ -344,7 +346,7 @@ var yolov9Reduced = (tier, res, sizes) => {
|
|
|
344
346
|
resolution: res
|
|
345
347
|
},
|
|
346
348
|
name: `YOLOv9 ${name} @${res}`,
|
|
347
|
-
description: `YOLOv9 ${name} @${res}×${res} (Ultralytics) — OpenVINO fp16, runs on Intel NPU + iGPU
|
|
349
|
+
description: `YOLOv9 ${name} @${res}×${res} (Ultralytics) — OpenVINO fp16, runs on Intel NPU + iGPU.`,
|
|
348
350
|
inputSize: {
|
|
349
351
|
width: res,
|
|
350
352
|
height: res
|
|
@@ -394,6 +396,11 @@ var yolov9Reduced = (tier, res, sizes) => {
|
|
|
394
396
|
* grouped under `{family, tier, resolution}`, plus an OpenVINO INT8 entry (best
|
|
395
397
|
* on Intel/N100) grouped with `precision:'int8'`. The grouped selector surfaces
|
|
396
398
|
* `resolution` as a variant axis alongside precision.
|
|
399
|
+
*
|
|
400
|
+
* Intel NPU (OpenVINO 2025.4, measured 2026-10-07): every YOLO26 IR compiles
|
|
401
|
+
* and runs. The base IRs are as accurate as the CPU; the INT8 IRs lose recall
|
|
402
|
+
* there (`yolo26s-int8` 0.58 on the NPU vs 0.70 on CPU/iGPU, `yolo26m-int8`
|
|
403
|
+
* 0.78 vs 0.83), so on an NPU the base IR is the one to run.
|
|
397
404
|
*/
|
|
398
405
|
var yolo26Reduced = (tier, res, sizes) => {
|
|
399
406
|
const name = YOLO26_TIER_NAME[tier] ?? tier.toUpperCase();
|
|
@@ -436,7 +443,7 @@ var yolo26Reduced = (tier, res, sizes) => {
|
|
|
436
443
|
resolution: res
|
|
437
444
|
},
|
|
438
445
|
name: `YOLO26 ${name} @${res} (INT8)`,
|
|
439
|
-
description: `YOLO26 ${name} @${res} — OpenVINO INT8 for Intel iGPU/CPU; the N100's fastest config`,
|
|
446
|
+
description: `YOLO26 ${name} @${res} — OpenVINO INT8 for Intel iGPU/CPU; the N100's fastest config. On the Intel NPU it loses recall — use the base model there`,
|
|
440
447
|
inputSize: {
|
|
441
448
|
width: res,
|
|
442
449
|
height: res
|
|
@@ -447,7 +454,11 @@ var yolo26Reduced = (tier, res, sizes) => {
|
|
|
447
454
|
formats: { openvino: ovFormat(hf(`objectDetection/yolo26/openvino/camstack-yolo26${tier}-${res}-int8.xml`), sizes.ovInt8) }
|
|
448
455
|
}];
|
|
449
456
|
};
|
|
450
|
-
|
|
457
|
+
/** Variant family of the YOLO26 builds with an instance-segmentation head. */
|
|
458
|
+
var YOLO26_SEG_FAMILY = "yolo26-seg";
|
|
459
|
+
/** What choosing a seg build as the root means, in the catalog's own words. */
|
|
460
|
+
var YOLO26_SEG_ROOT_NOTE = "As the root model it detects like YOLO26 and also supplies the Segmentation step its masks (detection + masks, slightly heavier).";
|
|
461
|
+
var OBJECT_DETECTION_MODEL_ENTRIES = [
|
|
451
462
|
{
|
|
452
463
|
id: "yolo26n",
|
|
453
464
|
license: ULTRALYTICS_AGPL,
|
|
@@ -617,6 +628,102 @@ var OBJECT_DETECTION_MODELS = [
|
|
|
617
628
|
runtimes: ["python"]
|
|
618
629
|
} }
|
|
619
630
|
},
|
|
631
|
+
{
|
|
632
|
+
id: "yolo26n-seg",
|
|
633
|
+
license: licensed(ULTRALYTICS_AGPL, { modifications: "exported to ONNX, OpenVINO IR and CoreML" }),
|
|
634
|
+
group: {
|
|
635
|
+
family: YOLO26_SEG_FAMILY,
|
|
636
|
+
tier: "n",
|
|
637
|
+
resolution: 640
|
|
638
|
+
},
|
|
639
|
+
name: "YOLO26-seg Nano",
|
|
640
|
+
description: `YOLO26 Nano with its instance-segmentation head — ultra-lightweight. ${YOLO26_SEG_ROOT_NOTE}`,
|
|
641
|
+
inputSize: {
|
|
642
|
+
width: 640,
|
|
643
|
+
height: 640
|
|
644
|
+
},
|
|
645
|
+
labels: [],
|
|
646
|
+
preprocessMode: "letterbox",
|
|
647
|
+
postprocessor: "yolo-seg",
|
|
648
|
+
formats: {
|
|
649
|
+
onnx: {
|
|
650
|
+
url: hf("segmentation/yolo26-seg/onnx/camstack-yolo26n-seg.onnx"),
|
|
651
|
+
sizeMB: 11
|
|
652
|
+
},
|
|
653
|
+
coreml: {
|
|
654
|
+
url: hf("segmentation/yolo26-seg/coreml/camstack-yolo26n-seg.mlpackage"),
|
|
655
|
+
sizeMB: 6,
|
|
656
|
+
isDirectory: true,
|
|
657
|
+
files: [...MLPACKAGE_FILES],
|
|
658
|
+
runtimes: ["python"]
|
|
659
|
+
},
|
|
660
|
+
openvino: ovFormat(hf("segmentation/yolo26-seg/openvino/camstack-yolo26n-seg.xml"), 11)
|
|
661
|
+
}
|
|
662
|
+
},
|
|
663
|
+
{
|
|
664
|
+
id: "yolo26s-seg",
|
|
665
|
+
license: licensed(ULTRALYTICS_AGPL, { modifications: "exported to ONNX, OpenVINO IR and CoreML" }),
|
|
666
|
+
group: {
|
|
667
|
+
family: YOLO26_SEG_FAMILY,
|
|
668
|
+
tier: "s",
|
|
669
|
+
resolution: 640
|
|
670
|
+
},
|
|
671
|
+
name: "YOLO26-seg Small",
|
|
672
|
+
description: `YOLO26 Small with its instance-segmentation head — balanced. ${YOLO26_SEG_ROOT_NOTE}`,
|
|
673
|
+
inputSize: {
|
|
674
|
+
width: 640,
|
|
675
|
+
height: 640
|
|
676
|
+
},
|
|
677
|
+
labels: [],
|
|
678
|
+
preprocessMode: "letterbox",
|
|
679
|
+
postprocessor: "yolo-seg",
|
|
680
|
+
formats: {
|
|
681
|
+
onnx: {
|
|
682
|
+
url: hf("segmentation/yolo26-seg/onnx/camstack-yolo26s-seg.onnx"),
|
|
683
|
+
sizeMB: 40
|
|
684
|
+
},
|
|
685
|
+
coreml: {
|
|
686
|
+
url: hf("segmentation/yolo26-seg/coreml/camstack-yolo26s-seg.mlpackage"),
|
|
687
|
+
sizeMB: 20,
|
|
688
|
+
isDirectory: true,
|
|
689
|
+
files: [...MLPACKAGE_FILES],
|
|
690
|
+
runtimes: ["python"]
|
|
691
|
+
},
|
|
692
|
+
openvino: ovFormat(hf("segmentation/yolo26-seg/openvino/camstack-yolo26s-seg.xml"), 40)
|
|
693
|
+
}
|
|
694
|
+
},
|
|
695
|
+
{
|
|
696
|
+
id: "yolo26m-seg",
|
|
697
|
+
license: licensed(ULTRALYTICS_AGPL, { modifications: "exported to ONNX, OpenVINO IR and CoreML" }),
|
|
698
|
+
group: {
|
|
699
|
+
family: YOLO26_SEG_FAMILY,
|
|
700
|
+
tier: "m",
|
|
701
|
+
resolution: 640
|
|
702
|
+
},
|
|
703
|
+
name: "YOLO26-seg Medium",
|
|
704
|
+
description: `YOLO26 Medium with its instance-segmentation head — high accuracy. ${YOLO26_SEG_ROOT_NOTE}`,
|
|
705
|
+
inputSize: {
|
|
706
|
+
width: 640,
|
|
707
|
+
height: 640
|
|
708
|
+
},
|
|
709
|
+
labels: [],
|
|
710
|
+
preprocessMode: "letterbox",
|
|
711
|
+
postprocessor: "yolo-seg",
|
|
712
|
+
formats: {
|
|
713
|
+
onnx: {
|
|
714
|
+
url: hf("segmentation/yolo26-seg/onnx/camstack-yolo26m-seg.onnx"),
|
|
715
|
+
sizeMB: 90
|
|
716
|
+
},
|
|
717
|
+
coreml: {
|
|
718
|
+
url: hf("segmentation/yolo26-seg/coreml/camstack-yolo26m-seg.mlpackage"),
|
|
719
|
+
sizeMB: 45,
|
|
720
|
+
isDirectory: true,
|
|
721
|
+
files: [...MLPACKAGE_FILES],
|
|
722
|
+
runtimes: ["python"]
|
|
723
|
+
},
|
|
724
|
+
openvino: ovFormat(hf("segmentation/yolo26-seg/openvino/camstack-yolo26m-seg.xml"), 90)
|
|
725
|
+
}
|
|
726
|
+
},
|
|
620
727
|
ovPrecisionVariant("yolo26n", "objectDetection/yolo26/openvino", "YOLO26 Nano", "fp16", 5, true),
|
|
621
728
|
ovPrecisionVariant("yolo26n", "objectDetection/yolo26/openvino", "YOLO26 Nano", "int8", 3),
|
|
622
729
|
ovPrecisionVariant("yolo26s", "objectDetection/yolo26/openvino", "YOLO26 Small", "fp16", 19, true),
|
|
@@ -724,6 +831,254 @@ var OBJECT_DETECTION_MODELS = [
|
|
|
724
831
|
ovPrecisionVariant("yolo26x", "objectDetection/yolo26/openvino", "YOLO26 XLarge", "fp16", 112, true),
|
|
725
832
|
ovPrecisionVariant("yolo26x", "objectDetection/yolo26/openvino", "YOLO26 XLarge", "int8", 56, true)
|
|
726
833
|
];
|
|
834
|
+
/**
|
|
835
|
+
* The per-class confidence-floor DEFAULTS of each object-detection model
|
|
836
|
+
* (D738), keyed by model id. Applied onto the catalog entries below as
|
|
837
|
+
* `defaultClassFloors`; this is the ONLY place a model's floor is written. A
|
|
838
|
+
* model absent here runs at the step slider's global default
|
|
839
|
+
* (`ObjectDetectionStep.getConfigSchema`: person 0.65, vehicle 0.50, animal
|
|
840
|
+
* 0.50).
|
|
841
|
+
*
|
|
842
|
+
* Measured 2026-10-07 (`docs/benchmarks/model-floors.json`, which also holds
|
|
843
|
+
* precision/recall per class): the floor is the lowest score at which the model
|
|
844
|
+
* makes no more false positives than the production root (`yolov9m-320-int8` at
|
|
845
|
+
* 0.65 / 0.50 / 0.50) on the same 409 hub frames, against an ensemble
|
|
846
|
+
* pseudo-ground-truth, rounded to 0.05, minimum 0.25. Floors carry about
|
|
847
|
+
* +/-0.05-0.10 of noise. Where a floor hinges on a single high-score false
|
|
848
|
+
* positive, the next-lower value the measurement gives is used instead (marked
|
|
849
|
+
* below). A re-measurement replaces the JSON and these rows together; a spec
|
|
850
|
+
* holds them equal.
|
|
851
|
+
*
|
|
852
|
+
* `package` is not calibrated (7 objects in the set) and stays at its global
|
|
853
|
+
* default. Every catalog model NOT listed here (the 256 builds, yolo26 l/x,
|
|
854
|
+
* the seg builds, the fp16 legacy IRs) is untuned and runs at the global
|
|
855
|
+
* defaults.
|
|
856
|
+
*/
|
|
857
|
+
var OBJECT_DETECTION_CLASS_FLOORS = {
|
|
858
|
+
"ssd-mobilenet-v2-coco-edgetpu": {
|
|
859
|
+
person: .6,
|
|
860
|
+
vehicle: .35,
|
|
861
|
+
animal: .4
|
|
862
|
+
},
|
|
863
|
+
yolo26m: {
|
|
864
|
+
person: .4,
|
|
865
|
+
vehicle: .25,
|
|
866
|
+
animal: .3
|
|
867
|
+
},
|
|
868
|
+
"yolo26m-320": {
|
|
869
|
+
person: .7,
|
|
870
|
+
vehicle: .3,
|
|
871
|
+
animal: .4
|
|
872
|
+
},
|
|
873
|
+
"yolo26m-320-int8": {
|
|
874
|
+
person: .6,
|
|
875
|
+
vehicle: .4,
|
|
876
|
+
animal: .3
|
|
877
|
+
},
|
|
878
|
+
"yolo26m-int8": {
|
|
879
|
+
person: .4,
|
|
880
|
+
vehicle: .35,
|
|
881
|
+
animal: .45
|
|
882
|
+
},
|
|
883
|
+
yolo26n: {
|
|
884
|
+
person: .65,
|
|
885
|
+
vehicle: .4,
|
|
886
|
+
animal: .5
|
|
887
|
+
},
|
|
888
|
+
"yolo26n-320": {
|
|
889
|
+
person: .6,
|
|
890
|
+
vehicle: .6,
|
|
891
|
+
animal: .4
|
|
892
|
+
},
|
|
893
|
+
"yolo26n-320-int8": {
|
|
894
|
+
person: .45,
|
|
895
|
+
vehicle: .55,
|
|
896
|
+
animal: .35
|
|
897
|
+
},
|
|
898
|
+
"yolo26n-int8": {
|
|
899
|
+
person: .55,
|
|
900
|
+
vehicle: .3,
|
|
901
|
+
animal: .4
|
|
902
|
+
},
|
|
903
|
+
yolo26s: {
|
|
904
|
+
person: .4,
|
|
905
|
+
vehicle: .45,
|
|
906
|
+
animal: .4
|
|
907
|
+
},
|
|
908
|
+
"yolo26s-320": {
|
|
909
|
+
person: .6,
|
|
910
|
+
vehicle: .45,
|
|
911
|
+
animal: .45
|
|
912
|
+
},
|
|
913
|
+
"yolo26s-320-int8": {
|
|
914
|
+
person: .5,
|
|
915
|
+
vehicle: .55,
|
|
916
|
+
animal: .45
|
|
917
|
+
},
|
|
918
|
+
"yolo26s-int8": {
|
|
919
|
+
person: .4,
|
|
920
|
+
vehicle: .3,
|
|
921
|
+
animal: .4
|
|
922
|
+
},
|
|
923
|
+
"yolov9c-320": {
|
|
924
|
+
person: .7,
|
|
925
|
+
vehicle: .45,
|
|
926
|
+
animal: .45
|
|
927
|
+
},
|
|
928
|
+
"yolov9c-320-int8": {
|
|
929
|
+
person: .7,
|
|
930
|
+
vehicle: .5,
|
|
931
|
+
animal: .25
|
|
932
|
+
},
|
|
933
|
+
"yolov9c-640": {
|
|
934
|
+
person: .55,
|
|
935
|
+
vehicle: .45,
|
|
936
|
+
animal: .3
|
|
937
|
+
},
|
|
938
|
+
"yolov9c-640-int8": {
|
|
939
|
+
person: .45,
|
|
940
|
+
vehicle: .4,
|
|
941
|
+
animal: .3
|
|
942
|
+
},
|
|
943
|
+
"yolov9m-320": {
|
|
944
|
+
person: .7,
|
|
945
|
+
vehicle: .5,
|
|
946
|
+
animal: .55
|
|
947
|
+
},
|
|
948
|
+
"yolov9m-320-int8": {
|
|
949
|
+
person: .65,
|
|
950
|
+
vehicle: .4,
|
|
951
|
+
animal: .45
|
|
952
|
+
},
|
|
953
|
+
"yolov9m-640": {
|
|
954
|
+
person: .6,
|
|
955
|
+
vehicle: .4,
|
|
956
|
+
animal: .55
|
|
957
|
+
},
|
|
958
|
+
"yolov9m-640-int8": {
|
|
959
|
+
person: .55,
|
|
960
|
+
vehicle: .4,
|
|
961
|
+
animal: .7
|
|
962
|
+
},
|
|
963
|
+
"yolov9s-320": {
|
|
964
|
+
person: .7,
|
|
965
|
+
vehicle: .55,
|
|
966
|
+
animal: .4
|
|
967
|
+
},
|
|
968
|
+
"yolov9s-320-int8": {
|
|
969
|
+
person: .7,
|
|
970
|
+
vehicle: .45,
|
|
971
|
+
animal: .4
|
|
972
|
+
},
|
|
973
|
+
"yolov9s-640": {
|
|
974
|
+
person: .7,
|
|
975
|
+
vehicle: .4,
|
|
976
|
+
animal: .6
|
|
977
|
+
},
|
|
978
|
+
"yolov9s-640-int8": {
|
|
979
|
+
person: .5,
|
|
980
|
+
vehicle: .3,
|
|
981
|
+
animal: .55
|
|
982
|
+
},
|
|
983
|
+
"yolov9t-320": {
|
|
984
|
+
person: .55,
|
|
985
|
+
vehicle: .45,
|
|
986
|
+
animal: .3
|
|
987
|
+
},
|
|
988
|
+
"yolov9t-320-int8": {
|
|
989
|
+
person: .55,
|
|
990
|
+
vehicle: .4,
|
|
991
|
+
animal: .3
|
|
992
|
+
},
|
|
993
|
+
"yolov9t-640": {
|
|
994
|
+
person: .65,
|
|
995
|
+
vehicle: .5,
|
|
996
|
+
animal: .5
|
|
997
|
+
},
|
|
998
|
+
"yolov9t-640-int8": {
|
|
999
|
+
person: .6,
|
|
1000
|
+
vehicle: .55,
|
|
1001
|
+
animal: .55
|
|
1002
|
+
}
|
|
1003
|
+
};
|
|
1004
|
+
/**
|
|
1005
|
+
* The floor on the DETECTION score below which a root detector's own fine
|
|
1006
|
+
* label (a species, a vehicle type — the D736 root supply) is not taken (D741).
|
|
1007
|
+
* Keyed by root model, then by the supplied step. Below it the detection keeps
|
|
1008
|
+
* its macro class with no fine label; it is never dropped. A floor of 1 means
|
|
1009
|
+
* "never take this label from this root". A root or step absent here has no
|
|
1010
|
+
* extra floor — the macro floor alone gates the label, as before D741.
|
|
1011
|
+
*
|
|
1012
|
+
* Measured 2026-10-07 (`docs/benchmarks/classifier-floors.json`): the
|
|
1013
|
+
* lowest detection score from which the root's species was right ~90% of the
|
|
1014
|
+
* time, against a two-model zero-shot reference on 219 animal crops dominated
|
|
1015
|
+
* by one dog. Unlisted roots behave alike — ~0.89-0.90 at the macro floor for
|
|
1016
|
+
* 640 roots, ~0.74 for 320 roots. Vehicle types needed no extra floor on any
|
|
1017
|
+
* root (0.99-1.00 at the macro floor). The Coral SSD named the species wrongly
|
|
1018
|
+
* three times in four.
|
|
1019
|
+
*/
|
|
1020
|
+
var ROOT_SUPPLIED_LABEL_FLOORS = {
|
|
1021
|
+
"yolov9m-320-int8": { "animal-classifier": .75 },
|
|
1022
|
+
"yolov9m-640-int8": { "animal-classifier": .7 },
|
|
1023
|
+
"yolov9c-640-int8": { "animal-classifier": .75 },
|
|
1024
|
+
yolo26s: { "animal-classifier": .45 },
|
|
1025
|
+
yolo26m: { "animal-classifier": .7 },
|
|
1026
|
+
"yolo26s-int8": { "animal-classifier": .55 },
|
|
1027
|
+
"ssd-mobilenet-v2-coco-edgetpu": { "animal-classifier": 1 }
|
|
1028
|
+
};
|
|
1029
|
+
/** Stamp each entry's row of `floors` on it as `suppliedLabelFloors`. Fresh objects only. */
|
|
1030
|
+
function withSuppliedLabelFloors(entries, floors) {
|
|
1031
|
+
return entries.map((entry) => {
|
|
1032
|
+
const row = floors[entry.id];
|
|
1033
|
+
return row === void 0 ? entry : {
|
|
1034
|
+
...entry,
|
|
1035
|
+
suppliedLabelFloors: { ...row }
|
|
1036
|
+
};
|
|
1037
|
+
});
|
|
1038
|
+
}
|
|
1039
|
+
/** Stamp each entry's row of `floors` on it as `defaultClassFloors`. Fresh objects only. */
|
|
1040
|
+
function withDefaultClassFloors(entries, floors) {
|
|
1041
|
+
return entries.map((entry) => {
|
|
1042
|
+
const row = floors[entry.id];
|
|
1043
|
+
return row === void 0 ? entry : {
|
|
1044
|
+
...entry,
|
|
1045
|
+
defaultClassFloors: { ...row }
|
|
1046
|
+
};
|
|
1047
|
+
});
|
|
1048
|
+
}
|
|
1049
|
+
/**
|
|
1050
|
+
* Object-detection IRs that need f32 inference on an Intel GPU
|
|
1051
|
+
* (`gpuInferencePrecision`). At the GPU's default f16 the YOLO26 FP32 IRs of
|
|
1052
|
+
* the larger tiers return no valid detection — measured 2026-10-07 on the Core
|
|
1053
|
+
* Ultra iGPU and the N100: `yolo26s` (640) 0 true / 146 false positives,
|
|
1054
|
+
* `yolo26m` and `yolo26m-320` NaN scores; at f32 they match the CPU, at ~60%
|
|
1055
|
+
* more GPU latency. `yolo26n`, `yolo26n-320` and `yolo26s-320` were measured
|
|
1056
|
+
* correct at f16 and are NOT listed. The rest of the list is the same pattern
|
|
1057
|
+
* not yet measured (tier m / l / x at any input, tier s at 640, the seg builds
|
|
1058
|
+
* of those tiers): f32 costs latency, f16 risks a detector that silently finds
|
|
1059
|
+
* nothing. INT8 IRs and every YOLOv9 IR are correct at the device default.
|
|
1060
|
+
*/
|
|
1061
|
+
var OPENVINO_GPU_F32_MODEL_IDS = new Set([
|
|
1062
|
+
"yolo26s",
|
|
1063
|
+
"yolo26m",
|
|
1064
|
+
"yolo26m-320",
|
|
1065
|
+
"yolo26m-256",
|
|
1066
|
+
"yolo26l",
|
|
1067
|
+
"yolo26l-320",
|
|
1068
|
+
"yolo26l-256",
|
|
1069
|
+
"yolo26x",
|
|
1070
|
+
"yolo26s-seg",
|
|
1071
|
+
"yolo26m-seg"
|
|
1072
|
+
]);
|
|
1073
|
+
/** Stamp `gpuInferencePrecision: 'f32'` on the listed entries. Fresh objects only. */
|
|
1074
|
+
function withGpuF32(entries, ids) {
|
|
1075
|
+
return entries.map((entry) => ids.has(entry.id) ? {
|
|
1076
|
+
...entry,
|
|
1077
|
+
gpuInferencePrecision: "f32"
|
|
1078
|
+
} : entry);
|
|
1079
|
+
}
|
|
1080
|
+
[...OPENVINO_GPU_F32_MODEL_IDS];
|
|
1081
|
+
var OBJECT_DETECTION_MODELS = withSuppliedLabelFloors(withGpuF32(withDefaultClassFloors(OBJECT_DETECTION_MODEL_ENTRIES, OBJECT_DETECTION_CLASS_FLOORS), OPENVINO_GPU_F32_MODEL_IDS), ROOT_SUPPLIED_LABEL_FLOORS);
|
|
727
1082
|
var FACE_DETECTION_MODELS = [{
|
|
728
1083
|
id: "yunet-2023mar",
|
|
729
1084
|
license: YUNET_MIT,
|
|
@@ -739,7 +1094,7 @@ var FACE_DETECTION_MODELS = [{
|
|
|
739
1094
|
}],
|
|
740
1095
|
preprocessMode: "letterbox",
|
|
741
1096
|
postprocessor: "yunet",
|
|
742
|
-
defaultConfidence: .
|
|
1097
|
+
defaultConfidence: .7,
|
|
743
1098
|
formats: {
|
|
744
1099
|
onnx: {
|
|
745
1100
|
url: hf("faceDetection/yunet/onnx/camstack-yunet-2023mar.onnx"),
|
|
@@ -891,7 +1246,8 @@ var ANIMAL_CLASSIFIER_MODELS = [{
|
|
|
891
1246
|
id: "animal-classifier",
|
|
892
1247
|
license: ANIMAL_CLASSIFIER_APACHE,
|
|
893
1248
|
name: "Animal Classifier (8)",
|
|
894
|
-
description: "EfficientNet-Lite0 animal classifier — bird, cat, cow, deer, dog, horse, sheep, squirrel (Open Images V7, publicly distributable)",
|
|
1249
|
+
description: "EfficientNet-Lite0 animal classifier — bird, cat, cow, deer, dog, horse, sheep, squirrel (Open Images V7, publicly distributable). Unreliable on home cameras: it has no reject class, so it names a species for anything it is given, and calls light curly-coated dogs sheep or cat at high confidence. Prefer a root detector that names animals itself.",
|
|
1250
|
+
defaultConfidence: .8,
|
|
895
1251
|
inputSize: {
|
|
896
1252
|
width: 224,
|
|
897
1253
|
height: 224
|
|
@@ -970,6 +1326,7 @@ var VEHICLE_CLASSIFIER_MODELS = [{
|
|
|
970
1326
|
license: VEHICLE_TYPE_V1_NC,
|
|
971
1327
|
name: "Vehicle Type (8)",
|
|
972
1328
|
description: "MobileNetV3-Large vehicle type classifier — Ambulance, Bicycle, Bus, Car, Motorcycle, Taxi, Truck, Van (val 89.4%)",
|
|
1329
|
+
defaultConfidence: .6,
|
|
973
1330
|
inputSize: {
|
|
974
1331
|
width: 224,
|
|
975
1332
|
height: 224
|
|
@@ -1030,86 +1387,13 @@ var SEGMENTATION_REFINER_MODELS = [{
|
|
|
1030
1387
|
openvino: ovFormat(hf("segmentationRefiner/u2netp/openvino/camstack-u2netp.xml"), 2.5)
|
|
1031
1388
|
}
|
|
1032
1389
|
}];
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
width: 640,
|
|
1041
|
-
height: 640
|
|
1042
|
-
},
|
|
1043
|
-
labels: [],
|
|
1044
|
-
preprocessMode: "letterbox",
|
|
1045
|
-
formats: {
|
|
1046
|
-
onnx: {
|
|
1047
|
-
url: hf("segmentation/yolo26-seg/onnx/camstack-yolo26n-seg.onnx"),
|
|
1048
|
-
sizeMB: 11
|
|
1049
|
-
},
|
|
1050
|
-
coreml: {
|
|
1051
|
-
url: hf("segmentation/yolo26-seg/coreml/camstack-yolo26n-seg.mlpackage"),
|
|
1052
|
-
sizeMB: 6,
|
|
1053
|
-
isDirectory: true,
|
|
1054
|
-
files: [...MLPACKAGE_FILES],
|
|
1055
|
-
runtimes: ["python"]
|
|
1056
|
-
},
|
|
1057
|
-
openvino: ovFormat(hf("segmentation/yolo26-seg/openvino/camstack-yolo26n-seg.xml"), 11)
|
|
1058
|
-
}
|
|
1059
|
-
},
|
|
1060
|
-
{
|
|
1061
|
-
id: "yolo26s-seg",
|
|
1062
|
-
license: licensed(ULTRALYTICS_AGPL, { modifications: "exported to ONNX, OpenVINO IR and CoreML" }),
|
|
1063
|
-
name: "YOLO26 Small Seg",
|
|
1064
|
-
description: "YOLO26 Small Segmentation — balanced instance segmentation",
|
|
1065
|
-
inputSize: {
|
|
1066
|
-
width: 640,
|
|
1067
|
-
height: 640
|
|
1068
|
-
},
|
|
1069
|
-
labels: [],
|
|
1070
|
-
preprocessMode: "letterbox",
|
|
1071
|
-
formats: {
|
|
1072
|
-
onnx: {
|
|
1073
|
-
url: hf("segmentation/yolo26-seg/onnx/camstack-yolo26s-seg.onnx"),
|
|
1074
|
-
sizeMB: 40
|
|
1075
|
-
},
|
|
1076
|
-
coreml: {
|
|
1077
|
-
url: hf("segmentation/yolo26-seg/coreml/camstack-yolo26s-seg.mlpackage"),
|
|
1078
|
-
sizeMB: 20,
|
|
1079
|
-
isDirectory: true,
|
|
1080
|
-
files: [...MLPACKAGE_FILES],
|
|
1081
|
-
runtimes: ["python"]
|
|
1082
|
-
},
|
|
1083
|
-
openvino: ovFormat(hf("segmentation/yolo26-seg/openvino/camstack-yolo26s-seg.xml"), 40)
|
|
1084
|
-
}
|
|
1085
|
-
},
|
|
1086
|
-
{
|
|
1087
|
-
id: "yolo26m-seg",
|
|
1088
|
-
license: licensed(ULTRALYTICS_AGPL, { modifications: "exported to ONNX, OpenVINO IR and CoreML" }),
|
|
1089
|
-
name: "YOLO26 Medium Seg",
|
|
1090
|
-
description: "YOLO26 Medium Segmentation — high-accuracy instance segmentation",
|
|
1091
|
-
inputSize: {
|
|
1092
|
-
width: 640,
|
|
1093
|
-
height: 640
|
|
1094
|
-
},
|
|
1095
|
-
labels: [],
|
|
1096
|
-
preprocessMode: "letterbox",
|
|
1097
|
-
formats: {
|
|
1098
|
-
onnx: {
|
|
1099
|
-
url: hf("segmentation/yolo26-seg/onnx/camstack-yolo26m-seg.onnx"),
|
|
1100
|
-
sizeMB: 90
|
|
1101
|
-
},
|
|
1102
|
-
coreml: {
|
|
1103
|
-
url: hf("segmentation/yolo26-seg/coreml/camstack-yolo26m-seg.mlpackage"),
|
|
1104
|
-
sizeMB: 45,
|
|
1105
|
-
isDirectory: true,
|
|
1106
|
-
files: [...MLPACKAGE_FILES],
|
|
1107
|
-
runtimes: ["python"]
|
|
1108
|
-
},
|
|
1109
|
-
openvino: ovFormat(hf("segmentation/yolo26-seg/openvino/camstack-yolo26m-seg.xml"), 90)
|
|
1110
|
-
}
|
|
1111
|
-
}
|
|
1112
|
-
];
|
|
1390
|
+
/**
|
|
1391
|
+
* The dormant `instance-segmentation` step's catalog: the YOLO26-seg entries of
|
|
1392
|
+
* {@link OBJECT_DETECTION_MODELS}, by reference. One entry per model (D703) —
|
|
1393
|
+
* the artifact lives once, in the root's catalog, where it can be selected as
|
|
1394
|
+
* the camera root and supply the `segmentation` step's masks (D737).
|
|
1395
|
+
*/
|
|
1396
|
+
var INSTANCE_SEGMENTATION_MODELS = OBJECT_DETECTION_MODELS.filter((m) => m.group?.family === YOLO26_SEG_FAMILY);
|
|
1113
1397
|
var CLIP_EMBEDDING_MODELS = [{
|
|
1114
1398
|
id: "siglip2-b16-224",
|
|
1115
1399
|
license: SIGLIP2_APACHE,
|
|
@@ -1215,6 +1499,20 @@ var PipelineStepBase = class {
|
|
|
1215
1499
|
return [];
|
|
1216
1500
|
}
|
|
1217
1501
|
};
|
|
1502
|
+
/**
|
|
1503
|
+
* The GLOBAL per-class confidence floors of the object-detection step — what a
|
|
1504
|
+
* model that declares no `defaultClassFloors` row runs at (D738). Tuned on the
|
|
1505
|
+
* YOLOv9 root; see the person slider for the measurement behind 0.65.
|
|
1506
|
+
*/
|
|
1507
|
+
var GLOBAL_CLASS_FLOORS = {
|
|
1508
|
+
person: .65,
|
|
1509
|
+
vehicle: .5,
|
|
1510
|
+
animal: .5
|
|
1511
|
+
};
|
|
1512
|
+
/** The model's own default floor for `macroClass`, else the global one (D738). */
|
|
1513
|
+
function classFloorDefault(model, macroClass, globalFloor) {
|
|
1514
|
+
return model?.defaultClassFloors?.[macroClass] ?? globalFloor;
|
|
1515
|
+
}
|
|
1218
1516
|
var ObjectDetectionStep = class {
|
|
1219
1517
|
definition = {
|
|
1220
1518
|
id: "object-detection",
|
|
@@ -1237,7 +1535,7 @@ var ObjectDetectionStep = class {
|
|
|
1237
1535
|
labels: require_dist.COCO_80_LABELS.map((l) => l.id),
|
|
1238
1536
|
classMap: require_dist.COCO_TO_MACRO
|
|
1239
1537
|
};
|
|
1240
|
-
getConfigSchema() {
|
|
1538
|
+
getConfigSchema(model) {
|
|
1241
1539
|
return [
|
|
1242
1540
|
{
|
|
1243
1541
|
type: "multiselect",
|
|
@@ -1272,7 +1570,8 @@ var ObjectDetectionStep = class {
|
|
|
1272
1570
|
min: 0,
|
|
1273
1571
|
max: 1,
|
|
1274
1572
|
step: .05,
|
|
1275
|
-
default: .
|
|
1573
|
+
default: classFloorDefault(model, "person", GLOBAL_CLASS_FLOORS.person),
|
|
1574
|
+
bindsToModel: true,
|
|
1276
1575
|
showValue: true
|
|
1277
1576
|
},
|
|
1278
1577
|
{
|
|
@@ -1294,7 +1593,8 @@ var ObjectDetectionStep = class {
|
|
|
1294
1593
|
min: 0,
|
|
1295
1594
|
max: 1,
|
|
1296
1595
|
step: .05,
|
|
1297
|
-
default: .
|
|
1596
|
+
default: classFloorDefault(model, "vehicle", GLOBAL_CLASS_FLOORS.vehicle),
|
|
1597
|
+
bindsToModel: true,
|
|
1298
1598
|
showValue: true
|
|
1299
1599
|
},
|
|
1300
1600
|
{
|
|
@@ -1305,7 +1605,8 @@ var ObjectDetectionStep = class {
|
|
|
1305
1605
|
min: 0,
|
|
1306
1606
|
max: 1,
|
|
1307
1607
|
step: .05,
|
|
1308
|
-
default: .
|
|
1608
|
+
default: classFloorDefault(model, "animal", GLOBAL_CLASS_FLOORS.animal),
|
|
1609
|
+
bindsToModel: true,
|
|
1309
1610
|
showValue: true
|
|
1310
1611
|
},
|
|
1311
1612
|
{
|
|
@@ -1391,7 +1692,7 @@ var AnimalClassifierStep = class {
|
|
|
1391
1692
|
labelTier: 1,
|
|
1392
1693
|
models: [...ANIMAL_CLASSIFIER_MODELS],
|
|
1393
1694
|
defaultModelId: "animal-classifier",
|
|
1394
|
-
enabledByDefault:
|
|
1695
|
+
enabledByDefault: true,
|
|
1395
1696
|
defaultConfidence: .5,
|
|
1396
1697
|
labels: [...ANIMAL_10_LABELS],
|
|
1397
1698
|
cadence: {
|
|
@@ -1417,6 +1718,7 @@ var AnimalClassifierStep = class {
|
|
|
1417
1718
|
label: "Min Confidence",
|
|
1418
1719
|
description: "Drop classifications whose score is below this threshold.",
|
|
1419
1720
|
default: resolveModelDefaultConfidence(this.definition, model),
|
|
1721
|
+
bindsToModel: true,
|
|
1420
1722
|
min: 0,
|
|
1421
1723
|
max: 1,
|
|
1422
1724
|
step: .05,
|
|
@@ -1458,6 +1760,7 @@ var PackageDetectionStep = class extends PipelineStepBase {
|
|
|
1458
1760
|
max: 1,
|
|
1459
1761
|
step: .05,
|
|
1460
1762
|
default: resolveModelDefaultConfidence(this.definition, model),
|
|
1763
|
+
bindsToModel: true,
|
|
1461
1764
|
showValue: true
|
|
1462
1765
|
}];
|
|
1463
1766
|
}
|
|
@@ -1470,6 +1773,7 @@ var ClassifierWithMinConfidence = class extends PipelineStepBase {
|
|
|
1470
1773
|
label: "Min Confidence",
|
|
1471
1774
|
description: "Drop classifications whose score is below this threshold.",
|
|
1472
1775
|
default: resolveModelDefaultConfidence(this.definition, model),
|
|
1776
|
+
bindsToModel: true,
|
|
1473
1777
|
min: 0,
|
|
1474
1778
|
max: 1,
|
|
1475
1779
|
step: .05,
|
|
@@ -1570,6 +1874,7 @@ var STEP_FACE_EMBEDDING = new FaceEmbeddingStep({
|
|
|
1570
1874
|
defaultModelId: "auraface-r100",
|
|
1571
1875
|
modelScope: "cluster",
|
|
1572
1876
|
defaultConfidence: 0,
|
|
1877
|
+
defaultMinParentScore: .85,
|
|
1573
1878
|
cadence: {
|
|
1574
1879
|
trigger: "improve",
|
|
1575
1880
|
minIntervalMs: 1e3,
|
|
@@ -1705,7 +2010,7 @@ var STEP_VEHICLE_CLASSIFIER = new VehicleClassifierStep({
|
|
|
1705
2010
|
labelTier: 1,
|
|
1706
2011
|
models: [...VEHICLE_CLASSIFIER_MODELS],
|
|
1707
2012
|
defaultModelId: "vehicle-type-v1",
|
|
1708
|
-
enabledByDefault:
|
|
2013
|
+
enabledByDefault: true,
|
|
1709
2014
|
defaultConfidence: .5,
|
|
1710
2015
|
cadence: {
|
|
1711
2016
|
trigger: "once",
|
|
@@ -2959,6 +3264,122 @@ function rootObjectGate(steps) {
|
|
|
2959
3264
|
return (steps?.find((s) => s.enabled !== false))?.settings;
|
|
2960
3265
|
}
|
|
2961
3266
|
//#endregion
|
|
3267
|
+
//#region src/detection-pipeline/default-detection-model.ts
|
|
3268
|
+
/** The object-detection step id — the only slot this resolver applies to. */
|
|
3269
|
+
var OBJECT_DETECTION_STEP_ID = "object-detection";
|
|
3270
|
+
/**
|
|
3271
|
+
* Balanced default object-detection model per accelerator class. `'cpu'` maps to
|
|
3272
|
+
* `null` → the caller substitutes the step's own `defaultModelId` (`yolo26n`).
|
|
3273
|
+
* INTEL NPU + iGPU default to the Ultralytics YOLOv9 re-export (int8 @320), which
|
|
3274
|
+
* runs on both (~298 fps measured on the NPU). YOLO26 also runs on the NPU since
|
|
3275
|
+
* OpenVINO 2025.4 (its base IRs as accurately as the CPU, its INT8 IRs with lost
|
|
3276
|
+
* recall) and is an operator pick there, not the default. Apple ANE uses the
|
|
3277
|
+
* CoreML yolov9 @320 build.
|
|
3278
|
+
*
|
|
3279
|
+
* Do **not** promote these ids to `yolov9m-640` / `*-640`. The controlled
|
|
3280
|
+
* evaluation recovered 0/3 misses at the current 0.50 threshold and failed the
|
|
3281
|
+
* false-positive and capacity gates — see
|
|
3282
|
+
* `docs/benchmarks/pipeline-frame-model-eval.md`. 640 remains an explicit
|
|
3283
|
+
* operator pick, not a hardware-aware default.
|
|
3284
|
+
*/
|
|
3285
|
+
var MODEL_BY_CLASS = {
|
|
3286
|
+
"apple-ane": "yolov9m-320",
|
|
3287
|
+
"intel-npu": "yolov9m-320-int8",
|
|
3288
|
+
"intel-gpu": "yolov9m-320-int8",
|
|
3289
|
+
cpu: null
|
|
3290
|
+
};
|
|
3291
|
+
/**
|
|
3292
|
+
* Classify a node's engine into an {@link AcceleratorClass} from its resolved
|
|
3293
|
+
* `backend` + `device`. Pure, total, never throws.
|
|
3294
|
+
*
|
|
3295
|
+
* OpenVINO's default device is `'auto'` (the python pool resolves NPU > GPU >
|
|
3296
|
+
* CPU at load). Because OpenVINO is only ever OFFERED when an Intel iGPU is
|
|
3297
|
+
* present, the GPU is the guaranteed accelerator while the NPU is an explicit
|
|
3298
|
+
* opt-in — so `'auto'` (and any non-cpu/non-npu device) is treated as
|
|
3299
|
+
* GPU-class conservatively. An operator who explicitly pins `device: 'npu'`
|
|
3300
|
+
* gets the NPU-tuned m-320.
|
|
3301
|
+
*
|
|
3302
|
+
* Also accepts the accelerator carried in the `backend` slot (e.g. `'ane'`,
|
|
3303
|
+
* `'mps'`, `'npu'`, `'intel-gpu'`) so a caller passing a device-style backend
|
|
3304
|
+
* still classifies correctly — real callers pass onnx/openvino/coreml.
|
|
3305
|
+
*/
|
|
3306
|
+
function classifyAccelerator(backend, device) {
|
|
3307
|
+
const b = backend.toLowerCase();
|
|
3308
|
+
const d = device?.toLowerCase() ?? null;
|
|
3309
|
+
if (b === "coreml" || b === "ane" || b === "mps") return "apple-ane";
|
|
3310
|
+
if (b === "openvino") {
|
|
3311
|
+
if (d === "npu") return "intel-npu";
|
|
3312
|
+
if (d === "cpu") return "cpu";
|
|
3313
|
+
return "intel-gpu";
|
|
3314
|
+
}
|
|
3315
|
+
if (b === "npu" || b === "intel-npu") return "intel-npu";
|
|
3316
|
+
if (b === "gpu" || b === "intel-gpu" || b === "gpu-openvino") return "intel-gpu";
|
|
3317
|
+
return "cpu";
|
|
3318
|
+
}
|
|
3319
|
+
/**
|
|
3320
|
+
* Resolve the hardware-aware default object-detection model id for a node's
|
|
3321
|
+
* engine `(backend, device, format)`.
|
|
3322
|
+
*
|
|
3323
|
+
* Guarantees:
|
|
3324
|
+
* - never throws (hot default-tree path);
|
|
3325
|
+
* - never returns a model id without a build for `format` (unless the step
|
|
3326
|
+
* has ZERO builds for `format`, which is unloadable regardless of pick and
|
|
3327
|
+
* flagged by `collectZeroBuildIssues`) — an unmapped backend, a `'cpu'`
|
|
3328
|
+
* class, a mapped id missing from the catalog, or a mapped id without a
|
|
3329
|
+
* `format` build all fall back to the step's PER-FORMAT default
|
|
3330
|
+
* (`getDefaultModelForFormatFromDef`), NOT the bare `defaultModelId`.
|
|
3331
|
+
*
|
|
3332
|
+
* `getStepDef` is injectable (defaults to the real catalog lookup) so the
|
|
3333
|
+
* missing-build fallback branch is unit-testable without a live catalog —
|
|
3334
|
+
* mirrors `collectZeroBuildIssues`' injection seam.
|
|
3335
|
+
*/
|
|
3336
|
+
function resolveDefaultDetectionModel(backend, device, format, getStepDef = getStepDefinition) {
|
|
3337
|
+
let def;
|
|
3338
|
+
try {
|
|
3339
|
+
def = getStepDef(OBJECT_DETECTION_STEP_ID);
|
|
3340
|
+
} catch {
|
|
3341
|
+
return "yolo26n";
|
|
3342
|
+
}
|
|
3343
|
+
const candidate = MODEL_BY_CLASS[classifyAccelerator(backend, device)];
|
|
3344
|
+
if (candidate !== null) {
|
|
3345
|
+
const entry = def.models.find((m) => m.id === candidate);
|
|
3346
|
+
if (entry && entry.formats[format] !== void 0) return candidate;
|
|
3347
|
+
}
|
|
3348
|
+
return getDefaultModelForFormatFromDef(def, format);
|
|
3349
|
+
}
|
|
3350
|
+
//#endregion
|
|
3351
|
+
//#region src/detection-pipeline/engine/resolve-device-engine.ts
|
|
3352
|
+
/**
|
|
3353
|
+
* Resolve a Phase-1 device key (`<backend>:<device>`, or bare `cpu`) into the
|
|
3354
|
+
* {@link PipelineEngineChoice} used to build that device's inference pool.
|
|
3355
|
+
* Throws on an unknown backend token so a bad `deviceKey` fails loud rather
|
|
3356
|
+
* than silently building a wrong pool. Format comes from the shared
|
|
3357
|
+
* {@link DEVICE_BACKEND_TO_FORMAT} SSOT (`@camstack/types`) — no local copy.
|
|
3358
|
+
*/
|
|
3359
|
+
function resolveDeviceEngine(deviceKey) {
|
|
3360
|
+
const colon = deviceKey.indexOf(":");
|
|
3361
|
+
const backend = colon >= 0 ? deviceKey.slice(0, colon) : deviceKey;
|
|
3362
|
+
const device = colon >= 0 ? deviceKey.slice(colon + 1) : deviceKey;
|
|
3363
|
+
const format = require_dist.DEVICE_BACKEND_TO_FORMAT[backend];
|
|
3364
|
+
if (format === void 0) throw new Error(`resolveDeviceEngine: unknown backend "${backend}" in deviceKey "${deviceKey}"`);
|
|
3365
|
+
return {
|
|
3366
|
+
runtime: "python",
|
|
3367
|
+
backend,
|
|
3368
|
+
format,
|
|
3369
|
+
device
|
|
3370
|
+
};
|
|
3371
|
+
}
|
|
3372
|
+
/**
|
|
3373
|
+
* The inverse of {@link resolveDeviceEngine}: the `<backend>:<device>` key that
|
|
3374
|
+
* names the pool an engine belongs to. Every pool-level log line carries this —
|
|
3375
|
+
* without it a default pool logs anonymously and six hours of logs cannot tell
|
|
3376
|
+
* "the NPU is unused" from "the NPU IS the anonymous default pool".
|
|
3377
|
+
* Falls back to the bare backend when the engine carries no device.
|
|
3378
|
+
*/
|
|
3379
|
+
function deviceKeyOf(engine) {
|
|
3380
|
+
return engine.device ? `${engine.backend}:${engine.device}` : engine.backend;
|
|
3381
|
+
}
|
|
3382
|
+
//#endregion
|
|
2962
3383
|
//#region src/pipeline-runner/device-jump.ts
|
|
2963
3384
|
/**
|
|
2964
3385
|
* Step-tree device jump (same-node, phase 1) — the PURE resolution core.
|
|
@@ -3268,88 +3689,6 @@ var CustomModelCatalog = class {
|
|
|
3268
3689
|
stepDefinition = (stepId) => mergedStepDefinition(stepId, this.byStep);
|
|
3269
3690
|
};
|
|
3270
3691
|
//#endregion
|
|
3271
|
-
//#region src/detection-pipeline/default-detection-model.ts
|
|
3272
|
-
/** The object-detection step id — the only slot this resolver applies to. */
|
|
3273
|
-
var OBJECT_DETECTION_STEP_ID = "object-detection";
|
|
3274
|
-
/**
|
|
3275
|
-
* Balanced default object-detection model per accelerator class. `'cpu'` maps to
|
|
3276
|
-
* `null` → the caller substitutes the step's own `defaultModelId` (`yolo26n`).
|
|
3277
|
-
* INTEL NPU + iGPU default to the Ultralytics YOLOv9 re-export (int8 @320): yolo26 does NOT compile on
|
|
3278
|
-
* the Intel NPU (arch incompat → 0 frames), while yolov9 runs on it (~298 fps
|
|
3279
|
-
* measured). Apple ANE uses the CoreML yolov9 @320 build.
|
|
3280
|
-
*
|
|
3281
|
-
* Do **not** promote these ids to `yolov9m-640` / `*-640`. The controlled
|
|
3282
|
-
* evaluation recovered 0/3 misses at the current 0.50 threshold and failed the
|
|
3283
|
-
* false-positive and capacity gates — see
|
|
3284
|
-
* `docs/benchmarks/pipeline-frame-model-eval.md`. 640 remains an explicit
|
|
3285
|
-
* operator pick, not a hardware-aware default.
|
|
3286
|
-
*/
|
|
3287
|
-
var MODEL_BY_CLASS = {
|
|
3288
|
-
"apple-ane": "yolov9m-320",
|
|
3289
|
-
"intel-npu": "yolov9m-320-int8",
|
|
3290
|
-
"intel-gpu": "yolov9m-320-int8",
|
|
3291
|
-
cpu: null
|
|
3292
|
-
};
|
|
3293
|
-
/**
|
|
3294
|
-
* Classify a node's engine into an {@link AcceleratorClass} from its resolved
|
|
3295
|
-
* `backend` + `device`. Pure, total, never throws.
|
|
3296
|
-
*
|
|
3297
|
-
* OpenVINO's default device is `'auto'` (the python pool resolves NPU > GPU >
|
|
3298
|
-
* CPU at load). Because OpenVINO is only ever OFFERED when an Intel iGPU is
|
|
3299
|
-
* present, the GPU is the guaranteed accelerator while the NPU is an explicit
|
|
3300
|
-
* opt-in — so `'auto'` (and any non-cpu/non-npu device) is treated as
|
|
3301
|
-
* GPU-class conservatively. An operator who explicitly pins `device: 'npu'`
|
|
3302
|
-
* gets the NPU-tuned m-320.
|
|
3303
|
-
*
|
|
3304
|
-
* Also accepts the accelerator carried in the `backend` slot (e.g. `'ane'`,
|
|
3305
|
-
* `'mps'`, `'npu'`, `'intel-gpu'`) so a caller passing a device-style backend
|
|
3306
|
-
* still classifies correctly — real callers pass onnx/openvino/coreml.
|
|
3307
|
-
*/
|
|
3308
|
-
function classifyAccelerator(backend, device) {
|
|
3309
|
-
const b = backend.toLowerCase();
|
|
3310
|
-
const d = device?.toLowerCase() ?? null;
|
|
3311
|
-
if (b === "coreml" || b === "ane" || b === "mps") return "apple-ane";
|
|
3312
|
-
if (b === "openvino") {
|
|
3313
|
-
if (d === "npu") return "intel-npu";
|
|
3314
|
-
if (d === "cpu") return "cpu";
|
|
3315
|
-
return "intel-gpu";
|
|
3316
|
-
}
|
|
3317
|
-
if (b === "npu" || b === "intel-npu") return "intel-npu";
|
|
3318
|
-
if (b === "gpu" || b === "intel-gpu" || b === "gpu-openvino") return "intel-gpu";
|
|
3319
|
-
return "cpu";
|
|
3320
|
-
}
|
|
3321
|
-
/**
|
|
3322
|
-
* Resolve the hardware-aware default object-detection model id for a node's
|
|
3323
|
-
* engine `(backend, device, format)`.
|
|
3324
|
-
*
|
|
3325
|
-
* Guarantees:
|
|
3326
|
-
* - never throws (hot default-tree path);
|
|
3327
|
-
* - never returns a model id without a build for `format` (unless the step
|
|
3328
|
-
* has ZERO builds for `format`, which is unloadable regardless of pick and
|
|
3329
|
-
* flagged by `collectZeroBuildIssues`) — an unmapped backend, a `'cpu'`
|
|
3330
|
-
* class, a mapped id missing from the catalog, or a mapped id without a
|
|
3331
|
-
* `format` build all fall back to the step's PER-FORMAT default
|
|
3332
|
-
* (`getDefaultModelForFormatFromDef`), NOT the bare `defaultModelId`.
|
|
3333
|
-
*
|
|
3334
|
-
* `getStepDef` is injectable (defaults to the real catalog lookup) so the
|
|
3335
|
-
* missing-build fallback branch is unit-testable without a live catalog —
|
|
3336
|
-
* mirrors `collectZeroBuildIssues`' injection seam.
|
|
3337
|
-
*/
|
|
3338
|
-
function resolveDefaultDetectionModel(backend, device, format, getStepDef = getStepDefinition) {
|
|
3339
|
-
let def;
|
|
3340
|
-
try {
|
|
3341
|
-
def = getStepDef(OBJECT_DETECTION_STEP_ID);
|
|
3342
|
-
} catch {
|
|
3343
|
-
return "yolo26n";
|
|
3344
|
-
}
|
|
3345
|
-
const candidate = MODEL_BY_CLASS[classifyAccelerator(backend, device)];
|
|
3346
|
-
if (candidate !== null) {
|
|
3347
|
-
const entry = def.models.find((m) => m.id === candidate);
|
|
3348
|
-
if (entry && entry.formats[format] !== void 0) return candidate;
|
|
3349
|
-
}
|
|
3350
|
-
return getDefaultModelForFormatFromDef(def, format);
|
|
3351
|
-
}
|
|
3352
|
-
//#endregion
|
|
3353
3692
|
Object.defineProperty(exports, "ALL_PIPELINE_STEPS", {
|
|
3354
3693
|
enumerable: true,
|
|
3355
3694
|
get: function() {
|
|
@@ -3386,6 +3725,12 @@ Object.defineProperty(exports, "createSessionDecodeCoordinator", {
|
|
|
3386
3725
|
return createSessionDecodeCoordinator;
|
|
3387
3726
|
}
|
|
3388
3727
|
});
|
|
3728
|
+
Object.defineProperty(exports, "deviceKeyOf", {
|
|
3729
|
+
enumerable: true,
|
|
3730
|
+
get: function() {
|
|
3731
|
+
return deviceKeyOf;
|
|
3732
|
+
}
|
|
3733
|
+
});
|
|
3389
3734
|
Object.defineProperty(exports, "getDefaultModelForFormat", {
|
|
3390
3735
|
enumerable: true,
|
|
3391
3736
|
get: function() {
|
|
@@ -3446,6 +3791,12 @@ Object.defineProperty(exports, "resolveDefaultDetectionModel", {
|
|
|
3446
3791
|
return resolveDefaultDetectionModel;
|
|
3447
3792
|
}
|
|
3448
3793
|
});
|
|
3794
|
+
Object.defineProperty(exports, "resolveDeviceEngine", {
|
|
3795
|
+
enumerable: true,
|
|
3796
|
+
get: function() {
|
|
3797
|
+
return resolveDeviceEngine;
|
|
3798
|
+
}
|
|
3799
|
+
});
|
|
3449
3800
|
Object.defineProperty(exports, "resolveFrameViewGeometry", {
|
|
3450
3801
|
enumerable: true,
|
|
3451
3802
|
get: function() {
|