From 1bf5e289ec08c6eb507c079fd16c877559b45684 Mon Sep 17 00:00:00 2001 From: giuros01 Date: Fri, 21 Dec 2018 14:57:48 +0000 Subject: COMPMID-1765: CPP: Implement TopKV Change-Id: Ib113f19e3e9ad1f2a3084df25eae38c0131df02d Reviewed-on: https://review.mlplatform.org/439 Reviewed-by: Manuel Bottini Reviewed-by: Michele Di Giorgio Tested-by: Arm Jenkins --- arm_compute/core/CPP/CPPKernels.h | 3 +- arm_compute/core/CPP/kernels/CPPTopKVKernel.h | 92 ++++++++++++ arm_compute/runtime/CPP/CPPFunctions.h | 3 +- arm_compute/runtime/CPP/functions/CPPTopKV.h | 60 ++++++++ src/core/CPP/kernels/CPPTopKVKernel.cpp | 152 ++++++++++++++++++++ src/runtime/CPP/functions/CPPTopKV.cpp | 42 ++++++ tests/validation/CPP/TopKV.cpp | 194 ++++++++++++++++++++++++++ 7 files changed, 544 insertions(+), 2 deletions(-) create mode 100644 arm_compute/core/CPP/kernels/CPPTopKVKernel.h create mode 100644 arm_compute/runtime/CPP/functions/CPPTopKV.h create mode 100644 src/core/CPP/kernels/CPPTopKVKernel.cpp create mode 100644 src/runtime/CPP/functions/CPPTopKV.cpp create mode 100644 tests/validation/CPP/TopKV.cpp diff --git a/arm_compute/core/CPP/CPPKernels.h b/arm_compute/core/CPP/CPPKernels.h index 39b77cde45..70d858220f 100644 --- a/arm_compute/core/CPP/CPPKernels.h +++ b/arm_compute/core/CPP/CPPKernels.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018 ARM Limited. + * Copyright (c) 2017-2019 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -31,6 +31,7 @@ #include "arm_compute/core/CPP/kernels/CPPFlipWeightsKernel.h" #include "arm_compute/core/CPP/kernels/CPPPermuteKernel.h" #include "arm_compute/core/CPP/kernels/CPPSortEuclideanDistanceKernel.h" +#include "arm_compute/core/CPP/kernels/CPPTopKVKernel.h" #include "arm_compute/core/CPP/kernels/CPPUpsampleKernel.h" #endif /* __ARM_COMPUTE_CPPKERNELS_H__ */ diff --git a/arm_compute/core/CPP/kernels/CPPTopKVKernel.h b/arm_compute/core/CPP/kernels/CPPTopKVKernel.h new file mode 100644 index 0000000000..8d2456f30f --- /dev/null +++ b/arm_compute/core/CPP/kernels/CPPTopKVKernel.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2019 ARM Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef __ARM_COMPUTE_CPPTOPKVERNEL_H__ +#define __ARM_COMPUTE_CPPTOPKVERNEL_H__ + +#include "arm_compute/core/CPP/ICPPKernel.h" + +namespace arm_compute +{ +class ITensor; + +/** CPP kernel to perform tensor TopKV operation. */ +class CPPTopKVKernel : public ICPPKernel +{ +public: + const char *name() const override + { + return "CPPTopKVKernel"; + } + /** Default constructor */ + CPPTopKVKernel(); + /** Prevent instances of this class from being copied (As this class contains pointers) */ + CPPTopKVKernel(const CPPTopKVKernel &) = delete; + /** Prevent instances of this class from being copied (As this class contains pointers) */ + CPPTopKVKernel &operator=(const CPPTopKVKernel &) = delete; + /** Allow instances of this class to be moved */ + CPPTopKVKernel(CPPTopKVKernel &&) = default; + /** Allow instances of this class to be moved */ + CPPTopKVKernel &operator=(CPPTopKVKernel &&) = default; + /** Default destructor */ + ~CPPTopKVKernel() = default; + + /** Set the input and output of the kernel. + * + * @param[in] predictions A batch_size x classes tensor. Data types supported: F16/S32/F32/QASYMM8 + * @param[in] targets A batch_size 1D tensor of class ids. Data types supported: S32 + * @param[out] output Computed precision at @p k as a bool 1D tensor. Data types supported: U8 + * @param[in] k Number of top elements to look at for computing precision. + */ + void configure(const ITensor *predictions, const ITensor *targets, ITensor *output, const unsigned int k); + + /** Static function to check if given info will lead to a valid configuration of @ref CPPTopKVKernel + * + * @param[in] predictions A batch_size x classes tensor info. Data types supported: F16/S32/F32/QASYMM8 + * @param[in] targets A batch_size 1D tensor info of class ids. Data types supported: S32 + * @param[in] output Computed precision at @p k as a bool 1D tensor info. Data types supported: U8 + * @param[in] k Number of top elements to look at for computing precision. + * + * @return a status + */ + static Status validate(const ITensorInfo *predictions, const ITensorInfo *targets, ITensorInfo *output, const unsigned int k); + + // Inherited methods overridden: + void run(const Window &window, const ThreadInfo &info) override; + bool is_parallelisable() const override; + +private: + /** Template function to run the topKV operation. */ + template + void run_topkv(); + + const ITensor *_predictions; + const ITensor *_targets; + ITensor *_output; + + unsigned int _k; + unsigned int _batch_size; + unsigned int _num_classes; +}; +} // namespace arm_compute +#endif /*__ARM_COMPUTE_CPPTOPKVKERNEL_H__ */ diff --git a/arm_compute/runtime/CPP/CPPFunctions.h b/arm_compute/runtime/CPP/CPPFunctions.h index 63df437d11..4bb668fc83 100644 --- a/arm_compute/runtime/CPP/CPPFunctions.h +++ b/arm_compute/runtime/CPP/CPPFunctions.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018 ARM Limited. + * Copyright (c) 2017-2019 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -28,6 +28,7 @@ #include "arm_compute/runtime/CPP/functions/CPPBoxWithNonMaximaSuppressionLimit.h" #include "arm_compute/runtime/CPP/functions/CPPDetectionOutputLayer.h" #include "arm_compute/runtime/CPP/functions/CPPPermute.h" +#include "arm_compute/runtime/CPP/functions/CPPTopKV.h" #include "arm_compute/runtime/CPP/functions/CPPUpsample.h" #endif /* __ARM_COMPUTE_CPPFUNCTIONS_H__ */ diff --git a/arm_compute/runtime/CPP/functions/CPPTopKV.h b/arm_compute/runtime/CPP/functions/CPPTopKV.h new file mode 100644 index 0000000000..10917be97c --- /dev/null +++ b/arm_compute/runtime/CPP/functions/CPPTopKV.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2019 ARM Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef __ARM_COMPUTE_CPPTOPKV_H__ +#define __ARM_COMPUTE_CPPTOPKV_H__ + +#include "arm_compute/runtime/CPP/ICPPSimpleFunction.h" + +#include "arm_compute/core/Types.h" + +namespace arm_compute +{ +class ITensor; + +/** Basic function to run @ref CPPTopKVKernel */ +class CPPTopKV : public ICPPSimpleFunction +{ +public: + /** Set the input and output of the kernel. + * + * @param[in] predictions A batch_size x classes tensor. Data types supported: F16/S32/F32/QASYMM8 + * @param[in] targets A batch_size 1D tensor of class ids. Data types supported: S32 + * @param[out] output Computed precision at @p k as a bool 1D tensor. Data types supported: U8 + * @param[in] k Number of top elements to look at for computing precision. + */ + void configure(const ITensor *predictions, const ITensor *targets, ITensor *output, const unsigned int k); + + /** Static function to check if given info will lead to a valid configuration of @ref CPPTopKVKernel + * + * @param[in] predictions A batch_size x classes tensor info. Data types supported: F16/S32/F32/QASYMM8 + * @param[in] targets A batch_size 1D tensor info of class ids. Data types supported: S32 + * @param[in] output Computed precision at @p k as a bool 1D tensor info. Data types supported: U8 + * @param[in] k Number of top elements to look at for computing precision. + * + * @return a status + */ + static Status validate(const ITensorInfo *predictions, const ITensorInfo *targets, ITensorInfo *output, const unsigned int k); +}; +} // namespace arm_compute +#endif /* __ARM_COMPUTE_CPPTOPKV_H__ */ diff --git a/src/core/CPP/kernels/CPPTopKVKernel.cpp b/src/core/CPP/kernels/CPPTopKVKernel.cpp new file mode 100644 index 0000000000..533543a988 --- /dev/null +++ b/src/core/CPP/kernels/CPPTopKVKernel.cpp @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2019 ARM Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "arm_compute/core/CPP/kernels/CPPTopKVKernel.h" +#include "arm_compute/core/Coordinates.h" +#include "arm_compute/core/Error.h" +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/TensorInfo.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/core/Utils.h" +#include "arm_compute/core/Validate.h" +#include "arm_compute/core/Window.h" +#include "arm_compute/core/utils/misc/Traits.h" + +namespace arm_compute +{ +namespace +{ +template ::value, int>::type = 0> +inline bool greater_than(T a, T b) +{ + const T epsilon = std::numeric_limits::epsilon(); + return (a - b > epsilon); +} + +template < typename T, + typename std::enable_if < !utils::traits::is_floating_point::value, int >::type = 0 > +inline bool greater_than(T a, T b) +{ + return (a > b); +} + +Status validate_arguments(const ITensorInfo *predictions, const ITensorInfo *targets, ITensorInfo *output, const unsigned int k) +{ + ARM_COMPUTE_UNUSED(k); + ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(predictions, 1, DataType::QASYMM8, DataType::S32, DataType::F16, DataType::F32); + ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(targets, 1, DataType::U32); + + ARM_COMPUTE_RETURN_ERROR_ON(predictions->num_dimensions() > 2); + ARM_COMPUTE_RETURN_ERROR_ON(targets->num_dimensions() > 1); + ARM_COMPUTE_RETURN_ERROR_ON(targets->dimension(0) != predictions->dimension(1)); + // Validate configured output + if(output->total_size() != 0) + { + ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DIMENSIONS(output->tensor_shape(), targets->tensor_shape()); + ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(output, 1, DataType::U8); + } + + return Status{}; +} +} // namespace + +template +void CPPTopKVKernel::run_topkv() +{ + for(unsigned int i = 0; i < _batch_size; ++i) + { + const auto target_class_id = *reinterpret_cast(_targets->ptr_to_element(Coordinates{ i })); + const auto predicted_value = *reinterpret_cast(_predictions->ptr_to_element(Coordinates{ target_class_id, i })); + + // The variable rank indicates how many values there are before the target_class_id + unsigned int rank = 0; + for(unsigned int j = 0; (j < _num_classes) && (rank < _k); ++j) + { + const auto current_prediction = *reinterpret_cast(_predictions->ptr_to_element(Coordinates{ j, i })); + if(greater_than(current_prediction, predicted_value)) + { + rank++; + } + } + *(_output->ptr_to_element(Coordinates{ i })) = static_cast(rank < _k); + } +} + +CPPTopKVKernel::CPPTopKVKernel() + : _predictions(nullptr), _targets(nullptr), _output(nullptr), _k(), _batch_size(), _num_classes() +{ +} + +void CPPTopKVKernel::configure(const ITensor *predictions, const ITensor *targets, ITensor *output, const unsigned int k) +{ + ARM_COMPUTE_ERROR_ON_NULLPTR(predictions, targets, output); + + // Perform validation step + ARM_COMPUTE_ERROR_THROW_ON(validate_arguments(predictions->info(), targets->info(), output->info(), k)); + auto_init_if_empty(*output->info(), targets->info()->tensor_shape(), 1, DataType::U8); + + _predictions = predictions; + _targets = targets; + _output = output; + + _k = k; + _batch_size = predictions->info()->dimension(1); + _num_classes = predictions->info()->dimension(0); + + ICPPKernel::configure(Window()); // Default 1 iteration window +} + +Status CPPTopKVKernel::validate(const ITensorInfo *predictions, const ITensorInfo *targets, ITensorInfo *output, const unsigned int k) +{ + ARM_COMPUTE_RETURN_ON_ERROR(validate_arguments(predictions, targets, output, k)); + return Status{}; +} + +bool CPPTopKVKernel::is_parallelisable() const +{ + return false; +} + +void CPPTopKVKernel::run(const Window &window, const ThreadInfo &info) +{ + ARM_COMPUTE_UNUSED(window, info); + switch(_predictions->info()->data_type()) + { + case DataType::F32: + run_topkv(); + break; + case DataType::F16: + run_topkv(); + break; + case DataType::S32: + run_topkv(); + break; + case DataType::QASYMM8: + run_topkv(); + break; + default: + ARM_COMPUTE_ERROR("Not supported"); + } +} +} // namespace arm_compute diff --git a/src/runtime/CPP/functions/CPPTopKV.cpp b/src/runtime/CPP/functions/CPPTopKV.cpp new file mode 100644 index 0000000000..c4e1eab16a --- /dev/null +++ b/src/runtime/CPP/functions/CPPTopKV.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2019 ARM Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "arm_compute/runtime/CPP/functions/CPPTopKV.h" + +#include "arm_compute/core/CPP/kernels/CPPTopKVKernel.h" +#include "support/ToolchainSupport.h" + +namespace arm_compute +{ +void CPPTopKV::configure(const ITensor *predictions, const ITensor *targets, ITensor *output, const unsigned int k) +{ + auto kernel = arm_compute::support::cpp14::make_unique(); + kernel->configure(predictions, targets, output, k); + _kernel = std::move(kernel); +} + +Status CPPTopKV::validate(const ITensorInfo *predictions, const ITensorInfo *targets, ITensorInfo *output, const unsigned int k) +{ + return CPPTopKVKernel::validate(predictions, targets, output, k); +} +} // namespace arm_compute diff --git a/tests/validation/CPP/TopKV.cpp b/tests/validation/CPP/TopKV.cpp new file mode 100644 index 0000000000..ee11cbc54c --- /dev/null +++ b/tests/validation/CPP/TopKV.cpp @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2019 ARM Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/CPP/functions/CPPTopKV.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" +#include "tests/NEON/Accessor.h" +#include "tests/PaddingCalculator.h" +#include "tests/datasets/ShapeDatasets.h" +#include "tests/framework/Asserts.h" +#include "tests/framework/Macros.h" +#include "tests/framework/datasets/Datasets.h" +#include "tests/validation/Validation.h" +#include "tests/validation/fixtures/PermuteFixture.h" + +namespace arm_compute +{ +namespace test +{ +namespace validation +{ +namespace +{ +template +inline void fill_tensor(U &&tensor, const std::vector &v) +{ + std::memcpy(tensor.data(), v.data(), sizeof(T) * v.size()); +} +} // namespace + +TEST_SUITE(CPP) +TEST_SUITE(TopKV) + +// *INDENT-OFF* +// clang-format off +DATA_TEST_CASE(Validate, framework::DatasetMode::ALL, zip(zip(zip(zip( + framework::dataset::make("PredictionsInfo", { TensorInfo(TensorShape(20, 10), 1, DataType::F32), + TensorInfo(TensorShape(10, 20), 1, DataType::F16), // Mismatching batch_size + TensorInfo(TensorShape(20, 10), 1, DataType::S8), // Unsupported data type + TensorInfo(TensorShape(10, 10, 10), 1, DataType::F32), // Wrong predictions dimensions + TensorInfo(TensorShape(20, 10), 1, DataType::F32)}), // Wrong output dimension + framework::dataset::make("TargetsInfo",{ TensorInfo(TensorShape(10), 1, DataType::U32), + TensorInfo(TensorShape(10), 1, DataType::U32), + TensorInfo(TensorShape(10), 1, DataType::U32), + TensorInfo(TensorShape(10), 1, DataType::U32), + TensorInfo(TensorShape(10), 1, DataType::U32)})), + framework::dataset::make("OutputInfo",{ TensorInfo(TensorShape(10), 1, DataType::U8), + TensorInfo(TensorShape(10), 1, DataType::U8), + TensorInfo(TensorShape(10), 1, DataType::U8), + TensorInfo(TensorShape(10), 1, DataType::U8), + TensorInfo(TensorShape(1), 1, DataType::U8)})), + + framework::dataset::make("k",{ 0, 1, 2, 3, 4 })), + framework::dataset::make("Expected", {true, false, false, false, false })), + prediction_info, targets_info, output_info, k, expected) +{ + const Status status = CPPTopKV::validate(&prediction_info.clone()->set_is_resizable(false),&targets_info.clone()->set_is_resizable(false), &output_info.clone()->set_is_resizable(false), k); + ARM_COMPUTE_EXPECT(bool(status) == expected, framework::LogLevel::ERRORS); +} +// clang-format on +// *INDENT-ON* + +TEST_CASE(Float, framework::DatasetMode::ALL) +{ + const unsigned int k = 5; + + Tensor predictions = create_tensor(TensorShape(10, 20), DataType::F32); + Tensor targets = create_tensor(TensorShape(20), DataType::U32); + + predictions.allocator()->allocate(); + targets.allocator()->allocate(); + + // Fill the tensors with random pre-generated values + fill_tensor(Accessor(predictions), std::vector + { + 0.8147, 0.6557, 0.4387, 0.7513, 0.3517, 0.1622, 0.1067, 0.8530, 0.7803, 0.5470, + 0.9058, 0.0357, 0.3816, 0.2551, 0.8308, 0.7943, 0.9619, 0.6221, 0.3897, 0.2963, + 0.1270, 0.8491, 0.7655, 0.5060, 0.5853, 0.3112, 0.0046, 0.3510, 0.2417, 0.7447, + 0.9134, 0.9340, 0.7952, 0.6991, 0.5497, 0.5285, 0.7749, 0.5132, 0.4039, 0.1890, + 0.6324, 0.6787, 0.1869, 0.8909, 0.9172, 0.1656, 0.8173, 0.4018, 0.0965, 0.6868, + 0.0975, 0.7577, 0.4898, 0.9593, 0.2858, 0.6020, 0.8687, 0.0760, 0.1320, 0.1835, + 0.2785, 0.7431, 0.4456, 0.5472, 0.7572, 0.2630, 0.0844, 0.2399, 0.9421, 0.3685, + 0.5469, 0.3922, 0.6463, 0.1386, 0.7537, 0.6541, 0.3998, 0.1233, 0.9561, 0.6256, + 0.9575, 0.6555, 0.7094, 0.1493, 0.3804, 0.6892, 0.2599, 0.1839, 0.5752, 0.7802, + 0.9649, 0.1712, 0.7547, 0.2575, 0.5678, 0.7482, 0.8001, 0.2400, 0.0598, 0.0811, + 0.1576, 0.7060, 0.2760, 0.8407, 0.0759, 0.4505, 0.4314, 0.4173, 0.2348, 0.9294, + 0.9706, 0.0318, 0.6797, 0.2543, 0.0540, 0.0838, 0.9106, 0.0497, 0.3532, 0.7757, + 0.9572, 0.2769, 0.6551, 0.8143, 0.5308, 0.2290, 0.1818, 0.9027, 0.8212, 0.4868, + 0.4854, 0.0462, 0.1626, 0.2435, 0.7792, 0.9133, 0.2638, 0.9448, 0.0154, 0.4359, + 0.8003, 0.0971, 0.1190, 0.9293, 0.9340, 0.1524, 0.1455, 0.4909, 0.0430, 0.4468, + 0.1419, 0.8235, 0.4984, 0.3500, 0.1299, 0.8258, 0.1361, 0.4893, 0.1690, 0.3063, + 0.4218, 0.6948, 0.9597, 0.1966, 0.5688, 0.5383, 0.8693, 0.3377, 0.6491, 0.5085, + 0.9157, 0.3171, 0.3404, 0.2511, 0.4694, 0.9961, 0.5797, 0.9001, 0.7317, 0.5108, + 0.7922, 0.9502, 0.5853, 0.6160, 0.0119, 0.0782, 0.5499, 0.3692, 0.6477, 0.8176, + 0.9595, 0.0344, 0.2238, 0.4733, 0.3371, 0.4427, 0.1450, 0.1112, 0.4509, 0.7948 + }); + + fill_tensor(Accessor(targets), std::vector { 1, 5, 7, 2, 8, 1, 2, 1, 2, 4, 3, 9, 4, 1, 9, 9, 4, 1, 2, 4 }); + + // Determine the output through the CPP kernel + Tensor output; + CPPTopKV topkv; + topkv.configure(&predictions, &targets, &output, k); + + output.allocator()->allocate(); + + // Run the kernel + topkv.run(); + + // Validate against the expected values + SimpleTensor expected_output(TensorShape(20), DataType::U8); + fill_tensor(expected_output, std::vector { 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1 }); + validate(Accessor(output), expected_output); +} + +TEST_CASE(Quantized, framework::DatasetMode::ALL) +{ + const unsigned int k = 5; + + Tensor predictions = create_tensor(TensorShape(10, 20), DataType::F32); + Tensor targets = create_tensor(TensorShape(20), DataType::U32); + + predictions.allocator()->allocate(); + targets.allocator()->allocate(); + + // Fill the tensors with random pre-generated values + fill_tensor(Accessor(predictions), std::vector + { + 133, 235, 69, 118, 140, 179, 189, 203, 137, 157, + 242, 1, 196, 170, 166, 25, 102, 244, 24, 254, + 164, 119, 49, 198, 140, 135, 175, 84, 29, 136, + 246, 109, 74, 90, 185, 136, 181, 172, 35, 123, + 62, 118, 24, 170, 134, 221, 114, 113, 174, 206, + 174, 198, 148, 107, 255, 125, 6, 214, 127, 59, + 75, 83, 175, 216, 56, 101, 85, 197, 49, 128, + 172, 201, 140, 214, 28, 172, 109, 43, 127, 231, + 178, 121, 109, 66, 29, 190, 70, 221, 38, 148, + 18, 10, 165, 158, 17, 134, 51, 254, 15, 217, + 66, 46, 166, 150, 104, 90, 211, 132, 218, 190, + 58, 185, 174, 139, 115, 39, 111, 227, 144, 151, + 171, 122, 163, 223, 94, 151, 228, 151, 238, 64, + 217, 40, 242, 68, 196, 68, 101, 40, 179, 171, + 89, 88, 54, 82, 161, 12, 197, 52, 150, 22, + 200, 156, 182, 31, 198, 194, 102, 105, 209, 161, + 173, 50, 61, 241, 239, 63, 207, 192, 226, 170, + 2, 190, 31, 166, 250, 114, 194, 212, 254, 187, + 155, 63, 156, 123, 50, 177, 97, 203, 1, 229, + 100, 235, 116, 164, 36, 92, 56, 82, 222, 252 + }); + + fill_tensor(Accessor(targets), std::vector { 1, 5, 7, 2, 8, 1, 2, 1, 2, 4, 3, 9, 4, 1, 9, 9, 4, 1, 2, 4 }); + + // Determine the output through the CPP kernel + Tensor output; + CPPTopKV topkv; + topkv.configure(&predictions, &targets, &output, k); + + output.allocator()->allocate(); + + // Run the kernel + topkv.run(); + + // Validate against the expected values + SimpleTensor expected_output(TensorShape(20), DataType::U8); + fill_tensor(expected_output, std::vector { 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0 }); + validate(Accessor(output), expected_output); +} + +TEST_SUITE_END() // TopKV +TEST_SUITE_END() // CPP +} // namespace validation +} // namespace test +} // namespace arm_compute -- cgit v1.2.1