1 // Copyright (c) Facebook, Inc. and its affiliates.
2 // All rights reserved.
3 //
4 // Copyright 2019 Google LLC
5 //
6 // This source code is licensed under the BSD-style license found in the
7 // LICENSE file in the root directory of this source tree.
8
9 #include <assert.h>
10 #include <math.h>
11 #include <stddef.h>
12 #include <stdint.h>
13 #include <stdlib.h>
14
15 #include <fp16.h>
16
17 #include <xnnpack.h>
18 #include <xnnpack/allocator.h>
19 #include <xnnpack/log.h>
20 #include <xnnpack/operator.h>
21 #include <xnnpack/microparams-init.h>
22 #include <xnnpack/params.h>
23
24
create_global_average_pooling_nwc(size_t channels,size_t input_stride,size_t output_stride,uint32_t flags,uint32_t log2_element_size,size_t params_offset,const void * params,size_t params_size,uint32_t datatype_init_flags,enum xnn_operator_type operator_type,xnn_operator_t * global_average_pooling_op_out)25 static enum xnn_status create_global_average_pooling_nwc(
26 size_t channels,
27 size_t input_stride,
28 size_t output_stride,
29 uint32_t flags,
30 uint32_t log2_element_size,
31 size_t params_offset,
32 const void* params,
33 size_t params_size,
34 uint32_t datatype_init_flags,
35 enum xnn_operator_type operator_type,
36 xnn_operator_t* global_average_pooling_op_out)
37 {
38 xnn_operator_t global_average_pooling_op = NULL;
39 enum xnn_status status = xnn_status_uninitialized;
40
41 if ((xnn_params.init_flags & XNN_INIT_FLAG_XNNPACK) == 0) {
42 xnn_log_error("failed to create %s operator: XNNPACK is not initialized",
43 xnn_operator_type_to_string(operator_type));
44 goto error;
45 }
46
47 status = xnn_status_unsupported_hardware;
48
49 if ((xnn_params.init_flags & datatype_init_flags) == 0) {
50 xnn_log_error("failed to create %s operator: operations on data type are not supported",
51 xnn_operator_type_to_string(operator_type));
52 goto error;
53 }
54
55 status = xnn_status_invalid_parameter;
56
57 if (channels == 0) {
58 xnn_log_error(
59 "failed to create %s operator with %zu channels: number of channels must be non-zero",
60 xnn_operator_type_to_string(operator_type), channels);
61 goto error;
62 }
63
64 if (input_stride < channels) {
65 xnn_log_error(
66 "failed to create %s operator with input element stride of %zu: "
67 "stride must be at least as large as the number of channels (%zu)",
68 xnn_operator_type_to_string(operator_type), input_stride, channels);
69 goto error;
70 }
71
72 if (output_stride < channels) {
73 xnn_log_error(
74 "failed to create %s operator with output element stride of %zu: "
75 "stride must be at least as large as the number of channels (%zu)",
76 xnn_operator_type_to_string(operator_type), output_stride, channels);
77 goto error;
78 }
79
80 status = xnn_status_out_of_memory;
81
82 global_average_pooling_op = xnn_allocate_zero_simd_memory(sizeof(struct xnn_operator));
83 if (global_average_pooling_op == NULL) {
84 xnn_log_error(
85 "failed to allocate %zu bytes for %s operator descriptor",
86 sizeof(struct xnn_operator), xnn_operator_type_to_string(operator_type));
87 goto error;
88 }
89
90 const size_t zero_size = (channels << log2_element_size) + XNN_EXTRA_BYTES;
91 void* zero_buffer = xnn_allocate_zero_simd_memory(zero_size);
92 if (zero_buffer == NULL) {
93 xnn_log_error(
94 "failed to allocate %zu bytes for %s operator zero padding",
95 zero_size, xnn_operator_type_to_string(operator_type));
96 goto error;
97 }
98 global_average_pooling_op->zero_buffer = zero_buffer;
99
100 global_average_pooling_op->channels = channels;
101 global_average_pooling_op->input_pixel_stride = input_stride;
102 global_average_pooling_op->output_pixel_stride = output_stride;
103 memcpy((void*) ((uintptr_t) global_average_pooling_op + params_offset), params, params_size);
104
105 global_average_pooling_op->type = operator_type;
106 global_average_pooling_op->flags = flags;
107
108 global_average_pooling_op->state = xnn_run_state_invalid;
109
110 *global_average_pooling_op_out = global_average_pooling_op;
111 return xnn_status_success;
112
113 error:
114 xnn_delete_operator(global_average_pooling_op);
115 return status;
116 }
117
setup_global_average_pooling_nwc(xnn_operator_t global_average_pooling_op,size_t batch_size,size_t width,const void * input,void * output,size_t log2_element_size,const struct gavgpool_parameters gavgpool[restrict XNN_MIN_ELEMENTS (1)],uint32_t datatype_init_flags,enum xnn_operator_type expected_operator_type,const void * params,size_t params_size,void (* update_params)(xnn_operator_t,size_t),pthreadpool_t threadpool)118 static enum xnn_status setup_global_average_pooling_nwc(
119 xnn_operator_t global_average_pooling_op,
120 size_t batch_size,
121 size_t width,
122 const void* input,
123 void* output,
124 size_t log2_element_size,
125 const struct gavgpool_parameters gavgpool[restrict XNN_MIN_ELEMENTS(1)],
126 uint32_t datatype_init_flags,
127 enum xnn_operator_type expected_operator_type,
128 const void* params,
129 size_t params_size,
130 void (*update_params)(xnn_operator_t, size_t),
131 pthreadpool_t threadpool)
132 {
133 if (global_average_pooling_op->type != expected_operator_type) {
134 xnn_log_error("failed to setup operator: operator type mismatch (expected %s, got %s)",
135 xnn_operator_type_to_string(expected_operator_type),
136 xnn_operator_type_to_string(global_average_pooling_op->type));
137 return xnn_status_invalid_parameter;
138 }
139 global_average_pooling_op->state = xnn_run_state_invalid;
140
141 if ((xnn_params.init_flags & XNN_INIT_FLAG_XNNPACK) == 0) {
142 xnn_log_error("failed to setup %s operator: XNNPACK is not initialized",
143 xnn_operator_type_to_string(global_average_pooling_op->type));
144 return xnn_status_uninitialized;
145 }
146
147 if ((xnn_params.init_flags & datatype_init_flags) == 0) {
148 xnn_log_error("failed to setup %s operator: operations on data type are not supported",
149 xnn_operator_type_to_string(global_average_pooling_op->type));
150 return xnn_status_unsupported_hardware;
151 }
152
153 if (width == 0) {
154 xnn_log_error("failed to setup %s operator with width %zu: width must be non-zero",
155 xnn_operator_type_to_string(global_average_pooling_op->type), width);
156 return xnn_status_invalid_parameter;
157 }
158
159 if (batch_size == 0) {
160 global_average_pooling_op->state = xnn_run_state_skip;
161 return xnn_status_success;
162 }
163
164 global_average_pooling_op->batch_size = batch_size;
165 global_average_pooling_op->input_width = width;
166 global_average_pooling_op->input = input;
167 global_average_pooling_op->output = output;
168
169 update_params(global_average_pooling_op, width);
170
171 assert(gavgpool->row_tile != 0);
172
173 const size_t input_stride_in_bytes = global_average_pooling_op->input_pixel_stride << log2_element_size;
174 const size_t channels = global_average_pooling_op->channels;
175 global_average_pooling_op->context.global_average_pooling_nwc = (struct global_average_pooling_nwc_context) {
176 .input = input,
177 .zero = global_average_pooling_op->zero_buffer,
178 .input_pixel_stride = input_stride_in_bytes,
179 .input_batch_stride = input_stride_in_bytes * width,
180 .input_elements = width,
181 .channels = channels,
182 .output = output,
183 .output_batch_stride = (global_average_pooling_op->output_pixel_stride << log2_element_size),
184 };
185 memcpy(&global_average_pooling_op->context.global_average_pooling_nwc.params, params, params_size);
186 global_average_pooling_op->compute.type = xnn_parallelization_type_1d;
187 global_average_pooling_op->compute.range[0] = batch_size;
188
189 if (width <= gavgpool->row_tile) {
190 global_average_pooling_op->compute.task_1d = (pthreadpool_task_1d_t) xnn_compute_global_average_pooling_nwc_unipass;
191 global_average_pooling_op->context.global_average_pooling_nwc.unipass_ukernel = gavgpool->unipass;
192 } else {
193 global_average_pooling_op->compute.task_1d = (pthreadpool_task_1d_t) xnn_compute_global_average_pooling_nwc_multipass;
194 global_average_pooling_op->context.global_average_pooling_nwc.multipass_ukernel = gavgpool->multipass;
195 }
196 global_average_pooling_op->state = xnn_run_state_ready;
197
198 return xnn_status_success;
199 }
200
xnn_create_global_average_pooling_nwc_qu8(size_t channels,size_t input_stride,size_t output_stride,uint8_t input_zero_point,float input_scale,uint8_t output_zero_point,float output_scale,uint8_t output_min,uint8_t output_max,uint32_t flags,xnn_operator_t * global_average_pooling_op_out)201 enum xnn_status xnn_create_global_average_pooling_nwc_qu8(
202 size_t channels,
203 size_t input_stride,
204 size_t output_stride,
205 uint8_t input_zero_point,
206 float input_scale,
207 uint8_t output_zero_point,
208 float output_scale,
209 uint8_t output_min,
210 uint8_t output_max,
211 uint32_t flags,
212 xnn_operator_t* global_average_pooling_op_out)
213 {
214 if (input_scale <= 0.0f || !isnormal(input_scale)) {
215 xnn_log_error(
216 "failed to create %s operator with %.7g input scale: scale must be finite, normalized, and positive",
217 xnn_operator_type_to_string(xnn_operator_type_global_average_pooling_nwc_qu8), input_scale);
218 return xnn_status_invalid_parameter;
219 }
220
221 if (output_scale <= 0.0f || !isnormal(output_scale)) {
222 xnn_log_error(
223 "failed to create %s operator with %.7g output scale: scale must be finite, normalized, and positive",
224 xnn_operator_type_to_string(xnn_operator_type_global_average_pooling_nwc_qu8), output_scale);
225 return xnn_status_invalid_parameter;
226 }
227
228 if (output_min >= output_max) {
229 xnn_log_error(
230 "failed to create %s operator with [%" PRIu8 ", %" PRIu8 "] output range: range min must be below range max",
231 xnn_operator_type_to_string(xnn_operator_type_global_average_pooling_nwc_qu8), output_min, output_max);
232 return xnn_status_invalid_parameter;
233 }
234
235 const float input_output_scale = input_scale / output_scale;
236 if (input_output_scale < 0x1.0p-8f || input_output_scale >= 0x1.0p+8f) {
237 xnn_log_error(
238 "failed to create %s operator with %.7g input-to-output scale ratio: scale ratio must be in [2**-8, 2**8) range",
239 xnn_operator_type_to_string(xnn_operator_type_global_average_pooling_nwc_qu8), input_output_scale);
240 return xnn_status_unsupported_parameter;
241 }
242
243 union xnn_qu8_avgpool_minmax_params params;
244 if (xnn_params.qu8.gavgpool.init.qu8 != NULL) {
245 xnn_params.qu8.gavgpool.init.qu8(¶ms,
246 0 /* bias */, 1.0f /* scale */, output_zero_point, output_min, output_max);
247 }
248 const enum xnn_status status = create_global_average_pooling_nwc(
249 channels, input_stride, output_stride, flags,
250 0 /* log2(sizeof(uint8_t)) */,
251 offsetof(struct xnn_operator, params.qu8_gavgpool),
252 ¶ms, sizeof(params),
253 XNN_INIT_FLAG_QU8,
254 xnn_operator_type_global_average_pooling_nwc_qu8,
255 global_average_pooling_op_out);
256 if (status == xnn_status_success) {
257 xnn_operator_t global_average_pooling_op = *global_average_pooling_op_out;
258 global_average_pooling_op->input_zero_point = (int32_t) (uint32_t) input_zero_point;
259 global_average_pooling_op->input_scale = input_scale;
260 global_average_pooling_op->output_scale = output_scale;
261 }
262 return status;
263 }
264
xnn_create_global_average_pooling_nwc_qs8(size_t channels,size_t input_stride,size_t output_stride,int8_t input_zero_point,float input_scale,int8_t output_zero_point,float output_scale,int8_t output_min,int8_t output_max,uint32_t flags,xnn_operator_t * global_average_pooling_op_out)265 enum xnn_status xnn_create_global_average_pooling_nwc_qs8(
266 size_t channels,
267 size_t input_stride,
268 size_t output_stride,
269 int8_t input_zero_point,
270 float input_scale,
271 int8_t output_zero_point,
272 float output_scale,
273 int8_t output_min,
274 int8_t output_max,
275 uint32_t flags,
276 xnn_operator_t* global_average_pooling_op_out)
277 {
278 if (input_scale <= 0.0f || !isnormal(input_scale)) {
279 xnn_log_error(
280 "failed to create %s operator with %.7g input scale: scale must be finite, normalized, and positive",
281 xnn_operator_type_to_string(xnn_operator_type_global_average_pooling_nwc_qs8), input_scale);
282 return xnn_status_invalid_parameter;
283 }
284
285 if (output_scale <= 0.0f || !isnormal(output_scale)) {
286 xnn_log_error(
287 "failed to create %s operator with %.7g output scale: scale must be finite, normalized, and positive",
288 xnn_operator_type_to_string(xnn_operator_type_global_average_pooling_nwc_qs8), output_scale);
289 return xnn_status_invalid_parameter;
290 }
291
292 if (output_min >= output_max) {
293 xnn_log_error(
294 "failed to create %s operator with [%" PRId8 ", %" PRId8 "] output range: range min must be below range max",
295 xnn_operator_type_to_string(xnn_operator_type_global_average_pooling_nwc_qs8), output_min, output_max);
296 return xnn_status_invalid_parameter;
297 }
298
299 const float input_output_scale = input_scale / output_scale;
300 if (input_output_scale < 0x1.0p-8f || input_output_scale >= 0x1.0p+8f) {
301 xnn_log_error(
302 "failed to create %s operator with %.7g input-to-output scale ratio: scale ratio must be in [2**-8, 2**8) range",
303 xnn_operator_type_to_string(xnn_operator_type_global_average_pooling_nwc_qs8), input_output_scale);
304 return xnn_status_unsupported_parameter;
305 }
306
307 union xnn_qs8_avgpool_minmax_params params;
308 if (xnn_params.qs8.gavgpool.init.qs8 != NULL) {
309 xnn_params.qs8.gavgpool.init.qs8(¶ms,
310 0 /* bias */, 1.0f /* scale */, output_zero_point, output_min, output_max);
311 }
312 const enum xnn_status status = create_global_average_pooling_nwc(
313 channels, input_stride, output_stride, flags,
314 0 /* log2(sizeof(int8_t)) */,
315 offsetof(struct xnn_operator, params.qs8_gavgpool),
316 ¶ms, sizeof(params),
317 XNN_INIT_FLAG_QS8,
318 xnn_operator_type_global_average_pooling_nwc_qs8,
319 global_average_pooling_op_out);
320 if (status == xnn_status_success) {
321 xnn_operator_t global_average_pooling_op = *global_average_pooling_op_out;
322 global_average_pooling_op->input_zero_point = (int32_t) input_zero_point;
323 global_average_pooling_op->input_scale = input_scale;
324 global_average_pooling_op->output_scale = output_scale;
325 }
326 return status;
327 }
328
xnn_create_global_average_pooling_nwc_f16(size_t channels,size_t input_stride,size_t output_stride,float output_min,float output_max,uint32_t flags,xnn_operator_t * global_average_pooling_op_out)329 enum xnn_status xnn_create_global_average_pooling_nwc_f16(
330 size_t channels,
331 size_t input_stride,
332 size_t output_stride,
333 float output_min,
334 float output_max,
335 uint32_t flags,
336 xnn_operator_t* global_average_pooling_op_out)
337 {
338 if (isnan(output_min)) {
339 xnn_log_error(
340 "failed to create %s operator with NaN output lower bound: lower bound must be non-NaN",
341 xnn_operator_type_to_string(xnn_operator_type_global_average_pooling_nwc_f16));
342 return xnn_status_invalid_parameter;
343 }
344
345 if (isnan(output_max)) {
346 xnn_log_error(
347 "failed to create %s operator with NaN output upper bound: upper bound must be non-NaN",
348 xnn_operator_type_to_string(xnn_operator_type_global_average_pooling_nwc_f16));
349 return xnn_status_invalid_parameter;
350 }
351
352 if (fp16_ieee_to_fp32_value(fp16_ieee_from_fp32_value(output_min)) >= fp16_ieee_to_fp32_value(fp16_ieee_from_fp32_value(output_max))) {
353 xnn_log_error(
354 "failed to create %s operator with [%.7g, %.7g] output range: lower bound must be below upper bound",
355 xnn_operator_type_to_string(xnn_operator_type_global_average_pooling_nwc_f16),
356 fp16_ieee_to_fp32_value(fp16_ieee_from_fp32_value(output_min)),
357 fp16_ieee_to_fp32_value(fp16_ieee_from_fp32_value(output_max)));
358 return xnn_status_invalid_parameter;
359 }
360
361 union xnn_f16_scaleminmax_params params;
362 if (xnn_params.f16.gavgpool.init.f16 != NULL) {
363 xnn_params.f16.gavgpool.init.f16(¶ms,
364 0 /* scale */, fp16_ieee_from_fp32_value(output_min), fp16_ieee_from_fp32_value(output_max));
365 }
366 return create_global_average_pooling_nwc(
367 channels, input_stride, output_stride, flags,
368 1 /* log2(sizeof(uint16_t)) */,
369 offsetof(struct xnn_operator, params.f16_scaleminmax),
370 ¶ms, sizeof(params),
371 XNN_INIT_FLAG_F16,
372 xnn_operator_type_global_average_pooling_nwc_f16,
373 global_average_pooling_op_out);
374 }
375
xnn_create_global_average_pooling_nwc_f32(size_t channels,size_t input_stride,size_t output_stride,float output_min,float output_max,uint32_t flags,xnn_operator_t * global_average_pooling_op_out)376 enum xnn_status xnn_create_global_average_pooling_nwc_f32(
377 size_t channels,
378 size_t input_stride,
379 size_t output_stride,
380 float output_min,
381 float output_max,
382 uint32_t flags,
383 xnn_operator_t* global_average_pooling_op_out)
384 {
385 if (isnan(output_min)) {
386 xnn_log_error(
387 "failed to create %s operator with NaN output lower bound: lower bound must be non-NaN",
388 xnn_operator_type_to_string(xnn_operator_type_global_average_pooling_nwc_f32));
389 return xnn_status_invalid_parameter;
390 }
391
392 if (isnan(output_max)) {
393 xnn_log_error(
394 "failed to create %s operator with NaN output upper bound: upper bound must be non-NaN",
395 xnn_operator_type_to_string(xnn_operator_type_global_average_pooling_nwc_f32));
396 return xnn_status_invalid_parameter;
397 }
398
399 if (output_min >= output_max) {
400 xnn_log_error(
401 "failed to create %s operator with [%.7g, %.7g] output range: lower bound must be below upper bound",
402 xnn_operator_type_to_string(xnn_operator_type_global_average_pooling_nwc_f32), output_min, output_max);
403 return xnn_status_invalid_parameter;
404 }
405
406 union xnn_f32_scaleminmax_params params;
407 if (xnn_params.f32.gavgpool.init.f32 != NULL) {
408 xnn_params.f32.gavgpool.init.f32(¶ms,
409 0.0f /* scale */, output_min, output_max);
410 }
411 return create_global_average_pooling_nwc(
412 channels, input_stride, output_stride, flags,
413 2 /* log2(sizeof(float)) */,
414 offsetof(struct xnn_operator, params.f32_scaleminmax),
415 ¶ms, sizeof(params),
416 XNN_INIT_FLAG_F32,
417 xnn_operator_type_global_average_pooling_nwc_f32,
418 global_average_pooling_op_out);
419 }
420
update_params_qu8(xnn_operator_t global_average_pooling_op,size_t width)421 static void update_params_qu8(
422 xnn_operator_t global_average_pooling_op,
423 size_t width)
424 {
425 const int32_t bias = -((int32_t) width * global_average_pooling_op->input_zero_point);
426 const float scale = global_average_pooling_op->input_scale / (global_average_pooling_op->output_scale * (float) width);
427 xnn_params.qu8.gavgpool.update.qu8(&global_average_pooling_op->params.qu8_gavgpool, bias, scale);
428 }
429
xnn_setup_global_average_pooling_nwc_qu8(xnn_operator_t global_average_pooling_op,size_t batch_size,size_t width,const uint8_t * input,uint8_t * output,pthreadpool_t threadpool)430 enum xnn_status xnn_setup_global_average_pooling_nwc_qu8(
431 xnn_operator_t global_average_pooling_op,
432 size_t batch_size,
433 size_t width,
434 const uint8_t* input,
435 uint8_t* output,
436 pthreadpool_t threadpool)
437 {
438 return setup_global_average_pooling_nwc(
439 global_average_pooling_op,
440 batch_size, width,
441 input, output,
442 0 /* log2(sizeof(uint8_t)) */,
443 &xnn_params.qu8.gavgpool,
444 XNN_INIT_FLAG_QU8,
445 xnn_operator_type_global_average_pooling_nwc_qu8,
446 &global_average_pooling_op->params.qu8_gavgpool,
447 sizeof(global_average_pooling_op->params.qu8_gavgpool),
448 update_params_qu8,
449 threadpool);
450 }
451
update_params_qs8(xnn_operator_t global_average_pooling_op,size_t width)452 static void update_params_qs8(
453 xnn_operator_t global_average_pooling_op,
454 size_t width)
455 {
456 const int32_t bias = -((int32_t) width * global_average_pooling_op->input_zero_point);
457 const float scale = global_average_pooling_op->input_scale / (global_average_pooling_op->output_scale * (float) width);
458 xnn_params.qs8.gavgpool.update.qs8(&global_average_pooling_op->params.qs8_gavgpool, bias, scale);
459 }
460
xnn_setup_global_average_pooling_nwc_qs8(xnn_operator_t global_average_pooling_op,size_t batch_size,size_t width,const int8_t * input,int8_t * output,pthreadpool_t threadpool)461 enum xnn_status xnn_setup_global_average_pooling_nwc_qs8(
462 xnn_operator_t global_average_pooling_op,
463 size_t batch_size,
464 size_t width,
465 const int8_t* input,
466 int8_t* output,
467 pthreadpool_t threadpool)
468 {
469 return setup_global_average_pooling_nwc(
470 global_average_pooling_op,
471 batch_size, width,
472 input, output,
473 0 /* log2(sizeof(int8_t)) */,
474 &xnn_params.qs8.gavgpool,
475 XNN_INIT_FLAG_QS8,
476 xnn_operator_type_global_average_pooling_nwc_qs8,
477 &global_average_pooling_op->params.qs8_gavgpool,
478 sizeof(global_average_pooling_op->params.qs8_gavgpool),
479 update_params_qs8,
480 threadpool);
481 }
482
update_params_f16(xnn_operator_t global_average_pooling_op,size_t width)483 static void update_params_f16(
484 xnn_operator_t global_average_pooling_op,
485 size_t width)
486 {
487 xnn_params.f16.gavgpool.update.f16(
488 &global_average_pooling_op->params.f16_scaleminmax,
489 fp16_ieee_from_fp32_value(1.0f / (float) width));
490 }
491
xnn_setup_global_average_pooling_nwc_f16(xnn_operator_t global_average_pooling_op,size_t batch_size,size_t width,const void * input,void * output,pthreadpool_t threadpool)492 enum xnn_status xnn_setup_global_average_pooling_nwc_f16(
493 xnn_operator_t global_average_pooling_op,
494 size_t batch_size,
495 size_t width,
496 const void* input,
497 void* output,
498 pthreadpool_t threadpool)
499 {
500 return setup_global_average_pooling_nwc(
501 global_average_pooling_op,
502 batch_size, width,
503 input, output,
504 1 /* log2(sizeof(uint16_t)) */,
505 &xnn_params.f16.gavgpool,
506 XNN_INIT_FLAG_F16,
507 xnn_operator_type_global_average_pooling_nwc_f16,
508 &global_average_pooling_op->params.f16_scaleminmax,
509 sizeof(global_average_pooling_op->params.f16_scaleminmax),
510 update_params_f16,
511 threadpool);
512 }
513
update_params_f32(xnn_operator_t global_average_pooling_op,size_t width)514 static void update_params_f32(
515 xnn_operator_t global_average_pooling_op,
516 size_t width)
517 {
518 xnn_params.f32.gavgpool.update.f32(&global_average_pooling_op->params.f32_scaleminmax, 1.0f / (float) width);
519 }
520
xnn_setup_global_average_pooling_nwc_f32(xnn_operator_t global_average_pooling_op,size_t batch_size,size_t width,const float * input,float * output,pthreadpool_t threadpool)521 enum xnn_status xnn_setup_global_average_pooling_nwc_f32(
522 xnn_operator_t global_average_pooling_op,
523 size_t batch_size,
524 size_t width,
525 const float* input,
526 float* output,
527 pthreadpool_t threadpool)
528 {
529 return setup_global_average_pooling_nwc(
530 global_average_pooling_op,
531 batch_size, width,
532 input, output,
533 2 /* log2(sizeof(float)) */,
534 &xnn_params.f32.gavgpool,
535 XNN_INIT_FLAG_F32,
536 xnn_operator_type_global_average_pooling_nwc_f32,
537 &global_average_pooling_op->params.f32_scaleminmax,
538 sizeof(global_average_pooling_op->params.f32_scaleminmax),
539 update_params_f32,
540 threadpool);
541 }
542