• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_depthwise_convolution_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 kernel_height,uint32_t kernel_width,uint32_t subsampling_height,uint32_t subsampling_width,uint32_t dilation_height,uint32_t dilation_width,uint32_t depth_multiplier,size_t input_channels,float output_min,float output_max,uint32_t input_id,uint32_t filter_id,uint32_t bias_id,uint32_t output_id,uint32_t flags)16 enum xnn_status xnn_define_depthwise_convolution_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 kernel_height,
23   uint32_t kernel_width,
24   uint32_t subsampling_height,
25   uint32_t subsampling_width,
26   uint32_t dilation_height,
27   uint32_t dilation_width,
28   uint32_t depth_multiplier,
29   size_t input_channels,
30   float output_min,
31   float output_max,
32   uint32_t input_id,
33   uint32_t filter_id,
34   uint32_t bias_id,
35   uint32_t output_id,
36   uint32_t flags)
37 {
38   if ((xnn_params.init_flags & XNN_INIT_FLAG_XNNPACK) == 0) {
39     xnn_log_error("failed to define %s operator: XNNPACK is not initialized",
40       xnn_node_type_to_string(xnn_node_type_depthwise_convolution_2d));
41     return xnn_status_uninitialized;
42   }
43 
44   if (kernel_width == 0 || kernel_height == 0) {
45     xnn_log_error(
46       "failed to define %s operator with %" PRIu32 "x%" PRIu32 " kernel: kernel dimensions must be non-zero",
47       xnn_node_type_to_string(xnn_node_type_depthwise_convolution_2d), kernel_width, kernel_height);
48     return xnn_status_invalid_parameter;
49   }
50 
51   if (subsampling_width == 0 || subsampling_height == 0) {
52     xnn_log_error(
53       "failed to define %s operator with %" PRIu32 "x%" PRIu32 " subsampling: subsampling dimensions must be non-zero",
54       xnn_node_type_to_string(xnn_node_type_depthwise_convolution_2d), subsampling_width, subsampling_height);
55     return xnn_status_invalid_parameter;
56   }
57 
58   if (dilation_width == 0 || dilation_height == 0) {
59     xnn_log_error(
60       "failed to define %s operator with %" PRIu32 "x%" PRIu32 " dilation: dilation dimensions must be non-zero",
61       xnn_node_type_to_string(xnn_node_type_depthwise_convolution_2d), dilation_width, dilation_height);
62     return xnn_status_invalid_parameter;
63   }
64 
65   if (depth_multiplier == 0) {
66     xnn_log_error(
67       "failed to define %s operator with %" PRIu32 " depth multiplier: depth multiplier must be non-zero",
68       xnn_node_type_to_string(xnn_node_type_depthwise_convolution_2d), depth_multiplier);
69     return xnn_status_invalid_parameter;
70   }
71 
72   if (input_channels == 0) {
73     xnn_log_error(
74       "failed to define %s operator with %zu input channels: number of channels must be non-zero",
75       xnn_node_type_to_string(xnn_node_type_depthwise_convolution_2d), input_channels);
76     return xnn_status_invalid_parameter;
77   }
78 
79   if (isnan(output_min)) {
80     xnn_log_error(
81       "failed to define %s operator with NaN output lower bound: lower bound must be non-NaN",
82       xnn_node_type_to_string(xnn_node_type_depthwise_convolution_2d));
83     return xnn_status_invalid_parameter;
84   }
85 
86   if (isnan(output_max)) {
87     xnn_log_error(
88       "failed to define %s operator with NaN output upper bound: upper bound must be non-NaN",
89       xnn_node_type_to_string(xnn_node_type_depthwise_convolution_2d));
90     return xnn_status_invalid_parameter;
91   }
92 
93   if (output_min >= output_max) {
94     xnn_log_error(
95       "failed to define %s operator with [%.7g, %.7g] output range: lower bound must be below upper bound",
96       xnn_node_type_to_string(xnn_node_type_depthwise_convolution_2d), output_min, output_max);
97     return xnn_status_invalid_parameter;
98   }
99 
100   const uint32_t supported_flags = XNN_FLAG_TENSORFLOW_SAME_PADDING;
101   const uint32_t invalid_flags = flags & ~supported_flags;
102   if (invalid_flags != 0) {
103     xnn_log_error(
104       "failed to define %s operator with 0x%08" PRIx32 " flags: invalid flags 0x%08" PRIx32,
105       xnn_node_type_to_string(xnn_node_type_depthwise_convolution_2d), flags, invalid_flags);
106     return xnn_status_invalid_parameter;
107   }
108 
109   const bool any_padding = (input_padding_left | input_padding_top | input_padding_right | input_padding_bottom) != 0;
110   if ((flags & XNN_FLAG_TENSORFLOW_SAME_PADDING) != 0 && any_padding) {
111     xnn_log_error(
112       "failed to define %s operator with %" PRIu32 "+%" PRIu32 "x%" PRIu32 "+%" PRIu32" padding: "
113       "TensorFlow SAME padding can't be combined with explicit padding specification",
114       xnn_node_type_to_string(xnn_node_type_convolution_2d),
115       input_padding_top, input_padding_left, input_padding_bottom, input_padding_right);
116     return xnn_status_invalid_parameter;
117   }
118 
119   // Convert TensorFlow SAME padding to explicit padding specification whenever possible
120   if ((flags & XNN_FLAG_TENSORFLOW_SAME_PADDING) != 0 && (subsampling_height | subsampling_width) == 1) {
121     flags &= ~XNN_FLAG_TENSORFLOW_SAME_PADDING;
122     const uint32_t padding_height = (kernel_height - 1) * dilation_height;
123     const uint32_t padding_width = (kernel_width - 1) * dilation_width;
124     input_padding_left = padding_width / 2;
125     input_padding_top = padding_height / 2;
126     input_padding_right = padding_width - input_padding_left;
127     input_padding_bottom = padding_height - input_padding_top;
128   }
129 
130   if (input_id >= subgraph->num_values) {
131     xnn_log_error(
132       "failed to define %s operator with input ID #%" PRIu32 ": invalid Value ID",
133       xnn_node_type_to_string(xnn_node_type_depthwise_convolution_2d), input_id);
134     return xnn_status_invalid_parameter;
135   }
136 
137   if (filter_id >= subgraph->num_values) {
138     xnn_log_error(
139       "failed to define %s operator with filter ID #%" PRIu32 ": invalid Value ID",
140       xnn_node_type_to_string(xnn_node_type_depthwise_convolution_2d), filter_id);
141     return xnn_status_invalid_parameter;
142   }
143 
144   if (bias_id >= subgraph->num_values) {
145     xnn_log_error(
146       "failed to define %s operator with bias ID #%" PRIu32 ": invalid Value ID",
147       xnn_node_type_to_string(xnn_node_type_depthwise_convolution_2d), bias_id);
148     return xnn_status_invalid_parameter;
149   }
150 
151   if (output_id >= subgraph->num_values) {
152     xnn_log_error(
153       "failed to define %s operator with output ID #%" PRIu32 ": invalid Value ID",
154       xnn_node_type_to_string(xnn_node_type_depthwise_convolution_2d), output_id);
155     return xnn_status_invalid_parameter;
156   }
157 
158   struct xnn_node* node = xnn_subgraph_new_node(subgraph);
159   if (node == NULL) {
160     return xnn_status_out_of_memory;
161   }
162 
163   node->type = xnn_node_type_depthwise_convolution_2d;
164   node->params.depthwise_convolution_2d.input_padding_top = input_padding_top;
165   node->params.depthwise_convolution_2d.input_padding_right = input_padding_right;
166   node->params.depthwise_convolution_2d.input_padding_bottom = input_padding_bottom;
167   node->params.depthwise_convolution_2d.input_padding_left = input_padding_left;
168   node->params.depthwise_convolution_2d.kernel_height = kernel_height;
169   node->params.depthwise_convolution_2d.kernel_width = kernel_width;
170   node->params.depthwise_convolution_2d.subsampling_height = subsampling_height;
171   node->params.depthwise_convolution_2d.subsampling_width = subsampling_width;
172   node->params.depthwise_convolution_2d.dilation_height = dilation_height;
173   node->params.depthwise_convolution_2d.dilation_width = dilation_width;
174   node->params.depthwise_convolution_2d.depth_multiplier = depth_multiplier;
175   node->params.depthwise_convolution_2d.input_channels = input_channels;
176   node->activation.output_min = output_min;
177   node->activation.output_max = output_max;
178   node->num_inputs = 3;
179   node->inputs[0] = input_id;
180   node->inputs[1] = filter_id;
181   node->inputs[2] = bias_id;
182   node->num_outputs = 1;
183   node->outputs[0] = output_id;
184   node->flags = flags;
185 
186   return xnn_status_success;
187 };
188