Support 1x1 Max/Average Pooling with 1x1 stride in XNNPACK delegate
PiperOrigin-RevId: 320703905 Change-Id: Id9787ba836b7d50f34dcad82033553d0e70b1ac9
This commit is contained in:
parent
d0ae0f8c70
commit
98db6af79d
@ -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.
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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),
|
||||
|
@ -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",
|
||||
|
Loading…
Reference in New Issue
Block a user