1 | /* |
2 | * Copyright (c) Facebook, Inc. and its affiliates. |
3 | * All rights reserved. |
4 | * |
5 | * This source code is licensed under the BSD-style license found in the |
6 | * LICENSE file in the root directory of this source tree. |
7 | */ |
8 | |
9 | #include <assert.h> |
10 | #include <math.h> |
11 | #include <stddef.h> |
12 | #include <stdint.h> |
13 | #include <stdlib.h> |
14 | |
15 | #include <qnnpack.h> |
16 | #include <qnnpack/operator.h> |
17 | #include <qnnpack/requantization.h> |
18 | #include <qnnpack/log.h> |
19 | #include <qnnpack/params.h> |
20 | |
21 | |
22 | enum qnnp_status qnnp_create_global_average_pooling_nwc_q8( |
23 | size_t channels, |
24 | uint8_t input_zero_point, |
25 | float input_scale, |
26 | uint8_t output_zero_point, |
27 | float output_scale, |
28 | uint8_t output_min, |
29 | uint8_t output_max, |
30 | uint32_t flags, |
31 | qnnp_operator_t* global_average_pooling_out) |
32 | { |
33 | qnnp_operator_t global_average_pooling_op = NULL; |
34 | enum qnnp_status status = qnnp_status_uninitialized; |
35 | |
36 | if (!qnnp_params.initialized) { |
37 | qnnp_log_error("qnnp_create_global_average_pooling_nwc_q8 failed because QNNPACK is not properly initialized" ); |
38 | goto error; |
39 | } |
40 | |
41 | status = qnnp_status_invalid_parameter; |
42 | |
43 | if (channels == 0) { |
44 | qnnp_log_error( |
45 | "failed to create global average pooling operator with %zu channels: number of channels must be non-zero" , channels); |
46 | goto error; |
47 | } |
48 | |
49 | if (input_scale <= 0.0f || !isnormal(input_scale)) { |
50 | qnnp_log_error( |
51 | "failed to create global average pooling operator with %.7g input scale: scale must be finite and positive" , input_scale); |
52 | goto error; |
53 | } |
54 | |
55 | if (output_scale <= 0.0f || !isnormal(output_scale)) { |
56 | qnnp_log_error( |
57 | "failed to create global average pooling operator with %.7g output scale: scale must be finite and positive" , output_scale); |
58 | goto error; |
59 | } |
60 | |
61 | status = qnnp_status_unsupported_parameter; |
62 | |
63 | const float input_output_scale = input_scale / output_scale; |
64 | if (input_output_scale < 0x1.0p-8f || input_output_scale >= 0x1.0p+8f) { |
65 | qnnp_log_error( |
66 | "failed to create global average pooling operator with %.7g input-to-output scale ratio: " |
67 | "scale ratio must be in [2**-8, 2**8) range" , |
68 | input_output_scale); |
69 | goto error; |
70 | } |
71 | |
72 | status = qnnp_status_out_of_memory; |
73 | |
74 | global_average_pooling_op = calloc(1, sizeof(struct qnnp_operator)); |
75 | if (global_average_pooling_op == NULL) { |
76 | qnnp_log_error("failed to allocate %zu bytes for qnnp_operator structure" , sizeof(struct qnnp_operator)); |
77 | goto error; |
78 | } |
79 | |
80 | void* zero_buffer = calloc(channels, sizeof(uint8_t)); |
81 | if (zero_buffer == NULL) { |
82 | qnnp_log_error("failed to allocate %zu bytes for zero padding" , channels * sizeof(uint8_t)); |
83 | goto error; |
84 | } |
85 | global_average_pooling_op->zero_buffer = zero_buffer; |
86 | global_average_pooling_op->zero_pointer = zero_buffer; |
87 | |
88 | global_average_pooling_op->channels = channels; |
89 | global_average_pooling_op->input_zero_point = input_zero_point; |
90 | global_average_pooling_op->output_zero_point = output_zero_point; |
91 | global_average_pooling_op->input_scale = input_scale; |
92 | global_average_pooling_op->output_scale = output_scale; |
93 | global_average_pooling_op->output_min = output_min; |
94 | global_average_pooling_op->output_max = output_max; |
95 | |
96 | global_average_pooling_op->ukernel_type = qnnp_ukernel_type_global_average_pooling; |
97 | global_average_pooling_op->format = qnnp_format_quint8; |
98 | |
99 | *global_average_pooling_out = global_average_pooling_op; |
100 | return qnnp_status_success; |
101 | |
102 | error: |
103 | qnnp_delete_operator(global_average_pooling_op); |
104 | return status; |
105 | } |
106 | |
107 | enum qnnp_status qnnp_setup_global_average_pooling_nwc_q8( |
108 | qnnp_operator_t global_average_pooling_op, |
109 | size_t batch_size, |
110 | size_t width, |
111 | const uint8_t* input, |
112 | size_t input_stride, |
113 | uint8_t* output, |
114 | size_t output_stride) |
115 | { |
116 | if (!qnnp_params.initialized) { |
117 | qnnp_log_error("qnnp_setup_global_average_pooling_nwc_q8 failed because QNNPACK is not properly initialized" ); |
118 | return qnnp_status_uninitialized; |
119 | } |
120 | |
121 | if (batch_size == 0) { |
122 | global_average_pooling_op->batch_size = 0; |
123 | return qnnp_status_success; |
124 | } |
125 | |
126 | if (width == 0) { |
127 | qnnp_log_error("failed to setup global average pooling operator with width %zu: width must be non-zero" , width); |
128 | return qnnp_status_invalid_parameter; |
129 | } |
130 | |
131 | global_average_pooling_op->batch_size = batch_size; |
132 | global_average_pooling_op->input_width = width; |
133 | global_average_pooling_op->input = input; |
134 | global_average_pooling_op->input_pixel_stride = input_stride; |
135 | global_average_pooling_op->output = output; |
136 | global_average_pooling_op->output_pixel_stride = output_stride; |
137 | |
138 | global_average_pooling_op->avgpool_quantization_params = |
139 | qnnp_compute_avgpool_quantization_params( |
140 | -(int32_t) width * (int32_t) (uint32_t) global_average_pooling_op->input_zero_point, |
141 | global_average_pooling_op->input_scale / (global_average_pooling_op->output_scale * (float) width), |
142 | global_average_pooling_op->output_zero_point, |
143 | global_average_pooling_op->output_min, |
144 | global_average_pooling_op->output_max); |
145 | |
146 | return qnnp_status_success; |
147 | } |
148 | |