Skip to content

Added TF add behaviour alignment#19477

Merged
alalek merged 2 commits intoopencv:3.4from
LupusSanctus:am/eltwice_vec
Mar 23, 2021
Merged

Added TF add behaviour alignment#19477
alalek merged 2 commits intoopencv:3.4from
LupusSanctus:am/eltwice_vec

Conversation

@LupusSanctus
Copy link
Copy Markdown

@LupusSanctus LupusSanctus commented Feb 7, 2021

Merge with extra: opencv/opencv_extra#849

Fixes #17364: inappropriate OpenCV processing of specific tensor summation case in LaneNet BiseNetv2 front end.

Added tf.math.add and OCV eltwise_layer behaviour alignment.

The initial problem problem is incorrect processing of the case, when, for example, there are two tensors: a (shape: [1,1,1,n] ) and b (shape: [1,<some_val_1>,<some_val_2>,n] ). tf.math.add returns the result c (shape: [1,<some_val_1>,<some_val_2>,n] ), whereas OpenCV compares 1 vs <some_val_1> and 1 vs <some_val_2>, throws exception in getMemoryShapes() and that's all.
The solution for such cases (for example, for tensor shape 1x10x1x1 (NxCxHxW) +1x10x5x5 (NxCxHxW)) was:

  1. choose the correct output resultant shape: 1x10x5x5 (NxCxHxW)
  2. expand 1x10x1x1 (NxCxHxW) for further correct summation with 1x10x5x5 (NxCxHxW).
    The initial problem problem is incorrect processing of the case, when, for example, there are two tensors: a (shape: [1,1,1,n] ) and b (shape: [1,<some_val_1>,<some_val_2>,n] ). tf.math.add returns the result c (shape: [1,<some_val_1>,<some_val_2>,n] ), whereas OpenCV compares 1 vs <some_val_1> and 1 vs <some_val_2>, throws exception in getMemoryShapes() and that's all.
    The solution for such cases (for example, for tensor shape 1x10x1x1 (NxCxHxW) +1x10x5x5 (NxCxHxW)) was:
  3. choose the correct output resultant shape: 1x10x5x5 (NxCxHxW)
  4. expand 1x10x1x1 (NxCxHxW) for further correct summation with 1x10x5x5 (NxCxHxW).

Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

  • I agree to contribute to the project under Apache 2 License.
  • To the best of my knowledge, the proposed patch is not based on a code under GPL or other license that is incompatible with OpenCV
  • The PR is proposed to proper branch
  • There is reference to original bug report and related work
  • There is accuracy test, performance test and test data in opencv_extra repository, if applicable
    Patch to opencv_extra has the same branch name.
  • The feature is well documented and sample code can be built with the project CMake
force_builders=Custom,Custom Win,Custom Mac
build_image:Custom=ubuntu-openvino-2021.1.0:20.04
build_image:Custom Win=openvino-2021.1.0
build_image:Custom Mac=openvino-2021.1.0

test_modules:Custom=dnn,python2,python3,java
test_modules:Custom Win=dnn,python2,python3,java
test_modules:Custom Mac=dnn,python2,python3,java

buildworker:Custom=linux-1
# disabled due high memory usage: test_opencl:Custom=ON
test_opencl:Custom=OFF
test_bigdata:Custom=1
test_filter:Custom=*

@dkurt
Copy link
Copy Markdown
Member

dkurt commented Feb 8, 2021

Please choose 3.4 as a target branch (more details in #19474 (comment) )

@LupusSanctus LupusSanctus changed the base branch from master to 3.4 February 8, 2021 10:30
@asmorkalov asmorkalov requested a review from dkurt February 10, 2021 08:14
Copy link
Copy Markdown
Member

@alalek alalek left a comment

Choose a reason for hiding this comment

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

Could we add explicit input parameter which changes operating mode?

We need to ensure that "layers fusing" is still properly handled (fused code may not call the ".forward()" method).

for (size_t x = 0; x < xSize; x++)
{
outIdx[2] = x;
inputs[i].at<float>(outIdx.data()) = tmpInput.at<float>(idx.data());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

IMHO, generating duplicated data doesn't look good from performance perspective.

Copy link
Copy Markdown
Author

@LupusSanctus LupusSanctus Feb 28, 2021

Choose a reason for hiding this comment

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

@alalek, there are two options to resolve the issue:

  1. support Mat (shape: [1, m, k, n] ) + Vec (shape: [1, 1, 1, n]) operation in multiple implementations (ex.: OCL), which is quite complex and error-prone
  2. expand Vec (shape: [1, 1, 1, n]) to Mat to support a new case using an existing implementation at the expense of extra memory usage

if (!allOnes && !isVecFound)
{
vecIdx = i;
isVecFound = true;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

IMHO, such stuff should be explicitly specified through parameters instead of implicit internal handling.

Copy link
Copy Markdown
Author

@LupusSanctus LupusSanctus Feb 28, 2021

Choose a reason for hiding this comment

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

@alalek, it seems that ''explicit input parameter'' is an extra option. This PR adds support Mat (shape: [1, m, k, n] ) + Vec (shape: [1, 1, 1, n]). This support was implemented with Vec (shape: [1, 1, 1, n]) to Mat expansion to avoid possible reconstruction of eltwise_layer.cpp summation core. Thus, the current approach should not lead to further corruptions:

We need to ensure that "layers fusing" is still properly handled (fused code may not call the ".forward()" method).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Main concern here is about correct and accurate implementation of supportBackend() callback.

Only OpenCV/CPU backend supports new mode (CUDA, Halide, Vulkan, even OpenCV/OpenCL doesn't support that).
Unsupported backends should be filtered out in the right way.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

@alalek, could you, please, clarify the following: if we don't change the computation core (forward(...) and run(...) functions were not changed) and modify only one of the inputs' shape, expanding it in getMemoryShapes(...), we should not impact on the chosen backend. Thus, do we really need supportBackend() callback corrections here?

Copy link
Copy Markdown
Member

@alalek alalek Mar 20, 2021

Choose a reason for hiding this comment

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

forward() is modified below, see if (channelsModeInput == ELTWISE_CHANNNELS_SAME && inputs[0].dims > 2)


Tests filter out non-working "OpenCL" cases (as mentioned there this should not be done for OpenCV/OCL code path)


modify only one of the inputs' shape

Probably we can't do that. Input is always a some output of another layer.


Thus, do we really need supportBackend() callback corrections here?

supportBackend() must be revised if we add support for new mode.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

@alalek, thank you for the review, added corrections for supportBackend().

@asmorkalov
Copy link
Copy Markdown
Contributor

@dkurt @alalek Please take a look.

CV_Assert(outputs.size() == 1);
const int nstripes = getNumThreads();

if (channelsModeInput == ELTWISE_CHANNNELS_SAME && inputs[0].dims > 2)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please add bailout code in forward_ocl() (line 546) for new functionality:

         if ((inputs_.depth() == CV_16S && op != SUM) || (channelsMode != ELTWISE_CHANNNELS_SAME))
             return false;
 
+        if (hasVecInput)
+            return false;  // TODO not implemented yet: https://github.com/opencv/opencv/pull/19477

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

@alalek, forward_ocl() was corrected.

Anastasia Murzova added 2 commits March 23, 2021 23:04
Support Mat (shape: [1, m, k, n] ) + Vec (shape: [1, 1, 1, n]) operation
by vec to mat expansion
Copy link
Copy Markdown
Member

@alalek alalek left a comment

Choose a reason for hiding this comment

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

Looks good to me! Thank you 👍

@alalek alalek merged commit 551d4a8 into opencv:3.4 Mar 23, 2021
@alalek alalek mentioned this pull request Apr 9, 2021
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.

4 participants