1 /**
2 * Copyright 2023 Huawei Technologies Co., Ltd
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "nnacl/kernel/prior_box.h"
18 #include <math.h>
19 #include "nnacl/kernel/default_kernel_base.h"
20 #include "nnacl/fp32/prior_box_fp32.h"
21 #include "nnacl/tensor_c_utils.h"
22
PriorBoxInitOutput(PriorBoxStruct * prior_box,const PriorBoxParameter * param,const float * different_aspect_ratios,int different_aspect_ratios_size)23 int PriorBoxInitOutput(PriorBoxStruct *prior_box, const PriorBoxParameter *param, const float *different_aspect_ratios,
24 int different_aspect_ratios_size) {
25 for (int i = 0; i < prior_box->fmap_h_; i++) {
26 float cy = i + param->offset;
27 for (int j = 0; j < prior_box->fmap_w_; j++) {
28 float cx = j + param->offset;
29 for (int32_t k = 0; k < param->min_sizes_size; k++) {
30 float min = param->min_sizes[k];
31 prior_box->output_[prior_box->output_size_++] = (cx - min / prior_box->step_w_ * 0.5f) / prior_box->fmap_w_;
32 prior_box->output_[prior_box->output_size_++] = (cy - min / prior_box->step_h_ * 0.5f) / prior_box->fmap_h_;
33 prior_box->output_[prior_box->output_size_++] = (cx + min / prior_box->step_w_ * 0.5f) / prior_box->fmap_w_;
34 prior_box->output_[prior_box->output_size_++] = (cy + min / prior_box->step_h_ * 0.5f) / prior_box->fmap_h_;
35
36 if (param->max_sizes_size > 0) {
37 float max = param->max_sizes[k];
38 NNACL_CHECK_FALSE(min * max <= 0, NNACL_PRIOR_BOX_VALUE_INVALID);
39 float prime = sqrt(min * max);
40 prior_box->output_[prior_box->output_size_++] = (cx - prime / prior_box->step_w_ * 0.5f) / prior_box->fmap_w_;
41 prior_box->output_[prior_box->output_size_++] = (cy - prime / prior_box->step_h_ * 0.5f) / prior_box->fmap_h_;
42 prior_box->output_[prior_box->output_size_++] = (cx + prime / prior_box->step_w_ * 0.5f) / prior_box->fmap_w_;
43 prior_box->output_[prior_box->output_size_++] = (cy + prime / prior_box->step_h_ * 0.5f) / prior_box->fmap_h_;
44 }
45
46 for (int m = 0; m < different_aspect_ratios_size; m++) {
47 float v = different_aspect_ratios[m];
48 if (fabs(v - 1.0f) < 1e-6) {
49 continue;
50 }
51 NNACL_CHECK_FALSE(v <= 0, NNACL_PRIOR_BOX_VALUE_INVALID);
52 float as_square_root = sqrt(v);
53 NNACL_CHECK_FALSE(as_square_root <= 0, NNACL_PRIOR_BOX_VALUE_INVALID);
54 float box_w = min * as_square_root;
55 float box_h = min / as_square_root;
56 prior_box->output_[prior_box->output_size_++] = (cx - box_w / prior_box->step_w_ * 0.5f) / prior_box->fmap_w_;
57 prior_box->output_[prior_box->output_size_++] = (cy - box_h / prior_box->step_h_ * 0.5f) / prior_box->fmap_h_;
58 prior_box->output_[prior_box->output_size_++] = (cx + box_w / prior_box->step_w_ * 0.5f) / prior_box->fmap_w_;
59 prior_box->output_[prior_box->output_size_++] = (cy + box_h / prior_box->step_h_ * 0.5f) / prior_box->fmap_h_;
60 }
61 }
62 }
63 }
64 return NNACL_OK;
65 }
66
RunPriorBox(void * cdata,int task_id,float l,float r)67 int RunPriorBox(void *cdata, int task_id, float l, float r) {
68 PriorBoxStruct *prior_box = (PriorBoxStruct *)cdata;
69 NNACL_CHECK_NULL_RETURN_ERR(prior_box);
70 TensorC *output_tensor = prior_box->base_.out_[OUTPUT_INDEX];
71 NNACL_CHECK_NULL_RETURN_ERR(output_tensor);
72 float *output_data = output_tensor->data_;
73 NNACL_CHECK_NULL_RETURN_ERR(output_data);
74 return PriorBox(prior_box->output_, output_data, GetSize(output_tensor), task_id, prior_box->base_.thread_nr_);
75 }
76
PriorBoxRelease(KernelBase * self)77 int PriorBoxRelease(KernelBase *self) {
78 PriorBoxStruct *prior_box = (PriorBoxStruct *)self;
79 NNACL_CHECK_NULL_RETURN_ERR(prior_box);
80 if (prior_box->output_ != NULL) {
81 self->env_->Free(self->env_->allocator_, prior_box->output_);
82 prior_box->output_ = NULL;
83 prior_box->output_size_ = 0;
84 }
85 return NNACL_OK;
86 }
87
PriorBoxResize(KernelBase * self)88 int PriorBoxResize(KernelBase *self) {
89 PriorBoxStruct *prior_box = (PriorBoxStruct *)self;
90 NNACL_CHECK_NULL_RETURN_ERR(prior_box);
91 PriorBoxParameter *param = (PriorBoxParameter *)self->param_;
92 NNACL_CHECK_NULL_RETURN_ERR(param);
93 TensorC *input0_tensor = prior_box->base_.in_[FIRST_INPUT];
94 NNACL_CHECK_NULL_RETURN_ERR(input0_tensor);
95 TensorC *input1_tensor = prior_box->base_.in_[FIRST_INPUT];
96 NNACL_CHECK_NULL_RETURN_ERR(input1_tensor);
97 TensorC *output_tensor = prior_box->base_.out_[OUTPUT_INDEX];
98 NNACL_CHECK_NULL_RETURN_ERR(output_tensor);
99
100 prior_box->fmap_w_ = GetWidth(input0_tensor);
101 NNACL_CHECK_ZERO_RETURN_ERR(prior_box->fmap_w_);
102 prior_box->fmap_h_ = GetHeight(input1_tensor);
103 NNACL_CHECK_ZERO_RETURN_ERR(prior_box->fmap_h_);
104 const int image_w = param->image_size_w > 0 ? param->image_size_w : GetWidth(input1_tensor);
105 const int image_h = param->image_size_h > 0 ? param->image_size_h : GetHeight(input1_tensor);
106
107 prior_box->step_w_ = param->step_w > 0.0f ? param->step_w : (float)(image_w) / prior_box->fmap_w_;
108 prior_box->step_h_ = param->step_h > 0.0f ? param->step_h : (float)(image_h) / prior_box->fmap_h_;
109
110 float *different_aspect_ratios =
111 (float *)self->env_->Alloc(self->env_->allocator_, param->aspect_ratios_size * sizeof(float) * Num2);
112 NNACL_MALLOC_CHECK_NULL_RETURN_ERR(different_aspect_ratios);
113 different_aspect_ratios[Index0] = 1.0f;
114 int different_aspect_ratios_size = 1;
115
116 float *aspect_ratios = param->aspect_ratios;
117 for (int32_t i = 0; i < param->aspect_ratios_size; i++) {
118 float ratio = aspect_ratios[i];
119
120 bool exist = false;
121 for (int k = 0; k < different_aspect_ratios_size; k++) {
122 if (fabs(ratio - different_aspect_ratios[k]) < 1e-6) {
123 exist = true;
124 }
125 }
126
127 if (!exist) {
128 different_aspect_ratios[different_aspect_ratios_size++] = ratio;
129 if (param->flip) {
130 NNACL_CHECK_FALSE(fabs(ratio) <= 1e-5, NNACL_PRIOR_BOX_RATIO_INVALID);
131 different_aspect_ratios[different_aspect_ratios_size++] = 1.0f / ratio;
132 }
133 }
134 }
135
136 PriorBoxRelease(self);
137 int size = Num4 + Num4 + different_aspect_ratios_size;
138 size = size * prior_box->fmap_h_ * prior_box->fmap_w_ * param->min_sizes_size;
139 size = size + UP_ROUND(GetHeight(output_tensor), COMM_SHAPE_SIZE);
140 size = size * sizeof(float);
141 NNACL_CHECK_MALLOC_SIZE(size);
142 prior_box->output_ = (float *)self->env_->Alloc(self->env_->allocator_, size);
143 NNACL_MALLOC_CHECK_NULL_RETURN_ERR(prior_box->output_);
144 prior_box->output_size_ = 0;
145
146 int ret = PriorBoxInitOutput(prior_box, param, different_aspect_ratios, different_aspect_ratios_size);
147 if (ret != NNACL_OK) {
148 return ret;
149 }
150
151 // do clip
152 if (param->clip) {
153 for (int i = 0; i < prior_box->output_size_; i++) {
154 float item = prior_box->output_[i];
155 if (item > 1.0f) {
156 item = 1.0f;
157 }
158 if (item < 0.0f) {
159 item = 0.0f;
160 }
161 }
162 }
163
164 // variance
165 for (int i = 0; i < GetHeight(output_tensor) / COMM_SHAPE_SIZE; i++) {
166 for (int j = 0; j < COMM_SHAPE_SIZE; j++) {
167 prior_box->output_[prior_box->output_size_++] = param->variances[j];
168 }
169 }
170 return NNACL_OK;
171 }
172
PriorBoxCompute(KernelBase * self)173 int PriorBoxCompute(KernelBase *self) {
174 return self->env_->ParallelLaunch(self->env_->thread_pool_, RunPriorBox, self, self->thread_nr_);
175 }
176
CreatePriorBox(OpParameter * param,int data_type)177 KernelBase *CreatePriorBox(OpParameter *param, int data_type) {
178 PriorBoxStruct *prior_box = (PriorBoxStruct *)malloc(sizeof(PriorBoxStruct));
179 NNACL_MALLOC_CHECK_NULL_RETURN_NULL(prior_box);
180 memset(prior_box, 0, sizeof(PriorBoxStruct));
181
182 prior_box->base_.Prepare = DefaultPrepare2In1Out;
183 prior_box->base_.Resize = PriorBoxResize;
184 prior_box->base_.Release = PriorBoxRelease;
185 prior_box->base_.Compute = PriorBoxCompute;
186 return (KernelBase *)prior_box;
187 }
188
189 REG_KERNEL_CREATOR(PrimType_PriorBox, kNumberTypeFloat32, CreatePriorBox)
190 REG_KERNEL_CREATOR(PrimType_PriorBox, kNumberTypeInt8, CreatePriorBox)
191