aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIsabella Gottardi <isabella.gottardi@arm.com>2017-06-23 15:02:11 +0100
committerAnthony Barbier <anthony.barbier@arm.com>2018-09-17 14:16:08 +0100
commitb797fa235f714440ffa7a2ad4eef7ae14ee45da4 (patch)
treeefdefae2963d612c1bb1f84b8b74823c64804702
parentac4e873dad6aa6291fc36aff62047a896db04f6a (diff)
downloadComputeLibrary-b797fa235f714440ffa7a2ad4eef7ae14ee45da4.tar.gz
COMPMID-424 - Implemented reference implementation and tests (NEON and CL) for TableLookup
Change-Id: I53098ee750ab07fe64e9e2af8df91954d64017f5 Reviewed-on: http://mpd-gerrit.cambridge.arm.com/79411 Tested-by: Kaizen <jeremy.johnson+kaizengerrit@arm.com> Reviewed-by: Steven Niu <steven.niu@arm.com>
-rwxr-xr-xscripts/check_clang-tidy.py3
-rw-r--r--tests/CL/CLLutAccessor.h95
-rw-r--r--tests/ILutAccessor.h68
-rw-r--r--tests/NEON/NELutAccessor.h90
-rw-r--r--tests/RawLutAccessor.h73
-rw-r--r--tests/validation/CL/TableLookup.cpp230
-rw-r--r--tests/validation/Helpers.h21
-rw-r--r--tests/validation/NEON/TableLookup.cpp230
-rw-r--r--tests/validation/Reference.cpp27
-rw-r--r--tests/validation/Reference.h11
-rw-r--r--tests/validation/ReferenceCPP.cpp15
-rw-r--r--tests/validation/ReferenceCPP.h14
-rw-r--r--tests/validation/TensorOperations.h10
-rw-r--r--tests/validation/TensorVisitors.h29
14 files changed, 903 insertions, 13 deletions
diff --git a/scripts/check_clang-tidy.py b/scripts/check_clang-tidy.py
index 237ed541f4..b24f5f7f8f 100755
--- a/scripts/check_clang-tidy.py
+++ b/scripts/check_clang-tidy.py
@@ -1,5 +1,6 @@
#!/usr/bin/env python3
+import re
import sys
if __name__ == "__main__":
@@ -40,8 +41,10 @@ if __name__ == "__main__":
("Validation.cpp" in line and "parameter 'expected_labels' is unused" in line) or
("Reference.cpp" in line and "parameter 'rois' is unused" in line) or
("Reference.cpp" in line and "parameter 'shapes' is unused" in line) or
+ ("Reference.cpp" in line and re.search(r"parameter '[^']+' is unused", line)) or
("ReferenceCPP.cpp" in line and "parameter 'rois' is unused" in line) or
("ReferenceCPP.cpp" in line and "parameter 'srcs' is unused" in line) or
+ ("ReferenceCPP.cpp" in line and re.search(r"parameter '[^']+' is unused", line)) or
("NEGEMMMatrixMultiplyKernel.cpp" in line and "do not use C-style cast to convert between unrelated types" in line) or
"3rdparty" in line):
continue
diff --git a/tests/CL/CLLutAccessor.h b/tests/CL/CLLutAccessor.h
new file mode 100644
index 0000000000..49bd12f327
--- /dev/null
+++ b/tests/CL/CLLutAccessor.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2017 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_TEST_CL_CLLUTACCESSOR_H__
+#define __ARM_COMPUTE_TEST_CL_CLLUTACCESSOR_H__
+
+#include "ILutAccessor.h"
+
+#include "arm_compute/runtime/CL/CLLut.h"
+
+namespace arm_compute
+{
+namespace test
+{
+namespace cl
+{
+/** Accessor implementation for @ref CLLut objects. */
+template <typename T>
+class CLLutAccessor : public ILutAccessor<T>
+{
+public:
+ /** Create an accessor for the given @p CLLut.
+ */
+ CLLutAccessor(CLLut &lut)
+ : _lut{ lut }
+ {
+ _lut.map(true);
+ }
+ ~CLLutAccessor()
+ {
+ _lut.unmap();
+ }
+
+ CLLutAccessor(const CLLutAccessor &) = delete;
+ CLLutAccessor &operator=(const CLLutAccessor &) = delete;
+ CLLutAccessor(CLLutAccessor &&) = default;
+ CLLutAccessor &operator=(CLLutAccessor &&) = default;
+
+ int num_elements() const override
+ {
+ return _lut.num_elements();
+ }
+
+ const T &operator[](T input_value) const override
+ {
+ auto lut = reinterpret_cast<T *>(_lut.buffer());
+ int32_t real_index = _lut.index_offset() + static_cast<int32_t>(input_value);
+
+ if(0 <= real_index && real_index < num_elements())
+ {
+ return lut[real_index];
+ }
+ ARM_COMPUTE_ERROR("Error index not in range.");
+ }
+
+ T &operator[](T input_value) override
+ {
+ auto lut = reinterpret_cast<T *>(_lut.buffer());
+ int32_t real_index = _lut.index_offset() + static_cast<int32_t>(input_value);
+
+ if(0 <= real_index && real_index < num_elements())
+ {
+ return lut[real_index];
+ }
+ ARM_COMPUTE_ERROR("Error index not in range.");
+ }
+
+private:
+ CLLut &_lut;
+};
+
+} // namespace cl
+} // namespace test
+} // namespace arm_compute
+#endif /* __ARM_COMPUTE_TEST_CL_CLLUTACCESSOR_H__ */
diff --git a/tests/ILutAccessor.h b/tests/ILutAccessor.h
new file mode 100644
index 0000000000..6431ed141f
--- /dev/null
+++ b/tests/ILutAccessor.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2017 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_TEST_ILUTACCESSOR_H__
+#define __ARM_COMPUTE_TEST_ILUTACCESSOR_H__
+
+#include "arm_compute/core/Coordinates.h"
+#include "arm_compute/core/Types.h"
+
+namespace arm_compute
+{
+namespace test
+{
+/** Common interface to provide information and access to Lut like
+ * structures.
+ */
+template <typename T>
+class ILutAccessor
+{
+public:
+ using value_type = T;
+
+ /** Pure virtual destructor. */
+ virtual ~ILutAccessor() = default;
+
+ /** Number of elements of the Lut. */
+ virtual int num_elements() const = 0;
+
+ /** Read access to the specified element.
+ *
+ * @param[in] input_value Lut input value, from numericlimits<T>:min to numericlimits<T>:max.
+ *
+ * @return Output desired element.
+ */
+ virtual const T &operator[](T input_value) const = 0;
+
+ /** Write access to the specified element.
+ *
+ * @param[in] input_value Lut input value, from numericlimits<T>:min to numericlimits<T>:max.
+ *
+ * @return Output desired element.
+ */
+ virtual T &operator[](T input_value) = 0;
+};
+
+} // namespace test
+} // namespace arm_compute
+#endif /* __ARM_COMPUTE_TEST_ILUTACCESSOR_H__ */
diff --git a/tests/NEON/NELutAccessor.h b/tests/NEON/NELutAccessor.h
new file mode 100644
index 0000000000..2dadcf5996
--- /dev/null
+++ b/tests/NEON/NELutAccessor.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2017 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_TEST_NEON_NELUTACCESSOR_H__
+#define __ARM_COMPUTE_TEST_NEON_NELUTACCESSOR_H__
+
+#include "ILutAccessor.h"
+
+#include "arm_compute/runtime/Lut.h"
+
+namespace arm_compute
+{
+namespace test
+{
+namespace neon
+{
+/** Accessor implementation for @ref Lut objects. */
+template <typename T>
+class NELutAccessor : public ILutAccessor<T>
+{
+public:
+ /** Create an accessor for the given @p Lut.
+ */
+ NELutAccessor(Lut &lut)
+ : _lut{ lut }
+ {
+ }
+
+ NELutAccessor(const NELutAccessor &) = delete;
+ NELutAccessor &operator=(const NELutAccessor &) = delete;
+ NELutAccessor(NELutAccessor &&) = default;
+ NELutAccessor &operator=(NELutAccessor &&) = default;
+
+ int num_elements() const override
+ {
+ return _lut.num_elements();
+ }
+
+ const T &operator[](T input_value) const override
+ {
+ auto lut = reinterpret_cast<T *>(_lut.buffer());
+ int32_t real_index = _lut.index_offset() + static_cast<int32_t>(input_value);
+
+ if(0 <= real_index && real_index < num_elements())
+ {
+ return lut[real_index];
+ }
+ ARM_COMPUTE_ERROR("Error index not in range.");
+ }
+
+ T &operator[](T input_value) override
+ {
+ auto lut = reinterpret_cast<T *>(_lut.buffer());
+ int32_t real_index = _lut.index_offset() + static_cast<int32_t>(input_value);
+
+ if(0 <= real_index && real_index < num_elements())
+ {
+ return lut[real_index];
+ }
+ ARM_COMPUTE_ERROR("Error index not in range.");
+ }
+
+private:
+ ILut &_lut;
+};
+
+} // namespace neon
+} // namespace test
+} // namespace arm_compute
+#endif /* __ARM_COMPUTE_TEST_NEON_NELUTACCESSOR_H__ */
diff --git a/tests/RawLutAccessor.h b/tests/RawLutAccessor.h
new file mode 100644
index 0000000000..61b3194523
--- /dev/null
+++ b/tests/RawLutAccessor.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2017 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_TEST_RAWLUTACCESSOR_H__
+#define __ARM_COMPUTE_TEST_RAWLUTACCESSOR_H__
+
+#include "ILutAccessor.h"
+
+#include <map>
+
+namespace arm_compute
+{
+namespace test
+{
+/** Accessor implementation for std::map-lut objects. */
+template <typename T>
+class RawLutAccessor : public ILutAccessor<T>
+{
+public:
+ /** Create an accessor for the given @p std::map.
+ */
+ RawLutAccessor(std::map<T, T> &lut)
+ : _lut{ lut }
+ {
+ }
+
+ RawLutAccessor(const RawLutAccessor &) = delete;
+ RawLutAccessor &operator=(const RawLutAccessor &) = delete;
+ RawLutAccessor(RawLutAccessor &&) = default;
+ RawLutAccessor &operator=(RawLutAccessor &&) = default;
+
+ int num_elements() const override
+ {
+ return _lut.size();
+ }
+
+ const T &operator[](T input_value) const override
+ {
+ return _lut[input_value];
+ }
+
+ T &operator[](T input_value) override
+ {
+ return _lut[input_value];
+ }
+
+private:
+ std::map<T, T> &_lut;
+};
+
+} // namespace test
+} // namespace arm_compute
+#endif /* __ARM_COMPUTE_TEST_RAWLUTACCESSOR_H__ */
diff --git a/tests/validation/CL/TableLookup.cpp b/tests/validation/CL/TableLookup.cpp
new file mode 100644
index 0000000000..d3062259d8
--- /dev/null
+++ b/tests/validation/CL/TableLookup.cpp
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2017 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 "CL/CLAccessor.h"
+#include "CL/CLLutAccessor.h"
+#include "Globals.h"
+#include "PaddingCalculator.h"
+#include "RawLutAccessor.h"
+#include "TensorLibrary.h"
+#include "TypePrinter.h"
+#include "Utils.h"
+#include "validation/Datasets.h"
+#include "validation/Helpers.h"
+#include "validation/Reference.h"
+#include "validation/Validation.h"
+
+#include "arm_compute/core/Helpers.h"
+#include "arm_compute/core/Types.h"
+#include "arm_compute/runtime/CL/CLTensor.h"
+#include "arm_compute/runtime/CL/CLTensorAllocator.h"
+#include "arm_compute/runtime/CL/functions/CLTableLookup.h"
+
+#include "boost_wrapper.h"
+
+#include <map>
+#include <random>
+#include <string>
+
+using namespace arm_compute;
+using namespace arm_compute::test;
+using namespace arm_compute::test::cl;
+using namespace arm_compute::test::validation;
+
+namespace
+{
+/** Compute Table Lookup function.
+ *
+ * @param[in] shape Shape of the input tensors
+ * @param[in] data_type Type of the input/output tensor
+ * @param[in] lut The input LUT.
+ *
+ * @return Computed output cl tensor.
+ */
+CLTensor compute_table_lookup(const TensorShape &shape, DataType data_type, CLLut &lut)
+{
+ // Create tensors
+ CLTensor src = create_tensor<CLTensor>(shape, data_type);
+ CLTensor dst = create_tensor<CLTensor>(shape, data_type);
+
+ // Create and configure function
+ CLTableLookup table_lookup;
+ table_lookup.configure(&src, &lut, &dst);
+
+ // Allocate tensors
+ src.allocator()->allocate();
+ dst.allocator()->allocate();
+
+ BOOST_TEST(!src.info()->is_resizable());
+ BOOST_TEST(!dst.info()->is_resizable());
+
+ // Fill tensors
+ library->fill_tensor_uniform(CLAccessor(src), 0);
+
+ // Compute function
+ table_lookup.run();
+
+ return dst;
+}
+} // namespace
+
+#ifndef DOXYGEN_SKIP_THIS
+BOOST_AUTO_TEST_SUITE(CL)
+BOOST_AUTO_TEST_SUITE(TableLookup)
+
+BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly"))
+BOOST_DATA_TEST_CASE(Configuration, (SmallShapes() + LargeShapes()) * boost::unit_test::data::make({ DataType::U8, DataType::S16 }),
+ shape, data_type)
+{
+ //Create Lut
+ const int num_elem = (data_type == DataType::U8) ? std::numeric_limits<uint8_t>::max() + 1 : std::numeric_limits<int16_t>::max() - std::numeric_limits<int16_t>::lowest() + 1;
+ CLLut cllut(num_elem, data_type);
+
+ if(data_type == DataType::U8)
+ {
+ fill_lookuptable(CLLutAccessor<uint8_t>(cllut));
+ }
+ else
+ {
+ fill_lookuptable(CLLutAccessor<int16_t>(cllut));
+ }
+
+ // Create tensors
+ CLTensor src = create_tensor<CLTensor>(shape, data_type);
+ CLTensor dst = create_tensor<CLTensor>(shape, data_type);
+
+ BOOST_TEST(src.info()->is_resizable());
+ BOOST_TEST(dst.info()->is_resizable());
+
+ // Create and configure function
+ CLTableLookup table_lookup;
+ table_lookup.configure(&src, &cllut, &dst);
+
+ // Validate valid region
+ const ValidRegion valid_region = shape_to_valid_region(shape);
+ validate(src.info()->valid_region(), valid_region);
+ validate(dst.info()->valid_region(), valid_region);
+
+ // Validate padding
+ const PaddingSize padding = PaddingCalculator(shape.x(), 8).required_padding();
+ validate(src.info()->padding(), padding);
+ validate(dst.info()->padding(), padding);
+}
+
+BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit"))
+BOOST_DATA_TEST_CASE(RunSmall,
+ SmallShapes() * boost::unit_test::data::make({ DataType::U8, DataType::S16 }),
+ shape, data_type)
+{
+ //Create Lut
+ const int num_elem = (data_type == DataType::U8) ? std::numeric_limits<uint8_t>::max() + 1 : std::numeric_limits<int16_t>::max() - std::numeric_limits<int16_t>::lowest() + 1;
+ CLLut cllut(num_elem, data_type);
+
+ if(data_type == DataType::U8)
+ {
+ //Create rawLut
+ std::map<uint8_t, uint8_t> rawlut;
+
+ //Fill the Lut
+ fill_lookuptable(CLLutAccessor<uint8_t>(cllut));
+ fill_lookuptable(RawLutAccessor<uint8_t>(rawlut));
+
+ // Compute function
+ CLTensor dst = compute_table_lookup(shape, data_type, cllut);
+
+ // Compute reference
+ RawTensor ref_dst = Reference::compute_reference_table_lookup(shape, data_type, rawlut);
+
+ // Validate output
+ validate(CLAccessor(dst), ref_dst);
+ }
+ else
+ {
+ //Create rawLut
+ std::map<int16_t, int16_t> rawlut;
+
+ //Fill the Lut
+ fill_lookuptable(CLLutAccessor<int16_t>(cllut));
+ fill_lookuptable(RawLutAccessor<int16_t>(rawlut));
+
+ // Compute function
+ CLTensor dst = compute_table_lookup(shape, data_type, cllut);
+
+ // Compute reference
+ RawTensor ref_dst = Reference::compute_reference_table_lookup(shape, data_type, rawlut);
+
+ // Validate output
+ validate(CLAccessor(dst), ref_dst);
+ }
+}
+
+BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly"))
+BOOST_DATA_TEST_CASE(RunLarge,
+ LargeShapes() * boost::unit_test::data::make({ DataType::U8, DataType::S16 }),
+ shape, data_type)
+{
+ //Create Lut
+ const int num_elem = (data_type == DataType::U8) ? std::numeric_limits<uint8_t>::max() + 1 : std::numeric_limits<int16_t>::max() - std::numeric_limits<int16_t>::lowest() + 1;
+ CLLut cllut(num_elem, data_type);
+
+ if(data_type == DataType::U8)
+ {
+ //Create rawLut
+ std::map<uint8_t, uint8_t> rawlut;
+
+ //Fill the Lut
+ fill_lookuptable(CLLutAccessor<uint8_t>(cllut));
+ fill_lookuptable(RawLutAccessor<uint8_t>(rawlut));
+
+ // Compute function
+ CLTensor dst = compute_table_lookup(shape, data_type, cllut);
+
+ // Compute reference
+ RawTensor ref_dst = Reference::compute_reference_table_lookup(shape, data_type, rawlut);
+
+ // Validate output
+ validate(CLAccessor(dst), ref_dst);
+ }
+ else
+ {
+ //Create rawLut
+ std::map<int16_t, int16_t> rawlut;
+
+ //Fill the Lut
+ fill_lookuptable(CLLutAccessor<int16_t>(cllut));
+ fill_lookuptable(RawLutAccessor<int16_t>(rawlut));
+
+ // Compute function
+ CLTensor dst = compute_table_lookup(shape, data_type, cllut);
+
+ // Compute reference
+ RawTensor ref_dst = Reference::compute_reference_table_lookup(shape, data_type, rawlut);
+
+ // Validate output
+ validate(CLAccessor(dst), ref_dst);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+BOOST_AUTO_TEST_SUITE_END()
+#endif /* DOXYGEN_SKIP_THIS */
diff --git a/tests/validation/Helpers.h b/tests/validation/Helpers.h
index cae1976bd6..4ee2112bcc 100644
--- a/tests/validation/Helpers.h
+++ b/tests/validation/Helpers.h
@@ -24,6 +24,7 @@
#ifndef __ARM_COMPUTE_TEST_VALIDATION_HELPERS_H__
#define __ARM_COMPUTE_TEST_VALIDATION_HELPERS_H__
+#include "ILutAccessor.h"
#include "Types.h"
#include "ValidationUserConfiguration.h"
@@ -210,7 +211,25 @@ inline TensorShape calculate_depth_concatenate_shape(std::vector<TensorShape> in
* @return A vector that contains the requested number of random ROIs
*/
std::vector<ROI> generate_random_rois(const TensorShape &shape, const ROIPoolingLayerInfo &pool_info, unsigned int num_rois, std::random_device::result_type seed);
+
+/** Helper function to fill the Lut random by a ILutAccessor.
+ *
+ * @param[in,out] table Accessor at the Lut.
+ *
+ */
+template <typename T>
+void fill_lookuptable(T &&table)
+{
+ std::mt19937 generator(user_config.seed.get());
+ std::uniform_int_distribution<typename T::value_type> distribution(std::numeric_limits<typename T::value_type>::min(), std::numeric_limits<typename T::value_type>::max());
+
+ for(int i = std::numeric_limits<typename T::value_type>::min(); i <= std::numeric_limits<typename T::value_type>::max(); i++)
+ {
+ table[i] = distribution(generator);
+ }
+}
+
} // namespace validation
} // namespace test
} // namespace arm_compute
-#endif //__ARM_COMPUTE_TEST_VALIDATION_HELPERS_H__
+#endif /* __ARM_COMPUTE_TEST_VALIDATION_HELPERS_H__ */
diff --git a/tests/validation/NEON/TableLookup.cpp b/tests/validation/NEON/TableLookup.cpp
new file mode 100644
index 0000000000..f8f56a6fab
--- /dev/null
+++ b/tests/validation/NEON/TableLookup.cpp
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2017 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 "Globals.h"
+#include "NEON/Helper.h"
+#include "NEON/NEAccessor.h"
+#include "NEON/NELutAccessor.h"
+#include "PaddingCalculator.h"
+#include "RawLutAccessor.h"
+#include "TensorLibrary.h"
+#include "TypePrinter.h"
+#include "Utils.h"
+#include "validation/Datasets.h"
+#include "validation/Helpers.h"
+#include "validation/Reference.h"
+#include "validation/Validation.h"
+
+#include "arm_compute/core/Helpers.h"
+#include "arm_compute/core/Types.h"
+#include "arm_compute/runtime/NEON/functions/NETableLookup.h"
+#include "arm_compute/runtime/Tensor.h"
+#include "arm_compute/runtime/TensorAllocator.h"
+
+#include "boost_wrapper.h"
+
+#include <random>
+#include <string>
+
+using namespace arm_compute;
+using namespace arm_compute::test;
+using namespace arm_compute::test::neon;
+using namespace arm_compute::test::validation;
+
+namespace
+{
+/** Compute Table Lookup function.
+ *
+ * @param[in] shape Shape of the input tensors
+ * @param[in] data_type Datatype of the input/output tensors
+ * @param[in] lut The input LUT.
+ *
+ * @return Computed output tensor.
+ */
+Tensor compute_table_lookup(const TensorShape &shape, DataType data_type, Lut &lut)
+{
+ // Create tensors
+ Tensor src = create_tensor<Tensor>(shape, data_type);
+ Tensor dst = create_tensor<Tensor>(shape, data_type);
+
+ // Create and configure function
+ NETableLookup table_lookup;
+ table_lookup.configure(&src, &lut, &dst);
+
+ // Allocate tensors
+ src.allocator()->allocate();
+ dst.allocator()->allocate();
+
+ BOOST_TEST(!src.info()->is_resizable());
+ BOOST_TEST(!dst.info()->is_resizable());
+
+ // Fill tensors
+ library->fill_tensor_uniform(NEAccessor(src), 0);
+
+ // Compute function
+ table_lookup.run();
+
+ return dst;
+}
+} // namespace
+
+#ifndef DOXYGEN_SKIP_THIS
+BOOST_AUTO_TEST_SUITE(NEON)
+BOOST_AUTO_TEST_SUITE(TableLookup)
+
+BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly"))
+BOOST_DATA_TEST_CASE(Configuration, (SmallShapes() + LargeShapes()) * boost::unit_test::data::make({ DataType::U8, DataType::S16 }),
+ shape, data_type)
+{
+ //Create Lut
+ const int num_elem = (data_type == DataType::U8) ? std::numeric_limits<uint8_t>::max() + 1 : std::numeric_limits<int16_t>::max() - std::numeric_limits<int16_t>::lowest() + 1;
+ Lut lut(num_elem, data_type);
+
+ if(data_type == DataType::U8)
+ {
+ fill_lookuptable(NELutAccessor<uint8_t>(lut));
+ }
+ else
+ {
+ fill_lookuptable(NELutAccessor<int16_t>(lut));
+ }
+
+ // Create tensors
+ Tensor src = create_tensor<Tensor>(shape, data_type);
+ Tensor dst = create_tensor<Tensor>(shape, data_type);
+
+ BOOST_TEST(src.info()->is_resizable());
+ BOOST_TEST(dst.info()->is_resizable());
+
+ // Create and configure function
+ NETableLookup table_lookup;
+ table_lookup.configure(&src, &lut, &dst);
+
+ // Validate valid region
+ const ValidRegion valid_region = shape_to_valid_region(shape);
+ validate(src.info()->valid_region(), valid_region);
+ validate(dst.info()->valid_region(), valid_region);
+
+ // Validate padding
+ const PaddingSize padding = PaddingCalculator(shape.x(), 16).required_padding();
+ validate(src.info()->padding(), padding);
+ validate(dst.info()->padding(), padding);
+}
+
+BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit"))
+BOOST_DATA_TEST_CASE(RunSmall,
+ SmallShapes() * boost::unit_test::data::make({ DataType::U8, DataType::S16 }),
+ shape, data_type)
+{
+ //Create Lut
+ const int num_elem = (data_type == DataType::U8) ? std::numeric_limits<uint8_t>::max() + 1 : std::numeric_limits<int16_t>::max() - std::numeric_limits<int16_t>::lowest() + 1;
+ Lut lut(num_elem, data_type);
+
+ if(data_type == DataType::U8)
+ {
+ //Create rawLut
+ std::map<uint8_t, uint8_t> rawlut;
+
+ //Fill the Lut
+ fill_lookuptable(NELutAccessor<uint8_t>(lut));
+ fill_lookuptable(RawLutAccessor<uint8_t>(rawlut));
+
+ // Compute function
+ Tensor dst = compute_table_lookup(shape, data_type, lut);
+
+ // Compute reference
+ RawTensor ref_dst = Reference::compute_reference_table_lookup(shape, data_type, rawlut);
+
+ // Validate output
+ validate(NEAccessor(dst), ref_dst);
+ }
+ else
+ {
+ //Create rawLut
+ std::map<int16_t, int16_t> rawlut;
+
+ //Fill the Lut
+ fill_lookuptable(NELutAccessor<int16_t>(lut));
+ fill_lookuptable(RawLutAccessor<int16_t>(rawlut));
+
+ // Compute function
+ Tensor dst = compute_table_lookup(shape, data_type, lut);
+
+ // Compute reference
+ RawTensor ref_dst = Reference::compute_reference_table_lookup(shape, data_type, rawlut);
+
+ // Validate output
+ validate(NEAccessor(dst), ref_dst);
+ }
+}
+
+BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly"))
+BOOST_DATA_TEST_CASE(RunLarge,
+ LargeShapes() * boost::unit_test::data::make({ DataType::U8, DataType::S16 }),
+ shape, data_type)
+{
+ //Create Lut
+ const int num_elem = (data_type == DataType::U8) ? std::numeric_limits<uint8_t>::max() + 1 : std::numeric_limits<int16_t>::max() - std::numeric_limits<int16_t>::lowest() + 1;
+ Lut lut(num_elem, data_type);
+
+ if(data_type == DataType::U8)
+ {
+ //Create rawLut
+ std::map<uint8_t, uint8_t> rawlut;
+
+ //Fill the Lut
+ fill_lookuptable(NELutAccessor<uint8_t>(lut));
+ fill_lookuptable(RawLutAccessor<uint8_t>(rawlut));
+
+ // Compute function
+ Tensor dst = compute_table_lookup(shape, data_type, lut);
+
+ // Compute reference
+ RawTensor ref_dst = Reference::compute_reference_table_lookup(shape, data_type, rawlut);
+
+ // Validate output
+ validate(NEAccessor(dst), ref_dst);
+ }
+ else
+ {
+ //Create rawLut
+ std::map<int16_t, int16_t> rawlut;
+
+ //Fill the Lut
+ fill_lookuptable(NELutAccessor<int16_t>(lut));
+ fill_lookuptable(RawLutAccessor<int16_t>(rawlut));
+
+ // Compute function
+ Tensor dst = compute_table_lookup(shape, data_type, lut);
+
+ // Compute reference
+ RawTensor ref_dst = Reference::compute_reference_table_lookup(shape, data_type, rawlut);
+
+ // Validate output
+ validate(NEAccessor(dst), ref_dst);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+BOOST_AUTO_TEST_SUITE_END()
+#endif /* DOXYGEN_SKIP_THIS */
diff --git a/tests/validation/Reference.cpp b/tests/validation/Reference.cpp
index 857dd7c741..0a57fc0ea5 100644
--- a/tests/validation/Reference.cpp
+++ b/tests/validation/Reference.cpp
@@ -34,6 +34,7 @@
using namespace arm_compute::test;
+#ifndef DOXYGEN_SKIP_THIS
namespace arm_compute
{
namespace test
@@ -407,17 +408,34 @@ RawTensor Reference::compute_reference_fixed_point_pixel_wise_multiplication(con
return ref_dst;
}
+template <typename T>
+RawTensor Reference::compute_reference_table_lookup(const TensorShape &shape, DataType dt_inout, std::map<T, T> &lut)
+{
+ // Create reference
+ RawTensor ref_src = library->get(shape, dt_inout);
+ RawTensor ref_dst = library->get(shape, dt_inout);
+ // Fill reference
+ library->fill_tensor_uniform(ref_src, 0);
+
+ // Compute reference
+ ReferenceCPP::table_lookup(ref_src, ref_dst, lut);
+
+ return ref_dst;
+}
+template RawTensor arm_compute::test::validation::Reference::compute_reference_table_lookup<uint8_t>(const TensorShape &shape, DataType dt_inout, std::map<uint8_t, uint8_t> &lut);
+template RawTensor arm_compute::test::validation::Reference::compute_reference_table_lookup<int16_t>(const TensorShape &shape, DataType dt_inout, std::map<int16_t, int16_t> &lut);
+
RawTensor Reference::compute_reference_threshold(const TensorShape &shape, uint8_t threshold, uint8_t false_value, uint8_t true_value, ThresholdType type, uint8_t upper)
{
// Create reference
- RawTensor ref_src1 = library->get(shape, DataType::U8);
- RawTensor ref_dst = library->get(shape, DataType::U8);
+ RawTensor ref_src = library->get(shape, DataType::U8);
+ RawTensor ref_dst = library->get(shape, DataType::U8);
// Fill reference
- library->fill_tensor_uniform(ref_src1, 0);
+ library->fill_tensor_uniform(ref_src, 0);
// Compute reference
- ReferenceCPP::threshold(ref_src1, ref_dst, threshold, false_value, true_value, type, upper);
+ ReferenceCPP::threshold(ref_src, ref_dst, threshold, false_value, true_value, type, upper);
return ref_dst;
}
@@ -746,3 +764,4 @@ RawTensor Reference::compute_reference_fixed_point_operation(const TensorShape &
} // namespace validation
} // namespace test
} // namespace arm_compute
+#endif /* DOXYGEN_SKIP_THIS */
diff --git a/tests/validation/Reference.h b/tests/validation/Reference.h
index 37a072b60a..902d04d151 100644
--- a/tests/validation/Reference.h
+++ b/tests/validation/Reference.h
@@ -27,6 +27,7 @@
#include "RawTensor.h"
#include "Types.h"
+#include <map>
#include <vector>
namespace arm_compute
@@ -251,6 +252,16 @@ public:
*/
static RawTensor compute_reference_fixed_point_pixel_wise_multiplication(const TensorShape &shape, DataType dt_in0, DataType dt_in1, DataType dt_out, float scale, int fixed_point_position,
ConvertPolicy convert_policy, RoundingPolicy rounding_policy);
+ /** Compute reference Table Lookup.
+ *
+ * @param[in] shape Shape of the input and output tensors.
+ * @param[in] dt_inout Data type of input/output tensor.
+ * @param[in] lut Input lookup table.
+ *
+ * @return Computed raw tensor.
+ */
+ template <typename T>
+ static RawTensor compute_reference_table_lookup(const TensorShape &shape, DataType dt_inout, std::map<T, T> &lut);
/** Compute reference threshold.
*
* @param[in] shape Shape of the input and output tensors.
diff --git a/tests/validation/ReferenceCPP.cpp b/tests/validation/ReferenceCPP.cpp
index 105bfc4b6c..0db0352863 100644
--- a/tests/validation/ReferenceCPP.cpp
+++ b/tests/validation/ReferenceCPP.cpp
@@ -254,13 +254,26 @@ void ReferenceCPP::fixed_point_pixel_wise_multiplication(const RawTensor &src1,
boost::apply_visitor(tensor_visitors::fixed_point_pixel_wise_multiplication_visitor(s1, s2, scale, convert_policy, rounding_policy), d);
}
+// Table lookup
+template <typename T>
+void ReferenceCPP::table_lookup(const RawTensor &src, RawTensor &dst, std::map<T, T> &lut)
+{
+ const TensorVariant s = TensorFactory::get_tensor(src);
+ TensorVariant d = TensorFactory::get_tensor(dst);
+ boost::apply_visitor(tensor_visitors::table_lookup<T>(s, lut), d);
+}
+#ifndef DOXYGEN_SKIP_THIS
+template void arm_compute::test::validation::ReferenceCPP::table_lookup<uint8_t>(const RawTensor &src, RawTensor &dst, std::map<uint8_t, uint8_t> &lut);
+template void arm_compute::test::validation::ReferenceCPP::table_lookup<int16_t>(const RawTensor &src, RawTensor &dst, std::map<int16_t, int16_t> &lut);
+#endif /* DOXYGEN_SKIP_THIS */
+
// Threshold
void ReferenceCPP::threshold(const RawTensor &src, RawTensor &dst, uint8_t threshold, uint8_t false_value, uint8_t true_value, ThresholdType type, uint8_t upper)
{
ARM_COMPUTE_ERROR_ON(src.data_type() != DataType::U8 || dst.data_type() != DataType::U8);
const Tensor<uint8_t> s(src.shape(), src.data_type(), src.fixed_point_position(), reinterpret_cast<const uint8_t *>(src.data()));
Tensor<uint8_t> d(dst.shape(), dst.data_type(), dst.fixed_point_position(), reinterpret_cast<uint8_t *>(dst.data()));
- threshold_operation(s, d, threshold, false_value, true_value, type, upper);
+ tensor_operations::threshold(s, d, threshold, false_value, true_value, type, upper);
}
// Activation layer
diff --git a/tests/validation/ReferenceCPP.h b/tests/validation/ReferenceCPP.h
index d3c77a2243..8a5d853806 100644
--- a/tests/validation/ReferenceCPP.h
+++ b/tests/validation/ReferenceCPP.h
@@ -24,10 +24,10 @@
#ifndef __ARM_COMPUTE_TEST_REFERENCE_REFERENCE_CPP_H__
#define __ARM_COMPUTE_TEST_REFERENCE_REFERENCE_CPP_H__
-#include "Reference.h"
-
#include "RawTensor.h"
+#include "Reference.h"
+#include <map>
#include <memory>
#include <ostream>
#include <vector>
@@ -223,9 +223,17 @@ public:
* @param[in] rounding_policy Rounding policy.
*/
static void fixed_point_pixel_wise_multiplication(const RawTensor &src1, const RawTensor &src2, RawTensor &dst, float scale, ConvertPolicy convert_policy, RoundingPolicy rounding_policy);
+ /** Table Lookup f@p src to @p dst
+ *
+ * @param[in] src Input tensor.
+ * @param[out] dst Result tensor.
+ * @param[in] lut Input lookup table.
+ */
+ template <typename T>
+ static void table_lookup(const RawTensor &src, RawTensor &dst, std::map<T, T> &lut);
/** Threshold of@p src to @p dst
*
- * @param[in] src First tensor.
+ * @param[in] src Input tensor.
* @param[out] dst Result tensor.
* @param[in] threshold Threshold. When the threhold type is RANGE, this is used as the lower threshold.
* @param[in] false_value value to set when the condition is not respected.
diff --git a/tests/validation/TensorOperations.h b/tests/validation/TensorOperations.h
index bf9bceff0a..e2747249b4 100644
--- a/tests/validation/TensorOperations.h
+++ b/tests/validation/TensorOperations.h
@@ -808,6 +808,16 @@ void fixed_point_pixel_wise_multiplication(const Tensor<T> &in1, const Tensor<T>
}
}
+//Table Lookup
+template <typename T, typename T1>
+void table_lookup(const Tensor<T> &in, Tensor<T> &out, std::map<T1, T1> &lut)
+{
+ for(int i = 0; i < in.num_elements(); ++i)
+ {
+ out[i] = static_cast<T>(lut[in[i]]);
+ }
+}
+
// Threshold
template <typename T>
void threshold(const Tensor<T> &in, Tensor<T> &out, uint8_t threshold, uint8_t false_value, uint8_t true_value, ThresholdType type, uint8_t upper)
diff --git a/tests/validation/TensorVisitors.h b/tests/validation/TensorVisitors.h
index fcc584dd46..c58b9a69c0 100644
--- a/tests/validation/TensorVisitors.h
+++ b/tests/validation/TensorVisitors.h
@@ -27,10 +27,12 @@
#include "Tensor.h"
#include "TensorOperations.h"
#include "arm_compute/core/Error.h"
+#include "arm_compute/runtime/Lut.h"
#include "boost_wrapper.h"
#include <algorithm>
+#include <map>
#include <memory>
#include <ostream>
#include <vector>
@@ -180,11 +182,30 @@ private:
ConvertPolicy _convert_policy;
RoundingPolicy _rounding_policy;
};
-// Threshold operation
-void threshold_operation(const Tensor<uint8_t> &in, Tensor<uint8_t> &out, uint8_t threshold, uint8_t false_value, uint8_t true_value, ThresholdType type, uint8_t upper)
+// Table lookup operation
+template <typename T1>
+struct table_lookup : public boost::static_visitor<>
{
- tensor_operations::threshold(in, out, threshold, false_value, true_value, type, upper);
-}
+public:
+ explicit table_lookup(const TensorVariant &in, std::map<T1, T1> &lut)
+ : _in(in), _lut(lut)
+ {
+ }
+
+ template <typename T>
+ void operator()(Tensor<T> &out) const
+ {
+ const auto &in = boost::get<Tensor<T>>(_in);
+ tensor_operations::table_lookup(in, out, _lut);
+ }
+
+private:
+ const TensorVariant &_in;
+ std::map<T1, T1> &_lut;
+};
+template struct arm_compute::test::validation::tensor_visitors::table_lookup<uint8_t>;
+template struct arm_compute::test::validation::tensor_visitors::table_lookup<int16_t>;
+
// Activation layer visitor
struct activation_layer_visitor : public boost::static_visitor<>
{