• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 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 #include <stdlib.h>
10 #include <string.h>
11 
12 #include <xnnpack.h>
13 #include <xnnpack/allocator.h>
14 #include <xnnpack/log.h>
15 #include <xnnpack/operator.h>
16 #include <xnnpack/params-init.h>
17 #include <xnnpack/params.h>
18 
19 
xnn_create_prelu_nc_f32(size_t channels,size_t input_stride,size_t output_stride,const float * negative_slope,uint32_t flags,xnn_operator_t * prelu_op_out)20 enum xnn_status xnn_create_prelu_nc_f32(
21     size_t channels,
22     size_t input_stride,
23     size_t output_stride,
24     const float* negative_slope,
25     uint32_t flags,
26     xnn_operator_t* prelu_op_out)
27 {
28   xnn_operator_t prelu_op = NULL;
29   enum xnn_status status = xnn_status_uninitialized;
30 
31   if ((xnn_params.init_flags & XNN_INIT_FLAG_XNNPACK) == 0) {
32     xnn_log_error("failed to create %s operator: XNNPACK is not initialized",
33       xnn_operator_type_to_string(xnn_operator_type_prelu_nc_f32));
34     goto error;
35   }
36 
37   status = xnn_status_invalid_parameter;
38 
39   if (channels == 0) {
40     xnn_log_error(
41       "failed to create %s operator with %zu channels: number of channels must be non-zero",
42       xnn_operator_type_to_string(xnn_operator_type_prelu_nc_f32), channels);
43     goto error;
44   }
45 
46   if (input_stride < channels) {
47     xnn_log_error(
48       "failed to create %s operator with input element stride of %zu: "
49       "stride must be at least as large as the number of channels (%zu)",
50       xnn_operator_type_to_string(xnn_operator_type_prelu_nc_f32), input_stride, channels);
51     goto error;
52   }
53 
54   if (output_stride < channels) {
55     xnn_log_error(
56       "failed to create %s operator with output element stride of %zu: "
57       "stride must be at least as large as the number of channels (%zu)",
58       xnn_operator_type_to_string(xnn_operator_type_prelu_nc_f32), output_stride, channels);
59     goto error;
60   }
61 
62   status = xnn_status_out_of_memory;
63 
64   prelu_op = xnn_allocate_zero_simd_memory(sizeof(struct xnn_operator));
65   if (prelu_op == NULL) {
66     xnn_log_error(
67       "failed to allocate %zu bytes for %s operator descriptor",
68       sizeof(struct xnn_operator), xnn_operator_type_to_string(xnn_operator_type_prelu_nc_f32));
69     goto error;
70   }
71 
72   const size_t packed_weights_size = channels * sizeof(float) + XNN_EXTRA_BYTES;
73   prelu_op->packed_weights = xnn_allocate_simd_memory(packed_weights_size);
74   if (prelu_op->packed_weights == NULL) {
75     xnn_log_error(
76       "failed to allocate %zu bytes for %s operator packed weights",
77       packed_weights_size, xnn_operator_type_to_string(xnn_operator_type_prelu_nc_f32));
78     goto error;
79   }
80   memcpy(prelu_op->packed_weights, negative_slope, channels * sizeof(float));
81 
82   prelu_op->channels = channels;
83   prelu_op->input_pixel_stride = input_stride;
84   prelu_op->output_pixel_stride = output_stride;
85 
86   prelu_op->type = xnn_operator_type_prelu_nc_f32;
87 
88   prelu_op->state = xnn_run_state_invalid;
89 
90   *prelu_op_out = prelu_op;
91   return xnn_status_success;
92 
93 error:
94   xnn_delete_operator(prelu_op);
95   return status;
96 }
97 
xnn_setup_prelu_nc_f32(xnn_operator_t prelu_op,size_t batch_size,const float * input,float * output,pthreadpool_t threadpool)98 enum xnn_status xnn_setup_prelu_nc_f32(
99     xnn_operator_t prelu_op,
100     size_t batch_size,
101     const float* input,
102     float* output,
103     pthreadpool_t threadpool)
104 {
105   if (prelu_op->type != xnn_operator_type_prelu_nc_f32) {
106     xnn_log_error("failed to setup operator: operator type mismatch (expected %s, got %s)",
107       xnn_operator_type_to_string(xnn_operator_type_prelu_nc_f32),
108       xnn_operator_type_to_string(prelu_op->type));
109     return xnn_status_invalid_parameter;
110   }
111   prelu_op->state = xnn_run_state_invalid;
112 
113   if ((xnn_params.init_flags & XNN_INIT_FLAG_XNNPACK) == 0) {
114     xnn_log_error("failed to setup %s operator: XNNPACK is not initialized",
115       xnn_operator_type_to_string(xnn_operator_type_prelu_nc_f32));
116     return xnn_status_uninitialized;
117   }
118 
119   if (batch_size == 0) {
120     prelu_op->state = xnn_run_state_skip;
121     return xnn_status_success;
122   }
123 
124   const size_t channels = prelu_op->channels;
125   prelu_op->context.prelu = (struct prelu_context) {
126     .n = channels * sizeof(float),
127     .x = input,
128     .x_stride = prelu_op->input_pixel_stride * sizeof(float),
129     .w = prelu_op->packed_weights,
130     .y = output,
131     .y_stride = prelu_op->output_pixel_stride * sizeof(float),
132     .ukernel = xnn_params.f32.prelu.ukernel,
133   };
134 
135   size_t batch_tile = batch_size;
136   const size_t num_threads = pthreadpool_get_threads_count(threadpool);
137   if (num_threads > 1) {
138     const size_t target_tiles_per_thread = 5;
139     const size_t max_batch_tile = divide_round_up(batch_size, num_threads * target_tiles_per_thread);
140     if (max_batch_tile < batch_tile) {
141       const uint32_t row_tile = xnn_params.f32.prelu.row_tile;
142       batch_tile = min(batch_tile, divide_round_up(batch_tile, max_batch_tile * row_tile) * row_tile);
143     }
144   }
145   prelu_op->compute.type = xnn_parallelization_type_1d_tile_1d;
146   prelu_op->compute.task_1d_tile_1d = (pthreadpool_task_1d_tile_1d_t) xnn_compute_prelu;
147   prelu_op->compute.range[0] = batch_size;
148   prelu_op->compute.tile[0] = batch_tile;
149   prelu_op->state = xnn_run_state_ready;
150 
151   return xnn_status_success;
152 }
153