-
Notifications
You must be signed in to change notification settings - Fork 3
AIMET Integration #366
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
AIMET Integration #366
Changes from all commits
b26e70f
ba56cb9
4bf1bcf
6e506ce
0e3673b
9cd6826
3d8828a
7dca296
58565e4
40518c0
fa33a8d
c051144
4923c8e
cb07292
9dd61d8
d45abc4
22c98a1
eafbcf9
59936ec
ea07550
ea3f8cd
2716b1e
9bccbc8
d200891
d34ca91
1140c36
fa5c934
5180a5e
87f98b5
ffa5bda
c359722
b77c126
068d8f1
5769e46
fb72ec6
1e95e2a
5c07a31
2476ef7
faef813
51f897d
5f5ddfa
4c0d8d6
b786595
8dffdec
5b09694
67953c4
8ff59a6
d249b57
1b3b8c1
bb379ff
6476482
34c0fdd
ad3e379
bed8285
06a6c2c
fc73aec
96f42da
d5fefe5
5993a6f
24ac150
478046c
3fc8cb4
e7b4a6e
4b74f04
a5558a4
d14f285
70f6675
ed6ed80
1d110ce
c06d002
0162f88
bb7f28c
25656ab
7bcd04b
c309012
a1fb63b
4dc9884
70faf84
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,8 +17,6 @@ | |
| from luxonis_train.utils.boundingbox import IoUType | ||
| from luxonis_train.utils.keypoints import insert_class | ||
|
|
||
| from .bce_with_logits import BCEWithLogitsLoss | ||
|
|
||
|
|
||
| class EfficientKeypointBBoxLoss(AdaptiveDetectionLoss): | ||
| node: EfficientKeypointBBoxHead | ||
|
|
@@ -74,9 +72,7 @@ def __init__( | |
| **kwargs, | ||
| ) | ||
|
|
||
| self.b_cross_entropy = BCEWithLogitsLoss( | ||
| pos_weight=torch.tensor([viz_pw]) | ||
| ) | ||
| self.pos_weight = torch.tensor([viz_pw]) | ||
| self.sigmas = get_sigmas( | ||
| sigmas=sigmas, n_keypoints=self.n_keypoints, caller_name=self.name | ||
| ) | ||
|
|
@@ -85,6 +81,13 @@ def __init__( | |
| ) | ||
| self.regr_kpts_loss_weight = regr_kpts_loss_weight | ||
| self.vis_kpts_loss_weight = vis_kpts_loss_weight | ||
| self.register_buffer( | ||
| "gt_kpts_scale", | ||
| torch.tensor( | ||
| [self.original_img_size[1], self.original_img_size[0]], | ||
| ), | ||
| persistent=False, | ||
| ) | ||
|
|
||
| def forward( | ||
| self, | ||
|
|
@@ -95,14 +98,14 @@ def forward( | |
| target_boundingbox: Tensor, | ||
| target_keypoints: Tensor, | ||
| ) -> tuple[Tensor, dict[str, Tensor]]: | ||
| self._init_parameters(features) | ||
|
|
||
| device = keypoints_raw.device | ||
| target_keypoints = insert_class(target_keypoints, target_boundingbox) | ||
|
|
||
| batch_size = class_scores.shape[0] | ||
| n_kpts = (target_keypoints.shape[1] - 2) // 3 | ||
|
|
||
| self._init_parameters(features) | ||
|
|
||
| pred_bboxes = dist2bbox(distributions, self.anchor_points_strided) | ||
| keypoints_raw = self.dist2kpts_noscale( | ||
| self.anchor_points_strided, | ||
|
|
@@ -124,7 +127,7 @@ def forward( | |
| scaled_raw_keypoints = keypoints_raw.clone() | ||
| scaled_raw_keypoints[..., :2] = scaled_raw_keypoints[ | ||
| ..., :2 | ||
| ] * self.stride_tensor.view(1, -1, 1, 1) | ||
| ] * self.stride_tensor.clone().view(1, -1, 1, 1) | ||
|
|
||
| sigmas = self.sigmas.to(device) | ||
|
|
||
|
|
@@ -190,8 +193,11 @@ def forward( | |
| regression_loss = ( | ||
| ((1 - torch.exp(-e)) * mask).sum(dim=1) / (mask.sum(dim=1) + 1e-9) | ||
| ).mean() | ||
| visibility_loss = self.b_cross_entropy.forward( | ||
| keypoints_raw[..., 2], mask | ||
|
|
||
| visibility_loss = F.binary_cross_entropy_with_logits( | ||
| keypoints_raw[..., 2], | ||
| mask, | ||
| pos_weight=self.pos_weight.clone().to(device), | ||
| ) | ||
|
|
||
| one_hot_label = F.one_hot(assigned_labels.long(), self.n_classes + 1)[ | ||
|
|
@@ -264,12 +270,3 @@ def dist2kpts_noscale(self, anchor_points: Tensor, kpts: Tensor) -> Tensor: | |
| adj_kpts[..., 0] += x_adj | ||
| adj_kpts[..., 1] += y_adj | ||
| return adj_kpts | ||
|
|
||
| def _init_parameters(self, features: list[Tensor]) -> None: | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Parameters created this way were causing weird errors during quantization because the tensors were created during |
||
| if hasattr(self, "gt_kpts_scale"): | ||
| return | ||
| super()._init_parameters(features) | ||
| self.gt_kpts_scale = torch.tensor( | ||
| [self.original_img_size[1], self.original_img_size[0]], | ||
| device=features[0].device, | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -92,7 +92,7 @@ def forward(self, img1: Tensor, img2: Tensor) -> Tensor: | |
|
|
||
| (_, channel, _, _) = img1.size() | ||
| if channel == self.channel and self.window.dtype == img1.dtype: | ||
| window = self.window.to(device) | ||
| window = self.window.to(device).clone() | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cloning is another way how to fix the "tensors created in inference mode" issue. |
||
| else: | ||
| window = ( | ||
| create_window(self.window_size, channel) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -164,6 +164,12 @@ def compute( | |
| """ | ||
| return super().compute() | ||
|
|
||
| def __eq__(self, other: object) -> bool: | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This fixes an issue with
For example you can do: from torchmetrics import Precision, Recall
precision = Precision(task="binary")
recall = Recall(task="binary")
# Operator overloading on the classes
f1_score = 2 * (precision * recall) / (precision + recall)The from torchmetrics import F1Score
official_f1_score = F1Score(task="binary")
f1_score.update(
tensor([0, 1, 1, 0, 0, 1]), tensor([0, 1, 0, 1, 1, 1])
)
print(f"F1 Score: {f1_score.compute()}")
# F1 Score: 0.5714
official_f1_score.update(
tensor([0, 1, 1, 0, 0, 1]), tensor([0, 1, 0, 1, 1, 1])
)
print(f"Official F1 Score: {official_f1_score.compute()}")
# Official F1 Score: 0.5714
print(f1_score)
# CompositionalMetric(
# true_divide(
# CompositionalMetric(
# mul(
# 2,
# CompositionalMetric(
# mul(
# BinaryPrecision(),
# BinaryRecall()
# )
# )
# )
# ),
# CompositionalMetric(
# add(
# BinaryPrecision(),
# BinaryRecall()
# )
# )
# )
# )This is cool but it works for foo = precision != 2
print(foo)
# CompositionalMetric(
# ne(
# BinaryPrecision(),
# 2
# )
# )This has one major disadvantage: foo = precision != 2
print(bool(foo))
# True
if precision == None:
print("This should not happen")
# This should not happenThis breaks AIMET which expects comparisons to work, so in order to fix it we have to re-implement |
||
| return self is other | ||
|
|
||
| def __hash__(self) -> int: | ||
| return id(self) | ||
|
|
||
| @cached_property | ||
| def _signature(self) -> dict[str, Parameter]: | ||
| return get_signature(self.update) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,8 +3,9 @@ | |
| from inspect import Parameter | ||
|
|
||
| import torch.nn.functional as F | ||
| from luxonis_ml.data.utils import ColorMap | ||
| from torch import Tensor | ||
| from typing_extensions import TypeVarTuple, Unpack | ||
| from typing_extensions import TypeVarTuple, Unpack, override | ||
|
|
||
| from luxonis_train.attached_modules import BaseAttachedModule | ||
| from luxonis_train.registry import VISUALIZERS | ||
|
|
@@ -25,6 +26,13 @@ def __init__(self, *args, scale: float = 1.0, **kwargs) -> None: | |
| super().__init__(*args, **kwargs) | ||
| self.scale = scale | ||
|
|
||
| @override | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| def __getstate__(self) -> dict: | ||
| state = super().__getstate__() | ||
| if "colormap" in state: | ||
| del state["colormap"] | ||
| return state | ||
|
|
||
| @staticmethod | ||
| def scale_canvas(canvas: Tensor, scale: float = 1.0) -> Tensor: | ||
| return F.interpolate( | ||
|
|
@@ -34,6 +42,10 @@ def scale_canvas(canvas: Tensor, scale: float = 1.0) -> Tensor: | |
| align_corners=False, | ||
| ) | ||
|
|
||
| @cached_property | ||
| def colormap(self) -> ColorMap: | ||
| return ColorMap() | ||
|
|
||
| @abstractmethod | ||
| def forward( | ||
| self, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Keeping a reference to another
BaseLossthat is not attached to a specific node is problematic when copying the model. In this case it's easier to useF.binary_cross_entropy_with_logitsdirectly instead of ourBSEWithLogitsLoss.