Support 1x1 Max/Average Pooling with 1x1 stride in XNNPACK delegate

PiperOrigin-RevId: 320703905
Change-Id: Id9787ba836b7d50f34dcad82033553d0e70b1ac9
This commit is contained in:
Marat Dukhan 2020-07-10 17:09:34 -07:00 committed by TensorFlower Gardener
parent d0ae0f8c70
commit 98db6af79d
4 changed files with 159 additions and 31 deletions

View File

@ -100,7 +100,7 @@ Below is the list of current operators and limitations:
### `AVERAGE_POOL_2D`
* Inputs and outputs must be in 32-bit floating-point format.
* 1x1 pooling is not supported.
* 1x1 pooling with non-unit stride is not supported.
* Fused `NONE`, `RELU`, `RELU_N1_TO_1`, and `RELU6` activations are supported,
but fused `TANH` and `SIGN_BIT` activations are not.
@ -157,7 +157,7 @@ Below is the list of current operators and limitations:
### `MAX_POOL_2D`
* Inputs and outputs must be in 32-bit floating-point format.
* 1x1 pooling is not supported.
* 1x1 pooling with non-unit stride is not supported.
* Fused `NONE`, `RELU`, `RELU_N1_TO_1`, and `RELU6` activations are supported,
but fused `TANH` and `SIGN_BIT` activations are not.

View File

@ -25,6 +25,60 @@ limitations under the License.
namespace tflite {
namespace xnnpack {
TEST(AveragePool2D, UnitPoolSamePadding) {
std::unique_ptr<TfLiteDelegate, decltype(&TfLiteXNNPackDelegateDelete)>
xnnpack_delegate(TfLiteXNNPackDelegateCreate(nullptr),
TfLiteXNNPackDelegateDelete);
std::random_device random_device;
auto rng = std::mt19937(random_device());
auto batch_rng =
std::bind(std::uniform_int_distribution<int32_t>(2, 4), std::ref(rng));
auto input_rng =
std::bind(std::uniform_int_distribution<int32_t>(10, 25), std::ref(rng));
auto channel_rng =
std::bind(std::uniform_int_distribution<int32_t>(5, 16), std::ref(rng));
Pool2DTester()
.BatchSize(batch_rng())
.InputHeight(input_rng())
.InputWidth(input_rng())
.Channels(channel_rng())
.PoolingHeight(1)
.PoolingWidth(1)
.StrideHeight(1)
.StrideWidth(1)
.SamePadding()
.Test(BuiltinOperator_AVERAGE_POOL_2D, xnnpack_delegate.get());
}
TEST(AveragePool2D, UnitPoolValidPadding) {
std::unique_ptr<TfLiteDelegate, decltype(&TfLiteXNNPackDelegateDelete)>
xnnpack_delegate(TfLiteXNNPackDelegateCreate(nullptr),
TfLiteXNNPackDelegateDelete);
std::random_device random_device;
auto rng = std::mt19937(random_device());
auto batch_rng =
std::bind(std::uniform_int_distribution<int32_t>(2, 4), std::ref(rng));
auto input_rng =
std::bind(std::uniform_int_distribution<int32_t>(10, 25), std::ref(rng));
auto channel_rng =
std::bind(std::uniform_int_distribution<int32_t>(5, 16), std::ref(rng));
Pool2DTester()
.BatchSize(batch_rng())
.InputHeight(input_rng())
.InputWidth(input_rng())
.Channels(channel_rng())
.PoolingHeight(1)
.PoolingWidth(1)
.StrideHeight(1)
.StrideWidth(1)
.ValidPadding()
.Test(BuiltinOperator_AVERAGE_POOL_2D, xnnpack_delegate.get());
}
TEST(AveragePool2D, EqualPoolAndStrideWithSamePadding) {
std::unique_ptr<TfLiteDelegate, decltype(&TfLiteXNNPackDelegateDelete)>
xnnpack_delegate(TfLiteXNNPackDelegateCreate(nullptr),

View File

@ -25,6 +25,60 @@ limitations under the License.
namespace tflite {
namespace xnnpack {
TEST(MaxPool2D, UnitPoolSamePadding) {
std::unique_ptr<TfLiteDelegate, decltype(&TfLiteXNNPackDelegateDelete)>
xnnpack_delegate(TfLiteXNNPackDelegateCreate(nullptr),
TfLiteXNNPackDelegateDelete);
std::random_device random_device;
auto rng = std::mt19937(random_device());
auto batch_rng =
std::bind(std::uniform_int_distribution<int32_t>(2, 4), std::ref(rng));
auto input_rng =
std::bind(std::uniform_int_distribution<int32_t>(10, 25), std::ref(rng));
auto channel_rng =
std::bind(std::uniform_int_distribution<int32_t>(5, 16), std::ref(rng));
Pool2DTester()
.BatchSize(batch_rng())
.InputHeight(input_rng())
.InputWidth(input_rng())
.Channels(channel_rng())
.PoolingHeight(1)
.PoolingWidth(1)
.StrideHeight(1)
.StrideWidth(1)
.SamePadding()
.Test(BuiltinOperator_MAX_POOL_2D, xnnpack_delegate.get());
}
TEST(MaxPool2D, UnitPoolValidPadding) {
std::unique_ptr<TfLiteDelegate, decltype(&TfLiteXNNPackDelegateDelete)>
xnnpack_delegate(TfLiteXNNPackDelegateCreate(nullptr),
TfLiteXNNPackDelegateDelete);
std::random_device random_device;
auto rng = std::mt19937(random_device());
auto batch_rng =
std::bind(std::uniform_int_distribution<int32_t>(2, 4), std::ref(rng));
auto input_rng =
std::bind(std::uniform_int_distribution<int32_t>(10, 25), std::ref(rng));
auto channel_rng =
std::bind(std::uniform_int_distribution<int32_t>(5, 16), std::ref(rng));
Pool2DTester()
.BatchSize(batch_rng())
.InputHeight(input_rng())
.InputWidth(input_rng())
.Channels(channel_rng())
.PoolingHeight(1)
.PoolingWidth(1)
.StrideHeight(1)
.StrideWidth(1)
.ValidPadding()
.Test(BuiltinOperator_MAX_POOL_2D, xnnpack_delegate.get());
}
TEST(MaxPool2D, EqualPoolAndStrideWithSamePadding) {
std::unique_ptr<TfLiteDelegate, decltype(&TfLiteXNNPackDelegateDelete)>
xnnpack_delegate(TfLiteXNNPackDelegateCreate(nullptr),

View File

@ -570,8 +570,13 @@ class Subgraph {
params->filter_height, node_index);
return kTfLiteError;
}
if (params->filter_width == 1 && params->filter_height == 1) {
TF_LITE_MAYBE_KERNEL_LOG(context, "meaningless 1x1 pooling in node #%d",
if (params->filter_width == 1 && params->filter_height == 1 &&
std::max(params->stride_width, params->stride_height) > 1) {
TF_LITE_MAYBE_KERNEL_LOG(context,
"unsupported pooling with 1x1 filter "
"and %dx%d stride in node #%d",
params->stride_width, params->stride_height,
node_index);
return kTfLiteError;
}
@ -1105,19 +1110,27 @@ class Subgraph {
&output_max));
if (subgraph != nullptr) {
const xnn_status status = xnn_define_average_pooling_2d(
subgraph,
/*input_padding_top=*/0,
/*input_padding_right=*/0,
/*input_padding_bottom=*/0,
/*input_padding_left=*/0,
static_cast<uint32_t>(pool_params->filter_height),
static_cast<uint32_t>(pool_params->filter_width),
static_cast<uint32_t>(pool_params->stride_height),
static_cast<uint32_t>(pool_params->stride_width), output_min,
output_max,
/*input_id=*/xnnpack_tensors[node->inputs->data[0]],
/*output_id=*/xnnpack_tensors[node->outputs->data[0]], flags);
xnn_status status = xnn_status_success;
if (pool_params->filter_height == 1 && pool_params->filter_width == 1) {
status = xnn_define_clamp(
subgraph, output_min, output_max,
/*input_id=*/xnnpack_tensors[node->inputs->data[0]],
/*output_id=*/xnnpack_tensors[node->outputs->data[0]], /*flags=*/0);
} else {
status = xnn_define_average_pooling_2d(
subgraph,
/*input_padding_top=*/0,
/*input_padding_right=*/0,
/*input_padding_bottom=*/0,
/*input_padding_left=*/0,
static_cast<uint32_t>(pool_params->filter_height),
static_cast<uint32_t>(pool_params->filter_width),
static_cast<uint32_t>(pool_params->stride_height),
static_cast<uint32_t>(pool_params->stride_width), output_min,
output_max,
/*input_id=*/xnnpack_tensors[node->inputs->data[0]],
/*output_id=*/xnnpack_tensors[node->outputs->data[0]], flags);
}
if (status != xnn_status_success) {
TF_LITE_KERNEL_LOG(logging_context,
"failed to delegate AVERAGE_POOL_2D node #%d",
@ -1710,20 +1723,27 @@ class Subgraph {
&output_max));
if (subgraph != nullptr) {
const xnn_status status = xnn_define_max_pooling_2d(
subgraph,
/*input_padding_top=*/0,
/*input_padding_right=*/0,
/*input_padding_bottom=*/0,
/*input_padding_left=*/0,
static_cast<uint32_t>(pool_params->filter_height),
static_cast<uint32_t>(pool_params->filter_width),
static_cast<uint32_t>(pool_params->stride_height),
static_cast<uint32_t>(pool_params->stride_width),
/*dilation_height=*/1,
/*dilation_width=*/1, output_min, output_max,
/*input_id=*/xnnpack_tensors[node->inputs->data[0]],
/*output_id=*/xnnpack_tensors[node->outputs->data[0]], flags);
xnn_status status = xnn_status_success;
if (pool_params->filter_height == 1 && pool_params->filter_width == 1) {
status = xnn_define_clamp(
subgraph, output_min, output_max,
/*input_id=*/xnnpack_tensors[node->inputs->data[0]],
/*output_id=*/xnnpack_tensors[node->outputs->data[0]], /*flags=*/0);
} else {
status = xnn_define_max_pooling_2d(
subgraph,
/*input_padding_top=*/0,
/*input_padding_right=*/0,
/*input_padding_bottom=*/0,
/*input_padding_left=*/0,
static_cast<uint32_t>(pool_params->filter_height),
static_cast<uint32_t>(pool_params->filter_width),
static_cast<uint32_t>(pool_params->stride_height),
static_cast<uint32_t>(pool_params->stride_width),
/*dilation_height=*/1, /*dilation_width=*/1, output_min, output_max,
/*input_id=*/xnnpack_tensors[node->inputs->data[0]],
/*output_id=*/xnnpack_tensors[node->outputs->data[0]], flags);
}
if (status != xnn_status_success) {
TF_LITE_KERNEL_LOG(logging_context,
"failed to delegate MAX_POOL_2D node #%d",