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

[TOPI][RELAY][OP] add op crop_and_resize #4417

Merged
merged 4 commits into from
Jan 11, 2020
Merged

Conversation

yongwww
Copy link
Member

@yongwww yongwww commented Nov 24, 2019

Add crop_and_resize op into topi and relay and TensorFlow frontend.

Some of the reasons why we need crop_and_resize are as below:

  • CropAndResize is being used in TensorFlow frequently in both training and inference, 'almost' all models (such as ssd, maskrcnn, etc.) in tensorflow object detection zoo are using this op.
  • It is possible to use strided_slice, resize and concatenate to compose crop_and_resize for some cases, but the composition is not able to cover all cases, for example, when extrapolation_value is used, boxes and/or box_indices are not list, etc.
  • Most importantly, using strided_slice, resize and concatenate to build CropAndResize will introduce a significant number of ops in the converted relay ir when there are a lot of boxes as input, it does happen in models like ssd in tensorflow object detection model zoo.

@kevinthesun @zhiics @icemelon9 @jwfromm @jroesch

"bilinear - Bilinear Interpolation");
TVM_ATTR_FIELD(extrapolation_value).set_default(0.0)
.describe("Specify value for extrapolation.");
TVM_ATTR_FIELD(out_dtype)
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is out_dtype needed? Shouldn't the out dtype = input dtype?

Copy link
Contributor

Choose a reason for hiding this comment

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

It's actually useful to be able to specify it. Most images you'd be applying this to have datatype uint8. Bilinear or Bicubic resizing will by default output floats due to their interpolation but there may be cases where you'd like to stay as an integer type. Similarly, nearest nearest neighbor wont change the output type to float since it has no interpolation. Being able to specify a fixed output type improves the predictability of the function.

Copy link
Contributor

Choose a reason for hiding this comment

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

Makes sense.

TVM_DECLARE_ATTRS(CropAndResizeAttrs, "relay.attrs.CropAndResizeAttrs") {
TVM_ATTR_FIELD(crop_size).set_default(NullValue<Array<IndexExpr> >())
.describe("Target Size.");
TVM_ATTR_FIELD(layout).set_default("NCHW")
Copy link
Contributor

Choose a reason for hiding this comment

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

Does it make sense to keep layout out?

Copy link
Contributor

Choose a reason for hiding this comment

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

Resize requires knowing which axes are the spatial dimensions, so having the layout as an attribute is necessary.

Copy link
Contributor

Choose a reason for hiding this comment

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

Makes sense.

topi/python/topi/image/resize.py Outdated Show resolved Hide resolved
Copy link
Contributor

@jwfromm jwfromm left a comment

Choose a reason for hiding this comment

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

This is definitely a good addition, crop_and_resize is a common op and having direct support for it will be useful. My only complaint with this implementation is the heavy duplication between resize and crop_and_resize, which I think can be dramatically reduced with a little refactoring. I recommend pulling out the kernels for nearest_neighbor, bilinear, and bicubic sampling and making them general enough to fit both types of resize.

topi/python/topi/image/resize.py Outdated Show resolved Hide resolved
topi/python/topi/image/resize.py Outdated Show resolved Hide resolved
topi/python/topi/image/resize.py Outdated Show resolved Hide resolved
Comment on lines 340 to 349
n, c, y, x, cc = _get_indices(*indices)
box_idx = box_indices(n)

y1, x1 = boxes(n, 0), boxes(n, 1)
y2, x2 = boxes(n, 2), boxes(n, 3)

in_h = (image_height - 1) * (y2 - y1)
in_w = (image_width - 1) * (x2 - x1)
h_scale = tvm.div(in_h, target_h - 1)
w_scale = tvm.div(in_w, target_w - 1)
Copy link
Contributor

Choose a reason for hiding this comment

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

Agree with @jwfromm This seeems to be repeated.

Copy link
Member Author

Choose a reason for hiding this comment

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

It is sligthtly different from crop, for example, h_scale is calculated based on boxes while crop has no boxes, etc. I have moved these kernels out of the op and generalized them to work for both resize and crop_and_resize.

topi/python/topi/image/resize.py Outdated Show resolved Hide resolved
@yongwww
Copy link
Member Author

yongwww commented Nov 26, 2019

have addressed the comments, please take a look if you have some cycles @jwfromm @anijain2305 @kevinthesun

@jwfromm
Copy link
Contributor

jwfromm commented Nov 27, 2019

Looking at this again, I was wondering if there's any reason we can't implement a separate topi.crop function then have topi.crop_and_resize simply first call topi.crop then call topi.resize. That seems like it would be by far the cleanest implementation.

@yongwww
Copy link
Member Author

yongwww commented Nov 27, 2019

Looking at this again, I was wondering if there's any reason we can't implement a separate topi.crop function then have topi.crop_and_resize simply first call topi.crop then call topi.resize. That seems like it would be by far the cleanest implementation.

I guess crop here is the same as strided_slice? I was thinking this for a while, besides the reasons in the pr description above, some of the other reasons are as following:

  • Having a single op crop_and_resize, we don't crop the input and then resize sequentially. crop_and_resize directly resizes the input with target size. However, if crop first, then resize, it has to iterate through input images twice, which would introduce some overhead, I guess it is one of the important reasons why TF has crop_and_resize.

  • "Crop and then Resize" is not able to handle interpolation with extrapolation_value > 0 (sorry TF has this), the extrapolation_value is related to boxes, original image height and width, that means we have to change resize to take some extra inputs like boxes and original (NOT the cropped) image height and width, seems it is not simple/clean.

@jwfromm
Copy link
Contributor

jwfromm commented Nov 28, 2019

Ok, those explanations make sense. In that case I like the updates you made. LGTM once you get the tests passing.

@kevinthesun
Copy link
Contributor

Overall lgtm. @yongwww Could you take a look at the ci?

@yongwww yongwww force-pushed the crop_resize branch 2 times, most recently from 17a4479 to 02b36c1 Compare December 8, 2019 19:39
@yongwww yongwww force-pushed the crop_resize branch 4 times, most recently from 19537ba to 4d894b0 Compare January 9, 2020 21:38
@yongwww
Copy link
Member Author

yongwww commented Jan 9, 2020

@kevinthesun @zhiics @jwfromm @anijain2305 fixed comments and ci. Please take another look

Copy link
Member

@zhiics zhiics left a comment

Choose a reason for hiding this comment

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

LGTM

Other folks please take another look as well.

Copy link
Contributor

@jwfromm jwfromm left a comment

Choose a reason for hiding this comment

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

LGTM! Nice job getting this all working. I think it turned out great.

@zhiics zhiics merged commit 56416ed into apache:master Jan 11, 2020
@zhiics
Copy link
Member

zhiics commented Jan 11, 2020

alexwong pushed a commit to alexwong/tvm that referenced this pull request Feb 26, 2020
* [TOPI][RELAY][OP] add op crop_and_resize

* fix pylint

* incorporate comments

* fix ci
alexwong pushed a commit to alexwong/tvm that referenced this pull request Feb 28, 2020
* [TOPI][RELAY][OP] add op crop_and_resize

* fix pylint

* incorporate comments

* fix ci
zhiics pushed a commit to neo-ai/tvm that referenced this pull request Mar 2, 2020
* [TOPI][RELAY][OP] add op crop_and_resize

* fix pylint

* incorporate comments

* fix ci
@yongwww yongwww deleted the crop_resize branch December 8, 2020 13:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants