mblt-vision-python 0.0.0__py3-none-any.whl
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.
- mblt_vision/__init__.py +86 -0
- mblt_vision/_api.py +53 -0
- mblt_vision/_compat.py +227 -0
- mblt_vision/_model_paths.py +137 -0
- mblt_vision/_tasks.py +30 -0
- mblt_vision/benchmark/__init__.py +1 -0
- mblt_vision/benchmark/argparse_utils.py +106 -0
- mblt_vision/benchmark/chart_utils.py +146 -0
- mblt_vision/benchmark/io_utils.py +64 -0
- mblt_vision/benchmark/summary_utils.py +770 -0
- mblt_vision/cli/__init__.py +5 -0
- mblt_vision/cli/__main__.py +5 -0
- mblt_vision/cli/_vision.py +337 -0
- mblt_vision/cli/compile.py +117 -0
- mblt_vision/cli/main.py +35 -0
- mblt_vision/cli/predict.py +64 -0
- mblt_vision/cli/val.py +562 -0
- mblt_vision/compile/__init__.py +21 -0
- mblt_vision/compile/vision.py +1120 -0
- mblt_vision/datasets/__init__.py +15 -0
- mblt_vision/datasets/ade20k.yaml +164 -0
- mblt_vision/datasets/cityscapes.yaml +54 -0
- mblt_vision/datasets/coco.yaml +178 -0
- mblt_vision/datasets/dotav1.yaml +28 -0
- mblt_vision/datasets/imagenet.yaml +1019 -0
- mblt_vision/datasets/imagenet_synsets.txt +1000 -0
- mblt_vision/datasets/nyu-depth.yaml +7 -0
- mblt_vision/datasets/registry.py +158 -0
- mblt_vision/datasets/widerface.yaml +9 -0
- mblt_vision/depth_estimation/__init__.py +19 -0
- mblt_vision/face_detection/__init__.py +43 -0
- mblt_vision/image_classification/__init__.py +311 -0
- mblt_vision/instance_segmentation/__init__.py +65 -0
- mblt_vision/models/AlexNet.yaml +23 -0
- mblt_vision/models/CAFormer_B36.yaml +22 -0
- mblt_vision/models/CAFormer_M36.yaml +22 -0
- mblt_vision/models/CAFormer_S18.yaml +22 -0
- mblt_vision/models/CAFormer_S36.yaml +22 -0
- mblt_vision/models/CoAtNet_0_RW_224.yaml +22 -0
- mblt_vision/models/CoAtNet_1_RW_224.yaml +22 -0
- mblt_vision/models/CoAtNet_2_RW_224.yaml +22 -0
- mblt_vision/models/ConvFormer_B36.yaml +22 -0
- mblt_vision/models/ConvFormer_M36.yaml +22 -0
- mblt_vision/models/ConvFormer_S18.yaml +22 -0
- mblt_vision/models/ConvFormer_S36.yaml +22 -0
- mblt_vision/models/ConvNext_Base.yaml +23 -0
- mblt_vision/models/ConvNext_Large.yaml +23 -0
- mblt_vision/models/ConvNext_Small.yaml +23 -0
- mblt_vision/models/ConvNext_Tiny.yaml +23 -0
- mblt_vision/models/DeiT3_Base_Patch16_224.yaml +22 -0
- mblt_vision/models/DeiT3_Base_Patch16_384.yaml +22 -0
- mblt_vision/models/DeiT3_Large_Patch16_224.yaml +22 -0
- mblt_vision/models/DeiT3_Large_Patch16_384.yaml +22 -0
- mblt_vision/models/DeiT3_Medium_Patch16_224.yaml +22 -0
- mblt_vision/models/DeiT3_Small_Patch16_224.yaml +22 -0
- mblt_vision/models/DeiT3_Small_Patch16_384.yaml +22 -0
- mblt_vision/models/DeiT_Base_Patch16_224.yaml +22 -0
- mblt_vision/models/DeiT_Base_Patch16_384.yaml +22 -0
- mblt_vision/models/DeiT_Small_Patch16_224.yaml +22 -0
- mblt_vision/models/DeiT_Tiny_Patch16_224.yaml +22 -0
- mblt_vision/models/DenseNet121.yaml +23 -0
- mblt_vision/models/DenseNet161.yaml +23 -0
- mblt_vision/models/DenseNet169.yaml +23 -0
- mblt_vision/models/DenseNet201.yaml +23 -0
- mblt_vision/models/EfficientFormer_L1.yaml +22 -0
- mblt_vision/models/EfficientFormer_L3.yaml +22 -0
- mblt_vision/models/EfficientFormer_L7.yaml +22 -0
- mblt_vision/models/EfficientNet_B0.yaml +23 -0
- mblt_vision/models/EfficientNet_B1.yaml +32 -0
- mblt_vision/models/EfficientNet_B2.yaml +23 -0
- mblt_vision/models/EfficientNet_B3.yaml +23 -0
- mblt_vision/models/EfficientNet_B4.yaml +23 -0
- mblt_vision/models/EfficientNet_B5.yaml +23 -0
- mblt_vision/models/EfficientNet_B6.yaml +23 -0
- mblt_vision/models/EfficientNet_B7.yaml +23 -0
- mblt_vision/models/EfficientNet_V2_L.yaml +23 -0
- mblt_vision/models/EfficientNet_V2_M.yaml +23 -0
- mblt_vision/models/EfficientNet_V2_S.yaml +23 -0
- mblt_vision/models/FlexiVit_Base.yaml +22 -0
- mblt_vision/models/FlexiVit_Large.yaml +22 -0
- mblt_vision/models/FlexiVit_Small.yaml +22 -0
- mblt_vision/models/GELANc-seg.yaml +29 -0
- mblt_vision/models/GELANc.yaml +28 -0
- mblt_vision/models/GELANe.yaml +28 -0
- mblt_vision/models/GELANm.yaml +28 -0
- mblt_vision/models/GELANs.yaml +28 -0
- mblt_vision/models/GoogLeNet.yaml +23 -0
- mblt_vision/models/Inception_V3.yaml +23 -0
- mblt_vision/models/LeViT_Conv_128.yaml +22 -0
- mblt_vision/models/LeViT_Conv_128S.yaml +22 -0
- mblt_vision/models/LeViT_Conv_192.yaml +22 -0
- mblt_vision/models/LeViT_Conv_256.yaml +22 -0
- mblt_vision/models/LeViT_Conv_384.yaml +22 -0
- mblt_vision/models/MNASNet0_5.yaml +23 -0
- mblt_vision/models/MNASNet0_75.yaml +23 -0
- mblt_vision/models/MNASNet1_0.yaml +23 -0
- mblt_vision/models/MNASNet1_3.yaml +23 -0
- mblt_vision/models/MobileNet_V2.yaml +32 -0
- mblt_vision/models/MobileNet_V3_Large.yaml +32 -0
- mblt_vision/models/MobileNet_V3_Small.yaml +23 -0
- mblt_vision/models/RegNet_X_16GF.yaml +32 -0
- mblt_vision/models/RegNet_X_1_6GF.yaml +32 -0
- mblt_vision/models/RegNet_X_32GF.yaml +32 -0
- mblt_vision/models/RegNet_X_3_2GF.yaml +32 -0
- mblt_vision/models/RegNet_X_400MF.yaml +32 -0
- mblt_vision/models/RegNet_X_800MF.yaml +32 -0
- mblt_vision/models/RegNet_X_8GF.yaml +32 -0
- mblt_vision/models/RegNet_Y_16GF.yaml +76 -0
- mblt_vision/models/RegNet_Y_1_6GF.yaml +32 -0
- mblt_vision/models/RegNet_Y_32GF.yaml +76 -0
- mblt_vision/models/RegNet_Y_3_2GF.yaml +32 -0
- mblt_vision/models/RegNet_Y_400MF.yaml +32 -0
- mblt_vision/models/RegNet_Y_800MF.yaml +32 -0
- mblt_vision/models/RegNet_Y_8GF.yaml +32 -0
- mblt_vision/models/RepViT_M0_9.yaml +22 -0
- mblt_vision/models/RepViT_M1.yaml +22 -0
- mblt_vision/models/RepViT_M1_0.yaml +22 -0
- mblt_vision/models/RepViT_M1_1.yaml +22 -0
- mblt_vision/models/RepViT_M1_5.yaml +22 -0
- mblt_vision/models/RepViT_M2.yaml +22 -0
- mblt_vision/models/RepViT_M2_3.yaml +22 -0
- mblt_vision/models/RepViT_M3.yaml +22 -0
- mblt_vision/models/ResNeXt101_32X8D.yaml +32 -0
- mblt_vision/models/ResNeXt101_64X4D.yaml +23 -0
- mblt_vision/models/ResNeXt50_32X4D.yaml +32 -0
- mblt_vision/models/ResNet101.yaml +32 -0
- mblt_vision/models/ResNet152.yaml +32 -0
- mblt_vision/models/ResNet18.yaml +23 -0
- mblt_vision/models/ResNet34.yaml +23 -0
- mblt_vision/models/ResNet50.yaml +32 -0
- mblt_vision/models/ShuffleNet_V2_X0_5.yaml +23 -0
- mblt_vision/models/ShuffleNet_V2_X1_0.yaml +23 -0
- mblt_vision/models/ShuffleNet_V2_X1_5.yaml +23 -0
- mblt_vision/models/ShuffleNet_V2_X2_0.yaml +23 -0
- mblt_vision/models/SqueezeNet1_0.yaml +23 -0
- mblt_vision/models/SqueezeNet1_1.yaml +23 -0
- mblt_vision/models/Swin_B.yaml +23 -0
- mblt_vision/models/Swin_S.yaml +23 -0
- mblt_vision/models/Swin_T.yaml +23 -0
- mblt_vision/models/VGG11.yaml +23 -0
- mblt_vision/models/VGG11_BN.yaml +23 -0
- mblt_vision/models/VGG13.yaml +23 -0
- mblt_vision/models/VGG13_BN.yaml +23 -0
- mblt_vision/models/VGG16.yaml +23 -0
- mblt_vision/models/VGG16_BN.yaml +23 -0
- mblt_vision/models/VGG19.yaml +23 -0
- mblt_vision/models/VGG19_BN.yaml +23 -0
- mblt_vision/models/ViT_B_16.yaml +67 -0
- mblt_vision/models/ViT_B_32.yaml +23 -0
- mblt_vision/models/ViT_Base_Patch16_224.yaml +22 -0
- mblt_vision/models/ViT_Base_Patch16_384.yaml +22 -0
- mblt_vision/models/ViT_Base_Patch32_224.yaml +22 -0
- mblt_vision/models/ViT_Base_Patch32_384.yaml +22 -0
- mblt_vision/models/ViT_Base_Patch8_224.yaml +22 -0
- mblt_vision/models/ViT_L_16.yaml +67 -0
- mblt_vision/models/ViT_L_32.yaml +23 -0
- mblt_vision/models/ViT_Large_Patch16_224.yaml +22 -0
- mblt_vision/models/ViT_Large_Patch16_384.yaml +22 -0
- mblt_vision/models/ViT_Large_Patch32_384.yaml +22 -0
- mblt_vision/models/ViT_Small_Patch16_224.yaml +22 -0
- mblt_vision/models/ViT_Small_Patch16_384.yaml +22 -0
- mblt_vision/models/ViT_Small_Patch32_224.yaml +22 -0
- mblt_vision/models/ViT_Small_Patch32_384.yaml +22 -0
- mblt_vision/models/ViT_Tiny_Patch16_224.yaml +22 -0
- mblt_vision/models/ViT_Tiny_Patch16_384.yaml +22 -0
- mblt_vision/models/VisFormer_Small.yaml +22 -0
- mblt_vision/models/VisFormer_Tiny.yaml +22 -0
- mblt_vision/models/Wide_ResNet101_2.yaml +32 -0
- mblt_vision/models/Wide_ResNet50_2.yaml +32 -0
- mblt_vision/models/YOLO11l-cls.yaml +23 -0
- mblt_vision/models/YOLO11l-face.yaml +27 -0
- mblt_vision/models/YOLO11l-obb.yaml +28 -0
- mblt_vision/models/YOLO11l-pose.yaml +28 -0
- mblt_vision/models/YOLO11l-seg.yaml +28 -0
- mblt_vision/models/YOLO11l.yaml +27 -0
- mblt_vision/models/YOLO11m-cls.yaml +23 -0
- mblt_vision/models/YOLO11m-face.yaml +27 -0
- mblt_vision/models/YOLO11m-obb.yaml +28 -0
- mblt_vision/models/YOLO11m-pose.yaml +28 -0
- mblt_vision/models/YOLO11m-seg.yaml +28 -0
- mblt_vision/models/YOLO11m.yaml +27 -0
- mblt_vision/models/YOLO11n-cls.yaml +23 -0
- mblt_vision/models/YOLO11n-face.yaml +27 -0
- mblt_vision/models/YOLO11n-obb.yaml +28 -0
- mblt_vision/models/YOLO11n-pose.yaml +28 -0
- mblt_vision/models/YOLO11n-seg.yaml +28 -0
- mblt_vision/models/YOLO11n.yaml +27 -0
- mblt_vision/models/YOLO11s-cls.yaml +23 -0
- mblt_vision/models/YOLO11s-face.yaml +27 -0
- mblt_vision/models/YOLO11s-obb.yaml +28 -0
- mblt_vision/models/YOLO11s-pose.yaml +28 -0
- mblt_vision/models/YOLO11s-seg.yaml +28 -0
- mblt_vision/models/YOLO11s.yaml +27 -0
- mblt_vision/models/YOLO11x-cls.yaml +23 -0
- mblt_vision/models/YOLO11x-obb.yaml +28 -0
- mblt_vision/models/YOLO11x-pose.yaml +28 -0
- mblt_vision/models/YOLO11x-seg.yaml +28 -0
- mblt_vision/models/YOLO11x.yaml +27 -0
- mblt_vision/models/YOLO12l-face.yaml +27 -0
- mblt_vision/models/YOLO12l-seg.yaml +28 -0
- mblt_vision/models/YOLO12l.yaml +27 -0
- mblt_vision/models/YOLO12m-face.yaml +27 -0
- mblt_vision/models/YOLO12m-seg.yaml +28 -0
- mblt_vision/models/YOLO12m.yaml +27 -0
- mblt_vision/models/YOLO12n-face.yaml +27 -0
- mblt_vision/models/YOLO12n-seg.yaml +28 -0
- mblt_vision/models/YOLO12n.yaml +27 -0
- mblt_vision/models/YOLO12s-face.yaml +27 -0
- mblt_vision/models/YOLO12s-seg.yaml +28 -0
- mblt_vision/models/YOLO12s.yaml +27 -0
- mblt_vision/models/YOLO12x-seg.yaml +28 -0
- mblt_vision/models/YOLO12x.yaml +27 -0
- mblt_vision/models/YOLO26l-cls.yaml +23 -0
- mblt_vision/models/YOLO26l-depth.yaml +17 -0
- mblt_vision/models/YOLO26l-distill.yaml +27 -0
- mblt_vision/models/YOLO26l-obb.yaml +28 -0
- mblt_vision/models/YOLO26l-pose.yaml +28 -0
- mblt_vision/models/YOLO26l-seg.yaml +28 -0
- mblt_vision/models/YOLO26l-sem-ade20k.yaml +17 -0
- mblt_vision/models/YOLO26l-sem.yaml +17 -0
- mblt_vision/models/YOLO26l.yaml +27 -0
- mblt_vision/models/YOLO26m-cls.yaml +23 -0
- mblt_vision/models/YOLO26m-depth.yaml +17 -0
- mblt_vision/models/YOLO26m-distill.yaml +27 -0
- mblt_vision/models/YOLO26m-obb.yaml +28 -0
- mblt_vision/models/YOLO26m-pose.yaml +28 -0
- mblt_vision/models/YOLO26m-seg.yaml +28 -0
- mblt_vision/models/YOLO26m-sem-ade20k.yaml +17 -0
- mblt_vision/models/YOLO26m-sem.yaml +17 -0
- mblt_vision/models/YOLO26m.yaml +27 -0
- mblt_vision/models/YOLO26n-cls.yaml +23 -0
- mblt_vision/models/YOLO26n-depth.yaml +17 -0
- mblt_vision/models/YOLO26n-distill.yaml +27 -0
- mblt_vision/models/YOLO26n-obb.yaml +28 -0
- mblt_vision/models/YOLO26n-pose.yaml +28 -0
- mblt_vision/models/YOLO26n-seg.yaml +28 -0
- mblt_vision/models/YOLO26n-sem-ade20k.yaml +17 -0
- mblt_vision/models/YOLO26n-sem.yaml +17 -0
- mblt_vision/models/YOLO26n.yaml +27 -0
- mblt_vision/models/YOLO26s-cls.yaml +23 -0
- mblt_vision/models/YOLO26s-depth.yaml +17 -0
- mblt_vision/models/YOLO26s-distill.yaml +27 -0
- mblt_vision/models/YOLO26s-obb.yaml +28 -0
- mblt_vision/models/YOLO26s-pose.yaml +28 -0
- mblt_vision/models/YOLO26s-seg.yaml +28 -0
- mblt_vision/models/YOLO26s-sem-ade20k.yaml +17 -0
- mblt_vision/models/YOLO26s-sem.yaml +17 -0
- mblt_vision/models/YOLO26s.yaml +27 -0
- mblt_vision/models/YOLO26x-cls.yaml +23 -0
- mblt_vision/models/YOLO26x-depth.yaml +17 -0
- mblt_vision/models/YOLO26x-distill.yaml +27 -0
- mblt_vision/models/YOLO26x-obb.yaml +28 -0
- mblt_vision/models/YOLO26x-pose.yaml +28 -0
- mblt_vision/models/YOLO26x-seg.yaml +28 -0
- mblt_vision/models/YOLO26x-sem-ade20k.yaml +17 -0
- mblt_vision/models/YOLO26x-sem.yaml +17 -0
- mblt_vision/models/YOLO26x.yaml +27 -0
- mblt_vision/models/YOLOv10b.yaml +28 -0
- mblt_vision/models/YOLOv10l-face.yaml +28 -0
- mblt_vision/models/YOLOv10l.yaml +28 -0
- mblt_vision/models/YOLOv10m-face.yaml +28 -0
- mblt_vision/models/YOLOv10m.yaml +28 -0
- mblt_vision/models/YOLOv10n-face.yaml +28 -0
- mblt_vision/models/YOLOv10n.yaml +28 -0
- mblt_vision/models/YOLOv10s-face.yaml +28 -0
- mblt_vision/models/YOLOv10s.yaml +28 -0
- mblt_vision/models/YOLOv10x.yaml +28 -0
- mblt_vision/models/YOLOv3-spp.yaml +44 -0
- mblt_vision/models/YOLOv3-sppu.yaml +27 -0
- mblt_vision/models/YOLOv3-tiny.yaml +38 -0
- mblt_vision/models/YOLOv3-tinyu.yaml +27 -0
- mblt_vision/models/YOLOv3.yaml +44 -0
- mblt_vision/models/YOLOv3u.yaml +27 -0
- mblt_vision/models/YOLOv5l-cls.yaml +22 -0
- mblt_vision/models/YOLOv5l-seg.yaml +45 -0
- mblt_vision/models/YOLOv5l.yaml +44 -0
- mblt_vision/models/YOLOv5l6.yaml +50 -0
- mblt_vision/models/YOLOv5l6u.yaml +27 -0
- mblt_vision/models/YOLOv5lu.yaml +27 -0
- mblt_vision/models/YOLOv5m-cls.yaml +22 -0
- mblt_vision/models/YOLOv5m-seg.yaml +45 -0
- mblt_vision/models/YOLOv5m.yaml +45 -0
- mblt_vision/models/YOLOv5m6.yaml +50 -0
- mblt_vision/models/YOLOv5m6u.yaml +27 -0
- mblt_vision/models/YOLOv5mu.yaml +27 -0
- mblt_vision/models/YOLOv5n-cls.yaml +22 -0
- mblt_vision/models/YOLOv5n-seg.yaml +45 -0
- mblt_vision/models/YOLOv5n.yaml +44 -0
- mblt_vision/models/YOLOv5n6.yaml +50 -0
- mblt_vision/models/YOLOv5n6u.yaml +27 -0
- mblt_vision/models/YOLOv5nu.yaml +27 -0
- mblt_vision/models/YOLOv5s-cls.yaml +22 -0
- mblt_vision/models/YOLOv5s-seg.yaml +45 -0
- mblt_vision/models/YOLOv5s.yaml +44 -0
- mblt_vision/models/YOLOv5s6.yaml +50 -0
- mblt_vision/models/YOLOv5s6u.yaml +27 -0
- mblt_vision/models/YOLOv5su.yaml +27 -0
- mblt_vision/models/YOLOv5x-cls.yaml +22 -0
- mblt_vision/models/YOLOv5x-seg.yaml +45 -0
- mblt_vision/models/YOLOv5x.yaml +44 -0
- mblt_vision/models/YOLOv5x6.yaml +50 -0
- mblt_vision/models/YOLOv5x6u.yaml +27 -0
- mblt_vision/models/YOLOv5xu.yaml +27 -0
- mblt_vision/models/YOLOv6m-face.yaml +27 -0
- mblt_vision/models/YOLOv6n-face.yaml +27 -0
- mblt_vision/models/YOLOv7.yaml +44 -0
- mblt_vision/models/YOLOv7d6.yaml +50 -0
- mblt_vision/models/YOLOv7e6.yaml +50 -0
- mblt_vision/models/YOLOv7e6e.yaml +50 -0
- mblt_vision/models/YOLOv7w6.yaml +50 -0
- mblt_vision/models/YOLOv7x.yaml +44 -0
- mblt_vision/models/YOLOv8l-cls.yaml +23 -0
- mblt_vision/models/YOLOv8l-face.yaml +27 -0
- mblt_vision/models/YOLOv8l-obb.yaml +28 -0
- mblt_vision/models/YOLOv8l-pose.yaml +28 -0
- mblt_vision/models/YOLOv8l-seg.yaml +28 -0
- mblt_vision/models/YOLOv8l.yaml +27 -0
- mblt_vision/models/YOLOv8m-cls.yaml +23 -0
- mblt_vision/models/YOLOv8m-face.yaml +27 -0
- mblt_vision/models/YOLOv8m-obb.yaml +28 -0
- mblt_vision/models/YOLOv8m-pose.yaml +28 -0
- mblt_vision/models/YOLOv8m-seg.yaml +28 -0
- mblt_vision/models/YOLOv8m.yaml +27 -0
- mblt_vision/models/YOLOv8n-cls.yaml +23 -0
- mblt_vision/models/YOLOv8n-face.yaml +27 -0
- mblt_vision/models/YOLOv8n-obb.yaml +28 -0
- mblt_vision/models/YOLOv8n-pose.yaml +28 -0
- mblt_vision/models/YOLOv8n-seg.yaml +28 -0
- mblt_vision/models/YOLOv8n.yaml +27 -0
- mblt_vision/models/YOLOv8s-cls.yaml +23 -0
- mblt_vision/models/YOLOv8s-obb.yaml +28 -0
- mblt_vision/models/YOLOv8s-pose.yaml +28 -0
- mblt_vision/models/YOLOv8s-seg.yaml +28 -0
- mblt_vision/models/YOLOv8s.yaml +27 -0
- mblt_vision/models/YOLOv8x-cls.yaml +23 -0
- mblt_vision/models/YOLOv8x-obb.yaml +28 -0
- mblt_vision/models/YOLOv8x-pose-p6.yaml +28 -0
- mblt_vision/models/YOLOv8x-pose.yaml +28 -0
- mblt_vision/models/YOLOv8x-seg.yaml +28 -0
- mblt_vision/models/YOLOv8x.yaml +27 -0
- mblt_vision/models/YOLOv9c-seg.yaml +28 -0
- mblt_vision/models/YOLOv9c.yaml +27 -0
- mblt_vision/models/YOLOv9e-seg.yaml +28 -0
- mblt_vision/models/YOLOv9e.yaml +27 -0
- mblt_vision/models/YOLOv9m.yaml +27 -0
- mblt_vision/models/YOLOv9s.yaml +27 -0
- mblt_vision/models/YOLOv9t.yaml +27 -0
- mblt_vision/obb/__init__.py +39 -0
- mblt_vision/object_detection/__init__.py +153 -0
- mblt_vision/pose_estimation/__init__.py +41 -0
- mblt_vision/py.typed +1 -0
- mblt_vision/semantic_segmentation/__init__.py +29 -0
- mblt_vision/utils/__init__.py +0 -0
- mblt_vision/utils/datasets/__init__.py +85 -0
- mblt_vision/utils/datasets/ade20k.py +41 -0
- mblt_vision/utils/datasets/cityscapes.py +66 -0
- mblt_vision/utils/datasets/coco.py +243 -0
- mblt_vision/utils/datasets/dataloader.py +1016 -0
- mblt_vision/utils/datasets/dotav1.py +59 -0
- mblt_vision/utils/datasets/imagenet.py +29 -0
- mblt_vision/utils/datasets/organizer.py +2145 -0
- mblt_vision/utils/datasets/readiness.py +1063 -0
- mblt_vision/utils/evaluation/__init__.py +51 -0
- mblt_vision/utils/evaluation/_result.py +22 -0
- mblt_vision/utils/evaluation/eval_ade20k.py +302 -0
- mblt_vision/utils/evaluation/eval_cityscapes.py +32 -0
- mblt_vision/utils/evaluation/eval_coco.py +465 -0
- mblt_vision/utils/evaluation/eval_dota.py +878 -0
- mblt_vision/utils/evaluation/eval_imagenet.py +151 -0
- mblt_vision/utils/evaluation/eval_nyu_depth.py +189 -0
- mblt_vision/utils/evaluation/eval_widerface.py +440 -0
- mblt_vision/utils/letterbox.py +118 -0
- mblt_vision/utils/postprocess/__init__.py +9 -0
- mblt_vision/utils/postprocess/_letterbox.py +102 -0
- mblt_vision/utils/postprocess/base.py +743 -0
- mblt_vision/utils/postprocess/build_post.py +120 -0
- mblt_vision/utils/postprocess/cls_post.py +117 -0
- mblt_vision/utils/postprocess/common.py +1571 -0
- mblt_vision/utils/postprocess/depth_post.py +106 -0
- mblt_vision/utils/postprocess/semantic_seg_post.py +192 -0
- mblt_vision/utils/postprocess/yolo_anchor_post.py +469 -0
- mblt_vision/utils/postprocess/yolo_anchorless_post.py +952 -0
- mblt_vision/utils/postprocess/yolo_dflfree_post.py +983 -0
- mblt_vision/utils/postprocess/yolo_nmsfree_post.py +176 -0
- mblt_vision/utils/preprocess/__init__.py +27 -0
- mblt_vision/utils/preprocess/_validation.py +66 -0
- mblt_vision/utils/preprocess/base.py +157 -0
- mblt_vision/utils/preprocess/build_pre.py +48 -0
- mblt_vision/utils/preprocess/center_crop.py +75 -0
- mblt_vision/utils/preprocess/letterbox.py +123 -0
- mblt_vision/utils/preprocess/normalize.py +94 -0
- mblt_vision/utils/preprocess/order.py +74 -0
- mblt_vision/utils/preprocess/reader.py +94 -0
- mblt_vision/utils/preprocess/resize.py +202 -0
- mblt_vision/utils/preprocess/yolo_pre.py +7 -0
- mblt_vision/utils/results.py +725 -0
- mblt_vision/utils/types.py +15 -0
- mblt_vision/wrapper.py +1121 -0
- mblt_vision_python-0.0.0.dist-info/METADATA +152 -0
- mblt_vision_python-0.0.0.dist-info/RECORD +404 -0
- mblt_vision_python-0.0.0.dist-info/WHEEL +5 -0
- mblt_vision_python-0.0.0.dist-info/entry_points.txt +2 -0
- mblt_vision_python-0.0.0.dist-info/licenses/LICENSE +28 -0
- mblt_vision_python-0.0.0.dist-info/top_level.txt +1 -0
mblt_vision/wrapper.py
ADDED
|
@@ -0,0 +1,1121 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Wrapper classes for MBLT model execution.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import copy
|
|
8
|
+
import importlib
|
|
9
|
+
import os
|
|
10
|
+
import stat
|
|
11
|
+
import sys
|
|
12
|
+
import tempfile
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from types import TracebackType
|
|
15
|
+
from typing import TYPE_CHECKING, Any, Sequence, cast
|
|
16
|
+
|
|
17
|
+
import numpy as np
|
|
18
|
+
import torch
|
|
19
|
+
import yaml
|
|
20
|
+
from huggingface_hub import hf_hub_download
|
|
21
|
+
from huggingface_hub.errors import EntryNotFoundError
|
|
22
|
+
|
|
23
|
+
from mblt_npu import MobilintNPUBackend, ONNXBackend, normalize_target_device
|
|
24
|
+
from ._model_paths import resolve_framework as _resolve_framework
|
|
25
|
+
from ._model_paths import split_model_paths as _split_model_paths
|
|
26
|
+
from ._model_paths import (
|
|
27
|
+
uses_shifted_engine_model_path_layout as _uses_shifted_engine_model_path_layout,
|
|
28
|
+
)
|
|
29
|
+
from .utils.postprocess import build_postprocess
|
|
30
|
+
from .utils.preprocess import build_preprocess
|
|
31
|
+
from .utils.results import Results
|
|
32
|
+
from .utils.types import TensorLike
|
|
33
|
+
|
|
34
|
+
if TYPE_CHECKING:
|
|
35
|
+
from qbruntime import Cluster, CoreId
|
|
36
|
+
|
|
37
|
+
MODEL_CONFIG_DIR = Path(__file__).parent / "models"
|
|
38
|
+
|
|
39
|
+
ONNXRUNTIME_INSTALL_GUIDE = (
|
|
40
|
+
"onnxruntime is not installed. To use ONNX inference, install one of the optional extras:\n"
|
|
41
|
+
"pip install mblt-vision-python[onnxruntime]\n"
|
|
42
|
+
+ (
|
|
43
|
+
"or\npip install mblt-vision-python[onnxruntime-gpu]"
|
|
44
|
+
if sys.platform != "darwin"
|
|
45
|
+
else ""
|
|
46
|
+
)
|
|
47
|
+
)
|
|
48
|
+
CoreMode = str
|
|
49
|
+
CORE_MODES: tuple[CoreMode, ...] = ("single", "multi", "global4", "global8")
|
|
50
|
+
REGULUS_TARGET_DEVICES = frozenset({"regulus-ra", "regulus-rb"})
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def core_modes_for_target_device(target_device: str) -> tuple[CoreMode, ...]:
|
|
54
|
+
"""Return the Vision core modes supported by a normalized NPU board."""
|
|
55
|
+
|
|
56
|
+
if normalize_target_device(target_device) in REGULUS_TARGET_DEVICES:
|
|
57
|
+
return ("single",)
|
|
58
|
+
return CORE_MODES
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def normalize_core_mode(
|
|
62
|
+
core_mode: str, *, target_device: str | None = None
|
|
63
|
+
) -> CoreMode:
|
|
64
|
+
"""Validate a Vision engine core mode, including board compatibility."""
|
|
65
|
+
|
|
66
|
+
if core_mode not in CORE_MODES:
|
|
67
|
+
raise ValueError(
|
|
68
|
+
f"Invalid core mode '{core_mode}'. Expected one of {list(CORE_MODES)}."
|
|
69
|
+
)
|
|
70
|
+
if target_device is not None:
|
|
71
|
+
normalized_target_device = normalize_target_device(target_device)
|
|
72
|
+
supported_modes = core_modes_for_target_device(normalized_target_device)
|
|
73
|
+
if core_mode not in supported_modes:
|
|
74
|
+
raise ValueError(
|
|
75
|
+
f"Core mode '{core_mode}' is not supported by "
|
|
76
|
+
f"{normalized_target_device}; expected one of {list(supported_modes)}."
|
|
77
|
+
)
|
|
78
|
+
return core_mode
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
__all__ = [
|
|
82
|
+
"CoreMode",
|
|
83
|
+
"core_modes_for_target_device",
|
|
84
|
+
"MOBILINT_CACHE_DIR",
|
|
85
|
+
"get_mobilint_cache_dir",
|
|
86
|
+
"normalize_core_mode",
|
|
87
|
+
"resolve_model_config",
|
|
88
|
+
"MBLT_Engine",
|
|
89
|
+
]
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _derive_onnx_filename(file_cfg: dict[str, Any]) -> str | None:
|
|
93
|
+
"""Return the configured or MXQ-derived ONNX artifact filename.
|
|
94
|
+
|
|
95
|
+
``onnx_filename`` is only required when the Hub ONNX artifact does not share
|
|
96
|
+
the MXQ artifact stem. Otherwise every model configuration follows the same
|
|
97
|
+
``.mxq`` to ``.onnx`` convention.
|
|
98
|
+
"""
|
|
99
|
+
|
|
100
|
+
onnx_filename = file_cfg.get("onnx_filename")
|
|
101
|
+
if isinstance(onnx_filename, str) and onnx_filename:
|
|
102
|
+
return onnx_filename
|
|
103
|
+
|
|
104
|
+
filename = file_cfg.get("filename")
|
|
105
|
+
if not isinstance(filename, str) or not filename:
|
|
106
|
+
return None
|
|
107
|
+
|
|
108
|
+
return f"{Path(filename).stem}.onnx"
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def _normalize_model_artifacts(model_config: dict[str, Any]) -> dict[str, Any]:
|
|
112
|
+
"""Populate the derived ONNX artifact name in a resolved model configuration."""
|
|
113
|
+
|
|
114
|
+
normalized = copy.deepcopy(model_config)
|
|
115
|
+
file_cfg = normalized.get("file_cfg")
|
|
116
|
+
if not isinstance(file_cfg, dict):
|
|
117
|
+
return normalized
|
|
118
|
+
|
|
119
|
+
onnx_filename = _derive_onnx_filename(file_cfg)
|
|
120
|
+
if onnx_filename is not None:
|
|
121
|
+
file_cfg["onnx_filename"] = onnx_filename
|
|
122
|
+
return normalized
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _default_cache_dir() -> str:
|
|
126
|
+
"""Returns a writable cache directory for downloaded vision artifacts."""
|
|
127
|
+
|
|
128
|
+
preferred = Path(os.path.expanduser("~/.mblt_model_zoo"))
|
|
129
|
+
try:
|
|
130
|
+
preferred.mkdir(parents=True, mode=0o700, exist_ok=True)
|
|
131
|
+
preferred_stat = os.lstat(preferred)
|
|
132
|
+
if (
|
|
133
|
+
not stat.S_ISDIR(preferred_stat.st_mode)
|
|
134
|
+
or stat.S_ISLNK(preferred_stat.st_mode)
|
|
135
|
+
or preferred_stat.st_uid != os.getuid()
|
|
136
|
+
or preferred_stat.st_mode & 0o077
|
|
137
|
+
):
|
|
138
|
+
return _fallback_cache_dir()
|
|
139
|
+
with tempfile.NamedTemporaryFile(prefix=".write_test-", dir=preferred):
|
|
140
|
+
pass
|
|
141
|
+
return str(preferred)
|
|
142
|
+
except OSError:
|
|
143
|
+
return _fallback_cache_dir()
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def _fallback_cache_dir() -> str:
|
|
147
|
+
"""Return a stable private fallback cache when the home cache is unavailable."""
|
|
148
|
+
|
|
149
|
+
uid = os.getuid()
|
|
150
|
+
fallback = Path(tempfile.gettempdir()) / f"mblt_model_zoo-{uid}"
|
|
151
|
+
try:
|
|
152
|
+
os.mkdir(fallback, mode=0o700)
|
|
153
|
+
except FileExistsError:
|
|
154
|
+
pass
|
|
155
|
+
except OSError as exc:
|
|
156
|
+
raise RuntimeError(
|
|
157
|
+
f"Unable to create fallback Mobilint cache directory: {fallback}"
|
|
158
|
+
) from exc
|
|
159
|
+
|
|
160
|
+
fallback_stat = os.lstat(fallback)
|
|
161
|
+
if (
|
|
162
|
+
not stat.S_ISDIR(fallback_stat.st_mode)
|
|
163
|
+
or stat.S_ISLNK(fallback_stat.st_mode)
|
|
164
|
+
or fallback_stat.st_uid != uid
|
|
165
|
+
or fallback_stat.st_mode & 0o077
|
|
166
|
+
):
|
|
167
|
+
raise RuntimeError(
|
|
168
|
+
f"Fallback Mobilint cache directory is not a private directory owned by this user: {fallback}"
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
try:
|
|
172
|
+
with tempfile.NamedTemporaryFile(prefix=".write_test-", dir=fallback):
|
|
173
|
+
pass
|
|
174
|
+
except OSError as exc:
|
|
175
|
+
raise RuntimeError(
|
|
176
|
+
f"Fallback Mobilint cache directory is not writable: {fallback}"
|
|
177
|
+
) from exc
|
|
178
|
+
return str(fallback)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
MOBILINT_CACHE_DIR = os.path.expanduser("~/.mblt_model_zoo")
|
|
182
|
+
"""Preferred artifact cache root, without creating it during import."""
|
|
183
|
+
|
|
184
|
+
_resolved_cache_dir: str | None = None
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def get_mobilint_cache_dir() -> str:
|
|
188
|
+
"""Return a writable artifact cache directory, creating it only when needed."""
|
|
189
|
+
|
|
190
|
+
global _resolved_cache_dir
|
|
191
|
+
if _resolved_cache_dir is None:
|
|
192
|
+
_resolved_cache_dir = _default_cache_dir()
|
|
193
|
+
return _resolved_cache_dir
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def _load_onnxruntime() -> Any:
|
|
197
|
+
"""Loads ``onnxruntime`` only when ONNX inference is requested.
|
|
198
|
+
|
|
199
|
+
Returns:
|
|
200
|
+
The imported ``onnxruntime`` module.
|
|
201
|
+
|
|
202
|
+
Raises:
|
|
203
|
+
ImportError: If ``onnxruntime`` is unavailable in the current environment.
|
|
204
|
+
"""
|
|
205
|
+
|
|
206
|
+
try:
|
|
207
|
+
module = importlib.import_module("onnxruntime")
|
|
208
|
+
except ImportError as exc:
|
|
209
|
+
raise ImportError(ONNXRUNTIME_INSTALL_GUIDE) from exc
|
|
210
|
+
|
|
211
|
+
if not hasattr(module, "InferenceSession"):
|
|
212
|
+
module_path = getattr(module, "__file__", None) or "<namespace package>"
|
|
213
|
+
msg = (
|
|
214
|
+
"onnxruntime is installed, but the package is incomplete or broken and does not expose "
|
|
215
|
+
f"`InferenceSession` (resolved from {module_path}). "
|
|
216
|
+
f"{ONNXRUNTIME_INSTALL_GUIDE.replace('is not installed. To use ONNX inference, install', 'Reinstall')}"
|
|
217
|
+
)
|
|
218
|
+
raise ImportError(msg)
|
|
219
|
+
|
|
220
|
+
return module
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def _resolve_onnx_providers(
|
|
224
|
+
ort_module: Any, requested_providers: Sequence[str] | None = None
|
|
225
|
+
) -> list[str]:
|
|
226
|
+
"""Selects ONNX Runtime execution providers.
|
|
227
|
+
|
|
228
|
+
Args:
|
|
229
|
+
ort_module: Imported ``onnxruntime`` module or compatible test double.
|
|
230
|
+
requested_providers: Optional provider order requested by the caller.
|
|
231
|
+
|
|
232
|
+
Returns:
|
|
233
|
+
The provider list passed to ``InferenceSession``.
|
|
234
|
+
"""
|
|
235
|
+
|
|
236
|
+
return (
|
|
237
|
+
list(requested_providers)
|
|
238
|
+
if requested_providers is not None
|
|
239
|
+
else ["CPUExecutionProvider"]
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def _model_name_aliasing(model_name: str) -> str:
|
|
244
|
+
"""Find the YAML filename matching a model name.
|
|
245
|
+
|
|
246
|
+
Args:
|
|
247
|
+
model_name: Model identifier provided by the caller.
|
|
248
|
+
|
|
249
|
+
Returns:
|
|
250
|
+
Exact YAML filename stored in ``MODEL_CONFIG_DIR``.
|
|
251
|
+
|
|
252
|
+
Raises:
|
|
253
|
+
ValueError: If no YAML file matches or the normalized name is ambiguous.
|
|
254
|
+
"""
|
|
255
|
+
|
|
256
|
+
def _stem(name: str) -> str:
|
|
257
|
+
return name[: -len(".yaml")] if name.lower().endswith(".yaml") else name
|
|
258
|
+
|
|
259
|
+
def _normalize_separators(name: str) -> str:
|
|
260
|
+
return "_".join(
|
|
261
|
+
part
|
|
262
|
+
for part in _stem(name)
|
|
263
|
+
.replace("-", "_")
|
|
264
|
+
.replace(" ", "_")
|
|
265
|
+
.lower()
|
|
266
|
+
.split("_")
|
|
267
|
+
if part
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
requested = _normalize_separators(model_name)
|
|
271
|
+
config_names = sorted(path.name for path in MODEL_CONFIG_DIR.glob("*.yaml"))
|
|
272
|
+
separator_matches = [
|
|
273
|
+
name for name in config_names if _normalize_separators(name) == requested
|
|
274
|
+
]
|
|
275
|
+
if len(separator_matches) == 1:
|
|
276
|
+
return separator_matches[0]
|
|
277
|
+
if len(separator_matches) > 1:
|
|
278
|
+
raise ValueError(
|
|
279
|
+
f"Ambiguous model name '{model_name}'. Matches: {separator_matches}."
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
compact_requested = requested.replace("_", "")
|
|
283
|
+
compact_matches = [
|
|
284
|
+
name
|
|
285
|
+
for name in config_names
|
|
286
|
+
if _normalize_separators(name).replace("_", "") == compact_requested
|
|
287
|
+
]
|
|
288
|
+
if len(compact_matches) == 1:
|
|
289
|
+
return compact_matches[0]
|
|
290
|
+
if len(compact_matches) > 1:
|
|
291
|
+
raise ValueError(
|
|
292
|
+
f"Ambiguous model name '{model_name}'. Matches: {compact_matches}."
|
|
293
|
+
)
|
|
294
|
+
raise ValueError(f"Model name '{model_name}' is not supported.")
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
def resolve_model_config(
|
|
298
|
+
model_cls: str | dict[str, Any], model_type: str = "DEFAULT"
|
|
299
|
+
) -> dict[str, Any]:
|
|
300
|
+
"""Resolve a vision model configuration without constructing a runtime.
|
|
301
|
+
|
|
302
|
+
Args:
|
|
303
|
+
model_cls: Model name, YAML path, or direct model configuration.
|
|
304
|
+
model_type: Variant key within a YAML model definition.
|
|
305
|
+
|
|
306
|
+
Returns:
|
|
307
|
+
A deep copy of the resolved ``file_cfg``, ``pre_cfg``, and ``post_cfg`` mapping.
|
|
308
|
+
``file_cfg`` always includes an ONNX filename when an MXQ filename is available.
|
|
309
|
+
|
|
310
|
+
Raises:
|
|
311
|
+
TypeError: If the YAML or resolved configuration is not a mapping.
|
|
312
|
+
ValueError: If a requested variant, alias, or update base is unavailable.
|
|
313
|
+
"""
|
|
314
|
+
|
|
315
|
+
if isinstance(model_cls, dict):
|
|
316
|
+
return _normalize_model_artifacts(model_cls)
|
|
317
|
+
|
|
318
|
+
config_path = Path(model_cls)
|
|
319
|
+
if not config_path.is_file():
|
|
320
|
+
config_path = MODEL_CONFIG_DIR / _model_name_aliasing(model_cls)
|
|
321
|
+
|
|
322
|
+
with config_path.open(encoding="utf-8") as config_file:
|
|
323
|
+
full_config = yaml.safe_load(config_file)
|
|
324
|
+
if not isinstance(full_config, dict):
|
|
325
|
+
raise TypeError(
|
|
326
|
+
f"Model configuration '{config_path}' should define a dictionary."
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
resolving: set[str] = set()
|
|
330
|
+
|
|
331
|
+
def _resolve_variant(variant: str) -> dict[str, Any]:
|
|
332
|
+
if variant in resolving:
|
|
333
|
+
raise ValueError(
|
|
334
|
+
f"Circular model configuration reference detected for '{variant}'."
|
|
335
|
+
)
|
|
336
|
+
resolving.add(variant)
|
|
337
|
+
try:
|
|
338
|
+
model_config_part = full_config.get(variant)
|
|
339
|
+
if model_config_part is None:
|
|
340
|
+
raise ValueError(f"Model type '{variant}' not found in configuration.")
|
|
341
|
+
if isinstance(model_config_part, str):
|
|
342
|
+
if model_config_part not in full_config:
|
|
343
|
+
raise ValueError(
|
|
344
|
+
f"Model alias '{model_config_part}' not found in configuration."
|
|
345
|
+
)
|
|
346
|
+
return _resolve_variant(model_config_part)
|
|
347
|
+
if not isinstance(model_config_part, dict):
|
|
348
|
+
raise TypeError(
|
|
349
|
+
f"Resolved model configuration for '{variant}' is not a dictionary."
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
resolved = copy.deepcopy(model_config_part)
|
|
353
|
+
base_config_key = resolved.pop("update", None)
|
|
354
|
+
if base_config_key is None:
|
|
355
|
+
return resolved
|
|
356
|
+
if (
|
|
357
|
+
not isinstance(base_config_key, str)
|
|
358
|
+
or base_config_key not in full_config
|
|
359
|
+
):
|
|
360
|
+
raise ValueError(
|
|
361
|
+
f"Base configuration '{base_config_key}' not found for update."
|
|
362
|
+
)
|
|
363
|
+
|
|
364
|
+
merged_config = _resolve_variant(base_config_key)
|
|
365
|
+
for key, value in resolved.items():
|
|
366
|
+
if (
|
|
367
|
+
key in merged_config
|
|
368
|
+
and isinstance(merged_config[key], dict)
|
|
369
|
+
and isinstance(value, dict)
|
|
370
|
+
):
|
|
371
|
+
merged_config[key].update(value)
|
|
372
|
+
else:
|
|
373
|
+
merged_config[key] = value
|
|
374
|
+
return merged_config
|
|
375
|
+
finally:
|
|
376
|
+
resolving.remove(variant)
|
|
377
|
+
|
|
378
|
+
return _normalize_model_artifacts(_resolve_variant(model_type))
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
class MBLT_Engine:
|
|
382
|
+
"""Main engine class for running vision models from the MBLT zoo.
|
|
383
|
+
|
|
384
|
+
Handles the full pipeline: Preprocessing -> Inference -> Postprocessing.
|
|
385
|
+
|
|
386
|
+
Attributes:
|
|
387
|
+
file_cfg: Model configuration.
|
|
388
|
+
pre_cfg: Preprocessing configuration.
|
|
389
|
+
post_cfg: Postprocessing configuration.
|
|
390
|
+
model: The underlying MXQ_Model.
|
|
391
|
+
device: The torch device being used.
|
|
392
|
+
"""
|
|
393
|
+
|
|
394
|
+
def __init__(
|
|
395
|
+
self,
|
|
396
|
+
model_cls: str | dict[str, Any],
|
|
397
|
+
model_type: str = "DEFAULT",
|
|
398
|
+
mxq_path: str = "",
|
|
399
|
+
onnx_path: str = "",
|
|
400
|
+
dev_no: int | None = None,
|
|
401
|
+
core_mode: CoreMode | None = None,
|
|
402
|
+
target_cores: Sequence[str | CoreId] | None = None,
|
|
403
|
+
target_clusters: Sequence[int | Cluster] | None = None,
|
|
404
|
+
postprocess_kwargs: dict[str, Any] | None = None,
|
|
405
|
+
framework: str | None = None,
|
|
406
|
+
onnx_providers: Sequence[str] | None = None,
|
|
407
|
+
model_path: str = "",
|
|
408
|
+
target_device: str | None = None,
|
|
409
|
+
) -> None:
|
|
410
|
+
"""Initializes the MBLT_Engine.
|
|
411
|
+
|
|
412
|
+
Args:
|
|
413
|
+
model_cls(if dict):
|
|
414
|
+
file_cfg: Model configuration.
|
|
415
|
+
mxq_path: path to mxq file
|
|
416
|
+
onnx_path: path to onnx file
|
|
417
|
+
model_path: generic path to local model file
|
|
418
|
+
dev_no: Accelerator No.
|
|
419
|
+
core_mode: single, multi, global4, global8
|
|
420
|
+
target_cores: single mode
|
|
421
|
+
target_clusters: multi, global modes
|
|
422
|
+
target_device: NPU board identifier; defaults to ``aries-rb``.
|
|
423
|
+
pre_cfg: Preprocessing configuration.
|
|
424
|
+
post_cfg: Postprocessing configuration.
|
|
425
|
+
model_cls(not dict): model name or yaml path
|
|
426
|
+
postprocess_kwargs: Optional runtime overrides passed to the postprocessor builder.
|
|
427
|
+
framework: Execution framework, either "mxq" or "onnx". When omitted,
|
|
428
|
+
``model_path`` suffix is used first, then MXQ is the fallback.
|
|
429
|
+
onnx_providers: Optional ONNX Runtime execution provider order.
|
|
430
|
+
target_device: NPU board identifier. An explicit value takes precedence
|
|
431
|
+
over ``file_cfg.target_device``; otherwise defaults to ``aries-rb``.
|
|
432
|
+
"""
|
|
433
|
+
|
|
434
|
+
if _uses_shifted_engine_model_path_layout(
|
|
435
|
+
model_path,
|
|
436
|
+
mxq_path,
|
|
437
|
+
dev_no,
|
|
438
|
+
core_mode,
|
|
439
|
+
target_cores,
|
|
440
|
+
postprocess_kwargs,
|
|
441
|
+
framework,
|
|
442
|
+
onnx_providers,
|
|
443
|
+
):
|
|
444
|
+
(
|
|
445
|
+
model_path,
|
|
446
|
+
mxq_path,
|
|
447
|
+
onnx_path,
|
|
448
|
+
dev_no,
|
|
449
|
+
core_mode,
|
|
450
|
+
target_cores,
|
|
451
|
+
target_clusters,
|
|
452
|
+
postprocess_kwargs,
|
|
453
|
+
framework,
|
|
454
|
+
onnx_providers,
|
|
455
|
+
) = (
|
|
456
|
+
mxq_path,
|
|
457
|
+
onnx_path,
|
|
458
|
+
cast(str, dev_no or ""),
|
|
459
|
+
cast(int | None, core_mode),
|
|
460
|
+
cast(CoreMode | None, target_cores),
|
|
461
|
+
cast(Sequence[str | Any] | None, target_clusters),
|
|
462
|
+
cast(Sequence[int | Any] | None, postprocess_kwargs),
|
|
463
|
+
cast(dict[str, Any] | None, framework),
|
|
464
|
+
cast(str | None, onnx_providers),
|
|
465
|
+
cast(Sequence[str] | None, model_path or None),
|
|
466
|
+
)
|
|
467
|
+
model_config_part = resolve_model_config(model_cls, model_type)
|
|
468
|
+
for section in ("file_cfg", "pre_cfg", "post_cfg"):
|
|
469
|
+
if not isinstance(model_config_part.get(section), dict):
|
|
470
|
+
raise ValueError(
|
|
471
|
+
f"Model configuration section '{section}' must be a mapping."
|
|
472
|
+
)
|
|
473
|
+
|
|
474
|
+
if mxq_path and Path(mxq_path).suffix.lower() != ".mxq":
|
|
475
|
+
raise ValueError(f"Explicit mxq_path must end in '.mxq', got {mxq_path!r}.")
|
|
476
|
+
if onnx_path and Path(onnx_path).suffix.lower() != ".onnx":
|
|
477
|
+
raise ValueError(
|
|
478
|
+
f"Explicit onnx_path must end in '.onnx', got {onnx_path!r}."
|
|
479
|
+
)
|
|
480
|
+
for key, suffix in (("mxq_path", ".mxq"), ("onnx_path", ".onnx")):
|
|
481
|
+
configured_path = model_config_part["file_cfg"].get(key)
|
|
482
|
+
if configured_path and (
|
|
483
|
+
not isinstance(configured_path, str)
|
|
484
|
+
or Path(configured_path).suffix.lower() != suffix
|
|
485
|
+
):
|
|
486
|
+
raise ValueError(
|
|
487
|
+
f"Configured file_cfg.{key} must end in {suffix!r}, "
|
|
488
|
+
f"got {configured_path!r}."
|
|
489
|
+
)
|
|
490
|
+
|
|
491
|
+
file_cfg_model_path = str(model_config_part["file_cfg"].get("model_path", ""))
|
|
492
|
+
file_cfg_onnx_path = str(model_config_part["file_cfg"].get("onnx_path", ""))
|
|
493
|
+
framework_model_path = model_path or file_cfg_model_path
|
|
494
|
+
if not framework_model_path and not mxq_path:
|
|
495
|
+
framework_model_path = onnx_path or file_cfg_onnx_path
|
|
496
|
+
self.framework = _resolve_framework(framework, framework_model_path)
|
|
497
|
+
mxq_path, onnx_path = _split_model_paths(
|
|
498
|
+
framework=self.framework,
|
|
499
|
+
model_path=model_path,
|
|
500
|
+
mxq_path=mxq_path,
|
|
501
|
+
onnx_path=onnx_path,
|
|
502
|
+
)
|
|
503
|
+
|
|
504
|
+
_mxq_path_passed = bool(mxq_path)
|
|
505
|
+
_onnx_path_passed = bool(onnx_path)
|
|
506
|
+
if _mxq_path_passed and not os.path.isfile(mxq_path):
|
|
507
|
+
raise FileNotFoundError(
|
|
508
|
+
"Explicit MXQ model path does not exist: "
|
|
509
|
+
f"{mxq_path}. Remove model_path/mxq_path to download the configured artifact."
|
|
510
|
+
)
|
|
511
|
+
if _onnx_path_passed and not os.path.isfile(onnx_path):
|
|
512
|
+
raise FileNotFoundError(
|
|
513
|
+
"Explicit ONNX model path does not exist: "
|
|
514
|
+
f"{onnx_path}. Remove model_path/onnx_path to download the configured artifact."
|
|
515
|
+
)
|
|
516
|
+
_dev_no_passed = dev_no is not None
|
|
517
|
+
_core_mode_passed = core_mode is not None
|
|
518
|
+
_target_cores_passed = target_cores is not None
|
|
519
|
+
_target_clusters_passed = target_clusters is not None
|
|
520
|
+
|
|
521
|
+
if dev_no is None:
|
|
522
|
+
dev_no = 0
|
|
523
|
+
if target_device is None:
|
|
524
|
+
target_device = model_config_part["file_cfg"].get(
|
|
525
|
+
"target_device", "aries-rb"
|
|
526
|
+
)
|
|
527
|
+
target_device = normalize_target_device(target_device)
|
|
528
|
+
is_regulus = target_device in {"regulus-ra", "regulus-rb"}
|
|
529
|
+
if core_mode is None:
|
|
530
|
+
core_mode = "single" if is_regulus else "global8"
|
|
531
|
+
else:
|
|
532
|
+
core_mode = normalize_core_mode(core_mode, target_device=target_device)
|
|
533
|
+
if target_cores is None:
|
|
534
|
+
target_cores = (
|
|
535
|
+
[]
|
|
536
|
+
if is_regulus
|
|
537
|
+
else ["0:0", "0:1", "0:2", "0:3", "1:0", "1:1", "1:2", "1:3"]
|
|
538
|
+
)
|
|
539
|
+
if target_clusters is None:
|
|
540
|
+
target_clusters = [] if is_regulus else [0, 1]
|
|
541
|
+
|
|
542
|
+
self.file_cfg = copy.deepcopy(model_config_part["file_cfg"])
|
|
543
|
+
file_cfg_model_path = self.file_cfg.pop("model_path", "")
|
|
544
|
+
if file_cfg_model_path:
|
|
545
|
+
yaml_mxq_path, yaml_onnx_path = _split_model_paths(
|
|
546
|
+
framework=self.framework,
|
|
547
|
+
model_path=file_cfg_model_path,
|
|
548
|
+
mxq_path=str(self.file_cfg.get("mxq_path", "")),
|
|
549
|
+
onnx_path=str(self.file_cfg.get("onnx_path", "")),
|
|
550
|
+
)
|
|
551
|
+
self.file_cfg["mxq_path"] = yaml_mxq_path
|
|
552
|
+
self.file_cfg["onnx_path"] = yaml_onnx_path
|
|
553
|
+
if _mxq_path_passed or "mxq_path" not in self.file_cfg:
|
|
554
|
+
self.file_cfg["mxq_path"] = mxq_path
|
|
555
|
+
if _onnx_path_passed or "onnx_path" not in self.file_cfg:
|
|
556
|
+
self.file_cfg["onnx_path"] = onnx_path
|
|
557
|
+
if _core_mode_passed or "core_mode" not in self.file_cfg or is_regulus:
|
|
558
|
+
self.file_cfg["core_mode"] = core_mode
|
|
559
|
+
if _target_cores_passed or "target_cores" not in self.file_cfg:
|
|
560
|
+
self.file_cfg["target_cores"] = target_cores
|
|
561
|
+
if _target_clusters_passed or "target_clusters" not in self.file_cfg:
|
|
562
|
+
self.file_cfg["target_clusters"] = target_clusters
|
|
563
|
+
if _dev_no_passed or "dev_no" not in self.file_cfg:
|
|
564
|
+
self.file_cfg["dev_no"] = dev_no
|
|
565
|
+
self.file_cfg["core_mode"] = normalize_core_mode(
|
|
566
|
+
self.file_cfg["core_mode"], target_device=target_device
|
|
567
|
+
)
|
|
568
|
+
self.file_cfg["target_device"] = target_device
|
|
569
|
+
|
|
570
|
+
self.pre_cfg = copy.deepcopy(model_config_part["pre_cfg"])
|
|
571
|
+
self.post_cfg = copy.deepcopy(model_config_part["post_cfg"])
|
|
572
|
+
self.postprocess_kwargs = (
|
|
573
|
+
{} if postprocess_kwargs is None else dict(postprocess_kwargs)
|
|
574
|
+
)
|
|
575
|
+
self.file_config_cleansing()
|
|
576
|
+
|
|
577
|
+
self.model: Any
|
|
578
|
+
self._mxq_model: MobilintNPUBackend | None = None
|
|
579
|
+
self._onnx_model: ONNXBackend | None = None
|
|
580
|
+
self._onnx_session: Any = None
|
|
581
|
+
self._closed = False
|
|
582
|
+
|
|
583
|
+
try:
|
|
584
|
+
if self.framework == "onnx":
|
|
585
|
+
ort = _load_onnxruntime()
|
|
586
|
+
resolved_onnx_path = self.file_cfg.get("onnx_path")
|
|
587
|
+
if not resolved_onnx_path:
|
|
588
|
+
raise RuntimeError(
|
|
589
|
+
f"ONNX path not resolved for model {model_cls}. Make sure the model repository has an ONNX file."
|
|
590
|
+
)
|
|
591
|
+
if not os.path.isfile(resolved_onnx_path):
|
|
592
|
+
raise FileNotFoundError(
|
|
593
|
+
f"ONNX file not found at: {resolved_onnx_path}"
|
|
594
|
+
)
|
|
595
|
+
|
|
596
|
+
providers = _resolve_onnx_providers(ort, onnx_providers)
|
|
597
|
+
onnx_model = ONNXBackend(
|
|
598
|
+
resolved_onnx_path, providers=providers, ort_module=ort
|
|
599
|
+
)
|
|
600
|
+
self._onnx_model = onnx_model
|
|
601
|
+
onnx_model.create()
|
|
602
|
+
self._onnx_session = onnx_model.session
|
|
603
|
+
self.model = self._onnx_session
|
|
604
|
+
onnx_inputs = self._onnx_session.get_inputs()
|
|
605
|
+
if len(onnx_inputs) != 1:
|
|
606
|
+
raise ValueError(
|
|
607
|
+
"ONNX models must declare exactly one input because "
|
|
608
|
+
"MBLT_Engine accepts one preprocessed tensor; got "
|
|
609
|
+
f"{len(onnx_inputs)} inputs."
|
|
610
|
+
)
|
|
611
|
+
self.input_name = onnx_inputs[0].name
|
|
612
|
+
self.output_names = [o.name for o in self._onnx_session.get_outputs()]
|
|
613
|
+
else:
|
|
614
|
+
mxq_model = MobilintNPUBackend(**self._mxq_backend_kwargs())
|
|
615
|
+
self._mxq_model = mxq_model
|
|
616
|
+
self.model = mxq_model
|
|
617
|
+
mxq_model.create()
|
|
618
|
+
mxq_model.launch()
|
|
619
|
+
|
|
620
|
+
if mxq_model.get_dtype() == "DataType.Uint8":
|
|
621
|
+
self.pre_cfg.pop("Normalize", None)
|
|
622
|
+
|
|
623
|
+
self.preprocessor = build_preprocess(self.pre_cfg)
|
|
624
|
+
self.postprocessor = build_postprocess(
|
|
625
|
+
self.pre_cfg, self.post_cfg, **self.postprocess_kwargs
|
|
626
|
+
)
|
|
627
|
+
self.device = torch.device("cpu")
|
|
628
|
+
except Exception:
|
|
629
|
+
self._close(suppress_errors=True)
|
|
630
|
+
raise
|
|
631
|
+
|
|
632
|
+
def _mxq_backend_kwargs(self) -> dict[str, Any]:
|
|
633
|
+
"""Builds the MXQ backend kwargs from the resolved file config."""
|
|
634
|
+
|
|
635
|
+
excluded_keys = {
|
|
636
|
+
"repo_id",
|
|
637
|
+
"filename",
|
|
638
|
+
"revision",
|
|
639
|
+
"onnx_filename",
|
|
640
|
+
"onnx_path",
|
|
641
|
+
}
|
|
642
|
+
return {
|
|
643
|
+
key: value
|
|
644
|
+
for key, value in self.file_cfg.items()
|
|
645
|
+
if key not in excluded_keys
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
def _derive_onnx_filename(self) -> str | None:
|
|
649
|
+
"""Returns the ONNX filename associated with the configured MXQ artifact."""
|
|
650
|
+
|
|
651
|
+
onnx_filename = _derive_onnx_filename(self.file_cfg)
|
|
652
|
+
if onnx_filename is not None:
|
|
653
|
+
self.file_cfg["onnx_filename"] = onnx_filename
|
|
654
|
+
return onnx_filename
|
|
655
|
+
|
|
656
|
+
def _resolve_local_onnx_path(self, mxq_path: str) -> str | None:
|
|
657
|
+
"""Tries to resolve a sibling ONNX file next to a local MXQ artifact."""
|
|
658
|
+
|
|
659
|
+
onnx_path = self.file_cfg.get("onnx_path", "")
|
|
660
|
+
if onnx_path and os.path.isfile(onnx_path):
|
|
661
|
+
return onnx_path
|
|
662
|
+
|
|
663
|
+
onnx_filename = self._derive_onnx_filename()
|
|
664
|
+
if onnx_filename:
|
|
665
|
+
sibling_path = Path(mxq_path).with_name(onnx_filename)
|
|
666
|
+
if sibling_path.is_file():
|
|
667
|
+
return str(sibling_path)
|
|
668
|
+
|
|
669
|
+
if mxq_path.endswith(".mxq"):
|
|
670
|
+
suffix_swapped = f"{mxq_path[:-4]}.onnx"
|
|
671
|
+
if os.path.isfile(suffix_swapped):
|
|
672
|
+
return suffix_swapped
|
|
673
|
+
|
|
674
|
+
return None
|
|
675
|
+
|
|
676
|
+
def _download_hub_artifact(
|
|
677
|
+
self,
|
|
678
|
+
*,
|
|
679
|
+
repo_id: str,
|
|
680
|
+
filename: str,
|
|
681
|
+
revision: str,
|
|
682
|
+
subfolders: Sequence[str] | None = None,
|
|
683
|
+
) -> str:
|
|
684
|
+
"""Downloads a model artifact from Hugging Face Hub and returns its cache path."""
|
|
685
|
+
|
|
686
|
+
last_error: Exception | None = None
|
|
687
|
+
normalized_subfolders = [""] if subfolders is None else list(subfolders)
|
|
688
|
+
for subfolder in normalized_subfolders:
|
|
689
|
+
kwargs: dict[str, Any] = {
|
|
690
|
+
"repo_id": repo_id,
|
|
691
|
+
"filename": filename,
|
|
692
|
+
"revision": revision,
|
|
693
|
+
"local_dir": get_mobilint_cache_dir(),
|
|
694
|
+
}
|
|
695
|
+
if subfolder:
|
|
696
|
+
kwargs["subfolder"] = subfolder
|
|
697
|
+
try:
|
|
698
|
+
return hf_hub_download(**kwargs)
|
|
699
|
+
except EntryNotFoundError as exc:
|
|
700
|
+
last_error = exc
|
|
701
|
+
|
|
702
|
+
attempted_paths = ", ".join(
|
|
703
|
+
f"{subfolder}/{filename}" if subfolder else filename
|
|
704
|
+
for subfolder in normalized_subfolders
|
|
705
|
+
)
|
|
706
|
+
raise RuntimeError(
|
|
707
|
+
f"Failed to download model from Hugging Face. Tried repo '{repo_id}' at: {attempted_paths}."
|
|
708
|
+
) from last_error
|
|
709
|
+
|
|
710
|
+
def file_config_cleansing(self) -> None:
|
|
711
|
+
"""Validates and resolves the MXQ and ONNX model file paths in ``self.file_cfg``."""
|
|
712
|
+
framework = getattr(self, "framework", "mxq")
|
|
713
|
+
model_path = self.file_cfg.pop("model_path", "")
|
|
714
|
+
if model_path:
|
|
715
|
+
mxq_path, onnx_path = _split_model_paths(
|
|
716
|
+
framework=framework,
|
|
717
|
+
model_path=model_path,
|
|
718
|
+
mxq_path=str(self.file_cfg.get("mxq_path", "")),
|
|
719
|
+
onnx_path=str(self.file_cfg.get("onnx_path", "")),
|
|
720
|
+
)
|
|
721
|
+
self.file_cfg["mxq_path"] = mxq_path
|
|
722
|
+
self.file_cfg["onnx_path"] = onnx_path
|
|
723
|
+
mxq_path = self.file_cfg.get("mxq_path", "")
|
|
724
|
+
onnx_path = self.file_cfg.get("onnx_path", "")
|
|
725
|
+
onnx_filename = self._derive_onnx_filename()
|
|
726
|
+
|
|
727
|
+
if onnx_path and os.path.isfile(onnx_path):
|
|
728
|
+
self.file_cfg["onnx_path"] = onnx_path
|
|
729
|
+
if framework == "onnx":
|
|
730
|
+
return
|
|
731
|
+
|
|
732
|
+
if mxq_path and os.path.isfile(mxq_path):
|
|
733
|
+
resolved_local_onnx = self._resolve_local_onnx_path(mxq_path)
|
|
734
|
+
if resolved_local_onnx is not None:
|
|
735
|
+
self.file_cfg["onnx_path"] = resolved_local_onnx
|
|
736
|
+
self.file_cfg.pop("repo_id", None)
|
|
737
|
+
self.file_cfg.pop("filename", None)
|
|
738
|
+
self.file_cfg.pop("revision", None)
|
|
739
|
+
elif framework == "mxq":
|
|
740
|
+
self.file_cfg.pop("repo_id", None)
|
|
741
|
+
self.file_cfg.pop("filename", None)
|
|
742
|
+
self.file_cfg.pop("revision", None)
|
|
743
|
+
if framework == "mxq":
|
|
744
|
+
return
|
|
745
|
+
|
|
746
|
+
repo_id = self.file_cfg.pop("repo_id", None)
|
|
747
|
+
filename = self.file_cfg.pop("filename", None)
|
|
748
|
+
revision = self.file_cfg.pop("revision", None)
|
|
749
|
+
if not repo_id or not revision:
|
|
750
|
+
return
|
|
751
|
+
|
|
752
|
+
if filename and framework == "mxq":
|
|
753
|
+
target_device = self.file_cfg.get("target_device", "aries-rb")
|
|
754
|
+
self.file_cfg["mxq_path"] = self._download_hub_artifact(
|
|
755
|
+
repo_id=repo_id,
|
|
756
|
+
filename=filename,
|
|
757
|
+
revision=revision,
|
|
758
|
+
subfolders=[target_device],
|
|
759
|
+
)
|
|
760
|
+
|
|
761
|
+
if onnx_filename and framework == "onnx" and not self.file_cfg.get("onnx_path"):
|
|
762
|
+
self.file_cfg["onnx_path"] = self._download_hub_artifact(
|
|
763
|
+
repo_id=repo_id,
|
|
764
|
+
filename=onnx_filename,
|
|
765
|
+
revision=revision,
|
|
766
|
+
)
|
|
767
|
+
|
|
768
|
+
def _prepare_onnx_inputs(self, x: TensorLike) -> dict[str, np.ndarray]:
|
|
769
|
+
"""Normalizes runtime inputs to match the ONNX session contract."""
|
|
770
|
+
|
|
771
|
+
if isinstance(x, torch.Tensor):
|
|
772
|
+
x_np = x.detach().cpu().numpy()
|
|
773
|
+
elif isinstance(x, np.ndarray):
|
|
774
|
+
x_np = x
|
|
775
|
+
else:
|
|
776
|
+
raise TypeError(f"Got unexpected type for ONNX input x={type(x)}.")
|
|
777
|
+
|
|
778
|
+
if x_np.dtype == np.float64:
|
|
779
|
+
x_np = x_np.astype(np.float32)
|
|
780
|
+
|
|
781
|
+
expected_shape = self._require_onnx_session().get_inputs()[0].shape
|
|
782
|
+
if len(expected_shape) == 4:
|
|
783
|
+
expected_second_dim = expected_shape[1]
|
|
784
|
+
expected_last_dim = expected_shape[-1]
|
|
785
|
+
expected_layout = None
|
|
786
|
+
expected_channels = None
|
|
787
|
+
# ONNX layout is encoded by the channel axis, not by a spatial
|
|
788
|
+
# dimension that happens to equal a channel count. This is crucial
|
|
789
|
+
# for square static inputs such as [1, 3, 224, 224].
|
|
790
|
+
if isinstance(expected_second_dim, int) and expected_second_dim in {
|
|
791
|
+
1,
|
|
792
|
+
2,
|
|
793
|
+
3,
|
|
794
|
+
4,
|
|
795
|
+
}:
|
|
796
|
+
expected_layout = "nchw"
|
|
797
|
+
expected_channels = expected_second_dim
|
|
798
|
+
elif isinstance(expected_last_dim, int) and expected_last_dim in {
|
|
799
|
+
1,
|
|
800
|
+
2,
|
|
801
|
+
3,
|
|
802
|
+
4,
|
|
803
|
+
}:
|
|
804
|
+
expected_layout = "nhwc"
|
|
805
|
+
expected_channels = expected_last_dim
|
|
806
|
+
|
|
807
|
+
if x_np.ndim == 3:
|
|
808
|
+
if (
|
|
809
|
+
expected_layout == "nchw"
|
|
810
|
+
and expected_channels is not None
|
|
811
|
+
and x_np.shape[0] == expected_channels
|
|
812
|
+
):
|
|
813
|
+
x_np = np.expand_dims(x_np, axis=0)
|
|
814
|
+
elif (
|
|
815
|
+
expected_layout == "nchw"
|
|
816
|
+
and expected_channels is not None
|
|
817
|
+
and x_np.shape[-1] == expected_channels
|
|
818
|
+
):
|
|
819
|
+
x_np = np.transpose(x_np, (2, 0, 1))
|
|
820
|
+
x_np = np.expand_dims(x_np, axis=0)
|
|
821
|
+
elif (
|
|
822
|
+
expected_layout == "nhwc"
|
|
823
|
+
and expected_channels is not None
|
|
824
|
+
and x_np.shape[-1] == expected_channels
|
|
825
|
+
):
|
|
826
|
+
x_np = np.expand_dims(x_np, axis=0)
|
|
827
|
+
elif (
|
|
828
|
+
expected_layout == "nhwc"
|
|
829
|
+
and expected_channels is not None
|
|
830
|
+
and x_np.shape[0] == expected_channels
|
|
831
|
+
):
|
|
832
|
+
x_np = np.transpose(x_np, (1, 2, 0))
|
|
833
|
+
x_np = np.expand_dims(x_np, axis=0)
|
|
834
|
+
elif x_np.ndim == 4:
|
|
835
|
+
if expected_layout == "nchw" and expected_channels is not None:
|
|
836
|
+
if x_np.shape[1] == expected_channels:
|
|
837
|
+
pass
|
|
838
|
+
elif x_np.shape[-1] == expected_channels:
|
|
839
|
+
x_np = np.transpose(x_np, (0, 3, 1, 2))
|
|
840
|
+
elif expected_layout == "nhwc" and expected_channels is not None:
|
|
841
|
+
if x_np.shape[-1] == expected_channels:
|
|
842
|
+
pass
|
|
843
|
+
elif x_np.shape[1] == expected_channels:
|
|
844
|
+
x_np = np.transpose(x_np, (0, 2, 3, 1))
|
|
845
|
+
|
|
846
|
+
return {self.input_name: x_np}
|
|
847
|
+
|
|
848
|
+
def _require_onnx_session(self) -> Any:
|
|
849
|
+
"""Return the active ONNX session."""
|
|
850
|
+
|
|
851
|
+
session = getattr(self, "_onnx_session", None)
|
|
852
|
+
if session is None:
|
|
853
|
+
fallback = getattr(self, "model", None)
|
|
854
|
+
if (
|
|
855
|
+
fallback is not None
|
|
856
|
+
and hasattr(fallback, "get_inputs")
|
|
857
|
+
and hasattr(fallback, "run")
|
|
858
|
+
):
|
|
859
|
+
return fallback
|
|
860
|
+
raise RuntimeError("ONNX session is not initialized.")
|
|
861
|
+
return session
|
|
862
|
+
|
|
863
|
+
def _require_mxq_model(self) -> MobilintNPUBackend:
|
|
864
|
+
"""Return the active MXQ backend."""
|
|
865
|
+
|
|
866
|
+
model = getattr(self, "_mxq_model", None)
|
|
867
|
+
if model is None:
|
|
868
|
+
fallback = getattr(self, "model", None)
|
|
869
|
+
if (
|
|
870
|
+
fallback is not None
|
|
871
|
+
and hasattr(fallback, "create")
|
|
872
|
+
and hasattr(fallback, "launch")
|
|
873
|
+
):
|
|
874
|
+
return cast(MobilintNPUBackend, fallback)
|
|
875
|
+
raise RuntimeError("MXQ backend is not initialized.")
|
|
876
|
+
return model
|
|
877
|
+
|
|
878
|
+
def __call__(
|
|
879
|
+
self,
|
|
880
|
+
x: TensorLike,
|
|
881
|
+
) -> Any:
|
|
882
|
+
"""Runs raw model inference on the input.
|
|
883
|
+
|
|
884
|
+
Note:
|
|
885
|
+
This does NOT include preprocessing or postprocessing.
|
|
886
|
+
|
|
887
|
+
Args:
|
|
888
|
+
x: Input tensor for the model.
|
|
889
|
+
|
|
890
|
+
Returns:
|
|
891
|
+
Raw model output.
|
|
892
|
+
"""
|
|
893
|
+
self._ensure_open()
|
|
894
|
+
if self.framework == "onnx":
|
|
895
|
+
outputs = self._require_onnx_session().run(
|
|
896
|
+
self.output_names, self._prepare_onnx_inputs(x)
|
|
897
|
+
)
|
|
898
|
+
if len(outputs) == 1:
|
|
899
|
+
return outputs[0]
|
|
900
|
+
return outputs
|
|
901
|
+
return cast(Any, self._require_mxq_model())(x)
|
|
902
|
+
|
|
903
|
+
def preprocess(
|
|
904
|
+
self,
|
|
905
|
+
x: Any,
|
|
906
|
+
**kwargs: Any,
|
|
907
|
+
) -> Any:
|
|
908
|
+
"""Runs preprocessing on the input.
|
|
909
|
+
|
|
910
|
+
Args:
|
|
911
|
+
x: Input data.
|
|
912
|
+
**kwargs: Additional arguments for preprocessing.
|
|
913
|
+
|
|
914
|
+
Returns:
|
|
915
|
+
Preprocessed data.
|
|
916
|
+
"""
|
|
917
|
+
return self.preprocessor(x, **kwargs)
|
|
918
|
+
|
|
919
|
+
def preprocess_with_metadata(
|
|
920
|
+
self,
|
|
921
|
+
x: Any,
|
|
922
|
+
) -> tuple[Any, dict[str, Any]]:
|
|
923
|
+
"""Runs preprocessing and returns metadata needed for exact postprocess scaling.
|
|
924
|
+
|
|
925
|
+
Args:
|
|
926
|
+
x: Input data.
|
|
927
|
+
|
|
928
|
+
Returns:
|
|
929
|
+
A tuple of preprocessed data and metadata such as ``ratio_pad``.
|
|
930
|
+
"""
|
|
931
|
+
return self.preprocessor.with_metadata(x)
|
|
932
|
+
|
|
933
|
+
def postprocess(
|
|
934
|
+
self,
|
|
935
|
+
x: Any,
|
|
936
|
+
**kwargs: Any,
|
|
937
|
+
) -> Results:
|
|
938
|
+
"""Runs postprocessing on the input.
|
|
939
|
+
|
|
940
|
+
Args:
|
|
941
|
+
x: Input data.
|
|
942
|
+
**kwargs: Additional arguments for postprocessing.
|
|
943
|
+
|
|
944
|
+
Returns:
|
|
945
|
+
Postprocessed results.
|
|
946
|
+
"""
|
|
947
|
+
pre_result = self.postprocessor(x, **kwargs)
|
|
948
|
+
result_kwargs = dict(kwargs)
|
|
949
|
+
conf_thres = getattr(self.postprocessor, "conf_thres", None)
|
|
950
|
+
iou_thres = getattr(self.postprocessor, "iou_thres", None)
|
|
951
|
+
if "conf_thres" not in result_kwargs and conf_thres is not None:
|
|
952
|
+
result_kwargs["conf_thres"] = conf_thres
|
|
953
|
+
if "iou_thres" not in result_kwargs and iou_thres is not None:
|
|
954
|
+
result_kwargs["iou_thres"] = iou_thres
|
|
955
|
+
return Results(self.pre_cfg, self.post_cfg, pre_result, **result_kwargs)
|
|
956
|
+
|
|
957
|
+
def set_postprocess_thresholds(
|
|
958
|
+
self, conf_thres: float | None = None, iou_thres: float | None = None
|
|
959
|
+
) -> None:
|
|
960
|
+
"""Updates configurable postprocess thresholds for the current model.
|
|
961
|
+
|
|
962
|
+
Args:
|
|
963
|
+
conf_thres: Optional confidence threshold override.
|
|
964
|
+
iou_thres: Optional IoU threshold override.
|
|
965
|
+
|
|
966
|
+
Raises:
|
|
967
|
+
NotImplementedError: If the current postprocessor does not support thresholds.
|
|
968
|
+
"""
|
|
969
|
+
set_threshold = getattr(self.postprocessor, "set_threshold", None)
|
|
970
|
+
if set_threshold is None:
|
|
971
|
+
raise NotImplementedError(
|
|
972
|
+
f"Threshold overrides are not supported for task `{self.post_cfg.get('task', 'unknown')}`."
|
|
973
|
+
)
|
|
974
|
+
set_threshold(conf_thres=conf_thres, iou_thres=iou_thres)
|
|
975
|
+
|
|
976
|
+
def to(
|
|
977
|
+
self,
|
|
978
|
+
device: str | torch.device,
|
|
979
|
+
) -> None:
|
|
980
|
+
"""Moves the engine and its components to the specified device.
|
|
981
|
+
|
|
982
|
+
Args:
|
|
983
|
+
device: Target device.
|
|
984
|
+
|
|
985
|
+
Raises:
|
|
986
|
+
TypeError: If device type is unexpected.
|
|
987
|
+
"""
|
|
988
|
+
self.preprocessor.to(device)
|
|
989
|
+
self.postprocessor.to(device)
|
|
990
|
+
|
|
991
|
+
if isinstance(device, str):
|
|
992
|
+
self.device = torch.device(device)
|
|
993
|
+
elif isinstance(device, torch.device):
|
|
994
|
+
self.device = device
|
|
995
|
+
else:
|
|
996
|
+
raise TypeError(f"Got unexpected type for device={type(device)}.")
|
|
997
|
+
|
|
998
|
+
def cpu(self) -> None:
|
|
999
|
+
"""Moves the engine to CPU."""
|
|
1000
|
+
self.to(device="cpu")
|
|
1001
|
+
|
|
1002
|
+
def gpu(self) -> None:
|
|
1003
|
+
"""Moves the engine to GPU (CUDA)."""
|
|
1004
|
+
self.to(device="cuda")
|
|
1005
|
+
|
|
1006
|
+
def cuda(
|
|
1007
|
+
self,
|
|
1008
|
+
device: str | int = 0,
|
|
1009
|
+
) -> None:
|
|
1010
|
+
"""Moves the engine to CUDA device.
|
|
1011
|
+
|
|
1012
|
+
Args:
|
|
1013
|
+
device: CUDA device identifier. Defaults to 0.
|
|
1014
|
+
|
|
1015
|
+
Raises:
|
|
1016
|
+
ValueError: If device string is invalid.
|
|
1017
|
+
RuntimeError: If CUDA is not available.
|
|
1018
|
+
"""
|
|
1019
|
+
if isinstance(device, int):
|
|
1020
|
+
device = f"cuda:{device}"
|
|
1021
|
+
elif isinstance(device, str):
|
|
1022
|
+
if not device.startswith("cuda:"):
|
|
1023
|
+
raise ValueError("Invalid device string. It should start with 'cuda:'.")
|
|
1024
|
+
|
|
1025
|
+
if not torch.cuda.is_available():
|
|
1026
|
+
raise RuntimeError("CUDA is not available. Please check your environment.")
|
|
1027
|
+
self.to(device=device)
|
|
1028
|
+
|
|
1029
|
+
def launch(self) -> None:
|
|
1030
|
+
"""Launches the underlying model."""
|
|
1031
|
+
self._ensure_open()
|
|
1032
|
+
if self.framework == "mxq":
|
|
1033
|
+
self._require_mxq_model().launch()
|
|
1034
|
+
|
|
1035
|
+
def dispose(self) -> None:
|
|
1036
|
+
"""Compatibility alias for :meth:`close`."""
|
|
1037
|
+
|
|
1038
|
+
self.close()
|
|
1039
|
+
|
|
1040
|
+
def close(self) -> None:
|
|
1041
|
+
"""Release backend resources. Safe to call more than once."""
|
|
1042
|
+
|
|
1043
|
+
self._close(suppress_errors=False)
|
|
1044
|
+
|
|
1045
|
+
def __enter__(self) -> MBLT_Engine:
|
|
1046
|
+
"""Return this engine for use in a context manager."""
|
|
1047
|
+
|
|
1048
|
+
self._ensure_open()
|
|
1049
|
+
return self
|
|
1050
|
+
|
|
1051
|
+
def __exit__(
|
|
1052
|
+
self,
|
|
1053
|
+
exc_type: type[BaseException] | None,
|
|
1054
|
+
exc_value: BaseException | None,
|
|
1055
|
+
traceback: TracebackType | None,
|
|
1056
|
+
) -> bool:
|
|
1057
|
+
"""Release resources when leaving a context manager block."""
|
|
1058
|
+
|
|
1059
|
+
del exc_value, traceback
|
|
1060
|
+
self._close(suppress_errors=exc_type is not None)
|
|
1061
|
+
return False
|
|
1062
|
+
|
|
1063
|
+
def __del__(self) -> None:
|
|
1064
|
+
"""Best-effort cleanup for engines not explicitly closed by callers."""
|
|
1065
|
+
|
|
1066
|
+
try:
|
|
1067
|
+
self._close(suppress_errors=True)
|
|
1068
|
+
except Exception:
|
|
1069
|
+
pass
|
|
1070
|
+
|
|
1071
|
+
def _ensure_open(self) -> None:
|
|
1072
|
+
"""Raise when inference is attempted after backend disposal."""
|
|
1073
|
+
|
|
1074
|
+
if getattr(self, "_closed", False):
|
|
1075
|
+
raise RuntimeError("MBLT_Engine is closed.")
|
|
1076
|
+
|
|
1077
|
+
def _close(self, *, suppress_errors: bool) -> None:
|
|
1078
|
+
"""Dispose acquired backends once, optionally suppressing cleanup failures."""
|
|
1079
|
+
|
|
1080
|
+
if getattr(self, "_closed", False):
|
|
1081
|
+
return
|
|
1082
|
+
self._closed = True
|
|
1083
|
+
first_error: Exception | None = None
|
|
1084
|
+
for backend in (
|
|
1085
|
+
getattr(self, "_mxq_model", None),
|
|
1086
|
+
getattr(self, "_onnx_model", None),
|
|
1087
|
+
):
|
|
1088
|
+
if backend is None:
|
|
1089
|
+
continue
|
|
1090
|
+
try:
|
|
1091
|
+
backend.dispose()
|
|
1092
|
+
except Exception as exc:
|
|
1093
|
+
if first_error is None:
|
|
1094
|
+
first_error = exc
|
|
1095
|
+
self._onnx_session = None
|
|
1096
|
+
if first_error is not None and not suppress_errors:
|
|
1097
|
+
raise first_error
|
|
1098
|
+
|
|
1099
|
+
def model_name_aliasing(self, model_name: str) -> str:
|
|
1100
|
+
"""Finds the YAML config filename that matches the given model name.
|
|
1101
|
+
|
|
1102
|
+
Matching is case-insensitive and first preserves separator boundaries
|
|
1103
|
+
so names such as ``regnet_x_16gf`` do not collide with
|
|
1104
|
+
``regnet_x_1_6gf``. A separator-stripped fallback is used only when it
|
|
1105
|
+
resolves to a single unique configuration, so inputs like ``resnet50``,
|
|
1106
|
+
``ResNet50``, ``Resnet_50``, and ``resnet-50`` all resolve to
|
|
1107
|
+
``ResNet50.yaml``.
|
|
1108
|
+
|
|
1109
|
+
Args:
|
|
1110
|
+
model_name: The model identifier provided by the caller.
|
|
1111
|
+
|
|
1112
|
+
Returns:
|
|
1113
|
+
The exact YAML filename (basename only) stored in
|
|
1114
|
+
``MODEL_CONFIG_DIR`` that corresponds to ``model_name``.
|
|
1115
|
+
|
|
1116
|
+
Raises:
|
|
1117
|
+
ValueError: If no YAML file matches, or if the name is ambiguous
|
|
1118
|
+
(i.e., multiple files match after normalization).
|
|
1119
|
+
"""
|
|
1120
|
+
|
|
1121
|
+
return _model_name_aliasing(model_name)
|