Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
9535a45
submodule upgrades
dtronmans Mar 10, 2026
f09ff0d
remove sys.path patch
dtronmans Mar 11, 2026
366537f
ultralytics requirement
dtronmans Mar 11, 2026
368b1b7
precommit newline
dtronmans Mar 11, 2026
fab4fee
[Automated] Updated coverage badge
actions-user Mar 11, 2026
7c952d4
remove ultralytics from requirements.txt and bring back the sys.path …
dtronmans Mar 11, 2026
2f7b28c
Merge branch 'feat/upgrade-submodules' of https://github.com/luxonis/…
dtronmans Mar 11, 2026
92d5264
[Automated] Updated coverage badge
actions-user Mar 11, 2026
4468265
requirement to bypass new ultralytics automatically importing cv2
dtronmans Mar 11, 2026
8d7542f
Merge branch 'feat/upgrade-submodules' of https://github.com/luxonis/…
dtronmans Mar 11, 2026
a046063
luxonis-ml[data] unused
dtronmans Mar 12, 2026
d718c46
rollback before 2ac3371a because of possible ultralytics regression
dtronmans Mar 12, 2026
50888ec
onnxsim down to 0.5.0
dtronmans Mar 12, 2026
566abb2
restore ultralytics commit hash to newest one before rollback
dtronmans Mar 12, 2026
5261959
Revert YOLOv6 submodule bump
dtronmans Jun 19, 2026
0481d32
Update ultralytics and yolov5 submodules
dtronmans Jun 19, 2026
eb1d6a8
add requests to requirements.txt to match yolov5s new minimum
dtronmans Jun 19, 2026
f4f02a9
Update DetectV26, SegmentV26 and PoseV26 for new Ultralytics head beh…
dtronmans Jun 19, 2026
cd9e941
fix merge conflict
dtronmans Jun 19, 2026
da031c6
[Automated] Updated coverage badge
actions-user Jun 19, 2026
17f8ae1
Revert most head-related changes except the rename from return_semseg…
dtronmans Jun 19, 2026
e569cc6
Merge branch 'feat/upgrade-submodules' of https://github.com/luxonis/…
dtronmans Jun 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions media/coverage_badge.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ psutil
seaborn
mmcv>=1.5.0,<2.0.0
dill==0.4.0
requests>=2.32.2
Comment thread
klemen1999 marked this conversation as resolved.
28 changes: 10 additions & 18 deletions tools/modules/heads.py
Original file line number Diff line number Diff line change
Expand Up @@ -578,8 +578,9 @@ def forward(self, x):
boxes = []
scores = []
for i in range(self.nl):
# Box regression
box = self.cv2[i](x[i])

# Class scores
cls_regress = self.cv3[i](x[i])
boxes.append(box.view(bs, 4, -1))
scores.append(cls_regress.view(bs, self.nc, -1))
Expand All @@ -590,6 +591,7 @@ def forward(self, x):
"feats": x,
}

# Detection output: boxes (4) + confidence (1) + class scores (nc)
dbox = self._get_decode_boxes(preds)
cls_scores = preds["scores"].sigmoid() # (bs, nc, num_anchors)
conf, _ = cls_scores.max(1, keepdim=True) # ReduceMax: (bs, 1, num_anchors)
Expand All @@ -599,7 +601,6 @@ def forward(self, x):

def _get_decode_boxes(self, preds):
# Emulate ultralytics.nn.modules.head.Detect._get_decode_boxes for end2end export.
# preds["boxes"]: (N, 4, A), preds["feats"]: list of feature maps (N, C, H_i, W_i)
Comment thread
klemen1999 marked this conversation as resolved.
shape = preds["feats"][0].shape # BCHW
if self.dynamic or self.shape != shape:
anchor_points, stride_tensor = self._make_anchors(
Expand All @@ -609,8 +610,6 @@ def _get_decode_boxes(self, preds):
self.strides = stride_tensor.transpose(0, 1)
self.shape = shape

# anchors: (1, 2, A), strides: (1, 1, A)
Comment thread
klemen1999 marked this conversation as resolved.
# returns: decoded boxes (N, 4, A) in xyxy pixels
dbox = self.dist2bbox(
preds["boxes"], self.anchors.unsqueeze(0), xywh=False, dim=1
)
Expand Down Expand Up @@ -703,14 +702,12 @@ def forward(self, x):
for i in range(self.nl):
# Box regression
box = self.cv2[i](x[i])
boxes.append(box.view(bs, 4, -1))

# Class scores
cls_regress = self.cv3[i](x[i])
scores.append(cls_regress.view(bs, self.nc, -1))

# Mask coefficients
mask = self.cv4[i](x[i])
boxes.append(box.view(bs, 4, -1))
scores.append(cls_regress.view(bs, self.nc, -1))
mask_coeffs.append(mask.view(bs, self.nm, -1))

preds = {
Expand Down Expand Up @@ -744,7 +741,7 @@ def _get_proto(self, x):

Proto26 takes all feature maps and returns prototype masks.
"""
return self.proto(x, return_semseg=False)
return self.proto(x, return_semantic=False)
Comment thread
klemen1999 marked this conversation as resolved.


class PoseV26(DetectV26):
Expand Down Expand Up @@ -798,15 +795,13 @@ def forward(self, x):
for i in range(self.nl):
# Box regression
box = self.cv2[i](x[i])
boxes.append(box.view(bs, 4, -1))

# Class scores
cls_regress = self.cv3[i](x[i])
scores.append(cls_regress.view(bs, self.nc, -1))

# Keypoints: cv4 extracts features, cv4_kpts predicts keypoints
feat = self.cv4[i](x[i])
kpt = self.cv4_kpts[i](feat)
boxes.append(box.view(bs, 4, -1))
scores.append(cls_regress.view(bs, self.nc, -1))
kpts_raw.append(kpt.view(bs, self.nk, -1))

preds = {
Expand All @@ -826,7 +821,6 @@ def forward(self, x):
y = y.permute(0, 2, 1) # (bs, num_anchors, 5+nc)

# Decode and concatenate keypoints
# Note: After _get_decode_boxes, self.anchors is (2, A) and self.strides is (1, A)
kpts_cat = torch.cat(kpts_raw, dim=2) # (bs, nk, num_anchors)
kpts_decoded = self._kpts_decode(bs, kpts_cat) # (bs, nk, num_anchors)
kpts_decoded = kpts_decoded.permute(0, 2, 1) # (bs, num_anchors, nk)
Expand All @@ -839,7 +833,6 @@ def _kpts_decode(self, bs, kpts):
Emulate ultralytics.nn.modules.head.Pose26.kpts_decode.

Args:
bs: Batch size
kpts: Raw keypoint predictions (bs, nk, num_anchors)

Returns:
Expand All @@ -855,9 +848,8 @@ def _kpts_decode(self, bs, kpts):
# After _get_decode_boxes, anchors and strides are already in the right format:
# self.anchors: (2, num_anchors), self.strides: (1, num_anchors)
# Reshape for broadcasting with y[:, :, :2, :] which is (bs, num_kpts, 2, num_anchors)
anchors_reshaped = self.anchors.view(1, 1, 2, num_anchors) # (1, 1, 2, A)
strides_reshaped = self.strides.view(1, 1, 1, num_anchors) # (1, 1, 1, A)

anchors_reshaped = self.anchors.view(1, 1, 2, num_anchors)
strides_reshaped = self.strides.view(1, 1, 1, num_anchors)
# Decode xy: (raw + anchor) * stride
xy = (y[:, :, :2, :] + anchors_reshaped) * strides_reshaped

Expand Down
2 changes: 1 addition & 1 deletion tools/yolo/ultralytics
Submodule ultralytics updated 861 files
2 changes: 1 addition & 1 deletion tools/yolo/yolov5
Submodule yolov5 updated 159 files
5 changes: 5 additions & 0 deletions tools/yolo/yolov5_exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@
from tools.utils.constants import Encoding

current_dir = os.path.dirname(os.path.abspath(__file__))
# Add ultralytics submodule to sys.path so that yolov5's internal
# `import ultralytics` resolves to the local submodule
ultralytics_path = os.path.join(current_dir, "ultralytics")
if ultralytics_path not in sys.path:
sys.path.insert(0, ultralytics_path)
yolov5_path = os.path.join(current_dir, "yolov5")
# Ensure it's first in sys.path
if yolov5_path not in sys.path:
Expand All @@ -32,7 +37,7 @@

model = models.experimental.Ensemble()
for w in weights if isinstance(weights, list) else [weights]:
ckpt = torch.load(

Check failure on line 40 in tools/yolo/yolov5_exporter.py

View workflow job for this annotation

GitHub Actions / semgrep/ci

Semgrep Issue

Functions reliant on pickle can result in arbitrary code execution. Consider loading from `state_dict`, using fickling, or switching to a safer serialization method like ONNX
models.experimental.attempt_download(w),
map_location="cpu",
weights_only=False,
Expand Down
Loading