• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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