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