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,952 @@
1
+ """
2
+ YOLO anchorless postprocessing.
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ from dataclasses import dataclass
8
+ from typing import Literal
9
+
10
+ import torch
11
+
12
+ from .base import YOLODetectionPostBase
13
+ from .common import (
14
+ YOLOOBBPostMixin,
15
+ YOLOPosePostMixin,
16
+ YOLOSegPostMixin,
17
+ concat_converted_obb_outputs,
18
+ decode_split_converted_obb_outputs,
19
+ dist2bbox,
20
+ dist2rbox,
21
+ non_max_suppression,
22
+ rotated_nms,
23
+ xywh2xyxy,
24
+ yolo_multilabel_candidates,
25
+ )
26
+
27
+ AnchorlessOutputLayout = Literal["channels_first", "candidates_first"]
28
+
29
+
30
+ @dataclass(frozen=True)
31
+ class _AnchorlessNMSInput:
32
+ """Decoded anchorless detections together with their source layout."""
33
+
34
+ detections: torch.Tensor | list[torch.Tensor]
35
+ layout: AnchorlessOutputLayout
36
+
37
+
38
+ class YOLOAnchorlessDetectionPost(YOLODetectionPostBase):
39
+ """Postprocessing for YOLO models without anchors."""
40
+
41
+ def __init__(self, pre_cfg: dict, post_cfg: dict, **kwargs: object) -> None:
42
+ """Initialize the anchorless YOLO postprocessor.
43
+
44
+ Args:
45
+ pre_cfg: Preprocessing configuration.
46
+ post_cfg: Postprocessing configuration.
47
+ **kwargs: Optional runtime overrides for postprocess behavior.
48
+ """
49
+ super().__init__(pre_cfg, post_cfg, **kwargs)
50
+ self.reg_max = post_cfg.get("reg_max", 0) # DFL channels
51
+ self.no = self.nc + self.reg_max * 4 # number of outputs per anchor (144)
52
+ self.dfl_weight = torch.arange(
53
+ self.reg_max, dtype=torch.float32, device=self.device
54
+ ).reshape(1, -1, 1, 1)
55
+
56
+ def non_e2e(self, x: list[torch.Tensor]) -> torch.Tensor | list[torch.Tensor]:
57
+ """Return the export-style output tensor for anchorless YOLO models."""
58
+ if len(x) == 1:
59
+ converted = self.conversion(x)
60
+ if isinstance(converted, torch.Tensor):
61
+ return self._converted_to_batch_output(converted)
62
+ det_out, proto_out = converted
63
+ return [self._converted_to_batch_output(det_out), proto_out]
64
+
65
+ rearranged = self.rearrange(x)
66
+ if isinstance(rearranged, tuple):
67
+ det_out, proto_out = rearranged
68
+ return [self.decode_batch(det_out), proto_out.permute(0, 3, 1, 2)]
69
+ return self.decode_batch(rearranged)
70
+
71
+ def _converted_to_batch_output(self, x: torch.Tensor) -> torch.Tensor:
72
+ """Normalize converted outputs to the export-style batched layout."""
73
+ if x.ndim == 4 and x.shape[1] == 1:
74
+ x = x.squeeze(1)
75
+ if x.ndim != 3:
76
+ raise ValueError(
77
+ f"Expected 3D converted tensor, got shape {tuple(x.shape)}."
78
+ )
79
+ if x.shape[1] == 4 + self.nc + self.n_extra:
80
+ return x
81
+ if x.shape[-1] == 4 + self.nc + self.n_extra:
82
+ return x.transpose(1, 2)
83
+ raise ValueError(
84
+ f"Unsupported converted tensor shape {tuple(x.shape)} for non-e2e output."
85
+ )
86
+
87
+ def decode_batch(self, x: torch.Tensor) -> torch.Tensor:
88
+ """Decode every anchor without confidence filtering for export-style output."""
89
+ box, scores, extra = torch.split(
90
+ x, [self.reg_max * 4, self.nc, self.n_extra], dim=1
91
+ )
92
+ anchors = self.anchors_as_tensor().unsqueeze(0)
93
+ stride = self.stride_as_tensor().unsqueeze(0)
94
+ dbox = dist2bbox(self.dfl(box), anchors, xywh=False, dim=1) * stride
95
+ return torch.cat([dbox, scores.sigmoid(), extra], dim=1)
96
+
97
+ def rearrange(
98
+ self, x: list[torch.Tensor]
99
+ ) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor]:
100
+ """Rearranges raw model output tensors into a concatenated decode input.
101
+
102
+ Args:
103
+ x (list[torch.Tensor]): List of raw output tensors from the model detection heads.
104
+
105
+ Returns:
106
+ torch.Tensor | tuple[torch.Tensor, torch.Tensor]: Concatenated tensor in
107
+ ``(batch, channels, anchors)`` format, optionally paired with prototype masks.
108
+ """
109
+ y_det = []
110
+ y_cls = []
111
+ for xi in x: # list of bchw outputs
112
+ if xi.ndim == 3:
113
+ xi = xi[None]
114
+ elif xi.ndim == 4:
115
+ pass
116
+ else:
117
+ raise NotImplementedError(f"Got unsupported ndim for input: {xi.ndim}.")
118
+ if xi.shape[-1] == self.reg_max * 4:
119
+ y_det.append(
120
+ xi.permute(0, 3, 1, 2)
121
+ ) # (b, 64, 80, 80), (b, 64 ,40, 40), ...
122
+ elif xi.shape[-1] == self.nc:
123
+ y_cls.append(
124
+ xi.permute(0, 3, 1, 2)
125
+ ) # (b, 80, 80, 80), (b, 80, 40, 40), ...
126
+ else:
127
+ raise ValueError(f"Wrong shape of input: {xi.shape}")
128
+ # sort as box, scores
129
+ y_det = sorted(y_det, key=lambda x: x.numel(), reverse=True)
130
+ y_cls = sorted(y_cls, key=lambda x: x.numel(), reverse=True)
131
+ self.validate_split_head_counts(detection=y_det, classification=y_cls)
132
+ return torch.cat(
133
+ [
134
+ torch.cat((yi_det, yi_cls), dim=1).flatten(2)
135
+ for yi_det, yi_cls in zip(y_det, y_cls)
136
+ ],
137
+ dim=-1,
138
+ )
139
+
140
+ def decode(self, x: torch.Tensor) -> list[torch.Tensor]:
141
+ """Decodes model outputs into box coordinates and class scores.
142
+
143
+ Args:
144
+ x (torch.Tensor): Concatenated output tensor from `rearrange`.
145
+
146
+ Returns:
147
+ list[torch.Tensor]: Per-image decoded detections in ``(channels, anchors)`` format.
148
+ """
149
+ return [self.process_box_cls(box_cls) for box_cls in x]
150
+
151
+ def _pre_process(
152
+ self,
153
+ x: list[torch.Tensor],
154
+ ) -> tuple[_AnchorlessNMSInput, torch.Tensor | None]:
155
+ """Decode detections while retaining whether the source was raw or converted.
156
+
157
+ Args:
158
+ x: Checked model output tensors.
159
+
160
+ Returns:
161
+ Layout-aware detections and an optional prototype output.
162
+ """
163
+ if len(x) == 1:
164
+ converted = self.conversion(x)
165
+ if not isinstance(converted, torch.Tensor):
166
+ raise TypeError(
167
+ "conversion should return a tensor for single-output YOLO postprocessing."
168
+ )
169
+ detections = self.filter_conversion(converted)
170
+ return _AnchorlessNMSInput(detections, "candidates_first"), None
171
+ rearranged = self.rearrange(x)
172
+ if not isinstance(rearranged, torch.Tensor):
173
+ raise TypeError(
174
+ "rearrange should return a tensor for non-segmentation YOLO postprocessing."
175
+ )
176
+ detections = self.decode(rearranged)
177
+ return _AnchorlessNMSInput(detections, "channels_first"), None
178
+
179
+ def process_box_cls(self, box_cls: torch.Tensor) -> torch.Tensor:
180
+ """Processes detection results for a single image.
181
+
182
+ Args:
183
+ box_cls: Raw detections for one image.
184
+
185
+ Returns:
186
+ Decoded boxes, scores, and extra data.
187
+ """
188
+ if self.n_extra == 0:
189
+ ic = torch.amax(box_cls[-self.nc :, :], dim=0) > self.inv_conf_thres
190
+ else:
191
+ ic = (
192
+ torch.amax(box_cls[-self.nc - self.n_extra : -self.n_extra, :], dim=0)
193
+ > self.inv_conf_thres
194
+ )
195
+ box_cls = box_cls[:, ic] # (144, *)
196
+ if box_cls.numel() == 0:
197
+ return torch.zeros(
198
+ (4 + self.nc + self.n_extra, 0), dtype=torch.float32
199
+ ) # (84, 0)
200
+ anchors = self.anchors_as_tensor()
201
+ stride = self.stride_as_tensor()
202
+ box, scores, extra = torch.split(
203
+ box_cls[None], [self.reg_max * 4, self.nc, self.n_extra], dim=1
204
+ ) # (1, 64, *), (1, 80, *), (1, 32, *)
205
+ dbox = (
206
+ dist2bbox(
207
+ self.dfl(box),
208
+ anchors[:, ic],
209
+ xywh=False,
210
+ dim=1,
211
+ )
212
+ * stride[:, ic]
213
+ )
214
+ return torch.cat([dbox, scores.sigmoid(), extra], dim=1).squeeze(0)
215
+
216
+ def filter_conversion(self, x: torch.Tensor) -> list[torch.Tensor]:
217
+ """Filters out low-confidence detections from a single concatenated output tensor.
218
+
219
+ Args:
220
+ x (torch.Tensor): Concatenated output tensor from the model.
221
+
222
+ Returns:
223
+ list[torch.Tensor]: Filtered detections for each image in the batch.
224
+ """
225
+ while x.ndim == 4 and 1 in (x.shape[0], x.shape[1]):
226
+ if x.shape[0] == 1:
227
+ x = x.squeeze(0)
228
+ elif x.shape[1] == 1:
229
+ x = x.squeeze(1)
230
+ if x.ndim != 3:
231
+ raise ValueError(
232
+ f"Expected 3D converted tensor, got shape {tuple(x.shape)}."
233
+ )
234
+ expected_dim = 4 + self.nc + self.n_extra
235
+ if x.shape[-1] == expected_dim:
236
+ normalized = x
237
+ elif x.shape[1] == expected_dim:
238
+ normalized = x.transpose(1, 2)
239
+ else:
240
+ raise ValueError(f"Unsupported converted tensor shape {tuple(x.shape)}.")
241
+ x_list = torch.split(
242
+ normalized, 1, dim=0
243
+ ) # [(1, 8400, 84), (1, 8400, 84), ...]
244
+
245
+ def process_conversion(x: torch.Tensor) -> torch.Tensor:
246
+ x = x.squeeze(0) # (8400, 84)
247
+ if self.n_extra == 0:
248
+ ic = torch.amax(x[:, -self.nc :], dim=1) > self.conf_thres
249
+ else:
250
+ ic = (
251
+ torch.amax(x[:, -self.nc - self.n_extra : -self.n_extra], dim=1)
252
+ > self.conf_thres
253
+ )
254
+ x = x[ic]
255
+ if x.numel() == 0:
256
+ return torch.zeros((0, 4 + self.nc + self.n_extra), dtype=torch.float32)
257
+ x = xywh2xyxy(x)
258
+ return x
259
+
260
+ return [process_conversion(xi) for xi in x_list]
261
+
262
+ def _nms_single(
263
+ self,
264
+ xi: torch.Tensor,
265
+ max_det: int,
266
+ max_nms: int,
267
+ max_wh: int,
268
+ multi_label: bool,
269
+ ) -> torch.Tensor:
270
+ """Apply anchorless NMS to a single decoded image tensor."""
271
+ return self._nms_single_legacy_rows(
272
+ self._normalize_nms_input(xi, "channels_first"),
273
+ max_det=max_det,
274
+ max_nms=max_nms,
275
+ max_wh=max_wh,
276
+ multi_label=multi_label,
277
+ )
278
+
279
+ def _normalize_nms_input(
280
+ self,
281
+ xi: torch.Tensor,
282
+ layout: AnchorlessOutputLayout | None = None,
283
+ ) -> torch.Tensor:
284
+ """Normalize one decoded tensor to ``(candidates, channels)``.
285
+
286
+ Source provenance resolves square tensors. Shape inference remains available
287
+ for callers that pass decoded tensors directly, with raw channel-first
288
+ layout taking precedence when both dimensions match.
289
+
290
+ Args:
291
+ xi: One image's decoded detections.
292
+ layout: Known source layout, if available.
293
+
294
+ Returns:
295
+ Detections in canonical ``(candidates, channels)`` layout.
296
+
297
+ Raises:
298
+ ValueError: If the tensor shape conflicts with the expected channel count
299
+ or with the supplied source layout.
300
+ """
301
+ if xi.ndim != 2:
302
+ raise ValueError(
303
+ f"Expected 2D decoded tensor, got shape {tuple(xi.shape)}."
304
+ )
305
+
306
+ expected_dim = 4 + self.nc + self.n_extra
307
+ if layout == "channels_first":
308
+ if xi.shape[0] != expected_dim:
309
+ raise ValueError(
310
+ f"Expected channel-first decoded tensor with {expected_dim} channels, got shape {tuple(xi.shape)}."
311
+ )
312
+ return xi.transpose(0, 1)
313
+ if layout == "candidates_first":
314
+ if xi.shape[1] != expected_dim:
315
+ raise ValueError(
316
+ "Expected candidates-first decoded tensor "
317
+ f"with {expected_dim} channels, got shape {tuple(xi.shape)}."
318
+ )
319
+ return xi
320
+
321
+ if xi.shape[0] == expected_dim:
322
+ return xi.transpose(0, 1)
323
+ if xi.shape[1] == expected_dim:
324
+ return xi
325
+ raise ValueError(f"Unsupported decoded tensor shape {tuple(xi.shape)}.")
326
+
327
+ def _nms_single_legacy_rows(
328
+ self,
329
+ xi: torch.Tensor,
330
+ max_det: int,
331
+ max_nms: int,
332
+ max_wh: int,
333
+ multi_label: bool,
334
+ ) -> torch.Tensor:
335
+ """Apply anchorless NMS to a single decoded image in row-major ``(anchors, channels)`` form."""
336
+ if xi.numel() == 0:
337
+ return torch.zeros(
338
+ (0, 6 + self.n_extra), dtype=torch.float32, device=self.device
339
+ )
340
+ if multi_label:
341
+ xi_out = yolo_multilabel_candidates(
342
+ xi, self.nc, self.n_extra, self.conf_thres
343
+ )
344
+ else:
345
+ box, score, extra = xi[:, :4], xi[:, 4 : 4 + self.nc], xi[:, 4 + self.nc :]
346
+ conf, cls_idx = score.max(dim=1)
347
+ filt = conf > self.conf_thres
348
+ if not torch.any(filt):
349
+ return torch.zeros(
350
+ (0, 6 + self.n_extra), dtype=torch.float32, device=self.device
351
+ )
352
+ box = box[filt]
353
+ conf = conf[filt]
354
+ cls_idx = cls_idx[filt]
355
+ extra = extra[filt]
356
+ xi_out = torch.empty(
357
+ (box.shape[0], 6 + self.n_extra), dtype=xi.dtype, device=xi.device
358
+ )
359
+ xi_out[:, :4] = box
360
+ xi_out[:, 4] = conf
361
+ xi_out[:, 5] = cls_idx.to(xi.dtype)
362
+ if self.n_extra > 0:
363
+ xi_out[:, 6:] = extra
364
+ xi_out = xi_out[torch.argsort(xi_out[:, 4], descending=True)[:max_nms]]
365
+ c = xi_out[:, 5:6] * max_wh
366
+ boxes, scores = xi_out[:, :4] + c, xi_out[:, 4]
367
+ i_idx = non_max_suppression(boxes, scores, self.iou_thres, max_det)
368
+ return xi_out[i_idx]
369
+
370
+ def nms(
371
+ self,
372
+ x: _AnchorlessNMSInput | torch.Tensor | list[torch.Tensor],
373
+ max_det: int = 300,
374
+ max_nms: int = 30000,
375
+ max_wh: int = 7680,
376
+ multi_label: bool = False,
377
+ ) -> list[torch.Tensor]:
378
+ """Performs Non-Maximum Suppression (NMS) on the decoded detections.
379
+
380
+ Args:
381
+ x: Decoded detections for each image, optionally with source-layout
382
+ provenance.
383
+ max_det (int, optional): Maximum number of detections to keep. Defaults to 300.
384
+ max_nms (int, optional): Maximum number of candidates to consider for NMS.
385
+ Defaults to 30000.
386
+ max_wh (int, optional): Maximum box width/height for offset calculation.
387
+ Defaults to 7680.
388
+ multi_label: Whether to retain every class candidate above threshold.
389
+
390
+ Returns:
391
+ list[torch.Tensor]: Post-NMS detections for each image.
392
+ """
393
+ layout: AnchorlessOutputLayout | None = None
394
+ if isinstance(x, _AnchorlessNMSInput):
395
+ layout = x.layout
396
+ x = x.detections
397
+
398
+ tensors = x if isinstance(x, list) else list(x)
399
+ return [
400
+ self._nms_single_legacy_rows(
401
+ self._normalize_nms_input(xi, layout),
402
+ max_det=max_det,
403
+ max_nms=max_nms,
404
+ max_wh=max_wh,
405
+ multi_label=multi_label,
406
+ )
407
+ for xi in tensors
408
+ ]
409
+
410
+ def nms_multilabel(
411
+ self,
412
+ x: _AnchorlessNMSInput | torch.Tensor | list[torch.Tensor],
413
+ ) -> list[torch.Tensor]:
414
+ """Perform Ultralytics-compatible multi-label NMS for validation."""
415
+ return self.nms(x, multi_label=True)
416
+
417
+ def dfl(self, x: torch.Tensor) -> torch.Tensor:
418
+ """Applies Distribution Focal Loss projection.
419
+
420
+ Args:
421
+ x: Tensor with shape ``(B, 4 * reg_max, A)``.
422
+
423
+ Returns:
424
+ Tensor with shape ``(B, 4, A)`` containing projected distances.
425
+ """
426
+ if self.reg_max == 0: # skip dfl for yolov6 s, n models
427
+ return x
428
+ if x.ndim != 3:
429
+ raise ValueError(
430
+ f"DFL input must have shape (B, 4 * reg_max, A), got {tuple(x.shape)}."
431
+ )
432
+ B, _, A = x.shape
433
+ x = x.view(B, 4, self.reg_max, A).softmax(dim=2)
434
+ return (x * self.dfl_weight.view(1, 1, self.reg_max, 1)).sum(dim=2)
435
+
436
+
437
+ class YOLOAnchorlessSegPost(YOLOSegPostMixin, YOLOAnchorlessDetectionPost):
438
+ """Postprocessing for YOLO segmentation models without anchors."""
439
+
440
+ def non_e2e(self, x: list[torch.Tensor]) -> torch.Tensor | list[torch.Tensor]:
441
+ """Return the export-style output tensor for anchorless YOLO segmentation models.
442
+
443
+ Args:
444
+ x: Checked raw model outputs.
445
+
446
+ Returns:
447
+ A detection tensor, or detections paired with prototype masks.
448
+ """
449
+ if len(x) == 2:
450
+ converted, proto_outs = self.conversion(x)
451
+ return [
452
+ self._converted_to_batch_output(converted),
453
+ self._proto_to_nchw(proto_outs),
454
+ ]
455
+ return super().non_e2e(x)
456
+
457
+ def _proto_to_nchw(self, proto: torch.Tensor) -> torch.Tensor:
458
+ """Convert prototype tensors to ``(B, C, H, W)`` if needed.
459
+
460
+ Args:
461
+ proto: Prototype tensor from a model runtime.
462
+
463
+ Returns:
464
+ Prototype tensor in channel-first batch layout.
465
+ """
466
+ if proto.ndim == 4 and proto.shape[1] == self.n_extra:
467
+ return proto
468
+ if proto.ndim == 4 and proto.shape[-1] == self.n_extra:
469
+ return proto.permute(0, 3, 1, 2)
470
+ raise ValueError(
471
+ f"Unsupported proto tensor shape {tuple(proto.shape)} for non-e2e output."
472
+ )
473
+
474
+ def _pre_process(
475
+ self, x: list[torch.Tensor]
476
+ ) -> tuple[_AnchorlessNMSInput, torch.Tensor]:
477
+ """Preprocesses intermediate inputs into (boxes, proto) format.
478
+
479
+ Args:
480
+ x (list[torch.Tensor]): Raw model output tensors.
481
+
482
+ Returns:
483
+ tuple: (decoded_detections, prototype_masks).
484
+ """
485
+ if len(x) == 2:
486
+ converted, proto_outs = self.conversion(x)
487
+ detections = self.filter_conversion(converted)
488
+ return _AnchorlessNMSInput(detections, "candidates_first"), proto_outs
489
+ rearranged, proto_outs = self.rearrange(x)
490
+ return _AnchorlessNMSInput(
491
+ self.decode(rearranged), "channels_first"
492
+ ), proto_outs
493
+
494
+ def conversion(self, x: list[torch.Tensor]) -> tuple[torch.Tensor, torch.Tensor]:
495
+ """Converts raw model output tensors into detections and prototypes.
496
+
497
+ Args:
498
+ x (list[torch.Tensor]): List of raw output tensors.
499
+
500
+ Returns:
501
+ tuple: (detections, prototypes)
502
+ """
503
+ if (self.nc + self.n_extra + 4) in x[0].shape[1:] and self.n_extra in x[
504
+ 1
505
+ ].shape[1:]:
506
+ return (
507
+ x[0],
508
+ x[1],
509
+ )
510
+ if (self.nc + self.n_extra + 4) in x[1].shape[1:] and self.n_extra in x[
511
+ 0
512
+ ].shape[1:]:
513
+ return (
514
+ x[1],
515
+ x[0],
516
+ )
517
+ raise ValueError(f"Wrong shape of input: {x[0].shape}, {x[1].shape}")
518
+
519
+ def rearrange(self, x: list[torch.Tensor]) -> tuple[torch.Tensor, torch.Tensor]:
520
+ """
521
+ Rearrange model output tensors for segmentation tasks.
522
+ Args:
523
+ x (list[torch.Tensor]): Raw output tensors.
524
+ Returns:
525
+ tuple: (concatenated_detections, prototype_masks)
526
+ """
527
+ y_det: list[torch.Tensor] = []
528
+ y_cls: list[torch.Tensor] = []
529
+ y_ext: list[torch.Tensor] = []
530
+ for xi in x:
531
+ if xi.shape[-1] == self.n_extra:
532
+ y_ext.append(
533
+ xi.permute(0, 3, 1, 2)
534
+ ) # (b, 32, 160, 160), (b, 32, 80, 80), ...
535
+ elif xi.shape[-1] == self.reg_max * 4:
536
+ y_det.append(
537
+ xi.permute(0, 3, 1, 2)
538
+ ) # (b, 64, 80, 80), (b, 64 ,40, 40), ...
539
+ elif xi.shape[-1] == self.nc:
540
+ y_cls.append(
541
+ xi.permute(0, 3, 1, 2)
542
+ ) # (b, 80, 80, 80), (b, 80, 40, 40), ...
543
+ else:
544
+ raise ValueError(f"Wrong shape of input: {xi.shape}")
545
+ # sort as box, scores
546
+ y_ext = sorted(y_ext, key=lambda x: x.numel(), reverse=True)
547
+ proto = y_ext.pop(0).permute(0, 2, 3, 1)
548
+ y_det = sorted(y_det, key=lambda x: x.numel(), reverse=True)
549
+ y_cls = sorted(y_cls, key=lambda x: x.numel(), reverse=True)
550
+ self.validate_split_head_counts(
551
+ detection=y_det, classification=y_cls, extra=y_ext
552
+ )
553
+ y = torch.cat(
554
+ [
555
+ torch.cat((yi_det, yi_cls, yi_ext), dim=1).flatten(2)
556
+ for yi_det, yi_cls, yi_ext in zip(y_det, y_cls, y_ext)
557
+ ],
558
+ dim=-1,
559
+ )
560
+ return y, proto
561
+
562
+
563
+ class YOLOAnchorlessPosePost(YOLOPosePostMixin, YOLOAnchorlessDetectionPost):
564
+ """Postprocessing for YOLO pose estimation models without anchors."""
565
+
566
+ def rearrange(self, x: list[torch.Tensor]) -> torch.Tensor:
567
+ """Rearranges model output tensors for pose estimation tasks.
568
+
569
+ Args:
570
+ x (list[torch.Tensor]): Raw output tensors.
571
+
572
+ Returns:
573
+ torch.Tensor: Concatenated tensor for decode.
574
+ """
575
+ y_det = []
576
+ y_cls = []
577
+ y_kpt = []
578
+ for xi in x: # list of bchw outputs
579
+ if xi.ndim == 3:
580
+ xi = xi[None]
581
+ elif xi.ndim == 4:
582
+ pass
583
+ else:
584
+ raise NotImplementedError(f"Got unsupported ndim for input: {xi.ndim}.")
585
+ if xi.shape[-1] == self.reg_max * 4:
586
+ y_det.append(
587
+ xi.permute(0, 3, 1, 2)
588
+ ) # (b, 64, 80, 80), (b, 64 ,40, 40), ...
589
+ elif xi.shape[-1] == self.nc:
590
+ y_cls.append(
591
+ xi.permute(0, 3, 1, 2)
592
+ ) # (b, 1, 80, 80), (b, 1, 40, 40), ...
593
+ elif xi.shape[-1] == self.n_extra:
594
+ y_kpt.append(
595
+ xi.permute(0, 3, 1, 2).flatten(2)
596
+ ) # (b, 51, 80, 80), (b, 1, 40, 40), ...
597
+ else:
598
+ raise ValueError(f"Wrong shape of input: {xi.shape}")
599
+ # sort as box, scores
600
+ y_det = sorted(y_det, key=lambda x: x.numel(), reverse=True)
601
+ y_cls = sorted(y_cls, key=lambda x: x.numel(), reverse=True)
602
+ y_kpt = sorted(
603
+ y_kpt, key=lambda x: x.numel(), reverse=True
604
+ ) # (b, 51, 6400), (b, 51, 1600), (b, 51, 400)
605
+ self.validate_split_head_counts(
606
+ detection=y_det, classification=y_cls, keypoint=y_kpt
607
+ )
608
+ y_tmp = [
609
+ torch.cat((yi_det, yi_cls), dim=1).flatten(2)
610
+ for (yi_det, yi_cls) in zip(
611
+ y_det, y_cls
612
+ ) # (b, 65, 6400), (b, 65, 1600), (b, 65, 400)
613
+ ]
614
+ return torch.cat(
615
+ [
616
+ torch.cat((yi_tmp, yi_kpt), dim=1)
617
+ for yi_tmp, yi_kpt in zip(y_tmp, y_kpt)
618
+ ],
619
+ dim=-1,
620
+ )
621
+
622
+ def process_box_cls(self, box_cls: torch.Tensor) -> torch.Tensor:
623
+ """Processes pose estimation results for a single image.
624
+
625
+ Args:
626
+ box_cls: Raw detections for one image.
627
+
628
+ Returns:
629
+ Decoded boxes, scores, and keypoints.
630
+ """
631
+ ic = (
632
+ torch.amax(box_cls[-self.nc - self.n_extra : -self.n_extra, :], dim=0)
633
+ > self.inv_conf_thres
634
+ )
635
+ box_cls = box_cls[:, ic] # (116, *)
636
+ if box_cls.numel() == 0:
637
+ return torch.zeros(
638
+ (4 + self.nc + self.n_extra, 0), dtype=torch.float32
639
+ ) # (56, 0)
640
+ anchors = self.anchors_as_tensor()
641
+ stride = self.stride_as_tensor()
642
+ box, scores, keypoints = torch.split(
643
+ box_cls[None], [self.reg_max * 4, self.nc, self.n_extra], dim=1
644
+ ) # (1, 64, *), (1, 1, *), (1, 51, *)
645
+ dbox = (
646
+ dist2bbox(
647
+ self.dfl(box),
648
+ anchors[:, ic],
649
+ xywh=False,
650
+ dim=1,
651
+ )
652
+ * stride[:, ic]
653
+ )
654
+ keypoints = keypoints.view(1, 17, 3, -1)
655
+ key_coord, key_conf = torch.split(
656
+ keypoints, [2, 1], dim=2
657
+ ) # (1, 17, 2, 8400), (1, 17, 1, 8400)
658
+ key_coord = (key_coord * 2 + anchors[:, ic] - 0.5) * stride[
659
+ :, ic
660
+ ] # (1, 17, 2, *)
661
+ keypoints = torch.cat([key_coord, key_conf.sigmoid()], dim=2).view(
662
+ 1, self.n_extra, -1
663
+ ) # (1, 51, *)
664
+ return torch.cat([dbox, scores.sigmoid(), keypoints], dim=1).squeeze(
665
+ 0
666
+ ) # (56, *)
667
+
668
+ def decode_batch(self, x: torch.Tensor) -> torch.Tensor:
669
+ """Decode every anchor without confidence filtering for export-style pose output."""
670
+ box, scores, keypoints = torch.split(
671
+ x, [self.reg_max * 4, self.nc, self.n_extra], dim=1
672
+ )
673
+ anchors = self.anchors_as_tensor().unsqueeze(0)
674
+ stride = self.stride_as_tensor().unsqueeze(0)
675
+ dbox = dist2bbox(self.dfl(box), anchors, xywh=False, dim=1) * stride
676
+ keypoints = keypoints.view(x.shape[0], 17, 3, -1)
677
+ key_coord, key_conf = torch.split(keypoints, [2, 1], dim=2)
678
+ key_coord = (key_coord * 2 + anchors.unsqueeze(1) - 0.5) * stride.unsqueeze(1)
679
+ keypoints = torch.cat([key_coord, key_conf.sigmoid()], dim=2).view(
680
+ x.shape[0], self.n_extra, -1
681
+ )
682
+ return torch.cat([dbox, scores.sigmoid(), keypoints], dim=1)
683
+
684
+
685
+ class YOLOAnchorlessOBBPost(YOLOOBBPostMixin, YOLOAnchorlessDetectionPost):
686
+ """Postprocessing for anchorless YOLO OBB models."""
687
+
688
+ def _angle_from_raw(self, angle: torch.Tensor) -> torch.Tensor:
689
+ """Decode YOLOv8/YOLO11 raw angle logits to radians."""
690
+ return (angle.sigmoid() - 0.25) * torch.pi
691
+
692
+ def _pre_process(
693
+ self, x: list[torch.Tensor]
694
+ ) -> tuple[_AnchorlessNMSInput, torch.Tensor | None]:
695
+ """Preprocess OBB inputs into row-major detections.
696
+
697
+ Args:
698
+ x: Raw model outputs.
699
+
700
+ Returns:
701
+ A tuple of detections and no prototype output.
702
+ """
703
+ if len(x) in {1, 3, 5}:
704
+ detections = self.filter_conversion(self.conversion(x))
705
+ return _AnchorlessNMSInput(detections, "candidates_first"), None
706
+ return _AnchorlessNMSInput(
707
+ self.decode(self.rearrange(x)), "channels_first"
708
+ ), None
709
+
710
+ def conversion(self, x: list[torch.Tensor]) -> torch.Tensor:
711
+ """Convert exported OBB outputs to one canonical tensor.
712
+
713
+ Args:
714
+ x: Converted OBB runtime outputs.
715
+
716
+ Returns:
717
+ Detections in ``cx, cy, w, h, class scores..., angle`` format.
718
+ """
719
+ if len(x) == 5:
720
+ return decode_split_converted_obb_outputs(
721
+ x,
722
+ self.nc,
723
+ self.n_extra,
724
+ self.anchors_as_tensor(),
725
+ self.stride_as_tensor(),
726
+ )
727
+ return concat_converted_obb_outputs(x, self.nc, self.n_extra)
728
+
729
+ def rearrange(self, x: list[torch.Tensor]) -> torch.Tensor:
730
+ """Rearrange raw OBB heads into ``(batch, channels, anchors)`` format.
731
+
732
+ Args:
733
+ x: Raw model output tensors.
734
+
735
+ Returns:
736
+ Concatenated OBB detection tensor.
737
+ """
738
+ target_count = len(x) // 3
739
+ y_det: list[torch.Tensor] = []
740
+ y_cls: list[torch.Tensor] = []
741
+ y_angle: list[torch.Tensor] = []
742
+ ambiguous: list[tuple[torch.Tensor, list[int]]] = []
743
+ for xi in x:
744
+ if xi.ndim == 3:
745
+ xi = xi.unsqueeze(0)
746
+ elif xi.ndim > 4:
747
+ while xi.ndim > 4 and 1 in xi.shape:
748
+ xi = xi.squeeze(
749
+ next(idx for idx, size in enumerate(xi.shape) if size == 1)
750
+ )
751
+ if xi.ndim == 3:
752
+ xi = xi.unsqueeze(0)
753
+ if xi.ndim != 4:
754
+ raise ValueError(
755
+ f"Expected 3D or 4D OBB head, got shape {tuple(xi.shape)}."
756
+ )
757
+
758
+ candidates: list[tuple[int, torch.Tensor]] = []
759
+ if xi.shape[1] in {self.reg_max * 4, self.nc, self.n_extra}:
760
+ candidates.append((int(xi.shape[1]), xi))
761
+ if xi.shape[-1] in {self.reg_max * 4, self.nc, self.n_extra}:
762
+ candidates.append((int(xi.shape[-1]), xi.permute(0, 3, 1, 2)))
763
+
764
+ deduped: list[tuple[int, torch.Tensor]] = []
765
+ seen_channels: set[int] = set()
766
+ for channel_count, candidate in candidates:
767
+ if channel_count not in seen_channels:
768
+ seen_channels.add(channel_count)
769
+ deduped.append((channel_count, candidate))
770
+
771
+ if len(candidates) == 2 and len(deduped) == 1:
772
+ channel_count, _ = deduped[0]
773
+ normalized = xi.permute(0, 3, 1, 2)
774
+ if channel_count == self.reg_max * 4:
775
+ y_det.append(normalized)
776
+ elif channel_count == self.nc:
777
+ y_cls.append(normalized)
778
+ elif channel_count == self.n_extra:
779
+ y_angle.append(normalized)
780
+ else:
781
+ raise ValueError(f"Wrong shape of input: {xi.shape}")
782
+ elif len(deduped) == 1:
783
+ channel_count, normalized = deduped[0]
784
+ if channel_count == self.reg_max * 4:
785
+ y_det.append(normalized)
786
+ elif channel_count == self.nc:
787
+ y_cls.append(normalized)
788
+ elif channel_count == self.n_extra:
789
+ y_angle.append(normalized)
790
+ else:
791
+ raise ValueError(f"Wrong shape of input: {xi.shape}")
792
+ elif len(deduped) > 1:
793
+ ambiguous.append((xi, [channel_count for channel_count, _ in deduped]))
794
+ else:
795
+ raise ValueError(f"Wrong shape of input: {xi.shape}")
796
+
797
+ for xi, channel_options in ambiguous:
798
+ if self.reg_max * 4 in channel_options and len(y_det) < target_count:
799
+ y_det.append(
800
+ xi if xi.shape[1] == self.reg_max * 4 else xi.permute(0, 3, 1, 2)
801
+ )
802
+ continue
803
+ if self.nc in channel_options and len(y_cls) < target_count:
804
+ y_cls.append(xi if xi.shape[1] == self.nc else xi.permute(0, 3, 1, 2))
805
+ continue
806
+ if self.n_extra in channel_options and len(y_angle) < target_count:
807
+ y_angle.append(
808
+ xi if xi.shape[1] == self.n_extra else xi.permute(0, 3, 1, 2)
809
+ )
810
+ continue
811
+ raise ValueError(f"Wrong shape of input: {xi.shape}")
812
+
813
+ y_det = sorted(y_det, key=lambda x: x.numel(), reverse=True)
814
+ y_cls = sorted(y_cls, key=lambda x: x.numel(), reverse=True)
815
+ y_angle = sorted(y_angle, key=lambda x: x.numel(), reverse=True)
816
+ self.validate_split_head_counts(
817
+ detection=y_det, classification=y_cls, angle=y_angle
818
+ )
819
+ return torch.cat(
820
+ [
821
+ torch.cat((yi_det, yi_cls, yi_angle), dim=1).flatten(2)
822
+ for yi_det, yi_cls, yi_angle in zip(y_det, y_cls, y_angle)
823
+ ],
824
+ dim=-1,
825
+ )
826
+
827
+ def decode_batch(self, x: torch.Tensor) -> torch.Tensor:
828
+ """Decode every OBB anchor without confidence filtering."""
829
+ box, scores, angle = torch.split(
830
+ x, [self.reg_max * 4, self.nc, self.n_extra], dim=1
831
+ )
832
+ anchors = self.anchors_as_tensor().unsqueeze(0)
833
+ stride = self.stride_as_tensor().unsqueeze(0)
834
+ angle = self._angle_from_raw(angle)
835
+ rbox = dist2rbox(self.dfl(box), angle, anchors, dim=1) * stride
836
+ return torch.cat([rbox, scores.sigmoid(), angle], dim=1)
837
+
838
+ def process_box_cls(self, box_cls: torch.Tensor) -> torch.Tensor:
839
+ """Processes OBB results for a single image.
840
+
841
+ Args:
842
+ box_cls: Raw detections for one image.
843
+
844
+ Returns:
845
+ Decoded rotated boxes, scores, and angle.
846
+ """
847
+ ic = (
848
+ torch.amax(box_cls[-self.nc - self.n_extra : -self.n_extra, :], dim=0)
849
+ > self.inv_conf_thres
850
+ )
851
+ box_cls = box_cls[:, ic]
852
+ if box_cls.numel() == 0:
853
+ return torch.zeros(
854
+ (4 + self.nc + self.n_extra, 0), dtype=torch.float32, device=self.device
855
+ )
856
+ anchors = self.anchors_as_tensor()
857
+ stride = self.stride_as_tensor()
858
+ box, scores, angle = torch.split(
859
+ box_cls[None], [self.reg_max * 4, self.nc, self.n_extra], dim=1
860
+ )
861
+ angle = self._angle_from_raw(angle)
862
+ rbox = dist2rbox(self.dfl(box), angle, anchors[:, ic], dim=1) * stride[:, ic]
863
+ return torch.cat([rbox, scores.sigmoid(), angle], dim=1).squeeze(0)
864
+
865
+ def filter_conversion(self, x: torch.Tensor) -> list[torch.Tensor]:
866
+ """Filters converted OBB outputs from a single ONNX tensor.
867
+
868
+ Args:
869
+ x: Converted output tensor.
870
+
871
+ Returns:
872
+ Per-image row-major tensors in ``cx, cy, w, h, scores..., angle`` format.
873
+ """
874
+ while x.ndim == 4 and 1 in (x.shape[0], x.shape[1]):
875
+ if x.shape[0] == 1:
876
+ x = x.squeeze(0)
877
+ elif x.shape[1] == 1:
878
+ x = x.squeeze(1)
879
+ if x.ndim != 3:
880
+ raise ValueError(
881
+ f"Expected 3D converted tensor, got shape {tuple(x.shape)}."
882
+ )
883
+ expected_dim = 4 + self.nc + self.n_extra
884
+ if x.shape[-1] == expected_dim:
885
+ normalized = x
886
+ elif x.shape[1] == expected_dim:
887
+ normalized = x.transpose(1, 2)
888
+ else:
889
+ raise ValueError(f"Unsupported converted tensor shape {tuple(x.shape)}.")
890
+
891
+ outputs = []
892
+ for xi in torch.split(normalized, 1, dim=0):
893
+ xi = xi.squeeze(0)
894
+ ic = torch.amax(xi[:, 4 : 4 + self.nc], dim=1) > self.conf_thres
895
+ if torch.any(ic):
896
+ outputs.append(xi[ic])
897
+ else:
898
+ outputs.append(
899
+ torch.zeros((0, expected_dim), dtype=xi.dtype, device=xi.device)
900
+ )
901
+ return outputs
902
+
903
+ def _nms_single(
904
+ self,
905
+ xi: torch.Tensor,
906
+ max_det: int,
907
+ max_nms: int,
908
+ max_wh: int,
909
+ multi_label: bool,
910
+ ) -> torch.Tensor:
911
+ """Apply rotated NMS to a single decoded OBB image tensor."""
912
+ if xi.numel() == 0:
913
+ return torch.zeros((0, 7), dtype=torch.float32, device=self.device)
914
+ xi_t = xi.transpose(0, 1)
915
+ return self._nms_single_legacy_rows(
916
+ xi_t,
917
+ max_det=max_det,
918
+ max_nms=max_nms,
919
+ max_wh=max_wh,
920
+ multi_label=multi_label,
921
+ )
922
+
923
+ def _nms_single_legacy_rows(
924
+ self,
925
+ xi: torch.Tensor,
926
+ max_det: int,
927
+ max_nms: int,
928
+ max_wh: int,
929
+ multi_label: bool,
930
+ ) -> torch.Tensor:
931
+ """Apply rotated NMS to row-major OBB detections."""
932
+ del multi_label
933
+ if xi.numel() == 0:
934
+ return torch.zeros((0, 7), dtype=torch.float32, device=self.device)
935
+ xi_out = yolo_multilabel_candidates(xi, self.nc, self.n_extra, self.conf_thres)
936
+ if xi_out.numel() == 0:
937
+ return torch.zeros((0, 7), dtype=torch.float32, device=self.device)
938
+ xi_out = xi_out[torch.argsort(xi_out[:, 4], descending=True)[:max_nms]]
939
+ c = xi_out[:, 5:6] * max_wh
940
+ boxes = torch.cat([xi_out[:, :2] + c, xi_out[:, 2:4], xi_out[:, 6:7]], dim=-1)
941
+ keep = rotated_nms(boxes, xi_out[:, 4], self.iou_thres)[:max_det]
942
+ return xi_out[keep]
943
+
944
+ def nms_multilabel(
945
+ self,
946
+ x: _AnchorlessNMSInput | torch.Tensor | list[torch.Tensor],
947
+ ) -> list[torch.Tensor]:
948
+ """Preserve existing OBB NMS behavior outside the COCO validation scope."""
949
+ return self.nms(x)
950
+
951
+
952
+ YOLOAnchorlessPost = YOLOAnchorlessDetectionPost