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.
Files changed (404) hide show
  1. mblt_vision/__init__.py +86 -0
  2. mblt_vision/_api.py +53 -0
  3. mblt_vision/_compat.py +227 -0
  4. mblt_vision/_model_paths.py +137 -0
  5. mblt_vision/_tasks.py +30 -0
  6. mblt_vision/benchmark/__init__.py +1 -0
  7. mblt_vision/benchmark/argparse_utils.py +106 -0
  8. mblt_vision/benchmark/chart_utils.py +146 -0
  9. mblt_vision/benchmark/io_utils.py +64 -0
  10. mblt_vision/benchmark/summary_utils.py +770 -0
  11. mblt_vision/cli/__init__.py +5 -0
  12. mblt_vision/cli/__main__.py +5 -0
  13. mblt_vision/cli/_vision.py +337 -0
  14. mblt_vision/cli/compile.py +117 -0
  15. mblt_vision/cli/main.py +35 -0
  16. mblt_vision/cli/predict.py +64 -0
  17. mblt_vision/cli/val.py +562 -0
  18. mblt_vision/compile/__init__.py +21 -0
  19. mblt_vision/compile/vision.py +1120 -0
  20. mblt_vision/datasets/__init__.py +15 -0
  21. mblt_vision/datasets/ade20k.yaml +164 -0
  22. mblt_vision/datasets/cityscapes.yaml +54 -0
  23. mblt_vision/datasets/coco.yaml +178 -0
  24. mblt_vision/datasets/dotav1.yaml +28 -0
  25. mblt_vision/datasets/imagenet.yaml +1019 -0
  26. mblt_vision/datasets/imagenet_synsets.txt +1000 -0
  27. mblt_vision/datasets/nyu-depth.yaml +7 -0
  28. mblt_vision/datasets/registry.py +158 -0
  29. mblt_vision/datasets/widerface.yaml +9 -0
  30. mblt_vision/depth_estimation/__init__.py +19 -0
  31. mblt_vision/face_detection/__init__.py +43 -0
  32. mblt_vision/image_classification/__init__.py +311 -0
  33. mblt_vision/instance_segmentation/__init__.py +65 -0
  34. mblt_vision/models/AlexNet.yaml +23 -0
  35. mblt_vision/models/CAFormer_B36.yaml +22 -0
  36. mblt_vision/models/CAFormer_M36.yaml +22 -0
  37. mblt_vision/models/CAFormer_S18.yaml +22 -0
  38. mblt_vision/models/CAFormer_S36.yaml +22 -0
  39. mblt_vision/models/CoAtNet_0_RW_224.yaml +22 -0
  40. mblt_vision/models/CoAtNet_1_RW_224.yaml +22 -0
  41. mblt_vision/models/CoAtNet_2_RW_224.yaml +22 -0
  42. mblt_vision/models/ConvFormer_B36.yaml +22 -0
  43. mblt_vision/models/ConvFormer_M36.yaml +22 -0
  44. mblt_vision/models/ConvFormer_S18.yaml +22 -0
  45. mblt_vision/models/ConvFormer_S36.yaml +22 -0
  46. mblt_vision/models/ConvNext_Base.yaml +23 -0
  47. mblt_vision/models/ConvNext_Large.yaml +23 -0
  48. mblt_vision/models/ConvNext_Small.yaml +23 -0
  49. mblt_vision/models/ConvNext_Tiny.yaml +23 -0
  50. mblt_vision/models/DeiT3_Base_Patch16_224.yaml +22 -0
  51. mblt_vision/models/DeiT3_Base_Patch16_384.yaml +22 -0
  52. mblt_vision/models/DeiT3_Large_Patch16_224.yaml +22 -0
  53. mblt_vision/models/DeiT3_Large_Patch16_384.yaml +22 -0
  54. mblt_vision/models/DeiT3_Medium_Patch16_224.yaml +22 -0
  55. mblt_vision/models/DeiT3_Small_Patch16_224.yaml +22 -0
  56. mblt_vision/models/DeiT3_Small_Patch16_384.yaml +22 -0
  57. mblt_vision/models/DeiT_Base_Patch16_224.yaml +22 -0
  58. mblt_vision/models/DeiT_Base_Patch16_384.yaml +22 -0
  59. mblt_vision/models/DeiT_Small_Patch16_224.yaml +22 -0
  60. mblt_vision/models/DeiT_Tiny_Patch16_224.yaml +22 -0
  61. mblt_vision/models/DenseNet121.yaml +23 -0
  62. mblt_vision/models/DenseNet161.yaml +23 -0
  63. mblt_vision/models/DenseNet169.yaml +23 -0
  64. mblt_vision/models/DenseNet201.yaml +23 -0
  65. mblt_vision/models/EfficientFormer_L1.yaml +22 -0
  66. mblt_vision/models/EfficientFormer_L3.yaml +22 -0
  67. mblt_vision/models/EfficientFormer_L7.yaml +22 -0
  68. mblt_vision/models/EfficientNet_B0.yaml +23 -0
  69. mblt_vision/models/EfficientNet_B1.yaml +32 -0
  70. mblt_vision/models/EfficientNet_B2.yaml +23 -0
  71. mblt_vision/models/EfficientNet_B3.yaml +23 -0
  72. mblt_vision/models/EfficientNet_B4.yaml +23 -0
  73. mblt_vision/models/EfficientNet_B5.yaml +23 -0
  74. mblt_vision/models/EfficientNet_B6.yaml +23 -0
  75. mblt_vision/models/EfficientNet_B7.yaml +23 -0
  76. mblt_vision/models/EfficientNet_V2_L.yaml +23 -0
  77. mblt_vision/models/EfficientNet_V2_M.yaml +23 -0
  78. mblt_vision/models/EfficientNet_V2_S.yaml +23 -0
  79. mblt_vision/models/FlexiVit_Base.yaml +22 -0
  80. mblt_vision/models/FlexiVit_Large.yaml +22 -0
  81. mblt_vision/models/FlexiVit_Small.yaml +22 -0
  82. mblt_vision/models/GELANc-seg.yaml +29 -0
  83. mblt_vision/models/GELANc.yaml +28 -0
  84. mblt_vision/models/GELANe.yaml +28 -0
  85. mblt_vision/models/GELANm.yaml +28 -0
  86. mblt_vision/models/GELANs.yaml +28 -0
  87. mblt_vision/models/GoogLeNet.yaml +23 -0
  88. mblt_vision/models/Inception_V3.yaml +23 -0
  89. mblt_vision/models/LeViT_Conv_128.yaml +22 -0
  90. mblt_vision/models/LeViT_Conv_128S.yaml +22 -0
  91. mblt_vision/models/LeViT_Conv_192.yaml +22 -0
  92. mblt_vision/models/LeViT_Conv_256.yaml +22 -0
  93. mblt_vision/models/LeViT_Conv_384.yaml +22 -0
  94. mblt_vision/models/MNASNet0_5.yaml +23 -0
  95. mblt_vision/models/MNASNet0_75.yaml +23 -0
  96. mblt_vision/models/MNASNet1_0.yaml +23 -0
  97. mblt_vision/models/MNASNet1_3.yaml +23 -0
  98. mblt_vision/models/MobileNet_V2.yaml +32 -0
  99. mblt_vision/models/MobileNet_V3_Large.yaml +32 -0
  100. mblt_vision/models/MobileNet_V3_Small.yaml +23 -0
  101. mblt_vision/models/RegNet_X_16GF.yaml +32 -0
  102. mblt_vision/models/RegNet_X_1_6GF.yaml +32 -0
  103. mblt_vision/models/RegNet_X_32GF.yaml +32 -0
  104. mblt_vision/models/RegNet_X_3_2GF.yaml +32 -0
  105. mblt_vision/models/RegNet_X_400MF.yaml +32 -0
  106. mblt_vision/models/RegNet_X_800MF.yaml +32 -0
  107. mblt_vision/models/RegNet_X_8GF.yaml +32 -0
  108. mblt_vision/models/RegNet_Y_16GF.yaml +76 -0
  109. mblt_vision/models/RegNet_Y_1_6GF.yaml +32 -0
  110. mblt_vision/models/RegNet_Y_32GF.yaml +76 -0
  111. mblt_vision/models/RegNet_Y_3_2GF.yaml +32 -0
  112. mblt_vision/models/RegNet_Y_400MF.yaml +32 -0
  113. mblt_vision/models/RegNet_Y_800MF.yaml +32 -0
  114. mblt_vision/models/RegNet_Y_8GF.yaml +32 -0
  115. mblt_vision/models/RepViT_M0_9.yaml +22 -0
  116. mblt_vision/models/RepViT_M1.yaml +22 -0
  117. mblt_vision/models/RepViT_M1_0.yaml +22 -0
  118. mblt_vision/models/RepViT_M1_1.yaml +22 -0
  119. mblt_vision/models/RepViT_M1_5.yaml +22 -0
  120. mblt_vision/models/RepViT_M2.yaml +22 -0
  121. mblt_vision/models/RepViT_M2_3.yaml +22 -0
  122. mblt_vision/models/RepViT_M3.yaml +22 -0
  123. mblt_vision/models/ResNeXt101_32X8D.yaml +32 -0
  124. mblt_vision/models/ResNeXt101_64X4D.yaml +23 -0
  125. mblt_vision/models/ResNeXt50_32X4D.yaml +32 -0
  126. mblt_vision/models/ResNet101.yaml +32 -0
  127. mblt_vision/models/ResNet152.yaml +32 -0
  128. mblt_vision/models/ResNet18.yaml +23 -0
  129. mblt_vision/models/ResNet34.yaml +23 -0
  130. mblt_vision/models/ResNet50.yaml +32 -0
  131. mblt_vision/models/ShuffleNet_V2_X0_5.yaml +23 -0
  132. mblt_vision/models/ShuffleNet_V2_X1_0.yaml +23 -0
  133. mblt_vision/models/ShuffleNet_V2_X1_5.yaml +23 -0
  134. mblt_vision/models/ShuffleNet_V2_X2_0.yaml +23 -0
  135. mblt_vision/models/SqueezeNet1_0.yaml +23 -0
  136. mblt_vision/models/SqueezeNet1_1.yaml +23 -0
  137. mblt_vision/models/Swin_B.yaml +23 -0
  138. mblt_vision/models/Swin_S.yaml +23 -0
  139. mblt_vision/models/Swin_T.yaml +23 -0
  140. mblt_vision/models/VGG11.yaml +23 -0
  141. mblt_vision/models/VGG11_BN.yaml +23 -0
  142. mblt_vision/models/VGG13.yaml +23 -0
  143. mblt_vision/models/VGG13_BN.yaml +23 -0
  144. mblt_vision/models/VGG16.yaml +23 -0
  145. mblt_vision/models/VGG16_BN.yaml +23 -0
  146. mblt_vision/models/VGG19.yaml +23 -0
  147. mblt_vision/models/VGG19_BN.yaml +23 -0
  148. mblt_vision/models/ViT_B_16.yaml +67 -0
  149. mblt_vision/models/ViT_B_32.yaml +23 -0
  150. mblt_vision/models/ViT_Base_Patch16_224.yaml +22 -0
  151. mblt_vision/models/ViT_Base_Patch16_384.yaml +22 -0
  152. mblt_vision/models/ViT_Base_Patch32_224.yaml +22 -0
  153. mblt_vision/models/ViT_Base_Patch32_384.yaml +22 -0
  154. mblt_vision/models/ViT_Base_Patch8_224.yaml +22 -0
  155. mblt_vision/models/ViT_L_16.yaml +67 -0
  156. mblt_vision/models/ViT_L_32.yaml +23 -0
  157. mblt_vision/models/ViT_Large_Patch16_224.yaml +22 -0
  158. mblt_vision/models/ViT_Large_Patch16_384.yaml +22 -0
  159. mblt_vision/models/ViT_Large_Patch32_384.yaml +22 -0
  160. mblt_vision/models/ViT_Small_Patch16_224.yaml +22 -0
  161. mblt_vision/models/ViT_Small_Patch16_384.yaml +22 -0
  162. mblt_vision/models/ViT_Small_Patch32_224.yaml +22 -0
  163. mblt_vision/models/ViT_Small_Patch32_384.yaml +22 -0
  164. mblt_vision/models/ViT_Tiny_Patch16_224.yaml +22 -0
  165. mblt_vision/models/ViT_Tiny_Patch16_384.yaml +22 -0
  166. mblt_vision/models/VisFormer_Small.yaml +22 -0
  167. mblt_vision/models/VisFormer_Tiny.yaml +22 -0
  168. mblt_vision/models/Wide_ResNet101_2.yaml +32 -0
  169. mblt_vision/models/Wide_ResNet50_2.yaml +32 -0
  170. mblt_vision/models/YOLO11l-cls.yaml +23 -0
  171. mblt_vision/models/YOLO11l-face.yaml +27 -0
  172. mblt_vision/models/YOLO11l-obb.yaml +28 -0
  173. mblt_vision/models/YOLO11l-pose.yaml +28 -0
  174. mblt_vision/models/YOLO11l-seg.yaml +28 -0
  175. mblt_vision/models/YOLO11l.yaml +27 -0
  176. mblt_vision/models/YOLO11m-cls.yaml +23 -0
  177. mblt_vision/models/YOLO11m-face.yaml +27 -0
  178. mblt_vision/models/YOLO11m-obb.yaml +28 -0
  179. mblt_vision/models/YOLO11m-pose.yaml +28 -0
  180. mblt_vision/models/YOLO11m-seg.yaml +28 -0
  181. mblt_vision/models/YOLO11m.yaml +27 -0
  182. mblt_vision/models/YOLO11n-cls.yaml +23 -0
  183. mblt_vision/models/YOLO11n-face.yaml +27 -0
  184. mblt_vision/models/YOLO11n-obb.yaml +28 -0
  185. mblt_vision/models/YOLO11n-pose.yaml +28 -0
  186. mblt_vision/models/YOLO11n-seg.yaml +28 -0
  187. mblt_vision/models/YOLO11n.yaml +27 -0
  188. mblt_vision/models/YOLO11s-cls.yaml +23 -0
  189. mblt_vision/models/YOLO11s-face.yaml +27 -0
  190. mblt_vision/models/YOLO11s-obb.yaml +28 -0
  191. mblt_vision/models/YOLO11s-pose.yaml +28 -0
  192. mblt_vision/models/YOLO11s-seg.yaml +28 -0
  193. mblt_vision/models/YOLO11s.yaml +27 -0
  194. mblt_vision/models/YOLO11x-cls.yaml +23 -0
  195. mblt_vision/models/YOLO11x-obb.yaml +28 -0
  196. mblt_vision/models/YOLO11x-pose.yaml +28 -0
  197. mblt_vision/models/YOLO11x-seg.yaml +28 -0
  198. mblt_vision/models/YOLO11x.yaml +27 -0
  199. mblt_vision/models/YOLO12l-face.yaml +27 -0
  200. mblt_vision/models/YOLO12l-seg.yaml +28 -0
  201. mblt_vision/models/YOLO12l.yaml +27 -0
  202. mblt_vision/models/YOLO12m-face.yaml +27 -0
  203. mblt_vision/models/YOLO12m-seg.yaml +28 -0
  204. mblt_vision/models/YOLO12m.yaml +27 -0
  205. mblt_vision/models/YOLO12n-face.yaml +27 -0
  206. mblt_vision/models/YOLO12n-seg.yaml +28 -0
  207. mblt_vision/models/YOLO12n.yaml +27 -0
  208. mblt_vision/models/YOLO12s-face.yaml +27 -0
  209. mblt_vision/models/YOLO12s-seg.yaml +28 -0
  210. mblt_vision/models/YOLO12s.yaml +27 -0
  211. mblt_vision/models/YOLO12x-seg.yaml +28 -0
  212. mblt_vision/models/YOLO12x.yaml +27 -0
  213. mblt_vision/models/YOLO26l-cls.yaml +23 -0
  214. mblt_vision/models/YOLO26l-depth.yaml +17 -0
  215. mblt_vision/models/YOLO26l-distill.yaml +27 -0
  216. mblt_vision/models/YOLO26l-obb.yaml +28 -0
  217. mblt_vision/models/YOLO26l-pose.yaml +28 -0
  218. mblt_vision/models/YOLO26l-seg.yaml +28 -0
  219. mblt_vision/models/YOLO26l-sem-ade20k.yaml +17 -0
  220. mblt_vision/models/YOLO26l-sem.yaml +17 -0
  221. mblt_vision/models/YOLO26l.yaml +27 -0
  222. mblt_vision/models/YOLO26m-cls.yaml +23 -0
  223. mblt_vision/models/YOLO26m-depth.yaml +17 -0
  224. mblt_vision/models/YOLO26m-distill.yaml +27 -0
  225. mblt_vision/models/YOLO26m-obb.yaml +28 -0
  226. mblt_vision/models/YOLO26m-pose.yaml +28 -0
  227. mblt_vision/models/YOLO26m-seg.yaml +28 -0
  228. mblt_vision/models/YOLO26m-sem-ade20k.yaml +17 -0
  229. mblt_vision/models/YOLO26m-sem.yaml +17 -0
  230. mblt_vision/models/YOLO26m.yaml +27 -0
  231. mblt_vision/models/YOLO26n-cls.yaml +23 -0
  232. mblt_vision/models/YOLO26n-depth.yaml +17 -0
  233. mblt_vision/models/YOLO26n-distill.yaml +27 -0
  234. mblt_vision/models/YOLO26n-obb.yaml +28 -0
  235. mblt_vision/models/YOLO26n-pose.yaml +28 -0
  236. mblt_vision/models/YOLO26n-seg.yaml +28 -0
  237. mblt_vision/models/YOLO26n-sem-ade20k.yaml +17 -0
  238. mblt_vision/models/YOLO26n-sem.yaml +17 -0
  239. mblt_vision/models/YOLO26n.yaml +27 -0
  240. mblt_vision/models/YOLO26s-cls.yaml +23 -0
  241. mblt_vision/models/YOLO26s-depth.yaml +17 -0
  242. mblt_vision/models/YOLO26s-distill.yaml +27 -0
  243. mblt_vision/models/YOLO26s-obb.yaml +28 -0
  244. mblt_vision/models/YOLO26s-pose.yaml +28 -0
  245. mblt_vision/models/YOLO26s-seg.yaml +28 -0
  246. mblt_vision/models/YOLO26s-sem-ade20k.yaml +17 -0
  247. mblt_vision/models/YOLO26s-sem.yaml +17 -0
  248. mblt_vision/models/YOLO26s.yaml +27 -0
  249. mblt_vision/models/YOLO26x-cls.yaml +23 -0
  250. mblt_vision/models/YOLO26x-depth.yaml +17 -0
  251. mblt_vision/models/YOLO26x-distill.yaml +27 -0
  252. mblt_vision/models/YOLO26x-obb.yaml +28 -0
  253. mblt_vision/models/YOLO26x-pose.yaml +28 -0
  254. mblt_vision/models/YOLO26x-seg.yaml +28 -0
  255. mblt_vision/models/YOLO26x-sem-ade20k.yaml +17 -0
  256. mblt_vision/models/YOLO26x-sem.yaml +17 -0
  257. mblt_vision/models/YOLO26x.yaml +27 -0
  258. mblt_vision/models/YOLOv10b.yaml +28 -0
  259. mblt_vision/models/YOLOv10l-face.yaml +28 -0
  260. mblt_vision/models/YOLOv10l.yaml +28 -0
  261. mblt_vision/models/YOLOv10m-face.yaml +28 -0
  262. mblt_vision/models/YOLOv10m.yaml +28 -0
  263. mblt_vision/models/YOLOv10n-face.yaml +28 -0
  264. mblt_vision/models/YOLOv10n.yaml +28 -0
  265. mblt_vision/models/YOLOv10s-face.yaml +28 -0
  266. mblt_vision/models/YOLOv10s.yaml +28 -0
  267. mblt_vision/models/YOLOv10x.yaml +28 -0
  268. mblt_vision/models/YOLOv3-spp.yaml +44 -0
  269. mblt_vision/models/YOLOv3-sppu.yaml +27 -0
  270. mblt_vision/models/YOLOv3-tiny.yaml +38 -0
  271. mblt_vision/models/YOLOv3-tinyu.yaml +27 -0
  272. mblt_vision/models/YOLOv3.yaml +44 -0
  273. mblt_vision/models/YOLOv3u.yaml +27 -0
  274. mblt_vision/models/YOLOv5l-cls.yaml +22 -0
  275. mblt_vision/models/YOLOv5l-seg.yaml +45 -0
  276. mblt_vision/models/YOLOv5l.yaml +44 -0
  277. mblt_vision/models/YOLOv5l6.yaml +50 -0
  278. mblt_vision/models/YOLOv5l6u.yaml +27 -0
  279. mblt_vision/models/YOLOv5lu.yaml +27 -0
  280. mblt_vision/models/YOLOv5m-cls.yaml +22 -0
  281. mblt_vision/models/YOLOv5m-seg.yaml +45 -0
  282. mblt_vision/models/YOLOv5m.yaml +45 -0
  283. mblt_vision/models/YOLOv5m6.yaml +50 -0
  284. mblt_vision/models/YOLOv5m6u.yaml +27 -0
  285. mblt_vision/models/YOLOv5mu.yaml +27 -0
  286. mblt_vision/models/YOLOv5n-cls.yaml +22 -0
  287. mblt_vision/models/YOLOv5n-seg.yaml +45 -0
  288. mblt_vision/models/YOLOv5n.yaml +44 -0
  289. mblt_vision/models/YOLOv5n6.yaml +50 -0
  290. mblt_vision/models/YOLOv5n6u.yaml +27 -0
  291. mblt_vision/models/YOLOv5nu.yaml +27 -0
  292. mblt_vision/models/YOLOv5s-cls.yaml +22 -0
  293. mblt_vision/models/YOLOv5s-seg.yaml +45 -0
  294. mblt_vision/models/YOLOv5s.yaml +44 -0
  295. mblt_vision/models/YOLOv5s6.yaml +50 -0
  296. mblt_vision/models/YOLOv5s6u.yaml +27 -0
  297. mblt_vision/models/YOLOv5su.yaml +27 -0
  298. mblt_vision/models/YOLOv5x-cls.yaml +22 -0
  299. mblt_vision/models/YOLOv5x-seg.yaml +45 -0
  300. mblt_vision/models/YOLOv5x.yaml +44 -0
  301. mblt_vision/models/YOLOv5x6.yaml +50 -0
  302. mblt_vision/models/YOLOv5x6u.yaml +27 -0
  303. mblt_vision/models/YOLOv5xu.yaml +27 -0
  304. mblt_vision/models/YOLOv6m-face.yaml +27 -0
  305. mblt_vision/models/YOLOv6n-face.yaml +27 -0
  306. mblt_vision/models/YOLOv7.yaml +44 -0
  307. mblt_vision/models/YOLOv7d6.yaml +50 -0
  308. mblt_vision/models/YOLOv7e6.yaml +50 -0
  309. mblt_vision/models/YOLOv7e6e.yaml +50 -0
  310. mblt_vision/models/YOLOv7w6.yaml +50 -0
  311. mblt_vision/models/YOLOv7x.yaml +44 -0
  312. mblt_vision/models/YOLOv8l-cls.yaml +23 -0
  313. mblt_vision/models/YOLOv8l-face.yaml +27 -0
  314. mblt_vision/models/YOLOv8l-obb.yaml +28 -0
  315. mblt_vision/models/YOLOv8l-pose.yaml +28 -0
  316. mblt_vision/models/YOLOv8l-seg.yaml +28 -0
  317. mblt_vision/models/YOLOv8l.yaml +27 -0
  318. mblt_vision/models/YOLOv8m-cls.yaml +23 -0
  319. mblt_vision/models/YOLOv8m-face.yaml +27 -0
  320. mblt_vision/models/YOLOv8m-obb.yaml +28 -0
  321. mblt_vision/models/YOLOv8m-pose.yaml +28 -0
  322. mblt_vision/models/YOLOv8m-seg.yaml +28 -0
  323. mblt_vision/models/YOLOv8m.yaml +27 -0
  324. mblt_vision/models/YOLOv8n-cls.yaml +23 -0
  325. mblt_vision/models/YOLOv8n-face.yaml +27 -0
  326. mblt_vision/models/YOLOv8n-obb.yaml +28 -0
  327. mblt_vision/models/YOLOv8n-pose.yaml +28 -0
  328. mblt_vision/models/YOLOv8n-seg.yaml +28 -0
  329. mblt_vision/models/YOLOv8n.yaml +27 -0
  330. mblt_vision/models/YOLOv8s-cls.yaml +23 -0
  331. mblt_vision/models/YOLOv8s-obb.yaml +28 -0
  332. mblt_vision/models/YOLOv8s-pose.yaml +28 -0
  333. mblt_vision/models/YOLOv8s-seg.yaml +28 -0
  334. mblt_vision/models/YOLOv8s.yaml +27 -0
  335. mblt_vision/models/YOLOv8x-cls.yaml +23 -0
  336. mblt_vision/models/YOLOv8x-obb.yaml +28 -0
  337. mblt_vision/models/YOLOv8x-pose-p6.yaml +28 -0
  338. mblt_vision/models/YOLOv8x-pose.yaml +28 -0
  339. mblt_vision/models/YOLOv8x-seg.yaml +28 -0
  340. mblt_vision/models/YOLOv8x.yaml +27 -0
  341. mblt_vision/models/YOLOv9c-seg.yaml +28 -0
  342. mblt_vision/models/YOLOv9c.yaml +27 -0
  343. mblt_vision/models/YOLOv9e-seg.yaml +28 -0
  344. mblt_vision/models/YOLOv9e.yaml +27 -0
  345. mblt_vision/models/YOLOv9m.yaml +27 -0
  346. mblt_vision/models/YOLOv9s.yaml +27 -0
  347. mblt_vision/models/YOLOv9t.yaml +27 -0
  348. mblt_vision/obb/__init__.py +39 -0
  349. mblt_vision/object_detection/__init__.py +153 -0
  350. mblt_vision/pose_estimation/__init__.py +41 -0
  351. mblt_vision/py.typed +1 -0
  352. mblt_vision/semantic_segmentation/__init__.py +29 -0
  353. mblt_vision/utils/__init__.py +0 -0
  354. mblt_vision/utils/datasets/__init__.py +85 -0
  355. mblt_vision/utils/datasets/ade20k.py +41 -0
  356. mblt_vision/utils/datasets/cityscapes.py +66 -0
  357. mblt_vision/utils/datasets/coco.py +243 -0
  358. mblt_vision/utils/datasets/dataloader.py +1016 -0
  359. mblt_vision/utils/datasets/dotav1.py +59 -0
  360. mblt_vision/utils/datasets/imagenet.py +29 -0
  361. mblt_vision/utils/datasets/organizer.py +2145 -0
  362. mblt_vision/utils/datasets/readiness.py +1063 -0
  363. mblt_vision/utils/evaluation/__init__.py +51 -0
  364. mblt_vision/utils/evaluation/_result.py +22 -0
  365. mblt_vision/utils/evaluation/eval_ade20k.py +302 -0
  366. mblt_vision/utils/evaluation/eval_cityscapes.py +32 -0
  367. mblt_vision/utils/evaluation/eval_coco.py +465 -0
  368. mblt_vision/utils/evaluation/eval_dota.py +878 -0
  369. mblt_vision/utils/evaluation/eval_imagenet.py +151 -0
  370. mblt_vision/utils/evaluation/eval_nyu_depth.py +189 -0
  371. mblt_vision/utils/evaluation/eval_widerface.py +440 -0
  372. mblt_vision/utils/letterbox.py +118 -0
  373. mblt_vision/utils/postprocess/__init__.py +9 -0
  374. mblt_vision/utils/postprocess/_letterbox.py +102 -0
  375. mblt_vision/utils/postprocess/base.py +743 -0
  376. mblt_vision/utils/postprocess/build_post.py +120 -0
  377. mblt_vision/utils/postprocess/cls_post.py +117 -0
  378. mblt_vision/utils/postprocess/common.py +1571 -0
  379. mblt_vision/utils/postprocess/depth_post.py +106 -0
  380. mblt_vision/utils/postprocess/semantic_seg_post.py +192 -0
  381. mblt_vision/utils/postprocess/yolo_anchor_post.py +469 -0
  382. mblt_vision/utils/postprocess/yolo_anchorless_post.py +952 -0
  383. mblt_vision/utils/postprocess/yolo_dflfree_post.py +983 -0
  384. mblt_vision/utils/postprocess/yolo_nmsfree_post.py +176 -0
  385. mblt_vision/utils/preprocess/__init__.py +27 -0
  386. mblt_vision/utils/preprocess/_validation.py +66 -0
  387. mblt_vision/utils/preprocess/base.py +157 -0
  388. mblt_vision/utils/preprocess/build_pre.py +48 -0
  389. mblt_vision/utils/preprocess/center_crop.py +75 -0
  390. mblt_vision/utils/preprocess/letterbox.py +123 -0
  391. mblt_vision/utils/preprocess/normalize.py +94 -0
  392. mblt_vision/utils/preprocess/order.py +74 -0
  393. mblt_vision/utils/preprocess/reader.py +94 -0
  394. mblt_vision/utils/preprocess/resize.py +202 -0
  395. mblt_vision/utils/preprocess/yolo_pre.py +7 -0
  396. mblt_vision/utils/results.py +725 -0
  397. mblt_vision/utils/types.py +15 -0
  398. mblt_vision/wrapper.py +1121 -0
  399. mblt_vision_python-0.0.0.dist-info/METADATA +152 -0
  400. mblt_vision_python-0.0.0.dist-info/RECORD +404 -0
  401. mblt_vision_python-0.0.0.dist-info/WHEEL +5 -0
  402. mblt_vision_python-0.0.0.dist-info/entry_points.txt +2 -0
  403. mblt_vision_python-0.0.0.dist-info/licenses/LICENSE +28 -0
  404. mblt_vision_python-0.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1120 @@
1
+ """Vision model compilation and calibration-data preparation."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import hashlib
6
+ import importlib
7
+ import json
8
+ import shutil
9
+ import warnings
10
+ from collections.abc import Callable, Mapping, Sequence
11
+ from pathlib import Path
12
+ from tempfile import TemporaryDirectory, mkdtemp
13
+ from typing import Any
14
+
15
+ import numpy as np
16
+ import torch
17
+ from huggingface_hub import hf_hub_download
18
+ from huggingface_hub.errors import HfHubHTTPError
19
+ from mblt_vision.utils.datasets.readiness import (
20
+ _path_has_symlink_component,
21
+ dataset_ready,
22
+ )
23
+
24
+ from mblt_vision._tasks import normalize_vision_task
25
+ from mblt_vision.datasets import get_dataset_config_for_task
26
+ from mblt_npu import normalize_target_device
27
+ from mblt_vision.wrapper import (
28
+ MOBILINT_CACHE_DIR,
29
+ MBLT_Engine,
30
+ get_mobilint_cache_dir,
31
+ resolve_model_config,
32
+ )
33
+
34
+ DEFAULT_PERCENTILE = 0.9999
35
+ DEFAULT_TOPK_RATIO = 0.01
36
+ DEFAULT_SEED = 0
37
+ DEFAULT_MODEL_DIR = Path(MOBILINT_CACHE_DIR)
38
+ SUPPORTED_TARGET_DEVICES = frozenset({"aries-rb", "regulus-ra", "regulus-rb"})
39
+ DEFAULT_SUBSET_SIZES = {
40
+ "image_classification": 1,
41
+ "depth_estimation": 100,
42
+ "object_detection": 100,
43
+ "instance_segmentation": 100,
44
+ "semantic_segmentation": 100,
45
+ "pose_estimation": 100,
46
+ "face_detection": 1,
47
+ "obb": 100,
48
+ }
49
+ IMAGE_SUFFIXES = {".bmp", ".jpeg", ".jpg", ".png", ".tif", ".tiff", ".webp"}
50
+
51
+
52
+ def _default_model_dir() -> Path:
53
+ """Return the writable default compilation output directory lazily."""
54
+
55
+ if DEFAULT_MODEL_DIR != Path(MOBILINT_CACHE_DIR):
56
+ return DEFAULT_MODEL_DIR
57
+ return Path(get_mobilint_cache_dir())
58
+
59
+
60
+ def _normalize_task(task: str) -> str:
61
+ """Validate and normalize a supported task name.
62
+
63
+ Args:
64
+ task: Task value from a model postprocess configuration.
65
+
66
+ Returns:
67
+ Canonical task name used by the dataset registry.
68
+
69
+ Raises:
70
+ ValueError: If the task is not supported by vision compilation.
71
+ """
72
+
73
+ return normalize_vision_task(task, supported=DEFAULT_SUBSET_SIZES)
74
+
75
+
76
+ def _validate_calibration_output_dir(output_dir: str | Path) -> Path:
77
+ """Return an output path only when it and its ancestors are not symlinks."""
78
+
79
+ destination = Path(output_dir).expanduser()
80
+ if _path_has_symlink_component(destination):
81
+ raise ValueError(
82
+ f"Calibration output_dir must not be or contain a symlink: {destination}."
83
+ )
84
+ return destination
85
+
86
+
87
+ def _dataset_ready(task: str, data_path: Path, dataset: str | None = None) -> bool:
88
+ """Return whether an organized dataset contains calibration images.
89
+
90
+ Args:
91
+ task: Canonical vision task name.
92
+ data_path: Organized dataset root.
93
+ dataset: Optional dense dataset taxonomy.
94
+
95
+ Returns:
96
+ Whether the expected dataset identity, metadata, and full validation split are present.
97
+ """
98
+
99
+ return dataset_ready(data_path, task, dataset)
100
+
101
+
102
+ def _find_dataset_source(data_path: Path, filename: str) -> Path | None:
103
+ """Find a manually supplied dataset source at or beside its organized root.
104
+
105
+ Args:
106
+ data_path: Organized dataset destination.
107
+ filename: Archive filename to locate.
108
+
109
+ Returns:
110
+ Existing archive path, or ``None`` when it is unavailable.
111
+ """
112
+
113
+ for directory in (data_path, data_path.parent):
114
+ candidate = directory / filename
115
+ if candidate.is_file():
116
+ return candidate
117
+ return None
118
+
119
+
120
+ def _organize_dataset(task: str, data_path: Path, dataset: str | None = None) -> None:
121
+ """Organize the registry-backed dataset required by a task.
122
+
123
+ Args:
124
+ task: Canonical vision task name.
125
+ data_path: Destination dataset root.
126
+ dataset: Optional dataset taxonomy used to disambiguate semantic datasets.
127
+ """
128
+
129
+ from mblt_vision.utils.datasets import (
130
+ organize_ade20k,
131
+ organize_cityscapes,
132
+ organize_coco,
133
+ organize_dotav1,
134
+ organize_imagenet,
135
+ organize_nyu_depth,
136
+ organize_widerface,
137
+ )
138
+
139
+ config = get_dataset_config_for_task(task, dataset)
140
+ download = config.get("download")
141
+ if not isinstance(download, dict):
142
+ raise ValueError(
143
+ f"Dataset `{config.get('name', task)}` does not define download metadata."
144
+ )
145
+
146
+ data_path.parent.mkdir(parents=True, exist_ok=True)
147
+ if task == "image_classification":
148
+ organize_imagenet(
149
+ image_dir=str(download["images"]),
150
+ xml_dir=str(download["annotations"]),
151
+ output_dir=str(data_path),
152
+ )
153
+ elif task in {"object_detection", "instance_segmentation", "pose_estimation"}:
154
+ organize_coco(
155
+ image_dir=str(download["images"]),
156
+ annotation_dir=str(download["annotations"]),
157
+ output_dir=str(data_path),
158
+ )
159
+ elif task == "face_detection":
160
+ organize_widerface(
161
+ image_dir=str(download["images"]),
162
+ annotation_dir=str(download["annotations"]),
163
+ output_dir=str(data_path),
164
+ )
165
+ elif task == "obb":
166
+ organize_dotav1(dataset_path=str(download["url"]), output_dir=str(data_path))
167
+ elif task == "depth_estimation":
168
+ organize_nyu_depth(dataset_path=str(download["url"]), output_dir=str(data_path))
169
+ elif config["name"] == "ade20k":
170
+ organize_ade20k(dataset_path=str(download["url"]), output_dir=str(data_path))
171
+ elif config["name"] == "cityscapes":
172
+ image_archive = _find_dataset_source(data_path, str(download["images_archive"]))
173
+ annotation_archive = _find_dataset_source(
174
+ data_path, str(download["annotations_archive"])
175
+ )
176
+ if image_archive is None or annotation_archive is None:
177
+ raise ValueError(
178
+ "Cityscapes compilation requires leftImg8bit_trainvaltest.zip and gtFine_trainvaltest.zip "
179
+ f"at {data_path} or {data_path.parent}."
180
+ )
181
+ organize_cityscapes(
182
+ image_dir=str(image_archive),
183
+ annotation_dir=str(annotation_archive),
184
+ output_dir=str(data_path),
185
+ )
186
+ else:
187
+ raise ValueError(
188
+ f"Unsupported calibration dataset `{config['name']}` for task `{task}`."
189
+ )
190
+
191
+
192
+ def ensure_calibration_dataset(
193
+ task: str,
194
+ data_path: str | Path | None = None,
195
+ dataset: str | None = None,
196
+ ) -> Path:
197
+ """Resolve and, when needed, organize a calibration dataset.
198
+
199
+ Args:
200
+ task: Vision task name.
201
+ data_path: Optional organized dataset root.
202
+ dataset: Optional dataset taxonomy from the model postprocess configuration.
203
+
204
+ Returns:
205
+ Expanded organized dataset root.
206
+ """
207
+
208
+ normalized_task = _normalize_task(task)
209
+ config = get_dataset_config_for_task(normalized_task, dataset)
210
+ dataset_name = str(config["name"])
211
+ resolved_path = (
212
+ Path(data_path).expanduser()
213
+ if data_path is not None
214
+ else _resolve_default_dataset_path(config["path"])
215
+ )
216
+ if not _dataset_ready(normalized_task, resolved_path, dataset_name):
217
+ _organize_dataset(normalized_task, resolved_path, dataset)
218
+ if not _dataset_ready(normalized_task, resolved_path, dataset_name):
219
+ raise ValueError(
220
+ f"Organized calibration dataset at {resolved_path} is incomplete or does not match "
221
+ f"the expected {dataset_name} dataset."
222
+ )
223
+ return resolved_path
224
+
225
+
226
+ def _resolve_default_dataset_path(configured_path: str | Path) -> Path:
227
+ """Translate registry cache paths to the active writable artifact cache."""
228
+
229
+ path = Path(configured_path).expanduser()
230
+ default_cache_root = Path.home() / ".mblt_model_zoo"
231
+ try:
232
+ relative_path = path.relative_to(default_cache_root)
233
+ except ValueError:
234
+ return path
235
+ return Path(get_mobilint_cache_dir()) / relative_path
236
+
237
+
238
+ def _validate_subset_size(subset_size: int) -> None:
239
+ """Validate a requested calibration subset size.
240
+
241
+ Args:
242
+ subset_size: Requested per-class or total sample count.
243
+
244
+ Raises:
245
+ ValueError: If the size is not positive.
246
+ """
247
+
248
+ if subset_size <= 0:
249
+ raise ValueError("subset_size must be greater than zero.")
250
+
251
+
252
+ def _validate_calibration_image(image_path: Path, dataset_root: Path) -> Path:
253
+ """Resolve and validate a calibration image within its dataset root.
254
+
255
+ Args:
256
+ image_path: Candidate calibration image path.
257
+ dataset_root: Resolved organized dataset root.
258
+
259
+ Returns:
260
+ Resolved regular image path.
261
+
262
+ Raises:
263
+ ValueError: If the candidate is a symlink, not a regular image, or escapes the dataset root.
264
+ """
265
+
266
+ if image_path.is_symlink():
267
+ raise ValueError(f"Calibration image must not be a symlink: {image_path}.")
268
+ try:
269
+ source = image_path.resolve(strict=True)
270
+ except OSError as exc:
271
+ raise ValueError(
272
+ f"Unable to resolve calibration image {image_path}: {exc}."
273
+ ) from exc
274
+ if not source.is_file() or source.suffix.lower() not in IMAGE_SUFFIXES:
275
+ raise ValueError(
276
+ f"Calibration image must be a supported regular image file: {image_path}."
277
+ )
278
+ if not source.is_relative_to(dataset_root):
279
+ raise ValueError(
280
+ f"Calibration image must remain within dataset root: {image_path}."
281
+ )
282
+ return source
283
+
284
+
285
+ def _selectable_calibration_images(
286
+ paths: Sequence[Path], dataset_root: Path
287
+ ) -> list[Path]:
288
+ """Validate supported image candidates before they enter subset sampling.
289
+
290
+ Args:
291
+ paths: Candidate filesystem paths.
292
+ dataset_root: Resolved organized dataset root.
293
+
294
+ Returns:
295
+ Validated candidate paths, retaining their original names for stable sampling.
296
+ """
297
+
298
+ images: list[Path] = []
299
+ for path in paths:
300
+ if path.suffix.lower() in IMAGE_SUFFIXES and (
301
+ path.is_symlink() or path.is_file()
302
+ ):
303
+ _validate_calibration_image(path, dataset_root)
304
+ images.append(path)
305
+ return images
306
+
307
+
308
+ def select_calibration_images(
309
+ task: str,
310
+ data_path: str | Path,
311
+ subset_size: int | None = None,
312
+ seed: int = DEFAULT_SEED,
313
+ ) -> list[Path]:
314
+ """Select deterministic calibration images from an organized dataset.
315
+
316
+ For ImageNet and WiderFace, ``subset_size`` is the number selected from
317
+ every category. For all other datasets it is the total number of selected
318
+ validation images.
319
+
320
+ Args:
321
+ task: Vision task name.
322
+ data_path: Organized dataset root.
323
+ subset_size: Optional sample count, using task-specific defaults when omitted.
324
+ seed: Random selection seed.
325
+
326
+ Returns:
327
+ Selected image paths in deterministic order.
328
+
329
+ Raises:
330
+ ValueError: If the dataset layout or requested size is invalid.
331
+ """
332
+
333
+ import random
334
+
335
+ normalized_task = _normalize_task(task)
336
+ root = Path(data_path).expanduser()
337
+ resolved_root = root.resolve()
338
+ requested_size = (
339
+ DEFAULT_SUBSET_SIZES[normalized_task] if subset_size is None else subset_size
340
+ )
341
+ _validate_subset_size(requested_size)
342
+ random_generator = random.Random(seed)
343
+
344
+ if normalized_task in {"image_classification", "face_detection"}:
345
+ category_root = (
346
+ root if normalized_task == "image_classification" else root / "images"
347
+ )
348
+ dataset_name = (
349
+ "ImageNet" if normalized_task == "image_classification" else "WiderFace"
350
+ )
351
+ category_dirs = (
352
+ sorted(path for path in category_root.iterdir() if path.is_dir())
353
+ if category_root.is_dir()
354
+ else []
355
+ )
356
+ if not category_dirs:
357
+ raise ValueError(
358
+ f"No {dataset_name} category directories found in {category_root}."
359
+ )
360
+ selected: list[Path] = []
361
+ for category_dir in category_dirs:
362
+ images = _selectable_calibration_images(
363
+ sorted(category_dir.iterdir()), resolved_root
364
+ )
365
+ if requested_size > len(images):
366
+ raise ValueError(
367
+ f"subset_size ({requested_size}) exceeds the {len(images)} available images in {category_dir.name}."
368
+ )
369
+ selected.extend(random_generator.sample(images, requested_size))
370
+ return selected
371
+
372
+ image_dir = {
373
+ "depth_estimation": root / "images",
374
+ "object_detection": root / "val2017",
375
+ "instance_segmentation": root / "val2017",
376
+ "semantic_segmentation": root / "images",
377
+ "pose_estimation": root / "val2017",
378
+ "obb": root / "images",
379
+ }[normalized_task]
380
+ images = (
381
+ _selectable_calibration_images(sorted(image_dir.rglob("*")), resolved_root)
382
+ if image_dir.is_dir()
383
+ else []
384
+ )
385
+ if not images:
386
+ raise ValueError(f"No calibration images found in {image_dir}.")
387
+ if requested_size > len(images):
388
+ raise ValueError(
389
+ f"subset_size ({requested_size}) exceeds the {len(images)} available images in {image_dir}."
390
+ )
391
+ return random_generator.sample(images, requested_size)
392
+
393
+
394
+ def copy_calibration_subset(
395
+ images: Sequence[Path], data_path: str | Path, output_dir: str | Path
396
+ ) -> list[Path]:
397
+ """Copy selected images into a flat directory using collision-safe names.
398
+
399
+ Args:
400
+ images: Selected source image paths.
401
+ data_path: Dataset root used to derive stable relative names.
402
+ output_dir: Destination directory.
403
+
404
+ Returns:
405
+ Copied image paths in input order.
406
+ """
407
+
408
+ root = Path(data_path).expanduser().resolve()
409
+ destination = _validate_calibration_output_dir(output_dir)
410
+ destination.mkdir(parents=True, exist_ok=True)
411
+ copied: list[Path] = []
412
+ for image_path in images:
413
+ source = _validate_calibration_image(image_path, root)
414
+ relative_name = source.relative_to(root).as_posix()
415
+ digest = hashlib.sha256(relative_name.encode()).hexdigest()[:12]
416
+ target = destination / f"{digest}_{source.name}"
417
+ if target.exists():
418
+ raise ValueError(f"Calibration subset filename collision for {source}.")
419
+ shutil.copy2(source, target)
420
+ copied.append(target)
421
+ return copied
422
+
423
+
424
+ def make_calibration_subset(
425
+ task: str,
426
+ data_path: str | Path,
427
+ output_dir: str | Path,
428
+ subset_size: int | None = None,
429
+ seed: int = DEFAULT_SEED,
430
+ ) -> list[Path]:
431
+ """Select and copy a deterministic flat calibration subset.
432
+
433
+ Args:
434
+ task: Vision task name.
435
+ data_path: Organized dataset root.
436
+ output_dir: Destination for copied images.
437
+ subset_size: Optional task-specific selection count.
438
+ seed: Random selection seed.
439
+
440
+ Returns:
441
+ Copied image paths.
442
+ """
443
+
444
+ source_root = Path(data_path).expanduser().resolve()
445
+ destination = _validate_calibration_output_dir(output_dir).resolve()
446
+ if source_root.is_relative_to(destination) or destination.is_relative_to(
447
+ source_root
448
+ ):
449
+ raise ValueError("output_dir must not overlap data_path.")
450
+ images = select_calibration_images(task, data_path, subset_size, seed)
451
+ destination.parent.mkdir(parents=True, exist_ok=True)
452
+ temporary_destination = Path(
453
+ mkdtemp(prefix=f".{destination.name}-", dir=destination.parent)
454
+ )
455
+ try:
456
+ copied = copy_calibration_subset(images, data_path, temporary_destination)
457
+ backup_destination: Path | None = None
458
+ if destination.exists():
459
+ backup_destination = Path(
460
+ mkdtemp(prefix=f".{destination.name}-backup-", dir=destination.parent)
461
+ )
462
+ backup_destination.rmdir()
463
+ destination.replace(backup_destination)
464
+ try:
465
+ temporary_destination.replace(destination)
466
+ except BaseException:
467
+ if backup_destination is not None and not destination.exists():
468
+ backup_destination.replace(destination)
469
+ raise
470
+ if backup_destination is not None:
471
+ shutil.rmtree(backup_destination)
472
+ return [destination / path.name for path in copied]
473
+ finally:
474
+ if temporary_destination.exists():
475
+ shutil.rmtree(temporary_destination)
476
+
477
+
478
+ def _as_hwc_float32(value: Any, image_path: Path) -> np.ndarray:
479
+ """Validate and convert engine preprocessing output for qbcompiler.
480
+
481
+ Args:
482
+ value: Engine preprocessing result.
483
+ image_path: Source image used for error context.
484
+
485
+ Returns:
486
+ Contiguous HWC float32 array.
487
+
488
+ Raises:
489
+ TypeError: If preprocessing did not return a tensor or array.
490
+ ValueError: If preprocessing did not return HWC three-channel data.
491
+ """
492
+
493
+ if isinstance(value, torch.Tensor):
494
+ array = value.detach().cpu().numpy()
495
+ elif isinstance(value, np.ndarray):
496
+ array = value
497
+ else:
498
+ raise TypeError(
499
+ f"Preprocessing {image_path} returned unsupported type {type(value).__name__}."
500
+ )
501
+ if array.ndim != 3 or array.shape[-1] != 3:
502
+ raise ValueError(
503
+ f"Preprocessing {image_path} must produce an HWC three-channel array; got shape {array.shape}."
504
+ )
505
+ return np.ascontiguousarray(array, dtype=np.float32)
506
+
507
+
508
+ def prepare_calibration_arrays(
509
+ engine: MBLT_Engine, images: Sequence[Path], output_dir: str | Path
510
+ ) -> list[Path]:
511
+ """Preprocess calibration images and save one NumPy array per sample.
512
+
513
+ Args:
514
+ engine: ONNX vision engine providing authoritative preprocessing.
515
+ images: Flat calibration image paths.
516
+ output_dir: Destination directory for ``.npy`` arrays.
517
+
518
+ Returns:
519
+ Saved NumPy paths.
520
+ """
521
+
522
+ destination = _validate_calibration_output_dir(output_dir)
523
+ destination.mkdir(parents=True, exist_ok=True)
524
+ saved: list[Path] = []
525
+ for index, image_path in enumerate(images):
526
+ array = _as_hwc_float32(engine.preprocess(str(image_path)), image_path)
527
+ array_path = destination / f"{index:06d}.npy"
528
+ np.save(array_path, array)
529
+ saved.append(array_path)
530
+ return saved
531
+
532
+
533
+ def get_subset_images(subset_path: str | Path) -> list[Path]:
534
+ """Load all images from an already-sampled subset.
535
+
536
+ Args:
537
+ subset_path: Root containing sampled images, either flat or nested.
538
+
539
+ Returns:
540
+ Image paths in deterministic order.
541
+
542
+ Raises:
543
+ ValueError: If the subset contains no supported image files.
544
+ """
545
+
546
+ root = Path(subset_path).expanduser()
547
+ images = (
548
+ sorted(
549
+ path
550
+ for path in root.rglob("*")
551
+ if path.is_file() and path.suffix.lower() in IMAGE_SUFFIXES
552
+ )
553
+ if root.is_dir()
554
+ else []
555
+ )
556
+ if not images:
557
+ raise ValueError(f"No calibration subset images found in {root}.")
558
+ return images
559
+
560
+
561
+ def _calibration_image_shape(pre_cfg: Mapping[str, Any]) -> tuple[int, int]:
562
+ """Derive the final HWC spatial shape produced by a model preprocessor."""
563
+
564
+ image_shape: tuple[int, int] | None = None
565
+ for operation, config in pre_cfg.items():
566
+ if operation not in {"LetterBox", "Resize", "CenterCrop"} or not isinstance(
567
+ config, Mapping
568
+ ):
569
+ continue
570
+ size = config.get("img_size", config.get("size"))
571
+ if isinstance(size, int) and not isinstance(size, bool) and size > 0:
572
+ image_shape = (size, size)
573
+ elif (
574
+ isinstance(size, Sequence)
575
+ and not isinstance(size, (str, bytes))
576
+ and len(size) == 2
577
+ and all(
578
+ isinstance(value, int) and not isinstance(value, bool) and value > 0
579
+ for value in size
580
+ )
581
+ ):
582
+ image_shape = (size[0], size[1])
583
+ if image_shape is None:
584
+ raise ValueError(
585
+ "Unable to derive calibration image shape from pre_cfg; expected a "
586
+ "positive LetterBox.img_size, Resize.size, or CenterCrop.size."
587
+ )
588
+ return image_shape
589
+
590
+
591
+ def validate_calibration_dataset(
592
+ calib_data_path: str | Path,
593
+ *,
594
+ image_shape: tuple[int, int] | None = None,
595
+ ) -> Path:
596
+ """Validate a ready directory of preprocessed calibration arrays.
597
+
598
+ Args:
599
+ calib_data_path: Directory containing HWC float32 ``.npy`` tensors.
600
+
601
+ Returns:
602
+ Expanded calibration directory path.
603
+
604
+ Raises:
605
+ ValueError: If the directory is empty or contains an invalid calibration tensor.
606
+ """
607
+
608
+ root = Path(calib_data_path).expanduser()
609
+ array_paths = sorted(root.glob("*.npy")) if root.is_dir() else []
610
+ if not array_paths:
611
+ raise ValueError(f"No calibration .npy files found in {root}.")
612
+ for array_path in array_paths:
613
+ try:
614
+ array = np.load(array_path, mmap_mode="r", allow_pickle=False)
615
+ except (OSError, ValueError) as exc:
616
+ raise ValueError(
617
+ f"Unable to load calibration tensor {array_path}: {exc}."
618
+ ) from exc
619
+ if array.ndim != 3 or array.shape[-1] != 3:
620
+ raise ValueError(
621
+ f"Calibration tensor {array_path} must be HWC with three channels; got {array.shape}."
622
+ )
623
+ if image_shape is not None and array.shape[:2] != image_shape:
624
+ raise ValueError(
625
+ f"Calibration tensor {array_path} must match the model pre_cfg "
626
+ f"image shape {image_shape}, got {array.shape[:2]}."
627
+ )
628
+ if array.dtype != np.float32:
629
+ raise ValueError(
630
+ f"Calibration tensor {array_path} must use float32; got {array.dtype}."
631
+ )
632
+ if not np.isfinite(array).all():
633
+ raise ValueError(
634
+ f"Calibration tensor {array_path} must contain only finite values."
635
+ )
636
+ if not array.flags.c_contiguous:
637
+ raise ValueError(f"Calibration tensor {array_path} must be C-contiguous.")
638
+ return root
639
+
640
+
641
+ def _validate_data_level_paths(
642
+ data_path: str | Path | None,
643
+ subset_path: str | Path | None,
644
+ calib_data_path: str | Path | None,
645
+ ) -> None:
646
+ """Ensure at most one calibration pipeline entry level is supplied.
647
+
648
+ Args:
649
+ data_path: Original organized dataset root.
650
+ subset_path: Already-sampled image subset root.
651
+ calib_data_path: Ready preprocessed NumPy dataset root.
652
+
653
+ Raises:
654
+ ValueError: If more than one data level is supplied.
655
+ """
656
+
657
+ supplied = [
658
+ name
659
+ for name, value in (
660
+ ("data_path", data_path),
661
+ ("subset_path", subset_path),
662
+ ("calib_data_path", calib_data_path),
663
+ )
664
+ if value is not None
665
+ ]
666
+ if len(supplied) > 1:
667
+ raise ValueError(
668
+ "Provide only one calibration pipeline input: `data_path`, `subset_path`, or `calib_data_path`; "
669
+ f"got {', '.join(supplied)}."
670
+ )
671
+
672
+
673
+ def _load_qbcompiler() -> tuple[Callable[..., Any], type[Any]]:
674
+ """Load qbcompiler only when compilation is requested.
675
+
676
+ Returns:
677
+ The ``mxq_compile`` function and ``CalibrationConfig`` class.
678
+
679
+ Raises:
680
+ ImportError: If qbcompiler is not installed.
681
+ """
682
+
683
+ try:
684
+ module = importlib.import_module("qbcompiler")
685
+ except ImportError as exc:
686
+ raise ImportError(
687
+ "Vision compilation requires qbcompiler>=1.2.0. Install the compiler package supplied by Mobilint."
688
+ ) from exc
689
+ return module.mxq_compile, module.CalibrationConfig
690
+
691
+
692
+ def _validate_ratio(name: str, value: Any) -> float:
693
+ """Validate a quantization ratio.
694
+
695
+ Args:
696
+ name: Field name used in an error message.
697
+ value: Candidate numeric ratio.
698
+
699
+ Returns:
700
+ Validated float value.
701
+
702
+ Raises:
703
+ ValueError: If the value is non-numeric or outside zero to one.
704
+ """
705
+
706
+ if isinstance(value, bool) or not isinstance(value, (int, float)):
707
+ raise ValueError(
708
+ f"Quantization metadata `{name}` must be numeric, got {value!r}."
709
+ )
710
+ resolved = float(value)
711
+ if not 0.0 <= resolved <= 1.0:
712
+ raise ValueError(
713
+ f"Quantization metadata `{name}` must be between 0 and 1, got {resolved}."
714
+ )
715
+ return resolved
716
+
717
+
718
+ def _fetch_quantization_config(
719
+ repo_id: str, revision: str, target_device: str = "aries-rb"
720
+ ) -> dict[str, Any] | None:
721
+ """Fetch optional hosted board quantization metadata.
722
+
723
+ Args:
724
+ repo_id: Hugging Face model repository ID.
725
+ revision: Repository revision.
726
+ target_device: Board folder containing the metadata.
727
+
728
+ Returns:
729
+ Hosted ``config`` mapping, or ``None`` when the optional file is unavailable.
730
+
731
+ Raises:
732
+ ValueError: If the hosted JSON or its ``config`` field is malformed.
733
+ """
734
+
735
+ try:
736
+ metadata_path = hf_hub_download(
737
+ repo_id=repo_id,
738
+ filename="best_result.json",
739
+ subfolder=normalize_target_device(target_device),
740
+ revision=revision,
741
+ )
742
+ except (HfHubHTTPError, OSError) as exc:
743
+ warnings.warn(
744
+ f"Unable to load optional quantization metadata for {repo_id}: {exc}. Using fallback values.",
745
+ stacklevel=2,
746
+ )
747
+ return None
748
+
749
+ try:
750
+ with Path(metadata_path).open(encoding="utf-8") as metadata_file:
751
+ metadata = json.load(metadata_file)
752
+ except json.JSONDecodeError as exc:
753
+ raise ValueError(
754
+ f"Malformed quantization metadata JSON at {metadata_path}: {exc.msg}."
755
+ ) from exc
756
+ if not isinstance(metadata, dict) or not isinstance(metadata.get("config"), dict):
757
+ raise ValueError(
758
+ f"Quantization metadata at {metadata_path} must contain a `config` object."
759
+ )
760
+ return metadata["config"]
761
+
762
+
763
+ def resolve_quantization_values(
764
+ file_cfg: dict[str, Any],
765
+ percentile: float | None,
766
+ topk_ratio: float | None,
767
+ ) -> tuple[float, float]:
768
+ """Resolve explicit, hosted, and fallback quantization values independently.
769
+
770
+ Args:
771
+ file_cfg: Resolved model file configuration.
772
+ percentile: Explicit compiler percentile override.
773
+ topk_ratio: Explicit compiler top-k ratio override.
774
+
775
+ Returns:
776
+ Resolved percentile and top-k ratio.
777
+
778
+ Raises:
779
+ ValueError: If explicit or hosted values are malformed.
780
+ """
781
+
782
+ resolved_percentile = (
783
+ _validate_ratio("percentile", percentile) if percentile is not None else None
784
+ )
785
+ resolved_topk = (
786
+ _validate_ratio("topk_ratio", topk_ratio) if topk_ratio is not None else None
787
+ )
788
+ hosted_config: dict[str, Any] | None = None
789
+ if resolved_percentile is None or resolved_topk is None:
790
+ repo_id = file_cfg.get("repo_id")
791
+ revision = file_cfg.get("revision", "main")
792
+ if isinstance(repo_id, str) and repo_id:
793
+ target_device = file_cfg.get("target_device")
794
+ if isinstance(target_device, str):
795
+ hosted_config = _fetch_quantization_config(
796
+ repo_id, str(revision), normalize_target_device(target_device)
797
+ )
798
+ else:
799
+ hosted_config = _fetch_quantization_config(repo_id, str(revision))
800
+ else:
801
+ warnings.warn(
802
+ "Model configuration has no repository ID; using fallback quantization values.",
803
+ stacklevel=2,
804
+ )
805
+
806
+ if (
807
+ resolved_percentile is None
808
+ and hosted_config is not None
809
+ and "percentile" in hosted_config
810
+ ):
811
+ hosted_percentile = _validate_ratio(
812
+ "config.percentile", hosted_config["percentile"]
813
+ )
814
+ resolved_percentile = 1.0 - hosted_percentile
815
+ if resolved_topk is None and hosted_config is not None:
816
+ hosted_topk = hosted_config.get("topk_ratio", hosted_config.get("topk"))
817
+ if hosted_topk is not None:
818
+ resolved_topk = _validate_ratio("config.topk_ratio", hosted_topk)
819
+
820
+ if resolved_percentile is None:
821
+ warnings.warn(
822
+ f"Quantization percentile is unavailable; using {DEFAULT_PERCENTILE}.",
823
+ stacklevel=2,
824
+ )
825
+ resolved_percentile = DEFAULT_PERCENTILE
826
+ if resolved_topk is None:
827
+ warnings.warn(
828
+ f"Quantization top-k ratio is unavailable; using {DEFAULT_TOPK_RATIO}.",
829
+ stacklevel=2,
830
+ )
831
+ resolved_topk = DEFAULT_TOPK_RATIO
832
+ return resolved_percentile, resolved_topk
833
+
834
+
835
+ def _configured_onnx_filename(file_cfg: dict[str, Any]) -> str | None:
836
+ """Derive the configured ONNX filename.
837
+
838
+ Args:
839
+ file_cfg: Resolved model file configuration.
840
+
841
+ Returns:
842
+ ONNX filename when it can be determined.
843
+ """
844
+
845
+ onnx_filename = file_cfg.get("onnx_filename")
846
+ if isinstance(onnx_filename, str) and onnx_filename:
847
+ return onnx_filename
848
+ filename = file_cfg.get("filename")
849
+ if isinstance(filename, str) and filename:
850
+ return f"{Path(filename).stem}.onnx"
851
+ return None
852
+
853
+
854
+ def _resolve_compile_onnx_path(
855
+ file_cfg: dict[str, Any], model_path: str | Path | None
856
+ ) -> Path:
857
+ """Resolve an ONNX artifact for compilation without constructing an inference runtime.
858
+
859
+ Args:
860
+ file_cfg: Resolved model file configuration.
861
+ model_path: Optional caller-provided ONNX path.
862
+
863
+ Returns:
864
+ Existing local or downloaded ONNX artifact path.
865
+
866
+ Raises:
867
+ FileNotFoundError: If no ONNX artifact can be resolved.
868
+ """
869
+
870
+ if model_path is not None:
871
+ local_path = Path(model_path).expanduser()
872
+ if local_path.is_file():
873
+ if local_path.suffix.lower() != ".onnx":
874
+ raise ValueError(
875
+ "Compilation requires an ONNX model; "
876
+ f"local model path must end with `.onnx`, got {local_path}."
877
+ )
878
+ return local_path.resolve()
879
+ configured_path = Path(str(file_cfg.get("onnx_path", ""))).expanduser()
880
+ if configured_path.is_file():
881
+ return configured_path.resolve()
882
+ repo_id = file_cfg.get("repo_id")
883
+ revision = file_cfg.get("revision")
884
+ filename = _configured_onnx_filename(file_cfg)
885
+ if isinstance(repo_id, str) and isinstance(revision, str) and filename:
886
+ downloaded_path = Path(
887
+ hf_hub_download(
888
+ repo_id=repo_id,
889
+ filename=filename,
890
+ revision=revision,
891
+ local_dir=get_mobilint_cache_dir(),
892
+ )
893
+ )
894
+ if downloaded_path.is_file():
895
+ return downloaded_path.resolve()
896
+ configured_name = filename or "the configured ONNX artifact"
897
+ raise FileNotFoundError(f"Unable to resolve {configured_name} for compilation.")
898
+
899
+
900
+ def _resolve_compile_output_path(
901
+ save_path: str | Path | None, resolved_onnx: Path
902
+ ) -> Path:
903
+ """Resolve and validate an MXQ compilation output path."""
904
+
905
+ requested_output_path = (
906
+ Path(save_path).expanduser()
907
+ if save_path is not None
908
+ else _default_model_dir() / f"{resolved_onnx.stem}.mxq"
909
+ )
910
+ if requested_output_path.suffix.lower() != ".mxq":
911
+ raise ValueError(
912
+ "Compilation output path must end with `.mxq`, "
913
+ f"got {requested_output_path}."
914
+ )
915
+ output_path = requested_output_path.resolve()
916
+ if output_path == resolved_onnx.resolve():
917
+ raise ValueError(
918
+ "Compilation output path must not be the same as the input ONNX path: "
919
+ f"{output_path}."
920
+ )
921
+ if output_path.suffix.lower() != ".mxq":
922
+ raise ValueError(
923
+ "Compilation output path must resolve to a path ending with `.mxq`, "
924
+ f"got {output_path}."
925
+ )
926
+ return output_path
927
+
928
+
929
+ def compile_vision_model(
930
+ model_cls: str,
931
+ *,
932
+ target_device: str,
933
+ model_type: str = "DEFAULT",
934
+ model_path: str | Path | None = None,
935
+ onnx_path: str | Path | None = None,
936
+ data_path: str | Path | None = None,
937
+ subset_path: str | Path | None = None,
938
+ calib_data_path: str | Path | None = None,
939
+ save_path: str | Path | None = None,
940
+ subset_size: int | None = None,
941
+ seed: int = DEFAULT_SEED,
942
+ percentile: float | None = None,
943
+ topk_ratio: float | None = None,
944
+ ) -> Path:
945
+ """Compile a configured vision ONNX model into a board-specific MXQ artifact.
946
+
947
+ Args:
948
+ model_cls: Vision model name or YAML path.
949
+ target_device: Required target board: ``aries-rb``, ``regulus-ra``, or ``regulus-rb``.
950
+ model_type: Model variant from the YAML configuration.
951
+ model_path: Preferred local ONNX path compatibility option.
952
+ onnx_path: Local ONNX path alias.
953
+ data_path: Original organized dataset root. The pipeline organizes it when needed, samples
954
+ an image subset, and preprocesses that subset.
955
+ subset_path: Already-sampled image subset. The pipeline preprocesses every image directly
956
+ without organizing or sampling an original dataset.
957
+ calib_data_path: Ready directory of HWC float32 ``.npy`` tensors. The pipeline passes it
958
+ directly to qbcompiler without dataset preparation, sampling, or preprocessing.
959
+ save_path: Output MXQ path. Defaults to the ONNX stem under ``~/.mblt_model_zoo``.
960
+ subset_size: ImageNet/WiderFace per-category count or total count for other datasets.
961
+ seed: Deterministic calibration selection seed.
962
+ percentile: Explicit quantization percentile.
963
+ topk_ratio: Explicit quantization top-k ratio.
964
+
965
+ Returns:
966
+ Output MXQ path.
967
+
968
+ Raises:
969
+ ImportError: If qbcompiler is unavailable.
970
+ ValueError: If model metadata, calibration data, or quantization values are invalid.
971
+ """
972
+
973
+ _validate_data_level_paths(data_path, subset_path, calib_data_path)
974
+ target_device = normalize_target_device(target_device)
975
+ if target_device not in SUPPORTED_TARGET_DEVICES:
976
+ raise ValueError(
977
+ f"Unsupported target_device {target_device!r}; expected one of "
978
+ f"{sorted(SUPPORTED_TARGET_DEVICES)}."
979
+ )
980
+ mxq_compile, calibration_config_class = _load_qbcompiler()
981
+ model_config = resolve_model_config(model_cls, model_type)
982
+ file_cfg = model_config.get("file_cfg")
983
+ pre_cfg = model_config.get("pre_cfg")
984
+ post_cfg = model_config.get("post_cfg")
985
+ if (
986
+ not isinstance(file_cfg, dict)
987
+ or not isinstance(pre_cfg, dict)
988
+ or not isinstance(post_cfg, dict)
989
+ ):
990
+ raise ValueError(
991
+ "Resolved vision model configuration requires `file_cfg`, `pre_cfg`, and `post_cfg` objects."
992
+ )
993
+ file_cfg["target_device"] = target_device
994
+
995
+ task = _normalize_task(str(post_cfg.get("task", "")))
996
+ dataset = post_cfg.get("dataset")
997
+ if not isinstance(dataset, str) or not dataset:
998
+ raise ValueError(
999
+ "Resolved vision model configuration requires a non-empty `post_cfg.dataset` value."
1000
+ )
1001
+ selected_local_path = model_path or onnx_path
1002
+ if calib_data_path is not None:
1003
+ resolved_onnx = _resolve_compile_onnx_path(file_cfg, selected_local_path)
1004
+ output_path = _resolve_compile_output_path(save_path, resolved_onnx)
1005
+ output_path.parent.mkdir(parents=True, exist_ok=True)
1006
+ resolved_percentile, resolved_topk = resolve_quantization_values(
1007
+ file_cfg, percentile, topk_ratio
1008
+ )
1009
+ calibration_config = calibration_config_class(
1010
+ method=1,
1011
+ output=0 if task == "image_classification" else 1,
1012
+ mode=1,
1013
+ max_percentile={
1014
+ "percentile": resolved_percentile,
1015
+ "topk_ratio": resolved_topk,
1016
+ },
1017
+ )
1018
+ mxq_compile(
1019
+ model=str(resolved_onnx),
1020
+ calib_data_path=str(
1021
+ validate_calibration_dataset(
1022
+ calib_data_path,
1023
+ image_shape=_calibration_image_shape(pre_cfg),
1024
+ )
1025
+ ),
1026
+ save_path=str(output_path),
1027
+ image_channels=3,
1028
+ backend="onnx",
1029
+ device="gpu",
1030
+ target_device=target_device,
1031
+ inference_scheme="all",
1032
+ calibration_config=calibration_config,
1033
+ )
1034
+ return output_path
1035
+ engine_kwargs: dict[str, Any] = {
1036
+ "model_cls": model_cls,
1037
+ "model_type": model_type,
1038
+ "framework": "onnx",
1039
+ "onnx_providers": ["CPUExecutionProvider"],
1040
+ }
1041
+ if selected_local_path is not None:
1042
+ expanded_local_path = Path(selected_local_path).expanduser()
1043
+ if expanded_local_path.is_file():
1044
+ engine_kwargs["model_path"] = str(expanded_local_path)
1045
+
1046
+ engine: MBLT_Engine | None = None
1047
+ try:
1048
+ engine = MBLT_Engine(**engine_kwargs)
1049
+ resolved_onnx = Path(str(engine.file_cfg.get("onnx_path", ""))).expanduser()
1050
+ if not resolved_onnx.is_file():
1051
+ configured_name = (
1052
+ _configured_onnx_filename(file_cfg) or "the configured ONNX artifact"
1053
+ )
1054
+ raise FileNotFoundError(
1055
+ f"Unable to resolve {configured_name} for model `{model_cls}`."
1056
+ )
1057
+
1058
+ output_path = _resolve_compile_output_path(save_path, resolved_onnx)
1059
+ output_path.parent.mkdir(parents=True, exist_ok=True)
1060
+ resolved_percentile, resolved_topk = resolve_quantization_values(
1061
+ file_cfg, percentile, topk_ratio
1062
+ )
1063
+ calibration_config = calibration_config_class(
1064
+ method=1,
1065
+ output=0 if task == "image_classification" else 1,
1066
+ mode=1,
1067
+ max_percentile={
1068
+ "percentile": resolved_percentile,
1069
+ "topk_ratio": resolved_topk,
1070
+ },
1071
+ )
1072
+
1073
+ def _compile(calibration_path: Path) -> None:
1074
+ """Run qbcompiler with a resolved calibration directory."""
1075
+
1076
+ mxq_compile(
1077
+ model=str(resolved_onnx),
1078
+ calib_data_path=str(calibration_path),
1079
+ save_path=str(output_path),
1080
+ image_channels=3,
1081
+ backend="onnx",
1082
+ device="gpu",
1083
+ target_device=target_device,
1084
+ inference_scheme="all",
1085
+ calibration_config=calibration_config,
1086
+ )
1087
+
1088
+ with TemporaryDirectory(prefix="mblt-vision-calibration-") as temporary_root:
1089
+ temporary_path = Path(temporary_root)
1090
+ if subset_path is not None:
1091
+ subset_images = get_subset_images(subset_path)
1092
+ else:
1093
+ dataset_path = ensure_calibration_dataset(task, data_path, dataset)
1094
+ subset_images = make_calibration_subset(
1095
+ task,
1096
+ dataset_path,
1097
+ temporary_path / "images",
1098
+ subset_size=subset_size,
1099
+ seed=seed,
1100
+ )
1101
+ array_dir = temporary_path / "arrays"
1102
+ prepare_calibration_arrays(engine, subset_images, array_dir)
1103
+ _compile(array_dir)
1104
+ return output_path
1105
+ finally:
1106
+ if engine is not None:
1107
+ engine.dispose()
1108
+
1109
+
1110
+ __all__ = [
1111
+ "compile_vision_model",
1112
+ "copy_calibration_subset",
1113
+ "ensure_calibration_dataset",
1114
+ "get_subset_images",
1115
+ "make_calibration_subset",
1116
+ "prepare_calibration_arrays",
1117
+ "resolve_quantization_values",
1118
+ "select_calibration_images",
1119
+ "validate_calibration_dataset",
1120
+ ]