1 // Copyright 2020 Google LLC
2 //
3 // This source code is licensed under the BSD-style license found in the
4 // LICENSE file in the root directory of this source tree.
5
6 #include <math.h>
7 #include <stddef.h>
8 #include <stdint.h>
9
10 #include <xnnpack.h>
11 #include <xnnpack/log.h>
12 #include <xnnpack/params.h>
13 #include <xnnpack/subgraph.h>
14
15
xnn_define_max_pooling_2d(xnn_subgraph_t subgraph,uint32_t input_padding_top,uint32_t input_padding_right,uint32_t input_padding_bottom,uint32_t input_padding_left,uint32_t pooling_height,uint32_t pooling_width,uint32_t stride_height,uint32_t stride_width,uint32_t dilation_height,uint32_t dilation_width,float output_min,float output_max,uint32_t input_id,uint32_t output_id,uint32_t flags)16 enum xnn_status xnn_define_max_pooling_2d(
17 xnn_subgraph_t subgraph,
18 uint32_t input_padding_top,
19 uint32_t input_padding_right,
20 uint32_t input_padding_bottom,
21 uint32_t input_padding_left,
22 uint32_t pooling_height,
23 uint32_t pooling_width,
24 uint32_t stride_height,
25 uint32_t stride_width,
26 uint32_t dilation_height,
27 uint32_t dilation_width,
28 float output_min,
29 float output_max,
30 uint32_t input_id,
31 uint32_t output_id,
32 uint32_t flags)
33 {
34 if ((xnn_params.init_flags & XNN_INIT_FLAG_XNNPACK) == 0) {
35 xnn_log_error("failed to define %s operator: XNNPACK is not initialized",
36 xnn_node_type_to_string(xnn_node_type_max_pooling_2d));
37 return xnn_status_uninitialized;
38 }
39
40 const uint32_t pooling_size = pooling_height * pooling_width;
41 if (pooling_size == 0) {
42 xnn_log_error(
43 "failed to define %s operator with %" PRIu32 "x%" PRIu32 " pooling size: "
44 "pooling size dimensions must be non-zero",
45 xnn_node_type_to_string(xnn_node_type_max_pooling_2d), pooling_width, pooling_height);
46 return xnn_status_invalid_parameter;
47 }
48
49 if (pooling_size == 1) {
50 xnn_log_error(
51 "failed to define %s operator with 1 pooling element: 1x1 pooling is meaningless",
52 xnn_node_type_to_string(xnn_node_type_max_pooling_2d));
53 return xnn_status_invalid_parameter;
54 }
55
56 if (stride_height == 0 || stride_width == 0) {
57 xnn_log_error(
58 "failed to define %s operator with %" PRIu32 "x%" PRIu32 " stride: stride dimensions must be non-zero",
59 xnn_node_type_to_string(xnn_node_type_max_pooling_2d), stride_width, stride_height);
60 return xnn_status_invalid_parameter;
61 }
62
63 if (dilation_height == 0 || dilation_width == 0) {
64 xnn_log_error(
65 "failed to define %s operator with %" PRIu32 "x%" PRIu32 " dilation: dilation dimensions must be non-zero",
66 xnn_node_type_to_string(xnn_node_type_max_pooling_2d), dilation_width, dilation_height);
67 return xnn_status_invalid_parameter;
68 }
69
70 if (isnan(output_min)) {
71 xnn_log_error(
72 "failed to define %s with NaN output lower bound: lower bound must be non-NaN",
73 xnn_node_type_to_string(xnn_node_type_max_pooling_2d));
74 return xnn_status_invalid_parameter;
75 }
76
77 if (isnan(output_max)) {
78 xnn_log_error(
79 "failed to define %s with NaN output upper bound: upper bound must be non-NaN",
80 xnn_node_type_to_string(xnn_node_type_max_pooling_2d));
81 return xnn_status_invalid_parameter;
82 }
83
84 if (output_min >= output_max) {
85 xnn_log_error(
86 "failed to define %s with [%.7g, %.7g] output range: lower bound must be below upper bound",
87 xnn_node_type_to_string(xnn_node_type_max_pooling_2d), output_min, output_max);
88 return xnn_status_invalid_parameter;
89 }
90
91 const bool any_padding = (input_padding_left | input_padding_top | input_padding_right | input_padding_bottom) != 0;
92 if ((flags & XNN_FLAG_TENSORFLOW_SAME_PADDING) != 0) {
93 if (any_padding) {
94 xnn_log_error(
95 "failed to define %s operator with %" PRIu32 "+%" PRIu32 "x%" PRIu32 "+%" PRIu32" padding: "
96 "TensorFlow SAME padding can't be combined with explicit padding specification",
97 xnn_node_type_to_string(xnn_node_type_max_pooling_2d),
98 input_padding_top, input_padding_left, input_padding_bottom, input_padding_right);
99 return xnn_status_invalid_parameter;
100 }
101 }
102
103 if (input_id >= subgraph->num_values) {
104 xnn_log_error(
105 "failed to define %s operator with input ID #%" PRIu32 ": invalid Value ID",
106 xnn_node_type_to_string(xnn_node_type_max_pooling_2d), input_id);
107 return xnn_status_invalid_parameter;
108 }
109
110 if (output_id >= subgraph->num_values) {
111 xnn_log_error(
112 "failed to define %s operator with output ID #%" PRIu32 ": invalid Value ID",
113 xnn_node_type_to_string(xnn_node_type_max_pooling_2d), output_id);
114 return xnn_status_invalid_parameter;
115 }
116
117 struct xnn_node* node = xnn_subgraph_new_node(subgraph);
118 if (node == NULL) {
119 return xnn_status_out_of_memory;
120 }
121
122 node->type = xnn_node_type_max_pooling_2d;
123 node->params.pooling_2d.padding_top = input_padding_top;
124 node->params.pooling_2d.padding_right = input_padding_right;
125 node->params.pooling_2d.padding_bottom = input_padding_bottom;
126 node->params.pooling_2d.padding_left = input_padding_left;
127 node->params.pooling_2d.pooling_height = pooling_height;
128 node->params.pooling_2d.pooling_width = pooling_width;
129 node->params.pooling_2d.stride_height = stride_height;
130 node->params.pooling_2d.stride_width = stride_width;
131 node->params.pooling_2d.dilation_height = dilation_height;
132 node->params.pooling_2d.dilation_width = dilation_width;
133 node->activation.output_min = output_min;
134 node->activation.output_max = output_max;
135 node->num_inputs = 1;
136 node->inputs[0] = input_id;
137 node->num_outputs = 1;
138 node->outputs[0] = output_id;
139 node->flags = flags;
140
141 return xnn_status_success;
142 }
143