• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2019-2020 Arm Limited.
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24 #include "src/core/NEON/kernels/NEGenerateProposalsLayerKernel.h"
25 
26 #include "arm_compute/core/Helpers.h"
27 #include "arm_compute/core/TensorInfo.h"
28 #include "arm_compute/core/Utils.h"
29 #include "arm_compute/core/Window.h"
30 #include "src/core/AccessWindowStatic.h"
31 #include "src/core/CPP/Validate.h"
32 #include "src/core/helpers/AutoConfiguration.h"
33 #include "src/core/helpers/WindowHelpers.h"
34 
35 #include <arm_neon.h>
36 
37 namespace arm_compute
38 {
39 namespace
40 {
validate_arguments(const ITensorInfo * anchors,const ITensorInfo * all_anchors,const ComputeAnchorsInfo & info)41 Status validate_arguments(const ITensorInfo *anchors, const ITensorInfo *all_anchors, const ComputeAnchorsInfo &info)
42 {
43     ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(anchors, all_anchors);
44     ARM_COMPUTE_RETURN_ERROR_ON_CPU_F16_UNSUPPORTED(anchors);
45     ARM_COMPUTE_RETURN_ERROR_ON(anchors->dimension(0) != info.values_per_roi());
46     ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_NOT_IN(anchors, DataType::QSYMM16, DataType::F16, DataType::F32);
47     ARM_COMPUTE_RETURN_ERROR_ON(anchors->num_dimensions() > 2);
48     if(all_anchors->total_size() > 0)
49     {
50         const size_t feature_height = info.feat_height();
51         const size_t feature_width  = info.feat_width();
52         const size_t num_anchors    = anchors->dimension(1);
53         ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DATA_TYPES(all_anchors, anchors);
54         ARM_COMPUTE_RETURN_ERROR_ON(all_anchors->num_dimensions() > 2);
55         ARM_COMPUTE_RETURN_ERROR_ON(all_anchors->dimension(0) != info.values_per_roi());
56         ARM_COMPUTE_RETURN_ERROR_ON(all_anchors->dimension(1) != feature_height * feature_width * num_anchors);
57 
58         if(is_data_type_quantized(anchors->data_type()))
59         {
60             ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_QUANTIZATION_INFO(anchors, all_anchors);
61         }
62     }
63     return Status{};
64 }
65 
66 } // namespace
67 
NEComputeAllAnchorsKernel()68 NEComputeAllAnchorsKernel::NEComputeAllAnchorsKernel()
69     : _anchors(nullptr), _all_anchors(nullptr), _anchors_info(0.f, 0.f, 0.f)
70 {
71 }
72 
configure(const ITensor * anchors,ITensor * all_anchors,const ComputeAnchorsInfo & info)73 void NEComputeAllAnchorsKernel::configure(const ITensor *anchors, ITensor *all_anchors, const ComputeAnchorsInfo &info)
74 {
75     ARM_COMPUTE_ERROR_ON_NULLPTR(anchors, all_anchors);
76     ARM_COMPUTE_ERROR_THROW_ON(validate_arguments(anchors->info(), all_anchors->info(), info));
77 
78     // Metadata
79     const size_t   num_anchors = anchors->info()->dimension(1);
80     const DataType data_type   = anchors->info()->data_type();
81     const float    width       = info.feat_width();
82     const float    height      = info.feat_height();
83 
84     // Initialize the output if empty
85     const TensorShape output_shape(info.values_per_roi(), width * height * num_anchors);
86     auto_init_if_empty(*all_anchors->info(), TensorInfo(output_shape, 1, data_type, anchors->info()->quantization_info()));
87 
88     // Set instance variables
89     _anchors      = anchors;
90     _all_anchors  = all_anchors;
91     _anchors_info = info;
92 
93     Window win = calculate_max_window(*all_anchors->info(), Steps(info.values_per_roi()));
94 
95     INEKernel::configure(win);
96 }
97 
validate(const ITensorInfo * anchors,const ITensorInfo * all_anchors,const ComputeAnchorsInfo & info)98 Status NEComputeAllAnchorsKernel::validate(const ITensorInfo *anchors, const ITensorInfo *all_anchors, const ComputeAnchorsInfo &info)
99 {
100     ARM_COMPUTE_RETURN_ON_ERROR(validate_arguments(anchors, all_anchors, info));
101     return Status{};
102 }
103 
104 template <>
internal_run(const Window & window)105 void NEComputeAllAnchorsKernel::internal_run<int16_t>(const Window &window)
106 {
107     Iterator all_anchors_it(_all_anchors, window);
108     Iterator anchors_it(_all_anchors, window);
109 
110     const size_t num_anchors = _anchors->info()->dimension(1);
111     const float  stride      = 1.f / _anchors_info.spatial_scale();
112     const size_t feat_width  = _anchors_info.feat_width();
113 
114     const UniformQuantizationInfo qinfo = _anchors->info()->quantization_info().uniform();
115 
116     execute_window_loop(window, [&](const Coordinates & id)
117     {
118         const size_t anchor_offset = id.y() % num_anchors;
119 
120         const auto out_anchor_ptr = reinterpret_cast<int16_t *>(all_anchors_it.ptr());
121         const auto anchor_ptr     = reinterpret_cast<int16_t *>(_anchors->ptr_to_element(Coordinates(0, anchor_offset)));
122 
123         const size_t shift_idy = id.y() / num_anchors;
124         const float  shiftx    = (shift_idy % feat_width) * stride;
125         const float  shifty    = (shift_idy / feat_width) * stride;
126 
127         const float new_anchor_x1 = dequantize_qsymm16(*anchor_ptr, qinfo.scale) + shiftx;
128         const float new_anchor_y1 = dequantize_qsymm16(*(1 + anchor_ptr), qinfo.scale) + shifty;
129         const float new_anchor_x2 = dequantize_qsymm16(*(2 + anchor_ptr), qinfo.scale) + shiftx;
130         const float new_anchor_y2 = dequantize_qsymm16(*(3 + anchor_ptr), qinfo.scale) + shifty;
131 
132         *out_anchor_ptr       = quantize_qsymm16(new_anchor_x1, qinfo.scale);
133         *(out_anchor_ptr + 1) = quantize_qsymm16(new_anchor_y1, qinfo.scale);
134         *(out_anchor_ptr + 2) = quantize_qsymm16(new_anchor_x2, qinfo.scale);
135         *(out_anchor_ptr + 3) = quantize_qsymm16(new_anchor_y2, qinfo.scale);
136     },
137     all_anchors_it);
138 }
139 
140 template <typename T>
internal_run(const Window & window)141 void NEComputeAllAnchorsKernel::internal_run(const Window &window)
142 {
143     Iterator all_anchors_it(_all_anchors, window);
144     Iterator anchors_it(_all_anchors, window);
145 
146     const size_t num_anchors = _anchors->info()->dimension(1);
147     const T      stride      = 1.f / _anchors_info.spatial_scale();
148     const size_t feat_width  = _anchors_info.feat_width();
149 
150     execute_window_loop(window, [&](const Coordinates & id)
151     {
152         const size_t anchor_offset = id.y() % num_anchors;
153 
154         const auto out_anchor_ptr = reinterpret_cast<T *>(all_anchors_it.ptr());
155         const auto anchor_ptr     = reinterpret_cast<T *>(_anchors->ptr_to_element(Coordinates(0, anchor_offset)));
156 
157         const size_t shift_idy = id.y() / num_anchors;
158         const T      shiftx    = (shift_idy % feat_width) * stride;
159         const T      shifty    = (shift_idy / feat_width) * stride;
160 
161         *out_anchor_ptr       = *anchor_ptr + shiftx;
162         *(out_anchor_ptr + 1) = *(1 + anchor_ptr) + shifty;
163         *(out_anchor_ptr + 2) = *(2 + anchor_ptr) + shiftx;
164         *(out_anchor_ptr + 3) = *(3 + anchor_ptr) + shifty;
165     },
166     all_anchors_it);
167 }
168 
run(const Window & window,const ThreadInfo & info)169 void NEComputeAllAnchorsKernel::run(const Window &window, const ThreadInfo &info)
170 {
171     ARM_COMPUTE_UNUSED(info);
172     ARM_COMPUTE_ERROR_ON_UNCONFIGURED_KERNEL(this);
173     ARM_COMPUTE_ERROR_ON_INVALID_SUBWINDOW(INEKernel::window(), window);
174 
175     switch(_anchors->info()->data_type())
176     {
177         case DataType::QSYMM16:
178         {
179             internal_run<int16_t>(window);
180             break;
181         }
182 #ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
183         case DataType::F16:
184         {
185             internal_run<float16_t>(window);
186             break;
187         }
188 #endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
189         case DataType::F32:
190         {
191             internal_run<float>(window);
192             break;
193         }
194         default:
195         {
196             ARM_COMPUTE_ERROR("Data type not supported");
197         }
198     }
199 }
200 } // namespace arm_compute
201