-
Notifications
You must be signed in to change notification settings - Fork 104
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
Update models #919
base: main
Are you sure you want to change the base?
Update models #919
Conversation
Add validation and tests for the following models: - Bounding box - Pose - Segments Add conversion to/from different bounding box formats, including normalized versions.
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #919 +/- ##
==========================================
+ Coverage 87.66% 87.77% +0.11%
==========================================
Files 130 131 +1
Lines 11698 11804 +106
Branches 1592 1596 +4
==========================================
+ Hits 10255 10361 +106
Misses 1043 1043
Partials 400 400
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
Deploying datachain-documentation with
|
Latest commit: |
db9edbe
|
Status: | ✅ Deploy successful! |
Preview URL: | https://8135dee3.datachain-documentation.pages.dev |
Branch Preview URL: | https://models-update.datachain-documentation.pages.dev |
Args: | ||
points (Sequence[Sequence[float]]): The x and y coordinates | ||
of the keypoints. List of 2 lists: x and y coordinates. | ||
normalized_to (Sequence[int], optional): The reference image size |
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.
let's just to image size - all tools usually accept size, not normalized_to
AFAIK
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.
I was thinking about using img_size
as the name of the parameter here, but then it might not be quite clear if we need to define img_size
or not and what is the difference here. If normalized_to
is not set, then points
are absolute pixel coordinates, if normalized_to
is set, then points are relative floats within normalized_to
image size.
Other possible option might be to separate those methods, such as from_list
takes points with absolute coordinates and no image size is required, and from_list_normalized
takes relative positions and image size is required.
What do you think in terms of API?
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.
okay, let me even step back - why do we need a such complicated method? that behaves differently depending on the input and the arguments passed? even from this discussion it seems it's too complicated wdyt?
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.
Oh, rhetorical question! 😅 Any function will behaves differently depending on the input and the arguments passed 🙃 Let me describe the way I was thinking.
In this case we have two options:
- Split the function into two:
from_list
+from_list_normalized
-> this means we should also have third function to follow the DRY principle, or drop all the validations. - Use one function
from_list
with additional argument (normalized_to=...
)
In terms of API I do not really see the difference, but in terms of "complexity" there is a difference. It is absolutely the same in both cases, except for additional conversion (removing all checks for simplicity here):
# validation
points_x, points_y = points
if normalized_to is not None:
width, height = normalized_to
points_x = [coord * width for coord in points_x]
points_y = [coord * height for coord in points_y]
# processing
It is kind of the same but same time it is complicated and kind of subjective, I would say. I was considering to have two separate functions, but in the end I have decided to make a single one. I still have no strong opinion on this, and if you feel we need to separate these functions, I will be happy to update this PR ❤️
I also have this described in docstrings here. Which also might signalize this was a bad idea, but same time this exactly comment I think we should keep in separate function if we decided to split these.
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.
Any function will behaves differently depending on the input and the arguments passed
in this context specifically - not every. All from_
and to_
are stable to my mind and have precise semantics of an output
Split the function into two: from_list + from_list_normalized -> this means we should also have third function to follow the DRY principle, or drop all the validations.
okay, why do we need from_list
at all?
it should be rather from_coco, from_yolo, from_albumentations ...
or it can be from(array, type: Literal['coco', 'yolo', ....])
"Normalized coordinates must be floats between 0 and 1." | ||
) | ||
width, height = validate_img_size(normalized_to) | ||
points_x = [coord * width for coord in points_x] |
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.
can it be a vectorized operation with numpy?
Returns: | ||
Pose: A Pose object. | ||
""" | ||
assert isinstance(points, (tuple, list)), "Pose must be a list of 2 lists." |
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.
probably we should be raising proper ValueErrors here, not do asserts
width, height = validate_img_size(normalized_to) | ||
points_x = [coord * width for coord in points_x] | ||
points_y = [coord * height for coord in points_y] | ||
|
||
return Pose( | ||
x=[round(coord) for coord in points_x], |
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.
same, all these could be vectorized operations most likely
can we outsource it to some exiting lib btw? (I'm afraid that this seemingly simple code has a lot of complexity potentially ... also, AFAIR yolo has some utils and since we depend on it already should we use it?
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.
I will take a look at vectorized operations, thank you for the suggestion 🙏
also, AFAIR yolo has some utils and since we depend on it already should we use it?
I don't want to import ultralytics
here because user might not have it installed, and I am not sure we should keep it as an optional dependency. Here I am trying to keep these models dead simple and do not rely on additional optional libraries. These base models (BBox,
Pose,
Segment`) in general should works with any library, not only Yolo, that's why we do have all these conversions here.
Note
These base models (
BBox,
Pose,
Segment`) in general should works with any library, not only Yolo, that's why we do have all these conversions here.
Strictly saying Pose
validation requires exactly 17 points, it is OK for Yolo but may not be OK for other pose models. I think I should remove this validation from here.
coords (Sequence[float]): The bounding box coordinates. | ||
title (str, optional): The title or label for the bounding box. | ||
Defaults to "". | ||
normalized_to (Sequence[int], optional): The reference image size |
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.
so, does it mean we have the same model that can be normalize and not?
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.
also, even here it is weird ... normalized_to ... the reference image size
|
||
If the input coordinates are normalized (i.e., floats between 0 and 1), | ||
they will be converted to absolute pixel values based on the provided | ||
image size. The image size should be given as a tuple (width, height) |
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.
what is the image size here?
|
||
def to_yolo(self) -> list[int]: | ||
""" | ||
Convert the bounding box to YOLO format. |
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.
yolo is normalized by default, no? (at when you train something it asks it to be normalized) - let's refer to utils in albumentations lib to be sure about formats, naming, etc
assert all(isinstance(value, float) for value in coords), ( | ||
"Bounding box normalized coordinates must be floats." | ||
) | ||
assert all(0 <= value <= 1 for value in coords), ( |
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.
how do bounding boxes behave on the edges (the same with poses) - is it true that it should be always <1 (since coodrinate starts with 0 and is always < image size)?
width, height = validate_img_size(img_size) | ||
|
||
assert ( | ||
0 <= coords[0] <= width |
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.
same question here - how do they behave on the edges?
Add validation and tests for the following models:
Add conversion to/from different bounding box formats, including normalized versions, for example:
TODO