Skip to content
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

Remove bounding box utils and refactor retinanet #2039

Open
wants to merge 11 commits into
base: master
Choose a base branch
from

Conversation

sineeli
Copy link
Collaborator

@sineeli sineeli commented Jan 8, 2025

  1. Moved non_max_suppression, anchor_generator, and box_matcher into the modeling layers for better integration.
  2. Removed redundant bounding box utilities and dependencies

@sineeli sineeli requested a review from mattdangerw January 9, 2025 16:27
@mattdangerw
Copy link
Member

mattdangerw commented Jan 13, 2025

Not sure what best to do about this test failure. @sineeli do you know the minimal version of Keras we would need for all of this?

@sineeli
Copy link
Collaborator Author

sineeli commented Jan 13, 2025

Not sure what best to do about this test failure. @sineeli do you know the minimal version of Keras we would need for all of this?

It would require latest release 3.8.0 which has iou function and box encoding utilities as well.

Copy link
Member

@mattdangerw mattdangerw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Left some comments

keras_hub/src/layers/modeling/non_max_supression.py Outdated Show resolved Hide resolved

@keras_hub_export("keras_hub.layers.AnchorGenerator")
class AnchorGenerator(keras.layers.Layer):
"""Generates anchor boxes for object detection tasks.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these look like copy paste bugs where selecting from github removes empty newlines. bring these empty newlines back

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unfixed. Take a look at the diff here and restore the empty newlines.

If you copy paste from the github ui you will remove all empty newlines from the file, just something to watch out for.

keras_hub/src/layers/modeling/box_matcher.py Show resolved Hide resolved
keras_hub/src/layers/modeling/anchor_generator.py Outdated Show resolved Hide resolved
Copy link
Member

@mattdangerw mattdangerw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still a few comments to address. The big one, we need to get rid of the private import of keras for that validation function. Let's remove or duplicate.

We might also want to set things up so the library still works with older keras versions, and throws an error when using an OD model that 3.8 is required. But I can help with that part.

keras_hub/src/layers/modeling/non_max_supression.py Outdated Show resolved Hide resolved
@sineeli
Copy link
Collaborator Author

sineeli commented Jan 21, 2025

Oh yeah make sense, we can only import when we have Keras>=3.8.0 version and then throw error when this doesn't satisfy? I hope this works.

keras_hub/api/layers/__init__.py Outdated Show resolved Hide resolved
keras_hub/src/layers/modeling/non_max_supression.py Outdated Show resolved Hide resolved
keras_hub/src/layers/modeling/non_max_supression.py Outdated Show resolved Hide resolved
@@ -18,6 +15,10 @@
RetinaNetObjectDetectorPreprocessor,
)

# Check if Keras version is greater than or equal to 2.10.0
if version.parse(keras.__version__) < version.parse("3.8.0"):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not how we can do this. We need this library to be importable with older versions of Keras. And this file will be imported, and this code block run, on library import!

We need to instead assert the version on usage of symbols we care about.

  • Add a function here called assert_bounding_box_support().
  • Call it here inside init, first thing. Also add the same check to anchor generator and box matcher layers.

# Check if Keras version is greater than or equal to 2.10.0
if version.parse(keras.__version__) < version.parse("3.8.0"):
raise ImportError("Requires 3.8.0 or higher.")


@keras_hub_export("keras_hub.models.RetinaNetObjectDetector")
class RetinaNetObjectDetector(ImageObjectDetector):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to align on names here. Either ImageObjectDetector and RetinaNetImageObjectDetector, or ObjectDetector and RetinaNetObjectDetector. That's our general pattern.

I'd prefer just rename ImageObjectDetector -> ObjectDetector everywhere. cc @divyashreepathihalli

@@ -10,25 +12,36 @@ class RetinaNetImageConverter(ImageConverter):

def __init__(
self,
image_size=None,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems suspicious. Why are we removing these args? Keep these unaltered, add bounding_box_format after.

@sineeli
Copy link
Collaborator Author

sineeli commented Jan 30, 2025

@mattdangerw what do you think on assert_bounding_box_support function, does it looks good or else any changes needed please let me know thanks!

@sineeli sineeli requested a review from mattdangerw January 30, 2025 21:49
@sineeli sineeli added the kokoro:force-run Runs Tests on GPU label Jan 30, 2025
@kokoro-team kokoro-team removed the kokoro:force-run Runs Tests on GPU label Jan 30, 2025
Copy link
Member

@mattdangerw mattdangerw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Looking good. Still a few minor things.


@keras_hub_export("keras_hub.layers.AnchorGenerator")
class AnchorGenerator(keras.layers.Layer):
"""Generates anchor boxes for object detection tasks.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unfixed. Take a look at the diff here and restore the empty newlines.

If you copy paste from the github ui you will remove all empty newlines from the file, just something to watch out for.

from keras_hub.src.tests.test_case import TestCase


class AnchorGeneratorTest(TestCase):
@pytest.mark.skipif(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You do a class level skipif later it looks like. Why not do that here? You are skipping every test.


from keras_hub.src.models.retinanet.box_matcher import BoxMatcher
from keras_hub.src.layers.modeling.box_matcher import BoxMatcher
from keras_hub.src.tests.test_case import TestCase


class BoxMatcherTest(TestCase):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, why not do this at the class level if you are skipping everything in the class.

@@ -262,6 +264,15 @@ def assert_tf_libs_installed(symbol_name):
)


def assert_bounding_box_support(symbol_name):
keras_version = re.sub(r".dev.*", "", keras.__version__)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do you need this line? version should handle dev release markers and other stuff here https://packaging.python.org/en/latest/discussions/versioning/

anchor_boxes,
gt_boxes,
bounding_box_format=self.bounding_box_format,
image_shape=image_shape,
image_shape=(height, width, 3),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like the RetinaNetBackbone allows passing the number of channels, but here we are hardcoding it. Isn't that a bug?

@@ -40,14 +59,15 @@ def call(self, inputs):
if self.norm_std:
x = x / self._expand_non_channel_dims(self.norm_std, x)

return x
return x, y, sample_weight
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

call pack_x_y_sample_weight here, it will gracefully handle the no label case.

# TODO: https://github.com/keras-team/keras-hub/issues/1965
x = inputs
def call(self, x, y=None, sample_weight=None):
if y is not None:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need two resizing layers here (which is also just kind of confusing).

Wouldn't it work to make one self.resizing layer above, and then...

if y is not None:
    inputs = self.resizing({"images": x, "bounding_boxes": y})
    x = inputs["images"]
    y = inputs["bounding_boxes"]
else:
    x = self.resizing(x) 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants