From 45e5b5a4c6aa0e8dadf3c1d08031807eb0a1523b Mon Sep 17 00:00:00 2001 From: Pablo Marquez Tello Date: Mon, 4 Sep 2023 15:13:44 +0100 Subject: Changes to BoundingBoxTransform to enable fp16 in armv8a multi_isa builds * Code guarded with __ARM_FEATURE_FP16_VECTOR_ARITHMETIC needs to be moved to an fp16.cpp file to allow compilation with -march=armv8.2-a+fp16 * Partially resolves MLCE-1102 Change-Id: I04822b043d9f87bc666750a8d95a8be8a6cc194d Signed-off-by: Pablo Marquez Tello Reviewed-on: https://review.mlplatform.org/c/ml/ComputeLibrary/+/10239 Benchmark: Arm Jenkins Tested-by: Arm Jenkins Reviewed-by: Viet-Hoa Do Comments-Addressed: Arm Jenkins --- .../boundingboxtransform/generic/neon/impl.cpp | 60 ---------------------- .../boundingboxtransform/generic/neon/impl.h | 55 +++++++++++++++++++- 2 files changed, 53 insertions(+), 62 deletions(-) diff --git a/src/cpu/kernels/boundingboxtransform/generic/neon/impl.cpp b/src/cpu/kernels/boundingboxtransform/generic/neon/impl.cpp index d74a8a712d..b3ffd0a676 100644 --- a/src/cpu/kernels/boundingboxtransform/generic/neon/impl.cpp +++ b/src/cpu/kernels/boundingboxtransform/generic/neon/impl.cpp @@ -85,65 +85,5 @@ void bounding_box_transform_qsymm16(const ITensor *boxes, ITensor *pred_boxes, c }, box_it); } - -template -void bounding_box_transform(const ITensor *boxes, ITensor *pred_boxes, const ITensor *deltas, BoundingBoxTransformInfo bbinfo, const Window &window) -{ - const size_t num_classes = deltas->info()->tensor_shape()[0] >> 2; - const size_t deltas_width = deltas->info()->tensor_shape()[0]; - const int img_h = std::floor(bbinfo.img_height() / bbinfo.scale() + 0.5f); - const int img_w = std::floor(bbinfo.img_width() / bbinfo.scale() + 0.5f); - - const auto scale_after = (bbinfo.apply_scale() ? T(bbinfo.scale()) : T(1)); - const auto scale_before = T(bbinfo.scale()); - ARM_COMPUTE_ERROR_ON(scale_before <= 0); - const auto offset = (bbinfo.correct_transform_coords() ? T(1.f) : T(0.f)); - - auto pred_ptr = reinterpret_cast(pred_boxes->buffer() + pred_boxes->info()->offset_first_element_in_bytes()); - auto delta_ptr = reinterpret_cast(deltas->buffer() + deltas->info()->offset_first_element_in_bytes()); - - Iterator box_it(boxes, window); - execute_window_loop(window, [&](const Coordinates & id) - { - const auto ptr = reinterpret_cast(box_it.ptr()); - const auto b0 = *ptr; - const auto b1 = *(ptr + 1); - const auto b2 = *(ptr + 2); - const auto b3 = *(ptr + 3); - const T width = (b2 / scale_before) - (b0 / scale_before) + T(1.f); - const T height = (b3 / scale_before) - (b1 / scale_before) + T(1.f); - const T ctr_x = (b0 / scale_before) + T(0.5f) * width; - const T ctr_y = (b1 / scale_before) + T(0.5f) * height; - for(size_t j = 0; j < num_classes; ++j) - { - // Extract deltas - const size_t delta_id = id.y() * deltas_width + 4u * j; - const T dx = delta_ptr[delta_id] / T(bbinfo.weights()[0]); - const T dy = delta_ptr[delta_id + 1] / T(bbinfo.weights()[1]); - T dw = delta_ptr[delta_id + 2] / T(bbinfo.weights()[2]); - T dh = delta_ptr[delta_id + 3] / T(bbinfo.weights()[3]); - // Clip dw and dh - dw = std::min(dw, T(bbinfo.bbox_xform_clip())); - dh = std::min(dh, T(bbinfo.bbox_xform_clip())); - // Determine the predictions - const T pred_ctr_x = dx * width + ctr_x; - const T pred_ctr_y = dy * height + ctr_y; - const T pred_w = std::exp(dw) * width; - const T pred_h = std::exp(dh) * height; - // Store the prediction into the output tensor - pred_ptr[delta_id] = scale_after * utility::clamp(pred_ctr_x - T(0.5f) * pred_w, T(0), T(img_w - 1)); - pred_ptr[delta_id + 1] = scale_after * utility::clamp(pred_ctr_y - T(0.5f) * pred_h, T(0), T(img_h - 1)); - pred_ptr[delta_id + 2] = scale_after * utility::clamp(pred_ctr_x + T(0.5f) * pred_w - offset, T(0), T(img_w - 1)); - pred_ptr[delta_id + 3] = scale_after * utility::clamp(pred_ctr_y + T(0.5f) * pred_h - offset, T(0), T(img_h - 1)); - } - }, - box_it); -} - -template void bounding_box_transform(const ITensor *boxes, ITensor *pred_boxes, const ITensor *deltas, BoundingBoxTransformInfo bbinfo, const Window &window); - -#if defined(__ARM_FEATURE_FP16_VECTOR_ARITHMETIC) && defined(ENABLE_FP16_KERNELS) -template void bounding_box_transform(const ITensor *boxes, ITensor *pred_boxes, const ITensor *deltas, BoundingBoxTransformInfo bbinfo, const Window &window); -#endif //defined(__ARM_FEATURE_FP16_VECTOR_ARITHMETIC) && defined(ENABLE_FP16_KERNELS) } // namespace cpu } // namespace arm_compute diff --git a/src/cpu/kernels/boundingboxtransform/generic/neon/impl.h b/src/cpu/kernels/boundingboxtransform/generic/neon/impl.h index d9ff694ae5..7f990396df 100644 --- a/src/cpu/kernels/boundingboxtransform/generic/neon/impl.h +++ b/src/cpu/kernels/boundingboxtransform/generic/neon/impl.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Arm Limited. + * Copyright (c) 2022-2023 Arm Limited. * * SPDX-License-Identifier: MIT * @@ -30,7 +30,58 @@ namespace arm_compute namespace cpu { template -void bounding_box_transform(const ITensor *boxes, ITensor *pred_boxes, const ITensor *deltas, BoundingBoxTransformInfo bbinfo, const Window &window); +void bounding_box_transform(const ITensor *boxes, ITensor *pred_boxes, const ITensor *deltas, BoundingBoxTransformInfo bbinfo, const Window &window) +{ + const size_t num_classes = deltas->info()->tensor_shape()[0] >> 2; + const size_t deltas_width = deltas->info()->tensor_shape()[0]; + const int img_h = std::floor(bbinfo.img_height() / bbinfo.scale() + 0.5f); + const int img_w = std::floor(bbinfo.img_width() / bbinfo.scale() + 0.5f); + + const auto scale_after = (bbinfo.apply_scale() ? T(bbinfo.scale()) : T(1)); + const auto scale_before = T(bbinfo.scale()); + ARM_COMPUTE_ERROR_ON(scale_before <= 0); + const auto offset = (bbinfo.correct_transform_coords() ? T(1.f) : T(0.f)); + + auto pred_ptr = reinterpret_cast(pred_boxes->buffer() + pred_boxes->info()->offset_first_element_in_bytes()); + auto delta_ptr = reinterpret_cast(deltas->buffer() + deltas->info()->offset_first_element_in_bytes()); + + Iterator box_it(boxes, window); + execute_window_loop(window, [&](const Coordinates & id) + { + const auto ptr = reinterpret_cast(box_it.ptr()); + const auto b0 = *ptr; + const auto b1 = *(ptr + 1); + const auto b2 = *(ptr + 2); + const auto b3 = *(ptr + 3); + const T width = (b2 / scale_before) - (b0 / scale_before) + T(1.f); + const T height = (b3 / scale_before) - (b1 / scale_before) + T(1.f); + const T ctr_x = (b0 / scale_before) + T(0.5f) * width; + const T ctr_y = (b1 / scale_before) + T(0.5f) * height; + for(size_t j = 0; j < num_classes; ++j) + { + // Extract deltas + const size_t delta_id = id.y() * deltas_width + 4u * j; + const T dx = delta_ptr[delta_id] / T(bbinfo.weights()[0]); + const T dy = delta_ptr[delta_id + 1] / T(bbinfo.weights()[1]); + T dw = delta_ptr[delta_id + 2] / T(bbinfo.weights()[2]); + T dh = delta_ptr[delta_id + 3] / T(bbinfo.weights()[3]); + // Clip dw and dh + dw = std::min(dw, T(bbinfo.bbox_xform_clip())); + dh = std::min(dh, T(bbinfo.bbox_xform_clip())); + // Determine the predictions + const T pred_ctr_x = dx * width + ctr_x; + const T pred_ctr_y = dy * height + ctr_y; + const T pred_w = std::exp(dw) * width; + const T pred_h = std::exp(dh) * height; + // Store the prediction into the output tensor + pred_ptr[delta_id] = scale_after * utility::clamp(pred_ctr_x - T(0.5f) * pred_w, T(0), T(img_w - 1)); + pred_ptr[delta_id + 1] = scale_after * utility::clamp(pred_ctr_y - T(0.5f) * pred_h, T(0), T(img_h - 1)); + pred_ptr[delta_id + 2] = scale_after * utility::clamp(pred_ctr_x + T(0.5f) * pred_w - offset, T(0), T(img_w - 1)); + pred_ptr[delta_id + 3] = scale_after * utility::clamp(pred_ctr_y + T(0.5f) * pred_h - offset, T(0), T(img_h - 1)); + } + }, + box_it); +} void bounding_box_transform_qsymm16(const ITensor *boxes, ITensor *pred_boxes, const ITensor *deltas, BoundingBoxTransformInfo bbinfo, const Window &window); } // namespace cpu -- cgit v1.2.1