diff options
author | Michele Di Giorgio <michele.digiorgio@arm.com> | 2017-07-04 17:19:43 +0100 |
---|---|---|
committer | Anthony Barbier <anthony.barbier@arm.com> | 2018-09-17 14:16:42 +0100 |
commit | ef4b4ae784f7533ed6d9e7b51827a894c32ed48e (patch) | |
tree | 6f4268044be18c003f5136b8ef7c7c07e219f2bd /src/core/NEON/kernels | |
parent | f87cc7f6fef95f9b022725304118796a6a764a7c (diff) | |
download | ComputeLibrary-ef4b4ae784f7533ed6d9e7b51827a894c32ed48e.tar.gz |
COMPMID-438: Add support for floating point Min-Max Location layer.
Change-Id: I84ae564a40fc7320a6f94a84d53906ba51404f51
Reviewed-on: http://mpd-gerrit.cambridge.arm.com/79797
Reviewed-by: Anthony Barbier <anthony.barbier@arm.com>
Tested-by: Kaizen <jeremy.johnson+kaizengerrit@arm.com>
Diffstat (limited to 'src/core/NEON/kernels')
-rw-r--r-- | src/core/NEON/kernels/NEMinMaxLocationKernel.cpp | 141 |
1 files changed, 114 insertions, 27 deletions
diff --git a/src/core/NEON/kernels/NEMinMaxLocationKernel.cpp b/src/core/NEON/kernels/NEMinMaxLocationKernel.cpp index 1e41ddcf80..a6da7f415d 100644 --- a/src/core/NEON/kernels/NEMinMaxLocationKernel.cpp +++ b/src/core/NEON/kernels/NEMinMaxLocationKernel.cpp @@ -41,14 +41,14 @@ namespace arm_compute { NEMinMaxKernel::NEMinMaxKernel() - : _func(), _input(nullptr), _min(), _max(), _min_init(), _max_init(), _mtx() + : _func(), _input(nullptr), _min(), _max(), _mtx() { } -void NEMinMaxKernel::configure(const IImage *input, int32_t *min, int32_t *max) +void NEMinMaxKernel::configure(const IImage *input, void *min, void *max) { ARM_COMPUTE_ERROR_ON_TENSOR_NOT_2D(input); - ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::U8, DataType::S16); + ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::U8, DataType::S16, DataType::F32); ARM_COMPUTE_ERROR_ON(nullptr == min); ARM_COMPUTE_ERROR_ON(nullptr == max); @@ -56,20 +56,19 @@ void NEMinMaxKernel::configure(const IImage *input, int32_t *min, int32_t *max) _min = min; _max = max; - switch(input->info()->format()) + switch(_input->info()->data_type()) { - case Format::U8: - _min_init = UCHAR_MAX; - _max_init = 0; - _func = &NEMinMaxKernel::minmax_U8; + case DataType::U8: + _func = &NEMinMaxKernel::minmax_U8; break; - case Format::S16: - _min_init = SHRT_MAX; - _max_init = SHRT_MIN; - _func = &NEMinMaxKernel::minmax_S16; + case DataType::S16: + _func = &NEMinMaxKernel::minmax_S16; + break; + case DataType::F32: + _func = &NEMinMaxKernel::minmax_F32; break; default: - ARM_COMPUTE_ERROR("You called with the wrong img formats"); + ARM_COMPUTE_ERROR("Unsupported data type"); break; } @@ -93,8 +92,24 @@ void NEMinMaxKernel::run(const Window &window) void NEMinMaxKernel::reset() { ARM_COMPUTE_ERROR_ON_UNCONFIGURED_KERNEL(this); - *_min = _min_init; - *_max = _max_init; + switch(_input->info()->data_type()) + { + case DataType::U8: + *static_cast<int32_t *>(_min) = UCHAR_MAX; + *static_cast<int32_t *>(_max) = 0; + break; + case DataType::S16: + *static_cast<int32_t *>(_min) = SHRT_MAX; + *static_cast<int32_t *>(_max) = SHRT_MIN; + break; + case DataType::F32: + *static_cast<float *>(_min) = std::numeric_limits<float>::max(); + *static_cast<float *>(_max) = std::numeric_limits<float>::lowest(); + break; + default: + ARM_COMPUTE_ERROR("Unsupported data type"); + break; + } } template <typename T> @@ -102,14 +117,19 @@ void NEMinMaxKernel::update_min_max(const T min, const T max) { std::lock_guard<std::mutex> lock(_mtx); - if(min < *_min) + using type = typename std::conditional<std::is_same<T, float>::value, float, int32_t>::type; + + auto min_ptr = static_cast<type *>(_min); + auto max_ptr = static_cast<type *>(_max); + + if(min < *min_ptr) { - *_min = min; + *min_ptr = min; } - if(max > *_max) + if(max > *max_ptr) { - *_max = max; + *max_ptr = max; } } @@ -229,6 +249,65 @@ void NEMinMaxKernel::minmax_S16(Window win) update_min_max(min_i, max_i); } +void NEMinMaxKernel::minmax_F32(Window win) +{ + float32x2_t carry_min = vdup_n_f32(std::numeric_limits<float>::max()); + float32x2_t carry_max = vdup_n_f32(std::numeric_limits<float>::lowest()); + + float carry_min_scalar = std::numeric_limits<float>::max(); + float carry_max_scalar = std::numeric_limits<float>::lowest(); + + const int x_start = win.x().start(); + const int x_end = win.x().end(); + + // Handle X dimension manually to split into two loops + // First one will use vector operations, second one processes the left over pixels + win.set(Window::DimX, Window::Dimension(0, 1, 1)); + + Iterator input(_input, win); + + execute_window_loop(win, [&](const Coordinates & id) + { + int x = x_start; + const auto in_ptr = reinterpret_cast<const float *const>(input.ptr()); + + // Vector loop + for(; x <= x_end - 8; x += 8) + { + const float32x4x2_t pixels = vld2q_f32(in_ptr + x); + const float32x4_t tmp_min1 = vminq_f32(pixels.val[0], pixels.val[1]); + const float32x4_t tmp_max1 = vmaxq_f32(pixels.val[0], pixels.val[1]); + const float32x2_t tmp_min2 = vmin_f32(vget_high_f32(tmp_min1), vget_low_f32(tmp_min1)); + const float32x2_t tmp_max2 = vmax_f32(vget_high_f32(tmp_max1), vget_low_f32(tmp_max1)); + carry_min = vmin_f32(tmp_min2, carry_min); + carry_max = vmax_f32(tmp_max2, carry_max); + } + + // Process leftover pixels + for(; x < x_end; ++x) + { + const float pixel = in_ptr[x]; + carry_min_scalar = std::min(pixel, carry_min_scalar); + carry_max_scalar = std::max(pixel, carry_max_scalar); + } + + }, + input); + + // Reduce result + carry_min = vpmin_f32(carry_min, carry_min); + carry_max = vpmax_f32(carry_max, carry_max); + carry_min = vpmin_f32(carry_min, carry_min); + carry_max = vpmax_f32(carry_max, carry_max); + + // Extract max/min values + const float min_i = std::min(vget_lane_f32(carry_min, 0), carry_min_scalar); + const float max_i = std::max(vget_lane_f32(carry_max, 0), carry_max_scalar); + + // Perform reduction of local min/max values + update_min_max(min_i, max_i); +} + NEMinMaxLocationKernel::NEMinMaxLocationKernel() : _func(nullptr), _input(nullptr), _min(nullptr), _max(nullptr), _min_count(nullptr), _max_count(nullptr), _min_loc(nullptr), _max_loc(nullptr) { @@ -271,12 +350,12 @@ const NEMinMaxLocationKernel::MinMaxLocFunction NEMinMaxLocationKernel::create_f &NEMinMaxLocationKernel::minmax_loc<T, bool(N & 8), bool(N & 4), bool(N & 2), bool(N & 1)>... }; -void NEMinMaxLocationKernel::configure(const IImage *input, int32_t *min, int32_t *max, +void NEMinMaxLocationKernel::configure(const IImage *input, void *min, void *max, ICoordinates2DArray *min_loc, ICoordinates2DArray *max_loc, uint32_t *min_count, uint32_t *max_count) { ARM_COMPUTE_ERROR_ON_TENSOR_NOT_2D(input); - ARM_COMPUTE_ERROR_ON_FORMAT_NOT_IN(input, Format::U8, Format::S16); + ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::U8, DataType::S16, DataType::F32); ARM_COMPUTE_ERROR_ON(nullptr == min); ARM_COMPUTE_ERROR_ON(nullptr == max); @@ -295,16 +374,19 @@ void NEMinMaxLocationKernel::configure(const IImage *input, int32_t *min, int32_ unsigned int table_idx = (count_min << 3) | (count_max << 2) | (loc_min << 1) | loc_max; - switch(input->info()->format()) + switch(input->info()->data_type()) { - case Format::U8: + case DataType::U8: _func = create_func_table<uint8_t, gen_index_seq<16>::type>::func_table[table_idx]; break; - case Format::S16: + case DataType::S16: _func = create_func_table<int16_t, gen_index_seq<16>::type>::func_table[table_idx]; break; + case DataType::F32: + _func = create_func_table<float, gen_index_seq<16>::type>::func_table[table_idx]; + break; default: - ARM_COMPUTE_ERROR("You called with the wrong img formats"); + ARM_COMPUTE_ERROR("Unsupported data type"); break; } @@ -349,6 +431,11 @@ void NEMinMaxLocationKernel::minmax_loc(const Window &win) _max_loc->clear(); } + using type = typename std::conditional<std::is_same<T, float>::value, float, int32_t>::type; + + auto min_ptr = static_cast<type *>(_min); + auto max_ptr = static_cast<type *>(_max); + execute_window_loop(win, [&](const Coordinates & id) { auto in_ptr = reinterpret_cast<const T *>(input.ptr()); @@ -360,7 +447,7 @@ void NEMinMaxLocationKernel::minmax_loc(const Window &win) if(count_min || loc_min) { - if(*_min == pixel) + if(*min_ptr == pixel) { if(count_min) { @@ -376,7 +463,7 @@ void NEMinMaxLocationKernel::minmax_loc(const Window &win) if(count_max || loc_max) { - if(*_max == pixel) + if(*max_ptr == pixel) { if(count_max) { |