1 /**
2 * Copyright 2021 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 "src/runtime/kernel/arm/fp32/crop_and_resize_fp32.h"
18 #include "schema/model_generated.h"
19 #include "src/kernel_registry.h"
20 #include "nnacl/fp32/resize_fp32.h"
21
22 using mindspore::kernel::KERNEL_ARCH;
23 using mindspore::lite::KernelRegistrar;
24 using mindspore::lite::RET_ERROR;
25 using mindspore::lite::RET_INVALID_OP_ATTR;
26 using mindspore::lite::RET_NULL_PTR;
27 using mindspore::lite::RET_OK;
28 using mindspore::schema::PrimitiveType_CropAndResize;
29
30 namespace mindspore::kernel {
31 namespace {
32 constexpr size_t kBoxIndex = 1;
33 constexpr size_t kBoxIdIndex = 2;
34 } // namespace
Init()35 int CropAndResizeCPUKernel::Init() {
36 if (!InferShapeDone()) {
37 return RET_OK;
38 }
39 return ReSize();
40 }
41
ReSize()42 int CropAndResizeCPUKernel::ReSize() {
43 const auto &shape = out_tensors_[0]->shape();
44 CHECK_LESS_RETURN(shape.size(), DIMENSION_3D);
45 new_height_ = shape[1];
46 new_width_ = shape[2];
47 return RET_OK;
48 }
49
MallocTmpBuffer()50 int CropAndResizeCPUKernel::MallocTmpBuffer() {
51 batch_ = out_tensors_[0]->Batch();
52 // Malloc buffer to save coordinate.
53 // For mode CROP_AND_RESIZE, different output batches require different cache coordinates.
54 int c = in_tensors_.at(0)->Channel();
55 y_bottoms_ = reinterpret_cast<int *>(ms_context_->allocator->Malloc(sizeof(int) * new_height_ * batch_));
56 if (y_bottoms_ == nullptr) {
57 MS_LOG(ERROR) << "malloc data failed";
58 return RET_NULL_PTR;
59 }
60 y_tops_ = reinterpret_cast<int *>(ms_context_->allocator->Malloc(sizeof(int) * new_height_ * batch_));
61 if (y_tops_ == nullptr) {
62 MS_LOG(ERROR) << "malloc data failed";
63 return RET_NULL_PTR;
64 }
65 y_bottom_weights_ = reinterpret_cast<float *>(ms_context_->allocator->Malloc(sizeof(float) * new_height_ * batch_));
66 if (y_bottom_weights_ == nullptr) {
67 MS_LOG(ERROR) << "malloc data failed";
68 return RET_NULL_PTR;
69 }
70
71 x_lefts_ = reinterpret_cast<int *>(ms_context_->allocator->Malloc(sizeof(int) * new_width_ * batch_));
72 if (x_lefts_ == nullptr) {
73 MS_LOG(ERROR) << "malloc data failed";
74 return RET_NULL_PTR;
75 }
76 x_rights_ = reinterpret_cast<int *>(ms_context_->allocator->Malloc(sizeof(int) * new_width_ * batch_));
77 if (x_rights_ == nullptr) {
78 MS_LOG(ERROR) << "malloc data failed";
79 return RET_NULL_PTR;
80 }
81 x_left_weights_ = reinterpret_cast<float *>(ms_context_->allocator->Malloc(sizeof(float) * new_width_ * batch_));
82 if (x_left_weights_ == nullptr) {
83 MS_LOG(ERROR) << "malloc data failed";
84 return RET_NULL_PTR;
85 }
86 line_buffer_ = reinterpret_cast<float *>(
87 ms_context_->allocator->Malloc(sizeof(float) * new_width_ * c * mapped_point_num_ * op_parameter_->thread_num_));
88 if (line_buffer_ == nullptr) {
89 MS_LOG(ERROR) << "malloc data failed";
90 return RET_NULL_PTR;
91 }
92 return RET_OK;
93 }
94
FreeTmpBuffer()95 void CropAndResizeCPUKernel::FreeTmpBuffer() {
96 ms_context_->allocator->Free(y_bottoms_);
97 ms_context_->allocator->Free(y_tops_);
98 ms_context_->allocator->Free(y_bottom_weights_);
99 ms_context_->allocator->Free(x_lefts_);
100 ms_context_->allocator->Free(x_rights_);
101 ms_context_->allocator->Free(x_left_weights_);
102 ms_context_->allocator->Free(line_buffer_);
103 y_bottoms_ = nullptr;
104 y_tops_ = nullptr;
105 y_bottom_weights_ = nullptr;
106 x_lefts_ = nullptr;
107 x_rights_ = nullptr;
108 x_left_weights_ = nullptr;
109 line_buffer_ = nullptr;
110 }
111
CropAndResizeImpl(void * cdata,int task_id,float lhs_scale,float rhs_scale)112 int CropAndResizeImpl(void *cdata, int task_id, float lhs_scale, float rhs_scale) {
113 CHECK_NULL_RETURN(cdata);
114 auto resize = reinterpret_cast<CropAndResizeCPUKernel *>(cdata);
115 auto error_code = resize->RunImpl(task_id);
116 if (error_code != RET_OK) {
117 MS_LOG(ERROR) << "CropAndResize Run error task_id[" << task_id << "] error_code[" << error_code << "]";
118 return RET_ERROR;
119 }
120 return RET_OK;
121 }
122
RunImpl(int task_id)123 int CropAndResizeCPUKernel::RunImpl(int task_id) {
124 auto input = in_tensors_.at(0);
125 auto input_data = reinterpret_cast<float *>(input->data());
126 CHECK_NULL_RETURN(input_data);
127 auto boxes = reinterpret_cast<float *>(in_tensors_.at(kBoxIndex)->data());
128 CHECK_NULL_RETURN(boxes);
129 auto box_idx = reinterpret_cast<int32_t *>(in_tensors_.at(kBoxIdIndex)->data());
130 CHECK_NULL_RETURN(box_idx);
131 auto output_data = reinterpret_cast<float *>(out_tensors_.at(0)->data());
132 CHECK_NULL_RETURN(output_data);
133 int unit = UP_DIV(new_height_, op_parameter_->thread_num_);
134 int h_begin = unit * task_id;
135 int h_end = MSMIN(h_begin + unit, new_height_);
136 if (h_end <= h_begin) {
137 return RET_OK;
138 }
139 const auto &input_shape = input->shape();
140 int c = input_shape[3];
141 float *line0 = line_buffer_ + new_width_ * c * 2 * task_id;
142 float *line1 = line0 + new_width_ * c;
143 auto ret = CropAndResizeBilinear(input_data, output_data, box_idx, boxes, param_, input_shape.data(),
144 out_tensors_.at(0)->shape().data(), y_bottoms_, y_tops_, x_lefts_, x_rights_,
145 y_bottom_weights_, x_left_weights_, line0, line1, h_begin, h_end);
146 return ret;
147 }
148
Run()149 int CropAndResizeCPUKernel::Run() {
150 auto ret = MallocTmpBuffer();
151 if (ret != RET_OK) {
152 FreeTmpBuffer();
153 return ret;
154 }
155
156 auto input = in_tensors_.at(0);
157 auto input_shape = input->shape();
158 auto boxes = reinterpret_cast<float *>(in_tensors_.at(1)->data());
159 auto box_idx = reinterpret_cast<int32_t *>(in_tensors_.at(2)->data());
160 CHECK_LESS_RETURN(input_shape.size(), DIMENSION_4D);
161 const auto &output_shape = out_tensors_.at(0)->shape();
162 CHECK_LESS_RETURN(output_shape.size(), DIMENSION_4D);
163 ret = PrepareCropAndResizeBilinear(input_shape.data(), boxes, box_idx, output_shape.data(), y_bottoms_, y_tops_,
164 x_lefts_, x_rights_, y_bottom_weights_, x_left_weights_);
165 if (ret != RET_OK) {
166 MS_LOG(ERROR) << "PrepareCropAndResizeBilinear, error_code[" << ret << "]";
167 FreeTmpBuffer();
168 return ret;
169 }
170
171 int error_code = ParallelLaunch(this->ms_context_, CropAndResizeImpl, this, op_parameter_->thread_num_);
172 if (error_code != RET_OK) {
173 MS_LOG(ERROR) << "CropAndResize run error, error_code[" << error_code << "]";
174 FreeTmpBuffer();
175 return RET_ERROR;
176 }
177 FreeTmpBuffer();
178 return RET_OK;
179 }
180
181 REG_KERNEL(kCPU, kNumberTypeFloat32, PrimitiveType_CropAndResize, LiteKernelCreator<CropAndResizeCPUKernel>)
182 } // namespace mindspore::kernel
183