blob: 49a122a19623eeac2cc6f06b01a570fb3fc54722 [file] [log] [blame]
XNNPACK Teamb455b122019-09-27 18:10:33 -07001// 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>
XNNPACK Teamb455b122019-09-27 18:10:33 -070014#include <xnnpack/log.h>
Marat Dukhaneeaa7bd2019-10-25 17:31:25 -070015#include <xnnpack/operator.h>
16#include <xnnpack/params-init.h>
17#include <xnnpack/params.h>
XNNPACK Teamb455b122019-09-27 18:10:33 -070018
19
20enum 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 float output_min,
26 float output_max,
27 uint32_t flags,
28 xnn_operator_t* prelu_op_out)
29{
30 xnn_operator_t prelu_op = NULL;
31 enum xnn_status status = xnn_status_uninitialized;
32
33 if (!xnn_params.initialized) {
34 xnn_log_error("failed to create PReLU operator: XNNPACK is not initialized");
35 goto error;
36 }
37
38 status = xnn_status_invalid_parameter;
39
40 if (channels == 0) {
41 xnn_log_error(
42 "failed to create PReLU operator with %zu channels: number of channels must be non-zero", channels);
43 goto error;
44 }
45
46 if (input_stride < channels) {
47 xnn_log_error(
48 "failed to create PReLU operator with input element stride of %zu: "
49 "stride must be at least as large as the number of channels (%zu)",
50 input_stride, channels);
51 goto error;
52 }
53
54 if (output_stride < channels) {
55 xnn_log_error(
56 "failed to create PReLU operator with output element stride of %zu: "
57 "stride must be at least as large as the number of channels (%zu)",
58 output_stride, channels);
59 goto error;
60 }
61
62 if (output_min >= output_max) {
63 xnn_log_error(
64 "failed to create PReLU operator with [%.7g, %.7g] output range: lower bound must be below upper bound",
65 output_min, output_max);
66 goto error;
67 }
68
69 status = xnn_status_out_of_memory;
70
Marat Dukhan04f03be2019-11-19 12:36:47 -080071 prelu_op = xnn_allocate_zero_simd_memory(sizeof(struct xnn_operator));
XNNPACK Teamb455b122019-09-27 18:10:33 -070072 if (prelu_op == NULL) {
73 xnn_log_error("failed to allocate %zu bytes for PReLU operator descriptor", sizeof(struct xnn_operator));
74 goto error;
75 }
76
Marat Dukhan69c3f2c2019-11-06 12:30:01 -080077 const size_t packed_channels = round_up_po2(channels, XNN_EXTRA_BYTES / sizeof(float));
Marat Dukhan04f03be2019-11-19 12:36:47 -080078 prelu_op->packed_weights = xnn_allocate_simd_memory(packed_channels * sizeof(float));
XNNPACK Teamb455b122019-09-27 18:10:33 -070079 if (prelu_op->packed_weights == NULL) {
80 xnn_log_error("failed to allocate %zu bytes for packed slope data",
81 packed_channels * sizeof(float));
82 goto error;
83 }
84 memcpy(prelu_op->packed_weights, negative_slope, channels * sizeof(float));
85
86 prelu_op->channels = channels;
87 prelu_op->input_pixel_stride = input_stride;
88 prelu_op->output_pixel_stride = output_stride;
Marat Dukhaneeaa7bd2019-10-25 17:31:25 -070089 prelu_op->f32_output_params = xnn_init_f32_output_params(output_min, output_max);
XNNPACK Teamb455b122019-09-27 18:10:33 -070090
Marat Dukhanefc47b82019-11-18 09:25:38 -080091 prelu_op->type = xnn_operator_type_prelu_nc_f32;
XNNPACK Teamb455b122019-09-27 18:10:33 -070092 prelu_op->ukernel.type = xnn_ukernel_type_prelu;
93
94 prelu_op->state = xnn_run_state_invalid;
95
96 *prelu_op_out = prelu_op;
97 return xnn_status_success;
98
99error:
100 xnn_delete_operator(prelu_op);
101 return status;
102}
103
104enum xnn_status xnn_setup_prelu_nc_f32(
105 xnn_operator_t prelu_op,
106 size_t batch_size,
107 const float* input,
108 float* output,
109 pthreadpool_t threadpool)
110{
Marat Dukhanefc47b82019-11-18 09:25:38 -0800111 if (prelu_op->type != xnn_operator_type_prelu_nc_f32) {
112 xnn_log_error("failed to setup PReLU (NC, F32) operator: operator type mismatch");
XNNPACK Teamb455b122019-09-27 18:10:33 -0700113 return xnn_status_invalid_parameter;
114 }
115 prelu_op->state = xnn_run_state_invalid;
116
117 if (!xnn_params.initialized) {
118 xnn_log_error("failed to setup PReLU operator: XNNPACK is not initialized");
119 return xnn_status_uninitialized;
120 }
121
122 if (batch_size == 0) {
123 prelu_op->state = xnn_run_state_skip;
124 return xnn_status_success;
125 }
126
127 const size_t channels = prelu_op->channels;
128 prelu_op->context.prelu = (struct prelu_context) {
129 .n = channels * sizeof(float),
130 .x = input,
131 .x_stride = prelu_op->input_pixel_stride * sizeof(float),
132 .w = prelu_op->packed_weights,
133 .y = output,
134 .y_stride = prelu_op->output_pixel_stride * sizeof(float),
135 .ukernel = xnn_params.f32.prelu.ukernel,
136 .params = prelu_op->f32_output_params,
137 };
Marat Dukhan69c3f2c2019-11-06 12:30:01 -0800138
139 size_t batch_tile = batch_size;
140 const size_t num_threads = pthreadpool_get_threads_count(threadpool);
141 if (num_threads > 1) {
142 const size_t target_tiles_per_thread = 5;
143 const size_t max_batch_tile = divide_round_up(batch_size, num_threads * target_tiles_per_thread);
144 if (max_batch_tile < batch_tile) {
145 const uint32_t row_tile = xnn_params.f32.prelu.row_tile;
146 batch_tile = min(batch_tile, divide_round_up(batch_tile, max_batch_tile * row_tile) * row_tile);
147 }
148 }
XNNPACK Teamb455b122019-09-27 18:10:33 -0700149 prelu_op->compute.type = xnn_parallelization_type_1d_tile_1d;
150 prelu_op->compute.task_1d_tile_1d = (pthreadpool_task_1d_tile_1d_t) xnn_compute_prelu;
151 prelu_op->compute.range[0] = batch_size;
Marat Dukhan69c3f2c2019-11-06 12:30:01 -0800152 prelu_op->compute.tile[0] = batch_tile;
XNNPACK Teamb455b122019-09-27 18:10:33 -0700153 prelu_op->state = xnn_run_state_ready;
154
155 return xnn_status_success;
156}