ultralytics 8.3.125__tar.gz → 8.3.127__tar.gz
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.
- {ultralytics-8.3.125/ultralytics.egg-info → ultralytics-8.3.127}/PKG-INFO +2 -1
- {ultralytics-8.3.125 → ultralytics-8.3.127}/pyproject.toml +1 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/tests/test_cuda.py +71 -66
- {ultralytics-8.3.125 → ultralytics-8.3.127}/tests/test_solutions.py +11 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/__init__.py +1 -1
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/default.yaml +1 -1
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/engine/trainer.py +1 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/solutions/__init__.py +3 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/solutions/config.py +2 -0
- ultralytics-8.3.127/ultralytics/solutions/similarity_search.py +176 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/solutions/solutions.py +49 -48
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/utils/__init__.py +4 -0
- ultralytics-8.3.127/ultralytics/utils/autodevice.py +175 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/utils/benchmarks.py +2 -2
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/utils/checks.py +2 -2
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/utils/torch_utils.py +18 -5
- {ultralytics-8.3.125 → ultralytics-8.3.127/ultralytics.egg-info}/PKG-INFO +2 -1
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics.egg-info/SOURCES.txt +2 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics.egg-info/requires.txt +1 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/LICENSE +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/README.md +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/setup.cfg +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/tests/__init__.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/tests/conftest.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/tests/test_cli.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/tests/test_engine.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/tests/test_exports.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/tests/test_integrations.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/tests/test_python.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/assets/bus.jpg +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/assets/zidane.jpg +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/__init__.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/datasets/Argoverse.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/datasets/DOTAv1.5.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/datasets/DOTAv1.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/datasets/GlobalWheat2020.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/datasets/ImageNet.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/datasets/Objects365.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/datasets/SKU-110K.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/datasets/VOC.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/datasets/VisDrone.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/datasets/african-wildlife.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/datasets/brain-tumor.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/datasets/carparts-seg.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/datasets/coco-pose.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/datasets/coco.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/datasets/coco128-seg.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/datasets/coco128.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/datasets/coco8-multispectral.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/datasets/coco8-pose.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/datasets/coco8-seg.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/datasets/coco8.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/datasets/crack-seg.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/datasets/dog-pose.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/datasets/dota8-multispectral.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/datasets/dota8.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/datasets/hand-keypoints.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/datasets/lvis.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/datasets/medical-pills.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/datasets/open-images-v7.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/datasets/package-seg.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/datasets/signature.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/datasets/tiger-pose.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/datasets/xView.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/11/yolo11-cls-resnet18.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/11/yolo11-cls.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/11/yolo11-obb.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/11/yolo11-pose.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/11/yolo11-seg.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/11/yolo11.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/11/yoloe-11-seg.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/11/yoloe-11.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/12/yolo12-cls.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/12/yolo12-obb.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/12/yolo12-pose.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/12/yolo12-seg.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/12/yolo12.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/rt-detr/rtdetr-l.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/rt-detr/rtdetr-resnet101.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/rt-detr/rtdetr-resnet50.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/rt-detr/rtdetr-x.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v10/yolov10b.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v10/yolov10l.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v10/yolov10m.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v10/yolov10n.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v10/yolov10s.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v10/yolov10x.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v3/yolov3-spp.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v3/yolov3-tiny.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v3/yolov3.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v5/yolov5-p6.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v5/yolov5.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v6/yolov6.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v8/yoloe-v8-seg.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v8/yoloe-v8.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v8/yolov8-cls-resnet101.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v8/yolov8-cls-resnet50.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v8/yolov8-cls.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v8/yolov8-ghost-p2.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v8/yolov8-ghost-p6.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v8/yolov8-ghost.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v8/yolov8-obb.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v8/yolov8-p2.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v8/yolov8-p6.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v8/yolov8-pose-p6.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v8/yolov8-pose.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v8/yolov8-rtdetr.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v8/yolov8-seg-p6.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v8/yolov8-seg.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v8/yolov8-world.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v8/yolov8-worldv2.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v8/yolov8.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v9/yolov9c-seg.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v9/yolov9c.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v9/yolov9e-seg.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v9/yolov9e.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v9/yolov9m.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v9/yolov9s.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/models/v9/yolov9t.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/trackers/botsort.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/cfg/trackers/bytetrack.yaml +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/data/__init__.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/data/annotator.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/data/augment.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/data/base.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/data/build.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/data/converter.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/data/dataset.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/data/loaders.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/data/scripts/download_weights.sh +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/data/scripts/get_coco.sh +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/data/scripts/get_coco128.sh +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/data/scripts/get_imagenet.sh +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/data/split.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/data/split_dota.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/data/utils.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/engine/__init__.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/engine/exporter.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/engine/model.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/engine/predictor.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/engine/results.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/engine/tuner.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/engine/validator.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/hub/__init__.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/hub/auth.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/hub/google/__init__.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/hub/session.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/hub/utils.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/__init__.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/fastsam/__init__.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/fastsam/model.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/fastsam/predict.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/fastsam/utils.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/fastsam/val.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/nas/__init__.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/nas/model.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/nas/predict.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/nas/val.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/rtdetr/__init__.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/rtdetr/model.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/rtdetr/predict.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/rtdetr/train.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/rtdetr/val.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/sam/__init__.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/sam/amg.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/sam/build.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/sam/model.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/sam/modules/__init__.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/sam/modules/blocks.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/sam/modules/decoders.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/sam/modules/encoders.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/sam/modules/memory_attention.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/sam/modules/sam.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/sam/modules/tiny_encoder.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/sam/modules/transformer.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/sam/modules/utils.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/sam/predict.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/utils/__init__.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/utils/loss.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/utils/ops.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/yolo/__init__.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/yolo/classify/__init__.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/yolo/classify/predict.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/yolo/classify/train.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/yolo/classify/val.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/yolo/detect/__init__.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/yolo/detect/predict.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/yolo/detect/train.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/yolo/detect/val.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/yolo/model.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/yolo/obb/__init__.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/yolo/obb/predict.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/yolo/obb/train.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/yolo/obb/val.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/yolo/pose/__init__.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/yolo/pose/predict.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/yolo/pose/train.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/yolo/pose/val.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/yolo/segment/__init__.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/yolo/segment/predict.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/yolo/segment/train.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/yolo/segment/val.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/yolo/world/__init__.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/yolo/world/train.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/yolo/world/train_world.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/yolo/yoloe/__init__.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/yolo/yoloe/predict.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/yolo/yoloe/train.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/yolo/yoloe/train_seg.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/models/yolo/yoloe/val.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/nn/__init__.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/nn/autobackend.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/nn/modules/__init__.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/nn/modules/activation.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/nn/modules/block.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/nn/modules/conv.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/nn/modules/head.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/nn/modules/transformer.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/nn/modules/utils.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/nn/tasks.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/nn/text_model.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/solutions/ai_gym.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/solutions/analytics.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/solutions/distance_calculation.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/solutions/heatmap.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/solutions/instance_segmentation.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/solutions/object_blurrer.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/solutions/object_counter.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/solutions/object_cropper.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/solutions/parking_management.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/solutions/queue_management.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/solutions/region_counter.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/solutions/security_alarm.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/solutions/speed_estimation.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/solutions/streamlit_inference.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/solutions/trackzone.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/solutions/vision_eye.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/trackers/__init__.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/trackers/basetrack.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/trackers/bot_sort.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/trackers/byte_tracker.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/trackers/track.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/trackers/utils/__init__.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/trackers/utils/gmc.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/trackers/utils/kalman_filter.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/trackers/utils/matching.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/utils/autobatch.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/utils/callbacks/__init__.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/utils/callbacks/base.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/utils/callbacks/clearml.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/utils/callbacks/comet.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/utils/callbacks/dvc.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/utils/callbacks/hub.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/utils/callbacks/mlflow.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/utils/callbacks/neptune.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/utils/callbacks/raytune.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/utils/callbacks/tensorboard.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/utils/callbacks/wb.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/utils/dist.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/utils/downloads.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/utils/errors.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/utils/export.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/utils/files.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/utils/instance.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/utils/loss.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/utils/metrics.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/utils/ops.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/utils/patches.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/utils/plotting.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/utils/tal.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/utils/triton.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics/utils/tuner.py +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics.egg-info/dependency_links.txt +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics.egg-info/entry_points.txt +0 -0
- {ultralytics-8.3.125 → ultralytics-8.3.127}/ultralytics.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: ultralytics
|
3
|
-
Version: 8.3.
|
3
|
+
Version: 8.3.127
|
4
4
|
Summary: Ultralytics YOLO 🚀 for SOTA object detection, multi-object tracking, instance segmentation, pose estimation and image classification.
|
5
5
|
Author-email: Glenn Jocher <glenn.jocher@ultralytics.com>, Jing Qiu <jing.qiu@ultralytics.com>
|
6
6
|
Maintainer-email: Ultralytics <hello@ultralytics.com>
|
@@ -70,6 +70,7 @@ Requires-Dist: h5py!=3.11.0; platform_machine == "aarch64" and extra == "export"
|
|
70
70
|
Provides-Extra: solutions
|
71
71
|
Requires-Dist: shapely>=2.0.0; extra == "solutions"
|
72
72
|
Requires-Dist: streamlit>=1.29.0; extra == "solutions"
|
73
|
+
Requires-Dist: flask; extra == "solutions"
|
73
74
|
Provides-Extra: logging
|
74
75
|
Requires-Dist: wandb; extra == "logging"
|
75
76
|
Requires-Dist: tensorboard; extra == "logging"
|
@@ -105,6 +105,7 @@ export = [
|
|
105
105
|
solutions = [
|
106
106
|
"shapely>=2.0.0", # shapely for point and polygon data matching
|
107
107
|
"streamlit>=1.29.0", # for live inference on web browser, i.e `yolo streamlit-predict`
|
108
|
+
"flask", # for similarity search solution
|
108
109
|
]
|
109
110
|
logging = [
|
110
111
|
"wandb", # https://docs.ultralytics.com/integrations/weights-biases/
|
@@ -10,8 +10,18 @@ from tests import CUDA_DEVICE_COUNT, CUDA_IS_AVAILABLE, MODEL, SOURCE
|
|
10
10
|
from ultralytics import YOLO
|
11
11
|
from ultralytics.cfg import TASK2DATA, TASK2MODEL, TASKS
|
12
12
|
from ultralytics.utils import ASSETS, WEIGHTS_DIR
|
13
|
+
from ultralytics.utils.autodevice import GPUInfo
|
13
14
|
from ultralytics.utils.checks import check_amp
|
14
15
|
|
16
|
+
# Try to find idle devices if CUDA is available
|
17
|
+
DEVICES = []
|
18
|
+
if CUDA_IS_AVAILABLE:
|
19
|
+
gpu_info = GPUInfo()
|
20
|
+
gpu_info.print_status()
|
21
|
+
idle_gpus = gpu_info.select_idle_gpu(count=2, min_memory_mb=2048)
|
22
|
+
if idle_gpus:
|
23
|
+
DEVICES = idle_gpus
|
24
|
+
|
15
25
|
|
16
26
|
def test_checks():
|
17
27
|
"""Validate CUDA settings against torch CUDA functions."""
|
@@ -19,16 +29,16 @@ def test_checks():
|
|
19
29
|
assert torch.cuda.device_count() == CUDA_DEVICE_COUNT
|
20
30
|
|
21
31
|
|
22
|
-
@pytest.mark.skipif(not
|
32
|
+
@pytest.mark.skipif(not DEVICES, reason="No CUDA devices available")
|
23
33
|
def test_amp():
|
24
34
|
"""Test AMP training checks."""
|
25
|
-
model = YOLO("yolo11n.pt").model.cuda
|
35
|
+
model = YOLO("yolo11n.pt").model.to(f"cuda:{DEVICES[0]}")
|
26
36
|
assert check_amp(model)
|
27
37
|
|
28
38
|
|
29
39
|
@pytest.mark.slow
|
30
40
|
@pytest.mark.skipif(True, reason="CUDA export tests disabled pending additional Ultralytics GPU server availability")
|
31
|
-
@pytest.mark.skipif(not
|
41
|
+
@pytest.mark.skipif(not DEVICES, reason="No CUDA devices available")
|
32
42
|
@pytest.mark.parametrize(
|
33
43
|
"task, dynamic, int8, half, batch",
|
34
44
|
[ # generate all combinations but exclude those where both int8 and half are True
|
@@ -40,16 +50,7 @@ def test_amp():
|
|
40
50
|
],
|
41
51
|
)
|
42
52
|
def test_export_engine_matrix(task, dynamic, int8, half, batch):
|
43
|
-
"""
|
44
|
-
Test YOLO model export to TensorRT format for various configurations and run inference.
|
45
|
-
|
46
|
-
Args:
|
47
|
-
task (str): Task type like 'detect', 'segment', etc.
|
48
|
-
dynamic (bool): Whether to use dynamic input size.
|
49
|
-
int8 (bool): Whether to use INT8 precision.
|
50
|
-
half (bool): Whether to use FP16 precision.
|
51
|
-
batch (int): Batch size for export.
|
52
|
-
"""
|
53
|
+
"""Test YOLO model export to TensorRT format for various configurations and run inference."""
|
53
54
|
file = YOLO(TASK2MODEL[task]).export(
|
54
55
|
format="engine",
|
55
56
|
imgsz=32,
|
@@ -60,105 +61,109 @@ def test_export_engine_matrix(task, dynamic, int8, half, batch):
|
|
60
61
|
data=TASK2DATA[task],
|
61
62
|
workspace=1, # reduce workspace GB for less resource utilization during testing
|
62
63
|
simplify=True, # use 'onnxslim'
|
64
|
+
device=DEVICES[0],
|
63
65
|
)
|
64
|
-
YOLO(file)([SOURCE] * batch, imgsz=64 if dynamic else 32) # exported model inference
|
66
|
+
YOLO(file)([SOURCE] * batch, imgsz=64 if dynamic else 32, device=DEVICES[0]) # exported model inference
|
65
67
|
Path(file).unlink() # cleanup
|
66
68
|
Path(file).with_suffix(".cache").unlink() if int8 else None # cleanup INT8 cache
|
67
69
|
|
68
70
|
|
69
|
-
@pytest.mark.skipif(not
|
71
|
+
@pytest.mark.skipif(not DEVICES, reason="No CUDA devices available")
|
70
72
|
def test_train():
|
71
73
|
"""Test model training on a minimal dataset using available CUDA devices."""
|
72
|
-
device =
|
74
|
+
device = DEVICES if len(DEVICES) > 1 else DEVICES[0]
|
73
75
|
YOLO(MODEL).train(data="coco8.yaml", imgsz=64, epochs=1, device=device) # requires imgsz>=64
|
74
76
|
|
75
77
|
|
76
78
|
@pytest.mark.slow
|
77
|
-
@pytest.mark.skipif(not
|
79
|
+
@pytest.mark.skipif(not DEVICES, reason="No CUDA devices available")
|
78
80
|
def test_predict_multiple_devices():
|
79
81
|
"""Validate model prediction consistency across CPU and CUDA devices."""
|
80
82
|
model = YOLO("yolo11n.pt")
|
83
|
+
|
84
|
+
# Test CPU
|
81
85
|
model = model.cpu()
|
82
86
|
assert str(model.device) == "cpu"
|
83
|
-
_ = model(SOURCE)
|
87
|
+
_ = model(SOURCE)
|
84
88
|
assert str(model.device) == "cpu"
|
85
89
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
assert str(model.device) ==
|
90
|
+
# Test CUDA
|
91
|
+
cuda_device = f"cuda:{DEVICES[0]}"
|
92
|
+
model = model.to(cuda_device)
|
93
|
+
assert str(model.device) == cuda_device
|
94
|
+
_ = model(SOURCE)
|
95
|
+
assert str(model.device) == cuda_device
|
90
96
|
|
97
|
+
# Test CPU again
|
91
98
|
model = model.cpu()
|
92
99
|
assert str(model.device) == "cpu"
|
93
|
-
_ = model(SOURCE)
|
100
|
+
_ = model(SOURCE)
|
94
101
|
assert str(model.device) == "cpu"
|
95
102
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
103
|
+
# Test CUDA again
|
104
|
+
model = model.to(cuda_device)
|
105
|
+
assert str(model.device) == cuda_device
|
106
|
+
_ = model(SOURCE)
|
107
|
+
assert str(model.device) == cuda_device
|
100
108
|
|
101
109
|
|
102
|
-
@pytest.mark.skipif(not
|
110
|
+
@pytest.mark.skipif(not DEVICES, reason="No CUDA devices available")
|
103
111
|
def test_autobatch():
|
104
112
|
"""Check optimal batch size for YOLO model training using autobatch utility."""
|
105
113
|
from ultralytics.utils.autobatch import check_train_batch_size
|
106
114
|
|
107
|
-
check_train_batch_size(YOLO(MODEL).model.cuda
|
115
|
+
check_train_batch_size(YOLO(MODEL).model.to(f"cuda:{DEVICES[0]}"), imgsz=128, amp=True)
|
108
116
|
|
109
117
|
|
110
118
|
@pytest.mark.slow
|
111
|
-
@pytest.mark.skipif(not
|
119
|
+
@pytest.mark.skipif(not DEVICES, reason="No CUDA devices available")
|
112
120
|
def test_utils_benchmarks():
|
113
121
|
"""Profile YOLO models for performance benchmarks."""
|
114
122
|
from ultralytics.utils.benchmarks import ProfileModels
|
115
123
|
|
116
124
|
# Pre-export a dynamic engine model to use dynamic inference
|
117
|
-
YOLO(MODEL).export(format="engine", imgsz=32, dynamic=True, batch=1)
|
118
|
-
ProfileModels(
|
125
|
+
YOLO(MODEL).export(format="engine", imgsz=32, dynamic=True, batch=1, device=DEVICES[0])
|
126
|
+
ProfileModels(
|
127
|
+
[MODEL],
|
128
|
+
imgsz=32,
|
129
|
+
half=False,
|
130
|
+
min_time=1,
|
131
|
+
num_timed_runs=3,
|
132
|
+
num_warmup_runs=1,
|
133
|
+
device=DEVICES[0],
|
134
|
+
).run()
|
119
135
|
|
120
136
|
|
121
|
-
@pytest.mark.skipif(not
|
137
|
+
@pytest.mark.skipif(not DEVICES, reason="No CUDA devices available")
|
122
138
|
def test_predict_sam():
|
123
|
-
"""Test SAM model predictions using different prompts
|
139
|
+
"""Test SAM model predictions using different prompts."""
|
124
140
|
from ultralytics import SAM
|
125
141
|
from ultralytics.models.sam import Predictor as SAMPredictor
|
126
142
|
|
127
|
-
# Load a model
|
128
143
|
model = SAM(WEIGHTS_DIR / "sam2.1_b.pt")
|
129
|
-
|
130
|
-
# Display model information (optional)
|
131
144
|
model.info()
|
132
145
|
|
133
|
-
# Run inference
|
134
|
-
model(SOURCE, device=0)
|
135
|
-
|
136
|
-
|
137
|
-
model(
|
138
|
-
|
139
|
-
|
140
|
-
model(ASSETS / "zidane.jpg", points=[900, 370], device=0)
|
141
|
-
|
142
|
-
#
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
# Create SAMPredictor
|
155
|
-
overrides = dict(conf=0.25, task="segment", mode="predict", imgsz=1024, model=WEIGHTS_DIR / "mobile_sam.pt")
|
156
|
-
predictor = SAMPredictor(overrides=overrides)
|
157
|
-
|
158
|
-
# Set image
|
159
|
-
predictor.set_image(ASSETS / "zidane.jpg") # set with image file
|
146
|
+
# Run inference with various prompts
|
147
|
+
model(SOURCE, device=DEVICES[0])
|
148
|
+
model(SOURCE, bboxes=[439, 437, 524, 709], device=DEVICES[0])
|
149
|
+
model(ASSETS / "zidane.jpg", points=[900, 370], device=DEVICES[0])
|
150
|
+
model(ASSETS / "zidane.jpg", points=[900, 370], labels=[1], device=DEVICES[0])
|
151
|
+
model(ASSETS / "zidane.jpg", points=[[900, 370]], labels=[1], device=DEVICES[0])
|
152
|
+
model(ASSETS / "zidane.jpg", points=[[400, 370], [900, 370]], labels=[1, 1], device=DEVICES[0])
|
153
|
+
model(ASSETS / "zidane.jpg", points=[[[900, 370], [1000, 100]]], labels=[[1, 1]], device=DEVICES[0])
|
154
|
+
|
155
|
+
# Test predictor
|
156
|
+
predictor = SAMPredictor(
|
157
|
+
overrides=dict(
|
158
|
+
conf=0.25,
|
159
|
+
task="segment",
|
160
|
+
mode="predict",
|
161
|
+
imgsz=1024,
|
162
|
+
model=WEIGHTS_DIR / "mobile_sam.pt",
|
163
|
+
device=DEVICES[0],
|
164
|
+
)
|
165
|
+
)
|
166
|
+
predictor.set_image(ASSETS / "zidane.jpg")
|
160
167
|
# predictor(bboxes=[439, 437, 524, 709])
|
161
168
|
# predictor(points=[900, 370], labels=[1])
|
162
|
-
|
163
|
-
# Reset image
|
164
169
|
predictor.reset_image()
|
@@ -174,3 +174,14 @@ def test_solution(name, solution_class, needs_frame_count, video, kwargs):
|
|
174
174
|
video_path=str(TMP / video),
|
175
175
|
needs_frame_count=needs_frame_count,
|
176
176
|
)
|
177
|
+
|
178
|
+
|
179
|
+
@pytest.mark.slow
|
180
|
+
@pytest.mark.skipif(checks.IS_PYTHON_3_8, reason="Disabled due to unsupported CLIP dependencies.")
|
181
|
+
@pytest.mark.skipif(IS_RASPBERRYPI, reason="Disabled due to slow performance on Raspberry Pi.")
|
182
|
+
def test_similarity_search():
|
183
|
+
"""Test similarity search solution."""
|
184
|
+
from ultralytics import solutions
|
185
|
+
|
186
|
+
searcher = solutions.VisualAISearch()
|
187
|
+
_ = searcher("a dog sitting on a bench") # Returns the results in format "- img name | similarity score"
|
@@ -17,7 +17,7 @@ imgsz: 640 # (int | list) input images size as int for train and val modes, or l
|
|
17
17
|
save: True # (bool) save train checkpoints and predict results
|
18
18
|
save_period: -1 # (int) Save checkpoint every x epochs (disabled if < 1)
|
19
19
|
cache: False # (bool) True/ram, disk or False. Use cache for data loading
|
20
|
-
device: # (int | str | list
|
20
|
+
device: # (int | str | list) device: CUDA device=0 or [0,1,2,3] or "cpu/mps" or -1 or [-1,-1] to auto-select idle GPUs
|
21
21
|
workers: 8 # (int) number of worker threads for data loading (per RANK if DDP)
|
22
22
|
project: # (str, optional) project name
|
23
23
|
name: # (str, optional) experiment name, results saved to 'project/name' directory
|
@@ -105,6 +105,7 @@ class BaseTrainer:
|
|
105
105
|
self.args = get_cfg(cfg, overrides)
|
106
106
|
self.check_resume(overrides)
|
107
107
|
self.device = select_device(self.args.device, self.args.batch)
|
108
|
+
self.args.device = str(self.device) # ensure -1 is updated to selected CUDA device
|
108
109
|
self.validator = None
|
109
110
|
self.metrics = None
|
110
111
|
self.plots = {}
|
@@ -12,6 +12,7 @@ from .parking_management import ParkingManagement, ParkingPtsSelection
|
|
12
12
|
from .queue_management import QueueManager
|
13
13
|
from .region_counter import RegionCounter
|
14
14
|
from .security_alarm import SecurityAlarm
|
15
|
+
from .similarity_search import SearchApp, VisualAISearch
|
15
16
|
from .speed_estimation import SpeedEstimator
|
16
17
|
from .streamlit_inference import Inference
|
17
18
|
from .trackzone import TrackZone
|
@@ -35,4 +36,6 @@ __all__ = (
|
|
35
36
|
"Analytics",
|
36
37
|
"Inference",
|
37
38
|
"TrackZone",
|
39
|
+
"SearchApp",
|
40
|
+
"VisualAISearch",
|
38
41
|
)
|
@@ -48,6 +48,7 @@ class SolutionConfig:
|
|
48
48
|
half (bool): Whether to use FP16 precision (requires a supported CUDA device).
|
49
49
|
tracker (str): Path to tracking configuration YAML file (e.g., 'botsort.yaml').
|
50
50
|
verbose (bool): Enable verbose logging output for debugging or diagnostics.
|
51
|
+
data (str): Path to image directory used for similarity search.
|
51
52
|
|
52
53
|
Methods:
|
53
54
|
update: Update the configuration with user-defined keyword arguments and raise error on invalid keys.
|
@@ -91,6 +92,7 @@ class SolutionConfig:
|
|
91
92
|
half: bool = False
|
92
93
|
tracker: str = "botsort.yaml"
|
93
94
|
verbose: bool = True
|
95
|
+
data: str = "images"
|
94
96
|
|
95
97
|
def update(self, **kwargs):
|
96
98
|
"""Update configuration parameters with new values provided as keyword arguments."""
|
@@ -0,0 +1,176 @@
|
|
1
|
+
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
|
2
|
+
|
3
|
+
import os
|
4
|
+
from pathlib import Path
|
5
|
+
|
6
|
+
import numpy as np
|
7
|
+
import torch
|
8
|
+
from PIL import Image
|
9
|
+
|
10
|
+
from ultralytics.data.utils import IMG_FORMATS
|
11
|
+
from ultralytics.solutions.solutions import BaseSolution
|
12
|
+
from ultralytics.utils.checks import check_requirements
|
13
|
+
from ultralytics.utils.torch_utils import select_device
|
14
|
+
|
15
|
+
os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE" # Avoid OpenMP conflict on some systems
|
16
|
+
|
17
|
+
|
18
|
+
class VisualAISearch(BaseSolution):
|
19
|
+
"""
|
20
|
+
VisualAISearch leverages OpenCLIP to generate high-quality image and text embeddings, aligning them in a shared
|
21
|
+
semantic space. It then uses FAISS to perform fast and scalable similarity-based retrieval, allowing users to search
|
22
|
+
large collections of images using natural language queries with high accuracy and speed.
|
23
|
+
|
24
|
+
Attributes:
|
25
|
+
data (str): Directory containing images.
|
26
|
+
device (str): Computation device, e.g., 'cpu' or 'cuda'.
|
27
|
+
"""
|
28
|
+
|
29
|
+
def __init__(self, **kwargs):
|
30
|
+
"""Initializes the VisualAISearch class with the FAISS index file and CLIP model."""
|
31
|
+
super().__init__(**kwargs)
|
32
|
+
check_requirements(["open-clip-torch", "faiss-cpu"])
|
33
|
+
import faiss
|
34
|
+
import open_clip
|
35
|
+
|
36
|
+
self.faiss = faiss
|
37
|
+
self.open_clip = open_clip
|
38
|
+
|
39
|
+
self.faiss_index = "faiss.index"
|
40
|
+
self.data_path_npy = "paths.npy"
|
41
|
+
self.model_name = "ViT-B-32-quickgelu"
|
42
|
+
self.data_dir = Path(self.CFG["data"])
|
43
|
+
self.device = select_device(self.CFG["device"])
|
44
|
+
|
45
|
+
if not self.data_dir.exists():
|
46
|
+
from ultralytics.utils import ASSETS_URL
|
47
|
+
|
48
|
+
self.LOGGER.warning(f"{self.data_dir} not found. Downloading images.zip from {ASSETS_URL}/images.zip")
|
49
|
+
from ultralytics.utils.downloads import safe_download
|
50
|
+
|
51
|
+
safe_download(url=f"{ASSETS_URL}/images.zip", unzip=True, retry=3)
|
52
|
+
self.data_dir = Path("images")
|
53
|
+
|
54
|
+
self.clip_model, _, self.preprocess = self.open_clip.create_model_and_transforms(
|
55
|
+
self.model_name, pretrained="openai"
|
56
|
+
)
|
57
|
+
self.clip_model = self.clip_model.to(self.device).eval()
|
58
|
+
self.tokenizer = self.open_clip.get_tokenizer(self.model_name)
|
59
|
+
|
60
|
+
self.index = None
|
61
|
+
self.image_paths = []
|
62
|
+
|
63
|
+
self.load_or_build_index()
|
64
|
+
|
65
|
+
def extract_image_feature(self, path):
|
66
|
+
"""Extract CLIP image embedding."""
|
67
|
+
image = Image.open(path)
|
68
|
+
tensor = self.preprocess(image).unsqueeze(0).to(self.device)
|
69
|
+
with torch.no_grad():
|
70
|
+
return self.clip_model.encode_image(tensor).cpu().numpy()
|
71
|
+
|
72
|
+
def extract_text_feature(self, text):
|
73
|
+
"""Extract CLIP text embedding."""
|
74
|
+
tokens = self.tokenizer([text]).to(self.device)
|
75
|
+
with torch.no_grad():
|
76
|
+
return self.clip_model.encode_text(tokens).cpu().numpy()
|
77
|
+
|
78
|
+
def load_or_build_index(self):
|
79
|
+
"""Loads FAISS index or builds a new one from image features."""
|
80
|
+
# Check if the FAISS index and corresponding image paths already exist
|
81
|
+
if Path(self.faiss_index).exists() and Path(self.data_path_npy).exists():
|
82
|
+
self.LOGGER.info("Loading existing FAISS index...")
|
83
|
+
self.index = self.faiss.read_index(self.faiss_index) # Load the FAISS index from disk
|
84
|
+
self.image_paths = np.load(self.data_path_npy) # Load the saved image path list
|
85
|
+
return # Exit the function as the index is successfully loaded
|
86
|
+
|
87
|
+
# If the index doesn't exist, start building it from scratch
|
88
|
+
self.LOGGER.info("Building FAISS index from images...")
|
89
|
+
vectors = [] # List to store feature vectors of images
|
90
|
+
|
91
|
+
# Iterate over all image files in the data directory
|
92
|
+
for file in self.data_dir.iterdir():
|
93
|
+
# Skip files that are not valid image formats
|
94
|
+
if file.suffix.lower().lstrip(".") not in IMG_FORMATS:
|
95
|
+
continue
|
96
|
+
try:
|
97
|
+
# Extract feature vector for the image and add to the list
|
98
|
+
vectors.append(self.extract_image_feature(file))
|
99
|
+
self.image_paths.append(file.name) # Store the corresponding image name
|
100
|
+
except Exception as e:
|
101
|
+
self.LOGGER.warning(f"Skipping {file.name}: {e}")
|
102
|
+
|
103
|
+
# If no vectors were successfully created, raise an error
|
104
|
+
if not vectors:
|
105
|
+
raise RuntimeError("No image embeddings could be generated.")
|
106
|
+
|
107
|
+
vectors = np.vstack(vectors).astype("float32") # Stack all vectors into a NumPy array and convert to float32
|
108
|
+
self.faiss.normalize_L2(vectors) # Normalize vectors to unit length for cosine similarity
|
109
|
+
|
110
|
+
self.index = self.faiss.IndexFlatIP(vectors.shape[1]) # Create a new FAISS index using inner product
|
111
|
+
self.index.add(vectors) # Add the normalized vectors to the FAISS index
|
112
|
+
self.faiss.write_index(self.index, self.faiss_index) # Save the newly built FAISS index to disk
|
113
|
+
np.save(self.data_path_npy, np.array(self.image_paths)) # Save the list of image paths to disk
|
114
|
+
|
115
|
+
self.LOGGER.info(f"Indexed {len(self.image_paths)} images.")
|
116
|
+
|
117
|
+
def search(self, query, k=30, similarity_thresh=0.1):
|
118
|
+
"""Returns top-k semantically similar images to the given query."""
|
119
|
+
text_feat = self.extract_text_feature(query).astype("float32")
|
120
|
+
self.faiss.normalize_L2(text_feat)
|
121
|
+
|
122
|
+
D, index = self.index.search(text_feat, k)
|
123
|
+
results = [
|
124
|
+
(self.image_paths[i], float(D[0][idx])) for idx, i in enumerate(index[0]) if D[0][idx] >= similarity_thresh
|
125
|
+
]
|
126
|
+
results.sort(key=lambda x: x[1], reverse=True)
|
127
|
+
|
128
|
+
self.LOGGER.info("\nRanked Results:")
|
129
|
+
for name, score in results:
|
130
|
+
self.LOGGER.info(f" - {name} | Similarity: {score:.4f}")
|
131
|
+
|
132
|
+
return [r[0] for r in results]
|
133
|
+
|
134
|
+
def __call__(self, query):
|
135
|
+
"""Direct call for search function."""
|
136
|
+
return self.search(query)
|
137
|
+
|
138
|
+
|
139
|
+
class SearchApp:
|
140
|
+
"""
|
141
|
+
A Flask-based web interface powers the semantic image search experience, enabling users to input natural language
|
142
|
+
queries and instantly view the most relevant images retrieved from the indexed database—all through a clean,
|
143
|
+
responsive, and easily customizable frontend.
|
144
|
+
|
145
|
+
Args:
|
146
|
+
data (str): Path to images to index and search.
|
147
|
+
device (str): Device to run inference on (e.g. 'cpu', 'cuda').
|
148
|
+
"""
|
149
|
+
|
150
|
+
def __init__(self, data="images", device=None):
|
151
|
+
"""Initialization of the VisualAISearch class for performing semantic image search."""
|
152
|
+
check_requirements("flask")
|
153
|
+
from flask import Flask, render_template, request
|
154
|
+
|
155
|
+
self.render_template = render_template
|
156
|
+
self.request = request
|
157
|
+
self.searcher = VisualAISearch(data=data, device=device)
|
158
|
+
self.app = Flask(
|
159
|
+
__name__,
|
160
|
+
template_folder="templates",
|
161
|
+
static_folder=Path(data).resolve(), # Absolute path to serve images
|
162
|
+
static_url_path="/images", # URL prefix for images
|
163
|
+
)
|
164
|
+
self.app.add_url_rule("/", view_func=self.index, methods=["GET", "POST"])
|
165
|
+
|
166
|
+
def index(self):
|
167
|
+
"""Function to process the user query and display output."""
|
168
|
+
results = []
|
169
|
+
if self.request.method == "POST":
|
170
|
+
query = self.request.form.get("query", "").strip()
|
171
|
+
results = self.searcher(query)
|
172
|
+
return self.render_template("similarity-search.html", results=results)
|
173
|
+
|
174
|
+
def run(self, debug=False):
|
175
|
+
"""Runs the Flask web app."""
|
176
|
+
self.app.run(debug=debug)
|
@@ -54,55 +54,56 @@ class BaseSolution:
|
|
54
54
|
is_cli (bool): Enables CLI mode if set to True.
|
55
55
|
**kwargs (Any): Additional configuration parameters that override defaults.
|
56
56
|
"""
|
57
|
-
check_requirements("shapely>=2.0.0")
|
58
|
-
from shapely.geometry import LineString, Point, Polygon
|
59
|
-
from shapely.prepared import prep
|
60
|
-
|
61
|
-
self.LineString = LineString
|
62
|
-
self.Polygon = Polygon
|
63
|
-
self.Point = Point
|
64
|
-
self.prep = prep
|
65
|
-
self.annotator = None # Initialize annotator
|
66
|
-
self.tracks = None
|
67
|
-
self.track_data = None
|
68
|
-
self.boxes = []
|
69
|
-
self.clss = []
|
70
|
-
self.track_ids = []
|
71
|
-
self.track_line = None
|
72
|
-
self.masks = None
|
73
|
-
self.r_s = None
|
74
|
-
|
75
|
-
self.LOGGER = LOGGER # Store logger object to be used in multiple solution classes
|
76
57
|
self.CFG = vars(SolutionConfig().update(**kwargs))
|
77
|
-
self.LOGGER
|
78
|
-
|
79
|
-
self.
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
self.
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
58
|
+
self.LOGGER = LOGGER # Store logger object to be used in multiple solution classes
|
59
|
+
|
60
|
+
if self.__class__.__name__ != "VisualAISearch":
|
61
|
+
check_requirements("shapely>=2.0.0")
|
62
|
+
from shapely.geometry import LineString, Point, Polygon
|
63
|
+
from shapely.prepared import prep
|
64
|
+
|
65
|
+
self.LineString = LineString
|
66
|
+
self.Polygon = Polygon
|
67
|
+
self.Point = Point
|
68
|
+
self.prep = prep
|
69
|
+
self.annotator = None # Initialize annotator
|
70
|
+
self.tracks = None
|
71
|
+
self.track_data = None
|
72
|
+
self.boxes = []
|
73
|
+
self.clss = []
|
74
|
+
self.track_ids = []
|
75
|
+
self.track_line = None
|
76
|
+
self.masks = None
|
77
|
+
self.r_s = None
|
78
|
+
|
79
|
+
self.LOGGER.info(f"Ultralytics Solutions: ✅ {self.CFG}")
|
80
|
+
self.region = self.CFG["region"] # Store region data for other classes usage
|
81
|
+
self.line_width = self.CFG["line_width"]
|
82
|
+
|
83
|
+
# Load Model and store additional information (classes, show_conf, show_label)
|
84
|
+
if self.CFG["model"] is None:
|
85
|
+
self.CFG["model"] = "yolo11n.pt"
|
86
|
+
self.model = YOLO(self.CFG["model"])
|
87
|
+
self.names = self.model.names
|
88
|
+
self.classes = self.CFG["classes"]
|
89
|
+
self.show_conf = self.CFG["show_conf"]
|
90
|
+
self.show_labels = self.CFG["show_labels"]
|
91
|
+
|
92
|
+
self.track_add_args = { # Tracker additional arguments for advance configuration
|
93
|
+
k: self.CFG[k] for k in ["iou", "conf", "device", "max_det", "half", "tracker", "device", "verbose"]
|
94
|
+
} # verbose must be passed to track method; setting it False in YOLO still logs the track information.
|
95
|
+
|
96
|
+
if is_cli and self.CFG["source"] is None:
|
97
|
+
d_s = "solutions_ci_demo.mp4" if "-pose" not in self.CFG["model"] else "solution_ci_pose_demo.mp4"
|
98
|
+
self.LOGGER.warning(f"source not provided. using default source {ASSETS_URL}/{d_s}")
|
99
|
+
from ultralytics.utils.downloads import safe_download
|
100
|
+
|
101
|
+
safe_download(f"{ASSETS_URL}/{d_s}") # download source from ultralytics assets
|
102
|
+
self.CFG["source"] = d_s # set default source
|
103
|
+
|
104
|
+
# Initialize environment and region setup
|
105
|
+
self.env_check = check_imshow(warn=True)
|
106
|
+
self.track_history = defaultdict(list)
|
106
107
|
|
107
108
|
def adjust_box_label(self, cls, conf, track_id=None):
|
108
109
|
"""
|
@@ -182,6 +182,10 @@ class TQDM(rich.tqdm if TQDM_RICH else tqdm.tqdm):
|
|
182
182
|
kwargs.setdefault("bar_format", TQDM_BAR_FORMAT) # override default value if passed
|
183
183
|
super().__init__(*args, **kwargs)
|
184
184
|
|
185
|
+
def __iter__(self):
|
186
|
+
"""Return self as iterator to satisfy Iterable interface."""
|
187
|
+
return super().__iter__()
|
188
|
+
|
185
189
|
|
186
190
|
class SimpleClass:
|
187
191
|
"""
|