Merge branch 'main' into new-cache

new-cache
Glenn Jocher 8 months ago committed by GitHub
commit fd21254c80
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      .github/workflows/ci.yaml
  2. 4
      .github/workflows/cla.yml
  3. 9
      ultralytics/data/augment.py
  4. 16
      ultralytics/engine/exporter.py
  5. 36
      ultralytics/utils/__init__.py
  6. 12
      ultralytics/utils/plotting.py

@ -123,7 +123,7 @@ jobs:
run: coverage run -a --source=ultralytics -m ultralytics.cfg.__init__ benchmark model='path with spaces/yolov8s-worldv2.pt' imgsz=160 verbose=0.318 run: coverage run -a --source=ultralytics -m ultralytics.cfg.__init__ benchmark model='path with spaces/yolov8s-worldv2.pt' imgsz=160 verbose=0.318
- name: Benchmark SegmentationModel - name: Benchmark SegmentationModel
shell: bash shell: bash
run: coverage run -a --source=ultralytics -m ultralytics.cfg.__init__ benchmark model='path with spaces/${{ matrix.model }}-seg.pt' imgsz=160 verbose=0.281 run: coverage run -a --source=ultralytics -m ultralytics.cfg.__init__ benchmark model='path with spaces/${{ matrix.model }}-seg.pt' imgsz=160 verbose=0.280
- name: Benchmark ClassificationModel - name: Benchmark ClassificationModel
shell: bash shell: bash
run: coverage run -a --source=ultralytics -m ultralytics.cfg.__init__ benchmark model='path with spaces/${{ matrix.model }}-cls.pt' imgsz=160 verbose=0.166 run: coverage run -a --source=ultralytics -m ultralytics.cfg.__init__ benchmark model='path with spaces/${{ matrix.model }}-cls.pt' imgsz=160 verbose=0.166

@ -1,4 +1,6 @@
# Ultralytics YOLO 🚀, AGPL-3.0 license # Ultralytics YOLO 🚀, AGPL-3.0 license
# Ultralytics Contributor License Agreement (CLA) action https://docs.ultralytics.com/help/CLA
# This workflow automatically requests Pull Requests (PR) authors to sign the Ultralytics CLA before PRs can be merged
name: CLA Assistant name: CLA Assistant
on: on:
@ -21,7 +23,7 @@ jobs:
uses: contributor-assistant/github-action@v2.3.2 uses: contributor-assistant/github-action@v2.3.2
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# must be repository secret token # must be repository secret PAT
PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
with: with:
path-to-signatures: "signatures/version1/cla.json" path-to-signatures: "signatures/version1/cla.json"

@ -975,17 +975,22 @@ class Format:
1 if self.mask_overlap else nl, img.shape[0] // self.mask_ratio, img.shape[1] // self.mask_ratio 1 if self.mask_overlap else nl, img.shape[0] // self.mask_ratio, img.shape[1] // self.mask_ratio
) )
labels["masks"] = masks labels["masks"] = masks
if self.normalize:
instances.normalize(w, h)
labels["img"] = self._format_img(img) labels["img"] = self._format_img(img)
labels["cls"] = torch.from_numpy(cls) if nl else torch.zeros(nl) labels["cls"] = torch.from_numpy(cls) if nl else torch.zeros(nl)
labels["bboxes"] = torch.from_numpy(instances.bboxes) if nl else torch.zeros((nl, 4)) labels["bboxes"] = torch.from_numpy(instances.bboxes) if nl else torch.zeros((nl, 4))
if self.return_keypoint: if self.return_keypoint:
labels["keypoints"] = torch.from_numpy(instances.keypoints) labels["keypoints"] = torch.from_numpy(instances.keypoints)
if self.normalize:
labels["keypoints"][..., 0] /= w
labels["keypoints"][..., 1] /= h
if self.return_obb: if self.return_obb:
labels["bboxes"] = ( labels["bboxes"] = (
xyxyxyxy2xywhr(torch.from_numpy(instances.segments)) if len(instances.segments) else torch.zeros((0, 5)) xyxyxyxy2xywhr(torch.from_numpy(instances.segments)) if len(instances.segments) else torch.zeros((0, 5))
) )
# NOTE: need to normalize obb in xywhr format for width-height consistency
if self.normalize:
labels["bboxes"][:, [0, 2]] /= w
labels["bboxes"][:, [1, 3]] /= h
# Then we can use collate_fn # Then we can use collate_fn
if self.batch_idx: if self.batch_idx:
labels["batch_idx"] = torch.zeros(nl) labels["batch_idx"] = torch.zeros(nl)

@ -529,12 +529,16 @@ class Exporter:
f"or in {ROOT}. See PNNX repo for full installation instructions." f"or in {ROOT}. See PNNX repo for full installation instructions."
) )
system = "macos" if MACOS else "windows" if WINDOWS else "linux-aarch64" if ARM64 else "linux" system = "macos" if MACOS else "windows" if WINDOWS else "linux-aarch64" if ARM64 else "linux"
_, assets = get_github_assets(repo="pnnx/pnnx", retry=True)
if assets: # PNNX link fixed at 20240226 due to bug in 20240410
url = [x for x in assets if f"{system}.zip" in x][0] # try:
else: # _, assets = get_github_assets(repo="pnnx/pnnx", retry=True)
url = f"https://github.com/pnnx/pnnx/releases/download/20240226/pnnx-20240226-{system}.zip" # url = [x for x in assets if f"{system}.zip" in x][0]
LOGGER.warning(f"{prefix} WARNING ⚠ PNNX GitHub assets not found, using default {url}") # except Exception as e:
# url = f"https://github.com/pnnx/pnnx/releases/download/20240226/pnnx-20240226-{system}.zip"
# LOGGER.warning(f"{prefix} WARNING ⚠ PNNX GitHub assets not found: {e}, using default {url}")
url = f"https://github.com/pnnx/pnnx/releases/download/20240226/pnnx-20240226-{system}.zip"
asset = attempt_download_asset(url, repo="pnnx/pnnx", release="latest") asset = attempt_download_asset(url, repo="pnnx/pnnx", release="latest")
if check_is_path_safe(Path.cwd(), asset): # avoid path traversal security vulnerability if check_is_path_safe(Path.cwd(), asset): # avoid path traversal security vulnerability
unzip_dir = Path(asset).with_suffix("") unzip_dir = Path(asset).with_suffix("")

@ -406,6 +406,20 @@ DEFAULT_CFG_KEYS = DEFAULT_CFG_DICT.keys()
DEFAULT_CFG = IterableSimpleNamespace(**DEFAULT_CFG_DICT) DEFAULT_CFG = IterableSimpleNamespace(**DEFAULT_CFG_DICT)
def read_device_model() -> str:
"""
Reads the device model information from the system and caches it for quick access. Used by is_jetson() and
is_raspberrypi().
Returns:
(str): Model file contents if read successfully or empty string otherwise.
"""
with contextlib.suppress(Exception):
with open("/proc/device-tree/model") as f:
return f.read()
return ""
def is_ubuntu() -> bool: def is_ubuntu() -> bool:
""" """
Check if the OS is Ubuntu. Check if the OS is Ubuntu.
@ -473,10 +487,18 @@ def is_raspberrypi() -> bool:
Returns: Returns:
(bool): True if running on a Raspberry Pi, False otherwise. (bool): True if running on a Raspberry Pi, False otherwise.
""" """
with contextlib.suppress(Exception): return "Raspberry Pi" in PROC_DEVICE_MODEL
with open("/proc/device-tree/model") as f:
return "Raspberry Pi" in f.read()
return False def is_jetson() -> bool:
"""
Determines if the Python environment is running on a Jetson Nano or Jetson Orin device by checking the device model
information.
Returns:
(bool): True if running on a Jetson Nano or Jetson Orin, False otherwise.
"""
return "NVIDIA" in PROC_DEVICE_MODEL # i.e. "NVIDIA Jetson Nano" or "NVIDIA Orin NX"
def is_online() -> bool: def is_online() -> bool:
@ -658,9 +680,11 @@ def get_user_config_dir(sub_dir="Ultralytics"):
# Define constants (required below) # Define constants (required below)
PROC_DEVICE_MODEL = read_device_model() # is_jetson() and is_raspberrypi() depend on this constant
ONLINE = is_online() ONLINE = is_online()
IS_COLAB = is_colab() IS_COLAB = is_colab()
IS_DOCKER = is_docker() IS_DOCKER = is_docker()
IS_JETSON = is_jetson()
IS_JUPYTER = is_jupyter() IS_JUPYTER = is_jupyter()
IS_KAGGLE = is_kaggle() IS_KAGGLE = is_kaggle()
IS_PIP_PACKAGE = is_pip_package() IS_PIP_PACKAGE = is_pip_package()
@ -696,8 +720,8 @@ def colorstr(*input):
(str): The input string wrapped with ANSI escape codes for the specified color and style. (str): The input string wrapped with ANSI escape codes for the specified color and style.
Examples: Examples:
>>> colorstr('blue', 'bold', 'hello world') >>> colorstr("blue", "bold", "hello world")
>>> '\033[34m\033[1mhello world\033[0m' >>> "\033[34m\033[1mhello world\033[0m"
""" """
*args, string = input if len(input) > 1 else ("blue", "bold", input[0]) # color arguments, string *args, string = input if len(input) > 1 else ("blue", "bold", input[0]) # color arguments, string
colors = { colors = {

@ -838,16 +838,16 @@ def plot_images(
if len(bboxes): if len(bboxes):
boxes = bboxes[idx] boxes = bboxes[idx]
conf = confs[idx] if confs is not None else None # check for confidence presence (label vs pred) conf = confs[idx] if confs is not None else None # check for confidence presence (label vs pred)
is_obb = boxes.shape[-1] == 5 # xywhr
boxes = ops.xywhr2xyxyxyxy(boxes) if is_obb else ops.xywh2xyxy(boxes)
if len(boxes): if len(boxes):
if boxes[:, :4].max() <= 1.1: # if normalized with tolerance 0.1 if boxes[:, :4].max() <= 1.1: # if normalized with tolerance 0.1
boxes[..., 0::2] *= w # scale to pixels boxes[..., [0, 2]] *= w # scale to pixels
boxes[..., 1::2] *= h boxes[..., [1, 3]] *= h
elif scale < 1: # absolute coords need scale if image scales elif scale < 1: # absolute coords need scale if image scales
boxes[..., :4] *= scale boxes[..., :4] *= scale
boxes[..., 0::2] += x boxes[..., 0] += x
boxes[..., 1::2] += y boxes[..., 1] += y
is_obb = boxes.shape[-1] == 5 # xywhr
boxes = ops.xywhr2xyxyxyxy(boxes) if is_obb else ops.xywh2xyxy(boxes)
for j, box in enumerate(boxes.astype(np.int64).tolist()): for j, box in enumerate(boxes.astype(np.int64).tolist()):
c = classes[j] c = classes[j]
color = colors(c) color = colors(c)

Loading…
Cancel
Save