diff options
Diffstat (limited to 'tests/validation_old')
112 files changed, 22298 insertions, 0 deletions
diff --git a/tests/validation_old/AssetsLibrary.cpp b/tests/validation_old/AssetsLibrary.cpp new file mode 100644 index 0000000000..d7c881d9a8 --- /dev/null +++ b/tests/validation_old/AssetsLibrary.cpp @@ -0,0 +1,447 @@ +/* + * 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 "tests/AssetsLibrary.h" + +#include "TypePrinter.h" +#include "Utils.h" + +#include "arm_compute/core/ITensor.h" + +#include <cctype> +#include <fstream> +#include <limits> +#include <map> +#include <mutex> +#include <sstream> +#include <stdexcept> +#include <tuple> +#include <unordered_map> +#include <utility> + +namespace arm_compute +{ +namespace test +{ +namespace +{ +template <typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0> +void rgb_to_luminance(const RawTensor &src, RawTensor &dst) +{ + const size_t min_size = std::min(src.size(), dst.size()); + + for(size_t i = 0, j = 0; i < min_size; i += 3, ++j) + { + reinterpret_cast<T *>(dst.data())[j] = 0.2126f * src.data()[i + 0] + 0.7152f * src.data()[i + 1] + 0.0722f * src.data()[i + 2]; + } +} + +void extract_r_from_rgb(const RawTensor &src, RawTensor &dst) +{ + const size_t min_size = std::min(src.size(), dst.size()); + + for(size_t i = 0, j = 0; i < min_size; i += 3, ++j) + { + dst.data()[j] = src.data()[i]; + } +} + +void extract_g_from_rgb(const RawTensor &src, RawTensor &dst) +{ + const size_t min_size = std::min(src.size(), dst.size()); + + for(size_t i = 1, j = 0; i < min_size; i += 3, ++j) + { + dst.data()[j] = src.data()[i]; + } +} + +void discard_comments(std::ifstream &fs) +{ + while(fs.peek() == '#') + { + fs.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); + } +} + +void discard_comments_and_spaces(std::ifstream &fs) +{ + while(true) + { + discard_comments(fs); + + if(isspace(fs.peek()) == 0) + { + break; + } + + fs.ignore(1); + } +} + +std::tuple<unsigned int, unsigned int, int> parse_ppm_header(std::ifstream &fs) +{ + // Check the PPM magic number is valid + std::array<char, 2> magic_number{ { 0 } }; + fs >> magic_number[0] >> magic_number[1]; + + if(magic_number[0] != 'P' || magic_number[1] != '6') + { + throw std::runtime_error("Only raw PPM format is suported"); + } + + discard_comments_and_spaces(fs); + + unsigned int width = 0; + fs >> width; + + discard_comments_and_spaces(fs); + + unsigned int height = 0; + fs >> height; + + discard_comments_and_spaces(fs); + + int max_value = 0; + fs >> max_value; + + if(!fs.good()) + { + throw std::runtime_error("Cannot read image dimensions"); + } + + if(max_value != 255) + { + throw std::runtime_error("RawTensor doesn't have 8-bit values"); + } + + discard_comments(fs); + + if(isspace(fs.peek()) == 0) + { + throw std::runtime_error("Invalid PPM header"); + } + + fs.ignore(1); + + return std::make_tuple(width, height, max_value); +} + +RawTensor load_ppm(const std::string &path) +{ + std::ifstream file(path, std::ios::in | std::ios::binary); + + if(!file.good()) + { + throw std::runtime_error("Could not load PPM image: " + path); + } + + unsigned int width = 0; + unsigned int height = 0; + + std::tie(width, height, std::ignore) = parse_ppm_header(file); + + RawTensor raw(TensorShape(width, height), Format::RGB888); + + // Check if the file is large enough to fill the image + const size_t current_position = file.tellg(); + file.seekg(0, std::ios_base::end); + const size_t end_position = file.tellg(); + file.seekg(current_position, std::ios_base::beg); + + if((end_position - current_position) < raw.size()) + { + throw std::runtime_error("Not enough data in file"); + } + + file.read(reinterpret_cast<std::fstream::char_type *>(raw.data()), raw.size()); + + if(!file.good()) + { + throw std::runtime_error("Failure while reading image buffer"); + } + + return raw; +} +} // namespace + +AssetsLibrary::AssetsLibrary(std::string path, std::random_device::result_type seed) //NOLINT + : _library_path(std::move(path)), + _seed{ seed } +{ +} + +std::random_device::result_type AssetsLibrary::seed() const +{ + return _seed; +} + +void AssetsLibrary::fill(RawTensor &raw, const std::string &name, Format format) const +{ + //FIXME: Should be done by swapping cached buffers + const RawTensor &src = get(name, format); + std::copy_n(src.data(), raw.size(), raw.data()); +} + +void AssetsLibrary::fill(RawTensor &raw, const std::string &name, Channel channel) const +{ + fill(raw, name, get_format_for_channel(channel), channel); +} + +void AssetsLibrary::fill(RawTensor &raw, const std::string &name, Format format, Channel channel) const +{ + const RawTensor &src = get(name, format, channel); + std::copy_n(src.data(), raw.size(), raw.data()); +} + +const AssetsLibrary::Loader &AssetsLibrary::get_loader(const std::string &extension) const +{ + static std::unordered_map<std::string, Loader> loaders = + { + { "ppm", load_ppm } + }; + + const auto it = loaders.find(extension); + + if(it != loaders.end()) + { + return it->second; + } + else + { + throw std::invalid_argument("Cannot load image with extension '" + extension + "'"); + } +} + +const AssetsLibrary::Converter &AssetsLibrary::get_converter(Format src, Format dst) const +{ + static std::map<std::pair<Format, Format>, Converter> converters = + { + { std::make_pair(Format::RGB888, Format::U8), rgb_to_luminance<uint8_t> }, + { std::make_pair(Format::RGB888, Format::U16), rgb_to_luminance<uint16_t> }, + { std::make_pair(Format::RGB888, Format::S16), rgb_to_luminance<int16_t> }, + { std::make_pair(Format::RGB888, Format::U32), rgb_to_luminance<uint32_t> } + }; + + const auto it = converters.find(std::make_pair(src, dst)); + + if(it != converters.end()) + { + return it->second; + } + else + { + std::stringstream msg; + msg << "Cannot convert from format '" << src << "' to format '" << dst << "'\n"; + throw std::invalid_argument(msg.str()); + } +} + +const AssetsLibrary::Converter &AssetsLibrary::get_converter(DataType src, Format dst) const +{ + static std::map<std::pair<DataType, Format>, Converter> converters = {}; + + const auto it = converters.find(std::make_pair(src, dst)); + + if(it != converters.end()) + { + return it->second; + } + else + { + std::stringstream msg; + msg << "Cannot convert from data type '" << src << "' to format '" << dst << "'\n"; + throw std::invalid_argument(msg.str()); + } +} + +const AssetsLibrary::Converter &AssetsLibrary::get_converter(DataType src, DataType dst) const +{ + static std::map<std::pair<DataType, DataType>, Converter> converters = {}; + + const auto it = converters.find(std::make_pair(src, dst)); + + if(it != converters.end()) + { + return it->second; + } + else + { + std::stringstream msg; + msg << "Cannot convert from data type '" << src << "' to data type '" << dst << "'\n"; + throw std::invalid_argument(msg.str()); + } +} + +const AssetsLibrary::Converter &AssetsLibrary::get_converter(Format src, DataType dst) const +{ + static std::map<std::pair<Format, DataType>, Converter> converters = {}; + + const auto it = converters.find(std::make_pair(src, dst)); + + if(it != converters.end()) + { + return it->second; + } + else + { + std::stringstream msg; + msg << "Cannot convert from format '" << src << "' to data type '" << dst << "'\n"; + throw std::invalid_argument(msg.str()); + } +} + +const AssetsLibrary::Extractor &AssetsLibrary::get_extractor(Format format, Channel channel) const +{ + static std::map<std::pair<Format, Channel>, Extractor> extractors = + { + { std::make_pair(Format::RGB888, Channel::R), extract_r_from_rgb }, + { std::make_pair(Format::RGB888, Channel::G), extract_g_from_rgb } + }; + + const auto it = extractors.find(std::make_pair(format, channel)); + + if(it != extractors.end()) + { + return it->second; + } + else + { + std::stringstream msg; + msg << "Cannot extract channel '" << channel << "' from format '" << format << "'\n"; + throw std::invalid_argument(msg.str()); + } +} + +RawTensor AssetsLibrary::load_image(const std::string &name) const +{ +#ifdef _WIN32 + const std::string image_path = ("\\images\\"); +#else /* _WIN32 */ + const std::string image_path = ("/images/"); +#endif /* _WIN32 */ + + const std::string path = _library_path + image_path + name; + const std::string extension = path.substr(path.find_last_of('.') + 1); + return (*get_loader(extension))(path); +} + +const RawTensor &AssetsLibrary::find_or_create_raw_tensor(const std::string &name, Format format) const +{ + std::lock_guard<std::mutex> guard(_format_lock); + + const RawTensor *ptr = _cache.find(std::make_tuple(name, format)); + + if(ptr != nullptr) + { + return *ptr; + } + + RawTensor raw = load_image(name); + + if(raw.format() != format) + { + //FIXME: Remove unnecessary copy + RawTensor dst(raw.shape(), format); + (*get_converter(raw.format(), format))(raw, dst); + raw = std::move(dst); + } + + return _cache.add(std::make_tuple(name, format), std::move(raw)); +} + +const RawTensor &AssetsLibrary::find_or_create_raw_tensor(const std::string &name, Format format, Channel channel) const +{ + std::lock_guard<std::mutex> guard(_channel_lock); + + const RawTensor *ptr = _cache.find(std::make_tuple(name, format, channel)); + + if(ptr != nullptr) + { + return *ptr; + } + + const RawTensor &src = get(name, format); + //FIXME: Need to change shape to match channel + RawTensor dst(src.shape(), get_channel_format(channel)); + + (*get_extractor(format, channel))(src, dst); + + return _cache.add(std::make_tuple(name, format, channel), std::move(dst)); +} + +TensorShape AssetsLibrary::get_image_shape(const std::string &name) +{ + return load_image(name).shape(); +} + +const RawTensor &AssetsLibrary::get(const std::string &name) const +{ + //FIXME: Format should be derived from the image name. Not be fixed to RGB. + return find_or_create_raw_tensor(name, Format::RGB888); +} + +RawTensor AssetsLibrary::get(const std::string &name) +{ + //FIXME: Format should be derived from the image name. Not be fixed to RGB. + return RawTensor(find_or_create_raw_tensor(name, Format::RGB888)); +} + +RawTensor AssetsLibrary::get(const std::string &name, DataType data_type, int num_channels) const +{ + const RawTensor &raw = get(name); + + return RawTensor(raw.shape(), data_type, num_channels); +} + +const RawTensor &AssetsLibrary::get(const std::string &name, Format format) const +{ + return find_or_create_raw_tensor(name, format); +} + +RawTensor AssetsLibrary::get(const std::string &name, Format format) +{ + return RawTensor(find_or_create_raw_tensor(name, format)); +} + +const RawTensor &AssetsLibrary::get(const std::string &name, Channel channel) const +{ + return get(name, get_format_for_channel(channel), channel); +} + +RawTensor AssetsLibrary::get(const std::string &name, Channel channel) +{ + return RawTensor(get(name, get_format_for_channel(channel), channel)); +} + +const RawTensor &AssetsLibrary::get(const std::string &name, Format format, Channel channel) const +{ + return find_or_create_raw_tensor(name, format, channel); +} + +RawTensor AssetsLibrary::get(const std::string &name, Format format, Channel channel) +{ + return RawTensor(find_or_create_raw_tensor(name, format, channel)); +} +} // namespace test +} // namespace arm_compute diff --git a/tests/validation_old/AssetsLibrary.h b/tests/validation_old/AssetsLibrary.h new file mode 100644 index 0000000000..6945aa6fe1 --- /dev/null +++ b/tests/validation_old/AssetsLibrary.h @@ -0,0 +1,674 @@ +/* + * 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_TENSOR_LIBRARY_H__ +#define __ARM_COMPUTE_TEST_TENSOR_LIBRARY_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/TensorShape.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/core/Window.h" +#include "tests/RawTensor.h" +#include "tests/TensorCache.h" +#include "tests/Utils.h" +#include "tests/validation_old/half.h" + +#include <algorithm> +#include <cstddef> +#include <fstream> +#include <random> +#include <string> +#include <type_traits> + +namespace arm_compute +{ +namespace test +{ +/** Factory class to create and fill tensors. + * + * Allows to initialise tensors from loaded images or by specifying the shape + * explicitly. Furthermore, provides methods to fill tensors with the content of + * loaded images or with random values. + */ +class AssetsLibrary final +{ +public: + /** Initialises the library with a @p path to the image directory. + * Furthermore, sets the seed for the random generator to @p seed. + * + * @param[in] path Path to load images from. + * @param[in] seed Seed used to initialise the random number generator. + */ + AssetsLibrary(std::string path, std::random_device::result_type seed); + + /** Seed that is used to fill tensors with random values. */ + std::random_device::result_type seed() const; + + /** Provides a tensor shape for the specified image. + * + * @param[in] name Image file used to look up the raw tensor. + */ + TensorShape get_image_shape(const std::string &name); + + /** Provides a contant raw tensor for the specified image. + * + * @param[in] name Image file used to look up the raw tensor. + */ + const RawTensor &get(const std::string &name) const; + + /** Provides a raw tensor for the specified image. + * + * @param[in] name Image file used to look up the raw tensor. + */ + RawTensor get(const std::string &name); + + /** Creates an uninitialised raw tensor with the given @p data_type and @p + * num_channels. The shape is derived from the specified image. + * + * @param[in] name Image file used to initialise the tensor. + * @param[in] data_type Data type used to initialise the tensor. + * @param[in] num_channels Number of channels used to initialise the tensor. + */ + RawTensor get(const std::string &name, DataType data_type, int num_channels = 1) const; + + /** Provides a contant raw tensor for the specified image after it has been + * converted to @p format. + * + * @param[in] name Image file used to look up the raw tensor. + * @param[in] format Format used to look up the raw tensor. + */ + const RawTensor &get(const std::string &name, Format format) const; + + /** Provides a raw tensor for the specified image after it has been + * converted to @p format. + * + * @param[in] name Image file used to look up the raw tensor. + * @param[in] format Format used to look up the raw tensor. + */ + RawTensor get(const std::string &name, Format format); + + /** Provides a contant raw tensor for the specified channel after it has + * been extracted form the given image. + * + * @param[in] name Image file used to look up the raw tensor. + * @param[in] channel Channel used to look up the raw tensor. + * + * @note The channel has to be unambiguous so that the format can be + * inferred automatically. + */ + const RawTensor &get(const std::string &name, Channel channel) const; + + /** Provides a raw tensor for the specified channel after it has been + * extracted form the given image. + * + * @param[in] name Image file used to look up the raw tensor. + * @param[in] channel Channel used to look up the raw tensor. + * + * @note The channel has to be unambiguous so that the format can be + * inferred automatically. + */ + RawTensor get(const std::string &name, Channel channel); + + /** Provides a constant raw tensor for the specified channel after it has + * been extracted form the given image formatted to @p format. + * + * @param[in] name Image file used to look up the raw tensor. + * @param[in] format Format used to look up the raw tensor. + * @param[in] channel Channel used to look up the raw tensor. + */ + const RawTensor &get(const std::string &name, Format format, Channel channel) const; + + /** Provides a raw tensor for the specified channel after it has been + * extracted form the given image formatted to @p format. + * + * @param[in] name Image file used to look up the raw tensor. + * @param[in] format Format used to look up the raw tensor. + * @param[in] channel Channel used to look up the raw tensor. + */ + RawTensor get(const std::string &name, Format format, Channel channel); + + /** Puts garbage values all around the tensor for testing purposes + * + * @param[in, out] tensor To be filled tensor. + * @param[in] distribution Distribution used to fill the tensor's surroundings. + * @param[in] seed_offset The offset will be added to the global seed before initialising the random generator. + */ + template <typename T, typename D> + void fill_borders_with_garbage(T &&tensor, D &&distribution, std::random_device::result_type seed_offset) const; + + /** Fills the specified @p tensor with random values drawn from @p + * distribution. + * + * @param[in, out] tensor To be filled tensor. + * @param[in] distribution Distribution used to fill the tensor. + * @param[in] seed_offset The offset will be added to the global seed before initialising the random generator. + * + * @note The @p distribution has to provide operator(Generator &) which + * will be used to draw samples. + */ + template <typename T, typename D> + void fill(T &&tensor, D &&distribution, std::random_device::result_type seed_offset) const; + + /** Fills the specified @p raw tensor with random values drawn from @p + * distribution. + * + * @param[in, out] raw To be filled raw. + * @param[in] distribution Distribution used to fill the tensor. + * @param[in] seed_offset The offset will be added to the global seed before initialising the random generator. + * + * @note The @p distribution has to provide operator(Generator &) which + * will be used to draw samples. + */ + template <typename D> + void fill(RawTensor &raw, D &&distribution, std::random_device::result_type seed_offset) const; + + /** Fills the specified @p tensor with the content of the specified image + * converted to the given format. + * + * @param[in, out] tensor To be filled tensor. + * @param[in] name Image file used to fill the tensor. + * @param[in] format Format of the image used to fill the tensor. + * + * @warning No check is performed that the specified format actually + * matches the format of the tensor. + */ + template <typename T> + void fill(T &&tensor, const std::string &name, Format format) const; + + /** Fills the raw tensor with the content of the specified image + * converted to the given format. + * + * @param[in, out] raw To be filled raw tensor. + * @param[in] name Image file used to fill the tensor. + * @param[in] format Format of the image used to fill the tensor. + * + * @warning No check is performed that the specified format actually + * matches the format of the tensor. + */ + void fill(RawTensor &raw, const std::string &name, Format format) const; + + /** Fills the specified @p tensor with the content of the specified channel + * extracted from the given image. + * + * @param[in, out] tensor To be filled tensor. + * @param[in] name Image file used to fill the tensor. + * @param[in] channel Channel of the image used to fill the tensor. + * + * @note The channel has to be unambiguous so that the format can be + * inferred automatically. + * + * @warning No check is performed that the specified format actually + * matches the format of the tensor. + */ + template <typename T> + void fill(T &&tensor, const std::string &name, Channel channel) const; + + /** Fills the raw tensor with the content of the specified channel + * extracted from the given image. + * + * @param[in, out] raw To be filled raw tensor. + * @param[in] name Image file used to fill the tensor. + * @param[in] channel Channel of the image used to fill the tensor. + * + * @note The channel has to be unambiguous so that the format can be + * inferred automatically. + * + * @warning No check is performed that the specified format actually + * matches the format of the tensor. + */ + void fill(RawTensor &raw, const std::string &name, Channel channel) const; + + /** Fills the specified @p tensor with the content of the specified channel + * extracted from the given image after it has been converted to the given + * format. + * + * @param[in, out] tensor To be filled tensor. + * @param[in] name Image file used to fill the tensor. + * @param[in] format Format of the image used to fill the tensor. + * @param[in] channel Channel of the image used to fill the tensor. + * + * @warning No check is performed that the specified format actually + * matches the format of the tensor. + */ + template <typename T> + void fill(T &&tensor, const std::string &name, Format format, Channel channel) const; + + /** Fills the raw tensor with the content of the specified channel + * extracted from the given image after it has been converted to the given + * format. + * + * @param[in, out] raw To be filled raw tensor. + * @param[in] name Image file used to fill the tensor. + * @param[in] format Format of the image used to fill the tensor. + * @param[in] channel Channel of the image used to fill the tensor. + * + * @warning No check is performed that the specified format actually + * matches the format of the tensor. + */ + void fill(RawTensor &raw, const std::string &name, Format format, Channel channel) const; + + /** Fill a tensor with uniform distribution across the range of its type + * + * @param[in, out] tensor To be filled tensor. + * @param[in] seed_offset The offset will be added to the global seed before initialising the random generator. + */ + template <typename T> + void fill_tensor_uniform(T &&tensor, std::random_device::result_type seed_offset) const; + + /** Fill a tensor with uniform distribution across the a specified range + * + * @param[in, out] tensor To be filled tensor. + * @param[in] seed_offset The offset will be added to the global seed before initialising the random generator. + * @param[in] low lowest value in the range (inclusive) + * @param[in] high highest value in the range (inclusive) + * + * @note @p low and @p high must be of the same type as the data type of @p tensor + */ + template <typename T, typename D> + void fill_tensor_uniform(T &&tensor, std::random_device::result_type seed_offset, D low, D high) const; + + /** Fills the specified @p tensor with data loaded from binary in specified path. + * + * @param[in, out] tensor To be filled tensor. + * @param[in] name Data file. + */ + template <typename T> + void fill_layer_data(T &&tensor, std::string name) const; + +private: + // Function prototype to convert between image formats. + using Converter = void (*)(const RawTensor &src, RawTensor &dst); + // Function prototype to extract a channel from an image. + using Extractor = void (*)(const RawTensor &src, RawTensor &dst); + // Function prototype to load an image file. + using Loader = RawTensor (*)(const std::string &path); + + const Converter &get_converter(Format src, Format dst) const; + const Converter &get_converter(DataType src, Format dst) const; + const Converter &get_converter(Format src, DataType dst) const; + const Converter &get_converter(DataType src, DataType dst) const; + const Extractor &get_extractor(Format format, Channel) const; + const Loader &get_loader(const std::string &extension) const; + + /** Creates a raw tensor from the specified image. + * + * @param[in] name To be loaded image file. + * + * @note If use_single_image is true @p name is ignored and the user image + * is loaded instead. + */ + RawTensor load_image(const std::string &name) const; + + /** Provides a raw tensor for the specified image and format. + * + * @param[in] name Image file used to look up the raw tensor. + * @param[in] format Format used to look up the raw tensor. + * + * If the tensor has already been requested before the cached version will + * be returned. Otherwise the tensor will be added to the cache. + * + * @note If use_single_image is true @p name is ignored and the user image + * is loaded instead. + */ + const RawTensor &find_or_create_raw_tensor(const std::string &name, Format format) const; + + /** Provides a raw tensor for the specified image, format and channel. + * + * @param[in] name Image file used to look up the raw tensor. + * @param[in] format Format used to look up the raw tensor. + * @param[in] channel Channel used to look up the raw tensor. + * + * If the tensor has already been requested before the cached version will + * be returned. Otherwise the tensor will be added to the cache. + * + * @note If use_single_image is true @p name is ignored and the user image + * is loaded instead. + */ + const RawTensor &find_or_create_raw_tensor(const std::string &name, Format format, Channel channel) const; + + mutable TensorCache _cache{}; + mutable std::mutex _format_lock{}; + mutable std::mutex _channel_lock{}; + const std::string _library_path; + std::random_device::result_type _seed; +}; + +template <typename T, typename D> +void AssetsLibrary::fill_borders_with_garbage(T &&tensor, D &&distribution, std::random_device::result_type seed_offset) const +{ + const PaddingSize padding_size = tensor.padding(); + + Window window; + window.set(0, Window::Dimension(-padding_size.left, tensor.shape()[0] + padding_size.right, 1)); + window.set(1, Window::Dimension(-padding_size.top, tensor.shape()[1] + padding_size.bottom, 1)); + + std::mt19937 gen(_seed); + + execute_window_loop(window, [&](const Coordinates & id) + { + TensorShape shape = tensor.shape(); + + // If outside of valid region + if(id.x() < 0 || id.x() >= static_cast<int>(shape.x()) || id.y() < 0 || id.y() >= static_cast<int>(shape.y())) + { + using ResultType = typename std::remove_reference<D>::type::result_type; + const ResultType value = distribution(gen); + void *const out_ptr = tensor(id); + store_value_with_data_type(out_ptr, value, tensor.data_type()); + } + }); +} + +template <typename T, typename D> +void AssetsLibrary::fill(T &&tensor, D &&distribution, std::random_device::result_type seed_offset) const +{ + Window window; + for(unsigned int d = 0; d < tensor.shape().num_dimensions(); ++d) + { + window.set(d, Window::Dimension(0, tensor.shape()[d], 1)); + } + + std::mt19937 gen(_seed + seed_offset); + + //FIXME: Replace with normal loop + execute_window_loop(window, [&](const Coordinates & id) + { + using ResultType = typename std::remove_reference<D>::type::result_type; + const ResultType value = distribution(gen); + void *const out_ptr = tensor(id); + store_value_with_data_type(out_ptr, value, tensor.data_type()); + }); + + fill_borders_with_garbage(tensor, distribution, seed_offset); +} + +template <typename D> +void AssetsLibrary::fill(RawTensor &raw, D &&distribution, std::random_device::result_type seed_offset) const +{ + std::mt19937 gen(_seed + seed_offset); + + for(size_t offset = 0; offset < raw.size(); offset += raw.element_size()) + { + using ResultType = typename std::remove_reference<D>::type::result_type; + const ResultType value = distribution(gen); + store_value_with_data_type(raw.data() + offset, value, raw.data_type()); + } +} + +template <typename T> +void AssetsLibrary::fill(T &&tensor, const std::string &name, Format format) const +{ + const RawTensor &raw = get(name, format); + + for(size_t offset = 0; offset < raw.size(); offset += raw.element_size()) + { + const Coordinates id = index2coord(raw.shape(), offset / raw.element_size()); + + const RawTensor::value_type *const raw_ptr = raw.data() + offset; + const auto out_ptr = static_cast<RawTensor::value_type *>(tensor(id)); + std::copy_n(raw_ptr, raw.element_size(), out_ptr); + } +} + +template <typename T> +void AssetsLibrary::fill(T &&tensor, const std::string &name, Channel channel) const +{ + fill(std::forward<T>(tensor), name, get_format_for_channel(channel), channel); +} + +template <typename T> +void AssetsLibrary::fill(T &&tensor, const std::string &name, Format format, Channel channel) const +{ + const RawTensor &raw = get(name, format, channel); + + for(size_t offset = 0; offset < raw.size(); offset += raw.element_size()) + { + const Coordinates id = index2coord(raw.shape(), offset / raw.element_size()); + + const RawTensor::value_type *const raw_ptr = raw.data() + offset; + const auto out_ptr = static_cast<RawTensor::value_type *>(tensor(id)); + std::copy_n(raw_ptr, raw.element_size(), out_ptr); + } +} + +template <typename T> +void AssetsLibrary::fill_tensor_uniform(T &&tensor, std::random_device::result_type seed_offset) const +{ + switch(tensor.data_type()) + { + case DataType::U8: + { + std::uniform_int_distribution<uint8_t> distribution_u8(std::numeric_limits<uint8_t>::lowest(), std::numeric_limits<uint8_t>::max()); + fill(tensor, distribution_u8, seed_offset); + break; + } + case DataType::S8: + case DataType::QS8: + { + std::uniform_int_distribution<int8_t> distribution_s8(std::numeric_limits<int8_t>::lowest(), std::numeric_limits<int8_t>::max()); + fill(tensor, distribution_s8, seed_offset); + break; + } + case DataType::U16: + { + std::uniform_int_distribution<uint16_t> distribution_u16(std::numeric_limits<uint16_t>::lowest(), std::numeric_limits<uint16_t>::max()); + fill(tensor, distribution_u16, seed_offset); + break; + } + case DataType::S16: + case DataType::QS16: + { + std::uniform_int_distribution<int16_t> distribution_s16(std::numeric_limits<int16_t>::lowest(), std::numeric_limits<int16_t>::max()); + fill(tensor, distribution_s16, seed_offset); + break; + } + case DataType::U32: + { + std::uniform_int_distribution<uint32_t> distribution_u32(std::numeric_limits<uint32_t>::lowest(), std::numeric_limits<uint32_t>::max()); + fill(tensor, distribution_u32, seed_offset); + break; + } + case DataType::S32: + { + std::uniform_int_distribution<int32_t> distribution_s32(std::numeric_limits<int32_t>::lowest(), std::numeric_limits<int32_t>::max()); + fill(tensor, distribution_s32, seed_offset); + break; + } + case DataType::U64: + { + std::uniform_int_distribution<uint64_t> distribution_u64(std::numeric_limits<uint64_t>::lowest(), std::numeric_limits<uint64_t>::max()); + fill(tensor, distribution_u64, seed_offset); + break; + } + case DataType::S64: + { + std::uniform_int_distribution<int64_t> distribution_s64(std::numeric_limits<int64_t>::lowest(), std::numeric_limits<int64_t>::max()); + fill(tensor, distribution_s64, seed_offset); + break; + } + case DataType::F16: + { + // It doesn't make sense to check [-inf, inf], so hard code it to a big number + std::uniform_real_distribution<float> distribution_f16(-100.f, 100.f); + fill(tensor, distribution_f16, seed_offset); + break; + } + case DataType::F32: + { + // It doesn't make sense to check [-inf, inf], so hard code it to a big number + std::uniform_real_distribution<float> distribution_f32(-1000.f, 1000.f); + fill(tensor, distribution_f32, seed_offset); + break; + } + case DataType::F64: + { + // It doesn't make sense to check [-inf, inf], so hard code it to a big number + std::uniform_real_distribution<double> distribution_f64(-1000.f, 1000.f); + fill(tensor, distribution_f64, seed_offset); + break; + } + case DataType::SIZET: + { + std::uniform_int_distribution<size_t> distribution_sizet(std::numeric_limits<size_t>::lowest(), std::numeric_limits<size_t>::max()); + fill(tensor, distribution_sizet, seed_offset); + break; + } + default: + ARM_COMPUTE_ERROR("NOT SUPPORTED!"); + } +} + +template <typename T, typename D> +void AssetsLibrary::fill_tensor_uniform(T &&tensor, std::random_device::result_type seed_offset, D low, D high) const +{ + switch(tensor.data_type()) + { + case DataType::U8: + { + ARM_COMPUTE_ERROR_ON(!(std::is_same<uint8_t, D>::value)); + std::uniform_int_distribution<uint8_t> distribution_u8(low, high); + fill(tensor, distribution_u8, seed_offset); + break; + } + case DataType::S8: + case DataType::QS8: + { + ARM_COMPUTE_ERROR_ON(!(std::is_same<int8_t, D>::value)); + std::uniform_int_distribution<int8_t> distribution_s8(low, high); + fill(tensor, distribution_s8, seed_offset); + break; + } + case DataType::U16: + { + ARM_COMPUTE_ERROR_ON(!(std::is_same<uint16_t, D>::value)); + std::uniform_int_distribution<uint16_t> distribution_u16(low, high); + fill(tensor, distribution_u16, seed_offset); + break; + } + case DataType::S16: + case DataType::QS16: + { + ARM_COMPUTE_ERROR_ON(!(std::is_same<int16_t, D>::value)); + std::uniform_int_distribution<int16_t> distribution_s16(low, high); + fill(tensor, distribution_s16, seed_offset); + break; + } + case DataType::U32: + { + ARM_COMPUTE_ERROR_ON(!(std::is_same<uint32_t, D>::value)); + std::uniform_int_distribution<uint32_t> distribution_u32(low, high); + fill(tensor, distribution_u32, seed_offset); + break; + } + case DataType::S32: + { + ARM_COMPUTE_ERROR_ON(!(std::is_same<int32_t, D>::value)); + std::uniform_int_distribution<int32_t> distribution_s32(low, high); + fill(tensor, distribution_s32, seed_offset); + break; + } + case DataType::U64: + { + ARM_COMPUTE_ERROR_ON(!(std::is_same<uint64_t, D>::value)); + std::uniform_int_distribution<uint64_t> distribution_u64(low, high); + fill(tensor, distribution_u64, seed_offset); + break; + } + case DataType::S64: + { + ARM_COMPUTE_ERROR_ON(!(std::is_same<int64_t, D>::value)); + std::uniform_int_distribution<int64_t> distribution_s64(low, high); + fill(tensor, distribution_s64, seed_offset); + break; + } + case DataType::F16: + { + std::uniform_real_distribution<float> distribution_f16(low, high); + fill(tensor, distribution_f16, seed_offset); + break; + } + case DataType::F32: + { + ARM_COMPUTE_ERROR_ON(!(std::is_same<float, D>::value)); + std::uniform_real_distribution<float> distribution_f32(low, high); + fill(tensor, distribution_f32, seed_offset); + break; + } + case DataType::F64: + { + ARM_COMPUTE_ERROR_ON(!(std::is_same<double, D>::value)); + std::uniform_real_distribution<double> distribution_f64(low, high); + fill(tensor, distribution_f64, seed_offset); + break; + } + case DataType::SIZET: + { + ARM_COMPUTE_ERROR_ON(!(std::is_same<size_t, D>::value)); + std::uniform_int_distribution<size_t> distribution_sizet(low, high); + fill(tensor, distribution_sizet, seed_offset); + break; + } + default: + ARM_COMPUTE_ERROR("NOT SUPPORTED!"); + } +} + +template <typename T> +void AssetsLibrary::fill_layer_data(T &&tensor, std::string name) const +{ +#ifdef _WIN32 + const std::string path_separator("\\"); +#else /* _WIN32 */ + const std::string path_separator("/"); +#endif /* _WIN32 */ + + const std::string path = _library_path + path_separator + name; + + // Open file + std::ifstream file(path, std::ios::in | std::ios::binary); + if(!file.good()) + { + throw std::runtime_error("Could not load binary data: " + path); + } + + Window window; + for(unsigned int d = 0; d < tensor.shape().num_dimensions(); ++d) + { + window.set(d, Window::Dimension(0, tensor.shape()[d], 1)); + } + + //FIXME : Replace with normal loop + execute_window_loop(window, [&](const Coordinates & id) + { + float val; + file.read(reinterpret_cast<char *>(&val), sizeof(float)); + void *const out_ptr = tensor(id); + store_value_with_data_type(out_ptr, val, tensor.data_type()); + }); +} +} // namespace test +} // namespace arm_compute +#endif /* __ARM_COMPUTE_TEST_TENSOR_LIBRARY_H__ */ diff --git a/tests/validation_old/CL/ArithmeticAddition.cpp b/tests/validation_old/CL/ArithmeticAddition.cpp new file mode 100644 index 0000000000..8e67bf3a26 --- /dev/null +++ b/tests/validation_old/CL/ArithmeticAddition.cpp @@ -0,0 +1,302 @@ +/* + * 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 "PaddingCalculator.h" +#include "TypePrinter.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/Utils.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/CL/functions/CLArithmeticAddition.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +/** Compute Neon arithmetic addition function. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] dt_in0 Data type of first input tensor. + * @param[in] dt_in1 Data type of second input tensor. + * @param[in] dt_out Data type of the output tensor. + * @param[in] policy Overflow policy of the operation. + * @param[in] fixed_point_position (Optional) Fixed point position that expresses the number of bits for the fractional part of the number when the tensor's data type is QS8 or QS16 (default = 0). + * + * @return Computed output tensor. + */ +CLTensor compute_arithmetic_addition(const TensorShape &shape, DataType dt_in0, DataType dt_in1, DataType dt_out, ConvertPolicy policy, int fixed_point_position = 0) +{ + // Create tensors + CLTensor src1 = create_tensor<CLTensor>(shape, dt_in0, 1, fixed_point_position); + CLTensor src2 = create_tensor<CLTensor>(shape, dt_in1, 1, fixed_point_position); + CLTensor dst = create_tensor<CLTensor>(shape, dt_out, 1, fixed_point_position); + + // Create and configure function + CLArithmeticAddition add; + add.configure(&src1, &src2, &dst, policy); + + // Allocate tensors + src1.allocator()->allocate(); + src2.allocator()->allocate(); + dst.allocator()->allocate(); + + BOOST_TEST(!src1.info()->is_resizable()); + BOOST_TEST(!src2.info()->is_resizable()); + BOOST_TEST(!dst.info()->is_resizable()); + + // Fill tensors + library->fill_tensor_uniform(CLAccessor(src1), 0); + library->fill_tensor_uniform(CLAccessor(src2), 1); + + // Compute function + add.run(); + + return dst; +} + +void validate_configuration(const CLTensor &src1, const CLTensor &src2, CLTensor &dst, TensorShape shape, ConvertPolicy policy) +{ + BOOST_TEST(src1.info()->is_resizable()); + BOOST_TEST(src2.info()->is_resizable()); + BOOST_TEST(dst.info()->is_resizable()); + + // Create and configure function + CLArithmeticAddition add; + add.configure(&src1, &src2, &dst, policy); + + // Validate valid region + const ValidRegion valid_region = shape_to_valid_region(shape); + validate(src1.info()->valid_region(), valid_region); + validate(src2.info()->valid_region(), valid_region); + validate(dst.info()->valid_region(), valid_region); + + // Validate padding + const PaddingSize padding = PaddingCalculator(shape.x(), 16).required_padding(); + validate(src1.info()->padding(), padding); + validate(src2.info()->padding(), padding); + validate(dst.info()->padding(), padding); +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(CL) +BOOST_AUTO_TEST_SUITE(ArithmeticAddition) + +BOOST_AUTO_TEST_SUITE(U8) +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({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }), + shape, policy) +{ + // Create tensors + CLTensor src1 = create_tensor<CLTensor>(shape, DataType::U8); + CLTensor src2 = create_tensor<CLTensor>(shape, DataType::U8); + CLTensor dst = create_tensor<CLTensor>(shape, DataType::U8); + + validate_configuration(src1, src2, dst, shape, policy); +} +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }), + shape, policy) +{ + // Compute function + CLTensor dst = compute_arithmetic_addition(shape, DataType::U8, DataType::U8, DataType::U8, policy); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_addition(shape, DataType::U8, DataType::U8, DataType::U8, policy); + + // Validate output + validate(CLAccessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(S16) +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 }) * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }), + shape, dt, policy) +{ + // Create tensors + CLTensor src1 = create_tensor<CLTensor>(shape, dt); + CLTensor src2 = create_tensor<CLTensor>(shape, DataType::S16); + CLTensor dst = create_tensor<CLTensor>(shape, DataType::S16); + + validate_configuration(src1, src2, dst, shape, policy); +} +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * boost::unit_test::data::make({ DataType::U8, DataType::S16 }) * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }), + shape, dt, policy) +{ + // Compute function + CLTensor dst = compute_arithmetic_addition(shape, dt, DataType::S16, DataType::S16, policy); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_addition(shape, dt, DataType::S16, DataType::S16, policy); + + // 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 }) * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }), + shape, dt, policy) +{ + // Compute function + CLTensor dst = compute_arithmetic_addition(shape, dt, DataType::S16, DataType::S16, policy); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_addition(shape, dt, DataType::S16, DataType::S16, policy); + + // Validate output + validate(CLAccessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(Quantized) +BOOST_AUTO_TEST_SUITE(QS8) +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * ConvertPolicies() * boost::unit_test::data::xrange(1, 7), + shape, policy, fixed_point_position) +{ + // Compute function + CLTensor dst = compute_arithmetic_addition(shape, DataType::QS8, DataType::QS8, DataType::QS8, policy, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_addition(shape, DataType::QS8, DataType::QS8, DataType::QS8, policy, fixed_point_position); + + // Validate output + validate(CLAccessor(dst), ref_dst); +} +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * ConvertPolicies() * boost::unit_test::data::xrange(1, 7), + shape, policy, fixed_point_position) +{ + // Compute function + CLTensor dst = compute_arithmetic_addition(shape, DataType::QS8, DataType::QS8, DataType::QS8, policy, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_addition(shape, DataType::QS8, DataType::QS8, DataType::QS8, policy, fixed_point_position); + + // Validate output + validate(CLAccessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(QS16) +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * ConvertPolicies() * boost::unit_test::data::xrange(1, 15), + shape, policy, fixed_point_position) +{ + // Compute function + CLTensor dst = compute_arithmetic_addition(shape, DataType::QS16, DataType::QS16, DataType::QS16, policy, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_addition(shape, DataType::QS16, DataType::QS16, DataType::QS16, policy, fixed_point_position); + + // Validate output + validate(CLAccessor(dst), ref_dst); +} +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * ConvertPolicies() * boost::unit_test::data::xrange(1, 15), + shape, policy, fixed_point_position) +{ + // Compute function + CLTensor dst = compute_arithmetic_addition(shape, DataType::QS16, DataType::QS16, DataType::QS16, policy, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_addition(shape, DataType::QS16, DataType::QS16, DataType::QS16, policy, fixed_point_position); + + // Validate output + validate(CLAccessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(F16) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes(), shape) +{ + // Compute function + CLTensor dst = compute_arithmetic_addition(shape, DataType::F16, DataType::F16, DataType::F16, ConvertPolicy::WRAP); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_addition(shape, DataType::F16, DataType::F16, DataType::F16, ConvertPolicy::WRAP); + + // Validate output + validate(CLAccessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(F32) +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({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }), + shape, policy) +{ + // Create tensors + CLTensor src1 = create_tensor<CLTensor>(shape, DataType::F32); + CLTensor src2 = create_tensor<CLTensor>(shape, DataType::F32); + CLTensor dst = create_tensor<CLTensor>(shape, DataType::F32); + + validate_configuration(src1, src2, dst, shape, policy); +} +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes(), shape) +{ + // Compute function + CLTensor dst = compute_arithmetic_addition(shape, DataType::F32, DataType::F32, DataType::F32, ConvertPolicy::WRAP); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_addition(shape, DataType::F32, DataType::F32, DataType::F32, ConvertPolicy::WRAP); + + // 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({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }), + shape, policy) +{ + // Compute function + CLTensor dst = compute_arithmetic_addition(shape, DataType::F32, DataType::F32, DataType::F32, policy); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_addition(shape, DataType::F32, DataType::F32, DataType::F32, policy); + + // Validate output + validate(CLAccessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/CL/ArithmeticSubtraction.cpp b/tests/validation_old/CL/ArithmeticSubtraction.cpp new file mode 100644 index 0000000000..522ee7b1e8 --- /dev/null +++ b/tests/validation_old/CL/ArithmeticSubtraction.cpp @@ -0,0 +1,288 @@ +/* + * 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 "PaddingCalculator.h" +#include "TypePrinter.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/Utils.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/CL/functions/CLArithmeticSubtraction.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +/** Compute Neon arithmetic subtraction function. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] dt_in0 Data type of first input tensor. + * @param[in] dt_in1 Data type of second input tensor. + * @param[in] dt_out Data type of the output tensor. + * @param[in] policy Overflow policy of the operation. + * @param[in] fixed_point_position (Optional) Fixed point position that expresses the number of bits for the fractional part of the number when the tensor's data type is QS8 or QS16 (default = 0). + * + * @return Computed output tensor. + */ +CLTensor compute_arithmetic_subtraction(const TensorShape &shape, DataType dt_in0, DataType dt_in1, DataType dt_out, ConvertPolicy policy, int fixed_point_position = 0) +{ + // Create tensors + CLTensor src1 = create_tensor<CLTensor>(shape, dt_in0, 1, fixed_point_position); + CLTensor src2 = create_tensor<CLTensor>(shape, dt_in1, 1, fixed_point_position); + CLTensor dst = create_tensor<CLTensor>(shape, dt_out, 1, fixed_point_position); + + // Create and configure function + CLArithmeticSubtraction sub; + sub.configure(&src1, &src2, &dst, policy); + + // Allocate tensors + src1.allocator()->allocate(); + src2.allocator()->allocate(); + dst.allocator()->allocate(); + + BOOST_TEST(!src1.info()->is_resizable()); + BOOST_TEST(!src2.info()->is_resizable()); + BOOST_TEST(!dst.info()->is_resizable()); + + // Fill tensors + library->fill_tensor_uniform(CLAccessor(src1), 0); + library->fill_tensor_uniform(CLAccessor(src2), 1); + + // Compute function + sub.run(); + + return dst; +} + +void validate_configuration(const CLTensor &src1, const CLTensor &src2, CLTensor &dst, TensorShape shape, ConvertPolicy policy) +{ + BOOST_TEST(src1.info()->is_resizable()); + BOOST_TEST(src2.info()->is_resizable()); + BOOST_TEST(dst.info()->is_resizable()); + + // Create and configure function + CLArithmeticSubtraction sub; + sub.configure(&src1, &src2, &dst, policy); + + // Validate valid region + const ValidRegion valid_region = shape_to_valid_region(shape); + validate(src1.info()->valid_region(), valid_region); + validate(src2.info()->valid_region(), valid_region); + validate(dst.info()->valid_region(), valid_region); + + // Validate padding + const PaddingSize padding = PaddingCalculator(shape.x(), 16).required_padding(); + validate(src1.info()->padding(), padding); + validate(src2.info()->padding(), padding); + validate(dst.info()->padding(), padding); +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(CL) +BOOST_AUTO_TEST_SUITE(ArithmeticSubtraction) + +BOOST_AUTO_TEST_SUITE(U8) +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({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }), + shape, policy) +{ + // Create tensors + CLTensor src1 = create_tensor<CLTensor>(shape, DataType::U8); + CLTensor src2 = create_tensor<CLTensor>(shape, DataType::U8); + CLTensor dst = create_tensor<CLTensor>(shape, DataType::U8); + + validate_configuration(src1, src2, dst, shape, policy); +} +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }), + shape, policy) +{ + // Compute function + CLTensor dst = compute_arithmetic_subtraction(shape, DataType::U8, DataType::U8, DataType::U8, policy); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_subtraction(shape, DataType::U8, DataType::U8, DataType::U8, policy); + + // Validate output + validate(CLAccessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(S16) +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 }) * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }), + shape, dt, policy) +{ + // Create tensors + CLTensor src1 = create_tensor<CLTensor>(shape, dt); + CLTensor src2 = create_tensor<CLTensor>(shape, DataType::S16); + CLTensor dst = create_tensor<CLTensor>(shape, DataType::S16); + + validate_configuration(src1, src2, dst, shape, policy); +} +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * boost::unit_test::data::make({ DataType::U8, DataType::S16 }) * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }), + shape, dt, policy) +{ + // Compute function + CLTensor dst = compute_arithmetic_subtraction(shape, dt, DataType::S16, DataType::S16, policy); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_subtraction(shape, dt, DataType::S16, DataType::S16, policy); + + // 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 }) * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }), + shape, dt, policy) +{ + // Compute function + CLTensor dst = compute_arithmetic_subtraction(shape, dt, DataType::S16, DataType::S16, policy); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_subtraction(shape, dt, DataType::S16, DataType::S16, policy); + + // Validate output + validate(CLAccessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(Quantized) +BOOST_AUTO_TEST_SUITE(QS8) +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * ConvertPolicies() * boost::unit_test::data::xrange(1, 7), + shape, policy, fixed_point_position) +{ + // Compute function + CLTensor dst = compute_arithmetic_subtraction(shape, DataType::QS8, DataType::QS8, DataType::QS8, policy, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_subtraction(shape, DataType::QS8, DataType::QS8, DataType::QS8, policy, fixed_point_position); + + // Validate output + validate(CLAccessor(dst), ref_dst); +} +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * ConvertPolicies() * boost::unit_test::data::xrange(1, 7), + shape, policy, fixed_point_position) +{ + // Compute function + CLTensor dst = compute_arithmetic_subtraction(shape, DataType::QS8, DataType::QS8, DataType::QS8, policy, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_subtraction(shape, DataType::QS8, DataType::QS8, DataType::QS8, policy, fixed_point_position); + + // Validate output + validate(CLAccessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(QS16) +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * ConvertPolicies() * boost::unit_test::data::xrange(1, 15), + shape, policy, fixed_point_position) +{ + // Compute function + CLTensor dst = compute_arithmetic_subtraction(shape, DataType::QS16, DataType::QS16, DataType::QS16, policy, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_subtraction(shape, DataType::QS16, DataType::QS16, DataType::QS16, policy, fixed_point_position); + + // Validate output + validate(CLAccessor(dst), ref_dst); +} +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * ConvertPolicies() * boost::unit_test::data::xrange(1, 15), + shape, policy, fixed_point_position) +{ + // Compute function + CLTensor dst = compute_arithmetic_subtraction(shape, DataType::QS16, DataType::QS16, DataType::QS16, policy, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_subtraction(shape, DataType::QS16, DataType::QS16, DataType::QS16, policy, fixed_point_position); + + // Validate output + validate(CLAccessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(Float) +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({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }), + shape, policy) +{ + // Create tensors + CLTensor src1 = create_tensor<CLTensor>(shape, DataType::F32); + CLTensor src2 = create_tensor<CLTensor>(shape, DataType::F32); + CLTensor dst = create_tensor<CLTensor>(shape, DataType::F32); + + validate_configuration(src1, src2, dst, shape, policy); +} +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes(), shape) +{ + // Compute function + CLTensor dst = compute_arithmetic_subtraction(shape, DataType::F32, DataType::F32, DataType::F32, ConvertPolicy::WRAP); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_subtraction(shape, DataType::F32, DataType::F32, DataType::F32, ConvertPolicy::WRAP); + + // 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({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }), + shape, policy) +{ + // Compute function + CLTensor dst = compute_arithmetic_subtraction(shape, DataType::F32, DataType::F32, DataType::F32, policy); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_subtraction(shape, DataType::F32, DataType::F32, DataType::F32, policy); + + // Validate output + validate(CLAccessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/CL/BatchNormalizationLayer.cpp b/tests/validation_old/CL/BatchNormalizationLayer.cpp new file mode 100644 index 0000000000..75c9a580ea --- /dev/null +++ b/tests/validation_old/CL/BatchNormalizationLayer.cpp @@ -0,0 +1,227 @@ +/* + * 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 "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Helpers.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" +#include "tests/validation_old/dataset/BatchNormalizationLayerDataset.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/CL/functions/CLBatchNormalizationLayer.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include <random> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +const float tolerance_f = 1e-05; /**< Tolerance value for comparing reference's output against floating point implementation's output */ +const float tolerance_qs8 = 3; /**< Tolerance value for comparing reference's output against quantized implementation's output */ +const float tolerance_qs16 = 6; /**< Tolerance value for comparing reference's output against quantized implementation's output */ + +/** Compute Neon batch normalization function. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] dt Data type of input and output tensors. + * @param[in] norm_info Normalization Layer information. + * + * @return Computed output tensor. + */ +CLTensor compute_reference_batch_normalization_layer(const TensorShape &shape0, const TensorShape &shape1, DataType dt, float epsilon, int fixed_point_position = 0) +{ + // Create tensors + CLTensor src = create_tensor<CLTensor>(shape0, dt, 1, fixed_point_position); + CLTensor dst = create_tensor<CLTensor>(shape0, dt, 1, fixed_point_position); + CLTensor mean = create_tensor<CLTensor>(shape1, dt, 1, fixed_point_position); + CLTensor var = create_tensor<CLTensor>(shape1, dt, 1, fixed_point_position); + CLTensor beta = create_tensor<CLTensor>(shape1, dt, 1, fixed_point_position); + CLTensor gamma = create_tensor<CLTensor>(shape1, dt, 1, fixed_point_position); + + // Create and configure function + CLBatchNormalizationLayer norm; + norm.configure(&src, &dst, &mean, &var, &beta, &gamma, epsilon); + + // Allocate tensors + src.allocator()->allocate(); + dst.allocator()->allocate(); + mean.allocator()->allocate(); + var.allocator()->allocate(); + beta.allocator()->allocate(); + gamma.allocator()->allocate(); + + BOOST_TEST(!src.info()->is_resizable()); + BOOST_TEST(!dst.info()->is_resizable()); + BOOST_TEST(!mean.info()->is_resizable()); + BOOST_TEST(!var.info()->is_resizable()); + BOOST_TEST(!beta.info()->is_resizable()); + BOOST_TEST(!gamma.info()->is_resizable()); + + // Fill tensors + if(dt == DataType::F32) + { + float min_bound = 0.f; + float max_bound = 0.f; + std::tie(min_bound, max_bound) = get_batchnormalization_layer_test_bounds<float>(); + std::uniform_real_distribution<> distribution(min_bound, max_bound); + std::uniform_real_distribution<> distribution_var(0, max_bound); + library->fill(CLAccessor(src), distribution, 0); + library->fill(CLAccessor(mean), distribution, 1); + library->fill(CLAccessor(var), distribution_var, 0); + library->fill(CLAccessor(beta), distribution, 3); + library->fill(CLAccessor(gamma), distribution, 4); + } + else + { + int min_bound = 0; + int max_bound = 0; + if(dt == DataType::QS8) + { + std::tie(min_bound, max_bound) = get_batchnormalization_layer_test_bounds<int8_t>(fixed_point_position); + } + else + { + std::tie(min_bound, max_bound) = get_batchnormalization_layer_test_bounds<int16_t>(fixed_point_position); + } + std::uniform_int_distribution<> distribution(min_bound, max_bound); + std::uniform_int_distribution<> distribution_var(0, max_bound); + library->fill(CLAccessor(src), distribution, 0); + library->fill(CLAccessor(mean), distribution, 1); + library->fill(CLAccessor(var), distribution_var, 0); + library->fill(CLAccessor(beta), distribution, 3); + library->fill(CLAccessor(gamma), distribution, 4); + } + + // Compute function + norm.run(); + + return dst; +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(CL) +BOOST_AUTO_TEST_SUITE(BatchNormalizationLayer) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(Configuration, RandomBatchNormalizationLayerDataset() * boost::unit_test::data::make({ DataType::QS8, DataType::QS16, DataType::F32 }), obj, dt) +{ + // Set fixed point position data type allowed + int fixed_point_position = (arm_compute::is_data_type_fixed_point(dt)) ? 3 : 0; + + // Create tensors + CLTensor src = create_tensor<CLTensor>(obj.shape0, dt, 1, fixed_point_position); + CLTensor dst = create_tensor<CLTensor>(obj.shape0, dt, 1, fixed_point_position); + CLTensor mean = create_tensor<CLTensor>(obj.shape1, dt, 1, fixed_point_position); + CLTensor var = create_tensor<CLTensor>(obj.shape1, dt, 1, fixed_point_position); + CLTensor beta = create_tensor<CLTensor>(obj.shape1, dt, 1, fixed_point_position); + CLTensor gamma = create_tensor<CLTensor>(obj.shape1, dt, 1, fixed_point_position); + + BOOST_TEST(src.info()->is_resizable()); + BOOST_TEST(dst.info()->is_resizable()); + BOOST_TEST(mean.info()->is_resizable()); + BOOST_TEST(var.info()->is_resizable()); + BOOST_TEST(beta.info()->is_resizable()); + BOOST_TEST(gamma.info()->is_resizable()); + + // Create and configure function + CLBatchNormalizationLayer norm; + norm.configure(&src, &dst, &mean, &var, &beta, &gamma, obj.epsilon); + + // Validate valid region + const ValidRegion valid_region = shape_to_valid_region(obj.shape0); + const ValidRegion valid_region_vec = shape_to_valid_region(obj.shape1); + validate(src.info()->valid_region(), valid_region); + validate(dst.info()->valid_region(), valid_region); + validate(mean.info()->valid_region(), valid_region_vec); + validate(var.info()->valid_region(), valid_region_vec); + validate(beta.info()->valid_region(), valid_region_vec); + validate(gamma.info()->valid_region(), valid_region_vec); +} + +BOOST_AUTO_TEST_SUITE(Float) +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(Random, + RandomBatchNormalizationLayerDataset() * boost::unit_test::data::make(DataType::F32), + obj, dt) +{ + // Compute function + CLTensor dst = compute_reference_batch_normalization_layer(obj.shape0, obj.shape1, dt, obj.epsilon); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_batch_normalization_layer(obj.shape0, obj.shape1, dt, obj.epsilon); + + // Validate output + validate(CLAccessor(dst), ref_dst, tolerance_f, 0); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(Quantized) + +BOOST_AUTO_TEST_SUITE(QS8) +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(Random, + RandomBatchNormalizationLayerDataset() * boost::unit_test::data::make(DataType::QS8) * boost::unit_test::data::xrange(1, 6), + obj, dt, fixed_point_position) +{ + // Compute function + CLTensor dst = compute_reference_batch_normalization_layer(obj.shape0, obj.shape1, dt, obj.epsilon, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_batch_normalization_layer(obj.shape0, obj.shape1, dt, obj.epsilon, fixed_point_position); + + // Validate output + validate(CLAccessor(dst), ref_dst, tolerance_qs8, 0); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(QS16) +BOOST_DATA_TEST_CASE(Random, + RandomBatchNormalizationLayerDataset() * boost::unit_test::data::make(DataType::QS16) * boost::unit_test::data::xrange(1, 14), + obj, dt, fixed_point_position) +{ + // Compute function + CLTensor dst = compute_reference_batch_normalization_layer(obj.shape0, obj.shape1, dt, obj.epsilon, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_batch_normalization_layer(obj.shape0, obj.shape1, dt, obj.epsilon, fixed_point_position); + + // Validate output + validate(CLAccessor(dst), ref_dst, tolerance_qs16, 0); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/CL/Box3x3.cpp b/tests/validation_old/CL/Box3x3.cpp new file mode 100644 index 0000000000..3eacb484b2 --- /dev/null +++ b/tests/validation_old/CL/Box3x3.cpp @@ -0,0 +1,166 @@ +/* + * 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 "PaddingCalculator.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" +#include "tests/validation_old/ValidationUserConfiguration.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/CLBox3x3.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +constexpr unsigned int filter_size = 3; /** Size of the kernel/filter in number of elements. */ +constexpr BorderSize border_size(filter_size / 2); /** Border size of the kernel/filter around its central element. */ + +/** Compute CL box3x3 filter. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] border_mode BorderMode used by the input tensor. + * @param[in] constant_border_value Constant to use if @p border_mode == CONSTANT. + * + * @return Computed output tensor. + */ +CLTensor compute_box3x3(const TensorShape &shape, BorderMode border_mode, uint8_t constant_border_value) +{ + // Create tensors + CLTensor src = create_tensor<CLTensor>(shape, DataType::U8); + CLTensor dst = create_tensor<CLTensor>(shape, DataType::U8); + + // Create and configure function + CLBox3x3 box3x3; + box3x3.configure(&src, &dst, border_mode, constant_border_value); + + // 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 + box3x3.run(); + + return dst; +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(CL) +BOOST_AUTO_TEST_SUITE(Box3x3) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(Configuration, (SmallShapes() + LargeShapes()) * BorderModes(), shape, border_mode) +{ + // Create tensors + CLTensor src = create_tensor<CLTensor>(shape, DataType::U8); + CLTensor dst = create_tensor<CLTensor>(shape, DataType::U8); + + BOOST_TEST(src.info()->is_resizable()); + BOOST_TEST(dst.info()->is_resizable()); + + // Create and configure function + CLBox3x3 box3x3; + box3x3.configure(&src, &dst, border_mode); + + // Validate valid region + const ValidRegion src_valid_region = shape_to_valid_region(shape); + const ValidRegion dst_valid_region = shape_to_valid_region(shape, border_mode == BorderMode::UNDEFINED, border_size); + validate(src.info()->valid_region(), src_valid_region); + validate(dst.info()->valid_region(), dst_valid_region); + + // Validate padding + PaddingCalculator calculator(shape.x(), 8); + calculator.set_border_size(1); + calculator.set_border_mode(border_mode); + + const PaddingSize dst_padding = calculator.required_padding(); + + calculator.set_accessed_elements(16); + calculator.set_access_offset(-1); + + const PaddingSize src_padding = calculator.required_padding(); + + validate(src.info()->padding(), src_padding); + validate(dst.info()->padding(), dst_padding); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * BorderModes(), shape, border_mode) +{ + std::mt19937 gen(user_config.seed.get()); + std::uniform_int_distribution<uint8_t> distribution(0, 255); + const uint8_t border_value = distribution(gen); + + // Compute function + CLTensor dst = compute_box3x3(shape, border_mode, border_value); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_box3x3(shape, border_mode, border_value); + + // Validate output + validate(CLAccessor(dst), ref_dst, shape_to_valid_region(shape, border_mode == BorderMode::UNDEFINED, border_size)); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * BorderModes(), shape, border_mode) +{ + std::mt19937 gen(user_config.seed.get()); + std::uniform_int_distribution<uint8_t> distribution(0, 255); + const uint8_t border_value = distribution(gen); + + // Compute function + CLTensor dst = compute_box3x3(shape, border_mode, border_value); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_box3x3(shape, border_mode, border_value); + + // Validate output + validate(CLAccessor(dst), ref_dst, shape_to_valid_region(shape, border_mode == BorderMode::UNDEFINED, border_size)); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/CL/CLFixture.cpp b/tests/validation_old/CL/CLFixture.cpp new file mode 100644 index 0000000000..aacaeb35b7 --- /dev/null +++ b/tests/validation_old/CL/CLFixture.cpp @@ -0,0 +1,32 @@ +/* + * 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 "tests/validation_old/CL/CLFixture.h" + +#include "tests/validation_old/boost_wrapper.h" + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +BOOST_GLOBAL_FIXTURE(CLFixture); diff --git a/tests/validation_old/CL/CLFixture.h b/tests/validation_old/CL/CLFixture.h new file mode 100644 index 0000000000..77538be8f4 --- /dev/null +++ b/tests/validation_old/CL/CLFixture.h @@ -0,0 +1,45 @@ +/* + * 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_VALIDATION_CL_CLFIXTURE_H__ +#define __ARM_COMPUTE_TEST_VALIDATION_CL_CLFIXTURE_H__ + +#include "arm_compute/runtime/CL/CLScheduler.h" + +namespace arm_compute +{ +namespace test +{ +namespace validation +{ +struct CLFixture +{ + CLFixture() + { + CLScheduler::get().default_init(); + } +}; +} // namespace validation +} // namespace test +} // namespace arm_compute +#endif /* __ARM_COMPUTE_TEST_VALIDATION_CL_CLFIXTURE_H__ */ diff --git a/tests/validation_old/CL/DepthConvert.cpp b/tests/validation_old/CL/DepthConvert.cpp new file mode 100644 index 0000000000..994a0327bf --- /dev/null +++ b/tests/validation_old/CL/DepthConvert.cpp @@ -0,0 +1,495 @@ +/* + * 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 "PaddingCalculator.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/CL/functions/CLDepthConvert.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +/** Compute CL depth convert function. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] dt_in Data type of input tensor. + * @param[in] dt_out Data type of the output tensor. + * @param[in] policy Conversion policy. + * @param[in] shift Value for down/up conversions. Must be 0 <= shift < 8. + * + * @return Computed output CLtensor. + */ +CLTensor compute_depth_convert(const TensorShape &shape, DataType dt_in, DataType dt_out, ConvertPolicy policy, uint32_t shift, uint32_t fixed_point_position = 0) +{ + // Create tensors + CLTensor src = create_tensor<CLTensor>(shape, dt_in, 1, fixed_point_position); + CLTensor dst = create_tensor<CLTensor>(shape, dt_out, 1, fixed_point_position); + + // Create and configure function + CLDepthConvert depth_convert; + depth_convert.configure(&src, &dst, policy, shift); + + // 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 + depth_convert.run(); + + return dst; +} +/** Configure and validate region/padding function. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] dt_in Data type of input tensor. + * @param[in] dt_out Data type of the output tensor. + * @param[in] policy Conversion policy. + * @param[in] shift Value for down/up conversions. Must be 0 <= shift < 8. + * @param[in] fixed_point_position Fixed point position. + * + */ +void compute_configure_validate(const TensorShape &shape, DataType dt_in, DataType dt_out, ConvertPolicy policy, uint32_t shift, uint32_t fixed_point_position = 0) +{ + // Create tensors + CLTensor src = create_tensor<CLTensor>(shape, dt_in, 1, fixed_point_position); + CLTensor dst = create_tensor<CLTensor>(shape, dt_out, 1, fixed_point_position); + + BOOST_TEST(src.info()->is_resizable()); + BOOST_TEST(dst.info()->is_resizable()); + + // Create and configure function + CLDepthConvert depth_convert; + depth_convert.configure(&src, &dst, policy, shift); + + // 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); +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(CL) +BOOST_AUTO_TEST_SUITE(DepthConvert) + +BOOST_AUTO_TEST_SUITE(U8_to_U16) +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({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute configure and validate region/padding + compute_configure_validate(shape, DataType::U8, DataType::U16, policy, shift); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute function + CLTensor dst = compute_depth_convert(shape, DataType::U8, DataType::U16, policy, shift); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::U8, DataType::U16, policy, shift, 0); + + // 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({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute function + CLTensor dst = compute_depth_convert(shape, DataType::U8, DataType::U16, policy, shift); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::U8, DataType::U16, policy, shift, 0); + + // Validate output + validate(CLAccessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(U8_to_S16) +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({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute configure and validate region/padding + compute_configure_validate(shape, DataType::U8, DataType::S16, policy, shift); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute function + CLTensor dst = compute_depth_convert(shape, DataType::U8, DataType::S16, policy, shift); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::U8, DataType::S16, policy, shift, 0); + + // 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({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute function + CLTensor dst = compute_depth_convert(shape, DataType::U8, DataType::S16, policy, shift); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::U8, DataType::S16, policy, shift, 0); + + // Validate output + validate(CLAccessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(U8_to_S32) +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({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute configure and validate region/padding + compute_configure_validate(shape, DataType::U8, DataType::S32, policy, shift); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute function + CLTensor dst = compute_depth_convert(shape, DataType::U8, DataType::S32, policy, shift); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::U8, DataType::S32, policy, shift, 0); + + // 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({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute function + CLTensor dst = compute_depth_convert(shape, DataType::U8, DataType::S32, policy, shift); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::U8, DataType::S32, policy, shift, 0); + + // Validate output + validate(CLAccessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(U16_to_U8) +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({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute configure and validate region/padding + compute_configure_validate(shape, DataType::U16, DataType::U8, policy, shift); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute function + CLTensor dst = compute_depth_convert(shape, DataType::U16, DataType::U8, policy, shift); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::U16, DataType::U8, policy, shift, 0); + + // 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({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute function + CLTensor dst = compute_depth_convert(shape, DataType::U16, DataType::U8, policy, shift); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::U16, DataType::U8, policy, shift, 0); + + // Validate output + validate(CLAccessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(U16_to_U32) +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({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute configure and validate region/padding + compute_configure_validate(shape, DataType::U16, DataType::U32, policy, shift); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute function + CLTensor dst = compute_depth_convert(shape, DataType::U16, DataType::U32, policy, shift); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::U16, DataType::U32, policy, shift, 0); + + // 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({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute function + CLTensor dst = compute_depth_convert(shape, DataType::U16, DataType::U32, policy, shift); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::U16, DataType::U32, policy, shift, 0); + + // Validate output + validate(CLAccessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(S16_to_U8) +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({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute configure and validate region/padding + compute_configure_validate(shape, DataType::S16, DataType::U8, policy, shift); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute function + CLTensor dst = compute_depth_convert(shape, DataType::S16, DataType::U8, policy, shift); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::S16, DataType::U8, policy, shift, 0); + + // 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({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute function + CLTensor dst = compute_depth_convert(shape, DataType::S16, DataType::U8, policy, shift); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::S16, DataType::U8, policy, shift, 0); + + // Validate output + validate(CLAccessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(S16_to_S32) +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({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute configure and validate region/padding + compute_configure_validate(shape, DataType::S16, DataType::S32, policy, shift); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute function + CLTensor dst = compute_depth_convert(shape, DataType::S16, DataType::S32, policy, shift); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::S16, DataType::S32, policy, shift, 0); + + // 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({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute function + CLTensor dst = compute_depth_convert(shape, DataType::S16, DataType::S32, policy, shift); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::S16, DataType::S32, policy, shift, 0); + + // Validate output + validate(CLAccessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(Quantized_to_F32) +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::QS8, DataType::QS16 }) + * boost::unit_test::data::make({ ConvertPolicy::SATURATE }) * boost::unit_test::data::xrange(1, 7, 1), + shape, dt, policy, fixed_point_position) +{ + // Compute configure and validate region/padding + compute_configure_validate(shape, dt, DataType::F32, policy, 0, fixed_point_position); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE }) + * boost::unit_test::data::make({ DataType::QS8, DataType::QS16 }) * boost::unit_test::data::xrange(1, 7, 1), + shape, policy, dt, fixed_point_position) +{ + // Compute function + CLTensor dst = compute_depth_convert(shape, dt, DataType::F32, policy, 0, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, dt, DataType::F32, policy, 0, fixed_point_position); + + // 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::QS8, DataType::QS16 }) + * boost::unit_test::data::make({ ConvertPolicy::SATURATE }) * boost::unit_test::data::xrange(1, 7, 1), + shape, dt, policy, fixed_point_position) +{ + // Compute function + CLTensor dst = compute_depth_convert(shape, dt, DataType::F32, policy, 0, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, dt, DataType::F32, policy, 0, fixed_point_position); + + // Validate output + validate(CLAccessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(F32_to_Quantized) +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::QS8, DataType::QS16 }) + * boost::unit_test::data::make({ ConvertPolicy::SATURATE }) * boost::unit_test::data::xrange(1, 7, 1), + shape, dt, policy, fixed_point_position) +{ + // Compute configure and validate region/padding + compute_configure_validate(shape, DataType::F32, dt, policy, 0, fixed_point_position); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * boost::unit_test::data::make({ DataType::QS8, DataType::QS16 }) + * boost::unit_test::data::make({ ConvertPolicy::SATURATE }) * boost::unit_test::data::xrange(1, 7, 1), + shape, dt, policy, fixed_point_position) +{ + // Compute function + CLTensor dst = compute_depth_convert(shape, DataType::F32, dt, policy, 0, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::F32, dt, policy, 0, fixed_point_position, fixed_point_position); + + // 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::QS8, DataType::QS16 }) + * boost::unit_test::data::make({ ConvertPolicy::SATURATE }) * boost::unit_test::data::xrange(1, 7, 1), + shape, dt, policy, fixed_point_position) +{ + // Compute function + CLTensor dst = compute_depth_convert(shape, DataType::F32, dt, policy, 0, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::F32, dt, policy, 0, fixed_point_position, fixed_point_position); + + // Validate output + validate(CLAccessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/CL/FillBorder.cpp b/tests/validation_old/CL/FillBorder.cpp new file mode 100644 index 0000000000..ed47a1eeb3 --- /dev/null +++ b/tests/validation_old/CL/FillBorder.cpp @@ -0,0 +1,89 @@ +/* + * 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 "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Validation.h" + +#include "arm_compute/core/CL/kernels/CLFillBorderKernel.h" +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/CL/CLScheduler.h" +#include "arm_compute/runtime/CL/CLTensor.h" +#include "arm_compute/runtime/CL/CLTensorAllocator.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(CL) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(FillBorder, BorderModes() * boost::unit_test::data::make({ PaddingSize{ 0 }, PaddingSize{ 1, 0, 1, 2 }, PaddingSize{ 10 } }), border_mode, padding) +{ + constexpr uint8_t border_value = 42U; + constexpr uint8_t tensor_value = 89U; + BorderSize border_size{ 5 }; + + // Create tensors + CLTensor src = create_tensor<CLTensor>(TensorShape{ 10U, 10U, 2U }, DataType::U8); + + src.info()->extend_padding(padding); + + // Allocate tensor + src.allocator()->allocate(); + + // Check padding is as required + validate(src.info()->padding(), padding); + + // Fill tensor with constant value + std::uniform_int_distribution<uint8_t> distribution{ tensor_value, tensor_value }; + library->fill(CLAccessor(src), distribution, 0); + + // Create and configure kernel + CLFillBorderKernel fill_border; + fill_border.configure(&src, border_size, border_mode, border_value); + + // Run kernel + fill_border.run(fill_border.window(), CLScheduler::get().queue()); + + // Validate border + border_size.limit(padding); + validate(CLAccessor(src), border_size, border_mode, &border_value); + + // Validate tensor + validate(CLAccessor(src), &tensor_value); +} + +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/CL/FixedPoint/FixedPoint_QS8.cpp b/tests/validation_old/CL/FixedPoint/FixedPoint_QS8.cpp new file mode 100644 index 0000000000..3721fb51d7 --- /dev/null +++ b/tests/validation_old/CL/FixedPoint/FixedPoint_QS8.cpp @@ -0,0 +1,224 @@ +/* + * 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 "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" + +#include "arm_compute/core/CL/CLKernelLibrary.h" +#include "arm_compute/core/CL/ICLKernel.h" +#include "arm_compute/core/CL/OpenCL.h" +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/core/Window.h" +#include "arm_compute/runtime/CL/CLScheduler.h" +#include "arm_compute/runtime/CL/CLSubTensor.h" +#include "arm_compute/runtime/CL/CLTensor.h" +#include "arm_compute/runtime/CL/CLTensorAllocator.h" + +#include "arm_compute/core/CL/ICLTensor.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +const float tolerance_exp = 1.0f; /**< Tolerance value for comparing reference's output against implementation's output (exponential)*/ +const float tolerance_invsqrt = 4.0f; /**< Tolerance value for comparing reference's output against implementation's output (inverse square-root) */ +const float tolerance_log = 5.0f; /**< Tolerance value for comparing reference's output against implementation's output (logarithm) */ + +/** Compute Neon fixed point operation for signed 8bit fixed point. + * + * @param[in] shape Shape of the input and output tensors. + * + * @return Computed output tensor. + */ +CLTensor compute_fixed_point_op(const TensorShape &shape, int fixed_point_position, FixedPointOp op) +{ + std::string fixed_point_operation_kernel; +#ifndef EMBEDDED_KERNELS + fixed_point_operation_kernel += "#include \"fixed_point.h\"\n"; +#endif /* EMBEDDED_KERNELS */ + fixed_point_operation_kernel += + "__kernel void fixed_point_operation_qs8( \n" + " __global char* src, \n" + " __global char* dst) \n" + "{ \n" + " char16 in = vload16(0, src + get_global_id(0) * 16); \n" + " if(FIXED_POINT_OP == 0) \n" + " { \n" + " vstore16(EXP_OP_EXPAND(in, DATA_TYPE, 16, FIXED_POINT_POS), 0, dst + get_global_id(0) * 16); \n" + " } \n" + " else if(FIXED_POINT_OP == 1) \n" + " { \n" + " vstore16(INVSQRT_OP_EXPAND(in, DATA_TYPE, 16, FIXED_POINT_POS), 0, dst + get_global_id(0) * 16); \n" + " } \n" + " else \n" + " { \n" + " vstore16(LOG_OP_EXPAND(in, DATA_TYPE, 16, FIXED_POINT_POS), 0, dst + get_global_id(0) * 16); \n" + " } \n" + "} \n" + "\n"; + + // Create tensors + CLTensor src = create_tensor<CLTensor>(shape, DataType::QS8, 1, fixed_point_position); + CLTensor dst = create_tensor<CLTensor>(shape, DataType::QS8, 1, fixed_point_position); + + // Allocate tensors + src.allocator()->allocate(); + dst.allocator()->allocate(); + + BOOST_TEST(!src.info()->is_resizable()); + BOOST_TEST(!dst.info()->is_resizable()); + + // Set build options + std::string build_opts = "-DFIXED_POINT_POS=" + support::cpp11::to_string(fixed_point_position); + build_opts += " -DDATA_TYPE=qs8"; + + // Fill tensors. + int min = 0; + int max = 0; + switch(op) + { + case FixedPointOp::EXP: + min = -(1 << (fixed_point_position - 1)); + max = (1 << (fixed_point_position - 1)); + build_opts += " -DFIXED_POINT_OP=0"; + break; + case FixedPointOp::INV_SQRT: + min = 1; + max = 0x7F; + build_opts += " -DFIXED_POINT_OP=1"; + break; + case FixedPointOp::LOG: + min = (1 << (fixed_point_position - 1)); + max = 0x3F; + build_opts += " -DFIXED_POINT_OP=2"; + break; + default: + ARM_COMPUTE_ERROR("Operation not supported"); + } + + std::uniform_int_distribution<> distribution(min, max); + library->fill(CLAccessor(src), distribution, 0); + + std::vector<std::string> sources; + +#ifndef EMBEDDED_KERNELS + build_opts += " -I" + CLKernelLibrary::get().get_kernel_path(); +#else /* EMBEDDED_KERNELS */ + sources.push_back(CLKernelLibrary::get().get_program_source("fixed_point.h")); +#endif /* EMBEDDED_KERNELS */ + + sources.push_back(fixed_point_operation_kernel); + + // Create program + ::cl::Program program(sources); + + // Build program + program.build(build_opts.c_str()); + + ::cl::Kernel kernel(program, "fixed_point_operation_qs8", nullptr); + + unsigned int idx = 0; + kernel.setArg(idx++, src.cl_buffer()); + kernel.setArg(idx++, dst.cl_buffer()); + + ::cl::NDRange gws(shape[0] / 16, 1, 1); + CLScheduler::get().queue().enqueueNDRangeKernel(kernel, 0, gws); + + return dst; +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(CL) +BOOST_AUTO_TEST_SUITE(FixedPoint) +BOOST_AUTO_TEST_SUITE(QS8) + +BOOST_AUTO_TEST_SUITE(Exp) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunSmall, Small1DShape() * boost::unit_test::data::xrange(1, 6), shape, fixed_point_position) +{ + // Compute function + CLTensor dst = compute_fixed_point_op(shape, fixed_point_position, FixedPointOp::EXP); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_fixed_point_operation(shape, DataType::QS8, DataType::QS8, FixedPointOp::EXP, fixed_point_position); + + // Validate output + validate(CLAccessor(dst), ref_dst, tolerance_exp); +} + +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(Log) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunSmall, Small1DShape() * boost::unit_test::data::xrange(3, 6), shape, fixed_point_position) +{ + // Compute function + CLTensor dst = compute_fixed_point_op(shape, fixed_point_position, FixedPointOp::LOG); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_fixed_point_operation(shape, DataType::QS8, DataType::QS8, FixedPointOp::LOG, fixed_point_position); + + // Validate output + validate(CLAccessor(dst), ref_dst, tolerance_log); +} + +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(Invsqrt) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunSmall, Small1DShape() * boost::unit_test::data::xrange(1, 6), shape, fixed_point_position) +{ + // Compute function + CLTensor dst = compute_fixed_point_op(shape, fixed_point_position, FixedPointOp::INV_SQRT); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_fixed_point_operation(shape, DataType::QS8, DataType::QS8, FixedPointOp::INV_SQRT, fixed_point_position); + + // Validate output + validate(CLAccessor(dst), ref_dst, tolerance_invsqrt); +} + +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/CL/Gaussian3x3.cpp b/tests/validation_old/CL/Gaussian3x3.cpp new file mode 100644 index 0000000000..27f4833289 --- /dev/null +++ b/tests/validation_old/CL/Gaussian3x3.cpp @@ -0,0 +1,166 @@ +/* + * 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 "PaddingCalculator.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" +#include "tests/validation_old/ValidationUserConfiguration.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/CLGaussian3x3.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +constexpr unsigned int filter_size = 3; /** Size of the kernel/filter in number of elements. */ +constexpr BorderSize border_size(filter_size / 2); /** Border size of the kernel/filter around its central element. */ + +/** Compute CL gaussian3x3 filter. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] border_mode BorderMode used by the input tensor. + * @param[in] constant_border_value Constant to use if @p border_mode == CONSTANT. + * + * @return Computed output tensor. + */ +CLTensor compute_gaussian3x3(const TensorShape &shape, BorderMode border_mode, uint8_t constant_border_value) +{ + // Create tensors + CLTensor src = create_tensor<CLTensor>(shape, DataType::U8); + CLTensor dst = create_tensor<CLTensor>(shape, DataType::U8); + + // Create and configure function + CLGaussian3x3 gaussian3x3; + gaussian3x3.configure(&src, &dst, border_mode, constant_border_value); + + // 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 + gaussian3x3.run(); + + return dst; +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(CL) +BOOST_AUTO_TEST_SUITE(Gaussian3x3) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(Configuration, (SmallShapes() + LargeShapes()) * BorderModes(), shape, border_mode) +{ + // Create tensors + CLTensor src = create_tensor<CLTensor>(shape, DataType::U8); + CLTensor dst = create_tensor<CLTensor>(shape, DataType::U8); + + BOOST_TEST(src.info()->is_resizable()); + BOOST_TEST(dst.info()->is_resizable()); + + // Create and configure function + CLGaussian3x3 gaussian3x3; + gaussian3x3.configure(&src, &dst, border_mode); + + // Validate valid region + const ValidRegion src_valid_region = shape_to_valid_region(shape); + const ValidRegion dst_valid_region = shape_to_valid_region(shape, border_mode == BorderMode::UNDEFINED, border_size); + validate(src.info()->valid_region(), src_valid_region); + validate(dst.info()->valid_region(), dst_valid_region); + + // Validate padding + PaddingCalculator calculator(shape.x(), 8); + calculator.set_border_size(1); + calculator.set_border_mode(border_mode); + + const PaddingSize dst_padding = calculator.required_padding(); + + calculator.set_accessed_elements(16); + calculator.set_access_offset(-1); + + const PaddingSize src_padding = calculator.required_padding(); + + validate(src.info()->padding(), src_padding); + validate(dst.info()->padding(), dst_padding); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * BorderModes(), shape, border_mode) +{ + std::mt19937 gen(user_config.seed.get()); + std::uniform_int_distribution<uint8_t> distribution(0, 255); + const uint8_t border_value = distribution(gen); + + // Compute function + CLTensor dst = compute_gaussian3x3(shape, border_mode, border_value); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_gaussian3x3(shape, border_mode, border_value); + + // Validate output + validate(CLAccessor(dst), ref_dst, shape_to_valid_region(shape, border_mode == BorderMode::UNDEFINED, border_size)); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * BorderModes(), shape, border_mode) +{ + std::mt19937 gen(user_config.seed.get()); + std::uniform_int_distribution<uint8_t> distribution(0, 255); + const uint8_t border_value = distribution(gen); + + // Compute function + CLTensor dst = compute_gaussian3x3(shape, border_mode, border_value); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_gaussian3x3(shape, border_mode, border_value); + + // Validate output + validate(CLAccessor(dst), ref_dst, shape_to_valid_region(shape, border_mode == BorderMode::UNDEFINED, border_size)); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/CL/Gaussian5x5.cpp b/tests/validation_old/CL/Gaussian5x5.cpp new file mode 100644 index 0000000000..c187426f4c --- /dev/null +++ b/tests/validation_old/CL/Gaussian5x5.cpp @@ -0,0 +1,166 @@ +/* + * 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 "PaddingCalculator.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" +#include "tests/validation_old/ValidationUserConfiguration.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/CLGaussian5x5.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +constexpr unsigned int filter_size = 5; /** Size of the kernel/filter in number of elements. */ +constexpr BorderSize border_size(filter_size / 2); /** Border size of the kernel/filter around its central element. */ + +/** Compute CL gaussian5x5 filter. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] border_mode BorderMode used by the input tensor. + * @param[in] constant_border_value Constant to use if @p border_mode == CONSTANT. + * + * @return Computed output tensor. + */ +CLTensor compute_gaussian5x5(const TensorShape &shape, BorderMode border_mode, uint8_t constant_border_value) +{ + // Create tensors + CLTensor src = create_tensor<CLTensor>(shape, DataType::U8); + CLTensor dst = create_tensor<CLTensor>(shape, DataType::U8); + + // Create and configure function + CLGaussian5x5 gaussian5x5; + gaussian5x5.configure(&src, &dst, border_mode, constant_border_value); + + // 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 + gaussian5x5.run(); + + return dst; +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(CL) +BOOST_AUTO_TEST_SUITE(Gaussian5x5) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(Configuration, (SmallShapes() + LargeShapes()) * BorderModes(), shape, border_mode) +{ + // Create tensors + CLTensor src = create_tensor<CLTensor>(shape, DataType::U8); + CLTensor dst = create_tensor<CLTensor>(shape, DataType::U8); + + BOOST_TEST(src.info()->is_resizable()); + BOOST_TEST(dst.info()->is_resizable()); + + // Create and configure function + CLGaussian5x5 gaussian5x5; + gaussian5x5.configure(&src, &dst, border_mode); + + // Validate valid region + const ValidRegion src_valid_region = shape_to_valid_region(shape); + const ValidRegion dst_valid_region = shape_to_valid_region(shape, border_mode == BorderMode::UNDEFINED, border_size); + validate(src.info()->valid_region(), src_valid_region); + validate(dst.info()->valid_region(), dst_valid_region); + + // Validate padding + PaddingCalculator calculator(shape.x(), 8); + calculator.set_border_size(2); + calculator.set_border_mode(border_mode); + + const PaddingSize dst_padding = calculator.required_padding(); + + calculator.set_accessed_elements(16); + calculator.set_access_offset(-2); + + const PaddingSize src_padding = calculator.required_padding(); + + validate(src.info()->padding(), src_padding); + validate(dst.info()->padding(), dst_padding); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * BorderModes(), shape, border_mode) +{ + std::mt19937 gen(user_config.seed.get()); + std::uniform_int_distribution<uint8_t> distribution(0, 255); + const uint8_t border_value = distribution(gen); + + // Compute function + CLTensor dst = compute_gaussian5x5(shape, border_mode, border_value); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_gaussian5x5(shape, border_mode, border_value); + + // Validate output + validate(CLAccessor(dst), ref_dst, shape_to_valid_region(shape, border_mode == BorderMode::UNDEFINED, border_size)); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * BorderModes(), shape, border_mode) +{ + std::mt19937 gen(user_config.seed.get()); + std::uniform_int_distribution<uint8_t> distribution(0, 255); + const uint8_t border_value = distribution(gen); + + // Compute function + CLTensor dst = compute_gaussian5x5(shape, border_mode, border_value); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_gaussian5x5(shape, border_mode, border_value); + + // Validate output + validate(CLAccessor(dst), ref_dst, shape_to_valid_region(shape, border_mode == BorderMode::UNDEFINED, border_size)); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/CL/HarrisCorners.cpp b/tests/validation_old/CL/HarrisCorners.cpp new file mode 100644 index 0000000000..2c73679058 --- /dev/null +++ b/tests/validation_old/CL/HarrisCorners.cpp @@ -0,0 +1,224 @@ +/* + * 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 "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" +#include "tests/validation_old/ValidationUserConfiguration.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/CL/CLArray.h" +#include "arm_compute/runtime/CL/functions/CLHarrisCorners.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include "PaddingCalculator.h" +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +/** Compute CL Harris corners function. + * + * @param[in] shape Shape of input tensor + * @param[in] threshold Minimum threshold with which to eliminate Harris Corner scores (computed using the normalized Sobel kernel). + * @param[in] min_dist Radial Euclidean distance for the euclidean distance stage + * @param[in] sensitivity Sensitivity threshold k from the Harris-Stephens equation + * @param[in] gradient_size The gradient window size to use on the input. The implementation supports 3, 5, and 7 + * @param[in] block_size The block window size used to compute the Harris Corner score. The implementation supports 3, 5, and 7. + * @param[in] border_mode Border mode to use + * @param[in] constant_border_value Constant value to use for borders if border_mode is set to CONSTANT. + * + * @return Computed corners' keypoints. + */ +void compute_harris_corners(const TensorShape &shape, CLKeyPointArray &corners, float threshold, float min_dist, float sensitivity, + int32_t gradient_size, int32_t block_size, BorderMode border_mode, uint8_t constant_border_value) +{ + // Create tensors + CLTensor src = create_tensor<CLTensor>(shape, DataType::U8); + src.info()->set_format(Format::U8); + + // Create harris corners configure function + CLHarrisCorners harris_corners; + harris_corners.configure(&src, threshold, min_dist, sensitivity, gradient_size, block_size, &corners, border_mode, constant_border_value); + + // Allocate tensors + src.allocator()->allocate(); + + BOOST_TEST(!src.info()->is_resizable()); + + // Fill tensors + library->fill_tensor_uniform(CLAccessor(src), 0); + + // Compute function + harris_corners.run(); +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(CL) +BOOST_AUTO_TEST_SUITE(HarrisCorners) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(Configuration, (Small2DShapes() + Large2DShapes()) * BorderModes() + * boost::unit_test::data::make({ 3, 5, 7 }) * boost::unit_test::data::make({ 3, 5, 7 }), + shape, border_mode, gradient, block) +{ + // Create tensors + CLTensor src = create_tensor<CLTensor>(shape, DataType::U8); + src.info()->set_format(Format::U8); + + CLKeyPointArray corners(shape.total_size()); + + uint8_t constant_border_value = 0; + + std::mt19937 gen(user_config.seed.get()); + std::uniform_real_distribution<float> real_dist(0.01, std::numeric_limits<float>::min()); + + const float threshold = real_dist(gen); + const float sensitivity = real_dist(gen); + const float max_euclidean_distance = 30.f; + + real_dist = std::uniform_real_distribution<float>(0.f, max_euclidean_distance); + float min_dist = real_dist(gen); + + // Generate a random constant value if border_mode is constant + if(border_mode == BorderMode::CONSTANT) + { + std::uniform_int_distribution<uint8_t> int_dist(0, 255); + constant_border_value = int_dist(gen); + } + + BOOST_TEST(src.info()->is_resizable()); + + // Create harris corners configure function + CLHarrisCorners harris_corners; + harris_corners.configure(&src, threshold, min_dist, sensitivity, gradient, block, &corners, border_mode, constant_border_value); + + // Validate valid region + const ValidRegion valid_region = shape_to_valid_region(shape); + + validate(src.info()->valid_region(), valid_region); + + // Validate padding + PaddingCalculator calculator(shape.x(), 8); + + calculator.set_border_mode(border_mode); + calculator.set_border_size(gradient / 2); + calculator.set_access_offset(-gradient / 2); + calculator.set_accessed_elements(16); + + const PaddingSize padding = calculator.required_padding(); + + validate(src.info()->padding(), padding); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, Small2DShapes() * BorderModes() * boost::unit_test::data::make({ 3, 5, 7 }) * boost::unit_test::data::make({ 3, 5, 7 }), shape, border_mode, gradient, block) +{ + uint8_t constant_border_value = 0; + + std::mt19937 gen(user_config.seed.get()); + std::uniform_real_distribution<float> real_dist(0.01, std::numeric_limits<float>::min()); + + const float threshold = real_dist(gen); + const float sensitivity = real_dist(gen); + const float max_euclidean_distance = 30.f; + + real_dist = std::uniform_real_distribution<float>(0.f, max_euclidean_distance); + const float min_dist = real_dist(gen); + + // Generate a random constant value if border_mode is constant + if(border_mode == BorderMode::CONSTANT) + { + std::uniform_int_distribution<uint8_t> int_dist(0, 255); + constant_border_value = int_dist(gen); + } + + // Create array of keypoints + CLKeyPointArray dst(shape.total_size()); + + // Compute function + compute_harris_corners(shape, dst, threshold, min_dist, sensitivity, gradient, block, border_mode, constant_border_value); + + // Compute reference + KeyPointArray ref_dst = Reference::compute_reference_harris_corners(shape, threshold, min_dist, sensitivity, gradient, block, border_mode, constant_border_value); + + // Validate output + dst.map(); + validate(dst, ref_dst, 1); + dst.unmap(); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, Large2DShapes() * BorderModes() * boost::unit_test::data::make({ 3, 5, 7 }) * boost::unit_test::data::make({ 3, 5, 7 }), shape, border_mode, gradient, block) +{ + uint8_t constant_border_value = 0; + + std::mt19937 gen(user_config.seed.get()); + std::uniform_real_distribution<float> real_dist(0.01, std::numeric_limits<float>::min()); + + const float threshold = real_dist(gen); + const float sensitivity = real_dist(gen); + const float max_euclidean_distance = 30.f; + + real_dist = std::uniform_real_distribution<float>(0.f, max_euclidean_distance); + const float min_dist = real_dist(gen); + + // Generate a random constant value if border_mode is constant + if(border_mode == BorderMode::CONSTANT) + { + std::uniform_int_distribution<uint8_t> int_dist(0, 255); + constant_border_value = int_dist(gen); + } + + // Create array of keypoints + CLKeyPointArray dst(shape.total_size()); + + // Compute function + compute_harris_corners(shape, dst, threshold, min_dist, sensitivity, gradient, block, border_mode, constant_border_value); + + // Compute reference + KeyPointArray ref_dst = Reference::compute_reference_harris_corners(shape, threshold, min_dist, sensitivity, gradient, block, border_mode, constant_border_value); + + // Validate output + dst.map(); + validate(dst, ref_dst); + dst.unmap(); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/CL/IntegralImage.cpp b/tests/validation_old/CL/IntegralImage.cpp new file mode 100644 index 0000000000..ea15b90b2a --- /dev/null +++ b/tests/validation_old/CL/IntegralImage.cpp @@ -0,0 +1,142 @@ +/* + * 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 "PaddingCalculator.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/CL/functions/CLIntegralImage.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +/** Compute CL integral image function. + * + * @param[in] shape Shape of the input and output tensors. + * + * @return Computed output tensor. + */ +CLTensor compute_integral_image(const TensorShape &shape) +{ + // Create tensors + CLTensor src = create_tensor<CLTensor>(shape, DataType::U8); + CLTensor dst = create_tensor<CLTensor>(shape, DataType::U32); + + // Create integral image configure function + CLIntegralImage integral_image; + integral_image.configure(&src, &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 + integral_image.run(); + + return dst; +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(CL) +BOOST_AUTO_TEST_SUITE(IntegralImage) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(Configuration, SmallShapes() + LargeShapes(), shape) +{ + // Create tensors + CLTensor src = create_tensor<CLTensor>(shape, DataType::U8); + CLTensor dst = create_tensor<CLTensor>(shape, DataType::U32); + + BOOST_TEST(src.info()->is_resizable()); + BOOST_TEST(dst.info()->is_resizable()); + + // Create integral image configure function + CLIntegralImage integral_image; + integral_image.configure(&src, &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(), shape) +{ + // Compute function + CLTensor dst = compute_integral_image(shape); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_integral_image(shape); + + // Validate output + validate(CLAccessor(dst), ref_dst); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes(), shape) +{ + // Compute function + CLTensor dst = compute_integral_image(shape); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_integral_image(shape); + + // 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_old/CL/MinMaxLocation.cpp b/tests/validation_old/CL/MinMaxLocation.cpp new file mode 100644 index 0000000000..8824215223 --- /dev/null +++ b/tests/validation_old/CL/MinMaxLocation.cpp @@ -0,0 +1,397 @@ +/* + * 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 "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/CL/functions/CLMinMaxLocation.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include "PaddingCalculator.h" +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +/** Compute CL MinMaxLocation function. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] dt_in Data type of first input tensor. + * @param[out] min Minimum value of tensor + * @param[out] max Maximum value of tensor + * @param[out] min_loc Array with locations of minimum values + * @param[out] max_loc Array with locations of maximum values + * @param[out] min_count Number of minimum values found + * @param[out] max_count Number of maximum values found + * + * @return Computed output tensor. + */ +void compute_min_max_location(const TensorShape &shape, DataType dt_in, void *min, void *max, + CLCoordinates2DArray &min_loc, CLCoordinates2DArray &max_loc, uint32_t &min_count, uint32_t &max_count) +{ + // Create tensor + CLTensor src = create_tensor<CLTensor>(shape, dt_in); + + // Create and configure min_max_location configure function + CLMinMaxLocation min_max_loc; + min_max_loc.configure(&src, min, max, &min_loc, &max_loc, &min_count, &max_count); + + // Allocate tensors + src.allocator()->allocate(); + + BOOST_TEST(!src.info()->is_resizable()); + + // Fill tensors + library->fill_tensor_uniform(CLAccessor(src), 0); + + // Compute function + min_max_loc.run(); +} + +void validate_configuration(const CLTensor &src, TensorShape shape) +{ + BOOST_TEST(src.info()->is_resizable()); + + // Create output storage + int32_t min; + int32_t max; + CLCoordinates2DArray min_loc(shape.total_size()); + CLCoordinates2DArray max_loc(shape.total_size()); + uint32_t min_count; + uint32_t max_count; + + // Create and configure function + CLMinMaxLocation min_max_loc; + min_max_loc.configure(&src, &min, &max, &min_loc, &max_loc, &min_count, &max_count); + + // Validate valid region + const ValidRegion valid_region = shape_to_valid_region(shape); + validate(src.info()->valid_region(), valid_region); + + // Validate padding + const PaddingSize padding = PaddingCalculator(shape.x(), src.info()->dimension(0)).required_padding(); + validate(src.info()->padding(), padding); +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(CL) +BOOST_AUTO_TEST_SUITE(MinMaxLocation) +BOOST_AUTO_TEST_SUITE(U8) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(Configuration, (Small2DShapes() + Large2DShapes()), + shape) +{ + // Create tensor + CLTensor src = create_tensor<CLTensor>(shape, DataType::U8); + src.info()->set_format(Format::U8); + + validate_configuration(src, shape); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, Small2DShapes(), + shape) +{ + // Create output storage + int32_t min; + int32_t max; + CLCoordinates2DArray min_loc(shape.total_size()); + CLCoordinates2DArray max_loc(shape.total_size()); + uint32_t min_count; + uint32_t max_count; + + int32_t ref_min; + int32_t ref_max; + CLCoordinates2DArray ref_min_loc(shape.total_size()); + CLCoordinates2DArray ref_max_loc(shape.total_size()); + uint32_t ref_min_count; + uint32_t ref_max_count; + + // Compute function + compute_min_max_location(shape, DataType::U8, &min, &max, min_loc, max_loc, min_count, max_count); + + // Compute reference + ref_min_loc.map(); + ref_max_loc.map(); + + Reference::compute_reference_min_max_location(shape, DataType::U8, &ref_min, &ref_max, ref_min_loc, ref_max_loc, ref_min_count, ref_max_count); + + min_loc.map(); + max_loc.map(); + + // Validate output + validate_min_max_loc(min, ref_min, max, ref_max, min_loc, ref_min_loc, max_loc, ref_max_loc, min_count, ref_min_count, max_count, ref_max_count); + + ref_min_loc.unmap(); + ref_max_loc.unmap(); + min_loc.unmap(); + max_loc.unmap(); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, Large2DShapes(), + shape) +{ + // Create output storage + int32_t min; + int32_t max; + CLCoordinates2DArray min_loc(shape.total_size()); + CLCoordinates2DArray max_loc(shape.total_size()); + uint32_t min_count; + uint32_t max_count; + + int32_t ref_min; + int32_t ref_max; + CLCoordinates2DArray ref_min_loc(shape.total_size()); + CLCoordinates2DArray ref_max_loc(shape.total_size()); + uint32_t ref_min_count; + uint32_t ref_max_count; + + // Compute function + compute_min_max_location(shape, DataType::U8, &min, &max, min_loc, max_loc, min_count, max_count); + + // Compute reference + ref_min_loc.map(); + ref_max_loc.map(); + + Reference::compute_reference_min_max_location(shape, DataType::U8, &ref_min, &ref_max, ref_min_loc, ref_max_loc, ref_min_count, ref_max_count); + + min_loc.map(); + max_loc.map(); + + // Validate output + validate_min_max_loc(min, ref_min, max, ref_max, min_loc, ref_min_loc, max_loc, ref_max_loc, min_count, ref_min_count, max_count, ref_max_count); + + ref_min_loc.unmap(); + ref_max_loc.unmap(); + min_loc.unmap(); + max_loc.unmap(); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(S16) +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(Configuration, (Small2DShapes() + Large2DShapes()), + shape) +{ + // Create tensor + CLTensor src = create_tensor<CLTensor>(shape, DataType::S16); + src.info()->set_format(Format::S16); + + validate_configuration(src, shape); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, Small2DShapes(), + shape) +{ + // Create output storage + int32_t min; + int32_t max; + CLCoordinates2DArray min_loc(shape.total_size()); + CLCoordinates2DArray max_loc(shape.total_size()); + uint32_t min_count; + uint32_t max_count; + + int32_t ref_min; + int32_t ref_max; + CLCoordinates2DArray ref_min_loc(shape.total_size()); + CLCoordinates2DArray ref_max_loc(shape.total_size()); + uint32_t ref_min_count; + uint32_t ref_max_count; + + // Compute function + compute_min_max_location(shape, DataType::S16, &min, &max, min_loc, max_loc, min_count, max_count); + + // Compute reference + ref_min_loc.map(); + ref_max_loc.map(); + + Reference::compute_reference_min_max_location(shape, DataType::S16, &ref_min, &ref_max, ref_min_loc, ref_max_loc, ref_min_count, ref_max_count); + + min_loc.map(); + max_loc.map(); + + // Validate output + validate_min_max_loc(min, ref_min, max, ref_max, min_loc, ref_min_loc, max_loc, ref_max_loc, min_count, ref_min_count, max_count, ref_max_count); + + ref_min_loc.unmap(); + ref_max_loc.unmap(); + min_loc.unmap(); + max_loc.unmap(); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, Large2DShapes(), + shape) +{ + // Create output storage + int32_t min; + int32_t max; + CLCoordinates2DArray min_loc(shape.total_size()); + CLCoordinates2DArray max_loc(shape.total_size()); + uint32_t min_count; + uint32_t max_count; + + int32_t ref_min; + int32_t ref_max; + CLCoordinates2DArray ref_min_loc(shape.total_size()); + CLCoordinates2DArray ref_max_loc(shape.total_size()); + uint32_t ref_min_count; + uint32_t ref_max_count; + + // Compute function + compute_min_max_location(shape, DataType::S16, &min, &max, min_loc, max_loc, min_count, max_count); + + // Compute reference + ref_min_loc.map(); + ref_max_loc.map(); + + Reference::compute_reference_min_max_location(shape, DataType::S16, &ref_min, &ref_max, ref_min_loc, ref_max_loc, ref_min_count, ref_max_count); + + min_loc.map(); + max_loc.map(); + + // Validate output + validate_min_max_loc(min, ref_min, max, ref_max, min_loc, ref_min_loc, max_loc, ref_max_loc, min_count, ref_min_count, max_count, ref_max_count); + + ref_min_loc.unmap(); + ref_max_loc.unmap(); + min_loc.unmap(); + max_loc.unmap(); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(Float) +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(Configuration, (Small2DShapes() + Large2DShapes()), + shape) +{ + // Create tensor + CLTensor src = create_tensor<CLTensor>(shape, DataType::F32); + + validate_configuration(src, shape); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, Small2DShapes(), + shape) +{ + // Create output storage + float min; + float max; + CLCoordinates2DArray min_loc(shape.total_size()); + CLCoordinates2DArray max_loc(shape.total_size()); + uint32_t min_count; + uint32_t max_count; + + float ref_min; + float ref_max; + CLCoordinates2DArray ref_min_loc(shape.total_size()); + CLCoordinates2DArray ref_max_loc(shape.total_size()); + uint32_t ref_min_count; + uint32_t ref_max_count; + + // Compute function + compute_min_max_location(shape, DataType::F32, &min, &max, min_loc, max_loc, min_count, max_count); + + // Compute reference + ref_min_loc.map(); + ref_max_loc.map(); + + Reference::compute_reference_min_max_location(shape, DataType::F32, &ref_min, &ref_max, ref_min_loc, ref_max_loc, ref_min_count, ref_max_count); + + min_loc.map(); + max_loc.map(); + + // Validate output + validate_min_max_loc(min, ref_min, max, ref_max, min_loc, ref_min_loc, max_loc, ref_max_loc, min_count, ref_min_count, max_count, ref_max_count); + + ref_min_loc.unmap(); + ref_max_loc.unmap(); + min_loc.unmap(); + max_loc.unmap(); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, Large2DShapes(), + shape) +{ + // Create output storage + float min; + float max; + CLCoordinates2DArray min_loc(shape.total_size()); + CLCoordinates2DArray max_loc(shape.total_size()); + uint32_t min_count; + uint32_t max_count; + + float ref_min; + float ref_max; + CLCoordinates2DArray ref_min_loc(shape.total_size()); + CLCoordinates2DArray ref_max_loc(shape.total_size()); + uint32_t ref_min_count; + uint32_t ref_max_count; + + // Compute function + compute_min_max_location(shape, DataType::F32, &min, &max, min_loc, max_loc, min_count, max_count); + + // Compute reference + ref_min_loc.map(); + ref_max_loc.map(); + + Reference::compute_reference_min_max_location(shape, DataType::F32, &ref_min, &ref_max, ref_min_loc, ref_max_loc, ref_min_count, ref_max_count); + + min_loc.map(); + max_loc.map(); + + // Validate output + validate_min_max_loc(min, ref_min, max, ref_max, min_loc, ref_min_loc, max_loc, ref_max_loc, min_count, ref_min_count, max_count, ref_max_count); + + ref_min_loc.unmap(); + ref_max_loc.unmap(); + min_loc.unmap(); + max_loc.unmap(); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/CL/NonLinearFilter.cpp b/tests/validation_old/CL/NonLinearFilter.cpp new file mode 100644 index 0000000000..0132f7db8c --- /dev/null +++ b/tests/validation_old/CL/NonLinearFilter.cpp @@ -0,0 +1,203 @@ +/* + * 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 "PaddingCalculator.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Helpers.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" +#include "tests/validation_old/ValidationUserConfiguration.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/CL/functions/CLNonLinearFilter.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +/** Compute NonLinearFilter function. + * + * @param[in] input Shape of the input and output tensors. + * @param[in] function Non linear function to perform + * @param[in] mask_size Mask size. Supported sizes: 3, 5 + * @param[in] pattern Mask pattern + * @param[in] mask The given mask. Will be used only if pattern is specified to PATTERN_OTHER + * @param[in] border_mode Strategy to use for borders. + * @param[in] constant_border_value (Optional) Constant value to use for borders if border_mode is set to CONSTANT. + * + * @return Computed output CL tensor. + */ +CLTensor compute_non_linear_filter(const TensorShape &shape, NonLinearFilterFunction function, unsigned int mask_size, + MatrixPattern pattern, const uint8_t *mask, BorderMode border_mode, + uint8_t constant_border_value) +{ + // Create tensors + CLTensor src = create_tensor<CLTensor>(shape, DataType::U8); + CLTensor dst = create_tensor<CLTensor>(shape, DataType::U8); + + // Create and configure function + CLNonLinearFilter filter; + filter.configure(&src, &dst, function, mask_size, pattern, mask, border_mode, constant_border_value); + + // 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 + filter.run(); + + return dst; +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(CL) +BOOST_AUTO_TEST_SUITE(NonLinearFilter) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(Configuration, (SmallShapes() + LargeShapes()) + * NonLinearFilterFunctions() * boost::unit_test::data::make({ 3U, 5U }) + * boost::unit_test::data::make({ MatrixPattern::BOX, MatrixPattern::CROSS, MatrixPattern::DISK }) * BorderModes(), + shape, function, mask_size, pattern, border_mode) +{ + std::mt19937 generator(user_config.seed.get()); + std::uniform_int_distribution<uint8_t> distribution_u8(0, 255); + const uint8_t constant_border_value = distribution_u8(generator); + + // Create the mask + uint8_t mask[mask_size * mask_size]; + fill_mask_from_pattern(mask, mask_size, mask_size, pattern); + const auto half_mask_size = static_cast<int>(mask_size / 2); + + // Create tensors + CLTensor src = create_tensor<CLTensor>(shape, DataType::U8); + CLTensor dst = create_tensor<CLTensor>(shape, DataType::U8); + + BOOST_TEST(src.info()->is_resizable()); + BOOST_TEST(dst.info()->is_resizable()); + + // Create and configure function + CLNonLinearFilter filter; + filter.configure(&src, &dst, function, mask_size, pattern, mask, border_mode, constant_border_value); + + // Validate valid region + const ValidRegion src_valid_region = shape_to_valid_region(shape); + const ValidRegion dst_valid_region = shape_to_valid_region(shape, border_mode == BorderMode::UNDEFINED, BorderSize(half_mask_size)); + + validate(src.info()->valid_region(), src_valid_region); + validate(dst.info()->valid_region(), dst_valid_region); + + // Validate padding + PaddingCalculator calculator(shape.x(), ((MatrixPattern::OTHER == pattern) ? 1 : 8)); + calculator.set_border_mode(border_mode); + calculator.set_border_size(half_mask_size); + + const PaddingSize write_padding = calculator.required_padding(PaddingCalculator::Option::EXCLUDE_BORDER); + + calculator.set_accessed_elements(16); + calculator.set_access_offset(-half_mask_size); + + const PaddingSize read_padding = calculator.required_padding(PaddingCalculator::Option::INCLUDE_BORDER); + + validate(src.info()->padding(), read_padding); + validate(dst.info()->padding(), write_padding); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() + * NonLinearFilterFunctions() * boost::unit_test::data::make({ 3U, 5U }) + * boost::unit_test::data::make({ MatrixPattern::BOX, MatrixPattern::CROSS, MatrixPattern::DISK }) * BorderModes(), + shape, function, mask_size, pattern, border_mode) +{ + std::mt19937 generator(user_config.seed.get()); + std::uniform_int_distribution<uint8_t> distribution_u8(0, 255); + const uint8_t constant_border_value = distribution_u8(generator); + + // Create the mask + uint8_t mask[mask_size * mask_size]; + fill_mask_from_pattern(mask, mask_size, mask_size, pattern); + + // Compute function + CLTensor dst = compute_non_linear_filter(shape, function, mask_size, pattern, mask, border_mode, constant_border_value); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_non_linear_filter(shape, function, mask_size, pattern, mask, border_mode, constant_border_value); + + // Calculate valid region + const ValidRegion valid_region = shape_to_valid_region(shape, border_mode == BorderMode::UNDEFINED, BorderSize(static_cast<int>(mask_size / 2))); + + // Validate output + validate(CLAccessor(dst), ref_dst, valid_region); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() + * NonLinearFilterFunctions() * boost::unit_test::data::make({ 3U, 5U }) + * boost::unit_test::data::make({ MatrixPattern::BOX, MatrixPattern::CROSS, MatrixPattern::DISK }) * BorderModes(), + shape, function, mask_size, pattern, border_mode) +{ + std::mt19937 generator(user_config.seed.get()); + std::uniform_int_distribution<uint8_t> distribution_u8(0, 255); + const uint8_t constant_border_value = distribution_u8(generator); + + // Create the mask + uint8_t mask[mask_size * mask_size]; + fill_mask_from_pattern(mask, mask_size, mask_size, pattern); + + // Compute function + CLTensor dst = compute_non_linear_filter(shape, function, mask_size, pattern, mask, border_mode, constant_border_value); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_non_linear_filter(shape, function, mask_size, pattern, mask, border_mode, constant_border_value); + + // Calculate valid region + const ValidRegion valid_region = shape_to_valid_region(shape, border_mode == BorderMode::UNDEFINED, BorderSize(static_cast<int>(mask_size / 2))); + + // Validate output + validate(CLAccessor(dst), ref_dst, valid_region); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/CL/PixelWiseMultiplication.cpp b/tests/validation_old/CL/PixelWiseMultiplication.cpp new file mode 100644 index 0000000000..f003298a23 --- /dev/null +++ b/tests/validation_old/CL/PixelWiseMultiplication.cpp @@ -0,0 +1,164 @@ +/* + * 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 "TypePrinter.h" +#include "tests/Globals.h" +#include "tests/Utils.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" + +#include "arm_compute/runtime/CL/functions/CLPixelWiseMultiplication.h" + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +const float tolerance_f32 = 1.f; /**< Tolerance value for comparing reference's output against implementation's output for float input */ +const float tolerance_f16 = 1.f; /**< Tolerance value for comparing reference's output against implementation's output for float input */ + +/** Compute CL pixel-wise multiplication function. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] dt_in0 Data type of first input tensor. + * @param[in] dt_in1 Data type of second input tensor. + * @param[in] dt_out Data type of the output tensor. + * @param[in] scale Non-negative scale. + * @param[in] convert_policy Overflow policy of the operation. + * @param[in] rounding_policy Rounding policy of the operation. + * @param[in] fixed_point_position (Optional) Fixed point position that expresses the number of bits for the fractional part of the number. + * + * @return Computed output tensor. + */ +CLTensor compute_pixel_wise_multiplication(const TensorShape &shape, DataType dt_in0, DataType dt_in1, DataType dt_out, float scale, ConvertPolicy convert_policy, RoundingPolicy rounding_policy, + int fixed_point_position = 0) +{ + // Create tensors + CLTensor src1 = create_tensor<CLTensor>(shape, dt_in0, 1, fixed_point_position); + CLTensor src2 = create_tensor<CLTensor>(shape, dt_in1, 1, fixed_point_position); + CLTensor dst = create_tensor<CLTensor>(shape, dt_out, 1, fixed_point_position); + + // Create and configure function + CLPixelWiseMultiplication multiply; + multiply.configure(&src1, &src2, &dst, scale, convert_policy, rounding_policy); + + // Allocate tensors + src1.allocator()->allocate(); + src2.allocator()->allocate(); + dst.allocator()->allocate(); + + BOOST_TEST(!src1.info()->is_resizable()); + BOOST_TEST(!src2.info()->is_resizable()); + BOOST_TEST(!dst.info()->is_resizable()); + + // Fill tensors + library->fill_tensor_uniform(CLAccessor(src1), 0); + library->fill_tensor_uniform(CLAccessor(src2), 1); + + // Compute function + multiply.run(); + + return dst; +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(CL) +BOOST_AUTO_TEST_SUITE(PixelWiseMultiplication) + +BOOST_AUTO_TEST_SUITE(Float16) +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * DataType::F16 *ConvertPolicies() * RoundingPolicy::TO_NEAREST_UP, + shape, dt, convert_policy, rounding_policy) +{ + constexpr float scale = 1.f / 255.f; + + // Compute function + CLTensor dst = compute_pixel_wise_multiplication(shape, dt, dt, dt, scale, convert_policy, rounding_policy); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_pixel_wise_multiplication(shape, dt, dt, dt, scale, convert_policy, rounding_policy); + + // Validate output + validate(CLAccessor(dst), ref_dst, tolerance_f16); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(Float) +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * DataType::F32 *ConvertPolicies() * RoundingPolicy::TO_NEAREST_UP, + shape, dt, convert_policy, rounding_policy) +{ + constexpr float scale = 1.f / 255.f; + + // Compute function + CLTensor dst = compute_pixel_wise_multiplication(shape, dt, dt, dt, scale, convert_policy, rounding_policy); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_pixel_wise_multiplication(shape, dt, dt, dt, scale, convert_policy, rounding_policy); + + // Validate output + validate(CLAccessor(dst), ref_dst, tolerance_f32); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(Quantized) +BOOST_AUTO_TEST_SUITE(QS8) +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * DataType::QS8 *ConvertPolicies() * RoundingPolicy::TO_ZERO * boost::unit_test::data::xrange<int>(1, 7), + shape, dt, convert_policy, rounding_policy, fixed_point_position) +{ + // Compute function + CLTensor dst = compute_pixel_wise_multiplication(shape, dt, dt, dt, 1.f, convert_policy, rounding_policy, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_fixed_point_pixel_wise_multiplication(shape, dt, dt, dt, 1.f, fixed_point_position, convert_policy, rounding_policy); + + // Validate output + validate(CLAccessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(QS16) +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * DataType::QS16 *ConvertPolicies() * RoundingPolicy::TO_ZERO * boost::unit_test::data::xrange<int>(1, 15), + shape, dt, convert_policy, rounding_policy, fixed_point_position) +{ + // Compute function + CLTensor dst = compute_pixel_wise_multiplication(shape, dt, dt, dt, 1.f, convert_policy, rounding_policy, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_fixed_point_pixel_wise_multiplication(shape, dt, dt, dt, 1.f, fixed_point_position, convert_policy, rounding_policy); + + // Validate output + validate(CLAccessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif // DOXYGEN_SKIP_THIS diff --git a/tests/validation_old/CL/ROIPoolingLayer.cpp b/tests/validation_old/CL/ROIPoolingLayer.cpp new file mode 100644 index 0000000000..edd1cccf2a --- /dev/null +++ b/tests/validation_old/CL/ROIPoolingLayer.cpp @@ -0,0 +1,112 @@ +/* + * 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/CLArrayAccessor.h" +#include "TypePrinter.h" +#include "arm_compute/runtime/CL/CLArray.h" +#include "arm_compute/runtime/CL/functions/CLROIPoolingLayer.h" +#include "tests/Globals.h" +#include "tests/Utils.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" +#include "tests/validation_old/ValidationUserConfiguration.h" + +#include <random> +#include <vector> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +CLTensor compute_roi_pooling_layer(const TensorShape &shape, DataType dt, const std::vector<ROI> &rois, ROIPoolingLayerInfo pool_info) +{ + TensorShape shape_dst; + shape_dst.set(0, pool_info.pooled_width()); + shape_dst.set(1, pool_info.pooled_height()); + shape_dst.set(2, shape.z()); + shape_dst.set(3, rois.size()); + + // Create tensors + CLTensor src = create_tensor<CLTensor>(shape, dt); + CLTensor dst = create_tensor<CLTensor>(shape_dst, dt); + + // Create ROI array + CLArray<ROI> rois_array(rois.size()); + fill_array(CLArrayAccessor<ROI>(rois_array), rois); + + // Create and configure function + CLROIPoolingLayer roi_pool; + roi_pool.configure(&src, &rois_array, &dst, pool_info); + + // Allocate tensors + src.allocator()->allocate(); + dst.allocator()->allocate(); + + BOOST_TEST(!src.info()->is_resizable()); + BOOST_TEST(!dst.info()->is_resizable()); + + // Fill tensors + std::uniform_real_distribution<> distribution(-1, 1); + library->fill(CLAccessor(src), distribution, 0); + + // Compute function + roi_pool.run(); + + return dst; +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(CL) +BOOST_AUTO_TEST_SUITE(ROIPoolingLayer) + +BOOST_AUTO_TEST_SUITE(Float) +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, boost::unit_test::data::make({ DataType::F16, DataType::F32 }) * boost::unit_test::data::make({ 10, 20, 40 }) * boost::unit_test::data::make({ 7, 9 }) * + boost::unit_test::data::make({ 1.f / 8.f, 1.f / 16.f }), + dt, num_rois, roi_pool_size, roi_scale) +{ + TensorShape shape(50U, 47U, 2U, 3U); + ROIPoolingLayerInfo pool_info(roi_pool_size, roi_pool_size, roi_scale); + + // Construct ROI vector + std::vector<ROI> rois = generate_random_rois(shape, pool_info, num_rois, user_config.seed); + + // Compute function + CLTensor dst = compute_roi_pooling_layer(shape, dt, rois, pool_info); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_roi_pooling_layer(shape, dt, rois, pool_info); + + // Validate output + validate(CLAccessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/CL/Sobel3x3.cpp b/tests/validation_old/CL/Sobel3x3.cpp new file mode 100644 index 0000000000..a4c779cd5c --- /dev/null +++ b/tests/validation_old/CL/Sobel3x3.cpp @@ -0,0 +1,205 @@ +/* + * 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 "PaddingCalculator.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" +#include "tests/validation_old/ValidationUserConfiguration.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/CL/CLSubTensor.h" +#include "arm_compute/runtime/CL/CLTensor.h" +#include "arm_compute/runtime/CL/CLTensorAllocator.h" +#include "arm_compute/runtime/CL/functions/CLSobel3x3.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +constexpr unsigned int filter_size = 3; /** Size of the kernel/filter in number of elements. */ +constexpr BorderSize border_size(filter_size / 2); /** Border size of the kernel/filter around its central element. */ + +/** Compute CL Sobel 3x3 function. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] border_mode BorderMode used by the input tensor + * @param[in] constant_border_value Constant to use if @p border_mode == CONSTANT + * + * @return Computed output tensor. + */ +std::pair<CLTensor, CLTensor> compute_sobel_3x3(const TensorShape &shape, BorderMode border_mode, uint8_t constant_border_value) +{ + // Create tensors + CLTensor src = create_tensor<CLTensor>(shape, DataType::U8); + CLTensor dst_x = create_tensor<CLTensor>(shape, DataType::S16); + CLTensor dst_y = create_tensor<CLTensor>(shape, DataType::S16); + + src.info()->set_format(Format::U8); + dst_x.info()->set_format(Format::S16); + dst_y.info()->set_format(Format::S16); + + // Create sobel image configure function + CLSobel3x3 sobel_3x3; + sobel_3x3.configure(&src, &dst_x, &dst_y, border_mode, constant_border_value); + + // Allocate tensors + src.allocator()->allocate(); + dst_x.allocator()->allocate(); + dst_y.allocator()->allocate(); + + BOOST_TEST(!src.info()->is_resizable()); + BOOST_TEST(!dst_x.info()->is_resizable()); + BOOST_TEST(!dst_y.info()->is_resizable()); + + // Fill tensors + library->fill_tensor_uniform(CLAccessor(src), 0); + + // Compute function + sobel_3x3.run(); + + return std::make_pair(std::move(dst_x), std::move(dst_y)); +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(CL) +BOOST_AUTO_TEST_SUITE(Sobel3x3) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(Configuration, (SmallShapes() + LargeShapes()) * BorderModes(), shape, border_mode) +{ + // Create tensors + CLTensor src = create_tensor<CLTensor>(shape, DataType::U8); + CLTensor dst_x = create_tensor<CLTensor>(shape, DataType::S16); + CLTensor dst_y = create_tensor<CLTensor>(shape, DataType::S16); + + src.info()->set_format(Format::U8); + dst_x.info()->set_format(Format::S16); + dst_y.info()->set_format(Format::S16); + + BOOST_TEST(src.info()->is_resizable()); + BOOST_TEST(dst_x.info()->is_resizable()); + BOOST_TEST(dst_y.info()->is_resizable()); + + // Create sobel 3x3 configure function + CLSobel3x3 sobel_3x3; + sobel_3x3.configure(&src, &dst_x, &dst_y, border_mode); + + // Validate valid region + const ValidRegion src_valid_region = shape_to_valid_region(shape); + const ValidRegion dst_valid_region = shape_to_valid_region(shape, border_mode == BorderMode::UNDEFINED, border_size); + + validate(src.info()->valid_region(), src_valid_region); + validate(dst_x.info()->valid_region(), dst_valid_region); + validate(dst_y.info()->valid_region(), dst_valid_region); + + // Validate padding + PaddingCalculator calculator(shape.x(), 8); + + calculator.set_border_mode(border_mode); + calculator.set_border_size(1); + + const PaddingSize dst_padding = calculator.required_padding(); + + calculator.set_accessed_elements(16); + calculator.set_access_offset(-1); + + const PaddingSize src_padding = calculator.required_padding(); + + validate(src.info()->padding(), src_padding); + validate(dst_x.info()->padding(), dst_padding); + validate(dst_y.info()->padding(), dst_padding); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * BorderModes(), shape, border_mode) +{ + uint8_t constant_border_value = 0; + + // Generate a random constant value if border_mode is constant + if(border_mode == BorderMode::CONSTANT) + { + std::mt19937 gen(user_config.seed.get()); + std::uniform_int_distribution<uint8_t> distribution(0, 255); + constant_border_value = distribution(gen); + } + + // Compute function + std::pair<CLTensor, CLTensor> dst = compute_sobel_3x3(shape, border_mode, constant_border_value); + + // Compute reference + std::pair<RawTensor, RawTensor> ref_dst = Reference::compute_reference_sobel_3x3(shape, border_mode, constant_border_value); + + // Calculate valid region + const ValidRegion valid_region = shape_to_valid_region(shape, border_mode == BorderMode::UNDEFINED, border_size); + + // Validate output + validate(CLAccessor(dst.first), ref_dst.first, valid_region); + validate(CLAccessor(dst.second), ref_dst.second, valid_region); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * BorderModes(), shape, border_mode) +{ + uint8_t constant_border_value = 0; + + // Generate a random constant value if border_mode is constant + if(border_mode == BorderMode::CONSTANT) + { + std::mt19937 gen(user_config.seed.get()); + std::uniform_int_distribution<uint8_t> distribution(0, 255); + constant_border_value = distribution(gen); + } + + // Compute function + std::pair<CLTensor, CLTensor> dst = compute_sobel_3x3(shape, border_mode, constant_border_value); + + // Compute reference + std::pair<RawTensor, RawTensor> ref_dst = Reference::compute_reference_sobel_3x3(shape, border_mode, constant_border_value); + + // Calculate valid region + const ValidRegion valid_region = shape_to_valid_region(shape, border_mode == BorderMode::UNDEFINED, border_size); + + // Validate output + validate(CLAccessor(dst.first), ref_dst.first, valid_region); + validate(CLAccessor(dst.second), ref_dst.second, valid_region); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/CL/Sobel5x5.cpp b/tests/validation_old/CL/Sobel5x5.cpp new file mode 100644 index 0000000000..7e5dec1209 --- /dev/null +++ b/tests/validation_old/CL/Sobel5x5.cpp @@ -0,0 +1,204 @@ +/* + * 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 "PaddingCalculator.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" +#include "tests/validation_old/ValidationUserConfiguration.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/CL/CLSubTensor.h" +#include "arm_compute/runtime/CL/CLTensor.h" +#include "arm_compute/runtime/CL/CLTensorAllocator.h" +#include "arm_compute/runtime/CL/functions/CLSobel5x5.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +constexpr unsigned int filter_size = 5; /** Size of the kernel/filter in number of elements. */ +constexpr BorderSize border_size(filter_size / 2); /** Border size of the kernel/filter around its central element. */ + +/** Compute CL Sobel 5x5 function. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] border_mode BorderMode used by the input tensor + * @param[in] constant_border_value Constant to use if @p border_mode == CONSTANT + * + * @return Computed output tensor. + */ +std::pair<CLTensor, CLTensor> compute_sobel_5x5(const TensorShape &shape, BorderMode border_mode, uint8_t constant_border_value) +{ + // Create tensors + CLTensor src = create_tensor<CLTensor>(shape, DataType::U8); + CLTensor dst_x = create_tensor<CLTensor>(shape, DataType::S16); + CLTensor dst_y = create_tensor<CLTensor>(shape, DataType::S16); + + src.info()->set_format(Format::U8); + dst_x.info()->set_format(Format::S16); + dst_y.info()->set_format(Format::S16); + + // Create sobel image configure function + CLSobel5x5 sobel_5x5; + sobel_5x5.configure(&src, &dst_x, &dst_y, border_mode, constant_border_value); + + // Allocate tensors + src.allocator()->allocate(); + dst_x.allocator()->allocate(); + dst_y.allocator()->allocate(); + + BOOST_TEST(!src.info()->is_resizable()); + BOOST_TEST(!dst_x.info()->is_resizable()); + BOOST_TEST(!dst_y.info()->is_resizable()); + + // Fill tensors + library->fill_tensor_uniform(CLAccessor(src), 0); + + // Compute function + sobel_5x5.run(); + + return std::make_pair(std::move(dst_x), std::move(dst_y)); +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(CL) +BOOST_AUTO_TEST_SUITE(Sobel5x5) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(Configuration, (SmallShapes() + LargeShapes()) * BorderModes(), shape, border_mode) +{ + // Create tensors + CLTensor src = create_tensor<CLTensor>(shape, DataType::U8); + CLTensor dst_x = create_tensor<CLTensor>(shape, DataType::S16); + CLTensor dst_y = create_tensor<CLTensor>(shape, DataType::S16); + + src.info()->set_format(Format::U8); + dst_x.info()->set_format(Format::S16); + dst_y.info()->set_format(Format::S16); + + BOOST_TEST(src.info()->is_resizable()); + BOOST_TEST(dst_x.info()->is_resizable()); + BOOST_TEST(dst_y.info()->is_resizable()); + + // Create sobel 5x5 configure function + CLSobel5x5 sobel_5x5; + sobel_5x5.configure(&src, &dst_x, &dst_y, border_mode); + + // Validate valid region + const ValidRegion src_valid_region = shape_to_valid_region(shape); + const ValidRegion dst_valid_region = shape_to_valid_region(shape, border_mode == BorderMode::UNDEFINED, border_size); + + validate(src.info()->valid_region(), src_valid_region); + validate(dst_x.info()->valid_region(), dst_valid_region); + validate(dst_y.info()->valid_region(), dst_valid_region); + + // Validate padding + PaddingCalculator calculator(shape.x(), 8); + calculator.set_border_mode(border_mode); + calculator.set_border_size(2); + + const PaddingSize dst_padding = calculator.required_padding(); + + calculator.set_accessed_elements(16); + calculator.set_access_offset(-2); + + const PaddingSize src_padding = calculator.required_padding(); + + validate(src.info()->padding(), src_padding); + validate(dst_x.info()->padding(), dst_padding); + validate(dst_y.info()->padding(), dst_padding); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * BorderModes(), shape, border_mode) +{ + uint8_t constant_border_value = 0; + + // Generate a random constant value if border_mode is constant + if(border_mode == BorderMode::CONSTANT) + { + std::mt19937 gen(user_config.seed.get()); + std::uniform_int_distribution<uint8_t> distribution(0, 255); + constant_border_value = distribution(gen); + } + + // Compute function + std::pair<CLTensor, CLTensor> dst = compute_sobel_5x5(shape, border_mode, constant_border_value); + + // Compute reference + std::pair<RawTensor, RawTensor> ref_dst = Reference::compute_reference_sobel_5x5(shape, border_mode, constant_border_value); + + // Calculate valid region + const ValidRegion valid_region = shape_to_valid_region(shape, border_mode == BorderMode::UNDEFINED, border_size); + + // Validate output + validate(CLAccessor(dst.first), ref_dst.first, valid_region); + validate(CLAccessor(dst.second), ref_dst.second, valid_region); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * BorderModes(), shape, border_mode) +{ + uint8_t constant_border_value = 0; + + // Generate a random constant value if border_mode is constant + if(border_mode == BorderMode::CONSTANT) + { + std::mt19937 gen(user_config.seed.get()); + std::uniform_int_distribution<uint8_t> distribution(0, 255); + constant_border_value = distribution(gen); + } + + // Compute function + std::pair<CLTensor, CLTensor> dst = compute_sobel_5x5(shape, border_mode, constant_border_value); + + // Compute reference + std::pair<RawTensor, RawTensor> ref_dst = Reference::compute_reference_sobel_5x5(shape, border_mode, constant_border_value); + + // Calculate valid region + const ValidRegion valid_region = shape_to_valid_region(shape, border_mode == BorderMode::UNDEFINED, border_size); + + // Validate output + validate(CLAccessor(dst.first), ref_dst.first, valid_region); + validate(CLAccessor(dst.second), ref_dst.second, valid_region); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/CL/TableLookup.cpp b/tests/validation_old/CL/TableLookup.cpp new file mode 100644 index 0000000000..26c38689f0 --- /dev/null +++ b/tests/validation_old/CL/TableLookup.cpp @@ -0,0 +1,229 @@ +/* + * 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 "PaddingCalculator.h" +#include "RawLutAccessor.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Helpers.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/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 "tests/validation_old/boost_wrapper.h" + +#include <map> +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +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_old/CL/Threshold.cpp b/tests/validation_old/CL/Threshold.cpp new file mode 100644 index 0000000000..74ddd6873e --- /dev/null +++ b/tests/validation_old/CL/Threshold.cpp @@ -0,0 +1,153 @@ +/* + * 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 "PaddingCalculator.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" +#include "tests/validation_old/dataset/ThresholdDataset.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/CLThreshold.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +/** Compute Threshold function. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] threshold Threshold. When the threshold type is RANGE, this is used as the lower threshold. + * @param[in] false_value value to set when the condition is not respected. + * @param[in] true_value value to set when the condition is respected. + * @param[in] type Thresholding type. Either RANGE or BINARY. + * @param[in] upper Upper threshold. Only used when the thresholding type is RANGE. + * + * @return Computed output tensor. + */ +CLTensor compute_threshold(const TensorShape &shape, uint8_t threshold, uint8_t false_value, uint8_t true_value, ThresholdType type, uint8_t upper) +{ + // Create tensors + CLTensor src = create_tensor<CLTensor>(shape, DataType::U8); + CLTensor dst = create_tensor<CLTensor>(shape, DataType::U8); + + // Create and configure function + CLThreshold thrsh; + thrsh.configure(&src, &dst, threshold, false_value, true_value, type, upper); + + // 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 + thrsh.run(); + + return dst; +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(CL) +BOOST_AUTO_TEST_SUITE(Threshold) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(Configuration, + (SmallShapes() + LargeShapes()) * ThresholdDataset(), + shape, threshold_conf) +{ + // Create tensors + CLTensor src = create_tensor<CLTensor>(shape, DataType::U8); + CLTensor dst = create_tensor<CLTensor>(shape, DataType::U8); + + BOOST_TEST(src.info()->is_resizable()); + BOOST_TEST(dst.info()->is_resizable()); + + // Create and configure function + CLThreshold cl_threshold; + cl_threshold.configure(&src, &dst, threshold_conf.threshold, threshold_conf.false_value, threshold_conf.true_value, threshold_conf.type, threshold_conf.upper); + + // 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() * ThresholdDataset(), + shape, threshold_conf) +{ + // Compute function + CLTensor dst = compute_threshold(shape, threshold_conf.threshold, threshold_conf.false_value, threshold_conf.true_value, threshold_conf.type, threshold_conf.upper); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_threshold(shape, threshold_conf.threshold, threshold_conf.false_value, threshold_conf.true_value, threshold_conf.type, threshold_conf.upper); + + // Validate output + validate(CLAccessor(dst), ref_dst); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, + LargeShapes() * ThresholdDataset(), + shape, threshold_conf) +{ + // Compute function + CLTensor dst = compute_threshold(shape, threshold_conf.threshold, threshold_conf.false_value, threshold_conf.true_value, threshold_conf.type, threshold_conf.upper); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_threshold(shape, threshold_conf.threshold, threshold_conf.false_value, threshold_conf.true_value, threshold_conf.type, threshold_conf.upper); + + // 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_old/CL/WarpPerspective.cpp b/tests/validation_old/CL/WarpPerspective.cpp new file mode 100644 index 0000000000..6252361003 --- /dev/null +++ b/tests/validation_old/CL/WarpPerspective.cpp @@ -0,0 +1,208 @@ +/* + * 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 "PaddingCalculator.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Helpers.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" +#include "tests/validation_old/ValidationUserConfiguration.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/CL/functions/CLWarpPerspective.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +/** Compute Warp Perspective function. + * + * @param[in] input Shape of the input and output tensors. + * @param[in] matrix The perspective matrix. Must be 3x3 of type float. + * @param[in] policy The interpolation type. + * @param[in] border_mode Strategy to use for borders. + * @param[in] constant_border_value Constant value to use for borders if border_mode is set to CONSTANT. + * + * @return Computed output tensor. + */ +CLTensor compute_warp_perspective(const TensorShape &shape, const float *matrix, InterpolationPolicy policy, + BorderMode border_mode, uint8_t constant_border_value) +{ + // Create tensors + CLTensor src = create_tensor<CLTensor>(shape, DataType::U8); + CLTensor dst = create_tensor<CLTensor>(shape, DataType::U8); + + // Create and configure function + CLWarpPerspective warp_perspective; + warp_perspective.configure(&src, &dst, matrix, policy, border_mode, constant_border_value); + + // 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 + warp_perspective.run(); + + return dst; +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(CL) +BOOST_AUTO_TEST_SUITE(WarpPerspective) + +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({ InterpolationPolicy::BILINEAR, InterpolationPolicy::NEAREST_NEIGHBOR }) * BorderModes(), + shape, policy, border_mode) +{ + uint8_t constant_border_value = 0; + + // Generate a random constant value if border_mode is constant + if(border_mode == BorderMode::CONSTANT) + { + std::mt19937 gen(user_config.seed.get()); + std::uniform_int_distribution<uint8_t> distribution_u8(0, 255); + constant_border_value = distribution_u8(gen); + } + + std::array<float, 9> matrix; + fill_warp_matrix<9>(matrix, 3, 3); + + // Create tensors + CLTensor src = create_tensor<CLTensor>(shape, DataType::U8); + CLTensor dst = create_tensor<CLTensor>(shape, DataType::U8); + + BOOST_TEST(src.info()->is_resizable()); + BOOST_TEST(dst.info()->is_resizable()); + + // Create and configure function + CLWarpPerspective warp_perspective; + warp_perspective.configure(&src, &dst, matrix.data(), policy, border_mode, constant_border_value); + + // 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 + PaddingCalculator calculator(shape.x(), 4); + calculator.set_border_mode(border_mode); + + const PaddingSize read_padding(1); + const PaddingSize write_padding = calculator.required_padding(PaddingCalculator::Option::EXCLUDE_BORDER); + + validate(src.info()->padding(), read_padding); + validate(dst.info()->padding(), write_padding); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() + * boost::unit_test::data::make({ InterpolationPolicy::BILINEAR, InterpolationPolicy::NEAREST_NEIGHBOR }) + * BorderModes(), + shape, policy, border_mode) +{ + uint8_t constant_border_value = 0; + + // Generate a random constant value if border_mode is constant + if(border_mode == BorderMode::CONSTANT) + { + std::mt19937 gen(user_config.seed.get()); + std::uniform_int_distribution<uint8_t> distribution_u8(0, 255); + constant_border_value = distribution_u8(gen); + } + + // Create the valid mask Tensor + RawTensor valid_mask(shape, DataType::U8); + + // Create the matrix + std::array<float, 9> matrix; + fill_warp_matrix<9>(matrix, 3, 3); + + // Compute function + CLTensor dst = compute_warp_perspective(shape, matrix.data(), policy, border_mode, constant_border_value); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_warp_perspective(shape, valid_mask, matrix.data(), policy, border_mode, constant_border_value); + + // Validate output + validate(CLAccessor(dst), ref_dst, valid_mask, 1, 0.2f); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() + * boost::unit_test::data::make({ InterpolationPolicy::NEAREST_NEIGHBOR, InterpolationPolicy::BILINEAR }) * BorderModes(), + shape, policy, border_mode) +{ + uint8_t constant_border_value = 0; + + // Generate a random constant value if border_mode is constant + if(border_mode == BorderMode::CONSTANT) + { + std::mt19937 gen(user_config.seed.get()); + std::uniform_int_distribution<uint8_t> distribution_u8(0, 255); + constant_border_value = distribution_u8(gen); + } + + // Create the valid mask Tensor + RawTensor valid_mask(shape, DataType::U8); + + // Create the matrix + std::array<float, 9> matrix; + fill_warp_matrix<9>(matrix, 3, 3); + + // Compute function + CLTensor dst = compute_warp_perspective(shape, matrix.data(), policy, border_mode, constant_border_value); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_warp_perspective(shape, valid_mask, matrix.data(), policy, border_mode, constant_border_value); + + // Validate output + validate(CLAccessor(dst), ref_dst, valid_mask, 1, 0.2f); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/Datasets.h b/tests/validation_old/Datasets.h new file mode 100644 index 0000000000..464fffd1cf --- /dev/null +++ b/tests/validation_old/Datasets.h @@ -0,0 +1,264 @@ +/* + * 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_VALIDATION_DATASETS_H__ +#define __ARM_COMPUTE_TEST_VALIDATION_DATASETS_H__ + +#include "tests/validation_old/dataset/ActivationFunctionDataset.h" +#include "tests/validation_old/dataset/BatchNormalizationLayerDataset.h" +#include "tests/validation_old/dataset/BorderModeDataset.h" +#include "tests/validation_old/dataset/ConvertPolicyDataset.h" +#include "tests/validation_old/dataset/ConvolutionLayerDataset.h" +#include "tests/validation_old/dataset/DataTypeDatasets.h" +#include "tests/validation_old/dataset/FullyConnectedLayerDataset.h" +#include "tests/validation_old/dataset/GEMMDataset.h" +#include "tests/validation_old/dataset/ImageDatasets.h" +#include "tests/validation_old/dataset/InterpolationPolicyDataset.h" +#include "tests/validation_old/dataset/MatrixPatternDataset.h" +#include "tests/validation_old/dataset/NonLinearFilterFunctionDataset.h" +#include "tests/validation_old/dataset/NormalizationTypeDataset.h" +#include "tests/validation_old/dataset/PoolingTypesDataset.h" +#include "tests/validation_old/dataset/RoundingPolicyDataset.h" +#include "tests/validation_old/dataset/ShapeDatasets.h" +#include "tests/validation_old/dataset/ThresholdDataset.h" + +#include "tests/validation_old/boost_wrapper.h" + +using namespace boost::unit_test::data::monomorphic; + +namespace boost +{ +namespace unit_test +{ +namespace data +{ +namespace monomorphic +{ +/// Register the data set with Boost +template <> +struct is_dataset<arm_compute::test::SmallImages> : boost::mpl::true_ +{ +}; + +/// Register the data set with Boost +template <> +struct is_dataset<arm_compute::test::LargeImages> : boost::mpl::true_ +{ +}; + +/// Register the data set with Boost +template <> +struct is_dataset<arm_compute::test::SmallShapes> : boost::mpl::true_ +{ +}; + +/// Register the data set with Boost +template <> +struct is_dataset<arm_compute::test::Small1DShape> : boost::mpl::true_ +{ +}; + +/// Register the data set with Boost +template <> +struct is_dataset<arm_compute::test::Small2DShapes> : boost::mpl::true_ +{ +}; + +/// Register the data set with Boost +template <> +struct is_dataset<arm_compute::test::LargeShapes> : boost::mpl::true_ +{ +}; + +/// Register the data set with Boost +template <> +struct is_dataset<arm_compute::test::Large2DShapes> : boost::mpl::true_ +{ +}; + +/// Register the data set with Boost +template <> +struct is_dataset<arm_compute::test::AllDataTypes> : boost::mpl::true_ +{ +}; + +/// Register the data set with Boost +template <> +struct is_dataset<arm_compute::test::UnsignedDataTypes> : boost::mpl::true_ +{ +}; + +// Register the data set with Boost +template <> +struct is_dataset<arm_compute::test::SignedDataTypes> : boost::mpl::true_ +{ +}; + +/// Register the data set with Boost +template <> +struct is_dataset<arm_compute::test::FloatDataTypes> : boost::mpl::true_ +{ +}; + +/// Register the data set with Boost +template <> +struct is_dataset<arm_compute::test::FixedPointDataTypes> : boost::mpl::true_ +{ +}; + +/// Register the data set with Boost +template <> +struct is_dataset<arm_compute::test::CNNFloatDataTypes> : boost::mpl::true_ +{ +}; + +/// Register the data set with Boost +template <> +struct is_dataset<arm_compute::test::CNNFixedPointDataTypes> : boost::mpl::true_ +{ +}; + +/// Register the data set with Boost +template <> +struct is_dataset<arm_compute::test::CNNDataTypes> : boost::mpl::true_ +{ +}; + +/// Register the data set with Boost +template <> +struct is_dataset<arm_compute::test::ActivationFunctions> : boost::mpl::true_ +{ +}; + +/// Register the data set with Boost +template <> +struct is_dataset<arm_compute::test::BorderModes> : boost::mpl::true_ +{ +}; + +/// Register the data set with Boost +template <> +struct is_dataset<arm_compute::test::ConvertPolicies> : boost::mpl::true_ +{ +}; + +/// Register the data set with Boost +template <> +struct is_dataset<arm_compute::test::InterpolationPolicies> : boost::mpl::true_ +{ +}; + +/// Register the data set with Boost +template <> +struct is_dataset<arm_compute::test::NormalizationTypes> : boost::mpl::true_ +{ +}; + +/// Register the data set with Boost +template <> +struct is_dataset<arm_compute::test::RoundingPolicies> : boost::mpl::true_ +{ +}; + +/// Register the data set with Boost +template <> +struct is_dataset<arm_compute::test::PoolingTypes> : boost::mpl::true_ +{ +}; + +/// Register the data set with Boost +template <> +struct is_dataset<arm_compute::test::AlexNetConvolutionLayerDataset> : boost::mpl::true_ +{ +}; + +/// Register the data set with Boost +template <> +struct is_dataset<arm_compute::test::AlexNetFullyConnectedLayerDataset> : boost::mpl::true_ +{ +}; + +/// Register the data set with Boost +template <> +struct is_dataset<arm_compute::test::DirectConvolutionShapes> : boost::mpl::true_ +{ +}; + +/// Register the data set with Boost +template <> +struct is_dataset<arm_compute::test::SmallFullyConnectedLayerDataset> : boost::mpl::true_ +{ +}; + +/// Register the data set with Boost +template <> +struct is_dataset<arm_compute::test::LargeFullyConnectedLayerDataset> : boost::mpl::true_ +{ +}; + +/// Register the data set with Boost +template <> +struct is_dataset<arm_compute::test::SmallConvolutionLayerDataset> : boost::mpl::true_ +{ +}; + +/// Register the data set with Boost +template <> +struct is_dataset<arm_compute::test::SmallGEMMDataset> : boost::mpl::true_ +{ +}; + +/// Register the data set with Boost +template <> +struct is_dataset<arm_compute::test::LargeGEMMDataset> : boost::mpl::true_ +{ +}; + +/// Register the data set with Boost +template <> +struct is_dataset<arm_compute::test::RandomBatchNormalizationLayerDataset> : boost::mpl::true_ +{ +}; + +/// Register the data set with Boost +template <> +struct is_dataset<arm_compute::test::ThresholdDataset> : boost::mpl::true_ +{ +}; + +/// Register the data set with Boost +template <> +struct is_dataset<arm_compute::test::NonLinearFilterFunctions> : boost::mpl::true_ +{ +}; + +/// Register the data set with Boost +template <> +struct is_dataset<arm_compute::test::MatrixPatterns> : boost::mpl::true_ +{ +}; +} +} +} +} +#endif /* __ARM_COMPUTE_TEST_VALIDATION_DATASETS_H__ */ diff --git a/tests/validation_old/FixedPoint.h b/tests/validation_old/FixedPoint.h new file mode 100644 index 0000000000..12ffcdfc3d --- /dev/null +++ b/tests/validation_old/FixedPoint.h @@ -0,0 +1,986 @@ +/* + * 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_VALIDATION_FIXEDPOINT_H__ +#define __ARM_COMPUTE_TEST_VALIDATION_FIXEDPOINT_H__ + +#include "Utils.h" +#include "support/ToolchainSupport.h" + +#include <cassert> +#include <cstdint> +#include <cstdlib> +#include <limits> +#include <string> +#include <type_traits> + +namespace arm_compute +{ +namespace test +{ +namespace fixed_point_arithmetic +{ +namespace detail +{ +// Forward declare structs +struct functions; +template <typename T> +struct constant_expr; +} + +/** Fixed point traits */ +namespace traits +{ +// Promote types +// *INDENT-OFF* +// clang-format off +template <typename T> struct promote { }; +template <> struct promote<uint8_t> { using type = uint16_t; }; +template <> struct promote<int8_t> { using type = int16_t; }; +template <> struct promote<uint16_t> { using type = uint32_t; }; +template <> struct promote<int16_t> { using type = int32_t; }; +template <> struct promote<uint32_t> { using type = uint64_t; }; +template <> struct promote<int32_t> { using type = int64_t; }; +template <> struct promote<uint64_t> { using type = uint64_t; }; +template <> struct promote<int64_t> { using type = int64_t; }; +// clang-format on +// *INDENT-ON* +} + +/** Strongly typed enum class representing the overflow policy */ +enum class OverflowPolicy +{ + WRAP, /**< Wrap policy */ + SATURATE /**< Saturate policy */ +}; +/** Strongly typed enum class representing the rounding policy */ +enum class RoundingPolicy +{ + TO_ZERO, /**< Round to zero policy */ + TO_NEAREST_EVEN /**< Round to nearest even policy */ +}; + +/** Arbitrary fixed-point arithmetic class */ +template <typename T> +class fixed_point +{ +public: + // Static Checks + static_assert(std::is_integral<T>::value, "Type is not an integer"); + + // Friends + friend struct detail::functions; + friend struct detail::constant_expr<T>; + + /** Constructor (from different fixed point type) + * + * @param[in] val Fixed point + * @param[in] p Fixed point precision + */ + template <typename U> + fixed_point(fixed_point<U> val, uint8_t p) + : _value(0), _fixed_point_position(p) + { + assert(p > 0 && p < std::numeric_limits<T>::digits); + T v = 0; + + if(std::numeric_limits<T>::digits < std::numeric_limits<U>::digits) + { + val.rescale(p); + v = detail::constant_expr<T>::saturate_cast(val.raw()); + } + else + { + auto v_cast = static_cast<fixed_point<T>>(val); + v_cast.rescale(p); + v = v_cast.raw(); + } + _value = static_cast<T>(v); + } + /** Constructor (from integer) + * + * @param[in] val Integer value to be represented as fixed point + * @param[in] p Fixed point precision + * @param[in] is_raw If true val is a raw fixed point value else an integer + */ + template <typename U, typename = typename std::enable_if<std::is_integral<U>::value>::type> + fixed_point(U val, uint8_t p, bool is_raw = false) + : _value(val << p), _fixed_point_position(p) + { + if(is_raw) + { + _value = val; + } + } + /** Constructor (from float) + * + * @param[in] val Float value to be represented as fixed point + * @param[in] p Fixed point precision + */ + fixed_point(float val, uint8_t p) + : _value(detail::constant_expr<T>::to_fixed(val, p)), _fixed_point_position(p) + { + assert(p > 0 && p < std::numeric_limits<T>::digits); + } + /** Constructor (from float string) + * + * @param[in] str Float string to be represented as fixed point + * @param[in] p Fixed point precision + */ + fixed_point(std::string str, uint8_t p) + : _value(detail::constant_expr<T>::to_fixed(support::cpp11::stof(str), p)), _fixed_point_position(p) + { + assert(p > 0 && p < std::numeric_limits<T>::digits); + } + /** Default copy constructor */ + fixed_point &operator=(const fixed_point &) = default; + /** Default move constructor */ + fixed_point &operator=(fixed_point &&) = default; + /** Default copy assignment operator */ + fixed_point(const fixed_point &) = default; + /** Default move assignment operator */ + fixed_point(fixed_point &&) = default; + + /** Float conversion operator + * + * @return Float representation of fixed point + */ + operator float() const + { + return detail::constant_expr<T>::to_float(_value, _fixed_point_position); + } + /** Integer conversion operator + * + * @return Integer representation of fixed point + */ + template <typename U, typename = typename std::enable_if<std::is_integral<T>::value>::type> + operator U() const + { + return detail::constant_expr<T>::to_int(_value, _fixed_point_position); + } + /** Convert to different fixed point of different type but same precision + * + * @note Down-conversion might fail. + */ + template <typename U> + operator fixed_point<U>() + { + U val = static_cast<U>(_value); + if(std::numeric_limits<U>::digits < std::numeric_limits<T>::digits) + { + val = detail::constant_expr<U>::saturate_cast(_value); + } + return fixed_point<U>(val, _fixed_point_position, true); + } + + /** Arithmetic += assignment operator + * + * @param[in] rhs Fixed point operand + * + * @return Reference to this fixed point + */ + template <typename U> + fixed_point<T> &operator+=(const fixed_point<U> &rhs) + { + fixed_point<T> val(rhs, _fixed_point_position); + _value += val.raw(); + return *this; + } + /** Arithmetic -= assignment operator + * + * @param[in] rhs Fixed point operand + * + * @return Reference to this fixed point + */ + template <typename U> + fixed_point<T> &operator-=(const fixed_point<U> &rhs) + { + fixed_point<T> val(rhs, _fixed_point_position); + _value -= val.raw(); + return *this; + } + + /** Raw value accessor + * + * @return Raw fixed point value + */ + T raw() const + { + return _value; + } + /** Precision accessor + * + * @return Precision of fixed point + */ + uint8_t precision() const + { + return _fixed_point_position; + } + /** Rescale a fixed point to a new precision + * + * @param[in] p New fixed point precision + */ + void rescale(uint8_t p) + { + assert(p > 0 && p < std::numeric_limits<T>::digits); + + using promoted_T = typename traits::promote<T>::type; + promoted_T val = _value; + if(p > _fixed_point_position) + { + val <<= (p - _fixed_point_position); + } + else if(p < _fixed_point_position) + { + uint8_t pbar = _fixed_point_position - p; + val += (pbar != 0) ? (1 << (pbar - 1)) : 0; + val >>= pbar; + } + + _value = detail::constant_expr<T>::saturate_cast(val); + _fixed_point_position = p; + } + +private: + T _value; /**< Fixed point raw value */ + uint8_t _fixed_point_position; /**< Fixed point precision */ +}; + +namespace detail +{ +/** Count the number of leading zero bits in the given value. + * + * @param[in] value Input value. + * + * @return Number of leading zero bits. + */ +template <typename T> +constexpr int clz(T value) +{ + using unsigned_T = typename std::make_unsigned<T>::type; + // __builtin_clz is available for int. Need to correct reported number to + // match the original type. + return __builtin_clz(value) - (32 - std::numeric_limits<unsigned_T>::digits); +} + +template <typename T> +struct constant_expr +{ + /** Calculate representation of 1 in fixed point given a fixed point precision + * + * @param[in] p Fixed point precision + * + * @return Representation of value 1 in fixed point. + */ + static constexpr T fixed_one(uint8_t p) + { + return (1 << p); + } + /** Calculate fixed point precision step given a fixed point precision + * + * @param[in] p Fixed point precision + * + * @return Fixed point precision step + */ + static constexpr float fixed_step(uint8_t p) + { + return (1.0f / static_cast<float>(1 << p)); + } + + /** Convert a fixed point value to float given its precision. + * + * @param[in] val Fixed point value + * @param[in] p Fixed point precision + * + * @return Float representation of the fixed point number + */ + static constexpr float to_float(T val, uint8_t p) + { + return static_cast<float>(val * fixed_step(p)); + } + /** Convert a fixed point value to integer given its precision. + * + * @param[in] val Fixed point value + * @param[in] p Fixed point precision + * + * @return Integer of the fixed point number + */ + static constexpr T to_int(T val, uint8_t p) + { + return val >> p; + } + /** Convert a single precision floating point value to a fixed point representation given its precision. + * + * @param[in] val Floating point value + * @param[in] p Fixed point precision + * + * @return The raw fixed point representation + */ + static constexpr T to_fixed(float val, uint8_t p) + { + return static_cast<T>(saturate_cast<float>(val * fixed_one(p) + ((val >= 0) ? 0.5 : -0.5))); + } + /** Clamp value between two ranges + * + * @param[in] val Value to clamp + * @param[in] min Minimum value to clamp to + * @param[in] max Maximum value to clamp to + * + * @return clamped value + */ + static constexpr T clamp(T val, T min, T max) + { + return std::min(std::max(val, min), max); + } + /** Saturate given number + * + * @param[in] val Value to saturate + * + * @return Saturated value + */ + template <typename U> + static constexpr T saturate_cast(U val) + { + return static_cast<T>(std::min<U>(std::max<U>(val, static_cast<U>(std::numeric_limits<T>::min())), static_cast<U>(std::numeric_limits<T>::max()))); + } +}; +struct functions +{ + /** Output stream operator + * + * @param[in] s Output stream + * @param[in] x Fixed point value + * + * @return Reference output to updated stream + */ + template <typename T, typename U, typename traits> + static std::basic_ostream<T, traits> &write(std::basic_ostream<T, traits> &s, fixed_point<U> &x) + { + return s << static_cast<float>(x); + } + /** Signbit of a fixed point number. + * + * @param[in] x Fixed point number + * + * @return True if negative else false. + */ + template <typename T> + static bool signbit(fixed_point<T> x) + { + return ((x._value >> std::numeric_limits<T>::digits) != 0); + } + /** Checks if two fixed point numbers are equal + * + * @param[in] x First fixed point operand + * @param[in] y Second fixed point operand + * + * @return True if fixed points are equal else false + */ + template <typename T> + static bool isequal(fixed_point<T> x, fixed_point<T> y) + { + uint8_t p = std::min(x._fixed_point_position, y._fixed_point_position); + x.rescale(p); + y.rescale(p); + return (x._value == y._value); + } + /** Checks if two fixed point number are not equal + * + * @param[in] x First fixed point operand + * @param[in] y Second fixed point operand + * + * @return True if fixed points are not equal else false + */ + template <typename T> + static bool isnotequal(fixed_point<T> x, fixed_point<T> y) + { + return !isequal(x, y); + } + /** Checks if one fixed point is greater than the other + * + * @param[in] x First fixed point operand + * @param[in] y Second fixed point operand + * + * @return True if fixed point is greater than other + */ + template <typename T> + static bool isgreater(fixed_point<T> x, fixed_point<T> y) + { + uint8_t p = std::min(x._fixed_point_position, y._fixed_point_position); + x.rescale(p); + y.rescale(p); + return (x._value > y._value); + } + /** Checks if one fixed point is greater or equal than the other + * + * @param[in] x First fixed point operand + * @param[in] y Second fixed point operand + * + * @return True if fixed point is greater or equal than other + */ + template <typename T> + static bool isgreaterequal(fixed_point<T> x, fixed_point<T> y) + { + uint8_t p = std::min(x._fixed_point_position, y._fixed_point_position); + x.rescale(p); + y.rescale(p); + return (x._value >= y._value); + } + /** Checks if one fixed point is less than the other + * + * @param[in] x First fixed point operand + * @param[in] y Second fixed point operand + * + * @return True if fixed point is less than other + */ + template <typename T> + static bool isless(fixed_point<T> x, fixed_point<T> y) + { + uint8_t p = std::min(x._fixed_point_position, y._fixed_point_position); + x.rescale(p); + y.rescale(p); + return (x._value < y._value); + } + /** Checks if one fixed point is less or equal than the other + * + * @param[in] x First fixed point operand + * @param[in] y Second fixed point operand + * + * @return True if fixed point is less or equal than other + */ + template <typename T> + static bool islessequal(fixed_point<T> x, fixed_point<T> y) + { + uint8_t p = std::min(x._fixed_point_position, y._fixed_point_position); + x.rescale(p); + y.rescale(p); + return (x._value <= y._value); + } + /** Checks if one fixed point is less or greater than the other + * + * @param[in] x First fixed point operand + * @param[in] y Second fixed point operand + * + * @return True if fixed point is less or greater than other + */ + template <typename T> + static bool islessgreater(fixed_point<T> x, fixed_point<T> y) + { + return isnotequal(x, y); + } + /** Clamp fixed point to specific range. + * + * @param[in] x Fixed point operand + * @param[in] min Minimum value to clamp to + * @param[in] max Maximum value to clamp to + * + * @return Clamped result + */ + template <typename T> + static fixed_point<T> clamp(fixed_point<T> x, T min, T max) + { + return fixed_point<T>(constant_expr<T>::clamp(x._value, min, max), x._fixed_point_position, true); + } + /** Negate number + * + * @param[in] x Fixed point operand + * + * @return Negated fixed point result + */ + template <OverflowPolicy OP = OverflowPolicy::SATURATE, typename T> + static fixed_point<T> negate(fixed_point<T> x) + { + using promoted_T = typename traits::promote<T>::type; + promoted_T val = -x._value; + if(OP == OverflowPolicy::SATURATE) + { + val = constant_expr<T>::saturate_cast(val); + } + return fixed_point<T>(static_cast<T>(val), x._fixed_point_position, true); + } + /** Perform addition among two fixed point numbers + * + * @param[in] x First fixed point operand + * @param[in] y Second fixed point operand + * + * @return Result fixed point with precision equal to minimum precision of both operands + */ + template <OverflowPolicy OP = OverflowPolicy::SATURATE, typename T> + static fixed_point<T> add(fixed_point<T> x, fixed_point<T> y) + { + uint8_t p = std::min(x._fixed_point_position, y._fixed_point_position); + x.rescale(p); + y.rescale(p); + if(OP == OverflowPolicy::SATURATE) + { + using type = typename traits::promote<T>::type; + type val = static_cast<type>(x._value) + static_cast<type>(y._value); + val = constant_expr<T>::saturate_cast(val); + return fixed_point<T>(static_cast<T>(val), p, true); + } + else + { + return fixed_point<T>(x._value + y._value, p, true); + } + } + /** Perform subtraction among two fixed point numbers + * + * @param[in] x First fixed point operand + * @param[in] y Second fixed point operand + * + * @return Result fixed point with precision equal to minimum precision of both operands + */ + template <OverflowPolicy OP = OverflowPolicy::SATURATE, typename T> + static fixed_point<T> sub(fixed_point<T> x, fixed_point<T> y) + { + uint8_t p = std::min(x._fixed_point_position, y._fixed_point_position); + x.rescale(p); + y.rescale(p); + if(OP == OverflowPolicy::SATURATE) + { + using type = typename traits::promote<T>::type; + type val = static_cast<type>(x._value) - static_cast<type>(y._value); + val = constant_expr<T>::saturate_cast(val); + return fixed_point<T>(static_cast<T>(val), p, true); + } + else + { + return fixed_point<T>(x._value - y._value, p, true); + } + } + /** Perform multiplication among two fixed point numbers + * + * @param[in] x First fixed point operand + * @param[in] y Second fixed point operand + * + * @return Result fixed point with precision equal to minimum precision of both operands + */ + template <OverflowPolicy OP = OverflowPolicy::SATURATE, typename T> + static fixed_point<T> mul(fixed_point<T> x, fixed_point<T> y) + { + using promoted_T = typename traits::promote<T>::type; + uint8_t p_min = std::min(x._fixed_point_position, y._fixed_point_position); + uint8_t p_max = std::max(x._fixed_point_position, y._fixed_point_position); + promoted_T round_factor = (1 << (p_max - 1)); + promoted_T val = ((static_cast<promoted_T>(x._value) * static_cast<promoted_T>(y._value)) + round_factor) >> p_max; + if(OP == OverflowPolicy::SATURATE) + { + val = constant_expr<T>::saturate_cast(val); + } + return fixed_point<T>(static_cast<T>(val), p_min, true); + } + /** Perform division among two fixed point numbers + * + * @param[in] x First fixed point operand + * @param[in] y Second fixed point operand + * + * @return Result fixed point with precision equal to minimum precision of both operands + */ + template <OverflowPolicy OP = OverflowPolicy::SATURATE, typename T> + static fixed_point<T> div(fixed_point<T> x, fixed_point<T> y) + { + using promoted_T = typename traits::promote<T>::type; + uint8_t p = std::min(x._fixed_point_position, y._fixed_point_position); + promoted_T denom = static_cast<promoted_T>(y._value); + if(denom != 0) + { + promoted_T val = (static_cast<promoted_T>(x._value) << std::max(x._fixed_point_position, y._fixed_point_position)) / denom; + if(OP == OverflowPolicy::SATURATE) + { + val = constant_expr<T>::saturate_cast(val); + } + return fixed_point<T>(static_cast<T>(val), p, true); + } + else + { + T val = (x._value < 0) ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max(); + return fixed_point<T>(val, p, true); + } + } + /** Shift left + * + * @param[in] x Fixed point operand + * @param[in] shift Shift value + * + * @return Shifted value + */ + template <OverflowPolicy OP = OverflowPolicy::SATURATE, typename T> + static fixed_point<T> shift_left(fixed_point<T> x, size_t shift) + { + using promoted_T = typename traits::promote<T>::type; + promoted_T val = static_cast<promoted_T>(x._value) << shift; + if(OP == OverflowPolicy::SATURATE) + { + val = constant_expr<T>::saturate_cast(val); + } + return fixed_point<T>(static_cast<T>(val), x._fixed_point_position, true); + } + /** Shift right + * + * @param[in] x Fixed point operand + * @param[in] shift Shift value + * + * @return Shifted value + */ + template <typename T> + static fixed_point<T> shift_right(fixed_point<T> x, size_t shift) + { + return fixed_point<T>(x._value >> shift, x._fixed_point_position, true); + } + /** Calculate absolute value + * + * @param[in] x Fixed point operand + * + * @return Absolute value of operand + */ + template <typename T> + static fixed_point<T> abs(fixed_point<T> x) + { + using promoted_T = typename traits::promote<T>::type; + T val = (x._value < 0) ? constant_expr<T>::saturate_cast(-static_cast<promoted_T>(x._value)) : x._value; + return fixed_point<T>(val, x._fixed_point_position, true); + } + /** Calculate the logarithm of a fixed point number + * + * @param[in] x Fixed point operand + * + * @return Logarithm value of operand + */ + template <typename T> + static fixed_point<T> log(fixed_point<T> x) + { + uint8_t p = x._fixed_point_position; + auto const_one = fixed_point<T>(static_cast<T>(1), p); + + // Logarithm of 1 is zero and logarithm of negative values is not defined in R, so return 0. + // Also, log(x) == -log(1/x) for 0 < x < 1. + if(isequal(x, const_one) || islessequal(x, fixed_point<T>(static_cast<T>(0), p))) + { + return fixed_point<T>(static_cast<T>(0), p, true); + } + else if(isless(x, const_one)) + { + return mul(log(div(const_one, x)), fixed_point<T>(-1, p)); + } + + // Remove even powers of 2 + T shift_val = 31 - __builtin_clz(x._value >> p); + x = shift_right(x, shift_val); + x = sub(x, const_one); + + // Constants + auto ln2 = fixed_point<T>(0.6931471, p); + auto A = fixed_point<T>(1.4384189, p); + auto B = fixed_point<T>(-0.67719, p); + auto C = fixed_point<T>(0.3218538, p); + auto D = fixed_point<T>(-0.0832229, p); + + // Polynomial expansion + auto sum = add(mul(x, D), C); + sum = add(mul(x, sum), B); + sum = add(mul(x, sum), A); + sum = mul(x, sum); + + return mul(add(sum, fixed_point<T>(static_cast<T>(shift_val), p)), ln2); + } + /** Calculate the exponential of a fixed point number. + * + * exp(x) = exp(floor(x)) * exp(x - floor(x)) + * = pow(2, floor(x) / ln(2)) * exp(x - floor(x)) + * = exp(x - floor(x)) << (floor(x) / ln(2)) + * + * @param[in] x Fixed point operand + * + * @return Exponential value of operand + */ + template <typename T> + static fixed_point<T> exp(fixed_point<T> x) + { + uint8_t p = x._fixed_point_position; + // Constants + auto const_one = fixed_point<T>(1, p); + auto ln2 = fixed_point<T>(0.6931471, p); + auto inv_ln2 = fixed_point<T>(1.442695, p); + auto A = fixed_point<T>(0.9978546, p); + auto B = fixed_point<T>(0.4994721, p); + auto C = fixed_point<T>(0.1763723, p); + auto D = fixed_point<T>(0.0435108, p); + + T scaled_int_part = detail::constant_expr<T>::to_int(mul(x, inv_ln2)._value, p); + + // Polynomial expansion + auto frac_part = sub(x, mul(ln2, fixed_point<T>(scaled_int_part, p))); + auto taylor = add(mul(frac_part, D), C); + taylor = add(mul(frac_part, taylor), B); + taylor = add(mul(frac_part, taylor), A); + taylor = mul(frac_part, taylor); + taylor = add(taylor, const_one); + + // Saturate value + if(static_cast<T>(clz(taylor.raw())) <= scaled_int_part) + { + return fixed_point<T>(std::numeric_limits<T>::max(), p, true); + } + + return (scaled_int_part < 0) ? shift_right(taylor, -scaled_int_part) : shift_left(taylor, scaled_int_part); + } + /** Calculate the inverse square root of a fixed point number + * + * @param[in] x Fixed point operand + * + * @return Inverse square root value of operand + */ + template <typename T> + static fixed_point<T> inv_sqrt(fixed_point<T> x) + { + const uint8_t p = x._fixed_point_position; + int8_t shift = std::numeric_limits<T>::digits - (p + detail::clz(x._value)); + + shift += std::numeric_limits<T>::is_signed ? 1 : 0; + + // Use volatile to restrict compiler optimizations on shift as compiler reports maybe-uninitialized error on Android + volatile int8_t *shift_ptr = &shift; + + auto const_three = fixed_point<T>(3, p); + auto a = (*shift_ptr < 0) ? shift_left(x, -(shift)) : shift_right(x, shift); + fixed_point<T> x2 = a; + + // We need three iterations to find the result for QS8 and five for QS16 + constexpr int num_iterations = std::is_same<T, int8_t>::value ? 3 : 5; + for(int i = 0; i < num_iterations; ++i) + { + fixed_point<T> three_minus_dx = sub(const_three, mul(a, mul(x2, x2))); + x2 = shift_right(mul(x2, three_minus_dx), 1); + } + + return (shift < 0) ? shift_left(x2, (-shift) >> 1) : shift_right(x2, shift >> 1); + } + /** Calculate the hyperbolic tangent of a fixed point number + * + * @param[in] x Fixed point operand + * + * @return Hyperbolic tangent of the operand + */ + template <typename T> + static fixed_point<T> tanh(fixed_point<T> x) + { + uint8_t p = x._fixed_point_position; + // Constants + auto const_one = fixed_point<T>(1, p); + auto const_two = fixed_point<T>(2, p); + + auto exp2x = exp(const_two * x); + auto num = exp2x - const_one; + auto den = exp2x + const_one; + auto tanh = num / den; + + return tanh; + } + /** Calculate the a-th power of a fixed point number. + * + * The power is computed as x^a = e^(log(x) * a) + * + * @param[in] x Fixed point operand + * @param[in] a Fixed point exponent + * + * @return a-th power of the operand + */ + template <typename T> + static fixed_point<T> pow(fixed_point<T> x, fixed_point<T> a) + { + return exp(log(x) * a); + } +}; + +template <typename T> +bool operator==(const fixed_point<T> &lhs, const fixed_point<T> &rhs) +{ + return functions::isequal(lhs, rhs); +} +template <typename T> +bool operator!=(const fixed_point<T> &lhs, const fixed_point<T> &rhs) +{ + return !operator==(lhs, rhs); +} +template <typename T> +bool operator<(const fixed_point<T> &lhs, const fixed_point<T> &rhs) +{ + return functions::isless(lhs, rhs); +} +template <typename T> +bool operator>(const fixed_point<T> &lhs, const fixed_point<T> &rhs) +{ + return operator<(rhs, lhs); +} +template <typename T> +bool operator<=(const fixed_point<T> &lhs, const fixed_point<T> &rhs) +{ + return !operator>(lhs, rhs); +} +template <typename T> +bool operator>=(const fixed_point<T> &lhs, const fixed_point<T> &rhs) +{ + return !operator<(lhs, rhs); +} +template <typename T> +fixed_point<T> operator+(const fixed_point<T> &lhs, const fixed_point<T> &rhs) +{ + return functions::add(lhs, rhs); +} +template <typename T> +fixed_point<T> operator-(const fixed_point<T> &lhs, const fixed_point<T> &rhs) +{ + return functions::sub(lhs, rhs); +} +template <typename T> +fixed_point<T> operator-(const fixed_point<T> &rhs) +{ + return functions::negate(rhs); +} +template <typename T> +fixed_point<T> operator*(fixed_point<T> x, fixed_point<T> y) +{ + return functions::mul(x, y); +} +template <typename T> +fixed_point<T> operator/(fixed_point<T> x, fixed_point<T> y) +{ + return functions::div(x, y); +} +template <typename T> +fixed_point<T> operator>>(fixed_point<T> x, size_t shift) +{ + return functions::shift_right(x, shift); +} +template <typename T> +fixed_point<T> operator<<(fixed_point<T> x, size_t shift) +{ + return functions::shift_left(x, shift); +} +template <typename T, typename U, typename traits> +std::basic_ostream<T, traits> &operator<<(std::basic_ostream<T, traits> &s, fixed_point<U> x) +{ + return functions::write(s, x); +} +template <typename T> +inline fixed_point<T> min(fixed_point<T> x, fixed_point<T> y) +{ + return x > y ? y : x; +} +template <typename T> +inline fixed_point<T> max(fixed_point<T> x, fixed_point<T> y) +{ + return x > y ? x : y; +} +template <OverflowPolicy OP = OverflowPolicy::SATURATE, typename T> +inline fixed_point<T> add(fixed_point<T> x, fixed_point<T> y) +{ + return functions::add<OP>(x, y); +} +template <OverflowPolicy OP = OverflowPolicy::SATURATE, typename T> +inline fixed_point<T> sub(fixed_point<T> x, fixed_point<T> y) +{ + return functions::sub<OP>(x, y); +} +template <OverflowPolicy OP = OverflowPolicy::SATURATE, typename T> +inline fixed_point<T> mul(fixed_point<T> x, fixed_point<T> y) +{ + return functions::mul<OP>(x, y); +} +template <typename T> +inline fixed_point<T> div(fixed_point<T> x, fixed_point<T> y) +{ + return functions::div(x, y); +} +template <typename T> +inline fixed_point<T> abs(fixed_point<T> x) +{ + return functions::abs(x); +} +template <typename T> +inline fixed_point<T> clamp(fixed_point<T> x, T min, T max) +{ + return functions::clamp(x, min, max); +} +template <typename T> +inline fixed_point<T> exp(fixed_point<T> x) +{ + return functions::exp(x); +} +template <typename T> +inline fixed_point<T> log(fixed_point<T> x) +{ + return functions::log(x); +} +template <typename T> +inline fixed_point<T> inv_sqrt(fixed_point<T> x) +{ + return functions::inv_sqrt(x); +} +template <typename T> +inline fixed_point<T> tanh(fixed_point<T> x) +{ + return functions::tanh(x); +} +template <typename T> +inline fixed_point<T> pow(fixed_point<T> x, fixed_point<T> a) +{ + return functions::pow(x, a); +} +} // namespace detail + +// Expose operators +using detail::operator==; +using detail::operator!=; +using detail::operator<; +using detail::operator>; +using detail::operator<=; +using detail::operator>=; +using detail::operator+; +using detail::operator-; +using detail::operator*; +using detail::operator/; +using detail::operator>>; +using detail::operator<<; + +// Expose additional functions +using detail::min; +using detail::max; +using detail::add; +using detail::sub; +using detail::mul; +using detail::div; +using detail::abs; +using detail::clamp; +using detail::exp; +using detail::log; +using detail::inv_sqrt; +using detail::tanh; +using detail::pow; +// TODO: floor +// TODO: ceil +// TODO: sqrt +} // namespace fixed_point_arithmetic +} // namespace test +} // namespace arm_compute +#endif /*__ARM_COMPUTE_TEST_VALIDATION_FIXEDPOINT_H__ */ diff --git a/tests/validation_old/Helpers.h b/tests/validation_old/Helpers.h new file mode 100644 index 0000000000..e109edee2a --- /dev/null +++ b/tests/validation_old/Helpers.h @@ -0,0 +1,273 @@ +/* + * 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_VALIDATION_HELPERS_H__ +#define __ARM_COMPUTE_TEST_VALIDATION_HELPERS_H__ + +#include "arm_compute/core/Types.h" +#include "tests/Globals.h" +#include "tests/ILutAccessor.h" +#include "tests/Types.h" +#include "tests/validation_old/ValidationUserConfiguration.h" +#include "tests/validation_old/half.h" + +#include <array> +#include <cstring> +#include <random> +#include <type_traits> +#include <utility> +#include <vector> + +namespace arm_compute +{ +namespace test +{ +namespace validation +{ +/** Helper function to fill one or more tensors with the uniform distribution with int values. + * + * @param[in] dist Distribution to be used to get the values for the tensor. + * @param[in] seeds List of seeds to be used to fill each tensor. + * @param[in,out] tensor Tensor to be initialized with the values of the distribution. + * @param[in,out] other_tensors (Optional) One or more tensors to be filled. + * + */ +template <typename D, typename T, typename... Ts> +void fill_tensors(D &&dist, std::initializer_list<int> seeds, T &&tensor, Ts &&... other_tensors) +{ + const std::array < T, 1 + sizeof...(Ts) > tensors{ { std::forward<T>(tensor), std::forward<Ts>(other_tensors)... } }; + std::vector<int> vs(seeds); + ARM_COMPUTE_ERROR_ON(vs.size() != tensors.size()); + int k = 0; + for(auto tp : tensors) + { + library->fill(*tp, std::forward<D>(dist), vs[k++]); + } +} + +/** Helper function to get the testing range for each activation layer. + * + * @param[in] activation Activation function to test. + * @param[in] fixed_point_position (Optional) Number of bits for the fractional part. Defaults to 1. + * + * @return A pair containing the lower upper testing bounds for a given function. + */ +template <typename T> +inline std::pair<T, T> get_activation_layer_test_bounds(ActivationLayerInfo::ActivationFunction activation, int fixed_point_position = 1) +{ + bool is_float = std::is_same<T, float>::value; + is_float = is_float || std::is_same<T, half_float::half>::value; + + std::pair<T, T> bounds; + + // Set initial values + if(is_float) + { + bounds = std::make_pair(-255.f, 255.f); + } + else + { + bounds = std::make_pair(std::numeric_limits<T>::lowest(), std::numeric_limits<T>::max()); + } + + // Reduce testing ranges + switch(activation) + { + case ActivationLayerInfo::ActivationFunction::LOGISTIC: + case ActivationLayerInfo::ActivationFunction::SOFT_RELU: + // Reduce range as exponent overflows + if(is_float) + { + bounds.first = -40.f; + bounds.second = 40.f; + } + else + { + bounds.first = -(1 << (fixed_point_position)); + bounds.second = 1 << (fixed_point_position); + } + break; + case ActivationLayerInfo::ActivationFunction::TANH: + // Reduce range as exponent overflows + if(!is_float) + { + bounds.first = -(1 << (fixed_point_position)); + bounds.second = 1 << (fixed_point_position); + } + break; + case ActivationLayerInfo::ActivationFunction::SQRT: + // Reduce range as sqrt should take a non-negative number + bounds.first = (is_float) ? 0 : 1; + break; + default: + break; + } + return bounds; +} +/** Helper function to get the testing range for batch normalization layer. + * + * @param[in] fixed_point_position (Optional) Number of bits for the fractional part. Defaults to 1. + * + * @return A pair containing the lower upper testing bounds. + */ +template <typename T> +std::pair<T, T> get_batchnormalization_layer_test_bounds(int fixed_point_position = 1) +{ + bool is_float = std::is_floating_point<T>::value; + std::pair<T, T> bounds; + + // Set initial values + if(is_float) + { + bounds = std::make_pair(-1.f, 1.f); + } + else + { + bounds = std::make_pair(1, 1 << (fixed_point_position)); + } + + return bounds; +} + +/** Fill mask with the corresponding given pattern. + * + * @param[in,out] mask Mask to be filled according to pattern + * @param[in] cols Columns (width) of mask + * @param[in] rows Rows (height) of mask + * @param[in] pattern Pattern to fill the mask according to + */ +inline void fill_mask_from_pattern(uint8_t *mask, int cols, int rows, MatrixPattern pattern) +{ + unsigned int v = 0; + std::mt19937 gen(user_config.seed.get()); + std::bernoulli_distribution dist(0.5); + + for(int r = 0; r < rows; ++r) + { + for(int c = 0; c < cols; ++c, ++v) + { + uint8_t val = 0; + + switch(pattern) + { + case MatrixPattern::BOX: + val = 255; + break; + case MatrixPattern::CROSS: + val = ((r == (rows / 2)) || (c == (cols / 2))) ? 255 : 0; + break; + case MatrixPattern::DISK: + val = (((r - rows / 2.0f + 0.5f) * (r - rows / 2.0f + 0.5f)) / ((rows / 2.0f) * (rows / 2.0f)) + ((c - cols / 2.0f + 0.5f) * (c - cols / 2.0f + 0.5f)) / ((cols / 2.0f) * + (cols / 2.0f))) <= 1.0f ? 255 : 0; + break; + case MatrixPattern::OTHER: + val = (dist(gen) ? 0 : 255); + break; + default: + return; + } + + mask[v] = val; + } + } + + if(pattern == MatrixPattern::OTHER) + { + std::uniform_int_distribution<uint8_t> distribution_u8(0, ((cols * rows) - 1)); + mask[distribution_u8(gen)] = 255; + } +} + +/** Calculate output tensor shape give a vector of input tensor to concatenate + * + * @param[in] input_shapes Shapes of the tensors to concatenate across depth. + * + * @return The shape of output concatenated tensor. + */ +inline TensorShape calculate_depth_concatenate_shape(std::vector<TensorShape> input_shapes) +{ + TensorShape out_shape = input_shapes.at(0); + + unsigned int max_x = 0; + unsigned int max_y = 0; + unsigned int depth = 0; + + for(auto const &shape : input_shapes) + { + max_x = std::max<unsigned int>(shape.x(), max_x); + max_y = std::max<unsigned int>(shape.y(), max_y); + depth += shape.z(); + } + + out_shape.set(0, max_x); + out_shape.set(1, max_y); + out_shape.set(2, depth); + + return out_shape; +} + +/** Fill matrix random. + * + * @param[in,out] matrix Matrix + * @param[in] cols Columns (width) of matrix + * @param[in] rows Rows (height) of matrix + */ +template <std::size_t SIZE> +inline void fill_warp_matrix(std::array<float, SIZE> &matrix, int cols, int rows) +{ + std::mt19937 gen(user_config.seed.get()); + std::uniform_real_distribution<float> dist(-1, 1); + + for(int v = 0, r = 0; r < rows; ++r) + { + for(int c = 0; c < cols; ++c, ++v) + { + matrix[v] = dist(gen); + } + } + if(SIZE == 9) + { + matrix[(cols * rows) - 1] = 1; + } +} + +/** 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__ */ diff --git a/tests/validation_old/NEON/AbsoluteDifference.cpp b/tests/validation_old/NEON/AbsoluteDifference.cpp new file mode 100644 index 0000000000..aa866fff49 --- /dev/null +++ b/tests/validation_old/NEON/AbsoluteDifference.cpp @@ -0,0 +1,200 @@ +/* + * 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 "NEON/Accessor.h" +#include "PaddingCalculator.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/NEON/functions/NEAbsoluteDifference.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +/** Compute Neon absolute difference function. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] dt_in0 Data type of first input tensor. + * @param[in] dt_in1 Data type of second input tensor. + * @param[in] dt_out Data type of the output tensor. + * + * @return Computed output tensor. + */ +Tensor compute_absolute_difference(const TensorShape &shape, DataType dt_in0, DataType dt_in1, DataType dt_out) +{ + // Create tensors + Tensor src1 = create_tensor<Tensor>(shape, dt_in0); + Tensor src2 = create_tensor<Tensor>(shape, dt_in1); + Tensor dst = create_tensor<Tensor>(shape, dt_out); + + // Create and configure function + NEAbsoluteDifference abs_d; + abs_d.configure(&src1, &src2, &dst); + + // Allocate tensors + src1.allocator()->allocate(); + src2.allocator()->allocate(); + dst.allocator()->allocate(); + + BOOST_TEST(!src1.info()->is_resizable()); + BOOST_TEST(!src2.info()->is_resizable()); + BOOST_TEST(!dst.info()->is_resizable()); + + // Fill tensors + library->fill_tensor_uniform(Accessor(src1), 0); + library->fill_tensor_uniform(Accessor(src2), 1); + + // Compute function + abs_d.run(); + + return dst; +} + +void validate_configuration(const Tensor &src1, const Tensor &src2, Tensor &dst, TensorShape shape) +{ + BOOST_TEST(src1.info()->is_resizable()); + BOOST_TEST(src2.info()->is_resizable()); + BOOST_TEST(dst.info()->is_resizable()); + + // Create and configure function + NEAbsoluteDifference abs_d; + abs_d.configure(&src1, &src2, &dst); + + // Validate valid region + const ValidRegion valid_region = shape_to_valid_region(shape); + validate(src1.info()->valid_region(), valid_region); + validate(src2.info()->valid_region(), valid_region); + validate(dst.info()->valid_region(), valid_region); + + // Validate padding + const PaddingSize padding = PaddingCalculator(shape.x(), 16).required_padding(); + validate(src1.info()->padding(), padding); + validate(src2.info()->padding(), padding); + validate(dst.info()->padding(), padding); +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(NEON) +BOOST_AUTO_TEST_SUITE(AbsoluteDifference) + +BOOST_AUTO_TEST_SUITE(U8) +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(Configuration, (SmallShapes() + LargeShapes()), + shape) +{ + // Create tensors + Tensor src1 = create_tensor<Tensor>(shape, DataType::U8); + Tensor src2 = create_tensor<Tensor>(shape, DataType::U8); + Tensor dst = create_tensor<Tensor>(shape, DataType::U8); + + validate_configuration(src1, src2, dst, shape); +} +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes(), + shape) +{ + // Compute function + Tensor dst = compute_absolute_difference(shape, DataType::U8, DataType::U8, DataType::U8); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_absolute_difference(shape, DataType::U8, DataType::U8, DataType::U8); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes(), + shape) +{ + // Compute function + Tensor dst = compute_absolute_difference(shape, DataType::U8, DataType::U8, DataType::U8); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_absolute_difference(shape, DataType::U8, DataType::U8, DataType::U8); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(S16) +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, dt) +{ + // Create tensors + Tensor src1 = create_tensor<Tensor>(shape, dt); + Tensor src2 = create_tensor<Tensor>(shape, DataType::S16); + Tensor dst = create_tensor<Tensor>(shape, DataType::S16); + + validate_configuration(src1, src2, dst, shape); +} +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * boost::unit_test::data::make({ DataType::U8, DataType::S16 }), + shape, dt) +{ + // Compute function + Tensor dst = compute_absolute_difference(shape, dt, DataType::S16, DataType::S16); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_absolute_difference(shape, dt, DataType::S16, DataType::S16); + + // Validate output + validate(Accessor(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, dt) +{ + // Compute function + Tensor dst = compute_absolute_difference(shape, dt, DataType::S16, DataType::S16); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_absolute_difference(shape, dt, DataType::S16, DataType::S16); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/NEON/Accumulate.cpp b/tests/validation_old/NEON/Accumulate.cpp new file mode 100644 index 0000000000..eb680a383d --- /dev/null +++ b/tests/validation_old/NEON/Accumulate.cpp @@ -0,0 +1,145 @@ +/* + * 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 "NEON/Accessor.h" +#include "PaddingCalculator.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/NEON/functions/NEAccumulate.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +/** Compute Neon accumulate function. + * + * @param[in] shape Shape of the input and output tensors. + * + * @return Computed output tensor. + */ +Tensor compute_accumulate(const TensorShape &shape) +{ + // Create tensors + Tensor src = create_tensor<Tensor>(shape, DataType::U8); + Tensor dst = create_tensor<Tensor>(shape, DataType::S16); + + // Create and configure function + NEAccumulate acc; + acc.configure(&src, &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(Accessor(src), 0); + library->fill_tensor_uniform(Accessor(dst), 1); + + // Compute function + acc.run(); + + return dst; +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(NEON) +BOOST_AUTO_TEST_SUITE(Accumulate) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(Configuration, (SmallShapes() + LargeShapes()), + shape) +{ + // Create tensors + Tensor src = create_tensor<Tensor>(shape, DataType::U8); + Tensor dst = create_tensor<Tensor>(shape, DataType::S16); + + BOOST_TEST(src.info()->is_resizable()); + BOOST_TEST(dst.info()->is_resizable()); + + // Create and configure function + NEAccumulate acc; + acc.configure(&src, &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(), + shape) +{ + // Compute function + Tensor dst = compute_accumulate(shape); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_accumulate(shape); + + // Validate output + validate(Accessor(dst), ref_dst); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes(), + shape) +{ + // Compute function + Tensor dst = compute_accumulate(shape); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_accumulate(shape); + + // Validate output + validate(Accessor(dst), ref_dst); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/NEON/AccumulateSquared.cpp b/tests/validation_old/NEON/AccumulateSquared.cpp new file mode 100644 index 0000000000..29b5edf41b --- /dev/null +++ b/tests/validation_old/NEON/AccumulateSquared.cpp @@ -0,0 +1,146 @@ +/* + * 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 "NEON/Accessor.h" +#include "PaddingCalculator.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/NEON/functions/NEAccumulate.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +/** Compute Neon accumulate squared function. + * + * @param[in] shape Shape of the input and output tensors. + * + * @return Computed output tensor. + */ +Tensor compute_accumulate_squared(const TensorShape &shape, uint32_t shift) +{ + // Create tensors + Tensor src = create_tensor<Tensor>(shape, DataType::U8); + Tensor dst = create_tensor<Tensor>(shape, DataType::S16); + + // Create and configure function + NEAccumulateSquared acc; + acc.configure(&src, shift, &dst); + + // Allocate tensors + src.allocator()->allocate(); + dst.allocator()->allocate(); + + BOOST_TEST(!src.info()->is_resizable()); + BOOST_TEST(!dst.info()->is_resizable()); + + // Fill tensors + // dst tensor filled with non-negative values + library->fill_tensor_uniform(Accessor(src), 0); + library->fill_tensor_uniform(Accessor(dst), 1, static_cast<int16_t>(0), std::numeric_limits<int16_t>::max()); + + // Compute function + acc.run(); + + return dst; +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(NEON) +BOOST_AUTO_TEST_SUITE(AccumulateSquared) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(Configuration, (SmallShapes() + LargeShapes()) * boost::unit_test::data::xrange(0U, 16U), + shape, shift) +{ + // Create tensors + Tensor src = create_tensor<Tensor>(shape, DataType::U8); + Tensor dst = create_tensor<Tensor>(shape, DataType::S16); + + BOOST_TEST(src.info()->is_resizable()); + BOOST_TEST(dst.info()->is_resizable()); + + // Create and configure function + NEAccumulateSquared acc; + acc.configure(&src, shift, &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::xrange(0U, 16U), + shape, shift) +{ + // Compute function + Tensor dst = compute_accumulate_squared(shape, shift); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_accumulate_squared(shape, shift); + + // Validate output + validate(Accessor(dst), ref_dst); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * boost::unit_test::data::make({ 0U, 1U, 15U }), + shape, shift) +{ + // Compute function + Tensor dst = compute_accumulate_squared(shape, shift); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_accumulate_squared(shape, shift); + + // Validate output + validate(Accessor(dst), ref_dst); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/NEON/AccumulateWeighted.cpp b/tests/validation_old/NEON/AccumulateWeighted.cpp new file mode 100644 index 0000000000..c59c1edbc8 --- /dev/null +++ b/tests/validation_old/NEON/AccumulateWeighted.cpp @@ -0,0 +1,145 @@ +/* + * 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 "NEON/Accessor.h" +#include "PaddingCalculator.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/NEON/functions/NEAccumulate.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +/** Compute Neon accumulate weighted function. + * + * @param[in] shape Shape of the input and output tensors. + * + * @return Computed output tensor. + */ +Tensor compute_accumulate_weighted(const TensorShape &shape, float alpha) +{ + // Create tensors + Tensor src = create_tensor<Tensor>(shape, DataType::U8); + Tensor dst = create_tensor<Tensor>(shape, DataType::U8); + + // Create and configure function + NEAccumulateWeighted acc; + acc.configure(&src, alpha, &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(Accessor(src), 0); + library->fill_tensor_uniform(Accessor(dst), 1); + + // Compute function + acc.run(); + + return dst; +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(NEON) +BOOST_AUTO_TEST_SUITE(AccumulateWeighted) + +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({ 0.f, 0.5f, 1.f }), + shape, alpha) +{ + // Create tensors + Tensor src = create_tensor<Tensor>(shape, DataType::U8); + Tensor dst = create_tensor<Tensor>(shape, DataType::U8); + + BOOST_TEST(src.info()->is_resizable()); + BOOST_TEST(dst.info()->is_resizable()); + + // Create and configure function + NEAccumulateWeighted acc; + acc.configure(&src, alpha, &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({ 0.f, 0.5f, 1.f }), + shape, alpha) +{ + // Compute function + Tensor dst = compute_accumulate_weighted(shape, alpha); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_accumulate_weighted(shape, alpha); + + // Validate output + validate(Accessor(dst), ref_dst); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * boost::unit_test::data::make({ 0.f, 0.5f, 1.f }), + shape, alpha) +{ + // Compute function + Tensor dst = compute_accumulate_weighted(shape, alpha); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_accumulate_weighted(shape, alpha); + + // Validate output + validate(Accessor(dst), ref_dst); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/NEON/ArithmeticAddition.cpp b/tests/validation_old/NEON/ArithmeticAddition.cpp new file mode 100644 index 0000000000..490f124422 --- /dev/null +++ b/tests/validation_old/NEON/ArithmeticAddition.cpp @@ -0,0 +1,304 @@ +/* + * 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 "NEON/Accessor.h" +#include "PaddingCalculator.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/NEON/functions/NEArithmeticAddition.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +/** Compute Neon arithmetic addition function. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] dt_in0 Data type of first input tensor. + * @param[in] dt_in1 Data type of second input tensor. + * @param[in] dt_out Data type of the output tensor. + * @param[in] policy Overflow policy of the operation. + * @param[in] fixed_point_position (Optional) Fixed point position that expresses the number of bits for the fractional part of the number when the tensor's data type is QS8 or QS16 (default = 0). + * + * @return Computed output tensor. + */ +Tensor compute_arithmetic_addition(const TensorShape &shape, DataType dt_in0, DataType dt_in1, DataType dt_out, ConvertPolicy policy, int fixed_point_position = 0) +{ + // Create tensors + Tensor src1 = create_tensor<Tensor>(shape, dt_in0, 1, fixed_point_position); + Tensor src2 = create_tensor<Tensor>(shape, dt_in1, 1, fixed_point_position); + Tensor dst = create_tensor<Tensor>(shape, dt_out, 1, fixed_point_position); + + // Create and configure function + NEArithmeticAddition add; + add.configure(&src1, &src2, &dst, policy); + + // Allocate tensors + src1.allocator()->allocate(); + src2.allocator()->allocate(); + dst.allocator()->allocate(); + + BOOST_TEST(!src1.info()->is_resizable()); + BOOST_TEST(!src2.info()->is_resizable()); + BOOST_TEST(!dst.info()->is_resizable()); + + // Fill tensors + library->fill_tensor_uniform(Accessor(src1), 0); + library->fill_tensor_uniform(Accessor(src2), 1); + + // Compute function + add.run(); + + return dst; +} + +void validate_configuration(const Tensor &src1, const Tensor &src2, Tensor &dst, TensorShape shape, ConvertPolicy policy) +{ + BOOST_TEST(src1.info()->is_resizable()); + BOOST_TEST(src2.info()->is_resizable()); + BOOST_TEST(dst.info()->is_resizable()); + + // Create and configure function + NEArithmeticAddition add; + add.configure(&src1, &src2, &dst, policy); + + // Validate valid region + const ValidRegion valid_region = shape_to_valid_region(shape); + validate(src1.info()->valid_region(), valid_region); + validate(src2.info()->valid_region(), valid_region); + validate(dst.info()->valid_region(), valid_region); + + // Validate padding + const PaddingSize padding = PaddingCalculator(shape.x(), 16).required_padding(); + validate(src1.info()->padding(), padding); + validate(src2.info()->padding(), padding); + validate(dst.info()->padding(), padding); +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(NEON) +BOOST_AUTO_TEST_SUITE(ArithmeticAddition) + +BOOST_AUTO_TEST_SUITE(U8) +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({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }), + shape, policy) +{ + // Create tensors + Tensor src1 = create_tensor<Tensor>(shape, DataType::U8); + Tensor src2 = create_tensor<Tensor>(shape, DataType::U8); + Tensor dst = create_tensor<Tensor>(shape, DataType::U8); + + validate_configuration(src1, src2, dst, shape, policy); +} +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }), + shape, policy) +{ + // Compute function + Tensor dst = compute_arithmetic_addition(shape, DataType::U8, DataType::U8, DataType::U8, policy); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_addition(shape, DataType::U8, DataType::U8, DataType::U8, policy); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(S16) +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 }) * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }), + shape, dt, policy) +{ + // Create tensors + Tensor src1 = create_tensor<Tensor>(shape, dt); + Tensor src2 = create_tensor<Tensor>(shape, DataType::S16); + Tensor dst = create_tensor<Tensor>(shape, DataType::S16); + + validate_configuration(src1, src2, dst, shape, policy); +} +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * boost::unit_test::data::make({ DataType::U8, DataType::S16 }) * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }), + shape, dt, policy) +{ + // Compute function + Tensor dst = compute_arithmetic_addition(shape, dt, DataType::S16, DataType::S16, policy); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_addition(shape, dt, DataType::S16, DataType::S16, policy); + + // Validate output + validate(Accessor(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 }) * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }), + shape, dt, policy) +{ + // Compute function + Tensor dst = compute_arithmetic_addition(shape, dt, DataType::S16, DataType::S16, policy); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_addition(shape, dt, DataType::S16, DataType::S16, policy); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(Quantized) +BOOST_AUTO_TEST_SUITE(QS8) +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * ConvertPolicies() * boost::unit_test::data::xrange(1, 7), + shape, policy, fixed_point_position) +{ + // Compute function + Tensor dst = compute_arithmetic_addition(shape, DataType::QS8, DataType::QS8, DataType::QS8, policy, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_addition(shape, DataType::QS8, DataType::QS8, DataType::QS8, policy, fixed_point_position); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * ConvertPolicies() * boost::unit_test::data::xrange(1, 7), + shape, policy, fixed_point_position) +{ + // Compute function + Tensor dst = compute_arithmetic_addition(shape, DataType::QS8, DataType::QS8, DataType::QS8, policy, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_addition(shape, DataType::QS8, DataType::QS8, DataType::QS8, policy, fixed_point_position); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(QS16) +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * ConvertPolicies() * boost::unit_test::data::xrange(1, 15), + shape, policy, fixed_point_position) +{ + // Compute function + Tensor dst = compute_arithmetic_addition(shape, DataType::QS16, DataType::QS16, DataType::QS16, policy, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_addition(shape, DataType::QS16, DataType::QS16, DataType::QS16, policy, fixed_point_position); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * ConvertPolicies() * boost::unit_test::data::xrange(1, 15), + shape, policy, fixed_point_position) +{ + // Compute function + Tensor dst = compute_arithmetic_addition(shape, DataType::QS16, DataType::QS16, DataType::QS16, policy, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_addition(shape, DataType::QS16, DataType::QS16, DataType::QS16, policy, fixed_point_position); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() + +#ifdef ARM_COMPUTE_ENABLE_FP16 +BOOST_AUTO_TEST_SUITE(F16) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes(), shape) +{ + // Compute function + Tensor dst = compute_arithmetic_addition(shape, DataType::F16, DataType::F16, DataType::F16, ConvertPolicy::WRAP); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_addition(shape, DataType::F16, DataType::F16, DataType::F16, ConvertPolicy::WRAP); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() +#endif /* ARM_COMPUTE_ENABLE_FP16 */ + +BOOST_AUTO_TEST_SUITE(F32) +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({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }), + shape, policy) +{ + // Create tensors + Tensor src1 = create_tensor<Tensor>(shape, DataType::F32); + Tensor src2 = create_tensor<Tensor>(shape, DataType::F32); + Tensor dst = create_tensor<Tensor>(shape, DataType::F32); + + validate_configuration(src1, src2, dst, shape, policy); +} +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes(), shape) +{ + // Compute function + Tensor dst = compute_arithmetic_addition(shape, DataType::F32, DataType::F32, DataType::F32, ConvertPolicy::WRAP); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_addition(shape, DataType::F32, DataType::F32, DataType::F32, ConvertPolicy::WRAP); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }), + shape, policy) +{ + // Compute function + Tensor dst = compute_arithmetic_addition(shape, DataType::F32, DataType::F32, DataType::F32, policy); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_addition(shape, DataType::F32, DataType::F32, DataType::F32, policy); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/NEON/ArithmeticSubtraction.cpp b/tests/validation_old/NEON/ArithmeticSubtraction.cpp new file mode 100644 index 0000000000..86aa124f00 --- /dev/null +++ b/tests/validation_old/NEON/ArithmeticSubtraction.cpp @@ -0,0 +1,306 @@ +/* + * 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 "NEON/Accessor.h" +#include "PaddingCalculator.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/NEON/functions/NEArithmeticSubtraction.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +/** Compute Neon arithmetic subtraction function. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] dt_in0 Data type of first input tensor. + * @param[in] dt_in1 Data type of second input tensor. + * @param[in] dt_out Data type of the output tensor. + * @param[in] policy Overflow policy of the operation. + * @param[in] fixed_point_position (Optional) Fixed point position that expresses the number of bits for the fractional part of the number when the tensor's data type is QS8 or QS16 (default = 0). + * + * @return Computed output tensor. + */ +Tensor compute_arithmetic_subtraction(const TensorShape &shape, DataType dt_in0, DataType dt_in1, DataType dt_out, ConvertPolicy policy, int fixed_point_position = 0) +{ + // Create tensors + Tensor src1 = create_tensor<Tensor>(shape, dt_in0, 1, fixed_point_position); + Tensor src2 = create_tensor<Tensor>(shape, dt_in1, 1, fixed_point_position); + Tensor dst = create_tensor<Tensor>(shape, dt_out, 1, fixed_point_position); + + // Create and configure function + NEArithmeticSubtraction sub; + sub.configure(&src1, &src2, &dst, policy); + + // Allocate tensors + src1.allocator()->allocate(); + src2.allocator()->allocate(); + dst.allocator()->allocate(); + + BOOST_TEST(!src1.info()->is_resizable()); + BOOST_TEST(!src2.info()->is_resizable()); + BOOST_TEST(!dst.info()->is_resizable()); + + // Fill tensors + library->fill_tensor_uniform(Accessor(src1), 0); + library->fill_tensor_uniform(Accessor(src2), 1); + + // Compute function + sub.run(); + + return dst; +} + +void validate_configuration(const Tensor &src1, const Tensor &src2, Tensor &dst, TensorShape shape, ConvertPolicy policy) +{ + BOOST_TEST(src1.info()->is_resizable()); + BOOST_TEST(src2.info()->is_resizable()); + BOOST_TEST(dst.info()->is_resizable()); + + // Create and configure function + NEArithmeticSubtraction sub; + sub.configure(&src1, &src2, &dst, policy); + + // Validate valid region + const ValidRegion valid_region = shape_to_valid_region(shape); + validate(src1.info()->valid_region(), valid_region); + validate(src2.info()->valid_region(), valid_region); + validate(dst.info()->valid_region(), valid_region); + + // Validate padding + const PaddingSize padding = PaddingCalculator(shape.x(), 16).required_padding(); + validate(src1.info()->padding(), padding); + validate(src2.info()->padding(), padding); + validate(dst.info()->padding(), padding); +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(NEON) +BOOST_AUTO_TEST_SUITE(ArithmeticSubtraction) + +BOOST_AUTO_TEST_SUITE(U8) +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({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }), + shape, policy) +{ + // Create tensors + Tensor src1 = create_tensor<Tensor>(shape, DataType::U8); + Tensor src2 = create_tensor<Tensor>(shape, DataType::U8); + Tensor dst = create_tensor<Tensor>(shape, DataType::U8); + + validate_configuration(src1, src2, dst, shape, policy); +} +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }), + shape, policy) +{ + // Compute function + Tensor dst = compute_arithmetic_subtraction(shape, DataType::U8, DataType::U8, DataType::U8, policy); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_subtraction(shape, DataType::U8, DataType::U8, DataType::U8, policy); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(S16) +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 }) * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }), + shape, dt, policy) +{ + // Create tensors + Tensor src1 = create_tensor<Tensor>(shape, dt); + Tensor src2 = create_tensor<Tensor>(shape, DataType::S16); + Tensor dst = create_tensor<Tensor>(shape, DataType::S16); + + validate_configuration(src1, src2, dst, shape, policy); +} +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * boost::unit_test::data::make({ DataType::U8, DataType::S16 }) * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }), + shape, dt, policy) +{ + // Compute function + Tensor dst = compute_arithmetic_subtraction(shape, dt, DataType::S16, DataType::S16, policy); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_subtraction(shape, dt, DataType::S16, DataType::S16, policy); + + // Validate output + validate(Accessor(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 }) * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }), + shape, dt, policy) +{ + // Compute function + Tensor dst = compute_arithmetic_subtraction(shape, dt, DataType::S16, DataType::S16, policy); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_subtraction(shape, dt, DataType::S16, DataType::S16, policy); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(Quantized) +BOOST_AUTO_TEST_SUITE(QS8) +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * ConvertPolicies() * boost::unit_test::data::xrange(1, 7), + shape, policy, fixed_point_position) +{ + // Compute function + Tensor dst = compute_arithmetic_subtraction(shape, DataType::QS8, DataType::QS8, DataType::QS8, policy, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_subtraction(shape, DataType::QS8, DataType::QS8, DataType::QS8, policy, fixed_point_position); + + // Validate output + validate(Accessor(dst), ref_dst); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * ConvertPolicies() * boost::unit_test::data::xrange(1, 7), + shape, policy, fixed_point_position) +{ + // Compute function + Tensor dst = compute_arithmetic_subtraction(shape, DataType::QS8, DataType::QS8, DataType::QS8, policy, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_subtraction(shape, DataType::QS8, DataType::QS8, DataType::QS8, policy, fixed_point_position); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(QS16) +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * ConvertPolicies() * boost::unit_test::data::xrange(1, 15), + shape, policy, fixed_point_position) +{ + // Compute function + Tensor dst = compute_arithmetic_subtraction(shape, DataType::QS16, DataType::QS16, DataType::QS16, policy, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_subtraction(shape, DataType::QS16, DataType::QS16, DataType::QS16, policy, fixed_point_position); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * ConvertPolicies() * boost::unit_test::data::xrange(1, 15), + shape, policy, fixed_point_position) +{ + // Compute function + Tensor dst = compute_arithmetic_subtraction(shape, DataType::QS16, DataType::QS16, DataType::QS16, policy, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_subtraction(shape, DataType::QS16, DataType::QS16, DataType::QS16, policy, fixed_point_position); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() + +#ifdef ARM_COMPUTE_ENABLE_FP16 +BOOST_AUTO_TEST_SUITE(Float16) +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes(), shape) +{ + // Compute function + Tensor dst = compute_arithmetic_subtraction(shape, DataType::F16, DataType::F16, DataType::F16, ConvertPolicy::WRAP); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_subtraction(shape, DataType::F16, DataType::F16, DataType::F16, ConvertPolicy::WRAP); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() +#endif /* ARM_COMPUTE_ENABLE_FP16 */ + +BOOST_AUTO_TEST_SUITE(Float) +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({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }), + shape, policy) +{ + // Create tensors + Tensor src1 = create_tensor<Tensor>(shape, DataType::F32); + Tensor src2 = create_tensor<Tensor>(shape, DataType::F32); + Tensor dst = create_tensor<Tensor>(shape, DataType::F32); + + validate_configuration(src1, src2, dst, shape, policy); +} +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes(), shape) +{ + // Compute function + Tensor dst = compute_arithmetic_subtraction(shape, DataType::F32, DataType::F32, DataType::F32, ConvertPolicy::WRAP); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_subtraction(shape, DataType::F32, DataType::F32, DataType::F32, ConvertPolicy::WRAP); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }), + shape, policy) +{ + // Compute function + Tensor dst = compute_arithmetic_subtraction(shape, DataType::F32, DataType::F32, DataType::F32, policy); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_arithmetic_subtraction(shape, DataType::F32, DataType::F32, DataType::F32, policy); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/NEON/BatchNormalizationLayer.cpp b/tests/validation_old/NEON/BatchNormalizationLayer.cpp new file mode 100644 index 0000000000..d98f99a63c --- /dev/null +++ b/tests/validation_old/NEON/BatchNormalizationLayer.cpp @@ -0,0 +1,258 @@ +/* + * 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 "NEON/Accessor.h" +#include "TypePrinter.h" +#include "tests/Globals.h" +#include "tests/NEON/Helper.h" +#include "tests/Utils.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Helpers.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" +#include "tests/validation_old/dataset/BatchNormalizationLayerDataset.h" + +#include "arm_compute/runtime/NEON/functions/NEBatchNormalizationLayer.h" + +#include <random> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +const float tolerance_qs8 = 6; /**< Tolerance value for comparing reference's output against quantized implementation's output */ +const float tolerance_qs16 = 6; /**< Tolerance value for comparing reference's output against quantized implementation's output */ +const float tolerance_f32 = 1e-05f; /**< Tolerance value for comparing reference's output against floating point implementation's output */ +#ifdef ARM_COMPUTE_ENABLE_FP16 +const float tolerance_f16 = 0.01f; /**< Tolerance value for comparing reference's output against half precision floating point implementation's output */ +#endif /* ARM_COMPUTE_ENABLE_FP16 */ + +/** Compute Neon batch normalization function. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] dt Data type of input and output tensors. + * @param[in] norm_info Normalization Layer information. + * + * @return Computed output tensor. + */ +Tensor compute_reference_batch_normalization_layer(const TensorShape &shape0, const TensorShape &shape1, DataType dt, float epsilon, int fixed_point_position = 0) +{ + // Create tensors + Tensor src = create_tensor<Tensor>(shape0, dt, 1, fixed_point_position); + Tensor dst = create_tensor<Tensor>(shape0, dt, 1, fixed_point_position); + Tensor mean = create_tensor<Tensor>(shape1, dt, 1, fixed_point_position); + Tensor var = create_tensor<Tensor>(shape1, dt, 1, fixed_point_position); + Tensor beta = create_tensor<Tensor>(shape1, dt, 1, fixed_point_position); + Tensor gamma = create_tensor<Tensor>(shape1, dt, 1, fixed_point_position); + + // Create and configure function + NEBatchNormalizationLayer norm; + norm.configure(&src, &dst, &mean, &var, &beta, &gamma, epsilon); + + // Allocate tensors + src.allocator()->allocate(); + dst.allocator()->allocate(); + mean.allocator()->allocate(); + var.allocator()->allocate(); + beta.allocator()->allocate(); + gamma.allocator()->allocate(); + + BOOST_TEST(!src.info()->is_resizable()); + BOOST_TEST(!dst.info()->is_resizable()); + BOOST_TEST(!mean.info()->is_resizable()); + BOOST_TEST(!var.info()->is_resizable()); + BOOST_TEST(!beta.info()->is_resizable()); + BOOST_TEST(!gamma.info()->is_resizable()); + + // Fill tensors + switch(dt) + { + case DataType::QS8: + { + const std::pair<int8_t, int8_t> bounds = get_batchnormalization_layer_test_bounds<int8_t>(fixed_point_position); + std::uniform_int_distribution<> distribution(bounds.first, bounds.second); + std::uniform_int_distribution<> distribution_var(0, bounds.second); + test::fill_tensors(distribution, { 0, 1, 3, 4 }, &src, &mean, &beta, &gamma); + test::fill_tensors(distribution_var, { 0 }, &var); + break; + } + case DataType::QS16: + { + const std::pair<int16_t, int16_t> bounds = get_batchnormalization_layer_test_bounds<int16_t>(fixed_point_position); + std::uniform_int_distribution<> distribution(bounds.first, bounds.second); + std::uniform_int_distribution<> distribution_var(0, bounds.second); + test::fill_tensors(distribution, { 0, 1, 3, 4 }, &src, &mean, &beta, &gamma); + test::fill_tensors(distribution_var, { 0 }, &var); + break; + } +#ifdef ARM_COMPUTE_ENABLE_FP16 + case DataType::F16: + { + const std::pair<half_float::half, half_float::half> bounds = get_batchnormalization_layer_test_bounds<half_float::half>(); + std::uniform_real_distribution<> distribution(bounds.first, bounds.second); + std::uniform_real_distribution<> distribution_var(0, bounds.second); + test::fill_tensors(distribution, { 0, 1, 3, 4 }, &src, &mean, &beta, &gamma); + test::fill_tensors(distribution_var, { 0 }, &var); + break; + } +#endif /* ARM_COMPUTE_ENABLE_FP16 */ + case DataType::F32: + { + const std::pair<float, float> bounds = get_batchnormalization_layer_test_bounds<float>(); + std::uniform_real_distribution<> distribution(bounds.first, bounds.second); + std::uniform_real_distribution<> distribution_var(0, bounds.second); + test::fill_tensors(distribution, { 0, 1, 3, 4 }, &src, &mean, &beta, &gamma); + test::fill_tensors(distribution_var, { 0 }, &var); + break; + } + default: + { + ARM_COMPUTE_ERROR("Not supported"); + break; + } + } + + // Compute function + norm.run(); + + return dst; +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(NEON) +BOOST_AUTO_TEST_SUITE(BatchNormalizationLayer) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(Configuration, RandomBatchNormalizationLayerDataset() * boost::unit_test::data::make({ DataType::QS8, DataType::QS16, DataType::F32 }), obj, dt) +{ + // Set fixed point position data type allowed + int fixed_point_position = (arm_compute::is_data_type_fixed_point(dt)) ? 3 : 0; + + // Create tensors + Tensor src = create_tensor<Tensor>(obj.shape0, dt, 1, fixed_point_position); + Tensor dst = create_tensor<Tensor>(obj.shape0, dt, 1, fixed_point_position); + Tensor mean = create_tensor<Tensor>(obj.shape1, dt, 1, fixed_point_position); + Tensor var = create_tensor<Tensor>(obj.shape1, dt, 1, fixed_point_position); + Tensor beta = create_tensor<Tensor>(obj.shape1, dt, 1, fixed_point_position); + Tensor gamma = create_tensor<Tensor>(obj.shape1, dt, 1, fixed_point_position); + + BOOST_TEST(src.info()->is_resizable()); + BOOST_TEST(dst.info()->is_resizable()); + BOOST_TEST(mean.info()->is_resizable()); + BOOST_TEST(var.info()->is_resizable()); + BOOST_TEST(beta.info()->is_resizable()); + BOOST_TEST(gamma.info()->is_resizable()); + + // Create and configure function + NEBatchNormalizationLayer norm; + norm.configure(&src, &dst, &mean, &var, &beta, &gamma, obj.epsilon); + + // Validate valid region + const ValidRegion valid_region = shape_to_valid_region(obj.shape0); + const ValidRegion valid_region_vec = shape_to_valid_region(obj.shape1); + validate(src.info()->valid_region(), valid_region); + validate(dst.info()->valid_region(), valid_region); + validate(mean.info()->valid_region(), valid_region_vec); + validate(var.info()->valid_region(), valid_region_vec); + validate(beta.info()->valid_region(), valid_region_vec); + validate(gamma.info()->valid_region(), valid_region_vec); +} + +BOOST_AUTO_TEST_SUITE(Float) +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(Random, + RandomBatchNormalizationLayerDataset() * boost::unit_test::data::make(DataType::F32), + obj, dt) +{ + // Compute function + Tensor dst = compute_reference_batch_normalization_layer(obj.shape0, obj.shape1, dt, obj.epsilon); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_batch_normalization_layer(obj.shape0, obj.shape1, dt, obj.epsilon); + + // Validate output + validate(Accessor(dst), ref_dst, tolerance_f32, 0); +} +BOOST_AUTO_TEST_SUITE_END() + +#ifdef ARM_COMPUTE_ENABLE_FP16 +BOOST_AUTO_TEST_SUITE(Float16) +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(Random, + RandomBatchNormalizationLayerDataset() * boost::unit_test::data::make(DataType::F16), + obj, dt) +{ + // Compute function + Tensor dst = compute_reference_batch_normalization_layer(obj.shape0, obj.shape1, dt, obj.epsilon); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_batch_normalization_layer(obj.shape0, obj.shape1, dt, obj.epsilon); + + // Validate output + validate(Accessor(dst), ref_dst, tolerance_f16, 0); +} +BOOST_AUTO_TEST_SUITE_END() +#endif /* ARM_COMPUTE_ENABLE_FP16 */ + +BOOST_AUTO_TEST_SUITE(Quantized) +BOOST_AUTO_TEST_SUITE(QS8) +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(Random, + RandomBatchNormalizationLayerDataset() * boost::unit_test::data::make(DataType::QS8) * boost::unit_test::data::xrange(1, 6), + obj, dt, fixed_point_position) +{ + // Compute function + Tensor dst = compute_reference_batch_normalization_layer(obj.shape0, obj.shape1, dt, obj.epsilon, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_batch_normalization_layer(obj.shape0, obj.shape1, dt, obj.epsilon, fixed_point_position); + + // Validate output + validate(Accessor(dst), ref_dst, tolerance_qs8); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(QS16) +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(Random, + RandomBatchNormalizationLayerDataset() * boost::unit_test::data::make(DataType::QS16) * boost::unit_test::data::xrange(1, 14), + obj, dt, fixed_point_position) +{ + // Compute function + Tensor dst = compute_reference_batch_normalization_layer(obj.shape0, obj.shape1, dt, obj.epsilon, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_batch_normalization_layer(obj.shape0, obj.shape1, dt, obj.epsilon, fixed_point_position); + + // Validate output + validate(Accessor(dst), ref_dst, tolerance_qs16); +} +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/NEON/Box3x3.cpp b/tests/validation_old/NEON/Box3x3.cpp new file mode 100644 index 0000000000..708b7de204 --- /dev/null +++ b/tests/validation_old/NEON/Box3x3.cpp @@ -0,0 +1,167 @@ +/* + * 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 "NEON/Accessor.h" +#include "PaddingCalculator.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" +#include "tests/validation_old/ValidationUserConfiguration.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/NEON/functions/NEBox3x3.h" +#include "arm_compute/runtime/SubTensor.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +constexpr unsigned int filter_size = 3; /** Size of the kernel/filter in number of elements. */ +constexpr BorderSize border_size(filter_size / 2); /** Border size of the kernel/filter around its central element. */ + +/** Compute Neon box3x3 filter. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] border_mode BorderMode used by the input tensor. + * @param[in] constant_border_value Constant to use if @p border_mode == CONSTANT. + * + * @return Computed output tensor. + */ +Tensor compute_box3x3(const TensorShape &shape, BorderMode border_mode, uint8_t constant_border_value) +{ + // Create tensors + Tensor src = create_tensor<Tensor>(shape, DataType::U8); + Tensor dst = create_tensor<Tensor>(shape, DataType::U8); + + // Create and configure function + NEBox3x3 box3x3; + box3x3.configure(&src, &dst, border_mode, constant_border_value); + + // 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(Accessor(src), 0); + + // Compute function + box3x3.run(); + + return dst; +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(NEON) +BOOST_AUTO_TEST_SUITE(Box3x3) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(Configuration, (SmallShapes() + LargeShapes()) * BorderModes(), shape, border_mode) +{ + // Create tensors + Tensor src = create_tensor<Tensor>(shape, DataType::U8); + Tensor dst = create_tensor<Tensor>(shape, DataType::U8); + + BOOST_TEST(src.info()->is_resizable()); + BOOST_TEST(dst.info()->is_resizable()); + + // Create and configure function + NEBox3x3 box3x3; + box3x3.configure(&src, &dst, border_mode); + + // Validate valid region + const ValidRegion src_valid_region = shape_to_valid_region(shape); + const ValidRegion dst_valid_region = shape_to_valid_region(shape, border_mode == BorderMode::UNDEFINED, border_size); + validate(src.info()->valid_region(), src_valid_region); + validate(dst.info()->valid_region(), dst_valid_region); + + // Validate padding + PaddingCalculator calculator(shape.x(), 8); + calculator.set_border_size(1); + calculator.set_border_mode(border_mode); + + const PaddingSize dst_padding = calculator.required_padding(); + + calculator.set_accessed_elements(16); + calculator.set_access_offset(-1); + + const PaddingSize src_padding = calculator.required_padding(); + + validate(src.info()->padding(), src_padding); + validate(dst.info()->padding(), dst_padding); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * BorderModes(), shape, border_mode) +{ + std::mt19937 gen(user_config.seed.get()); + std::uniform_int_distribution<uint8_t> distribution(0, 255); + const uint8_t border_value = distribution(gen); + + // Compute function + Tensor dst = compute_box3x3(shape, border_mode, border_value); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_box3x3(shape, border_mode, border_value); + + // Validate output + validate(Accessor(dst), ref_dst, shape_to_valid_region(shape, border_mode == BorderMode::UNDEFINED, border_size)); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * BorderModes(), shape, border_mode) +{ + std::mt19937 gen(user_config.seed.get()); + std::uniform_int_distribution<uint8_t> distribution(0, 255); + const uint8_t border_value = distribution(gen); + + // Compute function + Tensor dst = compute_box3x3(shape, border_mode, border_value); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_box3x3(shape, border_mode, border_value); + + // Validate output + validate(Accessor(dst), ref_dst, shape_to_valid_region(shape, border_mode == BorderMode::UNDEFINED, border_size)); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/NEON/DepthConvert.cpp b/tests/validation_old/NEON/DepthConvert.cpp new file mode 100644 index 0000000000..48a2b6d3f0 --- /dev/null +++ b/tests/validation_old/NEON/DepthConvert.cpp @@ -0,0 +1,637 @@ +/* + * 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 "NEON/Accessor.h" +#include "PaddingCalculator.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/NEON/functions/NEDepthConvert.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +/** Compute Neon depth convert function. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] dt_in Data type of input tensor. + * @param[in] dt_out Data type of the output tensor. + * @param[in] policy Conversion policy. + * @param[in] shift Value for down/up conversions. Must be 0 <= shift < 8. + * @param[in] fixed_point_position_in (Optional) Fixed point position for the input tensor. + * @param[in] fixed_point_position_out (Optional) Fixed point position for the output tensor. + * + * @return Computed output tensor. + */ +Tensor compute_depth_convert(const TensorShape &shape, DataType dt_in, DataType dt_out, ConvertPolicy policy, + uint32_t shift, uint32_t fixed_point_position_in = 0, uint32_t fixed_point_position_out = 0) +{ + // Create tensors + Tensor src = create_tensor<Tensor>(shape, dt_in, 1, fixed_point_position_in); + Tensor dst = create_tensor<Tensor>(shape, dt_out, 1, fixed_point_position_out); + + // Create and configure function + NEDepthConvert depth_convert; + depth_convert.configure(&src, &dst, policy, shift); + + // 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(Accessor(src), 0); + + // Compute function + depth_convert.run(); + + return dst; +} +/** Configure and validate region/padding function. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] dt_in Data type of input tensor. + * @param[in] dt_out Data type of the output tensor. + * @param[in] policy Conversion policy. + * @param[in] shift Value for down/up conversions. Must be 0 <= shift < 8. + * @param[in] fixed_point_position_in (Optional) Fixed point position for the input tensor. + * @param[in] fixed_point_position_out (Optional) Fixed point position for the output tensor. + * + */ + +void compute_configure_validate(const TensorShape &shape, DataType dt_in, DataType dt_out, ConvertPolicy policy, + uint32_t shift, uint32_t fixed_point_position_in = 0, uint32_t fixed_point_position_out = 0) +{ + // Create tensors + Tensor src = create_tensor<Tensor>(shape, dt_in, 1, fixed_point_position_in); + Tensor dst = create_tensor<Tensor>(shape, dt_out, 1, fixed_point_position_out); + + BOOST_TEST(src.info()->is_resizable()); + BOOST_TEST(dst.info()->is_resizable()); + + // Create and configure function + NEDepthConvert depth_convert; + depth_convert.configure(&src, &dst, policy, shift); + + // 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); +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(NEON) +BOOST_AUTO_TEST_SUITE(DepthConvert) + +BOOST_AUTO_TEST_SUITE(QS8_to_QS8) +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({ ConvertPolicy::SATURATE }) + * (boost::unit_test::data::make({ 1, 3, 5, 6 }) ^ boost::unit_test::data::make({ 6, 5, 1, 3 })), + shape, policy, fixed_point_position_in, fixed_point_position_out) +{ + // Compute configure and validate region/padding + compute_configure_validate(shape, DataType::QS8, DataType::QS8, policy, 0, fixed_point_position_in, fixed_point_position_out); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE }) + * (boost::unit_test::data::make({ 1, 3, 5, 6 }) ^ boost::unit_test::data::make({ 6, 5, 1, 3 })), + shape, policy, fixed_point_position_in, fixed_point_position_out) +{ + // Compute function + Tensor dst = compute_depth_convert(shape, DataType::QS8, DataType::QS8, policy, 0, fixed_point_position_in, fixed_point_position_out); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::QS8, DataType::QS8, policy, 0, fixed_point_position_in, fixed_point_position_out); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(QS8_to_F32) +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({ ConvertPolicy::SATURATE }) + * boost::unit_test::data::xrange(1, 7, 1), + shape, policy, fixed_point_position) +{ + // Compute configure and validate region/padding + compute_configure_validate(shape, DataType::QS8, DataType::F32, policy, 0, fixed_point_position, fixed_point_position); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE }) + * boost::unit_test::data::xrange(1, 7, 1), + shape, policy, fixed_point_position) +{ + // Compute function + Tensor dst = compute_depth_convert(shape, DataType::QS8, DataType::F32, policy, 0, fixed_point_position, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::QS8, DataType::F32, policy, 0, fixed_point_position, fixed_point_position); + + // Validate output + validate(Accessor(dst), ref_dst); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE }) + * boost::unit_test::data::xrange(1, 7, 1), + shape, policy, fixed_point_position) +{ + // Compute function + Tensor dst = compute_depth_convert(shape, DataType::QS8, DataType::F32, policy, 0, fixed_point_position, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::QS8, DataType::F32, policy, 0, fixed_point_position, fixed_point_position); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(F32_to_QS8) +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({ ConvertPolicy::SATURATE }) + * boost::unit_test::data::xrange(1, 7, 1), + shape, policy, fixed_point_position) +{ + // Compute configure and validate region/padding + compute_configure_validate(shape, DataType::F32, DataType::QS8, policy, 0, fixed_point_position, fixed_point_position); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE }) + * boost::unit_test::data::xrange(1, 7, 1), + shape, policy, fixed_point_position) +{ + // Compute function + Tensor dst = compute_depth_convert(shape, DataType::F32, DataType::QS8, policy, 0, fixed_point_position, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::F32, DataType::QS8, policy, 0, fixed_point_position, fixed_point_position); + + // Validate output + validate(Accessor(dst), ref_dst); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE }) + * boost::unit_test::data::xrange(1, 7, 1), + shape, policy, fixed_point_position) +{ + // Compute function + Tensor dst = compute_depth_convert(shape, DataType::F32, DataType::QS8, policy, 0, fixed_point_position, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::F32, DataType::QS8, policy, 0, fixed_point_position, fixed_point_position); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(QS16_to_QS16) +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({ ConvertPolicy::SATURATE }) + * (boost::unit_test::data::make({ 3, 6, 7, 13, 14 }) ^ boost::unit_test::data::make({ 5, 10, 14, 4, 7 })), + shape, policy, fixed_point_position_in, fixed_point_position_out) +{ + // Compute configure and validate region/padding + compute_configure_validate(shape, DataType::QS16, DataType::QS16, policy, 0, fixed_point_position_in, fixed_point_position_out); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE }) + * (boost::unit_test::data::make({ 3, 6, 7, 13, 14 }) ^ boost::unit_test::data::make({ 5, 10, 14, 4, 7 })), + shape, policy, fixed_point_position_in, fixed_point_position_out) +{ + // Compute function + Tensor dst = compute_depth_convert(shape, DataType::QS16, DataType::QS16, policy, 0, fixed_point_position_in, fixed_point_position_out); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::QS16, DataType::QS16, policy, 0, fixed_point_position_in, fixed_point_position_out); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(QS16_to_F32) +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({ ConvertPolicy::SATURATE }) + * boost::unit_test::data::xrange(1, 15, 1), + shape, policy, fixed_point_position) +{ + // Compute configure and validate region/padding + compute_configure_validate(shape, DataType::QS16, DataType::F32, policy, 0, fixed_point_position, fixed_point_position); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE }) + * boost::unit_test::data::xrange(1, 15, 1), + shape, policy, fixed_point_position) +{ + // Compute function + Tensor dst = compute_depth_convert(shape, DataType::QS16, DataType::F32, policy, 0, fixed_point_position, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::QS16, DataType::F32, policy, 0, fixed_point_position, fixed_point_position); + + // Validate output + validate(Accessor(dst), ref_dst); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE }) + * boost::unit_test::data::xrange(1, 15, 1), + shape, policy, fixed_point_position) +{ + // Compute function + Tensor dst = compute_depth_convert(shape, DataType::QS16, DataType::F32, policy, 0, fixed_point_position, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::QS16, DataType::F32, policy, 0, fixed_point_position, fixed_point_position); + + // Validate output + validate(Accessor(dst), ref_dst); +} + +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(F32_to_QS16) +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({ ConvertPolicy::SATURATE }) + * boost::unit_test::data::xrange(1, 7, 1), + shape, policy, fixed_point_position) +{ + // Compute configure and validate region/padding + compute_configure_validate(shape, DataType::F32, DataType::QS16, policy, 0, fixed_point_position, fixed_point_position); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE }) + * boost::unit_test::data::xrange(1, 15, 1), + shape, policy, fixed_point_position) +{ + // Compute function + Tensor dst = compute_depth_convert(shape, DataType::F32, DataType::QS16, policy, 0, fixed_point_position, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::F32, DataType::QS16, policy, 0, fixed_point_position, fixed_point_position); + + // Validate output + validate(Accessor(dst), ref_dst); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE }) + * boost::unit_test::data::xrange(1, 15, 1), + shape, policy, fixed_point_position) +{ + // Compute function + Tensor dst = compute_depth_convert(shape, DataType::F32, DataType::QS16, policy, 0, fixed_point_position, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::F32, DataType::QS16, policy, 0, fixed_point_position, fixed_point_position); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(U8_to_U16) +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({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute configure and validate region/padding + compute_configure_validate(shape, DataType::U8, DataType::U16, policy, shift, 0); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute function + Tensor dst = compute_depth_convert(shape, DataType::U8, DataType::U16, policy, shift); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::U8, DataType::U16, policy, shift); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute function + Tensor dst = compute_depth_convert(shape, DataType::U8, DataType::U16, policy, shift); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::U8, DataType::U16, policy, shift); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(U8_to_S16) +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({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute configure and validate region/padding + compute_configure_validate(shape, DataType::U8, DataType::S16, policy, shift); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute function + Tensor dst = compute_depth_convert(shape, DataType::U8, DataType::S16, policy, shift); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::U8, DataType::S16, policy, shift); + + // Validate output + validate(Accessor(dst), ref_dst); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute function + Tensor dst = compute_depth_convert(shape, DataType::U8, DataType::S16, policy, shift); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::U8, DataType::S16, policy, shift); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(U8_to_S32) +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({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute configure and validate region/padding + compute_configure_validate(shape, DataType::U8, DataType::S32, policy, shift); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute function + Tensor dst = compute_depth_convert(shape, DataType::U8, DataType::S32, policy, shift); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::U8, DataType::S32, policy, shift); + + // Validate output + validate(Accessor(dst), ref_dst); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute function + Tensor dst = compute_depth_convert(shape, DataType::U8, DataType::S32, policy, shift); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::U8, DataType::S32, policy, shift); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(U16_to_U8) +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({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute configure and validate region/padding + compute_configure_validate(shape, DataType::U16, DataType::U8, policy, shift); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute function + Tensor dst = compute_depth_convert(shape, DataType::U16, DataType::U8, policy, shift); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::U16, DataType::U8, policy, shift); + + // Validate output + validate(Accessor(dst), ref_dst); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute function + Tensor dst = compute_depth_convert(shape, DataType::U16, DataType::U8, policy, shift); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::U16, DataType::U8, policy, shift); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(U16_to_U32) +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({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute configure and validate region/padding + compute_configure_validate(shape, DataType::U16, DataType::U32, policy, shift); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute function + Tensor dst = compute_depth_convert(shape, DataType::U16, DataType::U32, policy, shift); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::U16, DataType::U32, policy, shift); + + // Validate output + validate(Accessor(dst), ref_dst); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute function + Tensor dst = compute_depth_convert(shape, DataType::U16, DataType::U32, policy, shift); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::U16, DataType::U32, policy, shift); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(S16_to_U8) +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({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute configure and validate region/padding + compute_configure_validate(shape, DataType::S16, DataType::U8, policy, shift); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute function + Tensor dst = compute_depth_convert(shape, DataType::S16, DataType::U8, policy, shift); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::S16, DataType::U8, policy, shift); + + // Validate output + validate(Accessor(dst), ref_dst); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute function + Tensor dst = compute_depth_convert(shape, DataType::S16, DataType::U8, policy, shift); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::S16, DataType::U8, policy, shift); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(S16_to_S32) +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({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute configure and validate region/padding + compute_configure_validate(shape, DataType::S16, DataType::S32, policy, shift); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute function + Tensor dst = compute_depth_convert(shape, DataType::S16, DataType::S32, policy, shift); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::S16, DataType::S32, policy, shift); + + // Validate output + validate(Accessor(dst), ref_dst); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * boost::unit_test::data::make({ ConvertPolicy::SATURATE, ConvertPolicy::WRAP }) + * boost::unit_test::data::xrange(0, 7, 1), + shape, policy, shift) +{ + // Compute function + Tensor dst = compute_depth_convert(shape, DataType::S16, DataType::S32, policy, shift); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_depth_convert(shape, DataType::S16, DataType::S32, policy, shift); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/NEON/FillBorder.cpp b/tests/validation_old/NEON/FillBorder.cpp new file mode 100644 index 0000000000..ad703d97fb --- /dev/null +++ b/tests/validation_old/NEON/FillBorder.cpp @@ -0,0 +1,88 @@ +/* + * 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 "NEON/Accessor.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Validation.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/NEON/kernels/NEFillBorderKernel.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(NEON) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(FillBorder, BorderModes() * boost::unit_test::data::make({ PaddingSize{ 0 }, PaddingSize{ 1, 0, 1, 2 }, PaddingSize{ 10 } }), border_mode, padding) +{ + constexpr uint8_t border_value = 42U; + constexpr uint8_t tensor_value = 89U; + BorderSize border_size{ 5 }; + + // Create tensors + Tensor src = create_tensor<Tensor>(TensorShape{ 10U, 10U, 2U }, DataType::U8); + + src.info()->extend_padding(padding); + + // Allocate tensor + src.allocator()->allocate(); + + // Check padding is as required + validate(src.info()->padding(), padding); + + // Fill tensor with constant value + std::uniform_int_distribution<uint8_t> distribution{ tensor_value, tensor_value }; + library->fill(Accessor(src), distribution, 0); + + // Create and configure kernel + NEFillBorderKernel fill_border; + fill_border.configure(&src, border_size, border_mode, border_value); + + // Run kernel + fill_border.run(fill_border.window()); + + // Validate border + border_size.limit(padding); + validate(Accessor(src), border_size, border_mode, &border_value); + + // Validate tensor + validate(Accessor(src), &tensor_value); +} + +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/NEON/Fixedpoint/Exp_QS16.cpp b/tests/validation_old/NEON/Fixedpoint/Exp_QS16.cpp new file mode 100644 index 0000000000..66115879aa --- /dev/null +++ b/tests/validation_old/NEON/Fixedpoint/Exp_QS16.cpp @@ -0,0 +1,122 @@ +/* + * 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 "NEON/Accessor.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/ReferenceCPP.h" +#include "tests/validation_old/Validation.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/NEON/NEFixedPoint.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +const float tolerance = 1.0f; /**< Tolerance value for comparing reference's output against implementation's output */ + +/** Compute Neon exponential function for signed 16 bit fixed point. + * + * @param[in] shape Shape of the input and output tensors. + * + * @return Computed output tensor. + */ +Tensor compute_exp_qs16(const TensorShape &shape, int fixed_point_position) +{ + // Create tensors + Tensor src = create_tensor<Tensor>(shape, DataType::QS16, 1, fixed_point_position); + Tensor dst = create_tensor<Tensor>(shape, DataType::QS16, 1, fixed_point_position); + + constexpr unsigned int num_elems_processed_per_iteration = 8; + Window window = calculate_max_window(*src.info(), Steps(num_elems_processed_per_iteration)); + AccessWindowHorizontal input_access(src.info(), 0, num_elems_processed_per_iteration); + AccessWindowHorizontal output_access(dst.info(), 0, num_elems_processed_per_iteration); + + update_window_and_padding(window, input_access, output_access); + output_access.set_valid_region(window, src.info()->valid_region()); + + // Allocate tensors + src.allocator()->allocate(); + dst.allocator()->allocate(); + + BOOST_TEST(!src.info()->is_resizable()); + BOOST_TEST(!dst.info()->is_resizable()); + + // Fill tensors. Keep the range between [-1.0, 1.0) so the result won't + // overflow. + std::uniform_int_distribution<> distribution(-(1 << (fixed_point_position - 1)), (1 << (fixed_point_position - 1))); + library->fill(Accessor(src), distribution, 0); + + Iterator input(&src, window); + Iterator output(&dst, window); + + execute_window_loop(window, [&](const Coordinates & id) + { + qint16x8_t in = vld1q_qs16(reinterpret_cast<const qint16_t *>(input.ptr())); + // Use saturated exp + vst1q_qs16(reinterpret_cast<qint16_t *>(output.ptr()), vqexpq_qs16(in, fixed_point_position)); + }, + input, output); + + return dst; +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(NEON) +BOOST_AUTO_TEST_SUITE(FixedPoint) +BOOST_AUTO_TEST_SUITE(QS16) +BOOST_AUTO_TEST_SUITE(Exp) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunSmall, Small1DShape() * boost::unit_test::data::xrange(1, 15), shape, fixed_point_position) +{ + // Compute function + Tensor dst = compute_exp_qs16(shape, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_fixed_point_operation(shape, DataType::QS16, DataType::QS16, FixedPointOp::EXP, fixed_point_position); + + // Validate output + validate(Accessor(dst), ref_dst, tolerance, 0); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/NEON/Fixedpoint/Exp_QS8.cpp b/tests/validation_old/NEON/Fixedpoint/Exp_QS8.cpp new file mode 100644 index 0000000000..9e8096fa75 --- /dev/null +++ b/tests/validation_old/NEON/Fixedpoint/Exp_QS8.cpp @@ -0,0 +1,122 @@ +/* + * 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 "NEON/Accessor.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/ReferenceCPP.h" +#include "tests/validation_old/Validation.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/NEON/NEFixedPoint.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +const float tolerance = 0.0f; /**< Tolerance value for comparing reference's output against implementation's output */ + +/** Compute Neon exponential function for signed 8bit fixed point. + * + * @param[in] shape Shape of the input and output tensors. + * + * @return Computed output tensor. + */ +Tensor compute_exp_qs8(const TensorShape &shape, int fixed_point_position) +{ + // Create tensors + Tensor src = create_tensor<Tensor>(shape, DataType::QS8, 1, fixed_point_position); + Tensor dst = create_tensor<Tensor>(shape, DataType::QS8, 1, fixed_point_position); + + constexpr unsigned int num_elems_processed_per_iteration = 16; + Window window = calculate_max_window(*src.info(), Steps(num_elems_processed_per_iteration)); + AccessWindowHorizontal input_access(src.info(), 0, num_elems_processed_per_iteration); + AccessWindowHorizontal output_access(dst.info(), 0, num_elems_processed_per_iteration); + + update_window_and_padding(window, input_access, output_access); + output_access.set_valid_region(window, src.info()->valid_region()); + + // Allocate tensors + src.allocator()->allocate(); + dst.allocator()->allocate(); + + BOOST_TEST(!src.info()->is_resizable()); + BOOST_TEST(!dst.info()->is_resizable()); + + // Fill tensors. Keep the range between [-1.0, 1.0) so the result won't + // overflow. E.g. e^7 = 1096, which cannot be represented in QS8 + std::uniform_int_distribution<> distribution(-(1 << (fixed_point_position - 1)), (1 << (fixed_point_position - 1))); + library->fill(Accessor(src), distribution, 0); + + Iterator input(&src, window); + Iterator output(&dst, window); + + execute_window_loop(window, [&](const Coordinates & id) + { + qint8x16_t in = vld1q_s8(reinterpret_cast<const qint8_t *>(input.ptr())); + // Use saturated exp + vst1q_s8(reinterpret_cast<qint8_t *>(output.ptr()), vqexpq_qs8(in, fixed_point_position)); + }, + input, output); + + return dst; +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(NEON) +BOOST_AUTO_TEST_SUITE(FixedPoint) +BOOST_AUTO_TEST_SUITE(QS8) +BOOST_AUTO_TEST_SUITE(Exp) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunSmall, Small1DShape() * boost::unit_test::data::xrange(1, 7), shape, fixed_point_position) +{ + // Compute function + Tensor dst = compute_exp_qs8(shape, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_fixed_point_operation(shape, DataType::QS8, DataType::QS8, FixedPointOp::EXP, fixed_point_position); + + // Validate output + validate(Accessor(dst), ref_dst, tolerance, 0); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/NEON/Fixedpoint/Invsqrt_QS16.cpp b/tests/validation_old/NEON/Fixedpoint/Invsqrt_QS16.cpp new file mode 100644 index 0000000000..f56707a93d --- /dev/null +++ b/tests/validation_old/NEON/Fixedpoint/Invsqrt_QS16.cpp @@ -0,0 +1,122 @@ +/* + * 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 "NEON/Accessor.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/ReferenceCPP.h" +#include "tests/validation_old/Validation.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/NEON/NEFixedPoint.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +const float tolerance = 5.0f; /**< Tolerance value for comparing reference's output against implementation's output */ + +/** Compute Neon inverse square root function for signed 16 bit fixed point. + * + * @param[in] shape Shape of the input and output tensors. + * + * @return Computed output tensor. + */ +Tensor compute_invsqrt_qs16(const TensorShape &shape, int fixed_point_position) +{ + // Create tensors + Tensor src = create_tensor<Tensor>(shape, DataType::QS16, 1, fixed_point_position); + Tensor dst = create_tensor<Tensor>(shape, DataType::QS16, 1, fixed_point_position); + + constexpr unsigned int num_elems_processed_per_iteration = 8; + Window window = calculate_max_window(*src.info(), Steps(num_elems_processed_per_iteration)); + AccessWindowHorizontal input_access(src.info(), 0, num_elems_processed_per_iteration); + AccessWindowHorizontal output_access(dst.info(), 0, num_elems_processed_per_iteration); + + update_window_and_padding(window, input_access, output_access); + output_access.set_valid_region(window, src.info()->valid_region()); + + // Allocate tensors + src.allocator()->allocate(); + dst.allocator()->allocate(); + + BOOST_TEST(!src.info()->is_resizable()); + BOOST_TEST(!dst.info()->is_resizable()); + + // Fill tensors. Keep the range between [1, 0x7FFF) + std::uniform_int_distribution<> distribution(1, 0x7FFF); + library->fill(Accessor(src), distribution, 0); + + Iterator input(&src, window); + Iterator output(&dst, window); + + execute_window_loop(window, [&](const Coordinates & id) + { + qint16x8_t in = vld1q_qs16(reinterpret_cast<const qint16_t *>(input.ptr())); + vst1q_qs16(reinterpret_cast<qint16_t *>(output.ptr()), vqinvsqrtq_qs16(in, fixed_point_position)); + }, + input, output); + + return dst; +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(NEON) +BOOST_AUTO_TEST_SUITE(FixedPoint) +BOOST_AUTO_TEST_SUITE(QS16) +BOOST_AUTO_TEST_SUITE(Invsqrt) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunSmall, boost::unit_test::data::xrange(1, 14), fixed_point_position) +{ + TensorShape shape(8192U); + + // Compute function + Tensor dst = compute_invsqrt_qs16(shape, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_fixed_point_operation(shape, DataType::QS16, DataType::QS16, FixedPointOp::INV_SQRT, fixed_point_position); + + // Validate output + validate(Accessor(dst), ref_dst, tolerance, 0); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/NEON/Fixedpoint/Invsqrt_QS8.cpp b/tests/validation_old/NEON/Fixedpoint/Invsqrt_QS8.cpp new file mode 100644 index 0000000000..fb33fd4632 --- /dev/null +++ b/tests/validation_old/NEON/Fixedpoint/Invsqrt_QS8.cpp @@ -0,0 +1,120 @@ +/* + * 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 "NEON/Accessor.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/ReferenceCPP.h" +#include "tests/validation_old/Validation.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/NEON/NEFixedPoint.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +const float tolerance = 4.0f; /**< Tolerance value for comparing reference's output against implementation's output */ + +/** Compute Neon inverse square root function for signed 8bit fixed point. + * + * @param[in] shape Shape of the input and output tensors. + * + * @return Computed output tensor. + */ +Tensor compute_invsqrt_qs8(const TensorShape &shape, int fixed_point_position) +{ + // Create tensors + Tensor src = create_tensor<Tensor>(shape, DataType::QS8, 1, fixed_point_position); + Tensor dst = create_tensor<Tensor>(shape, DataType::QS8, 1, fixed_point_position); + + constexpr unsigned int num_elems_processed_per_iteration = 16; + Window window = calculate_max_window(*src.info(), Steps(num_elems_processed_per_iteration)); + AccessWindowHorizontal input_access(src.info(), 0, num_elems_processed_per_iteration); + AccessWindowHorizontal output_access(dst.info(), 0, num_elems_processed_per_iteration); + + update_window_and_padding(window, input_access, output_access); + output_access.set_valid_region(window, src.info()->valid_region()); + + // Allocate tensors + src.allocator()->allocate(); + dst.allocator()->allocate(); + + BOOST_TEST(!src.info()->is_resizable()); + BOOST_TEST(!dst.info()->is_resizable()); + + // Fill tensors. Keep the range between [1, 127). + std::uniform_int_distribution<> distribution(1, 127); + library->fill(Accessor(src), distribution, 0); + + Iterator input(&src, window); + Iterator output(&dst, window); + + execute_window_loop(window, [&](const Coordinates & id) + { + qint8x16_t in = vld1q_s8(reinterpret_cast<const qint8_t *>(input.ptr())); + vst1q_s8(reinterpret_cast<qint8_t *>(output.ptr()), vqinvsqrtq_qs8(in, fixed_point_position)); + }, + input, output); + + return dst; +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(NEON) +BOOST_AUTO_TEST_SUITE(FixedPoint) +BOOST_AUTO_TEST_SUITE(QS8) +BOOST_AUTO_TEST_SUITE(Invsqrt) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(Small1DShape, SmallShapes() * boost::unit_test::data::xrange(1, 6), shape, fixed_point_position) +{ + // Compute function + Tensor dst = compute_invsqrt_qs8(shape, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_fixed_point_operation(shape, DataType::QS8, DataType::QS8, FixedPointOp::INV_SQRT, fixed_point_position); + + // Validate output + validate(Accessor(dst), ref_dst, tolerance, 0); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/NEON/Fixedpoint/Log_QS16.cpp b/tests/validation_old/NEON/Fixedpoint/Log_QS16.cpp new file mode 100644 index 0000000000..6485b2031c --- /dev/null +++ b/tests/validation_old/NEON/Fixedpoint/Log_QS16.cpp @@ -0,0 +1,121 @@ +/* + * 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 "NEON/Accessor.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/ReferenceCPP.h" +#include "tests/validation_old/Validation.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/NEON/NEFixedPoint.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +const float tolerance = 7.0f; /**< Tolerance value for comparing reference's output against implementation's output */ + +/** Compute Neon logarithm function for signed 16 bit fixed point. + * + * @param[in] shape Shape of the input and output tensors. + * + * @return Computed output tensor. + */ +Tensor compute_log_qs16(const TensorShape &shape, int fixed_point_position) +{ + // Create tensors + Tensor src = create_tensor<Tensor>(shape, DataType::QS16, 1, fixed_point_position); + Tensor dst = create_tensor<Tensor>(shape, DataType::QS16, 1, fixed_point_position); + + constexpr unsigned int num_elems_processed_per_iteration = 8; + Window window = calculate_max_window(*src.info(), Steps(num_elems_processed_per_iteration)); + AccessWindowHorizontal input_access(src.info(), 0, num_elems_processed_per_iteration); + AccessWindowHorizontal output_access(dst.info(), 0, num_elems_processed_per_iteration); + + update_window_and_padding(window, input_access, output_access); + output_access.set_valid_region(window, src.info()->valid_region()); + + // Allocate tensors + src.allocator()->allocate(); + dst.allocator()->allocate(); + + BOOST_TEST(!src.info()->is_resizable()); + BOOST_TEST(!dst.info()->is_resizable()); + + // Fill tensors. Keep the range between [(1 << (fixed_point_position - 1), 0x3FFF) so the result won't + // overflow. + std::uniform_int_distribution<> distribution((1 << (fixed_point_position - 1)), 0x3FFF); + library->fill(Accessor(src), distribution, 0); + + Iterator input(&src, window); + Iterator output(&dst, window); + + execute_window_loop(window, [&](const Coordinates & id) + { + qint16x8_t in = vld1q_qs16(reinterpret_cast<const qint16_t *>(input.ptr())); + vst1q_qs16(reinterpret_cast<qint16_t *>(output.ptr()), vlogq_qs16(in, fixed_point_position)); + }, + input, output); + + return dst; +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(NEON) +BOOST_AUTO_TEST_SUITE(FixedPoint) +BOOST_AUTO_TEST_SUITE(QS16) +BOOST_AUTO_TEST_SUITE(Log) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunSmall, Small1DShape() * boost::unit_test::data::xrange(4, 14), shape, fixed_point_position) +{ + // Compute function + Tensor dst = compute_log_qs16(shape, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_fixed_point_operation(shape, DataType::QS16, DataType::QS16, FixedPointOp::LOG, fixed_point_position); + + // Validate output + validate(Accessor(dst), ref_dst, tolerance, 0); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/NEON/Fixedpoint/Log_QS8.cpp b/tests/validation_old/NEON/Fixedpoint/Log_QS8.cpp new file mode 100644 index 0000000000..21012c52b0 --- /dev/null +++ b/tests/validation_old/NEON/Fixedpoint/Log_QS8.cpp @@ -0,0 +1,121 @@ +/* + * 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 "NEON/Accessor.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/ReferenceCPP.h" +#include "tests/validation_old/Validation.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/NEON/NEFixedPoint.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +const float tolerance = 5; /**< Tolerance value for comparing reference's output against implementation's output */ + +/** Compute Neon logarithm function for signed 8bit fixed point. + * + * @param[in] shape Shape of the input and output tensors. + * + * @return Computed output tensor. + */ +Tensor compute_log_qs8(const TensorShape &shape, int fixed_point_position) +{ + // Create tensors + Tensor src = create_tensor<Tensor>(shape, DataType::QS8, 1, fixed_point_position); + Tensor dst = create_tensor<Tensor>(shape, DataType::QS8, 1, fixed_point_position); + + constexpr unsigned int num_elems_processed_per_iteration = 16; + Window window = calculate_max_window(*src.info(), Steps(num_elems_processed_per_iteration)); + AccessWindowHorizontal input_access(src.info(), 0, num_elems_processed_per_iteration); + AccessWindowHorizontal output_access(dst.info(), 0, num_elems_processed_per_iteration); + + update_window_and_padding(window, input_access, output_access); + output_access.set_valid_region(window, src.info()->valid_region()); + + // Allocate tensors + src.allocator()->allocate(); + dst.allocator()->allocate(); + + BOOST_TEST(!src.info()->is_resizable()); + BOOST_TEST(!dst.info()->is_resizable()); + + // Fill tensors. Keep the range between [(1 << (fixed_point_position - 1), 63) so the result won't + // overflow. E.g. for Q2.5 ln(0.001) = -6.9, which cannot be represented. + std::uniform_int_distribution<> distribution((1 << (fixed_point_position - 1)), 0x3F); + library->fill(Accessor(src), distribution, 0); + + Iterator input(&src, window); + Iterator output(&dst, window); + + execute_window_loop(window, [&](const Coordinates & id) + { + qint8x16_t in = vld1q_s8(reinterpret_cast<const qint8_t *>(input.ptr())); + vst1q_s8(reinterpret_cast<qint8_t *>(output.ptr()), vlogq_qs8(in, fixed_point_position)); + }, + input, output); + + return dst; +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(NEON) +BOOST_AUTO_TEST_SUITE(FixedPoint) +BOOST_AUTO_TEST_SUITE(QS8) +BOOST_AUTO_TEST_SUITE(Log) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunSmall, Small1DShape() * boost::unit_test::data::xrange(3, 6), shape, fixed_point_position) +{ + // Compute function + Tensor dst = compute_log_qs8(shape, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_fixed_point_operation(shape, DataType::QS8, DataType::QS8, FixedPointOp::LOG, fixed_point_position); + + // Validate output + validate(Accessor(dst), ref_dst, tolerance, 0); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/NEON/Fixedpoint/Reciprocal_QS16.cpp b/tests/validation_old/NEON/Fixedpoint/Reciprocal_QS16.cpp new file mode 100644 index 0000000000..5630a3391a --- /dev/null +++ b/tests/validation_old/NEON/Fixedpoint/Reciprocal_QS16.cpp @@ -0,0 +1,121 @@ +/* + * 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 "NEON/Accessor.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/ReferenceCPP.h" +#include "tests/validation_old/Validation.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/NEON/NEFixedPoint.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +const float tolerance = 11.0f; /**< Tolerance value for comparing reference's output against implementation's output. */ + +/** Compute Neon reciprocal function for signed 16 bit fixed point. + * + * @param[in] shape Shape of the input and output tensors. + * + * @return Computed output tensor. + */ +Tensor compute_reciprocal_qs16(const TensorShape &shape, int fixed_point_position) +{ + // Create tensors + Tensor src = create_tensor<Tensor>(shape, DataType::QS16, 1, fixed_point_position); + Tensor dst = create_tensor<Tensor>(shape, DataType::QS16, 1, fixed_point_position); + + constexpr unsigned int num_elems_processed_per_iteration = 8; + Window window = calculate_max_window(*src.info(), Steps(num_elems_processed_per_iteration)); + AccessWindowHorizontal input_access(src.info(), 0, num_elems_processed_per_iteration); + AccessWindowHorizontal output_access(dst.info(), 0, num_elems_processed_per_iteration); + + update_window_and_padding(window, input_access, output_access); + output_access.set_valid_region(window, src.info()->valid_region()); + + // Allocate tensors + src.allocator()->allocate(); + dst.allocator()->allocate(); + + BOOST_TEST(!src.info()->is_resizable()); + BOOST_TEST(!dst.info()->is_resizable()); + + // Fill tensors. Keep the range between [15, 0x7FFF) so the result won't + // overflow. + std::uniform_int_distribution<> distribution(15, 0x7FFF); + library->fill(Accessor(src), distribution, 0); + + Iterator input(&src, window); + Iterator output(&dst, window); + + execute_window_loop(window, [&](const Coordinates & id) + { + qint16x8_t in = vld1q_qs16(reinterpret_cast<const qint16_t *>(input.ptr())); + vst1q_qs16(reinterpret_cast<qint16_t *>(output.ptr()), vqrecipq_qs16(in, fixed_point_position)); + }, + input, output); + + return dst; +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(NEON) +BOOST_AUTO_TEST_SUITE(FixedPoint) +BOOST_AUTO_TEST_SUITE(QS16) +BOOST_AUTO_TEST_SUITE(Reciprocal) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunSmall, Small1DShape() * boost::unit_test::data::xrange(1, 14), shape, fixed_point_position) +{ + // Compute function + Tensor dst = compute_reciprocal_qs16(shape, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_fixed_point_operation(shape, DataType::QS16, DataType::QS16, FixedPointOp::RECIPROCAL, fixed_point_position); + + // Validate output + validate(Accessor(dst), ref_dst, tolerance, 0); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/NEON/Fixedpoint/Reciprocal_QS8.cpp b/tests/validation_old/NEON/Fixedpoint/Reciprocal_QS8.cpp new file mode 100644 index 0000000000..23f98acc40 --- /dev/null +++ b/tests/validation_old/NEON/Fixedpoint/Reciprocal_QS8.cpp @@ -0,0 +1,121 @@ +/* + * 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 "NEON/Accessor.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/ReferenceCPP.h" +#include "tests/validation_old/Validation.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/NEON/NEFixedPoint.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +const float tolerance = 3; /**< Tolerance value for comparing reference's output against implementation's output */ + +/** Compute Neon reciprocal function for signed 8bit fixed point. + * + * @param[in] shape Shape of the input and output tensors. + * + * @return Computed output tensor. + */ +Tensor compute_reciprocal_qs8(const TensorShape &shape, int fixed_point_position) +{ + // Create tensors + Tensor src = create_tensor<Tensor>(shape, DataType::QS8, 1, fixed_point_position); + Tensor dst = create_tensor<Tensor>(shape, DataType::QS8, 1, fixed_point_position); + + constexpr unsigned int num_elems_processed_per_iteration = 16; + Window window = calculate_max_window(*src.info(), Steps(num_elems_processed_per_iteration)); + AccessWindowHorizontal input_access(src.info(), 0, num_elems_processed_per_iteration); + AccessWindowHorizontal output_access(dst.info(), 0, num_elems_processed_per_iteration); + + update_window_and_padding(window, input_access, output_access); + output_access.set_valid_region(window, src.info()->valid_region()); + + // Allocate tensors + src.allocator()->allocate(); + dst.allocator()->allocate(); + + BOOST_TEST(!src.info()->is_resizable()); + BOOST_TEST(!dst.info()->is_resizable()); + + // Fill tensors. Keep the range between [15, 100) so the result won't + // overflow. E.g. for Q2.5 reciprocal(0.001) = 1000, which cannot be represented. + std::uniform_int_distribution<> distribution(15, 0x7F); + library->fill(Accessor(src), distribution, 0); + + Iterator input(&src, window); + Iterator output(&dst, window); + + execute_window_loop(window, [&](const Coordinates & id) + { + qint8x16_t in = vld1q_s8(reinterpret_cast<const qint8_t *>(input.ptr())); + vst1q_s8(reinterpret_cast<qint8_t *>(output.ptr()), vrecipq_qs8(in, fixed_point_position)); + }, + input, output); + + return dst; +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(NEON) +BOOST_AUTO_TEST_SUITE(FixedPoint) +BOOST_AUTO_TEST_SUITE(QS8) +BOOST_AUTO_TEST_SUITE(Reciprocal) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunSmall, Small1DShape() * boost::unit_test::data::xrange(1, 6), shape, fixed_point_position) +{ + // Compute function + Tensor dst = compute_reciprocal_qs8(shape, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_fixed_point_operation(shape, DataType::QS8, DataType::QS8, FixedPointOp::RECIPROCAL, fixed_point_position); + + // Validate output + validate(Accessor(dst), ref_dst, tolerance, 0); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/NEON/Gaussian3x3.cpp b/tests/validation_old/NEON/Gaussian3x3.cpp new file mode 100644 index 0000000000..becd9196ea --- /dev/null +++ b/tests/validation_old/NEON/Gaussian3x3.cpp @@ -0,0 +1,167 @@ +/* + * 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 "NEON/Accessor.h" +#include "PaddingCalculator.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" +#include "tests/validation_old/ValidationUserConfiguration.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/NEON/functions/NEGaussian3x3.h" +#include "arm_compute/runtime/SubTensor.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +constexpr unsigned int filter_size = 3; /** Size of the kernel/filter in number of elements. */ +constexpr BorderSize border_size(filter_size / 2); /** Border size of the kernel/filter around its central element. */ + +/** Compute Neon gaussian3x3 filter. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] border_mode BorderMode used by the input tensor. + * @param[in] constant_border_value Constant to use if @p border_mode == CONSTANT. + * + * @return Computed output tensor. + */ +Tensor compute_gaussian3x3(const TensorShape &shape, BorderMode border_mode, uint8_t constant_border_value) +{ + // Create tensors + Tensor src = create_tensor<Tensor>(shape, DataType::U8); + Tensor dst = create_tensor<Tensor>(shape, DataType::U8); + + // Create and configure function + NEGaussian3x3 gaussian3x3; + gaussian3x3.configure(&src, &dst, border_mode, constant_border_value); + + // 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(Accessor(src), 0); + + // Compute function + gaussian3x3.run(); + + return dst; +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(NEON) +BOOST_AUTO_TEST_SUITE(Gaussian3x3) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(Configuration, (SmallShapes() + LargeShapes()) * BorderModes(), shape, border_mode) +{ + // Create tensors + Tensor src = create_tensor<Tensor>(shape, DataType::U8); + Tensor dst = create_tensor<Tensor>(shape, DataType::U8); + + BOOST_TEST(src.info()->is_resizable()); + BOOST_TEST(dst.info()->is_resizable()); + + // Create and configure function + NEGaussian3x3 gaussian3x3; + gaussian3x3.configure(&src, &dst, border_mode); + + // Validate valid region + const ValidRegion src_valid_region = shape_to_valid_region(shape); + const ValidRegion dst_valid_region = shape_to_valid_region(shape, border_mode == BorderMode::UNDEFINED, border_size); + validate(src.info()->valid_region(), src_valid_region); + validate(dst.info()->valid_region(), dst_valid_region); + + // Validate padding + PaddingCalculator calculator(shape.x(), 8); + calculator.set_border_size(1); + calculator.set_border_mode(border_mode); + + const PaddingSize dst_padding = calculator.required_padding(); + + calculator.set_accessed_elements(16); + calculator.set_access_offset(-1); + + const PaddingSize src_padding = calculator.required_padding(); + + validate(src.info()->padding(), src_padding); + validate(dst.info()->padding(), dst_padding); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * BorderModes(), shape, border_mode) +{ + std::mt19937 gen(user_config.seed.get()); + std::uniform_int_distribution<uint8_t> distribution(0, 255); + const uint8_t border_value = distribution(gen); + + // Compute function + Tensor dst = compute_gaussian3x3(shape, border_mode, border_value); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_gaussian3x3(shape, border_mode, border_value); + + // Validate output + validate(Accessor(dst), ref_dst, shape_to_valid_region(shape, border_mode == BorderMode::UNDEFINED, border_size)); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * BorderModes(), shape, border_mode) +{ + std::mt19937 gen(user_config.seed.get()); + std::uniform_int_distribution<uint8_t> distribution(0, 255); + const uint8_t border_value = distribution(gen); + + // Compute function + Tensor dst = compute_gaussian3x3(shape, border_mode, border_value); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_gaussian3x3(shape, border_mode, border_value); + + // Validate output + validate(Accessor(dst), ref_dst, shape_to_valid_region(shape, border_mode == BorderMode::UNDEFINED, border_size)); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/NEON/Gaussian5x5.cpp b/tests/validation_old/NEON/Gaussian5x5.cpp new file mode 100644 index 0000000000..240285afb6 --- /dev/null +++ b/tests/validation_old/NEON/Gaussian5x5.cpp @@ -0,0 +1,167 @@ +/* + * 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 "NEON/Accessor.h" +#include "PaddingCalculator.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" +#include "tests/validation_old/ValidationUserConfiguration.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/NEON/functions/NEGaussian5x5.h" +#include "arm_compute/runtime/SubTensor.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +constexpr unsigned int filter_size = 5; /** Size of the kernel/filter in number of elements. */ +constexpr BorderSize border_size(filter_size / 2); /** Border size of the kernel/filter around its central element. */ + +/** Compute Neon gaussian5x5 filter. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] border_mode BorderMode used by the input tensor. + * @param[in] constant_border_value Constant to use if @p border_mode == CONSTANT. + * + * @return Computed output tensor. + */ +Tensor compute_gaussian5x5(const TensorShape &shape, BorderMode border_mode, uint8_t constant_border_value) +{ + // Create tensors + Tensor src = create_tensor<Tensor>(shape, DataType::U8); + Tensor dst = create_tensor<Tensor>(shape, DataType::U8); + + // Create and configure function + NEGaussian5x5 gaussian5x5; + gaussian5x5.configure(&src, &dst, border_mode, constant_border_value); + + // 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(Accessor(src), 0); + + // Compute function + gaussian5x5.run(); + + return dst; +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(NEON) +BOOST_AUTO_TEST_SUITE(Gaussian5x5) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(Configuration, (SmallShapes() + LargeShapes()) * BorderModes(), shape, border_mode) +{ + // Create tensors + Tensor src = create_tensor<Tensor>(shape, DataType::U8); + Tensor dst = create_tensor<Tensor>(shape, DataType::U8); + + BOOST_TEST(src.info()->is_resizable()); + BOOST_TEST(dst.info()->is_resizable()); + + // Create and configure function + NEGaussian5x5 gaussian5x5; + gaussian5x5.configure(&src, &dst, border_mode); + + // Validate valid region + const ValidRegion src_valid_region = shape_to_valid_region(shape); + const ValidRegion dst_valid_region = shape_to_valid_region(shape, border_mode == BorderMode::UNDEFINED, border_size); + validate(src.info()->valid_region(), src_valid_region); + validate(dst.info()->valid_region(), dst_valid_region); + + // Validate padding + PaddingCalculator calculator(shape.x(), 16); + calculator.set_border_size(2); + calculator.set_border_mode(border_mode); + + const PaddingSize dst_padding = calculator.required_padding(); + + calculator.set_processed_elements(8); + calculator.set_access_offset(-2); + + const PaddingSize src_padding = calculator.required_padding(); + + validate(src.info()->padding(), src_padding); + validate(dst.info()->padding(), dst_padding); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * BorderModes(), shape, border_mode) +{ + std::mt19937 gen(user_config.seed.get()); + std::uniform_int_distribution<uint8_t> distribution(0, 255); + const uint8_t border_value = distribution(gen); + + // Compute function + Tensor dst = compute_gaussian5x5(shape, border_mode, border_value); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_gaussian5x5(shape, border_mode, border_value); + + // Validate output + validate(Accessor(dst), ref_dst, shape_to_valid_region(shape, border_mode == BorderMode::UNDEFINED, border_size)); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * BorderModes(), shape, border_mode) +{ + std::mt19937 gen(user_config.seed.get()); + std::uniform_int_distribution<uint8_t> distribution(0, 255); + const uint8_t border_value = distribution(gen); + + // Compute function + Tensor dst = compute_gaussian5x5(shape, border_mode, border_value); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_gaussian5x5(shape, border_mode, border_value); + + // Validate output + validate(Accessor(dst), ref_dst, shape_to_valid_region(shape, border_mode == BorderMode::UNDEFINED, border_size)); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/NEON/HarrisCorners.cpp b/tests/validation_old/NEON/HarrisCorners.cpp new file mode 100644 index 0000000000..809e61c053 --- /dev/null +++ b/tests/validation_old/NEON/HarrisCorners.cpp @@ -0,0 +1,229 @@ +/* + * 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 "NEON/Accessor.h" +#include "NEON/Helper.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" +#include "tests/validation_old/ValidationUserConfiguration.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/NEON/functions/NEHarrisCorners.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include "PaddingCalculator.h" +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +/** Compute Neon Harris corners function. + * + * @param[in] shape Shape of input tensor + * @param[in] threshold Minimum threshold with which to eliminate Harris Corner scores (computed using the normalized Sobel kernel). + * @param[in] min_dist Radial Euclidean distance for the euclidean distance stage + * @param[in] sensitivity Sensitivity threshold k from the Harris-Stephens equation + * @param[in] gradient_size The gradient window size to use on the input. The implementation supports 3, 5, and 7 + * @param[in] block_size The block window size used to compute the Harris Corner score. The implementation supports 3, 5, and 7. + * @param[in] border_mode Border mode to use + * @param[in] constant_border_value Constant value to use for borders if border_mode is set to CONSTANT. + * @param[in] use_fp16 If true the FP16 kernels will be used. If false F32 kernels are used. + * + * @return Computed corners' keypoints. + */ +KeyPointArray compute_harris_corners(const TensorShape &shape, float threshold, float min_dist, float sensitivity, + int32_t gradient_size, int32_t block_size, BorderMode border_mode, uint8_t constant_border_value, bool use_fp16) +{ + // Create tensors + Tensor src = create_tensor<Tensor>(shape, DataType::U8); + src.info()->set_format(Format::U8); + + // Create array of keypoints + KeyPointArray corners(shape.total_size()); + + // Create harris corners configure function + NEHarrisCorners harris_corners; + harris_corners.configure(&src, threshold, min_dist, sensitivity, gradient_size, block_size, &corners, border_mode, constant_border_value, use_fp16); + + // Allocate tensors + src.allocator()->allocate(); + + BOOST_TEST(!src.info()->is_resizable()); + + // Fill tensors + library->fill_tensor_uniform(Accessor(src), 0); + + // Compute function + harris_corners.run(); + + return corners; +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(NEON) +BOOST_AUTO_TEST_SUITE(HarrisCorners) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(Configuration, (Small2DShapes() + Large2DShapes()) * BorderModes() + * boost::unit_test::data::make({ 3, 5, 7 }) * boost::unit_test::data::make({ 3, 5, 7 }), + shape, border_mode, gradient, block) +{ + // Create tensors + Tensor src = create_tensor<Tensor>(shape, DataType::U8); + src.info()->set_format(Format::U8); + + KeyPointArray corners; + + uint8_t constant_border_value = 0; + + std::mt19937 gen(user_config.seed.get()); + std::uniform_real_distribution<float> real_dist(0.01, std::numeric_limits<float>::min()); + + const float threshold = real_dist(gen); + const float sensitivity = real_dist(gen); + const float max_euclidean_distance = 30.f; + + real_dist = std::uniform_real_distribution<float>(0.f, max_euclidean_distance); + const float min_dist = real_dist(gen); + + // 50% chance to use fp16 + bool use_fp16 = real_dist(gen) < max_euclidean_distance / 2 ? true : false; + + // Generate a random constant value if border_mode is constant + if(border_mode == BorderMode::CONSTANT) + { + std::uniform_int_distribution<uint8_t> int_dist(0, 255); + constant_border_value = int_dist(gen); + } + + BOOST_TEST(src.info()->is_resizable()); + + // Create harris corners configure function + NEHarrisCorners harris_corners; + harris_corners.configure(&src, threshold, min_dist, sensitivity, gradient, block, &corners, border_mode, constant_border_value, use_fp16); + + // Validate valid region + const ValidRegion valid_region = shape_to_valid_region(shape); + + validate(src.info()->valid_region(), valid_region); + + // Validate padding + PaddingCalculator calculator(shape.x(), 8); + + calculator.set_border_mode(border_mode); + calculator.set_border_size(gradient / 2); + calculator.set_access_offset(-gradient / 2); + calculator.set_accessed_elements(16); + + const PaddingSize padding = calculator.required_padding(); + + validate(src.info()->padding(), padding); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, Small2DShapes() * BorderModes() * boost::unit_test::data::make({ 3, 5, 7 }) * boost::unit_test::data::make({ 3, 5, 7 }), shape, border_mode, gradient, block) +{ + uint8_t constant_border_value = 0; + + std::mt19937 gen(user_config.seed.get()); + std::uniform_real_distribution<float> real_dist(0.01, std::numeric_limits<float>::min()); + + const float threshold = real_dist(gen); + const float sensitivity = real_dist(gen); + const float max_euclidean_distance = 30.f; + + real_dist = std::uniform_real_distribution<float>(0.f, max_euclidean_distance); + const float min_dist = real_dist(gen); + + // 50% chance to use fp16 + bool use_fp16 = real_dist(gen) < max_euclidean_distance / 2 ? true : false; + + // Generate a random constant value if border_mode is constant + if(border_mode == BorderMode::CONSTANT) + { + std::uniform_int_distribution<uint8_t> int_dist(0, 255); + constant_border_value = int_dist(gen); + } + + // Compute function + KeyPointArray dst = compute_harris_corners(shape, threshold, min_dist, sensitivity, gradient, block, border_mode, constant_border_value, use_fp16); + + // Compute reference + KeyPointArray ref_dst = Reference::compute_reference_harris_corners(shape, threshold, min_dist, sensitivity, gradient, block, border_mode, constant_border_value); + + // Validate output + validate(dst, ref_dst); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, Large2DShapes() * BorderModes() * boost::unit_test::data::make({ 3, 5, 7 }) * boost::unit_test::data::make({ 3, 5, 7 }), shape, border_mode, gradient, block) +{ + uint8_t constant_border_value = 0; + + std::mt19937 gen(user_config.seed.get()); + std::uniform_real_distribution<float> real_dist(0.01, std::numeric_limits<float>::min()); + + const float threshold = real_dist(gen); + const float sensitivity = real_dist(gen); + const float max_euclidean_distance = 30.f; + + real_dist = std::uniform_real_distribution<float>(0.f, max_euclidean_distance); + float min_dist = real_dist(gen); + + // 50% chance to use fp16 + bool use_fp16 = real_dist(gen) < max_euclidean_distance / 2 ? true : false; + + // Generate a random constant value if border_mode is constant + if(border_mode == BorderMode::CONSTANT) + { + std::uniform_int_distribution<uint8_t> int_dist(0, 255); + constant_border_value = int_dist(gen); + } + + // Compute function + KeyPointArray dst = compute_harris_corners(shape, threshold, min_dist, sensitivity, gradient, block, border_mode, constant_border_value, use_fp16); + + // Compute reference + KeyPointArray ref_dst = Reference::compute_reference_harris_corners(shape, threshold, min_dist, sensitivity, gradient, block, border_mode, constant_border_value); + + // Validate output + validate(dst, ref_dst); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/NEON/IntegralImage.cpp b/tests/validation_old/NEON/IntegralImage.cpp new file mode 100644 index 0000000000..69654b2585 --- /dev/null +++ b/tests/validation_old/NEON/IntegralImage.cpp @@ -0,0 +1,144 @@ +/* + * 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 "NEON/Accessor.h" +#include "PaddingCalculator.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/NEON/functions/NEIntegralImage.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +/** Compute Neon integral image function. + * + * @param[in] shape Shape of the input and output tensors. + * + * @return Computed output tensor. + */ +Tensor compute_integral_image(const TensorShape &shape) +{ + // Create tensors + Tensor src = create_tensor<Tensor>(shape, DataType::U8); + Tensor dst = create_tensor<Tensor>(shape, DataType::U32); + + // Create integral image configure function + NEIntegralImage integral_image; + integral_image.configure(&src, &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(Accessor(src), 0); + + // Compute function + integral_image.run(); + + return dst; +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(NEON) +BOOST_AUTO_TEST_SUITE(IntegralImage) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(Configuration, SmallShapes() + LargeShapes(), shape) +{ + // Create tensors + Tensor src = create_tensor<Tensor>(shape, DataType::U8); + Tensor dst = create_tensor<Tensor>(shape, DataType::U32); + + BOOST_TEST(src.info()->is_resizable()); + BOOST_TEST(dst.info()->is_resizable()); + + // Create integral image configure function + NEIntegralImage integral_image; + integral_image.configure(&src, &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 src_padding = PaddingCalculator(shape.x(), 16).required_padding(); + const PaddingSize dst_padding(1, src_padding.right, 0, 1); + + validate(src.info()->padding(), src_padding); + validate(dst.info()->padding(), dst_padding); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes(), shape) +{ + // Compute function + Tensor dst = compute_integral_image(shape); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_integral_image(shape); + + // Validate output + validate(Accessor(dst), ref_dst); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes(), shape) +{ + // Compute function + Tensor dst = compute_integral_image(shape); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_integral_image(shape); + + // Validate output + validate(Accessor(dst), ref_dst); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/NEON/MinMaxLocation.cpp b/tests/validation_old/NEON/MinMaxLocation.cpp new file mode 100644 index 0000000000..c41745a636 --- /dev/null +++ b/tests/validation_old/NEON/MinMaxLocation.cpp @@ -0,0 +1,224 @@ +/* + * 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 "NEON/Accessor.h" +#include "NEON/Helper.h" +#include "PaddingCalculator.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/NEON/functions/NEMinMaxLocation.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +/** Compute Neon MinMaxLocation function. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] dt_in Data type of first input tensor. + * @param[out] min Minimum value of tensor + * @param[out] max Maximum value of tensor + * @param[out] min_loc Array with locations of minimum values + * @param[out] max_loc Array with locations of maximum values + * @param[out] min_count Number of minimum values found + * @param[out] max_count Number of maximum values found + * + * @return Computed output tensor. + */ + +void compute_min_max_location(const TensorShape &shape, DataType dt_in, void *min, void *max, + Coordinates2DArray &min_loc, Coordinates2DArray &max_loc, uint32_t &min_count, uint32_t &max_count) +{ + // Create tensor + Tensor src = create_tensor<Tensor>(shape, dt_in); + + // Create and configure min_max_location configure function + NEMinMaxLocation min_max_loc; + min_max_loc.configure(&src, min, max, &min_loc, &max_loc, &min_count, &max_count); + + // Allocate tensors + src.allocator()->allocate(); + + BOOST_TEST(!src.info()->is_resizable()); + + // Fill tensors + library->fill_tensor_uniform(Accessor(src), 0); + + // Compute function + min_max_loc.run(); +} + +void validate_configuration(const Tensor &src, TensorShape shape) +{ + BOOST_TEST(src.info()->is_resizable()); + + // Create output storage + int32_t min; + int32_t max; + Coordinates2DArray min_loc; + Coordinates2DArray max_loc; + uint32_t min_count; + uint32_t max_count; + + // Create and configure function + NEMinMaxLocation min_max_loc; + min_max_loc.configure(&src, &min, &max, &min_loc, &max_loc, &min_count, &max_count); + + // Validate valid region + const ValidRegion valid_region = shape_to_valid_region(shape); + validate(src.info()->valid_region(), valid_region); + + // Validate padding + const PaddingSize padding = PaddingCalculator(shape.x(), 1).required_padding(); + validate(src.info()->padding(), padding); +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(NEON) +BOOST_AUTO_TEST_SUITE(MinMaxLocation) + +BOOST_AUTO_TEST_SUITE(Integer) +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(Configuration, (Small2DShapes() + Large2DShapes()) * boost::unit_test::data::make({ DataType::U8, DataType::S16 }), + shape, dt) +{ + // Create tensor + Tensor src = create_tensor<Tensor>(shape, dt); + src.info()->set_format(dt == DataType::U8 ? Format::U8 : Format::S16); + + validate_configuration(src, shape); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, Small2DShapes() * boost::unit_test::data::make({ DataType::U8, DataType::S16 }), + shape, dt) +{ + // Create output storage + int32_t min; + int32_t max; + Coordinates2DArray min_loc(shape.total_size()); + Coordinates2DArray max_loc(shape.total_size()); + uint32_t min_count; + uint32_t max_count; + + int32_t ref_min; + int32_t ref_max; + Coordinates2DArray ref_min_loc(shape.total_size()); + Coordinates2DArray ref_max_loc(shape.total_size()); + uint32_t ref_min_count; + uint32_t ref_max_count; + + // Compute function + compute_min_max_location(shape, dt, &min, &max, min_loc, max_loc, min_count, max_count); + + // Compute reference + Reference::compute_reference_min_max_location(shape, dt, &ref_min, &ref_max, ref_min_loc, ref_max_loc, ref_min_count, ref_max_count); + + // Validate output + validate_min_max_loc(min, ref_min, max, ref_max, min_loc, ref_min_loc, max_loc, ref_max_loc, min_count, ref_min_count, max_count, ref_max_count); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, Large2DShapes() * boost::unit_test::data::make({ DataType::U8, DataType::S16 }), + shape, dt) +{ + // Create output storage + int32_t min; + int32_t max; + Coordinates2DArray min_loc(shape.total_size()); + Coordinates2DArray max_loc(shape.total_size()); + uint32_t min_count; + uint32_t max_count; + + int32_t ref_min; + int32_t ref_max; + Coordinates2DArray ref_min_loc(shape.total_size()); + Coordinates2DArray ref_max_loc(shape.total_size()); + uint32_t ref_min_count; + uint32_t ref_max_count; + + // Compute function + compute_min_max_location(shape, dt, &min, &max, min_loc, max_loc, min_count, max_count); + + // Compute reference + Reference::compute_reference_min_max_location(shape, dt, &ref_min, &ref_max, ref_min_loc, ref_max_loc, ref_min_count, ref_max_count); + + // Validate output + validate_min_max_loc(min, ref_min, max, ref_max, min_loc, ref_min_loc, max_loc, ref_max_loc, min_count, ref_min_count, max_count, ref_max_count); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(Float) +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, Small2DShapes() * DataType::F32, + shape, dt) +{ + // Create output storage + float min; + float max; + Coordinates2DArray min_loc(shape.total_size()); + Coordinates2DArray max_loc(shape.total_size()); + uint32_t min_count; + uint32_t max_count; + + float ref_min; + float ref_max; + Coordinates2DArray ref_min_loc(shape.total_size()); + Coordinates2DArray ref_max_loc(shape.total_size()); + uint32_t ref_min_count; + uint32_t ref_max_count; + + // Compute function + compute_min_max_location(shape, dt, &min, &max, min_loc, max_loc, min_count, max_count); + + // Compute reference + Reference::compute_reference_min_max_location(shape, dt, &ref_min, &ref_max, ref_min_loc, ref_max_loc, ref_min_count, ref_max_count); + + // Validate output + validate_min_max_loc(min, ref_min, max, ref_max, min_loc, ref_min_loc, max_loc, ref_max_loc, min_count, ref_min_count, max_count, ref_max_count); +} + +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/NEON/NonLinearFilter.cpp b/tests/validation_old/NEON/NonLinearFilter.cpp new file mode 100644 index 0000000000..acc90a436a --- /dev/null +++ b/tests/validation_old/NEON/NonLinearFilter.cpp @@ -0,0 +1,203 @@ +/* + * 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 "NEON/Accessor.h" +#include "PaddingCalculator.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Helpers.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" +#include "tests/validation_old/ValidationUserConfiguration.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/NEON/functions/NENonLinearFilter.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +/** Compute NonLinearFilter function. + * + * @param[in] input Shape of the input and output tensors. + * @param[in] function Non linear function to perform + * @param[in] mask_size Mask size. Supported sizes: 3, 5 + * @param[in] pattern Mask pattern + * @param[in] mask The given mask. Will be used only if pattern is specified to PATTERN_OTHER + * @param[in] border_mode Strategy to use for borders. + * @param[in] constant_border_value (Optional) Constant value to use for borders if border_mode is set to CONSTANT. + * + * @return Computed output tensor. + */ +Tensor compute_non_linear_filter(const TensorShape &shape, NonLinearFilterFunction function, unsigned int mask_size, + MatrixPattern pattern, const uint8_t *mask, BorderMode border_mode, + uint8_t constant_border_value) +{ + // Create tensors + Tensor src = create_tensor<Tensor>(shape, DataType::U8); + Tensor dst = create_tensor<Tensor>(shape, DataType::U8); + + // Create and configure function + NENonLinearFilter filter; + filter.configure(&src, &dst, function, mask_size, pattern, mask, border_mode, constant_border_value); + + // 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(Accessor(src), 0); + + // Compute function + filter.run(); + + return dst; +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(NEON) +BOOST_AUTO_TEST_SUITE(NonLinearFilter) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(Configuration, (SmallShapes() + LargeShapes()) + * NonLinearFilterFunctions() * boost::unit_test::data::make({ 3U, 5U }) + * MatrixPatterns() * BorderModes(), + shape, function, mask_size, pattern, border_mode) +{ + std::mt19937 generator(user_config.seed.get()); + std::uniform_int_distribution<uint8_t> distribution_u8(0, 255); + const uint8_t constant_border_value = distribution_u8(generator); + + // Create the mask + uint8_t mask[mask_size * mask_size]; + fill_mask_from_pattern(mask, mask_size, mask_size, pattern); + const auto half_mask_size = static_cast<int>(mask_size / 2); + + // Create tensors + Tensor src = create_tensor<Tensor>(shape, DataType::U8); + Tensor dst = create_tensor<Tensor>(shape, DataType::U8); + + BOOST_TEST(src.info()->is_resizable()); + BOOST_TEST(dst.info()->is_resizable()); + + // Create and configure function + NENonLinearFilter filter; + filter.configure(&src, &dst, function, mask_size, pattern, mask, border_mode, constant_border_value); + + // Validate valid region + const ValidRegion src_valid_region = shape_to_valid_region(shape); + const ValidRegion dst_valid_region = shape_to_valid_region(shape, border_mode == BorderMode::UNDEFINED, BorderSize(half_mask_size)); + + validate(src.info()->valid_region(), src_valid_region); + validate(dst.info()->valid_region(), dst_valid_region); + + // Validate padding + PaddingCalculator calculator(shape.x(), ((MatrixPattern::OTHER == pattern) ? 1 : 8)); + calculator.set_border_mode(border_mode); + calculator.set_border_size(half_mask_size); + + const PaddingSize write_padding = calculator.required_padding(PaddingCalculator::Option::EXCLUDE_BORDER); + + calculator.set_accessed_elements(16); + calculator.set_access_offset(-half_mask_size); + + const PaddingSize read_padding = calculator.required_padding(PaddingCalculator::Option::INCLUDE_BORDER); + + validate(src.info()->padding(), read_padding); + validate(dst.info()->padding(), write_padding); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() + * NonLinearFilterFunctions() * boost::unit_test::data::make({ 3U, 5U }) + * MatrixPatterns() * BorderModes(), + shape, function, mask_size, pattern, border_mode) +{ + std::mt19937 generator(user_config.seed.get()); + std::uniform_int_distribution<uint8_t> distribution_u8(0, 255); + const uint8_t constant_border_value = distribution_u8(generator); + + // Create the mask + uint8_t mask[mask_size * mask_size]; + fill_mask_from_pattern(mask, mask_size, mask_size, pattern); + + // Compute function + Tensor dst = compute_non_linear_filter(shape, function, mask_size, pattern, mask, border_mode, constant_border_value); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_non_linear_filter(shape, function, mask_size, pattern, mask, border_mode, constant_border_value); + + // Calculate valid region + const ValidRegion valid_region = shape_to_valid_region(shape, border_mode == BorderMode::UNDEFINED, BorderSize(static_cast<int>(mask_size / 2))); + + // Validate output + validate(Accessor(dst), ref_dst, valid_region); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() + * NonLinearFilterFunctions() * boost::unit_test::data::make({ 3U, 5U }) + * MatrixPatterns() * BorderModes(), + shape, function, mask_size, pattern, border_mode) +{ + std::mt19937 generator(user_config.seed.get()); + std::uniform_int_distribution<uint8_t> distribution_u8(0, 255); + const uint8_t constant_border_value = distribution_u8(generator); + + // Create the mask + uint8_t mask[mask_size * mask_size]; + fill_mask_from_pattern(mask, mask_size, mask_size, pattern); + + // Compute function + Tensor dst = compute_non_linear_filter(shape, function, mask_size, pattern, mask, border_mode, constant_border_value); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_non_linear_filter(shape, function, mask_size, pattern, mask, border_mode, constant_border_value); + + // Calculate valid region + const ValidRegion valid_region = shape_to_valid_region(shape, border_mode == BorderMode::UNDEFINED, BorderSize(static_cast<int>(mask_size / 2))); + + // Validate output + validate(Accessor(dst), ref_dst, valid_region); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/NEON/PixelWiseMultiplication.cpp b/tests/validation_old/NEON/PixelWiseMultiplication.cpp new file mode 100644 index 0000000000..60eb82ef84 --- /dev/null +++ b/tests/validation_old/NEON/PixelWiseMultiplication.cpp @@ -0,0 +1,583 @@ +/* + * 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 "NEON/Accessor.h" +#include "PaddingCalculator.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/NEON/functions/NEPixelWiseMultiplication.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +/** Compute Neon pixel-wise multiplication function. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] dt_in0 Data type of first input tensor. + * @param[in] dt_in1 Data type of second input tensor. + * @param[in] dt_out Data type of the output tensor. + * @param[in] scale Non-negative scale. + * @param[in] convert_policy Overflow policy of the operation. + * @param[in] rounding_policy Rounding policy of the operation. + * @param[in] fixed_point_position (Optional) Fixed point position that expresses the number of bits for the fractional part of the number. + * + * @return Computed output tensor. + */ +Tensor compute_pixel_wise_multiplication(const TensorShape &shape, DataType dt_in0, DataType dt_in1, DataType dt_out, float scale, ConvertPolicy convert_policy, RoundingPolicy rounding_policy, + int fixed_point_position = 0) +{ + // Create tensors + Tensor src1 = create_tensor<Tensor>(shape, dt_in0, 1, fixed_point_position); + Tensor src2 = create_tensor<Tensor>(shape, dt_in1, 1, fixed_point_position); + Tensor dst = create_tensor<Tensor>(shape, dt_out, 1, fixed_point_position); + + // Create and configure function + NEPixelWiseMultiplication multiply; + multiply.configure(&src1, &src2, &dst, scale, convert_policy, rounding_policy); + + // Allocate tensors + src1.allocator()->allocate(); + src2.allocator()->allocate(); + dst.allocator()->allocate(); + + BOOST_TEST(!src1.info()->is_resizable()); + BOOST_TEST(!src2.info()->is_resizable()); + BOOST_TEST(!dst.info()->is_resizable()); + + // Fill tensors + library->fill_tensor_uniform(Accessor(src1), 0); + library->fill_tensor_uniform(Accessor(src2), 1); + + // Compute function + multiply.run(); + + return dst; +} + +void validate_configuration(const Tensor &src1, const Tensor &src2, Tensor &dst, TensorShape shape, float scale, ConvertPolicy convert_policy, RoundingPolicy rounding_policy) +{ + BOOST_TEST(src1.info()->is_resizable()); + BOOST_TEST(src2.info()->is_resizable()); + BOOST_TEST(dst.info()->is_resizable()); + + // Create and configure function + NEPixelWiseMultiplication multiply; + multiply.configure(&src1, &src2, &dst, scale, convert_policy, rounding_policy); + + // Validate valid region + const ValidRegion valid_region = shape_to_valid_region(shape); + validate(src1.info()->valid_region(), valid_region); + validate(src2.info()->valid_region(), valid_region); + validate(dst.info()->valid_region(), valid_region); + + // Validate padding + const PaddingSize padding = PaddingCalculator(shape.x(), 16).required_padding(); + validate(src1.info()->padding(), padding); + validate(src2.info()->padding(), padding); + validate(dst.info()->padding(), padding); +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(NEON) +BOOST_AUTO_TEST_SUITE(PixelWiseMultiplication) + +BOOST_AUTO_TEST_SUITE(U8) +BOOST_AUTO_TEST_SUITE(Scale255) +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(Configuration, (SmallShapes() + LargeShapes()) * (1.f / 255.f) * ConvertPolicies() + * RoundingPolicy::TO_NEAREST_UP, + shape, scale, convert_policy, rounding_policy) +{ + // Create tensors + Tensor src1 = create_tensor<Tensor>(shape, DataType::U8); + Tensor src2 = create_tensor<Tensor>(shape, DataType::U8); + Tensor dst = create_tensor<Tensor>(shape, DataType::U8); + + validate_configuration(src1, src2, dst, shape, scale, convert_policy, rounding_policy); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * (1.f / 255.f) * ConvertPolicies() * RoundingPolicy::TO_NEAREST_UP, + shape, scale, convert_policy, rounding_policy) +{ + // Compute function + Tensor dst = compute_pixel_wise_multiplication(shape, DataType::U8, DataType::U8, DataType::U8, scale, convert_policy, + rounding_policy); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_pixel_wise_multiplication(shape, DataType::U8, DataType::U8, + DataType::U8, scale, convert_policy, rounding_policy); + + // Validate output + // Allow tolerance value of 1.f to counteract imprecision due to 32-bit float conversion + validate(Accessor(dst), ref_dst, 1.f, 0.f, std::numeric_limits<uint8_t>::max()); +} +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * (1.f / 255.f) * ConvertPolicies() * RoundingPolicy::TO_NEAREST_UP, + shape, scale, convert_policy, rounding_policy) +{ + // Compute function + Tensor dst = compute_pixel_wise_multiplication(shape, DataType::U8, DataType::U8, DataType::U8, scale, convert_policy, + rounding_policy); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_pixel_wise_multiplication(shape, DataType::U8, DataType::U8, + DataType::U8, scale, convert_policy, rounding_policy); + + // Validate output + // Allow tolerance value of 1.f to counteract imprecision due to 32-bit float conversion + validate(Accessor(dst), ref_dst, 1.f, 0.f, std::numeric_limits<uint8_t>::max()); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(ScaleOther) +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({ 1.f, 1.f / 32768.f }) + * ConvertPolicies() + * RoundingPolicy::TO_ZERO, + shape, scale, convert_policy, rounding_policy) +{ + // Create tensors + Tensor src1 = create_tensor<Tensor>(shape, DataType::U8); + Tensor src2 = create_tensor<Tensor>(shape, DataType::U8); + Tensor dst = create_tensor<Tensor>(shape, DataType::U8); + + validate_configuration(src1, src2, dst, shape, scale, convert_policy, rounding_policy); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * boost::unit_test::data::make({ 1.f, 1.f / 32768.f }) * ConvertPolicies() + * RoundingPolicy::TO_ZERO, + shape, scale, convert_policy, rounding_policy) +{ + // Compute function + Tensor dst = compute_pixel_wise_multiplication(shape, DataType::U8, DataType::U8, DataType::U8, scale, convert_policy, + rounding_policy); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_pixel_wise_multiplication(shape, DataType::U8, DataType::U8, + DataType::U8, scale, convert_policy, rounding_policy); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * boost::unit_test::data::make({ 1.f, 1.f / 32768.f }) * ConvertPolicies() + * RoundingPolicy::TO_ZERO, + shape, scale, convert_policy, rounding_policy) +{ + // Compute function + Tensor dst = compute_pixel_wise_multiplication(shape, DataType::U8, DataType::U8, DataType::U8, scale, convert_policy, + rounding_policy); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_pixel_wise_multiplication(shape, DataType::U8, DataType::U8, + DataType::U8, scale, convert_policy, rounding_policy); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(S16) +BOOST_AUTO_TEST_SUITE(Scale255) +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 }) * (1.f / 255.f) * ConvertPolicies() + * RoundingPolicy::TO_NEAREST_UP, + shape, dt, scale, convert_policy, rounding_policy) +{ + // Create tensors + Tensor src1 = create_tensor<Tensor>(shape, dt); + Tensor src2 = create_tensor<Tensor>(shape, DataType::S16); + Tensor dst = create_tensor<Tensor>(shape, DataType::S16); + + validate_configuration(src1, src2, dst, shape, scale, convert_policy, rounding_policy); +} +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * boost::unit_test::data::make({ DataType::U8, DataType::S16 }) * (1.f / 255.f) * ConvertPolicies() + * RoundingPolicy::TO_NEAREST_UP, + shape, dt, scale, convert_policy, rounding_policy) +{ + // Compute function + Tensor dst = compute_pixel_wise_multiplication(shape, dt, DataType::S16, DataType::S16, scale, convert_policy, rounding_policy); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_pixel_wise_multiplication(shape, dt, DataType::S16, DataType::S16, scale, convert_policy, rounding_policy); + + // Validate output + // Allow tolerance value of 2.f to counteract imprecision due to 32-bit float conversion + validate(Accessor(dst), ref_dst, 2.f, 0.f, std::numeric_limits<int16_t>::max()); +} +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * boost::unit_test::data::make({ DataType::U8, DataType::S16 }) * (1.f / 255.f) * ConvertPolicies() + * RoundingPolicy::TO_NEAREST_UP, + shape, dt, scale, convert_policy, rounding_policy) +{ + // Compute function + Tensor dst = compute_pixel_wise_multiplication(shape, dt, DataType::S16, DataType::S16, scale, convert_policy, rounding_policy); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_pixel_wise_multiplication(shape, dt, DataType::S16, DataType::S16, + scale, convert_policy, rounding_policy); + + // Validate output + // Allow tolerance value of 2.f to counteract imprecision due to 32-bit float conversion + validate(Accessor(dst), ref_dst, 2.f, 0.f, std::numeric_limits<int16_t>::max()); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(ScaleOther) +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 }) * boost::unit_test::data::make({ 1.f, 1.f / 32768.f }) + * ConvertPolicies() + * RoundingPolicy::TO_ZERO, + shape, dt, scale, convert_policy, rounding_policy) +{ + // Create tensors + Tensor src1 = create_tensor<Tensor>(shape, dt); + Tensor src2 = create_tensor<Tensor>(shape, DataType::S16); + Tensor dst = create_tensor<Tensor>(shape, DataType::S16); + + validate_configuration(src1, src2, dst, shape, scale, convert_policy, rounding_policy); +} +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * boost::unit_test::data::make({ DataType::U8, DataType::S16 }) * boost::unit_test::data::make({ 1.f, 1.f / 32768.f }) * ConvertPolicies() + * RoundingPolicy::TO_ZERO, + shape, dt, scale, convert_policy, rounding_policy) +{ + // Compute function + Tensor dst = compute_pixel_wise_multiplication(shape, dt, DataType::S16, DataType::S16, scale, convert_policy, rounding_policy); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_pixel_wise_multiplication(shape, dt, DataType::S16, DataType::S16, scale, convert_policy, rounding_policy); + + // Validate output + validate(Accessor(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 }) * boost::unit_test::data::make({ 1.f, 1.f / 32768.f }) * ConvertPolicies() + * RoundingPolicy::TO_ZERO, + shape, dt, scale, convert_policy, rounding_policy) +{ + // Compute function + Tensor dst = compute_pixel_wise_multiplication(shape, dt, DataType::S16, DataType::S16, scale, convert_policy, rounding_policy); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_pixel_wise_multiplication(shape, dt, DataType::S16, DataType::S16, + scale, convert_policy, rounding_policy); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() + +#ifdef ARM_COMPUTE_ENABLE_FP16 +BOOST_AUTO_TEST_SUITE(F16) +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) + +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * (1.f / 255.f) * ConvertPolicies() * RoundingPolicy::TO_NEAREST_UP, + shape, scale, convert_policy, rounding_policy) +{ + // Compute function + Tensor dst = compute_pixel_wise_multiplication(shape, DataType::F16, DataType::F16, DataType::F16, scale, convert_policy, rounding_policy); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_pixel_wise_multiplication(shape, DataType::F16, DataType::F16, DataType::F16, scale, convert_policy, rounding_policy); + + // Validate output + // Allow tolerance value of 1.f to counteract imprecision due to 32-bit float conversion + validate(Accessor(dst), ref_dst, 1.f, 0.f, std::numeric_limits<int16_t>::max()); +} + +BOOST_AUTO_TEST_SUITE_END() +#endif /* ARM_COMPUTE_ENABLE_FP16 */ + +BOOST_AUTO_TEST_SUITE(F32) +BOOST_AUTO_TEST_SUITE(Scale255) +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(Configuration, (SmallShapes() + LargeShapes()) * (1.f / 255.f) * ConvertPolicies() + * RoundingPolicy::TO_NEAREST_UP, + shape, scale, convert_policy, rounding_policy) +{ + // Create tensors + Tensor src1 = create_tensor<Tensor>(shape, DataType::F32); + Tensor src2 = create_tensor<Tensor>(shape, DataType::F32); + Tensor dst = create_tensor<Tensor>(shape, DataType::F32); + + validate_configuration(src1, src2, dst, shape, scale, convert_policy, rounding_policy); +} +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * (1.f / 255.f) * ConvertPolicies() + * RoundingPolicy::TO_NEAREST_UP, + shape, scale, convert_policy, rounding_policy) +{ + // Compute function + Tensor dst = compute_pixel_wise_multiplication(shape, DataType::F32, DataType::F32, DataType::F32, scale, convert_policy, rounding_policy); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_pixel_wise_multiplication(shape, DataType::F32, DataType::F32, DataType::F32, scale, convert_policy, rounding_policy); + + // Validate output + // Allow tolerance value of 1.f to counteract imprecision due to 32-bit float conversion + validate(Accessor(dst), ref_dst, 1.f, 0.f, std::numeric_limits<int16_t>::max()); +} +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * (1.f / 255.f) * ConvertPolicies() + * RoundingPolicy::TO_NEAREST_UP, + shape, scale, convert_policy, rounding_policy) +{ + // Compute function + Tensor dst = compute_pixel_wise_multiplication(shape, DataType::F32, DataType::F32, DataType::F32, scale, convert_policy, rounding_policy); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_pixel_wise_multiplication(shape, DataType::F32, DataType::F32, DataType::F32, + scale, convert_policy, rounding_policy); + + // Validate output + // Allow tolerance value of 1.f to counteract imprecision due to 32-bit float conversion + validate(Accessor(dst), ref_dst, 1.f, 0.f, std::numeric_limits<int16_t>::max()); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(ScaleOther) +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({ 1.f, 1.f / 32768.f }) + * ConvertPolicies() + * RoundingPolicy::TO_ZERO, + shape, scale, convert_policy, rounding_policy) +{ + // Create tensors + Tensor src1 = create_tensor<Tensor>(shape, DataType::F32); + Tensor src2 = create_tensor<Tensor>(shape, DataType::F32); + Tensor dst = create_tensor<Tensor>(shape, DataType::F32); + + validate_configuration(src1, src2, dst, shape, scale, convert_policy, rounding_policy); +} +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * boost::unit_test::data::make({ 1.f, 1.f / 32768.f }) * ConvertPolicies() + * RoundingPolicy::TO_ZERO, + shape, scale, convert_policy, rounding_policy) +{ + // Compute function + Tensor dst = compute_pixel_wise_multiplication(shape, DataType::F32, DataType::F32, DataType::F32, scale, convert_policy, rounding_policy); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_pixel_wise_multiplication(shape, DataType::F32, DataType::F32, DataType::F32, scale, convert_policy, rounding_policy); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * boost::unit_test::data::make({ 1.f, 1.f / 32768.f }) * ConvertPolicies() + * RoundingPolicy::TO_ZERO, + shape, scale, convert_policy, rounding_policy) +{ + // Compute function + Tensor dst = compute_pixel_wise_multiplication(shape, DataType::F32, DataType::F32, DataType::F32, scale, convert_policy, rounding_policy); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_pixel_wise_multiplication(shape, DataType::F32, DataType::F32, DataType::F32, + scale, convert_policy, rounding_policy); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(Quantized) +BOOST_AUTO_TEST_SUITE(QS8) +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * DataType::QS8 *ConvertPolicies() * RoundingPolicy::TO_ZERO * boost::unit_test::data::xrange<int>(1, 7), + shape, dt, convert_policy, rounding_policy, fixed_point_position) +{ + // Compute function + Tensor dst = compute_pixel_wise_multiplication(shape, dt, dt, dt, 1.f, convert_policy, rounding_policy, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_fixed_point_pixel_wise_multiplication(shape, dt, dt, dt, 1.f, fixed_point_position, convert_policy, rounding_policy); + + // Validate output + validate(Accessor(dst), ref_dst); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmallScale255, SmallShapes() * DataType::QS8 * (1.f / 255.f) * ConvertPolicies() * RoundingPolicy::TO_NEAREST_UP * boost::unit_test::data::xrange(1, 7), + shape, dt, scale, convert_policy, rounding_policy, fixed_point_position) +{ + // Compute function + Tensor dst = compute_pixel_wise_multiplication(shape, dt, dt, dt, scale, convert_policy, rounding_policy, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_fixed_point_pixel_wise_multiplication(shape, dt, dt, dt, scale, fixed_point_position, convert_policy, rounding_policy); + + // Validate output + validate(Accessor(dst), ref_dst); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmallScaleOther, SmallShapes() * DataType::QS8 *ConvertPolicies() * RoundingPolicy::TO_ZERO * boost::unit_test::data::xrange(1, 7), + shape, dt, convert_policy, rounding_policy, fixed_point_position) +{ + const float scale = 1.f / static_cast<float>(1 << fixed_point_position); + + // Compute function + Tensor dst = compute_pixel_wise_multiplication(shape, dt, dt, dt, scale, convert_policy, rounding_policy, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_fixed_point_pixel_wise_multiplication(shape, dt, dt, dt, scale, fixed_point_position, convert_policy, rounding_policy); + + // Validate output + validate(Accessor(dst), ref_dst, 1.f); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * DataType::QS8 *ConvertPolicies() * RoundingPolicy::TO_ZERO * boost::unit_test::data::xrange<int>(1, 7), + shape, dt, convert_policy, rounding_policy, fixed_point_position) +{ + // Compute function + Tensor dst = compute_pixel_wise_multiplication(shape, dt, dt, dt, 1.f, convert_policy, rounding_policy); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_pixel_wise_multiplication(shape, dt, dt, dt, 1.f, convert_policy, rounding_policy); + + // Validate output + validate(Accessor(dst), ref_dst); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLargeScale255, LargeShapes() * DataType::QS8 * (1.f / 255.f) * ConvertPolicies() * RoundingPolicy::TO_ZERO * boost::unit_test::data::xrange(1, 7), + shape, dt, scale, convert_policy, rounding_policy, fixed_point_position) +{ + // Compute function + Tensor dst = compute_pixel_wise_multiplication(shape, dt, dt, dt, scale, convert_policy, rounding_policy, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_fixed_point_pixel_wise_multiplication(shape, dt, dt, dt, scale, fixed_point_position, convert_policy, rounding_policy); + + // Validate output + validate(Accessor(dst), ref_dst); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLargeScaleOther, LargeShapes() * DataType::QS8 *ConvertPolicies() * RoundingPolicy::TO_ZERO * boost::unit_test::data::xrange(1, 7), + shape, dt, convert_policy, rounding_policy, fixed_point_position) +{ + const float scale = 1.f / static_cast<float>(1 << fixed_point_position); + + // Compute function + Tensor dst = compute_pixel_wise_multiplication(shape, dt, dt, dt, scale, convert_policy, rounding_policy, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_fixed_point_pixel_wise_multiplication(shape, dt, dt, dt, scale, fixed_point_position, convert_policy, rounding_policy); + + // Validate output + validate(Accessor(dst), ref_dst, 1.f); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(QS16) +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * DataType::QS16 *ConvertPolicies() * RoundingPolicy::TO_ZERO * boost::unit_test::data::xrange<int>(1, 15), + shape, dt, convert_policy, rounding_policy, fixed_point_position) +{ + // Compute function + Tensor dst = compute_pixel_wise_multiplication(shape, dt, dt, dt, 1.f, convert_policy, rounding_policy, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_fixed_point_pixel_wise_multiplication(shape, dt, dt, dt, 1.f, fixed_point_position, convert_policy, rounding_policy); + + // Validate output + validate(Accessor(dst), ref_dst); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmallScale255, SmallShapes() * DataType::QS16 * (1.f / 255.f) * ConvertPolicies() * RoundingPolicy::TO_NEAREST_UP * boost::unit_test::data::xrange(1, 15), + shape, dt, scale, convert_policy, rounding_policy, fixed_point_position) +{ + // Compute function + Tensor dst = compute_pixel_wise_multiplication(shape, dt, dt, dt, scale, convert_policy, rounding_policy, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_fixed_point_pixel_wise_multiplication(shape, dt, dt, dt, scale, fixed_point_position, convert_policy, rounding_policy); + + // Validate output + validate(Accessor(dst), ref_dst); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmallScaleOther, SmallShapes() * DataType::QS16 *ConvertPolicies() * RoundingPolicy::TO_ZERO * boost::unit_test::data::xrange(1, 15), + shape, dt, convert_policy, rounding_policy, fixed_point_position) +{ + const float scale = 1.f / static_cast<float>(1 << fixed_point_position); + + // Compute function + Tensor dst = compute_pixel_wise_multiplication(shape, dt, dt, dt, scale, convert_policy, rounding_policy, fixed_point_position); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_fixed_point_pixel_wise_multiplication(shape, dt, dt, dt, scale, fixed_point_position, convert_policy, rounding_policy); + + // Validate output + validate(Accessor(dst), ref_dst, 1.f); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * DataType::QS16 *ConvertPolicies() * RoundingPolicy::TO_ZERO * boost::unit_test::data::xrange<int>(1, 15), + shape, dt, convert_policy, rounding_policy, fixed_point_position) +{ + // Compute function + Tensor dst = compute_pixel_wise_multiplication(shape, dt, dt, dt, 1.f, convert_policy, rounding_policy); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_pixel_wise_multiplication(shape, dt, dt, dt, 1.f, convert_policy, rounding_policy); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/NEON/ROIPoolingLayer.cpp b/tests/validation_old/NEON/ROIPoolingLayer.cpp new file mode 100644 index 0000000000..2046beb196 --- /dev/null +++ b/tests/validation_old/NEON/ROIPoolingLayer.cpp @@ -0,0 +1,110 @@ +/* + * 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 "NEON/Accessor.h" +#include "NEON/ArrayAccessor.h" +#include "TypePrinter.h" +#include "arm_compute/runtime/NEON/functions/NEROIPoolingLayer.h" +#include "tests/Globals.h" +#include "tests/Utils.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" +#include "tests/validation_old/ValidationUserConfiguration.h" + +#include <random> +#include <vector> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +Tensor compute_roi_pooling_layer(const TensorShape &shape, DataType dt, const std::vector<ROI> &rois, ROIPoolingLayerInfo pool_info) +{ + TensorShape shape_dst; + shape_dst.set(0, pool_info.pooled_width()); + shape_dst.set(1, pool_info.pooled_height()); + shape_dst.set(2, shape.z()); + shape_dst.set(3, rois.size()); + + // Create tensors + Tensor src = create_tensor<Tensor>(shape, dt); + Tensor dst = create_tensor<Tensor>(shape_dst, dt); + + // Create ROI array + Array<ROI> rois_array(rois.size()); + fill_array(ArrayAccessor<ROI>(rois_array), rois); + + // Create and configure function + NEROIPoolingLayer roi_pool; + roi_pool.configure(&src, &rois_array, &dst, pool_info); + + // Allocate tensors + src.allocator()->allocate(); + dst.allocator()->allocate(); + + BOOST_TEST(!src.info()->is_resizable()); + BOOST_TEST(!dst.info()->is_resizable()); + + // Fill tensors + std::uniform_real_distribution<> distribution(-1, 1); + library->fill(Accessor(src), distribution, 0); + + // Compute function + roi_pool.run(); + + return dst; +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(NEON) +BOOST_AUTO_TEST_SUITE(ROIPoolingLayer) + +BOOST_AUTO_TEST_SUITE(Float) +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, CNNFloatDataTypes() * boost::unit_test::data::make({ 10, 20, 40 }) * boost::unit_test::data::make({ 7, 9 }) * boost::unit_test::data::make({ 1.f / 8.f, 1.f / 16.f }), + dt, num_rois, roi_pool_size, roi_scale) +{ + TensorShape shape(50U, 47U, 2U, 3U); + ROIPoolingLayerInfo pool_info(roi_pool_size, roi_pool_size, roi_scale); + + // Construct ROI vector + std::vector<ROI> rois = generate_random_rois(shape, pool_info, num_rois, user_config.seed); + + // Compute function + Tensor dst = compute_roi_pooling_layer(shape, dt, rois, pool_info); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_roi_pooling_layer(shape, dt, rois, pool_info); + + // Validate output + validate(Accessor(dst), ref_dst); +} +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/NEON/Sobel3x3.cpp b/tests/validation_old/NEON/Sobel3x3.cpp new file mode 100644 index 0000000000..cb249e1a58 --- /dev/null +++ b/tests/validation_old/NEON/Sobel3x3.cpp @@ -0,0 +1,203 @@ +/* + * 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 "NEON/Accessor.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" +#include "tests/validation_old/ValidationUserConfiguration.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/NEON/functions/NESobel3x3.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include "PaddingCalculator.h" +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +constexpr unsigned int filter_size = 3; /** Size of the kernel/filter in number of elements. */ +constexpr BorderSize border_size(filter_size / 2); /** Border size of the kernel/filter around its central element. */ + +/** Compute Neon Sobel 3x3 function. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] border_mode BorderMode used by the input tensor + * @param[in] constant_border_value Constant to use if @p border_mode == CONSTANT + * + * @return Computed output tensor. + */ +std::pair<Tensor, Tensor> compute_sobel_3x3(const TensorShape &shape, BorderMode border_mode, uint8_t constant_border_value) +{ + // Create tensors + Tensor src = create_tensor<Tensor>(shape, DataType::U8); + Tensor dst_x = create_tensor<Tensor>(shape, DataType::S16); + Tensor dst_y = create_tensor<Tensor>(shape, DataType::S16); + + src.info()->set_format(Format::U8); + dst_x.info()->set_format(Format::S16); + dst_y.info()->set_format(Format::S16); + + // Create sobel image configure function + NESobel3x3 sobel_3x3; + sobel_3x3.configure(&src, &dst_x, &dst_y, border_mode, constant_border_value); + + // Allocate tensors + src.allocator()->allocate(); + dst_x.allocator()->allocate(); + dst_y.allocator()->allocate(); + + BOOST_TEST(!src.info()->is_resizable()); + BOOST_TEST(!dst_x.info()->is_resizable()); + BOOST_TEST(!dst_y.info()->is_resizable()); + + // Fill tensors + library->fill_tensor_uniform(Accessor(src), 0); + + // Compute function + sobel_3x3.run(); + + return std::make_pair(std::move(dst_x), std::move(dst_y)); +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(NEON) +BOOST_AUTO_TEST_SUITE(Sobel3x3) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(Configuration, (SmallShapes() + LargeShapes()) * BorderModes(), shape, border_mode) +{ + // Create tensors + Tensor src = create_tensor<Tensor>(shape, DataType::U8); + Tensor dst_x = create_tensor<Tensor>(shape, DataType::S16); + Tensor dst_y = create_tensor<Tensor>(shape, DataType::S16); + + src.info()->set_format(Format::U8); + dst_x.info()->set_format(Format::S16); + dst_y.info()->set_format(Format::S16); + + BOOST_TEST(src.info()->is_resizable()); + BOOST_TEST(dst_x.info()->is_resizable()); + BOOST_TEST(dst_y.info()->is_resizable()); + + // Create sobel 3x3 configure function + NESobel3x3 sobel_3x3; + sobel_3x3.configure(&src, &dst_x, &dst_y, border_mode); + + // Validate valid region + const ValidRegion src_valid_region = shape_to_valid_region(shape); + const ValidRegion dst_valid_region = shape_to_valid_region(shape, border_mode == BorderMode::UNDEFINED, border_size); + + validate(src.info()->valid_region(), src_valid_region); + validate(dst_x.info()->valid_region(), dst_valid_region); + validate(dst_y.info()->valid_region(), dst_valid_region); + + // Validate padding + PaddingCalculator calculator(shape.x(), 8); + + calculator.set_border_mode(border_mode); + calculator.set_border_size(1); + + const PaddingSize dst_padding = calculator.required_padding(); + + calculator.set_accessed_elements(16); + calculator.set_access_offset(-1); + + const PaddingSize src_padding = calculator.required_padding(); + + validate(src.info()->padding(), src_padding); + validate(dst_x.info()->padding(), dst_padding); + validate(dst_y.info()->padding(), dst_padding); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * BorderModes(), shape, border_mode) +{ + uint8_t constant_border_value = 0; + + // Generate a random constant value if border_mode is constant + if(border_mode == BorderMode::CONSTANT) + { + std::mt19937 gen(user_config.seed.get()); + std::uniform_int_distribution<uint8_t> distribution(0, 255); + constant_border_value = distribution(gen); + } + + // Compute function + std::pair<Tensor, Tensor> dst = compute_sobel_3x3(shape, border_mode, constant_border_value); + + // Compute reference + std::pair<RawTensor, RawTensor> ref_dst = Reference::compute_reference_sobel_3x3(shape, border_mode, constant_border_value); + + // Calculate valid region + const ValidRegion valid_region = shape_to_valid_region(shape, border_mode == BorderMode::UNDEFINED, border_size); + + // Validate output + validate(Accessor(dst.first), ref_dst.first, valid_region); + validate(Accessor(dst.second), ref_dst.second, valid_region); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * BorderModes(), shape, border_mode) +{ + uint8_t constant_border_value = 0; + + // Generate a random constant value if border_mode is constant + if(border_mode == BorderMode::CONSTANT) + { + std::mt19937 gen(user_config.seed.get()); + std::uniform_int_distribution<uint8_t> distribution(0, 255); + constant_border_value = distribution(gen); + } + + // Compute function + std::pair<Tensor, Tensor> dst = compute_sobel_3x3(shape, border_mode, constant_border_value); + + // Compute reference + std::pair<RawTensor, RawTensor> ref_dst = Reference::compute_reference_sobel_3x3(shape, border_mode, constant_border_value); + + // Calculate valid region + const ValidRegion valid_region = shape_to_valid_region(shape, border_mode == BorderMode::UNDEFINED, border_size); + + // Validate output + validate(Accessor(dst.first), ref_dst.first, valid_region); + validate(Accessor(dst.second), ref_dst.second, valid_region); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/NEON/Sobel5x5.cpp b/tests/validation_old/NEON/Sobel5x5.cpp new file mode 100644 index 0000000000..2f26e62e83 --- /dev/null +++ b/tests/validation_old/NEON/Sobel5x5.cpp @@ -0,0 +1,204 @@ +/* + * 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 "NEON/Accessor.h" +#include "PaddingCalculator.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" +#include "tests/validation_old/ValidationUserConfiguration.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/NEON/functions/NESobel5x5.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +constexpr unsigned int filter_size = 5; /** Size of the kernel/filter in number of elements. */ +constexpr BorderSize border_size(filter_size / 2); /** Border size of the kernel/filter around its central element. */ + +/** Compute Neon Sobel 5x5 function. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] border_mode BorderMode used by the input tensor + * @param[in] constant_border_value Constant to use if @p border_mode == CONSTANT + * + * @return Computed output tensor. + */ +std::pair<Tensor, Tensor> compute_sobel_5x5(const TensorShape &shape, BorderMode border_mode, uint8_t constant_border_value) +{ + // Create tensors + Tensor src = create_tensor<Tensor>(shape, DataType::U8); + Tensor dst_x = create_tensor<Tensor>(shape, DataType::S16); + Tensor dst_y = create_tensor<Tensor>(shape, DataType::S16); + + src.info()->set_format(Format::U8); + dst_x.info()->set_format(Format::S16); + dst_y.info()->set_format(Format::S16); + + // Create sobel image configure function + NESobel5x5 sobel_5x5; + sobel_5x5.configure(&src, &dst_x, &dst_y, border_mode, constant_border_value); + + // Allocate tensors + src.allocator()->allocate(); + dst_x.allocator()->allocate(); + dst_y.allocator()->allocate(); + + BOOST_TEST(!src.info()->is_resizable()); + BOOST_TEST(!dst_x.info()->is_resizable()); + BOOST_TEST(!dst_y.info()->is_resizable()); + + // Fill tensors + library->fill_tensor_uniform(Accessor(src), 0); + + // Compute function + sobel_5x5.run(); + + return std::make_pair(std::move(dst_x), std::move(dst_y)); +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(NEON) +BOOST_AUTO_TEST_SUITE(Sobel5x5) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(Configuration, (SmallShapes() + LargeShapes()) * BorderModes(), shape, border_mode) +{ + // Create tensors + Tensor src = create_tensor<Tensor>(shape, DataType::U8); + Tensor dst_x = create_tensor<Tensor>(shape, DataType::S16); + Tensor dst_y = create_tensor<Tensor>(shape, DataType::S16); + + src.info()->set_format(Format::U8); + dst_x.info()->set_format(Format::S16); + dst_y.info()->set_format(Format::S16); + + BOOST_TEST(src.info()->is_resizable()); + BOOST_TEST(dst_x.info()->is_resizable()); + BOOST_TEST(dst_y.info()->is_resizable()); + + // Create sobel 5x5 configure function + NESobel5x5 sobel_5x5; + sobel_5x5.configure(&src, &dst_x, &dst_y, border_mode); + + // Validate valid region + const ValidRegion src_valid_region = shape_to_valid_region(shape); + const ValidRegion dst_valid_region = shape_to_valid_region(shape, border_mode == BorderMode::UNDEFINED, border_size); + + validate(src.info()->valid_region(), src_valid_region); + validate(dst_x.info()->valid_region(), dst_valid_region); + validate(dst_y.info()->valid_region(), dst_valid_region); + + // Validate padding + PaddingCalculator calculator(shape.x(), 16); + + calculator.set_border_mode(border_mode); + calculator.set_border_size(2); + + const PaddingSize dst_padding = calculator.required_padding(); + + calculator.set_processed_elements(8); + calculator.set_access_offset(-2); + + const PaddingSize src_padding = calculator.required_padding(); + + validate(src.info()->padding(), src_padding); + validate(dst_x.info()->padding(), dst_padding); + validate(dst_y.info()->padding(), dst_padding); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * BorderModes(), shape, border_mode) +{ + uint8_t constant_border_value = 0; + + // Generate a random constant value if border_mode is constant + if(border_mode == BorderMode::CONSTANT) + { + std::mt19937 gen(user_config.seed.get()); + std::uniform_int_distribution<uint8_t> distribution(0, 255); + constant_border_value = distribution(gen); + } + + // Compute function + std::pair<Tensor, Tensor> dst = compute_sobel_5x5(shape, border_mode, constant_border_value); + + // Compute reference + std::pair<RawTensor, RawTensor> ref_dst = Reference::compute_reference_sobel_5x5(shape, border_mode, constant_border_value); + + // Calculate valid region + const ValidRegion valid_region = shape_to_valid_region(shape, border_mode == BorderMode::UNDEFINED, border_size); + + // Validate output + validate(Accessor(dst.first), ref_dst.first, valid_region); + validate(Accessor(dst.second), ref_dst.second, valid_region); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() * BorderModes(), shape, border_mode) +{ + uint8_t constant_border_value = 0; + + // Generate a random constant value if border_mode is constant + if(border_mode == BorderMode::CONSTANT) + { + std::mt19937 gen(user_config.seed.get()); + std::uniform_int_distribution<uint8_t> distribution(0, 255); + constant_border_value = distribution(gen); + } + + // Compute function + std::pair<Tensor, Tensor> dst = compute_sobel_5x5(shape, border_mode, constant_border_value); + + // Compute reference + std::pair<RawTensor, RawTensor> ref_dst = Reference::compute_reference_sobel_5x5(shape, border_mode, constant_border_value); + + // Calculate valid region + const ValidRegion valid_region = shape_to_valid_region(shape, border_mode == BorderMode::UNDEFINED, border_size); + + // Validate output + validate(Accessor(dst.first), ref_dst.first, valid_region); + validate(Accessor(dst.second), ref_dst.second, valid_region); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/NEON/TableLookup.cpp b/tests/validation_old/NEON/TableLookup.cpp new file mode 100644 index 0000000000..f134e5d417 --- /dev/null +++ b/tests/validation_old/NEON/TableLookup.cpp @@ -0,0 +1,229 @@ +/* + * 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 "NEON/Accessor.h" +#include "NEON/Helper.h" +#include "NEON/LutAccessor.h" +#include "PaddingCalculator.h" +#include "RawLutAccessor.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Helpers.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/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 "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +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(Accessor(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(LutAccessor<uint8_t>(lut)); + } + else + { + fill_lookuptable(LutAccessor<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(LutAccessor<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(Accessor(dst), ref_dst); + } + else + { + //Create rawLut + std::map<int16_t, int16_t> rawlut; + + //Fill the Lut + fill_lookuptable(LutAccessor<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(Accessor(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(LutAccessor<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(Accessor(dst), ref_dst); + } + else + { + //Create rawLut + std::map<int16_t, int16_t> rawlut; + + //Fill the Lut + fill_lookuptable(LutAccessor<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(Accessor(dst), ref_dst); + } +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/NEON/Threshold.cpp b/tests/validation_old/NEON/Threshold.cpp new file mode 100644 index 0000000000..d56ec5eb42 --- /dev/null +++ b/tests/validation_old/NEON/Threshold.cpp @@ -0,0 +1,153 @@ +/* + * 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 "NEON/Accessor.h" +#include "PaddingCalculator.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" +#include "tests/validation_old/dataset/ThresholdDataset.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/NEON/functions/NEThreshold.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +/** Compute Threshold function. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] threshold Threshold. When the threshold type is RANGE, this is used as the lower threshold. + * @param[in] false_value value to set when the condition is not respected. + * @param[in] true_value value to set when the condition is respected. + * @param[in] type Thresholding type. Either RANGE or BINARY. + * @param[in] upper Upper threshold. Only used when the thresholding type is RANGE. + * + * @return Computed output tensor. + */ +Tensor compute_threshold(const TensorShape &shape, uint8_t threshold, uint8_t false_value, uint8_t true_value, ThresholdType type, uint8_t upper) +{ + // Create tensors + Tensor src1 = create_tensor<Tensor>(shape, DataType::U8); + Tensor dst = create_tensor<Tensor>(shape, DataType::U8); + + // Create and configure function + NEThreshold thrsh; + thrsh.configure(&src1, &dst, threshold, false_value, true_value, type, upper); + + // Allocate tensors + src1.allocator()->allocate(); + dst.allocator()->allocate(); + + BOOST_TEST(!src1.info()->is_resizable()); + BOOST_TEST(!dst.info()->is_resizable()); + + // Fill tensors + library->fill_tensor_uniform(Accessor(src1), 0); + + // Compute function + thrsh.run(); + + return dst; +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(NEON) +BOOST_AUTO_TEST_SUITE(Threshold) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(Configuration, + (SmallShapes() + LargeShapes()) * ThresholdDataset(), + shape, thrshConf) +{ + // Create tensors + Tensor src = create_tensor<Tensor>(shape, DataType::U8); + Tensor dst = create_tensor<Tensor>(shape, DataType::U8); + + BOOST_TEST(src.info()->is_resizable()); + BOOST_TEST(dst.info()->is_resizable()); + + // Create and configure function + NEThreshold thrsh; + thrsh.configure(&src, &dst, thrshConf.threshold, thrshConf.false_value, thrshConf.true_value, thrshConf.type, thrshConf.upper); + + // 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() * ThresholdDataset(), + shape, thrshConf) +{ + // Compute function + Tensor dst = compute_threshold(shape, thrshConf.threshold, thrshConf.false_value, thrshConf.true_value, thrshConf.type, thrshConf.upper); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_threshold(shape, thrshConf.threshold, thrshConf.false_value, thrshConf.true_value, thrshConf.type, thrshConf.upper); + + // Validate output + validate(Accessor(dst), ref_dst); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, + LargeShapes() * ThresholdDataset(), + shape, thrshConf) +{ + // Compute function + Tensor dst = compute_threshold(shape, thrshConf.threshold, thrshConf.false_value, thrshConf.true_value, thrshConf.type, thrshConf.upper); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_threshold(shape, thrshConf.threshold, thrshConf.false_value, thrshConf.true_value, thrshConf.type, thrshConf.upper); + + // Validate output + validate(Accessor(dst), ref_dst); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/NEON/WarpPerspective.cpp b/tests/validation_old/NEON/WarpPerspective.cpp new file mode 100644 index 0000000000..5a15591261 --- /dev/null +++ b/tests/validation_old/NEON/WarpPerspective.cpp @@ -0,0 +1,209 @@ +/* + * 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 "NEON/Accessor.h" +#include "PaddingCalculator.h" +#include "TypePrinter.h" +#include "Utils.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Datasets.h" +#include "tests/validation_old/Helpers.h" +#include "tests/validation_old/Reference.h" +#include "tests/validation_old/Validation.h" +#include "tests/validation_old/ValidationUserConfiguration.h" + +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/NEON/functions/NEWarpPerspective.h" +#include "arm_compute/runtime/Tensor.h" +#include "arm_compute/runtime/TensorAllocator.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <random> +#include <string> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +/** Compute Warp Perspective function. + * + * @param[in] input Shape of the input and output tensors. + * @param[in] matrix The perspective matrix. Must be 3x3 of type float. + * @param[in] policy The interpolation type. + * @param[in] border_mode Strategy to use for borders. + * @param[in] constant_border_value Constant value to use for borders if border_mode is set to CONSTANT. + * + * @return Computed output tensor. + */ +Tensor compute_warp_perspective(const TensorShape &shape, const float *matrix, InterpolationPolicy policy, + BorderMode border_mode, uint8_t constant_border_value) +{ + // Create tensors + Tensor src = create_tensor<Tensor>(shape, DataType::U8); + Tensor dst = create_tensor<Tensor>(shape, DataType::U8); + + // Create and configure function + NEWarpPerspective warp_perspective; + warp_perspective.configure(&src, &dst, matrix, policy, border_mode, constant_border_value); + + // 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(Accessor(src), 0); + + // Compute function + warp_perspective.run(); + + return dst; +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(NEON) +BOOST_AUTO_TEST_SUITE(WarpPerspective) + +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({ InterpolationPolicy::BILINEAR, InterpolationPolicy::NEAREST_NEIGHBOR }) * BorderModes(), + shape, policy, border_mode) +{ + uint8_t constant_border_value = 0; + + // Generate a random constant value if border_mode is constant + if(border_mode == BorderMode::CONSTANT) + { + std::mt19937 gen(user_config.seed.get()); + std::uniform_int_distribution<uint8_t> distribution_u8(0, 255); + constant_border_value = distribution_u8(gen); + } + + // Create the matrix + std::array<float, 9> matrix; + fill_warp_matrix<9>(matrix, 3, 3); + + // Create tensors + Tensor src = create_tensor<Tensor>(shape, DataType::U8); + Tensor dst = create_tensor<Tensor>(shape, DataType::U8); + + BOOST_TEST(src.info()->is_resizable()); + BOOST_TEST(dst.info()->is_resizable()); + + // Create and configure function + NEWarpPerspective warp_perspective; + warp_perspective.configure(&src, &dst, matrix.data(), policy, border_mode, constant_border_value); + + // 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 + PaddingCalculator calculator(shape.x(), 1); + calculator.set_border_mode(border_mode); + calculator.set_border_size(1); + + const PaddingSize read_padding(1); + const PaddingSize write_padding = calculator.required_padding(); + + validate(src.info()->padding(), read_padding); + validate(dst.info()->padding(), write_padding); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() + * boost::unit_test::data::make({ InterpolationPolicy::BILINEAR, InterpolationPolicy::NEAREST_NEIGHBOR }) + * BorderModes(), + shape, policy, border_mode) +{ + uint8_t constant_border_value = 0; + + // Generate a random constant value if border_mode is constant + if(border_mode == BorderMode::CONSTANT) + { + std::mt19937 gen(user_config.seed.get()); + std::uniform_int_distribution<uint8_t> distribution_u8(0, 255); + constant_border_value = distribution_u8(gen); + } + + // Create the valid mask Tensor + RawTensor valid_mask(shape, DataType::U8); + + // Create the matrix + std::array<float, 9> matrix; + fill_warp_matrix<9>(matrix, 3, 3); + + // Compute function + Tensor dst = compute_warp_perspective(shape, matrix.data(), policy, border_mode, constant_border_value); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_warp_perspective(shape, valid_mask, matrix.data(), policy, border_mode, constant_border_value); + + // Validate output + validate(Accessor(dst), ref_dst, valid_mask, 1, 0.2f); +} +BOOST_TEST_DECORATOR(*boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RunLarge, LargeShapes() + * boost::unit_test::data::make({ InterpolationPolicy::NEAREST_NEIGHBOR, InterpolationPolicy::BILINEAR }) * BorderModes(), + shape, policy, border_mode) +{ + uint8_t constant_border_value = 0; + + // Generate a random constant value if border_mode is constant + if(border_mode == BorderMode::CONSTANT) + { + std::mt19937 gen(user_config.seed.get()); + std::uniform_int_distribution<uint8_t> distribution_u8(0, 255); + constant_border_value = distribution_u8(gen); + } + + // Create the valid mask Tensor + RawTensor valid_mask(shape, DataType::U8); + + // Create the matrix + std::array<float, 9> matrix; + fill_warp_matrix<9>(matrix, 3, 3); + + // Compute function + Tensor dst = compute_warp_perspective(shape, matrix.data(), policy, border_mode, constant_border_value); + + // Compute reference + RawTensor ref_dst = Reference::compute_reference_warp_perspective(shape, valid_mask, matrix.data(), policy, border_mode, constant_border_value); + + // Validate output + validate(Accessor(dst), ref_dst, valid_mask, 1, 0.2f); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/ProgramOptions.cpp b/tests/validation_old/ProgramOptions.cpp new file mode 100644 index 0000000000..b5a7bb14ad --- /dev/null +++ b/tests/validation_old/ProgramOptions.cpp @@ -0,0 +1,88 @@ +/* + * 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 "ProgramOptions.h" + +#include "TypePrinter.h" +#include "TypeReader.h" + +#include "arm_compute/core/Types.h" + +#include <random> +#include <sstream> + +namespace arm_compute +{ +namespace test +{ +ProgramOptions::ProgramOptions() +{ + boost::program_options::options_description generic("Generic options"); + generic.add_options()("help", "Print help message")("seed", boost::program_options::value<std::random_device::result_type>()->default_value(std::random_device()()), "Seed for the tensor library"); + + _visible.add(generic); + + _hidden.add_options()("path", boost::program_options::value<std::string>(), "Path from where to load the asset/s"); + + _positional.add("path", 1); +} + +void ProgramOptions::add_options(const boost::program_options::options_description &options) +{ + _visible.add(options); +} + +bool ProgramOptions::wants_help() const +{ + return (_vm.count("help") != 0); +} + +std::string ProgramOptions::get_help() const +{ + std::stringstream help; + help << _visible; + + return help.str(); +} + +void ProgramOptions::parse_commandline(int argc, char **argv) +{ + boost::program_options::options_description all; + all.add(_visible).add(_hidden); + + boost::program_options::store(boost::program_options::command_line_parser(argc, argv) + .options(all) + .positional(_positional) + .allow_unregistered() + .run(), + _vm); + + if(_vm.count("help") == 0 && _vm.count("path") == 0) + { + throw boost::program_options::required_option("PATH"); + } + + boost::program_options::notify(_vm); +} +} // namespace test +} // namespace arm_compute diff --git a/tests/validation_old/ProgramOptions.h b/tests/validation_old/ProgramOptions.h new file mode 100644 index 0000000000..0b28355aa6 --- /dev/null +++ b/tests/validation_old/ProgramOptions.h @@ -0,0 +1,101 @@ +/* + * 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_PROGRAM_OPTIONS_H__ +#define __ARM_COMPUTE_TEST_PROGRAM_OPTIONS_H__ + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Weffc++" +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +#pragma GCC diagnostic ignored "-Wctor-dtor-privacy" +#include "boost/program_options.hpp" +#pragma GCC diagnostic pop + +#include <random> +#include <sstream> + +namespace arm_compute +{ +namespace test +{ +/** Defines available commandline arguments and allows to parse them. */ +class ProgramOptions +{ +public: + /** Defines available options. */ + ProgramOptions(); + + /** Signals if the --help flag has been passed on the commandline. */ + bool wants_help() const; + + /** Returns a string describing all available options. */ + std::string get_help() const; + + /** Parses the given arguments and makes them available via @ref get. + * + * @param[in] argc Number of command line arguments. + * @param[in] argv Pointer to the command line arguments. + */ + void parse_commandline(int argc, char **argv); + + /** Sets @p value if it has been specified on the command line. + * + * @note The type T has to match the type that has been specified for the + * command line option. + * + * @param[in] name Name of the option to query. + * @param[out] value Variable to which the value will be assigned. + * + * @return True if the value is assigned, false otherwise. + */ + template <typename T> + bool get(const std::string &name, T &value) const; + +protected: + /** Allows subclasses to add more specific options + * + * @param[in] options Boost object containing options and their descriptions + */ + void add_options(const boost::program_options::options_description &options); + +private: + boost::program_options::options_description _hidden{}; + boost::program_options::options_description _visible{ "Configuration options" }; + boost::program_options::positional_options_description _positional{}; + boost::program_options::variables_map _vm{}; +}; + +template <typename T> +bool ProgramOptions::get(const std::string &name, T &value) const +{ + if(_vm.count(name) != 0) + { + value = _vm[name].as<T>(); + return true; + } + + return false; +} +} // namespace test +} // namespace arm_compute +#endif /* __ARM_COMPUTE_TEST_PROGRAM_OPTIONS_H__ */ diff --git a/tests/validation_old/RawTensor.cpp b/tests/validation_old/RawTensor.cpp new file mode 100644 index 0000000000..bc2747d2a1 --- /dev/null +++ b/tests/validation_old/RawTensor.cpp @@ -0,0 +1,67 @@ +/* + * 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 "RawTensor.h" + +namespace arm_compute +{ +namespace test +{ +RawTensor::RawTensor(TensorShape shape, Format format, int fixed_point_position) + : SimpleTensor(shape, format, fixed_point_position) +{ + _buffer = support::cpp14::make_unique<uint8_t[]>(SimpleTensor::num_elements() * SimpleTensor::num_channels() * SimpleTensor::element_size()); +} + +RawTensor::RawTensor(TensorShape shape, DataType data_type, int num_channels, int fixed_point_position) + : SimpleTensor(shape, data_type, num_channels, fixed_point_position) +{ + _buffer = support::cpp14::make_unique<uint8_t[]>(SimpleTensor::num_elements() * SimpleTensor::num_channels() * SimpleTensor::element_size()); +} + +RawTensor::RawTensor(const RawTensor &tensor) + : SimpleTensor(tensor.shape(), tensor.data_type(), tensor.num_channels(), tensor.fixed_point_position()) +{ + _format = tensor.format(); + _buffer = support::cpp14::make_unique<uint8_t[]>(num_elements() * num_channels() * element_size()); + std::copy_n(tensor.data(), num_elements() * num_channels() * element_size(), _buffer.get()); +} + +RawTensor &RawTensor::operator=(RawTensor tensor) +{ + swap(*this, tensor); + + return *this; +} + +const void *RawTensor::operator()(const Coordinates &coord) const +{ + return _buffer.get() + coord2index(_shape, coord) * element_size(); +} + +void *RawTensor::operator()(const Coordinates &coord) +{ + return _buffer.get() + coord2index(_shape, coord) * element_size(); +} +} // namespace test +} // namespace arm_compute diff --git a/tests/validation_old/RawTensor.h b/tests/validation_old/RawTensor.h new file mode 100644 index 0000000000..fd0ab2b9fd --- /dev/null +++ b/tests/validation_old/RawTensor.h @@ -0,0 +1,86 @@ +/* + * 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_RAW_TENSOR_H__ +#define __ARM_COMPUTE_TEST_RAW_TENSOR_H__ + +#include "tests/SimpleTensor.h" + +namespace arm_compute +{ +namespace test +{ +/** Subclass of SimpleTensor using uint8_t as value type. + * + * Access operations (except for operator[]) will be based on the data type to + * copy the right number of elements. + */ +class RawTensor : public SimpleTensor<uint8_t> +{ +public: + /** Create an uninitialised tensor of the given @p shape and @p format. + * + * @param[in] shape Shape of the new raw tensor. + * @param[in] format Format of the new raw tensor. + * @param[in] fixed_point_position (Optional) Number of bits for the fractional part of the fixed point numbers + */ + RawTensor(TensorShape shape, Format format, int fixed_point_position = 0); + + /** Create an uninitialised tensor of the given @p shape and @p data type. + * + * @param[in] shape Shape of the new raw tensor. + * @param[in] data_type Data type of the new raw tensor. + * @param[in] num_channels (Optional) Number of channels (default = 1). + * @param[in] fixed_point_position (Optional) Number of bits for the fractional part of the fixed point numbers (default = 0). + */ + RawTensor(TensorShape shape, DataType data_type, int num_channels = 1, int fixed_point_position = 0); + + /** Create a deep copy of the given @p tensor. + * + * @param[in] tensor To be copied tensor. + */ + RawTensor(const RawTensor &tensor); + + RawTensor &operator =(RawTensor tensor); + RawTensor(RawTensor &&) = default; + ~RawTensor() = default; + + /** Read only access to the specified element. + * + * @param[in] coord Coordinates of the desired element. + * + * @return A pointer to the desired element. + */ + const void *operator()(const Coordinates &coord) const override; + + /** Access to the specified element. + * + * @param[in] coord Coordinates of the desired element. + * + * @return A pointer to the desired element. + */ + void *operator()(const Coordinates &coord) override; +}; +} // namespace test +} // namespace arm_compute +#endif /* __ARM_COMPUTE_TEST_RAW_TENSOR_H__ */ diff --git a/tests/validation_old/Reference.cpp b/tests/validation_old/Reference.cpp new file mode 100644 index 0000000000..9099820929 --- /dev/null +++ b/tests/validation_old/Reference.cpp @@ -0,0 +1,510 @@ +/* + * 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 "Reference.h" + +#include "Helpers.h" +#include "ReferenceCPP.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/validation_old/Helpers.h" + +#include <random> +#include <vector> + +using namespace arm_compute::test; + +#ifndef DOXYGEN_SKIP_THIS +namespace arm_compute +{ +namespace test +{ +namespace validation +{ +std::pair<RawTensor, RawTensor> Reference::compute_reference_sobel_3x3(const TensorShape &shape, BorderMode border_mode, uint8_t constant_border_value) +{ + // Create reference + RawTensor ref_src(shape, Format::U8); + RawTensor ref_dst_x(shape, Format::S16); + RawTensor ref_dst_y(shape, Format::S16); + + // Fill reference + library->fill_tensor_uniform(ref_src, 0); + + // Compute reference + ReferenceCPP::sobel_3x3(ref_src, ref_dst_x, ref_dst_y, border_mode, constant_border_value); + + return std::make_pair(ref_dst_x, ref_dst_y); +} + +std::pair<RawTensor, RawTensor> Reference::compute_reference_sobel_5x5(const TensorShape &shape, BorderMode border_mode, uint8_t constant_border_value) +{ + // Create reference + RawTensor ref_src(shape, Format::U8); + RawTensor ref_dst_x(shape, Format::S16); + RawTensor ref_dst_y(shape, Format::S16); + + // Fill reference + library->fill_tensor_uniform(ref_src, 0); + + // Compute reference + ReferenceCPP::sobel_5x5(ref_src, ref_dst_x, ref_dst_y, border_mode, constant_border_value); + + return std::make_pair(ref_dst_x, ref_dst_y); +} +void Reference::compute_reference_min_max_location(const TensorShape &shape, DataType dt_in, void *min, void *max, IArray<Coordinates2D> &min_loc, IArray<Coordinates2D> &max_loc, + uint32_t &min_count, uint32_t &max_count) +{ + // Create reference + RawTensor ref_src(shape, dt_in); + + // Fill reference + library->fill_tensor_uniform(ref_src, 0); + + // Compute reference + ReferenceCPP::min_max_location(ref_src, min, max, min_loc, max_loc, min_count, max_count); +} + +KeyPointArray Reference::compute_reference_harris_corners(const TensorShape &shape, float threshold, float min_dist, float sensitivity, + int32_t gradient_size, int32_t block_size, BorderMode border_mode, uint8_t constant_border_value) +{ + // Create reference + RawTensor ref_src(shape, Format::U8); + RawTensor raw_Gx(shape, (gradient_size == 7) ? Format::S32 : Format::S16); + RawTensor raw_Gy(shape, (gradient_size == 7) ? Format::S32 : Format::S16); + RawTensor raw_candidates(shape, Format::F32); + RawTensor raw_non_maxima(shape, Format::F32); + + KeyPointArray corners(shape.total_size()); + + // Fill reference + library->fill_tensor_uniform(ref_src, 0); + + // Compute reference + ReferenceCPP::harris_corners(ref_src, raw_Gx, raw_Gy, raw_candidates, raw_non_maxima, threshold, min_dist, sensitivity, gradient_size, block_size, corners, border_mode, constant_border_value); + + return corners; +} + +RawTensor Reference::compute_reference_integral_image(const TensorShape &shape) +{ + // Create reference + RawTensor ref_src(shape, DataType::U8); + RawTensor ref_dst(shape, DataType::U32); + + // Fill reference + library->fill_tensor_uniform(ref_src, 0); + + // Compute reference + ReferenceCPP::integral_image(ref_src, ref_dst); + + return ref_dst; +} + +RawTensor Reference::compute_reference_absolute_difference(const TensorShape &shape, DataType dt_in0, DataType dt_in1, DataType dt_out) +{ + // Create reference + RawTensor ref_src1(shape, dt_in0); + RawTensor ref_src2(shape, dt_in1); + RawTensor ref_dst(shape, dt_out); + + // Fill reference + library->fill_tensor_uniform(ref_src1, 0); + library->fill_tensor_uniform(ref_src2, 1); + + // Compute reference + ReferenceCPP::absolute_difference(ref_src1, ref_src2, ref_dst); + + return ref_dst; +} + +RawTensor Reference::compute_reference_accumulate(const TensorShape &shape) +{ + // Create reference + RawTensor ref_src(shape, DataType::U8); + RawTensor ref_dst(shape, DataType::S16); + + // Fill reference + library->fill_tensor_uniform(ref_src, 0); + library->fill_tensor_uniform(ref_dst, 1); + + // Compute reference + ReferenceCPP::accumulate(ref_src, ref_dst); + + return ref_dst; +} + +RawTensor Reference::compute_reference_accumulate_squared(const TensorShape &shape, uint32_t shift) +{ + // Create reference + RawTensor ref_src(shape, DataType::U8); + RawTensor ref_dst(shape, DataType::S16); + + // Fill reference + // ref_dst tensor filled with non-negative values + library->fill_tensor_uniform(ref_src, 0); + library->fill_tensor_uniform(ref_dst, 1, static_cast<int16_t>(0), std::numeric_limits<int16_t>::max()); + + // Compute reference + ReferenceCPP::accumulate_squared(ref_src, ref_dst, shift); + + return ref_dst; +} + +RawTensor Reference::compute_reference_accumulate_weighted(const TensorShape &shape, float alpha) +{ + // Create reference + RawTensor ref_src(shape, DataType::U8); + RawTensor ref_dst(shape, DataType::U8); + + // Fill reference + library->fill_tensor_uniform(ref_src, 0); + library->fill_tensor_uniform(ref_dst, 1); + + // Compute reference + ReferenceCPP::accumulate_weighted(ref_src, ref_dst, alpha); + + return ref_dst; +} + +RawTensor Reference::compute_reference_arithmetic_addition(const TensorShape &shape, DataType dt_in0, DataType dt_in1, DataType dt_out, ConvertPolicy convert_policy, int fixed_point_position) +{ + // Create reference + RawTensor ref_src1(shape, dt_in0, 1, fixed_point_position); + RawTensor ref_src2(shape, dt_in1, 1, fixed_point_position); + RawTensor ref_dst(shape, dt_out, 1, fixed_point_position); + + // Fill reference + library->fill_tensor_uniform(ref_src1, 0); + library->fill_tensor_uniform(ref_src2, 1); + + // Compute reference + ReferenceCPP::arithmetic_addition(ref_src1, ref_src2, ref_dst, convert_policy); + + return ref_dst; +} + +RawTensor Reference::compute_reference_arithmetic_subtraction(const TensorShape &shape, DataType dt_in0, DataType dt_in1, DataType dt_out, ConvertPolicy convert_policy, int fixed_point_position) +{ + // Create reference + RawTensor ref_src1(shape, dt_in0, 1, fixed_point_position); + RawTensor ref_src2(shape, dt_in1, 1, fixed_point_position); + RawTensor ref_dst(shape, dt_out, 1, fixed_point_position); + + // Fill reference + library->fill_tensor_uniform(ref_src1, 0); + library->fill_tensor_uniform(ref_src2, 1); + + // Compute reference + ReferenceCPP::arithmetic_subtraction(ref_src1, ref_src2, ref_dst, convert_policy); + + return ref_dst; +} + +RawTensor Reference::compute_reference_box3x3(const TensorShape &shape, BorderMode border_mode, uint8_t constant_border_value) +{ + // Create reference + RawTensor ref_src(shape, DataType::U8); + RawTensor ref_dst(shape, DataType::U8); + + // Fill reference + library->fill_tensor_uniform(ref_src, 0); + + // Compute reference + ReferenceCPP::box3x3(ref_src, ref_dst, border_mode, constant_border_value); + + return ref_dst; +} + +RawTensor Reference::compute_reference_depth_convert(const TensorShape &shape, DataType dt_in, DataType dt_out, ConvertPolicy policy, + uint32_t shift, uint32_t fixed_point_position_in, uint32_t fixed_point_position_out) +{ + RawTensor ref_src(shape, dt_in, 1, fixed_point_position_in); + RawTensor ref_dst(shape, dt_out, 1, fixed_point_position_out); + + // Fill reference + library->fill_tensor_uniform(ref_src, 0); + + // Compute reference + ReferenceCPP::depth_convert(ref_src, ref_dst, policy, shift); + + return ref_dst; +} + +RawTensor Reference::compute_reference_gaussian3x3(const TensorShape &shape, BorderMode border_mode, uint8_t constant_border_value) +{ + // Create reference + RawTensor ref_src(shape, DataType::U8); + RawTensor ref_dst(shape, DataType::U8); + + // Fill reference + library->fill_tensor_uniform(ref_src, 0); + + // Compute reference + ReferenceCPP::gaussian3x3(ref_src, ref_dst, border_mode, constant_border_value); + + return ref_dst; +} + +RawTensor Reference::compute_reference_gaussian5x5(const TensorShape &shape, BorderMode border_mode, uint8_t constant_border_value) +{ + // Create reference + RawTensor ref_src(shape, DataType::U8); + RawTensor ref_dst(shape, DataType::U8); + + // Fill reference + library->fill_tensor_uniform(ref_src, 0); + + // Compute reference + ReferenceCPP::gaussian5x5(ref_src, ref_dst, border_mode, constant_border_value); + + return ref_dst; +} + +RawTensor Reference::compute_reference_non_linear_filter(const TensorShape &shape, NonLinearFilterFunction function, unsigned int mask_size, + MatrixPattern pattern, const uint8_t *mask, BorderMode border_mode, uint8_t constant_border_value) +{ + // Create reference + RawTensor ref_src(shape, DataType::U8); + RawTensor ref_dst(shape, DataType::U8); + + // Fill reference + library->fill_tensor_uniform(ref_src, 0); + + // Compute reference + ReferenceCPP::non_linear_filter(ref_src, ref_dst, function, mask_size, pattern, mask, border_mode, constant_border_value); + + return ref_dst; +} + +RawTensor Reference::compute_reference_pixel_wise_multiplication(const TensorShape &shape, DataType dt_in0, DataType dt_in1, DataType dt_out, float scale, ConvertPolicy convert_policy, + RoundingPolicy rounding_policy) +{ + // Create reference + RawTensor ref_src1(shape, dt_in0); + RawTensor ref_src2(shape, dt_in1); + RawTensor ref_dst(shape, dt_out); + + // Fill reference + library->fill_tensor_uniform(ref_src1, 0); + library->fill_tensor_uniform(ref_src2, 1); + + // Compute reference + ReferenceCPP::pixel_wise_multiplication(ref_src1, ref_src2, ref_dst, scale, convert_policy, rounding_policy); + + return ref_dst; +} + +RawTensor Reference::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) +{ + // Create reference + RawTensor ref_src1(shape, dt_in0, 1, fixed_point_position); + RawTensor ref_src2(shape, dt_in1, 1, fixed_point_position); + RawTensor ref_dst(shape, dt_out, 1, fixed_point_position); + + // Fill reference + library->fill_tensor_uniform(ref_src1, 0); + library->fill_tensor_uniform(ref_src2, 1); + + // Compute reference + ReferenceCPP::fixed_point_pixel_wise_multiplication(ref_src1, ref_src2, ref_dst, scale, convert_policy, rounding_policy); + + 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(shape, dt_inout); + RawTensor ref_dst(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_src(shape, DataType::U8); + RawTensor ref_dst(shape, DataType::U8); + + // Fill reference + library->fill_tensor_uniform(ref_src, 0); + + // Compute reference + ReferenceCPP::threshold(ref_src, ref_dst, threshold, false_value, true_value, type, upper); + + return ref_dst; +} + +RawTensor Reference::compute_reference_warp_perspective(const TensorShape &shape, RawTensor &valid_mask, const float *matrix, InterpolationPolicy policy, BorderMode border_mode, + uint8_t constant_border_value) +{ + // Create reference + RawTensor ref_src(shape, DataType::U8); + RawTensor ref_dst(shape, DataType::U8); + + // Fill reference + library->fill_tensor_uniform(ref_src, 0); + + // Compute reference + ReferenceCPP::warp_perspective(ref_src, ref_dst, valid_mask, matrix, policy, border_mode, constant_border_value); + + return ref_dst; +} + +RawTensor Reference::compute_reference_batch_normalization_layer(const TensorShape &shape0, const TensorShape &shape1, DataType dt, float epsilon, int fixed_point_position) +{ + // Create reference + RawTensor ref_src(shape0, dt, 1, fixed_point_position); + RawTensor ref_dst(shape0, dt, 1, fixed_point_position); + RawTensor ref_mean(shape1, dt, 1, fixed_point_position); + RawTensor ref_var(shape1, dt, 1, fixed_point_position); + RawTensor ref_beta(shape1, dt, 1, fixed_point_position); + RawTensor ref_gamma(shape1, dt, 1, fixed_point_position); + + // Fill tensors + switch(dt) + { + case DataType::QS8: + { + const std::pair<int8_t, int8_t> bounds = get_batchnormalization_layer_test_bounds<int8_t>(fixed_point_position); + std::uniform_int_distribution<> distribution(bounds.first, bounds.second); + std::uniform_int_distribution<> distribution_var(0, bounds.second); + fill_tensors(distribution, { 0, 1, 3, 4 }, &ref_src, &ref_mean, &ref_beta, &ref_gamma); + fill_tensors(distribution_var, { 0 }, &ref_var); + break; + } + case DataType::QS16: + { + const std::pair<int16_t, int16_t> bounds = get_batchnormalization_layer_test_bounds<int16_t>(fixed_point_position); + std::uniform_int_distribution<> distribution(bounds.first, bounds.second); + std::uniform_int_distribution<> distribution_var(0, bounds.second); + fill_tensors(distribution, { 0, 1, 3, 4 }, &ref_src, &ref_mean, &ref_beta, &ref_gamma); + fill_tensors(distribution_var, { 0 }, &ref_var); + break; + } + case DataType::F16: + { + const std::pair<half_float::half, half_float::half> bounds = get_batchnormalization_layer_test_bounds<half_float::half>(); + std::uniform_real_distribution<> distribution(bounds.first, bounds.second); + std::uniform_real_distribution<> distribution_var(0, bounds.second); + fill_tensors(distribution, { 0, 1, 3, 4 }, &ref_src, &ref_mean, &ref_beta, &ref_gamma); + fill_tensors(distribution_var, { 0 }, &ref_var); + break; + } + case DataType::F32: + { + const std::pair<float, float> bounds = get_batchnormalization_layer_test_bounds<float>(); + std::uniform_real_distribution<> distribution(bounds.first, bounds.second); + std::uniform_real_distribution<> distribution_var(0, bounds.second); + fill_tensors(distribution, { 0, 1, 3, 4 }, &ref_src, &ref_mean, &ref_beta, &ref_gamma); + fill_tensors(distribution_var, { 0 }, &ref_var); + break; + } + default: + { + ARM_COMPUTE_ERROR("Not supported"); + break; + } + } + + // Compute reference + ReferenceCPP::batch_normalization_layer(ref_src, ref_dst, ref_mean, ref_var, ref_beta, ref_gamma, epsilon, fixed_point_position); + + return ref_dst; +} + +RawTensor Reference::compute_reference_roi_pooling_layer(const TensorShape &shape, DataType dt, const std::vector<ROI> &rois, const ROIPoolingLayerInfo &pool_info) +{ + TensorShape shape_dst; + shape_dst.set(0, pool_info.pooled_width()); + shape_dst.set(1, pool_info.pooled_height()); + shape_dst.set(2, shape.z()); + shape_dst.set(3, rois.size()); + + // Create reference + RawTensor ref_src(shape, dt); + RawTensor ref_dst(shape_dst, dt); + + // Fill reference + std::uniform_real_distribution<> distribution(-1, 1); + library->fill(ref_src, distribution, 0.0); + + // Compute reference + ReferenceCPP::roi_pooling_layer(ref_src, ref_dst, rois, pool_info); + + return ref_dst; +} + +RawTensor Reference::compute_reference_fixed_point_operation(const TensorShape &shape, DataType dt_in, DataType dt_out, FixedPointOp op, int fixed_point_position) +{ + // Create reference + RawTensor ref_src(shape, dt_in, 1, fixed_point_position); + RawTensor ref_dst(shape, dt_out, 1, fixed_point_position); + + // Fill reference + int min = 0; + int max = 0; + switch(op) + { + case(FixedPointOp::INV_SQRT): + min = 1; + max = (dt_in == DataType::QS8) ? 0x7F : 0x7FFF; + break; + case(FixedPointOp::LOG): + min = (1 << (fixed_point_position - 1)); + max = (dt_in == DataType::QS8) ? 0x3F : 0x3FFF; + break; + case(FixedPointOp::EXP): + min = -(1 << (fixed_point_position - 1)); + max = (1 << (fixed_point_position - 1)); + break; + case(FixedPointOp::RECIPROCAL): + min = 15; + max = (dt_in == DataType::QS8) ? 0x7F : 0x7FFF; + break; + default: + ARM_COMPUTE_ERROR("Fixed point operation not supported"); + } + std::uniform_int_distribution<> distribution(min, max); + library->fill(ref_src, distribution, 0); + + // Compute reference + ReferenceCPP::fixed_point_operation(ref_src, ref_dst, op); + + return ref_dst; +} + +} // namespace validation +} // namespace test +} // namespace arm_compute +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/Reference.h b/tests/validation_old/Reference.h new file mode 100644 index 0000000000..698b60e96b --- /dev/null +++ b/tests/validation_old/Reference.h @@ -0,0 +1,316 @@ +/* + * 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_REFERENCE_REFERENCE_H__ +#define __ARM_COMPUTE_TEST_REFERENCE_REFERENCE_H__ + +#include "RawTensor.h" +#include "Types.h" +#include "arm_compute/runtime/Array.h" + +#include <map> +#include <vector> + +namespace arm_compute +{ +namespace test +{ +namespace validation +{ +/** Interface for reference implementations. */ +class Reference +{ +public: + /** Compute reference sobel 3x3. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] border_mode Border mode to use for input tensor + * @param[in] constant_border_value Constant value to use if @p border_mode is constant + * + * @return Computed raw tensors along x and y axis. + */ + static std::pair<RawTensor, RawTensor> compute_reference_sobel_3x3(const TensorShape &shape, BorderMode border_mode, uint8_t constant_border_value); + /** Compute reference sobel 5x5. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] border_mode Border mode to use for input tensor + * @param[in] constant_border_value Constant value to use if @p border_mode is constant + * + * @return Computed raw tensors along x and y axis. + */ + static std::pair<RawTensor, RawTensor> compute_reference_sobel_5x5(const TensorShape &shape, BorderMode border_mode, uint8_t constant_border_value); + /** Compute reference Harris corners. + * + * @param[in] shape Shape of input tensor + * @param[in] threshold Minimum threshold with which to eliminate Harris Corner scores (computed using the normalized Sobel kernel). + * @param[in] min_dist Radial Euclidean distance for the euclidean distance stage + * @param[in] sensitivity Sensitivity threshold k from the Harris-Stephens equation + * @param[in] gradient_size The gradient window size to use on the input. The implementation supports 3, 5, and 7 + * @param[in] block_size The block window size used to compute the Harris Corner score. The implementation supports 3, 5, and 7. + * @param[in] border_mode Border mode to use + * @param[in] constant_border_value Constant value to use for borders if border_mode is set to CONSTANT. + * + * @return Computed corners' keypoints. + */ + static KeyPointArray compute_reference_harris_corners(const TensorShape &shape, float threshold, float min_dist, float sensitivity, + int32_t gradient_size, int32_t block_size, BorderMode border_mode, uint8_t constant_border_value); + /** Compute min max location. + * + * @param[in] shape Shape of the input tensors. + * @param[in] dt_in Data type of input tensor. + * @param[out] min Minimum value of tensor + * @param[out] max Maximum value of tensor + * @param[out] min_loc Array with locations of minimum values + * @param[out] max_loc Array with locations of maximum values + * @param[out] min_count Number of minimum values found + * @param[out] max_count Number of maximum values found + * + * @return Computed minimum, maximum values and their locations. + */ + static void compute_reference_min_max_location(const TensorShape &shape, DataType dt_in, void *min, void *max, IArray<Coordinates2D> &min_loc, IArray<Coordinates2D> &max_loc, + uint32_t &min_count, + uint32_t &max_count); + /** Compute reference integral image. + * + * @param[in] shape Shape of the input and output tensors. + * + * @return Computed raw tensor. + */ + static RawTensor compute_reference_integral_image(const TensorShape &shape); + /** Compute reference absolute difference. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] dt_in0 Data type of first input tensor. + * @param[in] dt_in1 Data type of second input tensor. + * @param[in] dt_out Data type of the output tensor. + * + * @return Computed raw tensor. + */ + static RawTensor compute_reference_absolute_difference(const TensorShape &shape, DataType dt_in0, DataType dt_in1, DataType dt_out); + /** Compute reference accumulate. + * + * @param[in] shape Shape of the input and output tensors. + * + * @return Computed raw tensor. + */ + static RawTensor compute_reference_accumulate(const TensorShape &shape); + /** Compute reference accumulate. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] shift A uint32_t value within the range of [0, 15] + * + * @return Computed raw tensor. + */ + static RawTensor compute_reference_accumulate_squared(const TensorShape &shape, uint32_t shift); + /** Compute reference accumulate. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] alpha A float value within the range of [0, 1] + * + * @return Computed raw tensor. + */ + static RawTensor compute_reference_accumulate_weighted(const TensorShape &shape, float alpha); + /** Compute reference arithmetic addition. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] dt_in0 Data type of first input tensor. + * @param[in] dt_in1 Data type of second input tensor. + * @param[in] dt_out Data type of the output tensor. + * @param[in] convert_policy Overflow policy of the operation. + * @param[in] fixed_point_position (Optional) Number of bits for the fractional part of the fixed point numbers + * + * @return Computed raw tensor. + */ + static RawTensor compute_reference_arithmetic_addition(const TensorShape &shape, DataType dt_in0, DataType dt_in1, DataType dt_out, ConvertPolicy convert_policy, int fixed_point_position = 0); + /** Compute reference arithmetic subtraction. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] dt_in0 Data type of first input tensor. + * @param[in] dt_in1 Data type of second input tensor. + * @param[in] dt_out Data type of the output tensor. + * @param[in] convert_policy Overflow policy of the operation. + * @param[in] fixed_point_position (Optional) Number of bits for the fractional part of the fixed point numbers + * + * @return Computed raw tensor. + */ + static RawTensor compute_reference_arithmetic_subtraction(const TensorShape &shape, DataType dt_in0, DataType dt_in1, DataType dt_out, ConvertPolicy convert_policy, int fixed_point_position = 0); + /** Compute reference box3x3 filter. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] border_mode BorderMode used by the input tensor. + * @param[in] constant_border_value Constant to use if @p border_mode == CONSTANT. + * + * @return Computed raw tensor. + */ + static RawTensor compute_reference_box3x3(const TensorShape &shape, BorderMode border_mode, uint8_t constant_border_value); + /** Compute reference depth convert. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] dt_in Data type of input tensor. + * @param[in] dt_out Data type of the output tensor. + * @param[in] policy Overflow policy of the operation. + * @param[in] shift Value for down/up conversions. Must be 0 <= shift < 8. + * @param[in] fixed_point_position_in (Optional) Fixed point position for the input tensor. + * @param[in] fixed_point_position_out (Optional) Fixed point position for the output tensor. + * + * @return Computed raw tensor. + */ + static RawTensor compute_reference_depth_convert(const TensorShape &shape, DataType dt_in, DataType dt_out, ConvertPolicy policy, + uint32_t shift, uint32_t fixed_point_position_in = 0, uint32_t fixed_point_position_out = 0); + /** Compute reference gaussian3x3 filter. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] border_mode BorderMode used by the input tensor + * @param[in] constant_border_value Constant to use if @p border_mode == CONSTANT + * + * @return Computed raw tensor. + */ + static RawTensor compute_reference_gaussian3x3(const TensorShape &shape, BorderMode border_mode, uint8_t constant_border_value); + /** Compute reference gaussian5x5 filter. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] border_mode BorderMode used by the input tensor. + * @param[in] constant_border_value Constant to use if @p border_mode == CONSTANT. + * + * @return Computed raw tensor. + */ + static RawTensor compute_reference_gaussian5x5(const TensorShape &shape, BorderMode border_mode, uint8_t constant_border_value); + /** Compute reference non linear filter function + * + * @param[in] shape Shape of the input and output tensors.Data type supported: U8 + * @param[in] function Non linear function to perform + * @param[in] mask_size Mask size. Supported sizes: 3, 5 + * @param[in] pattern Matrix pattern + * @param[in] mask The given mask. Will be used only if pattern is specified to PATTERN_OTHER + * @param[in] border_mode Strategy to use for borders. + * @param[in] constant_border_value (Optional) Constant value to use for borders if border_mode is set to CONSTANT. + * + * @return Computed raw tensor. + */ + static RawTensor compute_reference_non_linear_filter(const TensorShape &shape, NonLinearFilterFunction function, unsigned int mask_size, + MatrixPattern pattern, const uint8_t *mask, BorderMode border_mode, uint8_t constant_border_value = 0); + /** Compute reference pixel-wise multiplication + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] dt_in0 Data type of first input tensor. + * @param[in] dt_in1 Data type of second input tensor. + * @param[in] dt_out Data type of the output tensor. + * @param[in] scale Non-negative scale. + * @param[in] convert_policy Overflow policy of the operation. + * @param[in] rounding_policy Rounding policy of the operation. + * + * @return Computed raw tensor. + */ + static RawTensor compute_reference_pixel_wise_multiplication(const TensorShape &shape, DataType dt_in0, DataType dt_in1, DataType dt_out, float scale, ConvertPolicy convert_policy, + RoundingPolicy rounding_policy); + /** Compute reference pixel-wise multiplication. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] dt_in0 Data type of first input tensor. + * @param[in] dt_in1 Data type of second input tensor. + * @param[in] dt_out Data type of the output tensor. + * @param[in] scale Scale to apply after multiplication. Must be positive. + * @param[in] fixed_point_position Fixed point position that expresses the number of bits for the fractional part of the number. + * @param[in] convert_policy Overflow policy of the operation. + * @param[in] rounding_policy Rounding policy of the operation. + * + * @return Computed raw tensor. + */ + 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. + * @param[in] threshold Threshold. When the threshold type is RANGE, this is used as the lower threshold. + * @param[in] false_value value to set when the condition is not respected. + * @param[in] true_value value to set when the condition is respected. + * @param[in] type Thresholding type. Either RANGE or BINARY. + * @param[in] upper Upper threshold. Only used when the thresholding type is RANGE. + * + * @return Computed raw tensor. + */ + static RawTensor compute_reference_threshold(const TensorShape &shape, uint8_t threshold, uint8_t false_value, uint8_t true_value, ThresholdType type, uint8_t upper); + + /** Compute reference Warp Perspective. + * + * @param[in] shape Shape of the input and output tensors. + * @param[out] valid_mask Valid mask tensor. + * @param[in] matrix The perspective matrix. Must be 3x3 of type float. + * @param[in] policy The interpolation type. + * @param[in] border_mode Strategy to use for borders. + * @param[in] constant_border_value Constant value to use for borders if border_mode is set to CONSTANT. + * + * @return Computed raw tensor. + */ + static RawTensor compute_reference_warp_perspective(const TensorShape &shape, RawTensor &valid_mask, const float *matrix, InterpolationPolicy policy, BorderMode border_mode, + uint8_t constant_border_value); + + /** Compute reference batch normalization layer. + * + * @param[in] shape0 Shape of the input and output tensors. + * @param[in] shape1 Shape of the vector tensors. + * @param[in] dt Data type of all input and output tensors. + * @param[in] epsilon Small value to avoid division with zero. + * @param[in] fixed_point_position Fixed point position. + * + * @return Computed raw tensor. + */ + static RawTensor compute_reference_batch_normalization_layer(const TensorShape &shape0, const TensorShape &shape1, DataType dt, float epsilon, int fixed_point_position = 0); + /** Compute reference roi pooling layer. + * + * @param[in] shape Shape of the input tensor. + * @param[in] dt Data type of input and output tensors. + * @param[in] rois Region of interest vector. + * @param[in] pool_info ROI Pooling Layer information. + */ + static RawTensor compute_reference_roi_pooling_layer(const TensorShape &shape, DataType dt, const std::vector<ROI> &rois, const ROIPoolingLayerInfo &pool_info); + /** Compute reference fixed point operation. + * + * @param[in] shape Shape of the input and output tensors. + * @param[in] dt_in Data type of the input tensor. + * @param[in] dt_out Data type of the output tensor. + * @param[in] op Fixed point operation to perform. + * @param[in] fixed_point_position Number of bits for the fractional part of the fixed point numbers + * + * @return Computed raw tensor. + */ + static RawTensor compute_reference_fixed_point_operation(const TensorShape &shape, DataType dt_in, DataType dt_out, FixedPointOp op, int fixed_point_position); + +protected: + Reference() = default; + ~Reference() = default; +}; +} // namespace validation +} // namespace test +} // namespace arm_compute +#endif /* __ARM_COMPUTE_TEST_REFERENCE_REFERENCE_H__ */ diff --git a/tests/validation_old/ReferenceCPP.cpp b/tests/validation_old/ReferenceCPP.cpp new file mode 100644 index 0000000000..31c170a040 --- /dev/null +++ b/tests/validation_old/ReferenceCPP.cpp @@ -0,0 +1,294 @@ +/* + * 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 "ReferenceCPP.h" + +#include "TensorFactory.h" +#include "TensorOperations.h" +#include "TensorVisitors.h" +#include "TypePrinter.h" + +#include "arm_compute/core/Coordinates.h" +#include "arm_compute/core/Error.h" +#include "arm_compute/core/TensorInfo.h" +#include "arm_compute/core/TensorShape.h" +#include "arm_compute/runtime/Tensor.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <algorithm> +#include <functional> +#include <memory> +#include <numeric> +#include <vector> + +using namespace arm_compute::test::validation::tensor_visitors; + +namespace arm_compute +{ +namespace test +{ +namespace validation +{ +// Sobel 3x3 +void ReferenceCPP::sobel_3x3(RawTensor &src, RawTensor &dst_x, RawTensor &dst_y, BorderMode border_mode, uint8_t constant_border_value) +{ + ARM_COMPUTE_ERROR_ON(src.data_type() != DataType::U8 || dst_x.data_type() != DataType::S16 || dst_y.data_type() != DataType::S16); + Tensor<uint8_t> s(src.shape(), src.data_type(), src.fixed_point_position(), reinterpret_cast<const uint8_t *>(src.data())); + Tensor<int16_t> dx(dst_x.shape(), dst_x.data_type(), dst_x.fixed_point_position(), reinterpret_cast<int16_t *>(dst_x.data())); + Tensor<int16_t> dy(dst_y.shape(), dst_y.data_type(), dst_y.fixed_point_position(), reinterpret_cast<int16_t *>(dst_y.data())); + tensor_operations::sobel_3x3(s, dx, dy, border_mode, constant_border_value); +} + +// Sobel 5x5 +void ReferenceCPP::sobel_5x5(RawTensor &src, RawTensor &dst_x, RawTensor &dst_y, BorderMode border_mode, uint8_t constant_border_value) +{ + ARM_COMPUTE_ERROR_ON(src.data_type() != DataType::U8 || dst_x.data_type() != DataType::S16 || dst_y.data_type() != DataType::S16); + Tensor<uint8_t> s(src.shape(), src.data_type(), src.fixed_point_position(), reinterpret_cast<const uint8_t *>(src.data())); + Tensor<int16_t> dx(dst_x.shape(), dst_x.data_type(), dst_x.fixed_point_position(), reinterpret_cast<int16_t *>(dst_x.data())); + Tensor<int16_t> dy(dst_y.shape(), dst_y.data_type(), dst_y.fixed_point_position(), reinterpret_cast<int16_t *>(dst_y.data())); + tensor_operations::sobel_5x5(s, dx, dy, border_mode, constant_border_value); +} + +// Harris corners +void ReferenceCPP::harris_corners(RawTensor &src, RawTensor &Gx, RawTensor &Gy, const RawTensor &candidates, const RawTensor &non_maxima, float threshold, float min_dist, float sensitivity, + int32_t gradient_size, int32_t block_size, KeyPointArray &corners, BorderMode border_mode, uint8_t constant_border_value) +{ + ARM_COMPUTE_ERROR_ON(src.data_type() != DataType::U8 || (Gx.data_type() != DataType::S16 && Gx.data_type() != DataType::S32) || (Gy.data_type() != DataType::S16 && Gy.data_type() != DataType::S32) + || candidates.data_type() != DataType::F32 || non_maxima.data_type() != DataType::F32); + + Tensor<uint8_t> s(src.shape(), src.data_type(), src.fixed_point_position(), reinterpret_cast<const uint8_t *>(src.data())); + Tensor<float> c(candidates.shape(), candidates.data_type(), candidates.fixed_point_position(), const_cast<float *>(reinterpret_cast<const float *>(candidates.data()))); // NOLINT + Tensor<float> nm(non_maxima.shape(), non_maxima.data_type(), non_maxima.fixed_point_position(), const_cast<float *>(reinterpret_cast<const float *>(non_maxima.data()))); // NOLINT + + if(gradient_size == 7) + { + Tensor<int32_t> gx(Gx.shape(), Gx.data_type(), Gx.fixed_point_position(), reinterpret_cast<int32_t *>(Gx.data())); + Tensor<int32_t> gy(Gy.shape(), Gy.data_type(), Gy.fixed_point_position(), reinterpret_cast<int32_t *>(Gy.data())); + tensor_operations::harris_corners(s, gx, gy, c, nm, threshold, min_dist, sensitivity, gradient_size, block_size, corners, border_mode, constant_border_value); + } + else + { + Tensor<int16_t> gx(Gx.shape(), Gx.data_type(), Gx.fixed_point_position(), reinterpret_cast<int16_t *>(Gx.data())); + Tensor<int16_t> gy(Gy.shape(), Gy.data_type(), Gy.fixed_point_position(), reinterpret_cast<int16_t *>(Gy.data())); + tensor_operations::harris_corners(s, gx, gy, c, nm, threshold, min_dist, sensitivity, gradient_size, block_size, corners, border_mode, constant_border_value); + } +} + +// Minimum maximum location +void ReferenceCPP::min_max_location(const RawTensor &src, void *min, void *max, IArray<Coordinates2D> &min_loc, IArray<Coordinates2D> &max_loc, uint32_t &min_count, uint32_t &max_count) +{ + const TensorVariant s = TensorFactory::get_tensor(src); + boost::apply_visitor(tensor_visitors::min_max_location_visitor(min, max, min_loc, max_loc, min_count, max_count), s); +} + +// Absolute difference +void ReferenceCPP::absolute_difference(const RawTensor &src1, const RawTensor &src2, RawTensor &dst) +{ + const TensorVariant s1 = TensorFactory::get_tensor(src1); + const TensorVariant s2 = TensorFactory::get_tensor(src2); + TensorVariant d = TensorFactory::get_tensor(dst); + boost::apply_visitor(absolute_difference_visitor(), s1, s2, d); +} + +// Integral image +void ReferenceCPP::integral_image(const RawTensor &src, RawTensor &dst) +{ + ARM_COMPUTE_ERROR_ON(src.data_type() != DataType::U8 || dst.data_type() != DataType::U32); + const Tensor<uint8_t> s(src.shape(), src.data_type(), src.fixed_point_position(), reinterpret_cast<const uint8_t *>(src.data())); + Tensor<uint32_t> d(dst.shape(), dst.data_type(), dst.fixed_point_position(), reinterpret_cast<uint32_t *>(dst.data())); + tensor_operations::integral_image(s, d); +} + +// Accumulate +void ReferenceCPP::accumulate(const RawTensor &src, RawTensor &dst) +{ + ARM_COMPUTE_ERROR_ON(src.data_type() != DataType::U8 || dst.data_type() != DataType::S16); + const Tensor<uint8_t> s(src.shape(), src.data_type(), src.fixed_point_position(), reinterpret_cast<const uint8_t *>(src.data())); + Tensor<int16_t> d(dst.shape(), dst.data_type(), dst.fixed_point_position(), reinterpret_cast<int16_t *>(dst.data())); + tensor_operations::accumulate(s, d); +} + +// Accumulate squared +void ReferenceCPP::accumulate_squared(const RawTensor &src, RawTensor &dst, uint32_t shift) +{ + ARM_COMPUTE_ERROR_ON(src.data_type() != DataType::U8 || dst.data_type() != DataType::S16); + const Tensor<uint8_t> s(src.shape(), src.data_type(), src.fixed_point_position(), reinterpret_cast<const uint8_t *>(src.data())); + Tensor<int16_t> d(dst.shape(), dst.data_type(), dst.fixed_point_position(), reinterpret_cast<int16_t *>(dst.data())); + tensor_operations::accumulate_squared(s, d, shift); +} + +// Accumulate weighted +void ReferenceCPP::accumulate_weighted(const RawTensor &src, RawTensor &dst, float alpha) +{ + 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())); + tensor_operations::accumulate_weighted(s, d, alpha); +} + +// Arithmetic addition +void ReferenceCPP::arithmetic_addition(const RawTensor &src1, const RawTensor &src2, RawTensor &dst, ConvertPolicy convert_policy) +{ + const TensorVariant s1 = TensorFactory::get_tensor(src1); + const TensorVariant s2 = TensorFactory::get_tensor(src2); + TensorVariant d = TensorFactory::get_tensor(dst); + boost::apply_visitor(arithmetic_addition_visitor(convert_policy), s1, s2, d); +} + +// Arithmetic subtraction +void ReferenceCPP::arithmetic_subtraction(const RawTensor &src1, const RawTensor &src2, RawTensor &dst, ConvertPolicy convert_policy) +{ + const TensorVariant s1 = TensorFactory::get_tensor(src1); + const TensorVariant s2 = TensorFactory::get_tensor(src2); + TensorVariant d = TensorFactory::get_tensor(dst); + boost::apply_visitor(arithmetic_subtraction_visitor(convert_policy), s1, s2, d); +} + +// Box3x3 filter +void ReferenceCPP::box3x3(const RawTensor &src, RawTensor &dst, BorderMode border_mode, uint8_t constant_border_value) +{ + 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())); + tensor_operations::box3x3(s, d, border_mode, constant_border_value); +} + +// Depth conversion +void ReferenceCPP::depth_convert(const RawTensor &src, RawTensor &dst, ConvertPolicy policy, uint32_t shift) +{ + const TensorVariant s = TensorFactory::get_tensor(src); + TensorVariant d = TensorFactory::get_tensor(dst); + boost::apply_visitor(tensor_visitors::depth_convert_visitor(policy, shift), s, d); +} + +// Gaussian3x3 filter +void ReferenceCPP::gaussian3x3(const RawTensor &src, RawTensor &dst, BorderMode border_mode, uint8_t constant_border_value) +{ + 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())); + tensor_operations::gaussian3x3(s, d, border_mode, constant_border_value); +} + +// Gaussian5x5 filter +void ReferenceCPP::gaussian5x5(const RawTensor &src, RawTensor &dst, BorderMode border_mode, uint8_t constant_border_value) +{ + 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())); + tensor_operations::gaussian5x5(s, d, border_mode, constant_border_value); +} + +// Non linear filter +void ReferenceCPP::non_linear_filter(const RawTensor &src, RawTensor &dst, NonLinearFilterFunction function, unsigned int mask_size, + MatrixPattern pattern, const uint8_t *mask, BorderMode border_mode, uint8_t constant_border_value) +{ + 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())); + tensor_operations::non_linear_filter(s, d, function, mask_size, pattern, mask, border_mode, constant_border_value); +} + +// Pixel-wise multiplication +void ReferenceCPP::pixel_wise_multiplication(const RawTensor &src1, const RawTensor &src2, RawTensor &dst, float scale, ConvertPolicy convert_policy, RoundingPolicy rounding_policy) +{ + const TensorVariant s1 = TensorFactory::get_tensor(src1); + const TensorVariant s2 = TensorFactory::get_tensor(src2); + TensorVariant d = TensorFactory::get_tensor(dst); + boost::apply_visitor(pixel_wise_multiplication_visitor(scale, convert_policy, rounding_policy), s1, s2, d); +} + +// Fixed-point Pixel-wise multiplication +void ReferenceCPP::fixed_point_pixel_wise_multiplication(const RawTensor &src1, const RawTensor &src2, RawTensor &dst, float scale, ConvertPolicy convert_policy, RoundingPolicy rounding_policy) +{ + const TensorVariant s1 = TensorFactory::get_tensor(src1); + const TensorVariant s2 = TensorFactory::get_tensor(src2); + TensorVariant d = TensorFactory::get_tensor(dst); + 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())); + tensor_operations::threshold(s, d, threshold, false_value, true_value, type, upper); +} + +// Warp perspective +void ReferenceCPP::warp_perspective(const RawTensor &src, RawTensor &dst, RawTensor &valid_mask, const float *matrix, InterpolationPolicy policy, BorderMode border_mode, uint8_t constant_border_value) +{ + 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())); + Tensor<uint8_t> vmask(valid_mask.shape(), valid_mask.data_type(), valid_mask.fixed_point_position(), reinterpret_cast<uint8_t *>(valid_mask.data())); + tensor_operations::warp_perspective(s, d, vmask, matrix, policy, border_mode, constant_border_value); +} + +// Batch Normalization Layer +void ReferenceCPP::batch_normalization_layer(const RawTensor &src, RawTensor &dst, const RawTensor &mean, const RawTensor &var, const RawTensor &beta, const RawTensor &gamma, float epsilon, + int fixed_point_position) +{ + const TensorVariant s = TensorFactory::get_tensor(src); + TensorVariant d = TensorFactory::get_tensor(dst); + const TensorVariant m = TensorFactory::get_tensor(mean); + const TensorVariant v = TensorFactory::get_tensor(var); + const TensorVariant b = TensorFactory::get_tensor(beta); + const TensorVariant g = TensorFactory::get_tensor(gamma); + boost::apply_visitor(tensor_visitors::batch_normalization_layer_visitor(s, m, v, b, g, epsilon, fixed_point_position), d); +} + +// ROI Pooling Layer +void ReferenceCPP::roi_pooling_layer(const RawTensor &src, RawTensor &dst, const std::vector<ROI> &rois, const ROIPoolingLayerInfo &pool_info) +{ + const TensorVariant s = TensorFactory::get_tensor(src); + TensorVariant d = TensorFactory::get_tensor(dst); + boost::apply_visitor(tensor_visitors::roi_pooling_layer_visitor(s, rois, pool_info), d); +} + +// Fixed point operation +void ReferenceCPP::fixed_point_operation(const RawTensor &src, RawTensor &dst, FixedPointOp op) +{ + const TensorVariant s = TensorFactory::get_tensor(src); + TensorVariant d = TensorFactory::get_tensor(dst); + boost::apply_visitor(tensor_visitors::fixed_point_operation_visitor(s, op), d); +} + +} // namespace validation +} // namespace test +} // namespace arm_compute diff --git a/tests/validation_old/ReferenceCPP.h b/tests/validation_old/ReferenceCPP.h new file mode 100644 index 0000000000..fcc4da471d --- /dev/null +++ b/tests/validation_old/ReferenceCPP.h @@ -0,0 +1,278 @@ +/* + * 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_REFERENCE_REFERENCE_CPP_H__ +#define __ARM_COMPUTE_TEST_REFERENCE_REFERENCE_CPP_H__ + +#include "RawTensor.h" +#include "Reference.h" + +#include <map> +#include <memory> +#include <ostream> +#include <vector> + +namespace arm_compute +{ +class Tensor; + +namespace test +{ +namespace validation +{ +/** C++ reference implementation. */ +class ReferenceCPP final : public Reference +{ +public: + /** Function to compute reference sobel 3x3. + * + * @param[in] src Input tensor. + * @param[in] dst_x Result tensor along x axis + * @param[in] dst_y Result tensor along y axis + * @param[in] border_mode Border mode to use for input tensor + * @param[in] constant_border_value Constant value to use if @p border_mode is constant + * + */ + static void sobel_3x3(RawTensor &src, RawTensor &dst_x, RawTensor &dst_y, BorderMode border_mode, uint8_t constant_border_value); + /** Function to compute reference sobel 5x5. + * + * @param[in] src Input tensor. + * @param[in] dst_x Result tensor along x axis + * @param[in] dst_y Result tensor along y axis + * @param[in] border_mode Border mode to use for input tensor + * @param[in] constant_border_value Constant value to use if @p border_mode is constant + * + */ + static void sobel_5x5(RawTensor &src, RawTensor &dst_x, RawTensor &dst_y, BorderMode border_mode, uint8_t constant_border_value); + /** Function to compute reference Harris corners. + * + * @param[in] src Input tensor + * @param[in] Gx Tensor used to compute Sobel along the x axis + * @param[in] Gy Tensor used to compute Sobel along the y axis + * @param[in] candidates Tensor used to store candidate corners + * @param[in] non_maxima Tensor used to store non_maxima suppressed candidate corners + * @param[in] threshold Minimum threshold with which to eliminate Harris Corner scores (computed using the normalized Sobel kernel). + * @param[in] min_dist Radial Euclidean distance for the euclidean distance stage + * @param[in] sensitivity Sensitivity threshold k from the Harris-Stephens equation + * @param[in] gradient_size The gradient window size to use on the input. The implementation supports 3, 5, and 7 + * @param[in] block_size The block window size used to compute the Harris Corner score. The implementation supports 3, 5, and 7. + * @param[out] corners Array of keypoints to store the results. + * @param[in] border_mode Border mode to use + * @param[in] constant_border_value Constant value to use for borders if border_mode is set to CONSTANT. + * + */ + static void harris_corners(RawTensor &src, RawTensor &Gx, RawTensor &Gy, const RawTensor &candidates, const RawTensor &non_maxima, float threshold, float min_dist, float sensitivity, + int32_t gradient_size, int32_t block_size, KeyPointArray &corners, BorderMode border_mode, uint8_t constant_border_value); + /** Function to compute the min max values and their location in a tensor. + * + * @param[in] src Input tensor. + * @param[out] min Minimum value of the tensor. + * @param[out] max Maximum value of the tensor + * @param[out] min_loc Array with locations of minimum values + * @param[out] max_loc Array with locations of maximum values + * @param[out] min_count Number of minimum values found + * @param[out] max_count Number of maximum values found + */ + static void min_max_location(const RawTensor &src, void *min, void *max, IArray<Coordinates2D> &min_loc, IArray<Coordinates2D> &max_loc, uint32_t &min_count, uint32_t &max_count); + /** Function to compute the integral image of a tensor. + * + * @param[in] src Input tensor. + * @param[out] dst Result tensor. + */ + static void integral_image(const RawTensor &src, RawTensor &dst); + /** Function to compute the absolute difference between two tensors. + * + * @param[in] src1 First tensor. + * @param[in] src2 Second tensor. + * @param[out] dst Result tensor. + */ + static void absolute_difference(const RawTensor &src1, const RawTensor &src2, RawTensor &dst); + /** Function to accumulate an input tensor into an output tensor. + * + * @param[in] src Input tensor. + * @param[in, out] dst Result tensor. + */ + static void accumulate(const RawTensor &src, RawTensor &dst); + /** Function to accumulate a squared value from an input tensor to an output tensor. + * + * @param[in] src Input tensor. + * @param[in, out] dst Result tensor. + * @param[in] shift A uint32_t value within the range of [0, 15] + */ + static void accumulate_squared(const RawTensor &src, RawTensor &dst, uint32_t shift); + /** Function to accumulate a weighted value from an input tensor to an output tensor. + * + * @param[in] src Input tensor. + * @param[in, out] dst Result tensor. + * @param[in] alpha A float value within the range of [0, 1] + */ + static void accumulate_weighted(const RawTensor &src, RawTensor &dst, float alpha); + /** Arithmetic addition of @p src1 and @p src2 + * + * @param[in] src1 First tensor. + * @param[in] src2 Second tensor. + * @param[out] dst Result tensor. + * @param[in] convert_policy Overflow policy. + */ + static void arithmetic_addition(const RawTensor &src1, const RawTensor &src2, RawTensor &dst, ConvertPolicy convert_policy); + /** Arithmetic subtraction of @p src2 from @p src1 + * + * @param[in] src1 First tensor. + * @param[in] src2 Second tensor. + * @param[out] dst Result tensor. + * @param[in] convert_policy Overflow policy. + */ + static void arithmetic_subtraction(const RawTensor &src1, const RawTensor &src2, RawTensor &dst, ConvertPolicy convert_policy); + /** Function to compute box3x3 filtered result tensor. + * + * @param[in] src Input tensor. + * @param[out] dst Result tensor. + * @param[in] border_mode Border mode. + * @param[in] constant_border_value Constant border value if @p border_mode is BorderMode::CONSTANT. + */ + static void box3x3(const RawTensor &src, RawTensor &dst, BorderMode border_mode, uint8_t constant_border_value); + /** Depth conversion from @p src to @p dst + * + * @param[in] src First tensor. + * @param[out] dst Result tensor. + * @param[in] policy Overflow policy. + * @param[in] shift Value for down/up conversions. + */ + static void depth_convert(const RawTensor &src, RawTensor &dst, ConvertPolicy policy, uint32_t shift); + /** Function to compute gaussian3x3 filtered result tensor. + * + * @param[in] src Input tensor. + * @param[out] dst Result tensor. + * @param[in] border_mode Border mode + * @param[in] constant_border_value Constant border value if @p border_mode is BorderMode::CONSTANT + */ + static void gaussian3x3(const RawTensor &src, RawTensor &dst, BorderMode border_mode, uint8_t constant_border_value); + /** Function to compute gaussian5x5 filtered result tensor. + * + * @param[in] src Input tensor. + * @param[out] dst Result tensor. + * @param[in] border_mode Border mode + * @param[in] constant_border_value Constant border value if @p border_mode is BorderMode::CONSTANT + */ + static void gaussian5x5(const RawTensor &src, RawTensor &dst, BorderMode border_mode, uint8_t constant_border_value); + /** Compute non linear filter function. + * + * @param[in] src First input tensor + * @param[out] dst Output tensor + * @param[in] function Non linear function to perform + * @param[in] mask_size Mask size. Supported sizes: 3, 5 + * @param[in] pattern Matrix pattern + * @param[in] mask The given mask. + * @param[in] border_mode Strategy to use for borders. + * @param[in] constant_border_value (Optional) Constant value to use for borders if border_mode is set to CONSTANT. + */ + static void non_linear_filter(const RawTensor &src, RawTensor &dst, NonLinearFilterFunction function, unsigned int mask_size, + MatrixPattern pattern, const uint8_t *mask, BorderMode border_mode, uint8_t constant_border_value = 0); + /** Element-wise multiplication of @p src1, @p src2 and @p scale + * + * @param[in] src1 First tensor. + * @param[in] src2 Second tensor. + * @param[out] dst Result tensor. + * @param[in] scale A non-negative float multiplied to each product. + * @param[in] convert_policy Overflow policy. + * @param[in] rounding_policy Rounding policy. + */ + static void pixel_wise_multiplication(const RawTensor &src1, const RawTensor &src2, RawTensor &dst, float scale, ConvertPolicy convert_policy, RoundingPolicy rounding_policy); + /** Fixed-point Pixel-wise multiplication of @p src1 by @p src2 + * + * @param[in] src1 First tensor. + * @param[in] src2 Second tensor. + * @param[out] dst Result tensor. + * @param[in] scale A non-negative float multiplied to each product. + * @param[in] convert_policy Overflow policy. + * @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 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. + * @param[in] true_value value to set when the condition is respected. + * @param[in] type Thresholding type. Either RANGE or BINARY. + * @param[in] upper Upper threshold. Only used when the thresholding type is RANGE. + */ + static void threshold(const RawTensor &src, RawTensor &dst, uint8_t threshold, uint8_t false_value, uint8_t true_value, ThresholdType type, uint8_t upper); + /** Warp perspective of@p src to @p dst + * + * @param[in] src First tensor. + * @param[out] dst Result tensor. + * @param[out] valid_mask Valid mask tensor. + * @param[in] matrix The perspective matrix. Must be 3x3 of type float. + * @param[in] policy The interpolation type. + * @param[in] border_mode Strategy to use for borders. + * @param[in] constant_border_value Constant value to use for borders if border_mode is set to CONSTANT. + */ + static void warp_perspective(const RawTensor &src, RawTensor &dst, RawTensor &valid_mask, const float *matrix, InterpolationPolicy policy, BorderMode border_mode, uint8_t constant_border_value); + + /** Batch Normalization of @p src based on the information from @p norm_info. + * + * @param[in] src Input tensor. + * @param[out] dst Result tensor. + * @param[out] mean Mean vector tensor. + * @param[out] var Var vector tensor. + * @param[out] beta Beta vector tensor. + * @param[out] gamma Gamma vector tensor. + * @param[in] epsilon Small value to avoid division with zero. + * @param[in] fixed_point_position Fixed point position. + */ + static void batch_normalization_layer(const RawTensor &src, RawTensor &dst, const RawTensor &mean, const RawTensor &var, const RawTensor &beta, const RawTensor &gamma, float epsilon, + int fixed_point_position = 0); + /** ROI Pooling layer of @p src based on the information from @p pool_info and @p rois. + * + * @param[in] src Input tensor. + * @param[out] dst Result tensor. + * @param[in] rois Region of Interest points. + * @param[in] pool_info ROI Pooling Layer information. + */ + static void roi_pooling_layer(const RawTensor &src, RawTensor &dst, const std::vector<ROI> &rois, const ROIPoolingLayerInfo &pool_info); + /** Fixed point operations of @p src + * + * @param[in] src Input tensor. + * @param[out] dst Result tensor. + * @param[in] op Fixed point operation to perform. + */ + static void fixed_point_operation(const RawTensor &src, RawTensor &dst, FixedPointOp op); + +private: + ReferenceCPP() = delete; + ~ReferenceCPP() = delete; +}; +} // namespace validation +} // namespace test +} // namespace arm_compute +#endif /* __ARM_COMPUTE_TEST_REFERENCE_REFERENCE_CPP_H__ */ diff --git a/tests/validation_old/SConscript b/tests/validation_old/SConscript new file mode 100644 index 0000000000..fdf8e7fff8 --- /dev/null +++ b/tests/validation_old/SConscript @@ -0,0 +1,119 @@ +# 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. +import SCons +import os.path + +Import('env') +Import('vars') + +# vars is imported from arm_compute: +variables = [ + #FIXME: Remove before release! + BoolVariable("openvx", "Enable OpenVX support in tests", False), + BoolVariable("openblas", "Enable OpenBLAS support in tests", False), + #FIXME Remove before release (And remove all references to INTERNAL_ONLY) + BoolVariable("internal_only", "Enable ARM internal only tests", True), + BoolVariable("pmu", "Enable PMU counters", False), + BoolVariable("validation_tests", "Build validation test programs", True), + BoolVariable("benchmark_tests", "Build benchmark test programs", True) +] + +# We need a separate set of Variables for the Help message (Otherwise the global variables will get displayed twice) +new_options = Variables('scons') + +for v in variables: + new_options.Add(v) + vars.Add(v) + +# Clone the environment to make sure we're not polluting the arm_compute one: +old_validation_env = env.Clone() +vars.Update(old_validation_env) + +Help(new_options.GenerateHelpText(old_validation_env)) + +if old_validation_env['openblas']: + if env['os'] == 'bare_metal': + print("OpenBLAS is not supported on bare metal") + Exit(1) + old_validation_env.Append(CPPDEFINES = ['USE_OPENBLAS']) + old_validation_env.Append(LIBS = ['openblas', 'pthread']) + +if env['os'] in ['android', 'bare_metal'] or env['standalone']: + Import('arm_compute_a') + old_validation_env.Append(LIBS = [arm_compute_a]) + arm_compute_lib = arm_compute_a +else: + Import('arm_compute_so') + old_validation_env.Append(LIBS = ["arm_compute"]) + arm_compute_lib = arm_compute_so + +#FIXME Delete before release +if old_validation_env['internal_only']: + old_validation_env.Append(CPPDEFINES=['INTERNAL_ONLY']) + +old_validation_env.Append(CPPPATH = [".", "#tests", "#3rdparty/include"]) +old_validation_env.Append(LIBPATH = ["#3rdparty/%s/%s" % (env['os'], env['arch'])]) +old_validation_env.Append(LIBPATH = ["#build/%s" % env['build_dir']]) +old_validation_env.Append(LIBPATH = ["#build/%s/opencl-1.2-stubs" % env['build_dir']]) +old_validation_env.Append(LIBS = ['boost_program_options']) +old_validation_env.Append(CXXFLAGS = ['-Wno-missing-field-initializers']) +old_validation_env.Append(CPPDEFINES=['BOOST']) +old_validation_env.Append(LIBS = ['boost_unit_test_framework']) + +old_files_validation = Glob('*.cpp') + +# Add unit tests +old_files_validation += Glob('UNIT/*.cpp') +old_files_validation += Glob('UNIT/*/*.cpp') + +if env['opencl']: + Import('opencl') + + old_files_validation += Glob('CL/*.cpp') + old_files_validation += Glob('CL/*/*.cpp') + old_files_validation += Glob('system_tests/CL/*.cpp') + + old_validation_env.Append(LIBS = "OpenCL") + old_validation_env.Append(CPPDEFINES=['ARM_COMPUTE_CL']) + +#FIXME Remove before release +if old_validation_env['openvx']: + old_files_validation += Glob('VX/*.cpp') + old_files_validation += Glob('VX/*/*.cpp') + + old_validation_env.Append(LIBS = ['openvx', 'vxu']) + +if env['neon']: + old_files_validation += Glob('NEON/*.cpp') + old_files_validation += Glob('NEON/*/*.cpp') + old_files_validation += Glob('system_tests/NEON/*.cpp') + +if env['os'] == 'android': + old_validation_env.Append(LIBS = ["log"]) + +if old_validation_env['validation_tests']: + arm_compute_validation_old = old_validation_env.Program('arm_compute_validation_old', old_files_validation) + Depends(arm_compute_validation_old, arm_compute_lib) + if env['opencl']: + Depends(arm_compute_validation_old, opencl) + Default(arm_compute_validation_old) + Export('arm_compute_validation_old') diff --git a/tests/validation_old/Tensor.h b/tests/validation_old/Tensor.h new file mode 100644 index 0000000000..84d76e7143 --- /dev/null +++ b/tests/validation_old/Tensor.h @@ -0,0 +1,118 @@ +/* + * 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_TENSOR_H__ +#define __ARM_COMPUTE_TEST_TENSOR_H__ + +#include "arm_compute/core/TensorShape.h" +#include "arm_compute/core/Types.h" + +namespace arm_compute +{ +namespace test +{ +namespace validation +{ +template <typename T> +class Tensor +{ +public: + Tensor() + : _shape(), _dt(DataType::UNKNOWN), _fixed_point_position(0), _ptr(nullptr), _ptr_const(nullptr) {}; + + Tensor(TensorShape shape, DataType dt, int fixed_point_position, T *ptr) + : _shape(shape), _dt(dt), _fixed_point_position(fixed_point_position), _ptr(ptr), _ptr_const(nullptr) {}; + + Tensor(TensorShape shape, DataType dt, int fixed_point_position, const T *ptr) + : _shape(shape), _dt(dt), _fixed_point_position(fixed_point_position), _ptr(nullptr), _ptr_const(ptr) {}; + + Tensor(const Tensor &tensor) = delete; + Tensor &operator=(const Tensor &) = delete; + Tensor(Tensor &&) = default; + Tensor &operator=(Tensor &&) = default; + + ~Tensor() = default; + + T &operator[](size_t offset) + { + ARM_COMPUTE_ERROR_ON(_ptr == nullptr); + + return _ptr[offset]; + } + + const T &operator[](size_t offset) const + { + const T *ptr = (_ptr_const != nullptr) ? _ptr_const : _ptr; + + ARM_COMPUTE_ERROR_ON(ptr == nullptr); + + return ptr[offset]; // NOLINT + } + + int num_elements() const + { + return std::accumulate(_shape.cbegin(), _shape.cend(), 1, std::multiplies<int>()); + } + + TensorShape shape() const + { + return _shape; + } + + DataType data_type() const + { + return _dt; + } + + int fixed_point_position() const + { + return _fixed_point_position; + } + + const T *data() const + { + return (_ptr_const != nullptr) ? _ptr_const : _ptr; + } + + T *data() + { + return _ptr; + } + + const T *data_const() const + { + return _ptr_const; + } + +private: + TensorShape _shape; + DataType _dt; + int _fixed_point_position; + T *_ptr; + const T *_ptr_const; +}; +} // namespace validation +} // test +} // arm_compute + +#endif /* __ARM_COMPUTE_TEST_TENSOR_H__ */ diff --git a/tests/validation_old/TensorFactory.h b/tests/validation_old/TensorFactory.h new file mode 100644 index 0000000000..3f5b960927 --- /dev/null +++ b/tests/validation_old/TensorFactory.h @@ -0,0 +1,111 @@ +/* + * 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_TENSOR_FACTORY_H__ +#define __ARM_COMPUTE_TEST_TENSOR_FACTORY_H__ + +#include "arm_compute/core/Error.h" +#include "tests/RawTensor.h" +#include "tests/validation_old/Tensor.h" +#include "tests/validation_old/half.h" + +#include "tests/validation_old/boost_wrapper.h" + +namespace arm_compute +{ +namespace test +{ +namespace validation +{ +using TensorVariant = boost::variant<Tensor<uint8_t>, Tensor<int8_t>, + Tensor<uint16_t>, Tensor<int16_t>, + Tensor<uint32_t>, Tensor<int32_t>, + Tensor<half_float::half>, + Tensor<float>>; + +/** Helper to create a constant type if the passed reference is constant. */ +template <typename R, typename T> +struct match_const +{ + using type = typename std::conditional<std::is_const<typename std::remove_reference<R>::type>::value, const T, T>::type; +}; + +class TensorFactory +{ +public: + template <typename R> + static TensorVariant get_tensor(R &&raw) + { + TensorVariant v; + DataType dt = raw.data_type(); + int fixed_point_position = raw.fixed_point_position(); + auto shape = raw.shape(); + auto data = raw.data(); + + switch(dt) + { + case DataType::U8: + using value_type_u8 = typename match_const<R, uint8_t>::type; + v = Tensor<uint8_t>(shape, dt, fixed_point_position, reinterpret_cast<value_type_u8 *>(data)); + break; + case DataType::S8: + case DataType::QS8: + using value_type_s8 = typename match_const<R, int8_t>::type; + v = Tensor<int8_t>(shape, dt, fixed_point_position, reinterpret_cast<value_type_s8 *>(data)); + break; + case DataType::U16: + using value_type_u16 = typename match_const<R, uint16_t>::type; + v = Tensor<uint16_t>(shape, dt, fixed_point_position, reinterpret_cast<value_type_u16 *>(data)); + break; + case DataType::S16: + case DataType::QS16: + using value_type_s16 = typename match_const<R, int16_t>::type; + v = Tensor<int16_t>(shape, dt, fixed_point_position, reinterpret_cast<value_type_s16 *>(data)); + break; + case DataType::U32: + using value_type_u32 = typename match_const<R, uint32_t>::type; + v = Tensor<uint32_t>(shape, dt, fixed_point_position, reinterpret_cast<value_type_u32 *>(data)); + break; + case DataType::S32: + using value_type_s32 = typename match_const<R, int32_t>::type; + v = Tensor<int32_t>(shape, dt, fixed_point_position, reinterpret_cast<value_type_s32 *>(data)); + break; + case DataType::F16: + using value_type_f16 = typename match_const<R, half_float::half>::type; + v = Tensor<half_float::half>(shape, dt, fixed_point_position, reinterpret_cast<value_type_f16 *>(data)); + break; + case DataType::F32: + using value_type_f32 = typename match_const<R, float>::type; + v = Tensor<float>(shape, dt, fixed_point_position, reinterpret_cast<value_type_f32 *>(data)); + break; + default: + ARM_COMPUTE_ERROR("NOT SUPPORTED!"); + } + return v; + } +}; +} // namespace validation +} // namespace test +} // namespace arm_compute + +#endif /* __ARM_COMPUTE_TEST_TENSOR_FACTORY_H__ */ diff --git a/tests/validation_old/TensorOperations.h b/tests/validation_old/TensorOperations.h new file mode 100644 index 0000000000..48661bbab9 --- /dev/null +++ b/tests/validation_old/TensorOperations.h @@ -0,0 +1,1178 @@ +/* + * 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_TENSOR_OPERATIONS_H__ +#define __ARM_COMPUTE_TEST_TENSOR_OPERATIONS_H__ + +#include "arm_compute/core/FixedPoint.h" +#include "arm_compute/core/Helpers.h" +#include "arm_compute/core/Types.h" +#include "support/ToolchainSupport.h" +#include "tests/Types.h" +#include "tests/Utils.h" +#include "tests/validation_old/FixedPoint.h" +#include "tests/validation_old/Tensor.h" +#include "tests/validation_old/ValidationUserConfiguration.h" +#include "tests/validation_old/half.h" + +#include <algorithm> +#include <array> +#include <cmath> +#include <random> +#include <string> +#include <vector> + +namespace arm_compute +{ +namespace test +{ +namespace validation +{ +namespace tensor_operations +{ +namespace +{ +template <class T> +struct is_floating_point + : std::integral_constant < bool, + std::is_same<float, typename std::remove_cv<T>::type>::value || std::is_same<half_float::half, typename std::remove_cv<T>::type>::value + || std::is_same<double, typename std::remove_cv<T>::type>::value || std::is_same<long double, typename std::remove_cv<T>::type>::value > +{ +}; + +// Return a tensor element at a specified coordinate with different border modes +template <typename T> +T tensor_elem_at(const Tensor<T> &in, Coordinates coord, BorderMode border_mode, T constant_border_value) +{ + const int x = coord.x(); + const int y = coord.y(); + const int width = static_cast<int>(in.shape().x()); + const int height = static_cast<int>(in.shape().y()); + + // If coordinates beyond range of tensor's width or height + if(x < 0 || y < 0 || x >= width || y >= height) + { + if(border_mode == BorderMode::REPLICATE) + { + coord.set(0, std::max(0, std::min(x, width - 1))); + coord.set(1, std::max(0, std::min(y, height - 1))); + } + else + { + return constant_border_value; + } + } + + return in[coord2index(in.shape(), coord)]; +} + +/** Apply 2D spatial filter on a single element of @p in at coordinates @p coord + * + * - filter sizes have to be odd number + * - Row major order of filter assumed + * - TO_ZERO rounding policy assumed + * - SATURATE convert policy assumed + * + */ +template <typename T1, typename T2, typename T3> +void apply_2d_spatial_filter(Coordinates coord, const Tensor<T1> &in, Tensor<T3> &out, const TensorShape &filter_shape, const T2 *filter_itr, float scale, BorderMode border_mode, + T1 constant_border_value = 0) +{ + double val = 0; + const int x = coord.x(); + const int y = coord.y(); + for(int j = y - static_cast<int>(filter_shape[1] / 2); j <= y + static_cast<int>(filter_shape[1] / 2); ++j) + { + for(int i = x - static_cast<int>(filter_shape[0] / 2); i <= x + static_cast<int>(filter_shape[0] / 2); ++i) + { + coord.set(0, i); + coord.set(1, j); + val += static_cast<double>(*filter_itr) * tensor_elem_at(in, coord, border_mode, constant_border_value); + ++filter_itr; + } + } + coord.set(0, x); + coord.set(1, y); + const double rounded_val = support::cpp11::trunc(val * static_cast<double>(scale)); + out[coord2index(in.shape(), coord)] = saturate_cast<T3>(rounded_val); +} +} // namespace + +template <typename T> +T bilinear_policy(const Tensor<T> &in, Coordinates id, float xn, float yn, BorderMode border_mode, uint8_t constant_border_value) +{ + int idx = std::floor(xn); + int idy = std::floor(yn); + + const float dx = xn - idx; + const float dy = yn - idy; + const float dx_1 = 1.0f - dx; + const float dy_1 = 1.0f - dy; + + id.set(0, idx); + id.set(1, idy); + const T tl = tensor_elem_at(in, id, border_mode, constant_border_value); + id.set(0, idx + 1); + id.set(1, idy); + const T tr = tensor_elem_at(in, id, border_mode, constant_border_value); + id.set(0, idx); + id.set(1, idy + 1); + const T bl = tensor_elem_at(in, id, border_mode, constant_border_value); + id.set(0, idx + 1); + id.set(1, idy + 1); + const T br = tensor_elem_at(in, id, border_mode, constant_border_value); + + return tl * (dx_1 * dy_1) + tr * (dx * dy_1) + bl * (dx_1 * dy) + br * (dx * dy); +} + +bool valid_bilinear_policy(float xn, float yn, int width, int height, BorderMode border_mode) +{ + if(border_mode != BorderMode::UNDEFINED) + { + return true; + } + if((0 <= yn + 1) && (yn + 1 < height) && (0 <= xn + 1) && (xn + 1 < width)) + { + return true; + } + return false; +} + +// Sobel 3x3 +template <typename T1, typename T2> +void sobel_3x3(Tensor<T1> &in, Tensor<T2> &out_x, Tensor<T2> &out_y, BorderMode border_mode, uint8_t constant_border_value) +{ + const std::array<int8_t, 9> sobel_x{ { -1, 0, 1, -2, 0, 2, -1, 0, 1 } }; + const std::array<int8_t, 9> sobel_y{ { -1, -2, -1, 0, 0, 0, 1, 2, 1 } }; + + for(int element_idx = 0; element_idx < in.num_elements(); ++element_idx) + { + const Coordinates id = index2coord(in.shape(), element_idx); + + apply_2d_spatial_filter(id, in, out_x, TensorShape(3U, 3U), sobel_x.data(), 1.f, border_mode, constant_border_value); + apply_2d_spatial_filter(id, in, out_y, TensorShape(3U, 3U), sobel_y.data(), 1.f, border_mode, constant_border_value); + } +} + +// Sobel 5x5 +template <typename T1, typename T2> +void sobel_5x5(Tensor<T1> &in, Tensor<T2> &out_x, Tensor<T2> &out_y, BorderMode border_mode, uint8_t constant_border_value) +{ + const std::array<int8_t, 25> sobel_x{ { + -1, -2, 0, 2, 1, + -4, -8, 0, 8, 4, + -6, -12, 0, 12, 6, + -4, -8, 0, 8, 4, + -1, -2, 0, 2, 1 + } }; + + const std::array<int8_t, 25> sobel_y{ { + -1, -4, -6, -4, -1, + -2, -8, -12, -8, -2, + 0, 0, 0, 0, 0, + 2, 8, 12, 8, 2, + 1, 4, 6, 4, 1 + } }; + + for(int element_idx = 0; element_idx < in.num_elements(); ++element_idx) + { + const Coordinates id = index2coord(in.shape(), element_idx); + + apply_2d_spatial_filter(id, in, out_x, TensorShape(5U, 5U), sobel_x.data(), 1.f, border_mode, constant_border_value); + apply_2d_spatial_filter(id, in, out_y, TensorShape(5U, 5U), sobel_y.data(), 1.f, border_mode, constant_border_value); + } +} + +// Sobel 7x7 +template <typename T1, typename T2> +void sobel_7x7(Tensor<T1> &in, Tensor<T2> &out_x, Tensor<T2> &out_y, BorderMode border_mode, uint8_t constant_border_value) +{ + const std::array<int8_t, 49> sobel_x{ { + -1, -4, -5, 0, 5, 4, 1, + -6, -24, -30, 0, 30, 24, 6, + -15, -60, -75, 0, 75, 60, 15, + -20, -80, -100, 0, 100, 80, 20, + -15, -60, -75, 0, 75, 60, 15, + -6, -24, -30, 0, 30, 24, 6, + -1, -4, -5, 0, 5, 4, 1 + } }; + + const std::array<int8_t, 49> sobel_y{ { + -1, -6, -15, -20, -15, -6, -1, + -4, -24, -60, -80, -60, -24, -4, + -5, -30, -75, -100, -75, -30, -5, + 0, 0, 0, 0, 0, 0, 0, + 5, 30, 75, 100, 75, 30, 5, + 4, 24, 60, 80, 60, 24, 4, + 1, 6, 15, 20, 15, 6, 1 + } }; + + for(int element_idx = 0; element_idx < in.num_elements(); ++element_idx) + { + const Coordinates id = index2coord(in.shape(), element_idx); + + apply_2d_spatial_filter(id, in, out_x, TensorShape(7U, 7U), sobel_x.data(), 1.f, border_mode, constant_border_value); + apply_2d_spatial_filter(id, in, out_y, TensorShape(7U, 7U), sobel_y.data(), 1.f, border_mode, constant_border_value); + } +} + +template <typename T> +void non_maxima_suppression_3x3(Tensor<T> &in, Tensor<T> &out, BorderMode border_mode) +{ + for(int i = 0; i < in.num_elements(); ++i) + { + Coordinates coord = index2coord(in.shape(), i); + int x = coord.x(); + int y = coord.y(); + + if(in[i] >= tensor_elem_at(in, Coordinates(x - 1, y - 1), border_mode, 0.f) && in[i] >= tensor_elem_at(in, Coordinates(x, y - 1), border_mode, 0.f) + && in[i] >= tensor_elem_at(in, Coordinates(x + 1, y - 1), border_mode, 0.f) && in[i] >= tensor_elem_at(in, Coordinates(x - 1, y), border_mode, 0.f) + && in[i] > tensor_elem_at(in, Coordinates(x + 1, y), border_mode, 0.f) && in[i] > tensor_elem_at(in, Coordinates(x - 1, y + 1), border_mode, 0.f) + && in[i] > tensor_elem_at(in, Coordinates(x, y + 1), border_mode, 0.f) && in[i] > tensor_elem_at(in, Coordinates(x + 1, y + 1), border_mode, 0.f)) + { + out[i] = in[i]; + } + else + { + out[i] = 0; + } + } +} + +// Harris corners +template <typename T1, typename T2, typename T3> +void harris_corners(Tensor<T1> &in, Tensor<T2> &Gx, Tensor<T2> &Gy, Tensor<T3> &candidates, Tensor<T3> &non_maxima, float threshold, float min_dist, float sensitivity, + int32_t gradient_size, int32_t block_size, KeyPointArray &corners, BorderMode border_mode, uint8_t constant_border_value) +{ + ARM_COMPUTE_ERROR_ON(block_size != 3 && block_size != 5 && block_size != 7); + + ValidRegion valid_region = shape_to_valid_region(candidates.shape()); + float norm_factor = 0.f; + + // Sobel + switch(gradient_size) + { + case 3: + sobel_3x3(in, Gx, Gy, border_mode, constant_border_value); + norm_factor = 1.f / (4 * 255 * block_size); + break; + case 5: + sobel_5x5(in, Gx, Gy, border_mode, constant_border_value); + norm_factor = 1.f / (16 * 255 * block_size); + break; + case 7: + sobel_7x7(in, Gx, Gy, border_mode, constant_border_value); + norm_factor = 1.f / (64 * 255 * block_size); + break; + default: + ARM_COMPUTE_ERROR("Gradient size not supported."); + } + + //Calculate scores + for(int i = 0; i < in.num_elements(); ++i) + { + Coordinates in_coord = index2coord(in.shape(), i); + + float Gx2 = 0; + float Gy2 = 0; + float Gxy = 0; + + // Calculate Gx^2, Gy^2 and Gxy within the given window + for(int y = in_coord.y() - block_size / 2; y <= in_coord.y() + block_size / 2; ++y) + { + for(int x = in_coord.x() - block_size / 2; x <= in_coord.x() + block_size / 2; ++x) + { + Coordinates block_coord(x, y); + + float norm_gx = tensor_elem_at(Gx, block_coord, border_mode, static_cast<T2>(constant_border_value)) * norm_factor; + float norm_gy = tensor_elem_at(Gy, block_coord, border_mode, static_cast<T2>(constant_border_value)) * norm_factor; + + Gx2 += std::pow(norm_gx, 2); + Gy2 += std::pow(norm_gy, 2); + Gxy += norm_gx * norm_gy; + } + } + + float trace2 = std::pow(Gx2 + Gy2, 2); + float det = Gx2 * Gy2 - std::pow(Gxy, 2); + float response = det - sensitivity * trace2; + + if(response > threshold) + { + candidates[i] = response; + } + else + { + candidates[i] = 0.f; + } + } + + // Update valid region and remove candidates on borders for border_mode == UNDEFINED + if(border_mode == BorderMode::UNDEFINED) + { + valid_region = shape_to_valid_region(candidates.shape(), true, BorderSize((gradient_size / 2) + (block_size / 2))); + + for(int i = 0; i < candidates.num_elements(); ++i) + { + if(!is_in_valid_region(valid_region, index2coord(candidates.shape(), i))) + { + candidates[i] = 0.f; + } + } + } + + // Suppress non-maxima candidates + non_maxima_suppression_3x3(candidates, non_maxima, border_mode != BorderMode::UNDEFINED ? BorderMode::CONSTANT : BorderMode::UNDEFINED); + if(border_mode == BorderMode::UNDEFINED) + { + valid_region = shape_to_valid_region(non_maxima.shape(), true, BorderSize((gradient_size / 2) + (block_size / 2) + 1)); + } + + // Create vector of candidate corners + KeyPointArray candidates_vector(corners.max_num_values()); + for(int i = 0; i < non_maxima.num_elements(); ++i) + { + Coordinates coord = index2coord(non_maxima.shape(), i); + + if(non_maxima[i] != 0.f && is_in_valid_region(valid_region, coord)) + { + KeyPoint corner; + corner.x = coord.x(); + corner.y = coord.y(); + corner.tracking_status = 1; + corner.strength = non_maxima[i]; + + corner.scale = 0.f; + corner.orientation = 0.f; + corner.error = 0.f; + + candidates_vector.push_back(corner); + } + } + + // If there are any candidates, sort them by strength and add them to the output corners vector if there are no stronger corners within the given euclidean radius + if(candidates_vector.num_values() > 0) + { + std::sort(candidates_vector.buffer(), candidates_vector.buffer() + candidates_vector.num_values(), [](KeyPoint a, KeyPoint b) + { + return a.strength > b.strength; + }); + corners.push_back(candidates_vector.at(0)); + + for(size_t j = 0; j < candidates_vector.num_values(); ++j) + { + bool found = false; + int32_t x = candidates_vector.at(j).x; + int32_t y = candidates_vector.at(j).y; + + for(size_t i = 0; i < corners.num_values(); ++i) + { + int32_t corners_x = corners.at(i).x; + int32_t corners_y = corners.at(i).y; + + // Euclidean distance + if(std::sqrt((std::pow(x - corners_x, 2) + std::pow(y - corners_y, 2))) < min_dist) + { + found = true; + } + } + + // If no stronger corners within the given euclidean radius + if(!found) + { + corners.push_back(candidates_vector.at(j)); + } + } + } +} + +template <typename T> +void compute_min_max(const Tensor<T> &in, void *min, void *max) +{ + using type = typename std::conditional<std::is_same<T, float>::value, float, int32_t>::type; + + // Set min and max to first pixel + type tmp_min = static_cast<type>(in[0]); + type tmp_max = static_cast<type>(in[0]); + + // Look for min and max values + for(int i = 1; i < in.num_elements(); ++i) + { + if(static_cast<type>(in[i]) < tmp_min) + { + tmp_min = static_cast<type>(in[i]); + } + if(static_cast<type>(in[i]) > tmp_max) + { + tmp_max = static_cast<type>(in[i]); + } + } + + *static_cast<type *>(min) = tmp_min; + *static_cast<type *>(max) = tmp_max; +} + +// Min max location +template <typename T1> +void min_max_location(const Tensor<T1> &in, void *min, void *max, IArray<Coordinates2D> &min_loc, IArray<Coordinates2D> &max_loc, uint32_t &min_count, uint32_t &max_count) +{ + const size_t width = in.shape().x(); + + compute_min_max(in, min, max); + + using type = typename std::conditional<std::is_same<T1, float>::value, float, int32_t>::type; + + type min_value = *static_cast<type *>(min); + type max_value = *static_cast<type *>(max); + + min_count = 0; + max_count = 0; + for(int i = 0; i < in.num_elements(); ++i) + { + if(static_cast<type>(in[i]) == min_value) + { + Coordinates2D min_coord; + min_coord.x = static_cast<int32_t>(i % width); + min_coord.y = static_cast<int32_t>(i / width); + + min_loc.push_back(min_coord); + + min_count++; + } + if(static_cast<type>(in[i]) == max_value) + { + Coordinates2D max_coord; + max_coord.x = static_cast<int32_t>(i % width); + max_coord.y = static_cast<int32_t>(i / width); + + max_loc.push_back(max_coord); + + max_count++; + } + } +} + +// Integral Image +void integral_image(const Tensor<uint8_t> &in, Tensor<uint32_t> &out) +{ + // Length of dimensions + const size_t width = in.shape().x(); + const size_t height = in.shape().y(); + const size_t depth = in.shape().z() * in.shape()[3] * in.shape()[4] * in.shape()[5]; + + const size_t image_size = width * height; + + for(size_t z = 0; z < depth; ++z) + { + size_t current_image = z * image_size; + + //First element of each image + out[current_image] = in[current_image]; + + // First row of each image (add only pixel on the left) + for(size_t x = 1; x < width; ++x) + { + out[current_image + x] = static_cast<uint32_t>(in[current_image + x]) + out[current_image + x - 1]; + } + + // Subsequent rows + for(size_t y = 1; y < height; ++y) + { + size_t current_row = current_image + (width * y); + + // First element of each row (add only pixel up) + out[current_row] = static_cast<uint32_t>(in[current_row]) + out[current_row - width]; + + // Following row elements + for(size_t x = 1; x < width; ++x) + { + size_t current_pixel = current_row + x; + + // out = in + up(out) + left(out) - up_left(out) + out[current_pixel] = static_cast<uint32_t>(in[current_pixel]) + out[current_pixel - 1] + + out[current_pixel - width] - out[current_pixel - width - 1]; + } + } + } +} + +// Absolute difference +template <typename T1, typename T2, typename T3> +void absolute_difference(const Tensor<T1> &in1, const Tensor<T2> &in2, Tensor<T3> &out) +{ + using intermediate_type = typename common_promoted_signed_type<T1, T2, T3>::intermediate_type; + + for(int i = 0; i < in1.num_elements(); ++i) + { + intermediate_type val(std::abs(static_cast<intermediate_type>(in1[i]) - static_cast<intermediate_type>(in2[i]))); + out[i] = saturate_cast<T3>(val); + } +} + +// Accumulate +template <typename T1, typename T2> +void accumulate(const Tensor<T1> &in, Tensor<T2> &out) +{ + using intermediate_type = typename common_promoted_signed_type<T1, T2>::intermediate_type; + + for(int i = 0; i < in.num_elements(); ++i) + { + intermediate_type val = static_cast<intermediate_type>(out[i]) + static_cast<intermediate_type>(in[i]); + out[i] = saturate_cast<T2>(val); + } +} + +// Accumulate squared +template <typename T1, typename T2> +void accumulate_squared(const Tensor<T1> &in, Tensor<T2> &out, uint32_t shift) +{ + if(shift > 15) + { + ARM_COMPUTE_ERROR("Shift in accumulate_squared must be within the range [0, 15]"); + } + using intermediate_type = typename common_promoted_signed_type<T1, T2>::intermediate_type; + intermediate_type denom = 1 << shift; + + for(int i = 0; i < in.num_elements(); ++i) + { + intermediate_type val = static_cast<intermediate_type>(out[i]) + (static_cast<intermediate_type>(in[i]) * static_cast<intermediate_type>(in[i]) / denom); + out[i] = saturate_cast<T2>(val); + } +} + +// Accumulate weighted total_size = init_auto_padding(tensor_shape, num_channels, type); +template <typename T> +void accumulate_weighted(const Tensor<T> &in, Tensor<T> &out, float alpha) +{ + if(alpha < 0.f || alpha > 1.f) + { + ARM_COMPUTE_ERROR("Weight (alpha) specified in accumulate_weighted must be within the range [0, 1]"); + } + using intermediate_type = typename common_promoted_signed_type<T>::intermediate_type; + + for(int i = 0; i < in.num_elements(); ++i) + { + double val = (1. - static_cast<double>(alpha)) * static_cast<intermediate_type>(out[i]) + static_cast<double>(alpha) * static_cast<intermediate_type>(in[i]); + out[i] = static_cast<T>(val); + } +} + +// Arithmetic addition +template <typename T1, typename T2, typename T3> +void arithmetic_addition(const Tensor<T1> &in1, const Tensor<T2> &in2, Tensor<T3> &out, ConvertPolicy convert_policy) +{ + using intermediate_type = typename common_promoted_signed_type<T1, T2, T3>::intermediate_type; + + for(int i = 0; i < in1.num_elements(); ++i) + { + intermediate_type val = static_cast<intermediate_type>(in1[i]) + static_cast<intermediate_type>(in2[i]); + out[i] = (convert_policy == ConvertPolicy::SATURATE) ? saturate_cast<T3>(val) : static_cast<T3>(val); + } +} + +// Arithmetic Subtraction +template <typename T1, typename T2, typename T3> +void arithmetic_subtraction(const Tensor<T1> &in1, const Tensor<T2> &in2, Tensor<T3> &out, ConvertPolicy convert_policy) +{ + using intermediate_type = typename common_promoted_signed_type<T1, T2, T3>::intermediate_type; + + for(int i = 0; i < in1.num_elements(); ++i) + { + intermediate_type val = static_cast<intermediate_type>(in1[i]) - static_cast<intermediate_type>(in2[i]); + out[i] = (convert_policy == ConvertPolicy::SATURATE) ? saturate_cast<T3>(val) : static_cast<T3>(val); + } +} + +// Box3x3 filter +template <typename T, typename = typename std::enable_if<std::is_integral<T>::value>::type> +void box3x3(const Tensor<T> &in, Tensor<T> &out, BorderMode border_mode, T constant_border_value) +{ + const std::array<T, 9> filter{ { 1, 1, 1, 1, 1, 1, 1, 1, 1 } }; + float scale = 1.f / static_cast<float>(filter.size()); + for(int element_idx = 0; element_idx < in.num_elements(); ++element_idx) + { + const Coordinates id = index2coord(in.shape(), element_idx); + apply_2d_spatial_filter(id, in, out, TensorShape(3U, 3U), filter.data(), scale, border_mode, constant_border_value); + } +} + +// Depth conversion +template < typename T1, typename T2, typename std::enable_if < std::is_integral<T1>::value &&is_floating_point<T2>::value, int >::type = 0 > +void depth_convert(const Tensor<T1> &in, Tensor<T2> &out, ConvertPolicy policy, uint32_t shift) +{ + using namespace fixed_point_arithmetic; + + const int fixed_point_position = in.fixed_point_position(); + for(int i = 0; i < in.num_elements(); ++i) + { + out[i] = static_cast<float>(fixed_point<T1>(in[i], fixed_point_position, true)); + } +} + +template < typename T1, typename T2, typename std::enable_if < is_floating_point<T1>::value &&std::is_integral<T2>::value, int >::type = 0 > +void depth_convert(const Tensor<T1> &in, Tensor<T2> &out, ConvertPolicy policy, uint32_t shift) +{ + using namespace fixed_point_arithmetic; + + const int fixed_point_position = out.fixed_point_position(); + for(int i = 0; i < in.num_elements(); ++i) + { + out[i] = fixed_point<T2>(in[i], fixed_point_position).raw(); + } +} + +template < typename T1, typename T2, typename std::enable_if < std::is_integral<T1>::value &&std::is_integral<T2>::value &&!std::is_same<T1, T2>::value, int >::type = 0 > +void depth_convert(const Tensor<T1> &in, Tensor<T2> &out, ConvertPolicy policy, uint32_t shift) +{ + // Up-casting + if(std::numeric_limits<T1>::digits <= std::numeric_limits<T2>::digits) + { + for(int i = 0; i < in.num_elements(); ++i) + { + out[i] = static_cast<T2>(in[i]) << shift; + } + } + // Down-casting + else + { + for(int i = 0; i < in.num_elements(); ++i) + { + T1 val = in[i] >> shift; + out[i] = ((policy == ConvertPolicy::SATURATE) ? saturate_cast<T2>(val) : static_cast<T2>(val)); + } + } +} + +template < typename T1, typename T2, typename std::enable_if < std::is_integral<T1>::value &&std::is_integral<T2>::value &&std::is_same<T1, T2>::value, int >::type = 0 > +void depth_convert(const Tensor<T1> &in, Tensor<T2> &out, ConvertPolicy policy, uint32_t shift) +{ + using namespace fixed_point_arithmetic; + bool is_in_place = (&in == &out); + + const int fixed_point_position_in = in.fixed_point_position(); + const int fixed_point_position_out = (is_in_place) ? static_cast<int>(shift) : out.fixed_point_position(); + + if(!is_in_place || (fixed_point_position_in != fixed_point_position_out)) + { + for(int i = 0; i < in.num_elements(); ++i) + { + auto x = fixed_point<T2>(in[i], fixed_point_position_in, true); + x.rescale(fixed_point_position_out); + out[i] = x.raw(); + } + } +} + +template < typename T1, typename T2, typename std::enable_if < is_floating_point<T1>::value &&is_floating_point<T2>::value, int >::type = 0 > +void depth_convert(const Tensor<T1> &in, Tensor<T2> &out, ConvertPolicy policy, uint32_t shift) +{ + for(int i = 0; i < in.num_elements(); ++i) + { + out[i] = static_cast<T2>(in[i]); + } +} + +// Gaussian3x3 filter +template <typename T, typename = typename std::enable_if<std::is_integral<T>::value>::type> +void gaussian3x3(const Tensor<T> &in, Tensor<T> &out, BorderMode border_mode, T constant_border_value) +{ + const std::array<T, 9> filter{ { 1, 2, 1, 2, 4, 2, 1, 2, 1 } }; + const float scale = 1.f / 16.f; + for(int element_idx = 0; element_idx < in.num_elements(); ++element_idx) + { + const Coordinates id = index2coord(in.shape(), element_idx); + apply_2d_spatial_filter(id, in, out, TensorShape(3U, 3U), filter.data(), scale, border_mode, constant_border_value); + } +} + +// Gaussian5x5 filter +template <typename T, typename = typename std::enable_if<std::is_integral<T>::value>::type> +void gaussian5x5(const Tensor<T> &in, Tensor<T> &out, BorderMode border_mode, T constant_border_value) +{ + const std::array<T, 25> filter{ { + 1, 4, 6, 4, 1, + 4, 16, 24, 16, 4, + 6, 24, 36, 24, 6, + 4, 16, 24, 16, 4, + 1, 4, 6, 4, 1 + } }; + const float scale = 1.f / 256.f; + for(int element_idx = 0; element_idx < in.num_elements(); ++element_idx) + { + const Coordinates id = index2coord(in.shape(), element_idx); + apply_2d_spatial_filter(id, in, out, TensorShape(5U, 5U), filter.data(), scale, border_mode, constant_border_value); + } +} + +// Non linear filter +template <typename T> +void non_linear_filter(const Tensor<T> &in, Tensor<T> &out, NonLinearFilterFunction function, unsigned int mask_size, + MatrixPattern pattern, const uint8_t *mask, BorderMode border_mode, uint8_t constant_border_value) +{ + ARM_COMPUTE_ERROR_ON(pattern == MatrixPattern::OTHER && mask == nullptr); + + using intermediate_type = typename common_promoted_signed_type<T>::intermediate_type; + + const int sq_mask_size = mask_size * mask_size; + const int half_mask_size = mask_size / 2; + std::vector<intermediate_type> vals(sq_mask_size); + intermediate_type current_value = 0; + + const ValidRegion valid_region = shape_to_valid_region(in.shape(), border_mode == BorderMode::UNDEFINED, BorderSize(half_mask_size)); + + for(int element_idx = 0, count = 0, index = 0; element_idx < in.num_elements(); ++element_idx, count = 0, index = 0) + { + Coordinates id = index2coord(in.shape(), element_idx); + if(is_in_valid_region(valid_region, id)) + { + int idx = id.x(); + int idy = id.y(); + for(int y = idy - half_mask_size; y <= idy + half_mask_size; ++y) + { + for(int x = idx - half_mask_size; x <= idx + half_mask_size; ++x, ++index) + { + id.set(0, x); + id.set(1, y); + current_value = tensor_elem_at(in, id, border_mode, constant_border_value); + + if(mask[index] == 255) + { + vals[count] = static_cast<intermediate_type>(current_value); + ++count; + } + } + } + std::sort(vals.begin(), vals.begin() + count); + switch(function) + { + case NonLinearFilterFunction::MIN: + out[element_idx] = saturate_cast<T>(vals[0]); + break; + case NonLinearFilterFunction::MAX: + out[element_idx] = saturate_cast<T>(vals[count - 1]); + break; + case NonLinearFilterFunction::MEDIAN: + out[element_idx] = saturate_cast<T>(vals[count / 2]); + break; + default: + ARM_COMPUTE_ERROR("Unsupported NonLinearFilter function."); + } + } + } +} + +// Pixel-wise multiplication +template <typename T1, typename T2, typename T3> +void pixel_wise_multiplication(const Tensor<T1> &in1, const Tensor<T2> &in2, Tensor<T3> &out, float scale, ConvertPolicy convert_policy, RoundingPolicy rounding_policy) +{ + if(scale < 0) + { + ARM_COMPUTE_ERROR("Scale of pixel-wise multiplication must be non-negative"); + } + using intermediate_type = typename common_promoted_signed_type<T1, T2, T3>::intermediate_type; + for(int i = 0; i < in1.num_elements(); ++i) + { + double val = static_cast<intermediate_type>(in1[i]) * static_cast<intermediate_type>(in2[i]) * static_cast<double>(scale); + if(is_floating_point<T3>::value) + { + out[i] = val; + } + else + { + double rounded_val = 0; + switch(rounding_policy) + { + case(RoundingPolicy::TO_ZERO): + rounded_val = support::cpp11::trunc(val); + break; + case(RoundingPolicy::TO_NEAREST_UP): + rounded_val = round_half_up(val); + break; + case(RoundingPolicy::TO_NEAREST_EVEN): + rounded_val = round_half_even(val); + break; + default: + ARM_COMPUTE_ERROR("Unsupported rounding policy"); + } + out[i] = (convert_policy == ConvertPolicy::SATURATE) ? saturate_cast<T3>(rounded_val) : static_cast<T3>(rounded_val); + } + } +} + +// Fixed-point Pixel-wise Multiplication +template <typename T, typename = typename std::enable_if<std::is_integral<T>::value>::type> +void fixed_point_pixel_wise_multiplication(const Tensor<T> &in1, const Tensor<T> &in2, Tensor<T> &out, float scale, ConvertPolicy convert_policy, RoundingPolicy rounding_policy) +{ + using namespace fixed_point_arithmetic; + + const int fixed_point_position = in1.fixed_point_position(); + + ARM_COMPUTE_ERROR_ON_MSG(in1.data_type() != in2.data_type() || in1.data_type() != out.data_type(), + "Tensors must all have the same DataType"); + ARM_COMPUTE_ERROR_ON_MSG(fixed_point_position != in2.fixed_point_position() || fixed_point_position != out.fixed_point_position(), + "Fixed-point position must be the same for both inputs and outputs"); + + // Validate fixed_point_position + ARM_COMPUTE_ERROR_ON((in1.data_type() == DataType::QS8) && (fixed_point_position == 0 || fixed_point_position > 7)); + ARM_COMPUTE_ERROR_ON((in1.data_type() == DataType::QS16) && (fixed_point_position == 0 || fixed_point_position > 15)); + + const fixed_point<T> fp_scale(scale, fixed_point_position); + const bool is_sat = convert_policy == ConvertPolicy::SATURATE; + + for(int i = 0; i < in1.num_elements(); ++i) + { + const fixed_point<T> val1(in1[i], fixed_point_position, true); + fixed_point<T> res(in2[i], fixed_point_position, true); + if(is_sat) + { + res = mul(mul(res, val1), fp_scale); + } + else + { + res = mul<OverflowPolicy::WRAP>(mul<OverflowPolicy::WRAP>(res, val1), fp_scale); + } + out[i] = res.raw(); + } +} + +//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) +{ + switch(type) + { + case ThresholdType::BINARY: + for(int i = 0; i < in.num_elements(); ++i) + { + out[i] = ((in[i] > threshold) ? true_value : false_value); + } + break; + case ThresholdType::RANGE: + for(int i = 0; i < in.num_elements(); ++i) + { + if(in[i] > upper) + { + out[i] = false_value; + } + else if(in[i] < threshold) + { + out[i] = false_value; + } + else + { + out[i] = true_value; + } + } + break; + default: + ARM_COMPUTE_ERROR("Thresholding type not recognised"); + break; + } +} + +// Warp Perspective +template <typename T> +void warp_perspective(const Tensor<T> &in, Tensor<T> &out, Tensor<T> &valid_mask, const float *matrix, InterpolationPolicy policy, BorderMode border_mode, uint8_t constant_border_value) +{ + // x0 = M00 * x + M01 * y + M02 + // y0 = M10 * x + M11 * y + M12 + // z0 = M20 * x + M21 * y + M22 + // xn = x0 / z0 + // yn = y0 / z0 + const float M00 = matrix[0]; + const float M10 = matrix[1]; + const float M20 = matrix[2]; + const float M01 = matrix[0 + 1 * 3]; + const float M11 = matrix[1 + 1 * 3]; + const float M21 = matrix[2 + 1 * 3]; + const float M02 = matrix[0 + 2 * 3]; + const float M12 = matrix[1 + 2 * 3]; + const float M22 = matrix[2 + 2 * 3]; + + const int width = in.shape().x(); + const int height = in.shape().y(); + + for(int element_idx = 0; element_idx < in.num_elements(); ++element_idx) + { + valid_mask[element_idx] = 1; + Coordinates id = index2coord(in.shape(), element_idx); + int idx = id.x(); + int idy = id.y(); + const float z0 = M20 * idx + M21 * idy + M22; + + float x0 = (M00 * idx + M01 * idy + M02); + float y0 = (M10 * idx + M11 * idy + M12); + + float xn = x0 / z0; + float yn = y0 / z0; + id.set(0, static_cast<int>(std::floor(xn))); + id.set(1, static_cast<int>(std::floor(yn))); + if((0 <= yn) && (yn < height) && (0 <= xn) && (xn < width)) + { + switch(policy) + { + case InterpolationPolicy::NEAREST_NEIGHBOR: + out[element_idx] = tensor_elem_at(in, id, border_mode, constant_border_value); + break; + case InterpolationPolicy::BILINEAR: + (valid_bilinear_policy(xn, yn, width, height, border_mode)) ? out[element_idx] = bilinear_policy(in, id, xn, yn, border_mode, constant_border_value) : valid_mask[element_idx] = 0; + break; + case InterpolationPolicy::AREA: + default: + ARM_COMPUTE_ERROR("Interpolation not supported"); + } + } + else + { + if(border_mode == BorderMode::UNDEFINED) + { + valid_mask[element_idx] = 0; + } + else + { + switch(policy) + { + case InterpolationPolicy::NEAREST_NEIGHBOR: + if(border_mode == BorderMode::CONSTANT) + { + out[element_idx] = constant_border_value; + } + else if(border_mode == BorderMode::REPLICATE) + { + id.set(0, std::max(0, std::min(static_cast<int>(xn), width - 1))); + id.set(1, std::max(0, std::min(static_cast<int>(yn), height - 1))); + out[element_idx] = in[coord2index(in.shape(), id)]; + } + break; + case InterpolationPolicy::BILINEAR: + out[element_idx] = bilinear_policy(in, id, xn, yn, border_mode, constant_border_value); + break; + case InterpolationPolicy::AREA: + default: + ARM_COMPUTE_ERROR("Interpolation not supported"); + } + } + } + } +} + +// Batch Normalization Layer for fixed point type +template <typename T, typename std::enable_if<std::is_integral<T>::value, int>::type * = nullptr> +void batch_normalization_layer(const Tensor<T> &in, Tensor<T> &out, const Tensor<T> &mean, const Tensor<T> &var, const Tensor<T> &beta, const Tensor<T> &gamma, float epsilon, int fixed_point_position) +{ + const int cols = static_cast<int>(in.shape()[0]); + const int rows = static_cast<int>(in.shape()[1]); + const int depth = static_cast<int>(in.shape()[2]); + int upper_dims = in.shape().total_size() / (cols * rows * depth); + + for(int r = 0; r < upper_dims; ++r) + { + for(int i = 0; i < depth; ++i) + { + for(int k = 0; k < rows; ++k) + { + for(int l = 0; l < cols; ++l) + { + const int pos = l + k * cols + i * rows * cols + r * cols * rows * depth; + fixed_point_arithmetic::fixed_point<T> in_qs(in[pos], fixed_point_position, true); + fixed_point_arithmetic::fixed_point<T> var_qs(var[i], fixed_point_position, true); + fixed_point_arithmetic::fixed_point<T> mean_qs(mean[i], fixed_point_position, true); + fixed_point_arithmetic::fixed_point<T> beta_qs(beta[i], fixed_point_position, true); + fixed_point_arithmetic::fixed_point<T> gamma_qs(gamma[i], fixed_point_position, true); + fixed_point_arithmetic::fixed_point<T> epsilon_qs(epsilon, fixed_point_position); + + auto denominator = fixed_point_arithmetic::inv_sqrt(var_qs + epsilon_qs); + auto numerator = in_qs - mean_qs; + auto x_bar = numerator * denominator; + x_bar = beta_qs + x_bar * gamma_qs; + out[pos] = x_bar.raw(); + } + } + } + } +} + +// Batch Normalization Layer for floating point type +template <typename T, typename std::enable_if<is_floating_point<T>::value, int>::type * = nullptr> +void batch_normalization_layer(const Tensor<T> &in, Tensor<T> &out, const Tensor<T> &mean, const Tensor<T> &var, const Tensor<T> &beta, const Tensor<T> &gamma, float epsilon, int fixed_point_position) +{ + const int cols = static_cast<int>(in.shape()[0]); + const int rows = static_cast<int>(in.shape()[1]); + const int depth = static_cast<int>(in.shape()[2]); + int upper_dims = in.shape().total_size() / (cols * rows * depth); + + for(int r = 0; r < upper_dims; ++r) + { + for(int i = 0; i < depth; ++i) + { + for(int k = 0; k < rows; ++k) + { + for(int l = 0; l < cols; ++l) + { + const int pos = l + k * cols + i * rows * cols + r * cols * rows * depth; + const float denominator = sqrt(var[i] + epsilon); + const float numerator = in[pos] - mean[i]; + const float x_bar = numerator / denominator; + out[pos] = beta[i] + x_bar * gamma[i]; + } + } + } + } +} + +// ROI Pooling layer +template <typename T> +void roi_pooling_layer(const Tensor<T> &in, Tensor<T> &out, const std::vector<ROI> &rois, const ROIPoolingLayerInfo &pool_info) +{ + const int num_rois = rois.size(); + const int width_in = in.shape().x(); + const int height_in = in.shape().y(); + const int fms = in.shape().z(); + const int volume_in = width_in * height_in * fms; + const int pool_w = pool_info.pooled_width(); + const int pool_h = pool_info.pooled_height(); + const int volume_out = pool_w * pool_h * fms; + const float roi_scale = pool_info.spatial_scale(); + + // Iterate through all rois + for(int roi_idx = 0; roi_idx < num_rois; ++roi_idx) + { + // Get dimensions of current ROI + const ROI &roi = rois[roi_idx]; + + int batch_id = roi.batch_idx; + int roi_start_x = support::cpp11::round(roi.rect.x * roi_scale); + int roi_start_y = support::cpp11::round(roi.rect.y * roi_scale); + int roi_width = std::max(support::cpp11::round(roi.rect.width * roi_scale), 1.f); + int roi_height = std::max(support::cpp11::round(roi.rect.height * roi_scale), 1.f); + + // Determine pooling regions + float pool_region_size_x = static_cast<float>(roi_width) / pool_w; + float pool_region_size_y = static_cast<float>(roi_height) / pool_h; + + // Iterate through all channel + for(int fm = 0; fm < fms; ++fm) + { + // Calculate each output pixel + for(int py = 0; py < pool_h; ++py) + { + for(int px = 0; px < pool_w; ++px) + { + int region_start_x = static_cast<int>(std::floor(px * pool_region_size_x)); + int region_end_x = static_cast<int>(std::ceil((px + 1) * pool_region_size_x)); + int region_start_y = static_cast<int>(std::floor(py * pool_region_size_y)); + int region_end_y = static_cast<int>(std::ceil((py + 1) * pool_region_size_y)); + + region_start_x = std::min(std::max(region_start_x + roi_start_x, 0), width_in); + region_end_x = std::min(std::max(region_end_x + roi_start_x, 0), width_in); + region_start_y = std::min(std::max(region_start_y + roi_start_y, 0), height_in); + region_end_y = std::min(std::max(region_end_y + roi_start_y, 0), height_in); + + // Iterate through each pixel in the pooling region + if((region_end_x <= region_start_x) || (region_end_y <= region_start_y)) + { + out[roi_idx * volume_out + fm * pool_w * pool_h + py * pool_w + px] = 0; + } + else + { + T curr_max = std::numeric_limits<T>::lowest(); + for(int j = region_start_y; j < region_end_y; ++j) + { + for(int i = region_start_x; i < region_end_x; ++i) + { + const auto val = in[batch_id * volume_in + fm * width_in * height_in + j * width_in + i]; + curr_max = std::max(val, curr_max); + } + } + out[roi_idx * volume_out + fm * pool_w * pool_h + py * pool_w + px] = curr_max; + } + } + } + } + } +} + +// Fixed point operations +template <typename T> +void fixed_point_operation(const Tensor<T> &in, Tensor<T> &out, FixedPointOp op) +{ + int p = in.fixed_point_position(); + switch(op) + { + case FixedPointOp::EXP: + for(int i = 0; i < in.num_elements(); ++i) + { + out[i] = fixed_point_arithmetic::exp(fixed_point_arithmetic::fixed_point<T>(in[i], p, true)).raw(); + } + break; + case FixedPointOp::LOG: + for(int i = 0; i < in.num_elements(); ++i) + { + out[i] = fixed_point_arithmetic::log(fixed_point_arithmetic::fixed_point<T>(in[i], p, true)).raw(); + } + break; + case FixedPointOp::INV_SQRT: + for(int i = 0; i < in.num_elements(); ++i) + { + out[i] = fixed_point_arithmetic::inv_sqrt(fixed_point_arithmetic::fixed_point<T>(in[i], p, true)).raw(); + } + break; + case FixedPointOp::RECIPROCAL: + for(int i = 0; i < in.num_elements(); ++i) + { + out[i] = fixed_point_arithmetic::div(fixed_point_arithmetic::fixed_point<T>(1, p), fixed_point_arithmetic::fixed_point<T>(in[i], p, true)).raw(); + } + break; + default: + ARM_COMPUTE_ERROR("Fixed point operation not supported"); + break; + } +} + +// Tensor print +template <typename T> +void print(const Tensor<T> &in, std::ostream &out) +{ + out << "\n"; + for(int i = 0; i < in.num_elements(); ++i) + { + out << in[i] << " "; + } + out << "\n"; +} +} // namespace tensor_operations +} // namespace validation +} // namespace test +} // namespace arm_compute + +#endif /* __ARM_COMPUTE_TEST_TENSOR_OPERATIONS_H__ */ diff --git a/tests/validation_old/TensorVisitors.h b/tests/validation_old/TensorVisitors.h new file mode 100644 index 0000000000..6e5f8c3b21 --- /dev/null +++ b/tests/validation_old/TensorVisitors.h @@ -0,0 +1,306 @@ +/* + * 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_TENSOR_VISITORS_H__ +#define __ARM_COMPUTE_TEST_TENSOR_VISITORS_H__ + +#include "Tensor.h" +#include "TensorOperations.h" +#include "arm_compute/core/Error.h" +#include "arm_compute/core/Helpers.h" +#include "arm_compute/runtime/Lut.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <algorithm> +#include <map> +#include <memory> +#include <ostream> +#include <vector> + +namespace arm_compute +{ +namespace test +{ +namespace validation +{ +namespace tensor_visitors +{ +// Min max location visitor +struct min_max_location_visitor : public boost::static_visitor<> +{ +public: + explicit min_max_location_visitor(void *min, void *max, IArray<Coordinates2D> &min_loc, IArray<Coordinates2D> &max_loc, uint32_t &min_count, uint32_t &max_count) + : _min(min), _max(max), _min_loc(min_loc), _max_loc(max_loc), _min_count(min_count), _max_count(max_count) + { + } + template <typename T1> + void operator()(const Tensor<T1> &in) const + { + tensor_operations::min_max_location(in, _min, _max, _min_loc, _max_loc, _min_count, _max_count); + } + +private: + void *_min; + void *_max; + IArray<Coordinates2D> &_min_loc; + IArray<Coordinates2D> &_max_loc; + uint32_t &_min_count; + uint32_t &_max_count; +}; +// Absolute Difference visitor +struct absolute_difference_visitor : public boost::static_visitor<> +{ +public: + template <typename T1, typename T2, typename T3> + void operator()(const Tensor<T1> &in1, const Tensor<T2> &in2, Tensor<T3> &out) const + { + tensor_operations::absolute_difference(in1, in2, out); + } +}; +// Arithmetic Addition visitor +struct arithmetic_addition_visitor : public boost::static_visitor<> +{ +public: + explicit arithmetic_addition_visitor(ConvertPolicy convert_policy) + : _policy(convert_policy) + { + } + + template <typename T1, typename T2, typename T3> + void operator()(const Tensor<T1> &in1, const Tensor<T2> &in2, Tensor<T3> &out) const + { + tensor_operations::arithmetic_addition(in1, in2, out, _policy); + } + +private: + ConvertPolicy _policy; +}; +// Arithmetic Subtraction visitor +struct arithmetic_subtraction_visitor : public boost::static_visitor<> +{ +public: + explicit arithmetic_subtraction_visitor(ConvertPolicy convert_policy) + : _policy(convert_policy) + { + } + + template <typename T1, typename T2, typename T3> + void operator()(const Tensor<T1> &in1, const Tensor<T2> &in2, Tensor<T3> &out) const + { + tensor_operations::arithmetic_subtraction(in1, in2, out, _policy); + } + +private: + ConvertPolicy _policy; +}; +// Depth Convert visitor +struct depth_convert_visitor : public boost::static_visitor<> +{ +public: + explicit depth_convert_visitor(ConvertPolicy policy, uint32_t shift) + : _policy(policy), _shift(shift) + { + } + + template <typename T1, typename T2> + void operator()(const Tensor<T1> &in, Tensor<T2> &out) const + { + tensor_operations::depth_convert(in, out, _policy, _shift); + } + +private: + ConvertPolicy _policy; + uint32_t _shift; +}; +// Pixel-wise Multiplication visitor +struct pixel_wise_multiplication_visitor : public boost::static_visitor<> +{ +public: + explicit pixel_wise_multiplication_visitor(float scale, ConvertPolicy convert_policy, RoundingPolicy rounding_policy) + : _scale(scale), _convert_policy(convert_policy), _rounding_policy(rounding_policy) + { + } + + template <typename T1, typename T2, typename T3> + void operator()(const Tensor<T1> &in1, const Tensor<T2> &in2, Tensor<T3> &out) const + { + tensor_operations::pixel_wise_multiplication(in1, in2, out, _scale, _convert_policy, _rounding_policy); + } + +private: + float _scale; + ConvertPolicy _convert_policy; + RoundingPolicy _rounding_policy; +}; +// Fixed Point Pixel-wise Multiplication visitor +struct fixed_point_pixel_wise_multiplication_visitor : public boost::static_visitor<> +{ +public: + explicit fixed_point_pixel_wise_multiplication_visitor(const TensorVariant &in1, const TensorVariant &in2, float scale, ConvertPolicy convert_policy, RoundingPolicy rounding_policy) + : _in1(in1), _in2(in2), _scale(scale), _convert_policy(convert_policy), _rounding_policy(rounding_policy) + { + } + + template <typename T, typename = typename std::enable_if<std::is_integral<T>::value>::type> + void operator()(Tensor<T> &out) const + { + const Tensor<T> &in1 = boost::get<Tensor<T>>(_in1); + const Tensor<T> &in2 = boost::get<Tensor<T>>(_in2); + tensor_operations::fixed_point_pixel_wise_multiplication(in1, in2, out, _scale, _convert_policy, _rounding_policy); + } + template < typename T, typename std::enable_if < !std::is_integral<T>::value, int >::type = 0 > + void operator()(Tensor<T> &out) const + { + ARM_COMPUTE_ERROR("NOT SUPPORTED!"); + } + +private: + const TensorVariant &_in1; + const TensorVariant &_in2; + float _scale; + ConvertPolicy _convert_policy; + RoundingPolicy _rounding_policy; +}; +// Table lookup operation +template <typename T1> +struct table_lookup : public boost::static_visitor<> +{ +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>; + +// Batch Normalization Layer visitor +struct batch_normalization_layer_visitor : public boost::static_visitor<> +{ +public: + explicit batch_normalization_layer_visitor(const TensorVariant &in, const TensorVariant &mean, const TensorVariant &var, const TensorVariant &beta, const TensorVariant &gamma, float epsilon, + int fixed_point_position = 0) + : _in(in), _mean(mean), _var(var), _beta(beta), _gamma(gamma), _epsilon(epsilon), _fixed_point_position(fixed_point_position) + { + } + + template <typename T> + void operator()(Tensor<T> &out) const + { + const Tensor<T> &in = boost::get<Tensor<T>>(_in); + const Tensor<T> &mean = boost::get<Tensor<T>>(_mean); + const Tensor<T> &var = boost::get<Tensor<T>>(_var); + const Tensor<T> &beta = boost::get<Tensor<T>>(_beta); + const Tensor<T> &gamma = boost::get<Tensor<T>>(_gamma); + tensor_operations::batch_normalization_layer(in, out, mean, var, beta, gamma, _epsilon, _fixed_point_position); + } + +private: + const TensorVariant &_in, &_mean, &_var, &_beta, &_gamma; + float _epsilon; + int _fixed_point_position; +}; + +// ROI Pooling layer +struct roi_pooling_layer_visitor : public boost::static_visitor<> +{ +public: + explicit roi_pooling_layer_visitor(const TensorVariant &in, const std::vector<ROI> &rois, ROIPoolingLayerInfo pool_info) + : _in(in), _rois(rois), _pool_info(pool_info) + { + } + + template <typename T> + void operator()(Tensor<T> &out) const + { + const Tensor<T> &in = boost::get<Tensor<T>>(_in); + tensor_operations::roi_pooling_layer(in, out, _rois, _pool_info); + } + +private: + const TensorVariant &_in; + const std::vector<ROI> &_rois; + ROIPoolingLayerInfo _pool_info; +}; + +// Fixed Point operations visitor +struct fixed_point_operation_visitor : public boost::static_visitor<> +{ +public: + explicit fixed_point_operation_visitor(const TensorVariant &in, FixedPointOp op) + : _in(in), _op(op) + { + } + + template <typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0> + void operator()(Tensor<T> &out) const + { + const Tensor<T> &in = boost::get<Tensor<T>>(_in); + tensor_operations::fixed_point_operation(in, out, _op); + } + template < typename T, typename std::enable_if < !std::is_integral<T>::value, int >::type = 0 > + void operator()(Tensor<T> &out) const + { + ARM_COMPUTE_ERROR("NOT SUPPORTED!"); + } + +private: + const TensorVariant &_in; + FixedPointOp _op; +}; +// Print Tensor visitor +struct print_visitor : public boost::static_visitor<> +{ +public: + explicit print_visitor(std::ostream &out) + : _out(out) + { + } + + template <typename T> + void operator()(const Tensor<T> &in) const + { + tensor_operations::print(in, _out); + } + +private: + std::ostream &_out; +}; +} // namespace tensor_visitors +} // namespace validation +} // namespace test +} // namespace arm_compute + +#endif /* __ARM_COMPUTE_TEST_TENSOR_VISITORS_H__ */ diff --git a/tests/validation_old/UNIT/FixedPoint.cpp b/tests/validation_old/UNIT/FixedPoint.cpp new file mode 100644 index 0000000000..53fef97769 --- /dev/null +++ b/tests/validation_old/UNIT/FixedPoint.cpp @@ -0,0 +1,164 @@ +/* + * 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 "tests/validation_old/FixedPoint.h" + +#include "TypePrinter.h" +#include "Utils.h" +#include "support/ToolchainSupport.h" +#include "tests/validation_old/Validation.h" +#include "tests/validation_old/ValidationUserConfiguration.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <fstream> +#include <vector> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +std::string func_names[] = +{ + "add", "sub", "mul", "exp", "log", "inv_sqrt" +}; +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(UNIT) +BOOST_AUTO_TEST_SUITE(FixedPoint) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(FixedPointQS8Inputs, boost::unit_test::data::make(func_names) * boost::unit_test::data::xrange(1, 7), func_name, frac_bits) +{ + const std::string base_file_name = user_config.path.get() + "/dumps/" + func_name + "_Q8." + support::cpp11::to_string(frac_bits); + std::ifstream inputs_file{ base_file_name + ".in", std::ios::binary | std::ios::in }; + + BOOST_TEST_INFO(base_file_name + ".in"); + BOOST_TEST_REQUIRE(inputs_file.good()); + + float float_val = 0.f; + + // Read first value + inputs_file.read(reinterpret_cast<char *>(&float_val), sizeof(float_val)); + + while(inputs_file.good()) + { + // Convert to fixed point + fixed_point_arithmetic::fixed_point<int8_t> in_val(float_val, frac_bits); + + // Check that the value didn't change + BOOST_TEST(static_cast<float>(in_val) == float_val); + + // Read next value + inputs_file.read(reinterpret_cast<char *>(&float_val), sizeof(float_val)); + } +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +//FIXME: Figure out how to handle expected failures properly +// The last input argument specifies the expected number of failures for a +// given combination of (function name, number of fractional bits) as defined +// by the first two arguments. +BOOST_DATA_TEST_CASE(FixedPointQS8Outputs, (boost::unit_test::data::make(func_names) * boost::unit_test::data::xrange(1, 7)) ^ (boost::unit_test::data::make({ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 13, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 33, 96 })), + func_name, frac_bits, expected_failures) +{ + const std::string base_file_name = user_config.path.get() + "/dumps/" + func_name + "_Q8." + support::cpp11::to_string(frac_bits); + std::ifstream inputs_file{ base_file_name + ".in", std::ios::binary | std::ios::in }; + std::ifstream reference_file{ base_file_name + ".out", std::ios::binary | std::ios::in }; + + BOOST_TEST_INFO(base_file_name + ".in"); + BOOST_TEST_REQUIRE(inputs_file.good()); + BOOST_TEST_INFO(base_file_name + ".out"); + BOOST_TEST_REQUIRE(reference_file.good()); + + const float step_size = std::pow(2.f, -frac_bits); + + float float_val = 0.f; + float ref_val = 0.f; + int64_t num_mismatches = 0; + + // Read first values + inputs_file.read(reinterpret_cast<char *>(&float_val), sizeof(float_val)); + reference_file.read(reinterpret_cast<char *>(&ref_val), sizeof(ref_val)); + + while(inputs_file.good() && reference_file.good()) + { + fixed_point_arithmetic::fixed_point<int8_t> in_val(float_val, frac_bits); + fixed_point_arithmetic::fixed_point<int8_t> out_val(0.f, frac_bits); + + float tolerance = 0.f; + + if(func_name == "add") + { + out_val = in_val + in_val; + } + else if(func_name == "sub") + { + out_val = in_val - in_val; //NOLINT + } + else if(func_name == "mul") + { + tolerance = 1.f * step_size; + out_val = in_val * in_val; + } + else if(func_name == "exp") + { + tolerance = 2.f * step_size; + out_val = fixed_point_arithmetic::exp(in_val); + } + else if(func_name == "log") + { + tolerance = 4.f * step_size; + out_val = fixed_point_arithmetic::log(in_val); + } + else if(func_name == "inv_sqrt") + { + tolerance = 5.f * step_size; + out_val = fixed_point_arithmetic::inv_sqrt(in_val); + } + + if(std::abs(static_cast<float>(out_val) - ref_val) > tolerance) + { + BOOST_TEST_INFO("input = " << in_val); + BOOST_TEST_INFO("output = " << out_val); + BOOST_TEST_INFO("reference = " << ref_val); + BOOST_TEST_INFO("tolerance = " << tolerance); + BOOST_TEST_WARN((std::abs(static_cast<float>(out_val) - ref_val) <= tolerance)); + + ++num_mismatches; + } + + // Read next values + inputs_file.read(reinterpret_cast<char *>(&float_val), sizeof(float_val)); + reference_file.read(reinterpret_cast<char *>(&ref_val), sizeof(ref_val)); + } + + BOOST_TEST(num_mismatches == expected_failures); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/UNIT/TensorInfo.cpp b/tests/validation_old/UNIT/TensorInfo.cpp new file mode 100644 index 0000000000..f2a3acfee0 --- /dev/null +++ b/tests/validation_old/UNIT/TensorInfo.cpp @@ -0,0 +1,91 @@ +/* + * 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 "TypePrinter.h" +#include "tests/validation_old/Validation.h" + +#include "arm_compute/core/TensorInfo.h" +#include "arm_compute/core/Types.h" + +#include "tests/validation_old/boost_wrapper.h" + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(UNIT) +BOOST_AUTO_TEST_SUITE(TensorInfoValidation) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(AutoPadding, + boost::unit_test::data::make({ TensorShape{}, + TensorShape{ 10U }, + TensorShape{ 10U, 10U }, + TensorShape{ 10U, 10U, 10U }, + TensorShape{ 10U, 10U, 10U, 10U }, + TensorShape{ 10U, 10U, 10U, 10U, 10U }, + TensorShape{ 10U, 10U, 10U, 10U, 10U, 10U } + }) + ^ boost::unit_test::data::make({ PaddingSize{ 0, 0, 0, 0 }, + PaddingSize{ 0, 36, 0, 4 }, + PaddingSize{ 4, 36, 4, 4 }, + PaddingSize{ 4, 36, 4, 4 }, + PaddingSize{ 4, 36, 4, 4 }, + PaddingSize{ 4, 36, 4, 4 }, + PaddingSize{ 4, 36, 4, 4 } + }) + ^ boost::unit_test::data::make({ Strides{}, + Strides{ 1U }, + Strides{ 1U, 50U }, + Strides{ 1U, 50U, 900U }, + Strides{ 1U, 50U, 900U, 9000U }, + Strides{ 1U, 50U, 900U, 9000U, 90000U }, + Strides{ 1U, 50U, 900U, 9000U, 90000U, 900000U } + }) + ^ boost::unit_test::data::make( +{ + 0, + 4, + 204, + 204, + 204, + 204, + 204, +}), +shape, auto_padding, strides, offset) +{ + TensorInfo info{ shape, Format::U8 }; + + BOOST_TEST(!info.has_padding()); + + info.auto_padding(); + + validate(info.padding(), auto_padding); + BOOST_TEST(compare_dimensions(info.strides_in_bytes(), strides)); + BOOST_TEST(info.offset_first_element_in_bytes() == offset); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/UNIT/TensorShape.cpp b/tests/validation_old/UNIT/TensorShape.cpp new file mode 100644 index 0000000000..dc75b93de4 --- /dev/null +++ b/tests/validation_old/UNIT/TensorShape.cpp @@ -0,0 +1,70 @@ +/* + * 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 "TypePrinter.h" +#include "tests/validation_old/Validation.h" + +#include "arm_compute/core/TensorShape.h" + +#include "tests/validation_old/boost_wrapper.h" + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(UNIT) +BOOST_AUTO_TEST_SUITE(TensorShapeValidation) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(Construction, + boost::unit_test::data::make({ TensorShape{}, + TensorShape{ 1U }, + TensorShape{ 2U }, + TensorShape{ 2U, 3U }, + TensorShape{ 2U, 3U, 5U }, + TensorShape{ 2U, 3U, 5U, 7U }, + TensorShape{ 2U, 3U, 5U, 7U, 11U }, + TensorShape{ 2U, 3U, 5U, 7U, 11U, 13U } + }) + ^ boost::unit_test::data::make({ 0, 0, 1, 2, 3, 4, 5, 6 }) ^ boost::unit_test::data::make({ 0, 1, 2, 6, 30, 210, 2310, 30030 }), + shape, num_dimensions, total_size) +{ + BOOST_TEST(shape.num_dimensions() == num_dimensions); + BOOST_TEST(shape.total_size() == total_size); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(SetEmpty, boost::unit_test::data::make({ 0, 1, 2, 3, 4, 5 }), dimension) +{ + TensorShape shape; + + shape.set(dimension, 10); + + BOOST_TEST(shape.num_dimensions() == dimension + 1); + BOOST_TEST(shape.total_size() == 10); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/UNIT/Utils.cpp b/tests/validation_old/UNIT/Utils.cpp new file mode 100644 index 0000000000..b302bf27c1 --- /dev/null +++ b/tests/validation_old/UNIT/Utils.cpp @@ -0,0 +1,94 @@ +/* + * 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 "Utils.h" + +#include "TypePrinter.h" +#include "tests/validation_old/Validation.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <stdexcept> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(UNIT) +BOOST_AUTO_TEST_SUITE(Utils) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RoundHalfUp, boost::unit_test::data::make({ 1.f, 1.2f, 1.5f, 2.5f, 2.9f, -3.f, -3.5f, -3.8f, -4.3f, -4.5f }) ^ boost::unit_test::data::make({ 1.f, 1.f, 2.f, 3.f, 3.f, -3.f, -3.f, -4.f, -4.f, -4.f }), + value, result) +{ + BOOST_TEST(round_half_up(value) == result); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(RoundHalfEven, boost::unit_test::data::make({ 1.f, 1.2f, 1.5f, 2.5f, 2.9f, -3.f, -3.5f, -3.8f, -4.3f, -4.5f }) ^ boost::unit_test::data::make({ 1.f, 1.f, 2.f, 2.f, 3.f, -3.f, -4.f, -4.f, -4.f, -4.f }), + value, result) +{ + BOOST_TEST(round_half_even(value) == result); +} + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(Index2Coord, boost::unit_test::data::make({ TensorShape{ 1U }, TensorShape{ 2U }, TensorShape{ 2U, 3U } }) ^ boost::unit_test::data::make({ 0, 1, 2 }) ^ + boost::unit_test::data::make({ Coordinates{ 0 }, Coordinates{ 1 }, Coordinates{ 0, 1 } }), shape, index, ref_coordinate) +{ + Coordinates coordinate = index2coord(shape, index); + + BOOST_TEST(compare_dimensions(coordinate, ref_coordinate)); +} + +//FIXME: Negative tests only work in debug mode +#if 0 +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(Index2CoordFail, boost::unit_test::data::make({ TensorShape{}, TensorShape{ 2U }, TensorShape{ 2U } }) ^ boost::unit_test::data::make({ 0, -1, 2 }), shape, index) +{ + BOOST_CHECK_THROW(index2coord(shape, index), std::runtime_error); +} +#endif /* 0 */ + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(Coord2Index, boost::unit_test::data::make({ TensorShape{ 1U }, TensorShape{ 2U }, TensorShape{ 2U, 3U } }) ^ boost::unit_test::data::make({ Coordinates{ 0 }, Coordinates{ 1 }, Coordinates{ 0, 1 } }) + ^ boost::unit_test::data::make({ 0, 1, 2 }), + shape, coordinate, ref_index) +{ + int index = coord2index(shape, coordinate); + + BOOST_TEST(index == ref_index); +} + +//FIXME: Negative tests only work in debug mode +#if 0 +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit") * boost::unit_test::label("nightly")) +BOOST_DATA_TEST_CASE(Coord2IndexFail, boost::unit_test::data::make({ TensorShape{}, TensorShape{ 2U } }) ^ boost::unit_test::data::make({ Coordinates{ 0 }, Coordinates{} }), shape, coordinate) +{ + BOOST_CHECK_THROW(coord2index(shape, coordinate), std::runtime_error); +} +#endif /* 0 */ + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ diff --git a/tests/validation_old/UserConfiguration.cpp b/tests/validation_old/UserConfiguration.cpp new file mode 100644 index 0000000000..a24de90468 --- /dev/null +++ b/tests/validation_old/UserConfiguration.cpp @@ -0,0 +1,55 @@ +/* + * 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 "UserConfiguration.h" + +#include "ProgramOptions.h" + +#include <string> + +namespace arm_compute +{ +namespace test +{ +UserConfiguration::UserConfiguration(const ProgramOptions &options) +{ + std::random_device::result_type tmp_seed = 0; + if(options.get("seed", tmp_seed)) + { + seed = tmp_seed; + } + + std::string tmp_path; + if(options.get("path", tmp_path)) + { + path = tmp_path; + } + + unsigned int tmp_threads = 0; + if(options.get("threads", tmp_threads)) + { + threads = tmp_threads; + } +} +} // namespace test +} // namespace arm_compute diff --git a/tests/validation_old/UserConfiguration.h b/tests/validation_old/UserConfiguration.h new file mode 100644 index 0000000000..815da04810 --- /dev/null +++ b/tests/validation_old/UserConfiguration.h @@ -0,0 +1,136 @@ +/* + * 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_USER_CONFIGURATION_H__ +#define __ARM_COMPUTE_TEST_USER_CONFIGURATION_H__ + +#include "arm_compute/core/Error.h" +#include "arm_compute/core/Types.h" + +#include <random> +#include <string> + +namespace arm_compute +{ +namespace test +{ +class ProgramOptions; + +/** Container providing easy access to runtime options provided by the user. */ +struct UserConfiguration +{ +protected: + /** Wrapper around options to store if an option has been set. */ + template <typename T> + class Option + { + public: + /** Initialise the option to its default (C++) value and mark it as 'not set'. */ + Option(); + + /** Initialise the option to the given @p value and mark it as 'set'. */ + Option(const T &value); + + /** Assign the given @p value and mark it as 'set'. */ + Option<T> &operator=(const T &value); + + /** Query if the option has been set. */ + constexpr bool is_set() const; + + /** Return the underlying value as constant. */ + T get() const; + + /** Return the underlying value. */ + T &get(); + + /** Implicitly return the underlying value. */ + operator T() const; + + private: + T _value; + bool _is_set; + }; + +public: + UserConfiguration() = default; + + /** Initialise the configuration according to the program options. + * + * @param[in] options Parsed command line options. + */ + UserConfiguration(const ProgramOptions &options); + + Option<std::string> path{}; + Option<std::random_device::result_type> seed{}; + Option<unsigned int> threads{}; +}; + +template <typename T> +UserConfiguration::Option<T>::Option() + : _value{}, _is_set{ false } +{ +} + +template <typename T> +UserConfiguration::Option<T>::Option(const T &value) + : _value{ value }, _is_set{ true } +{ +} + +template <typename T> +UserConfiguration::Option<T> &UserConfiguration::Option<T>::operator=(const T &value) +{ + _value = value; + _is_set = true; + + return *this; +} + +template <typename T> +constexpr bool UserConfiguration::Option<T>::is_set() const +{ + return _is_set; +} + +template <typename T> +T UserConfiguration::Option<T>::get() const +{ + ARM_COMPUTE_ERROR_ON(!is_set()); + return _value; +} + +template <typename T> +T &UserConfiguration::Option<T>::get() +{ + return _value; +} + +template <typename T> +UserConfiguration::Option<T>::operator T() const +{ + ARM_COMPUTE_ERROR_ON(!is_set()); + return _value; +} +} // namespace test +} // namespace arm_compute +#endif /* __ARM_COMPUTE_TEST_USER_CONFIGURATION_H__ */ diff --git a/tests/validation_old/Validation.cpp b/tests/validation_old/Validation.cpp new file mode 100644 index 0000000000..8f173ba962 --- /dev/null +++ b/tests/validation_old/Validation.cpp @@ -0,0 +1,477 @@ +/* + * 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 "Validation.h" + +#include "arm_compute/core/Coordinates.h" +#include "arm_compute/core/Error.h" +#include "arm_compute/core/FixedPoint.h" +#include "arm_compute/core/IArray.h" +#include "arm_compute/core/TensorShape.h" +#include "arm_compute/runtime/Tensor.h" +#include "tests/IAccessor.h" +#include "tests/RawTensor.h" +#include "tests/TypePrinter.h" +#include "tests/Utils.h" +#include "tests/validation_old/half.h" + +#include <array> +#include <cmath> +#include <cstddef> +#include <cstdint> +#include <iomanip> +#include <vector> + +namespace arm_compute +{ +namespace test +{ +namespace validation +{ +namespace +{ +/** Get the data from *ptr after casting according to @p data_type and then convert the data to double. + * + * @param[in] ptr Pointer to value. + * @param[in] data_type Data type of both values. + * + * @return The data from the ptr after converted to double. + */ +double get_double_data(const void *ptr, DataType data_type) +{ + if(ptr == nullptr) + { + ARM_COMPUTE_ERROR("Can't dereference a null pointer!"); + } + + switch(data_type) + { + case DataType::U8: + return *reinterpret_cast<const uint8_t *>(ptr); + case DataType::S8: + return *reinterpret_cast<const int8_t *>(ptr); + case DataType::QS8: + return *reinterpret_cast<const qint8_t *>(ptr); + case DataType::U16: + return *reinterpret_cast<const uint16_t *>(ptr); + case DataType::S16: + return *reinterpret_cast<const int16_t *>(ptr); + case DataType::QS16: + return *reinterpret_cast<const qint16_t *>(ptr); + case DataType::U32: + return *reinterpret_cast<const uint32_t *>(ptr); + case DataType::S32: + return *reinterpret_cast<const int32_t *>(ptr); + case DataType::U64: + return *reinterpret_cast<const uint64_t *>(ptr); + case DataType::S64: + return *reinterpret_cast<const int64_t *>(ptr); + case DataType::F16: + return *reinterpret_cast<const half_float::half *>(ptr); + case DataType::F32: + return *reinterpret_cast<const float *>(ptr); + case DataType::F64: + return *reinterpret_cast<const double *>(ptr); + case DataType::SIZET: + return *reinterpret_cast<const size_t *>(ptr); + default: + ARM_COMPUTE_ERROR("NOT SUPPORTED!"); + } +} + +bool is_equal(double target, double ref, double max_absolute_error = std::numeric_limits<double>::epsilon(), double max_relative_error = 0.0001f) +{ + if(!std::isfinite(target) || !std::isfinite(ref)) + { + return false; + } + + // No need further check if they are equal + if(ref == target) + { + return true; + } + + // Need this check for the situation when the two values close to zero but have different sign + if(std::abs(std::abs(ref) - std::abs(target)) <= max_absolute_error) + { + return true; + } + + double relative_error = 0; + + if(std::abs(target) > std::abs(ref)) + { + relative_error = std::abs((target - ref) / target); + } + else + { + relative_error = std::abs((ref - target) / ref); + } + + return relative_error <= max_relative_error; +} + +void check_border_element(const IAccessor &tensor, const Coordinates &id, + const BorderMode &border_mode, const void *border_value, + int64_t &num_elements, int64_t &num_mismatches) +{ + const size_t channel_size = element_size_from_data_type(tensor.data_type()); + const auto ptr = static_cast<const uint8_t *>(tensor(id)); + + if(border_mode == BorderMode::REPLICATE) + { + Coordinates border_id{ id }; + border_id.set(1, 0); + border_value = tensor(border_id); + } + + // Iterate over all channels within one element + for(int channel = 0; channel < tensor.num_channels(); ++channel) + { + const size_t channel_offset = channel * channel_size; + const double target = get_double_data(ptr + channel_offset, tensor.data_type()); + const double ref = get_double_data(static_cast<const uint8_t *>(border_value) + channel_offset, tensor.data_type()); + const bool equal = is_equal(target, ref); + + BOOST_TEST_INFO("id = " << id); + BOOST_TEST_INFO("channel = " << channel); + BOOST_TEST_INFO("reference = " << std::setprecision(5) << ref); + BOOST_TEST_INFO("target = " << std::setprecision(5) << target); + BOOST_TEST_WARN(equal); + + if(!equal) + { + ++num_mismatches; + } + + ++num_elements; + } +} + +void check_single_element(const Coordinates &id, const IAccessor &tensor, const RawTensor &reference, float tolerance_value, + uint64_t wrap_range, int min_channels, size_t channel_size, int64_t &num_mismatches, int64_t &num_elements) +{ + const auto ptr = static_cast<const uint8_t *>(tensor(id)); + const auto ref_ptr = static_cast<const uint8_t *>(reference(id)); + + // Iterate over all channels within one element + for(int channel = 0; channel < min_channels; ++channel) + { + const size_t channel_offset = channel * channel_size; + const double target = get_double_data(ptr + channel_offset, reference.data_type()); + const double ref = get_double_data(ref_ptr + channel_offset, reference.data_type()); + bool equal = is_equal(target, ref, tolerance_value); + + if(wrap_range != 0 && !equal) + { + equal = is_equal(target, ref, wrap_range - tolerance_value); + } + + if(!equal) + { + BOOST_TEST_INFO("id = " << id); + BOOST_TEST_INFO("channel = " << channel); + BOOST_TEST_INFO("reference = " << std::setprecision(5) << ref); + BOOST_TEST_INFO("target = " << std::setprecision(5) << target); + BOOST_TEST_WARN(equal); + ++num_mismatches; + } + ++num_elements; + } +} +} // namespace + +void validate(const arm_compute::ValidRegion ®ion, const arm_compute::ValidRegion &reference) +{ + BOOST_TEST(region.anchor.num_dimensions() == reference.anchor.num_dimensions()); + BOOST_TEST(region.shape.num_dimensions() == reference.shape.num_dimensions()); + + for(unsigned int d = 0; d < region.anchor.num_dimensions(); ++d) + { + BOOST_TEST(region.anchor[d] == reference.anchor[d]); + } + + for(unsigned int d = 0; d < region.shape.num_dimensions(); ++d) + { + BOOST_TEST(region.shape[d] == reference.shape[d]); + } +} + +void validate(const arm_compute::PaddingSize &padding, const arm_compute::PaddingSize &reference) +{ + BOOST_TEST(padding.top == reference.top); + BOOST_TEST(padding.right == reference.right); + BOOST_TEST(padding.bottom == reference.bottom); + BOOST_TEST(padding.left == reference.left); +} + +void validate(const IAccessor &tensor, const RawTensor &reference, float tolerance_value, float tolerance_number, uint64_t wrap_range) +{ + // Validate with valid region covering the entire shape + validate(tensor, reference, shape_to_valid_region(tensor.shape()), tolerance_value, tolerance_number, wrap_range); +} + +void validate(const IAccessor &tensor, const RawTensor &reference, const ValidRegion &valid_region, float tolerance_value, float tolerance_number, uint64_t wrap_range) +{ + int64_t num_mismatches = 0; + int64_t num_elements = 0; + + BOOST_TEST(tensor.element_size() == reference.element_size()); + BOOST_TEST(tensor.format() == reference.format()); + BOOST_TEST(tensor.data_type() == reference.data_type()); + BOOST_TEST(tensor.num_channels() == reference.num_channels()); + BOOST_TEST(compare_dimensions(tensor.shape(), reference.shape())); + + const int min_elements = std::min(tensor.num_elements(), reference.num_elements()); + const int min_channels = std::min(tensor.num_channels(), reference.num_channels()); + const size_t channel_size = element_size_from_data_type(reference.data_type()); + + // Iterate over all elements within valid region, e.g. U8, S16, RGB888, ... + for(int element_idx = 0; element_idx < min_elements; ++element_idx) + { + const Coordinates id = index2coord(reference.shape(), element_idx); + if(is_in_valid_region(valid_region, id)) + { + check_single_element(id, tensor, reference, tolerance_value, wrap_range, min_channels, channel_size, num_mismatches, num_elements); + } + } + + const int64_t absolute_tolerance_number = tolerance_number * num_elements; + const float percent_mismatches = static_cast<float>(num_mismatches) / num_elements * 100.f; + + BOOST_TEST(num_mismatches <= absolute_tolerance_number, + num_mismatches << " values (" << std::setprecision(2) << percent_mismatches + << "%) mismatched (maximum tolerated " << std::setprecision(2) << tolerance_number << "%)"); +} + +void validate(const IAccessor &tensor, const RawTensor &reference, const RawTensor &valid_mask, float tolerance_value, float tolerance_number, uint64_t wrap_range) +{ + int64_t num_mismatches = 0; + int64_t num_elements = 0; + + BOOST_TEST(tensor.element_size() == reference.element_size()); + BOOST_TEST(tensor.format() == reference.format()); + BOOST_TEST(tensor.data_type() == reference.data_type()); + BOOST_TEST(tensor.num_channels() == reference.num_channels()); + BOOST_TEST(compare_dimensions(tensor.shape(), reference.shape())); + + const int min_elements = std::min(tensor.num_elements(), reference.num_elements()); + const int min_channels = std::min(tensor.num_channels(), reference.num_channels()); + const size_t channel_size = element_size_from_data_type(reference.data_type()); + + // Iterate over all elements within valid region, e.g. U8, S16, RGB888, ... + for(int element_idx = 0; element_idx < min_elements; ++element_idx) + { + const Coordinates id = index2coord(reference.shape(), element_idx); + if(valid_mask[element_idx] == 1) + { + check_single_element(id, tensor, reference, tolerance_value, wrap_range, min_channels, channel_size, num_mismatches, num_elements); + } + else + { + ++num_elements; + } + } + + const int64_t absolute_tolerance_number = tolerance_number * num_elements; + const float percent_mismatches = static_cast<float>(num_mismatches) / num_elements * 100.f; + + BOOST_TEST(num_mismatches <= absolute_tolerance_number, + num_mismatches << " values (" << std::setprecision(2) << percent_mismatches + << "%) mismatched (maximum tolerated " << std::setprecision(2) << tolerance_number << "%)"); +} + +void validate(const IAccessor &tensor, const void *reference_value) +{ + BOOST_TEST_REQUIRE((reference_value != nullptr)); + + int64_t num_mismatches = 0; + int64_t num_elements = 0; + const size_t channel_size = element_size_from_data_type(tensor.data_type()); + + // Iterate over all elements, e.g. U8, S16, RGB888, ... + for(int element_idx = 0; element_idx < tensor.num_elements(); ++element_idx) + { + const Coordinates id = index2coord(tensor.shape(), element_idx); + + const auto ptr = static_cast<const uint8_t *>(tensor(id)); + + // Iterate over all channels within one element + for(int channel = 0; channel < tensor.num_channels(); ++channel) + { + const size_t channel_offset = channel * channel_size; + const double target = get_double_data(ptr + channel_offset, tensor.data_type()); + const double ref = get_double_data(reference_value, tensor.data_type()); + const bool equal = is_equal(target, ref); + + BOOST_TEST_INFO("id = " << id); + BOOST_TEST_INFO("channel = " << channel); + BOOST_TEST_INFO("reference = " << std::setprecision(5) << ref); + BOOST_TEST_INFO("target = " << std::setprecision(5) << target); + BOOST_TEST_WARN(equal); + + if(!equal) + { + ++num_mismatches; + } + + ++num_elements; + } + } + + const float percent_mismatches = static_cast<float>(num_mismatches) / num_elements * 100.f; + + BOOST_TEST(num_mismatches == 0, + num_mismatches << " values (" << std::setprecision(2) << percent_mismatches << "%) mismatched"); +} + +void validate(const IAccessor &tensor, BorderSize border_size, const BorderMode &border_mode, const void *border_value) +{ + if(border_mode == BorderMode::UNDEFINED) + { + return; + } + else if(border_mode == BorderMode::CONSTANT) + { + BOOST_TEST((border_value != nullptr)); + } + + int64_t num_mismatches = 0; + int64_t num_elements = 0; + const int slice_size = tensor.shape()[0] * tensor.shape()[1]; + + for(int element_idx = 0; element_idx < tensor.num_elements(); element_idx += slice_size) + { + Coordinates id = index2coord(tensor.shape(), element_idx); + + // Top border + for(int y = -border_size.top; y < 0; ++y) + { + id.set(1, y); + + for(int x = -border_size.left; x < static_cast<int>(tensor.shape()[0]) + static_cast<int>(border_size.right); ++x) + { + id.set(0, x); + + check_border_element(tensor, id, border_mode, border_value, num_elements, num_mismatches); + } + } + + // Bottom border + for(int y = tensor.shape()[1]; y < static_cast<int>(tensor.shape()[1]) + static_cast<int>(border_size.bottom); ++y) + { + id.set(1, y); + + for(int x = -border_size.left; x < static_cast<int>(tensor.shape()[0]) + static_cast<int>(border_size.right); ++x) + { + id.set(0, x); + + check_border_element(tensor, id, border_mode, border_value, num_elements, num_mismatches); + } + } + + // Left/right border + for(int y = 0; y < static_cast<int>(tensor.shape()[1]); ++y) + { + id.set(1, y); + + // Left border + for(int x = -border_size.left; x < 0; ++x) + { + id.set(0, x); + + check_border_element(tensor, id, border_mode, border_value, num_elements, num_mismatches); + } + + // Right border + for(int x = tensor.shape()[0]; x < static_cast<int>(tensor.shape()[0]) + static_cast<int>(border_size.right); ++x) + { + id.set(0, x); + + check_border_element(tensor, id, border_mode, border_value, num_elements, num_mismatches); + } + } + } + + const float percent_mismatches = static_cast<float>(num_mismatches) / num_elements * 100.f; + + BOOST_TEST(num_mismatches == 0, + num_mismatches << " values (" << std::setprecision(2) << percent_mismatches << "%) mismatched"); +} + +void validate(std::vector<unsigned int> classified_labels, std::vector<unsigned int> expected_labels) +{ + ARM_COMPUTE_UNUSED(classified_labels); + ARM_COMPUTE_UNUSED(expected_labels); + BOOST_TEST(expected_labels.size() != 0); + BOOST_TEST(classified_labels.size() == expected_labels.size()); + + for(unsigned int i = 0; i < expected_labels.size(); ++i) + { + BOOST_TEST(classified_labels[i] == expected_labels[i]); + } +} + +void validate(float target, float ref, float tolerance_abs_error, float tolerance_relative_error) +{ + const bool equal = is_equal(target, ref, tolerance_abs_error, tolerance_relative_error); + + BOOST_TEST_INFO("reference = " << std::setprecision(5) << ref); + BOOST_TEST_INFO("target = " << std::setprecision(5) << target); + BOOST_TEST(equal); +} + +void validate(IArray<KeyPoint> &target, IArray<KeyPoint> &ref, int64_t tolerance) +{ + int64_t num_mismatches = 0; + + BOOST_TEST_WARN(target.num_values() == ref.num_values()); + + for(size_t i = 0; i < target.num_values(); ++i) + { + KeyPoint *ref_val = std::find_if(ref.buffer(), ref.buffer() + ref.num_values(), [&target, i](KeyPoint key) + { + return key.x == target.at(i).x && key.y == target.at(i).y; + }); + + const KeyPoint &key = target.at(i); + + if((ref_val == ref.buffer() + ref.num_values()) || !(is_equal(key.strength, ref_val->strength) && is_equal(key.scale, ref_val->scale) && is_equal(key.orientation, ref_val->orientation) + && is_equal(key.tracking_status, ref_val->tracking_status) && is_equal(key.error, ref_val->error))) + { + ++num_mismatches; + + BOOST_TEST_WARN(is_equal(key.strength, ref_val->strength)); + BOOST_TEST_WARN(is_equal(key.scale, ref_val->scale)); + BOOST_TEST_WARN(is_equal(key.orientation, ref_val->orientation)); + BOOST_TEST_WARN(is_equal(key.tracking_status, ref_val->tracking_status)); + BOOST_TEST_WARN(is_equal(key.error, ref_val->error)); + } + } + + BOOST_TEST(num_mismatches <= tolerance); +} +} // namespace validation +} // namespace test +} // namespace arm_compute diff --git a/tests/validation_old/Validation.h b/tests/validation_old/Validation.h new file mode 100644 index 0000000000..4c8752b937 --- /dev/null +++ b/tests/validation_old/Validation.h @@ -0,0 +1,193 @@ +/* + * 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_REFERENCE_VALIDATION_H__ +#define __ARM_COMPUTE_TEST_REFERENCE_VALIDATION_H__ + +#include "arm_compute/core/Types.h" +#include "arm_compute/runtime/Array.h" +#include "tests/RawTensor.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <vector> + +namespace arm_compute +{ +class Tensor; + +namespace test +{ +class IAccessor; + +namespace validation +{ +template <typename T> +boost::test_tools::predicate_result compare_dimensions(const Dimensions<T> &dimensions1, const Dimensions<T> &dimensions2) +{ + if(dimensions1.num_dimensions() != dimensions2.num_dimensions()) + { + boost::test_tools::predicate_result result(false); + result.message() << "Different dimensionality [" << dimensions1.num_dimensions() << "!=" << dimensions2.num_dimensions() << "]"; + return result; + } + + for(unsigned int i = 0; i < dimensions1.num_dimensions(); ++i) + { + if(dimensions1[i] != dimensions2[i]) + { + boost::test_tools::predicate_result result(false); + result.message() << "Mismatch in dimension " << i << " [" << dimensions1[i] << "!=" << dimensions2[i] << "]"; + return result; + } + } + + return true; +} + +/** Validate valid regions. + * + * - Dimensionality has to be the same. + * - Anchors have to match. + * - Shapes have to match. + */ +void validate(const arm_compute::ValidRegion ®ion, const arm_compute::ValidRegion &reference); + +/** Validate padding. + * + * Padding on all sides has to be the same. + */ +void validate(const arm_compute::PaddingSize &padding, const arm_compute::PaddingSize &reference); + +/** Validate tensors. + * + * - Dimensionality has to be the same. + * - All values have to match. + * + * @note: wrap_range allows cases where reference tensor rounds up to the wrapping point, causing it to wrap around to + * zero while the test tensor stays at wrapping point to pass. This may permit true erroneous cases (difference between + * reference tensor and test tensor is multiple of wrap_range), but such errors would be detected by + * other test cases. + */ +void validate(const IAccessor &tensor, const RawTensor &reference, float tolerance_value = 0.f, float tolerance_number = 0.f, uint64_t wrap_range = 0); + +/** Validate tensors with valid region. + * + * - Dimensionality has to be the same. + * - All values have to match. + * + * @note: wrap_range allows cases where reference tensor rounds up to the wrapping point, causing it to wrap around to + * zero while the test tensor stays at wrapping point to pass. This may permit true erroneous cases (difference between + * reference tensor and test tensor is multiple of wrap_range), but such errors would be detected by + * other test cases. + */ +void validate(const IAccessor &tensor, const RawTensor &reference, const ValidRegion &valid_region, float tolerance_value = 0.f, float tolerance_number = 0.f, uint64_t wrap_range = 0); + +/** Validate tensors with valid mask. + * + * - Dimensionality has to be the same. + * - All values have to match. + * + * @note: wrap_range allows cases where reference tensor rounds up to the wrapping point, causing it to wrap around to + * zero while the test tensor stays at wrapping point to pass. This may permit true erroneous cases (difference between + * reference tensor and test tensor is multiple of wrap_range), but such errors would be detected by + * other test cases. + */ +void validate(const IAccessor &tensor, const RawTensor &reference, const RawTensor &valid_mask, float tolerance_value = 0.f, float tolerance_number = 0.f, uint64_t wrap_range = 0); + +/** Validate tensors against constant value. + * + * - All values have to match. + */ +void validate(const IAccessor &tensor, const void *reference_value); + +/** Validate border against a constant value. + * + * - All border values have to match the specified value if mode is CONSTANT. + * - All border values have to be replicated if mode is REPLICATE. + * - Nothing is validated for mode UNDEFINED. + */ +void validate(const IAccessor &tensor, BorderSize border_size, const BorderMode &border_mode, const void *border_value); + +/** Validate classified labels against expected ones. + * + * - All values should match + */ +void validate(std::vector<unsigned int> classified_labels, std::vector<unsigned int> expected_labels); + +/** Validate float value. + * + * - All values should match + */ +void validate(float target, float ref, float tolerance_abs_error = std::numeric_limits<float>::epsilon(), float tolerance_relative_error = 0.0001f); + +/** Validate min max location. + * + * - All values should match + */ +template <typename T> +void validate_min_max_loc(T min, T ref_min, T max, T ref_max, + IArray<Coordinates2D> &min_loc, IArray<Coordinates2D> &ref_min_loc, IArray<Coordinates2D> &max_loc, IArray<Coordinates2D> &ref_max_loc, + uint32_t min_count, uint32_t ref_min_count, uint32_t max_count, uint32_t ref_max_count) +{ + BOOST_TEST(min == ref_min); + BOOST_TEST(max == ref_max); + + BOOST_TEST(min_count == min_loc.num_values()); + BOOST_TEST(max_count == max_loc.num_values()); + BOOST_TEST(ref_min_count == ref_min_loc.num_values()); + BOOST_TEST(ref_max_count == ref_max_loc.num_values()); + + BOOST_TEST(min_count == ref_min_count); + BOOST_TEST(max_count == ref_max_count); + + for(uint32_t i = 0; i < min_count; i++) + { + Coordinates2D *same_coords = std::find_if(ref_min_loc.buffer(), ref_min_loc.buffer() + min_count, [&min_loc, i](Coordinates2D coord) + { + return coord.x == min_loc.at(i).x && coord.y == min_loc.at(i).y; + }); + + BOOST_TEST(same_coords != ref_min_loc.buffer() + min_count); + } + + for(uint32_t i = 0; i < max_count; i++) + { + Coordinates2D *same_coords = std::find_if(ref_max_loc.buffer(), ref_max_loc.buffer() + max_count, [&max_loc, i](Coordinates2D coord) + { + return coord.x == max_loc.at(i).x && coord.y == max_loc.at(i).y; + }); + + BOOST_TEST(same_coords != ref_max_loc.buffer() + max_count); + } +} + +/** Validate KeyPoint arrays. + * + * - All values should match + */ +void validate(IArray<KeyPoint> &target, IArray<KeyPoint> &ref, int64_t tolerance = 0); +} // namespace validation +} // namespace test +} // namespace arm_compute +#endif /* __ARM_COMPUTE_TEST_REFERENCE_VALIDATION_H__ */ diff --git a/tests/validation_old/ValidationProgramOptions.cpp b/tests/validation_old/ValidationProgramOptions.cpp new file mode 100644 index 0000000000..adb8c5ab6c --- /dev/null +++ b/tests/validation_old/ValidationProgramOptions.cpp @@ -0,0 +1,50 @@ +/* + * 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 "ValidationProgramOptions.h" + +#include <thread> + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Weffc++" +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +#pragma GCC diagnostic ignored "-Wctor-dtor-privacy" +#include "boost/program_options.hpp" +#pragma GCC diagnostic pop + +namespace arm_compute +{ +namespace test +{ +namespace validation +{ +ValidationProgramOptions::ValidationProgramOptions() +{ + boost::program_options::options_description options("Validation options"); + options.add_options()("runs", boost::program_options::value<unsigned int>()->default_value(1), "Repetitions per test"); + options.add_options()("threads", boost::program_options::value<unsigned int>()->default_value(std::thread::hardware_concurrency()), "Number of parallel CPU threads"); + add_options(options); +} +} // namespace validation +} // namespace test +} // namespace arm_compute diff --git a/tests/validation_old/ValidationProgramOptions.h b/tests/validation_old/ValidationProgramOptions.h new file mode 100644 index 0000000000..6b29b807de --- /dev/null +++ b/tests/validation_old/ValidationProgramOptions.h @@ -0,0 +1,45 @@ +/* + * 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_VALIDATION_PROGRAM_OPTIONS_H__ +#define __ARM_COMPUTE_TEST_VALIDATION_PROGRAM_OPTIONS_H__ + +#include "ProgramOptions.h" + +namespace arm_compute +{ +namespace test +{ +namespace validation +{ +/** Subclass of @ref ProgramOptions that adds validation specific options. */ +class ValidationProgramOptions : public ProgramOptions +{ +public: + /** Defines additonal options. */ + ValidationProgramOptions(); +}; +} // namespace validation +} // namespace test +} // namespace arm_compute +#endif /* __ARM_COMPUTE_TEST_VALIDATION_PROGRAM_OPTIONS_H__ */ diff --git a/tests/validation_old/ValidationUserConfiguration.h b/tests/validation_old/ValidationUserConfiguration.h new file mode 100644 index 0000000000..a9b8b4fe40 --- /dev/null +++ b/tests/validation_old/ValidationUserConfiguration.h @@ -0,0 +1,42 @@ +/* + * 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_REFERENCE_VALIDATION_USER_CONFIGURATION_H__ +#define __ARM_COMPUTE_TEST_REFERENCE_VALIDATION_USER_CONFIGURATION_H__ + +#include "UserConfiguration.h" + +namespace arm_compute +{ +namespace test +{ +namespace validation +{ +// Validation requires no specific configuration +using ValidationUserConfiguration = UserConfiguration; +} // namespace validation + +extern validation::ValidationUserConfiguration user_config; +} // namespace test +} // namespace arm_compute +#endif /* __ARM_COMPUTE_TEST_REFERENCE_VALIDATION_USER_CONFIGURATION_H__ */ diff --git a/tests/validation_old/boost_wrapper.h b/tests/validation_old/boost_wrapper.h new file mode 100644 index 0000000000..b584e4cd1f --- /dev/null +++ b/tests/validation_old/boost_wrapper.h @@ -0,0 +1,40 @@ +/* + * 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. + */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Woverloaded-virtual" +#pragma GCC diagnostic ignored "-Weffc++" +#pragma GCC diagnostic ignored "-Wctor-dtor-privacy" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wsign-compare" +#include "boost/test/unit_test.hpp" +#include "boost/variant.hpp" +#include "boost/variant/multivisitors.hpp" +#pragma GCC diagnostic pop + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Weffc++" +#include "boost/test/data/test_case.hpp" +#pragma GCC diagnostic pop + +#include "boost/test/data/monomorphic.hpp" diff --git a/tests/validation_old/dataset/ActivationFunctionDataset.h b/tests/validation_old/dataset/ActivationFunctionDataset.h new file mode 100644 index 0000000000..b72cffbcd9 --- /dev/null +++ b/tests/validation_old/dataset/ActivationFunctionDataset.h @@ -0,0 +1,67 @@ +/* + * 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_DATASET_ACTIVATION_FUNCTION_DATASET_H__ +#define __ARM_COMPUTE_TEST_DATASET_ACTIVATION_FUNCTION_DATASET_H__ + +#include "arm_compute/core/Types.h" +#include "tests/validation_old/dataset/GenericDataset.h" + +#ifdef BOOST +#include "tests/validation_old/boost_wrapper.h" +#endif /* BOOST */ + +namespace arm_compute +{ +namespace test +{ +/** Data set containing all possible activation functions. + * + * Can be used as input for Boost data test cases to automatically run a test + * case on all activation functions. + */ +class ActivationFunctions final : public GenericDataset<ActivationLayerInfo::ActivationFunction, 10> +{ +public: + ActivationFunctions() + : GenericDataset + { + ActivationLayerInfo::ActivationFunction::ABS, + ActivationLayerInfo::ActivationFunction::LINEAR, + ActivationLayerInfo::ActivationFunction::LOGISTIC, + ActivationLayerInfo::ActivationFunction::RELU, + ActivationLayerInfo::ActivationFunction::BOUNDED_RELU, + ActivationLayerInfo::ActivationFunction::LEAKY_RELU, + ActivationLayerInfo::ActivationFunction::SOFT_RELU, + ActivationLayerInfo::ActivationFunction::SQRT, + ActivationLayerInfo::ActivationFunction::SQUARE, + ActivationLayerInfo::ActivationFunction::TANH + } + { + } + + ~ActivationFunctions() = default; +}; +} // namespace test +} // namespace arm_compute +#endif /* __ARM_COMPUTE_TEST_DATASET_ACTIVATION_FUNCTION_DATASET_H__ */ diff --git a/tests/validation_old/dataset/ActivationLayerDataset.h b/tests/validation_old/dataset/ActivationLayerDataset.h new file mode 100644 index 0000000000..ead52a2961 --- /dev/null +++ b/tests/validation_old/dataset/ActivationLayerDataset.h @@ -0,0 +1,177 @@ +/* + * 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_DATASET_ACTIVATION_LAYER_DATASET_H__ +#define __ARM_COMPUTE_TEST_DATASET_ACTIVATION_LAYER_DATASET_H__ + +#include "TypePrinter.h" + +#include "arm_compute/core/TensorShape.h" +#include "arm_compute/core/Types.h" +#include "tests/validation_old/dataset/GenericDataset.h" + +#include <sstream> +#include <type_traits> + +#ifdef BOOST +#include "tests/validation_old/boost_wrapper.h" +#endif /* BOOST */ + +namespace arm_compute +{ +namespace test +{ +class ActivationLayerDataObject +{ +public: + operator std::string() const + { + std::stringstream ss; + ss << "ActivationLayer"; + ss << "_I" << shape; + ss << "_F_" << info.activation(); + return ss.str(); + } + +public: + TensorShape shape; + ActivationLayerInfo info; +}; + +template <unsigned int Size> +using ActivationLayerDataset = GenericDataset<ActivationLayerDataObject, Size>; + +class AlexNetActivationLayerDataset final : public ActivationLayerDataset<5> +{ +public: + AlexNetActivationLayerDataset() + : GenericDataset + { + ActivationLayerDataObject{ TensorShape(55U, 55U, 96U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + ActivationLayerDataObject{ TensorShape(27U, 27U, 256U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + ActivationLayerDataObject{ TensorShape(13U, 13U, 384U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + ActivationLayerDataObject{ TensorShape(13U, 13U, 256U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + ActivationLayerDataObject{ TensorShape(4096U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + } + { + } + + ~AlexNetActivationLayerDataset() = default; +}; + +class LeNet5ActivationLayerDataset final : public ActivationLayerDataset<1> +{ +public: + LeNet5ActivationLayerDataset() + : GenericDataset + { + ActivationLayerDataObject{ TensorShape(500U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + } + { + } + + ~LeNet5ActivationLayerDataset() = default; +}; + +class GoogLeNetActivationLayerDataset final : public ActivationLayerDataset<33> +{ +public: + GoogLeNetActivationLayerDataset() + : GenericDataset + { + // conv1/relu_7x7 + ActivationLayerDataObject{ TensorShape(112U, 112U, 64U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + // conv2/relu_3x3_reduce + ActivationLayerDataObject{ TensorShape(56U, 56U, 64U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + // conv2/relu_3x3 + ActivationLayerDataObject{ TensorShape(56U, 56U, 192U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + // inception_3a/relu_1x1, inception_3b/relu_pool_proj + ActivationLayerDataObject{ TensorShape(28U, 28U, 64U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + // inception_3a/relu_3x3_reduce, inception_3b/relu_5x5 + ActivationLayerDataObject{ TensorShape(28U, 28U, 96U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + // inception_3a/relu_3x3, inception_3b/relu_1x1, inception_3b/relu_3x3_reduce + ActivationLayerDataObject{ TensorShape(28U, 28U, 128U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + // inception_3a/relu_5x5_reduce + ActivationLayerDataObject{ TensorShape(28U, 28U, 16U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + // inception_3a/relu_5x5, inception_3a/relu_pool_proj, inception_3b/relu_5x5_reduce + ActivationLayerDataObject{ TensorShape(28U, 28U, 32U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + // inception_3b/relu_3x3 + ActivationLayerDataObject{ TensorShape(28U, 28U, 192U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + // inception_4a/relu_1x1 + ActivationLayerDataObject{ TensorShape(14U, 14U, 192U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + // inception_4a/relu_3x3_reduce + ActivationLayerDataObject{ TensorShape(14U, 14U, 96U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + // inception_4a/relu_3x3 + ActivationLayerDataObject{ TensorShape(14U, 14U, 208U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + // inception_4a/relu_5x5_reduce + ActivationLayerDataObject{ TensorShape(14U, 14U, 16U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + // inception_4a/relu_5x5 + ActivationLayerDataObject{ TensorShape(14U, 14U, 48U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + // inception_4a/relu_pool_proj, inception_4b/relu_5x5, inception_4b/relu_pool_proj, inception_4c/relu_5x5, inception_4c/relu_pool_proj, inception_4d/relu_5x5, inception_4d/relu_pool_proj + ActivationLayerDataObject{ TensorShape(14U, 14U, 64U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + // inception_4b/relu_1x1, inception_4e/relu_3x3_reduce + ActivationLayerDataObject{ TensorShape(14U, 14U, 160U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + // inception_4b/relu_3x3_reduce, inception_4d/relu_1x1 + ActivationLayerDataObject{ TensorShape(14U, 14U, 112U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + // inception_4b/relu_3x3 + ActivationLayerDataObject{ TensorShape(14U, 14U, 224U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + // inception_4b/relu_5x5_reduce, inception_4c/relu_5x5_reduce + ActivationLayerDataObject{ TensorShape(14U, 14U, 24U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + // inception_4c/relu_1x1, inception_4c/relu_3x3_reduce, inception_4e/relu_5x5, inception_4e/relu_pool_proj + ActivationLayerDataObject{ TensorShape(14U, 14U, 128U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + // inception_4c/relu_3x3, inception_4e/relu_1x1 + ActivationLayerDataObject{ TensorShape(14U, 14U, 256U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + // inception_4d/relu_3x3_reduce + ActivationLayerDataObject{ TensorShape(14U, 14U, 144U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + // inception_4d/relu_3x3 + ActivationLayerDataObject{ TensorShape(14U, 14U, 288U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + // inception_4d/relu_5x5_reduce, inception_4e/relu_5x5_reduce + ActivationLayerDataObject{ TensorShape(14U, 14U, 32U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + // inception_4e/relu_3x3 + ActivationLayerDataObject{ TensorShape(14U, 14U, 320U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + // inception_5a/relu_1x1 + ActivationLayerDataObject{ TensorShape(7U, 7U, 256U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + // inception_5a/relu_3x3_reduce + ActivationLayerDataObject{ TensorShape(7U, 7U, 160U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + // inception_5a/relu_3x3 + ActivationLayerDataObject{ TensorShape(7U, 7U, 320U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + // inception_5a/relu_5x5_reduce + ActivationLayerDataObject{ TensorShape(7U, 7U, 32U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + // inception_5a/relu_5x5, inception_5a/relu_pool_proj, inception_5b/relu_5x5, inception_5b/relu_pool_proj + ActivationLayerDataObject{ TensorShape(7U, 7U, 128U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + // inception_5b/relu_1x1, inception_5b/relu_3x3 + ActivationLayerDataObject{ TensorShape(7U, 7U, 384U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + // inception_5b/relu_3x3_reduce + ActivationLayerDataObject{ TensorShape(7U, 7U, 192U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) }, + // inception_5b/relu_5x5_reduce + ActivationLayerDataObject{ TensorShape(7U, 7U, 48U), ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU) } + } + { + } + + ~GoogLeNetActivationLayerDataset() = default; +}; + +} // namespace test +} // namespace arm_compute +#endif //__ARM_COMPUTE_TEST_DATASET_ACTIVATION_LAYER_DATASET_H__ diff --git a/tests/validation_old/dataset/BatchNormalizationLayerDataset.h b/tests/validation_old/dataset/BatchNormalizationLayerDataset.h new file mode 100644 index 0000000000..ca1e3b694c --- /dev/null +++ b/tests/validation_old/dataset/BatchNormalizationLayerDataset.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_DATASET_BATCH_NORMALIZATION_LAYER_DATASET_H__ +#define __ARM_COMPUTE_TEST_DATASET_BATCH_NORMALIZATION_LAYER_DATASET_H__ + +#include "TypePrinter.h" + +#include "arm_compute/core/TensorShape.h" +#include "arm_compute/core/Types.h" +#include "tests/validation_old/dataset/GenericDataset.h" + +#include <ostream> +#include <sstream> + +#ifdef BOOST +#include "tests/validation_old/boost_wrapper.h" +#endif /* BOOST */ + +namespace arm_compute +{ +namespace test +{ +class BatchNormalizationLayerDataObject +{ +public: + operator std::string() const + { + std::stringstream ss; + ss << "BatchNormalizationLayer"; + ss << "_I" << shape0; + ss << "_I" << shape1; + ss << "_I" << epsilon; + return ss.str(); + } + + friend std::ostream &operator<<(std::ostream &s, const BatchNormalizationLayerDataObject &obj) + { + s << static_cast<std::string>(obj); + return s; + } + +public: + TensorShape shape0; + TensorShape shape1; + float epsilon; +}; + +template <unsigned int Size> +using BatchNormalizationLayerDataset = GenericDataset<BatchNormalizationLayerDataObject, Size>; + +class RandomBatchNormalizationLayerDataset final : public BatchNormalizationLayerDataset<3> +{ +public: + RandomBatchNormalizationLayerDataset() + : GenericDataset + { + BatchNormalizationLayerDataObject{ TensorShape(15U, 16U, 2U, 12U), TensorShape(2U), 0.1f }, + BatchNormalizationLayerDataObject{ TensorShape(21U, 11U, 12U, 7U), TensorShape(12U), 0.1f }, + BatchNormalizationLayerDataObject{ TensorShape(7U, 3U, 6U, 11U), TensorShape(6U), 0.1f }, + } + { + } + + ~RandomBatchNormalizationLayerDataset() = default; +}; + +} // namespace test +} // namespace arm_compute +#endif //__ARM_COMPUTE_TEST_DATASET_BATCH_NORMALIZATION_LAYER_DATASET_H__ diff --git a/tests/validation_old/dataset/BorderModeDataset.h b/tests/validation_old/dataset/BorderModeDataset.h new file mode 100644 index 0000000000..d1eb48d3bd --- /dev/null +++ b/tests/validation_old/dataset/BorderModeDataset.h @@ -0,0 +1,82 @@ +/* + * 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_BORDER_MODE_DATASET_H__ +#define __ARM_COMPUTE_TEST_BORDER_MODE_DATASET_H__ + +#include "arm_compute/core/Types.h" + +#ifdef BOOST +#include "tests/validation_old/boost_wrapper.h" +#endif /* BOOST */ + +#include <array> + +namespace arm_compute +{ +namespace test +{ +/** Data set containing all possible border modes. + * + * Can be used as input for Boost data test cases to automatically run a test + * case on all border modes. + */ +class BorderModes +{ +public: + /** Type of the samples in the data set. */ + using sample = BorderMode; + + /** Dimensionality of the data set. */ + enum + { + arity = 1 + }; + + /** Number of samples in the data set. */ +#ifdef BOOST + boost::unit_test::data::size_t size() const +#else /* BOOST */ + unsigned int size() const +#endif /* BOOST */ + { + return _modes.size(); + } + + /** Type of the iterator used to step through all samples in the data set. + * Needs to support operator*() and operator++() which a pointer does. + */ + using iterator = const BorderMode *; + + /** Iterator to the first sample in the data set. */ + iterator begin() const + { + return _modes.data(); + } + +private: + std::array<BorderMode, 3> _modes{ { BorderMode::UNDEFINED, BorderMode::CONSTANT, BorderMode::REPLICATE } }; +}; +} // namespace test +} // namespace arm_compute +#endif /* __ARM_COMPUTE_TEST_BORDER_MODE_DATASET_H__ */ diff --git a/tests/validation_old/dataset/ConvertPolicyDataset.h b/tests/validation_old/dataset/ConvertPolicyDataset.h new file mode 100644 index 0000000000..591b7ad388 --- /dev/null +++ b/tests/validation_old/dataset/ConvertPolicyDataset.h @@ -0,0 +1,82 @@ +/* + * 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_CONVERT_POLICY_DATASETS_H__ +#define __ARM_COMPUTE_TEST_CONVERT_POLICY_DATASETS_H__ + +#include "arm_compute/core/Types.h" + +#include <type_traits> + +#ifdef BOOST +#include "tests/validation_old/boost_wrapper.h" +#endif /* BOOST */ + +namespace arm_compute +{ +namespace test +{ +/** Data set containing all possible convert/overflow policies. + * + * Can be used as input for Boost data test cases to automatically run a test + * case on different convert policies. + */ +class ConvertPolicies +{ +public: + /** Type of the samples in the data set. */ + using sample = ConvertPolicy; + + /** Dimensionality of the data set. */ + enum + { + arity = 1 + }; + + /** Number of samples in the data set. */ +#ifdef BOOST + boost::unit_test::data::size_t size() const +#else /* BOOST */ + unsigned int size() const +#endif /* BOOST */ + { + return _policies.size(); + } + + /** Type of the iterator used to step through all samples in the data set. + * Needs to support operator*() and operator++() which a pointer does. + */ + using iterator = const ConvertPolicy *; + + /** Iterator to the first sample in the data set. */ + iterator begin() const + { + return _policies.data(); + } + +private: + std::array<ConvertPolicy, 2> _policies{ { ConvertPolicy::WRAP, ConvertPolicy::SATURATE } }; +}; +} // namespace test +} // namespace arm_compute +#endif /* __ARM_COMPUTE_TEST_CONVERT_POLICY_DATASETS_H__ */ diff --git a/tests/validation_old/dataset/ConvolutionLayerDataset.h b/tests/validation_old/dataset/ConvolutionLayerDataset.h new file mode 100644 index 0000000000..4fcba8d86d --- /dev/null +++ b/tests/validation_old/dataset/ConvolutionLayerDataset.h @@ -0,0 +1,273 @@ +/* + * 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_DATASET_CONVOLUTION_LAYER_DATASET_H__ +#define __ARM_COMPUTE_TEST_DATASET_CONVOLUTION_LAYER_DATASET_H__ + +#include "TypePrinter.h" + +#include "arm_compute/core/TensorShape.h" +#include "tests/validation_old/dataset/GenericDataset.h" +#include "tests/validation_old/dataset/ShapeDatasets.h" + +#include <sstream> +#include <type_traits> + +#ifdef BOOST +#include "tests/validation_old/boost_wrapper.h" +#endif /* BOOST */ + +namespace arm_compute +{ +namespace test +{ +/** Convolution Layer data object */ +class ConvolutionLayerDataObject +{ +public: + operator std::string() const + { + std::stringstream ss; + ss << "ConvolutionLayer"; + ss << "_I" << src_shape; + ss << "_K" << weights_shape; + ss << "_PS" << info; + return ss.str(); + } + + friend std::ostream &operator<<(std::ostream &os, const ConvolutionLayerDataObject &obj) + { + os << static_cast<std::string>(obj); + return os; + } + +public: + TensorShape src_shape; + TensorShape weights_shape; + TensorShape bias_shape; + TensorShape dst_shape; + PadStrideInfo info; +}; + +template <unsigned int Size> +using ConvolutionLayerDataset = GenericDataset<ConvolutionLayerDataObject, Size>; + +/** Data set containing small convolution layer shapes */ +class SmallConvolutionLayerDataset final : public ConvolutionLayerDataset<6> +{ +public: + SmallConvolutionLayerDataset() + : GenericDataset + { + ConvolutionLayerDataObject{ TensorShape(23U, 27U, 5U), TensorShape(3U, 3U, 5U, 21U), TensorShape(21U), TensorShape(11U, 25U, 21U), PadStrideInfo(2, 1, 0, 0) }, + ConvolutionLayerDataObject{ TensorShape(33U, 27U, 7U), TensorShape(5U, 5U, 7U, 16U), TensorShape(16U), TensorShape(11U, 12U, 16U), PadStrideInfo(3, 2, 1, 0) }, + ConvolutionLayerDataObject{ TensorShape(17U, 31U, 2U, 7U), TensorShape(5U, 5U, 2U, 19U), TensorShape(19U), TensorShape(15U, 15U, 19U, 7U), PadStrideInfo(1, 2, 1, 1) }, + ConvolutionLayerDataObject{ TensorShape(23U, 27U, 5U), TensorShape(3U, 1U, 5U, 21U), TensorShape(21U), TensorShape(11U, 27U, 21U), PadStrideInfo(2, 1, 0, 0) }, + ConvolutionLayerDataObject{ TensorShape(33U, 27U, 7U), TensorShape(5U, 7U, 7U, 16U), TensorShape(16U), TensorShape(11U, 11U, 16U), PadStrideInfo(3, 2, 1, 0) }, + ConvolutionLayerDataObject{ TensorShape(17U, 31U, 2U, 7U), TensorShape(5U, 3U, 2U, 19U), TensorShape(19U), TensorShape(15U, 16U, 19U, 7U), PadStrideInfo(1, 2, 1, 1) } + } + { + } + + ~SmallConvolutionLayerDataset() = default; +}; + +/** Data set containing direct convolution tensor shapes. */ +class DirectConvolutionShapes final : public ShapeDataset<4> +{ +public: + DirectConvolutionShapes() + : ShapeDataset(TensorShape(3U, 3U, 3U, 2U, 4U, 5U), + TensorShape(32U, 37U, 3U), + TensorShape(64U, 32U, 4U, 2U), + TensorShape(13U, 15U, 8U, 3U)) + { + } +}; + +/** AlexNet's convolution layers tensor shapes. */ +class AlexNetConvolutionLayerDataset final : public ConvolutionLayerDataset<5> +{ +public: + AlexNetConvolutionLayerDataset() + : GenericDataset + { + ConvolutionLayerDataObject{ TensorShape(227U, 227U, 3U), TensorShape(11U, 11U, 3U, 96U), TensorShape(96U), TensorShape(55U, 55U, 96U), PadStrideInfo(4, 4, 0, 0) }, + ConvolutionLayerDataObject{ TensorShape(27U, 27U, 96U), TensorShape(5U, 5U, 96U, 256U), TensorShape(256U), TensorShape(27U, 27U, 256U), PadStrideInfo(1, 1, 2, 2) }, + ConvolutionLayerDataObject{ TensorShape(13U, 13U, 256U), TensorShape(3U, 3U, 256U, 384U), TensorShape(384U), TensorShape(13U, 13U, 384U), PadStrideInfo(1, 1, 1, 1) }, + ConvolutionLayerDataObject{ TensorShape(13U, 13U, 384U), TensorShape(3U, 3U, 384U, 384U), TensorShape(384U), TensorShape(13U, 13U, 384U), PadStrideInfo(1, 1, 1, 1) }, + ConvolutionLayerDataObject{ TensorShape(13U, 13U, 384U), TensorShape(3U, 3U, 384U, 256U), TensorShape(256U), TensorShape(13U, 13U, 256U), PadStrideInfo(1, 1, 1, 1) } + } + { + } + + ~AlexNetConvolutionLayerDataset() = default; +}; + +/** LeNet5's convolution layers tensor shapes. */ +class LeNet5ConvolutionLayerDataset final : public ConvolutionLayerDataset<2> +{ +public: + LeNet5ConvolutionLayerDataset() + : GenericDataset + { + ConvolutionLayerDataObject{ TensorShape(28U, 28U, 1U), TensorShape(5U, 5U, 1U, 20U), TensorShape(20U), TensorShape(24U, 24U, 20U), PadStrideInfo(1, 1, 0, 0) }, + ConvolutionLayerDataObject{ TensorShape(12U, 12U, 20U), TensorShape(5U, 5U, 20U, 50U), TensorShape(50U), TensorShape(8U, 8U, 50U), PadStrideInfo(1, 1, 0, 0) }, + } + { + } + + ~LeNet5ConvolutionLayerDataset() = default; +}; + +/** GoogleLeNet v1 convolution layers tensor shapes (Part 1). + * + * @note Dataset is split into two to avoid a register allocation failure produced by clang in Android debug builds. + */ +class GoogLeNetConvolutionLayerDataset1 final : public ConvolutionLayerDataset<32> +{ +public: + GoogLeNetConvolutionLayerDataset1() + : GenericDataset + { + // conv1/7x7_s2 + ConvolutionLayerDataObject{ TensorShape(224U, 224U, 3U), TensorShape(7U, 7U, 3U, 64U), TensorShape(64U), TensorShape(112U, 112U, 64U), PadStrideInfo(2, 2, 3, 3) }, + // conv2/3x3_reduce + ConvolutionLayerDataObject{ TensorShape(56U, 56U, 64U), TensorShape(1U, 1U, 64U, 64U), TensorShape(64U), TensorShape(56U, 56U, 64U), PadStrideInfo(1, 1, 0, 0) }, + // conv2/3x3 + ConvolutionLayerDataObject{ TensorShape(56U, 56U, 64U), TensorShape(3U, 3U, 64U, 192U), TensorShape(192U), TensorShape(56U, 56U, 192U), PadStrideInfo(1, 1, 1, 1) }, + // inception_3a/1x1 + ConvolutionLayerDataObject{ TensorShape(28U, 28U, 192U), TensorShape(1U, 1U, 192U, 64U), TensorShape(64U), TensorShape(28U, 28U, 64U), PadStrideInfo(1, 1, 0, 0) }, + // inception_3a/3x3_reduce + ConvolutionLayerDataObject{ TensorShape(28U, 28U, 192U), TensorShape(1U, 1U, 192U, 96U), TensorShape(96U), TensorShape(28U, 28U, 96U), PadStrideInfo(1, 1, 0, 0) }, + // inception_3a/3x3 + ConvolutionLayerDataObject{ TensorShape(28U, 28U, 96U), TensorShape(3U, 3U, 96U, 128U), TensorShape(128U), TensorShape(28U, 28U, 128U), PadStrideInfo(1, 1, 1, 1) }, + // inception_3a/5x5_reduce + ConvolutionLayerDataObject{ TensorShape(28U, 28U, 192U), TensorShape(1U, 1U, 192U, 16U), TensorShape(16U), TensorShape(28U, 28U, 16U), PadStrideInfo(1, 1, 0, 0) }, + // inception_3a/5x5 + ConvolutionLayerDataObject{ TensorShape(28U, 28U, 16U), TensorShape(5U, 5U, 16U, 32U), TensorShape(32U), TensorShape(28U, 28U, 32U), PadStrideInfo(1, 1, 2, 2) }, + // inception_3a/pool_proj + ConvolutionLayerDataObject{ TensorShape(28U, 28U, 192U), TensorShape(1U, 1U, 192U, 32U), TensorShape(32U), TensorShape(28U, 28U, 32U), PadStrideInfo(1, 1, 0, 0) }, + // inception_3b/1x1, inception_3b/3x3_reduce + ConvolutionLayerDataObject{ TensorShape(28U, 28U, 256U), TensorShape(1U, 1U, 256U, 128U), TensorShape(128U), TensorShape(28U, 28U, 128U), PadStrideInfo(1, 1, 0, 0) }, + // inception_3b/3x3 + ConvolutionLayerDataObject{ TensorShape(28U, 28U, 128U), TensorShape(3U, 3U, 128U, 192U), TensorShape(192U), TensorShape(28U, 28U, 192U), PadStrideInfo(1, 1, 1, 1) }, + // inception_3b/5x5_reduce + ConvolutionLayerDataObject{ TensorShape(28U, 28U, 256U), TensorShape(1U, 1U, 256U, 32U), TensorShape(32U), TensorShape(28U, 28U, 32U), PadStrideInfo(1, 1, 0, 0) }, + // inception_3b/5x5 + ConvolutionLayerDataObject{ TensorShape(28U, 28U, 32U), TensorShape(5U, 5U, 32U, 96U), TensorShape(96U), TensorShape(28U, 28U, 96U), PadStrideInfo(1, 1, 2, 2) }, + // inception_3b/pool_proj + ConvolutionLayerDataObject{ TensorShape(28U, 28U, 256U), TensorShape(1U, 1U, 256U, 64U), TensorShape(64U), TensorShape(28U, 28U, 64U), PadStrideInfo(1, 1, 0, 0) }, + // inception_4a/1x1 + ConvolutionLayerDataObject{ TensorShape(14U, 14U, 480U), TensorShape(1U, 1U, 480U, 192U), TensorShape(192U), TensorShape(14U, 14U, 192U), PadStrideInfo(1, 1, 0, 0) }, + // inception_4a/3x3_reduce + ConvolutionLayerDataObject{ TensorShape(14U, 14U, 480U), TensorShape(1U, 1U, 480U, 96U), TensorShape(96U), TensorShape(14U, 14U, 96U), PadStrideInfo(1, 1, 0, 0) }, + // inception_4a/3x3 + ConvolutionLayerDataObject{ TensorShape(14U, 14U, 96U), TensorShape(3U, 3U, 96U, 208U), TensorShape(208U), TensorShape(14U, 14U, 208U), PadStrideInfo(1, 1, 1, 1) }, + // inception_4a/5x5_reduce + ConvolutionLayerDataObject{ TensorShape(14U, 14U, 480U), TensorShape(1U, 1U, 480U, 16U), TensorShape(16U), TensorShape(14U, 14U, 16U), PadStrideInfo(1, 1, 0, 0) }, + // inception_4a/5x5 + ConvolutionLayerDataObject{ TensorShape(14U, 14U, 16U), TensorShape(5U, 5U, 16U, 48U), TensorShape(48U), TensorShape(14U, 14U, 48U), PadStrideInfo(1, 1, 2, 2) }, + // inception_4a/pool_proj + ConvolutionLayerDataObject{ TensorShape(14U, 14U, 480U), TensorShape(1U, 1U, 480U, 64U), TensorShape(64U), TensorShape(14U, 14U, 64U), PadStrideInfo(1, 1, 0, 0) }, + // inception_4b/1x1 + ConvolutionLayerDataObject{ TensorShape(14U, 14U, 512U), TensorShape(1U, 1U, 512U, 160U), TensorShape(160U), TensorShape(14U, 14U, 160U), PadStrideInfo(1, 1, 0, 0) }, + // inception_4b/3x3_reduce, inception_4d/1x1 + ConvolutionLayerDataObject{ TensorShape(14U, 14U, 512U), TensorShape(1U, 1U, 512U, 112U), TensorShape(112U), TensorShape(14U, 14U, 112U), PadStrideInfo(1, 1, 0, 0) }, + // inception_4b/3x3 + ConvolutionLayerDataObject{ TensorShape(14U, 14U, 112U), TensorShape(3U, 3U, 112U, 224U), TensorShape(224U), TensorShape(14U, 14U, 224U), PadStrideInfo(1, 1, 1, 1) }, + // inception_4b/5x5_reduce, inception_4c/5x5_reduce + ConvolutionLayerDataObject{ TensorShape(14U, 14U, 512U), TensorShape(1U, 1U, 512U, 24U), TensorShape(24U), TensorShape(14U, 14U, 24U), PadStrideInfo(1, 1, 0, 0) }, + // inception_4b/5x5, inception_4c/5x5 + ConvolutionLayerDataObject{ TensorShape(14U, 14U, 24U), TensorShape(5U, 5U, 24U, 64U), TensorShape(64U), TensorShape(14U, 14U, 64U), PadStrideInfo(1, 1, 2, 2) }, + // inception_4b/pool_proj, inception_4c/pool_proj, inception_4d/pool_proj + ConvolutionLayerDataObject{ TensorShape(14U, 14U, 512U), TensorShape(1U, 1U, 512U, 64U), TensorShape(64U), TensorShape(14U, 14U, 64U), PadStrideInfo(1, 1, 0, 0) }, + // inception_4c/1x1, inception_4c/3x3_reduce + ConvolutionLayerDataObject{ TensorShape(14U, 14U, 512U), TensorShape(1U, 1U, 512U, 128U), TensorShape(128U), TensorShape(14U, 14U, 128U), PadStrideInfo(1, 1, 0, 0) }, + // inception_4c/3x3 + ConvolutionLayerDataObject{ TensorShape(14U, 14U, 128U), TensorShape(3U, 3U, 128U, 256U), TensorShape(256U), TensorShape(14U, 14U, 256U), PadStrideInfo(1, 1, 1, 1) }, + // inception_4d/3x3_reduce + ConvolutionLayerDataObject{ TensorShape(14U, 14U, 512U), TensorShape(1U, 1U, 512U, 144U), TensorShape(144U), TensorShape(14U, 14U, 144U), PadStrideInfo(1, 1, 0, 0) }, + // inception_4d/3x3 + ConvolutionLayerDataObject{ TensorShape(14U, 14U, 144U), TensorShape(3U, 3U, 144U, 288U), TensorShape(288U), TensorShape(14U, 14U, 288U), PadStrideInfo(1, 1, 1, 1) }, + // inception_4d/5x5_reduce + ConvolutionLayerDataObject{ TensorShape(14U, 14U, 512U), TensorShape(1U, 1U, 512U, 32U), TensorShape(32U), TensorShape(14U, 14U, 32U), PadStrideInfo(1, 1, 0, 0) }, + // inception_4d/5x5 + ConvolutionLayerDataObject{ TensorShape(14U, 14U, 32U), TensorShape(5U, 5U, 32U, 64U), TensorShape(64U), TensorShape(14U, 14U, 64U), PadStrideInfo(1, 1, 2, 2) }, + } + { + } + + ~GoogLeNetConvolutionLayerDataset1() = default; +}; + +/** GoogleLeNet v1 convolution layers tensor shapes (Part 2). */ +class GoogLeNetConvolutionLayerDataset2 final : public ConvolutionLayerDataset<17> +{ +public: + GoogLeNetConvolutionLayerDataset2() + : GenericDataset + { + // inception_4e/1x1 + ConvolutionLayerDataObject{ TensorShape(14U, 14U, 528U), TensorShape(1U, 1U, 528U, 256U), TensorShape(256U), TensorShape(14U, 14U, 256U), PadStrideInfo(1, 1, 0, 0) }, + // inception_4e/3x3_reduce + ConvolutionLayerDataObject{ TensorShape(14U, 14U, 528U), TensorShape(1U, 1U, 528U, 160U), TensorShape(160U), TensorShape(14U, 14U, 160U), PadStrideInfo(1, 1, 0, 0) }, + // inception_4e/3x3 + ConvolutionLayerDataObject{ TensorShape(14U, 14U, 160U), TensorShape(3U, 3U, 160U, 320U), TensorShape(320U), TensorShape(14U, 14U, 320U), PadStrideInfo(1, 1, 1, 1) }, + // inception_4e/5x5_reduce + ConvolutionLayerDataObject{ TensorShape(14U, 14U, 528U), TensorShape(1U, 1U, 528U, 32U), TensorShape(32U), TensorShape(14U, 14U, 32U), PadStrideInfo(1, 1, 0, 0) }, + // inception_4e/5x5 + ConvolutionLayerDataObject{ TensorShape(14U, 14U, 32U), TensorShape(5U, 5U, 32U, 128U), TensorShape(128U), TensorShape(14U, 14U, 128U), PadStrideInfo(1, 1, 2, 2) }, + // inception_4e/pool_proj + ConvolutionLayerDataObject{ TensorShape(14U, 14U, 528U), TensorShape(1U, 1U, 528U, 128U), TensorShape(128U), TensorShape(14U, 14U, 128U), PadStrideInfo(1, 1, 0, 0) }, + // inception_5a/1x1 + ConvolutionLayerDataObject{ TensorShape(7U, 7U, 832U), TensorShape(1U, 1U, 832U, 256U), TensorShape(256U), TensorShape(7U, 7U, 256U), PadStrideInfo(1, 1, 0, 0) }, + // inception_5a/3x3_reduce + ConvolutionLayerDataObject{ TensorShape(7U, 7U, 832U), TensorShape(1U, 1U, 832U, 160U), TensorShape(160U), TensorShape(7U, 7U, 160U), PadStrideInfo(1, 1, 0, 0) }, + // inception_5a/3x3 + ConvolutionLayerDataObject{ TensorShape(7U, 7U, 160U), TensorShape(3U, 3U, 160U, 320U), TensorShape(320U), TensorShape(7U, 7U, 320U), PadStrideInfo(1, 1, 1, 1) }, + // inception_5a/5x5_reduce + ConvolutionLayerDataObject{ TensorShape(7U, 7U, 832U), TensorShape(1U, 1U, 832U, 32U), TensorShape(32U), TensorShape(7U, 7U, 32U), PadStrideInfo(1, 1, 0, 0) }, + // inception_5a/5x5 + ConvolutionLayerDataObject{ TensorShape(7U, 7U, 32U), TensorShape(5U, 5U, 32U, 128U), TensorShape(128U), TensorShape(7U, 7U, 128U), PadStrideInfo(1, 1, 2, 2) }, + // inception_5a/pool_proj, inception_5b/pool_proj + ConvolutionLayerDataObject{ TensorShape(7U, 7U, 832U), TensorShape(1U, 1U, 832U, 128U), TensorShape(128U), TensorShape(7U, 7U, 128U), PadStrideInfo(1, 1, 0, 0) }, + // inception_5b/1x1 + ConvolutionLayerDataObject{ TensorShape(7U, 7U, 832U), TensorShape(1U, 1U, 832U, 384U), TensorShape(384U), TensorShape(7U, 7U, 384U), PadStrideInfo(1, 1, 0, 0) }, + // inception_5b/3x3_reduce + ConvolutionLayerDataObject{ TensorShape(7U, 7U, 832U), TensorShape(1U, 1U, 832U, 192U), TensorShape(192U), TensorShape(7U, 7U, 192U), PadStrideInfo(1, 1, 0, 0) }, + // inception_5b/3x3 + ConvolutionLayerDataObject{ TensorShape(7U, 7U, 192U), TensorShape(3U, 3U, 192U, 384U), TensorShape(384U), TensorShape(7U, 7U, 384U), PadStrideInfo(1, 1, 1, 1) }, + // inception_5b/5x5_reduce + ConvolutionLayerDataObject{ TensorShape(7U, 7U, 832U), TensorShape(1U, 1U, 832U, 48U), TensorShape(48U), TensorShape(7U, 7U, 48U), PadStrideInfo(1, 1, 0, 0) }, + // inception_5b/5x5 + ConvolutionLayerDataObject{ TensorShape(7U, 7U, 48U), TensorShape(5U, 5U, 48U, 128U), TensorShape(128U), TensorShape(7U, 7U, 128U), PadStrideInfo(1, 1, 2, 2) } + } + { + } + + ~GoogLeNetConvolutionLayerDataset2() = default; +}; +} // namespace test +} // namespace arm_compute +#endif /* __ARM_COMPUTE_TEST_DATASET_CONVOLUTION_LAYER_DATASET_H__ */ diff --git a/tests/validation_old/dataset/DataTypeDatasets.h b/tests/validation_old/dataset/DataTypeDatasets.h new file mode 100644 index 0000000000..34fc782b10 --- /dev/null +++ b/tests/validation_old/dataset/DataTypeDatasets.h @@ -0,0 +1,193 @@ +/* + * 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_DATA_TYPE_DATASET_H__ +#define __ARM_COMPUTE_TEST_DATA_TYPE_DATASET_H__ + +#include "arm_compute/core/Types.h" + +#ifdef BOOST +#include "tests/validation_old/boost_wrapper.h" +#endif /* BOOST */ + +namespace arm_compute +{ +namespace test +{ +/** Abstract data set containing data types. + * + * Can be used as input for Boost data test cases to automatically run a test + * case on different data types. + */ +template <unsigned int Size> +class DataTypes +{ +public: + /** Type of the samples in the data set. */ + using sample = DataType; + + /** Dimensionality of the data set. */ + enum + { + arity = 1 + }; + + /** Number of samples in the data set. */ +#ifdef BOOST + boost::unit_test::data::size_t size() const +#else /* BOOST */ + unsigned int size() const +#endif /* BOOST */ + { + return _types.size(); + } + + /** Type of the iterator used to step through all samples in the data set. + * Needs to support operator*() and operator++() which a pointer does. + */ + using iterator = const DataType *; + + /** Iterator to the first sample in the data set. */ + iterator begin() const + { + return _types.data(); + } + +protected: + /** Protected constructor to make the class abstract. */ + template <typename... Ts> + DataTypes(Ts &&... types) + : _types{ { types... } } + { + } + + /** Protected destructor to prevent deletion of derived classes through a + * pointer to the base class. + */ + ~DataTypes() = default; + +private: + std::array<DataType, Size> _types; +}; + +/** Data set containing all data types. */ +class AllDataTypes final : public DataTypes<14> +{ +public: + AllDataTypes() + : DataTypes{ DataType::U8, DataType::S8, DataType::U16, DataType::S16, + DataType::U32, DataType::S32, DataType::U64, DataType::S64, + DataType::F16, DataType::F32, DataType::F64, DataType::SIZET, + DataType::QS8, DataType::QS16 } + { + } + + ~AllDataTypes() = default; +}; + +/** Data set containing all unsigned data types. */ +class UnsignedDataTypes final : public DataTypes<4> +{ +public: + UnsignedDataTypes() + : DataTypes{ DataType::U8, DataType::U16, DataType::U32, DataType::U64 } + { + } + + ~UnsignedDataTypes() = default; +}; + +/** Data set containing all signed data types. */ +class SignedDataTypes final : public DataTypes<4> +{ +public: + SignedDataTypes() + : DataTypes{ DataType::S8, DataType::S16, DataType::S32, DataType::S64 } + { + } + + ~SignedDataTypes() = default; +}; + +/** Data set containing all floating point data types. */ +class FloatDataTypes final : public DataTypes<3> +{ +public: + FloatDataTypes() + : DataTypes{ DataType::F16, DataType::F32, DataType::F64 } + { + } + + ~FloatDataTypes() = default; +}; + +/** Data set containing all fixed point data types. */ +class FixedPointDataTypes final : public DataTypes<2> +{ +public: + FixedPointDataTypes() + : DataTypes{ DataType::QS8, DataType::QS16 } + { + } + + ~FixedPointDataTypes() = default; +}; + +/** Supported CNN float types. */ +class CNNFloatDataTypes final : public DataTypes<1> +{ +public: + CNNFloatDataTypes() + : DataTypes{ DataType::F32 } + { + } + + ~CNNFloatDataTypes() = default; +}; + +/** Supported CNN fixed point types. */ +class CNNFixedPointDataTypes final : public DataTypes<2> +{ +public: + CNNFixedPointDataTypes() + : DataTypes{ DataType::QS8, DataType::QS16 } + { + } + + ~CNNFixedPointDataTypes() = default; +}; + +/** Supported CNN types. */ +class CNNDataTypes final : public DataTypes<2> +{ +public: + CNNDataTypes() + : DataTypes{ DataType::F32, DataType::QS8 } + { + } + + ~CNNDataTypes() = default; +}; +} // namespace test +} // namespace arm_compute +#endif /* __ARM_COMPUTE_TEST_DATA_TYPE_DATASET_H__ */ diff --git a/tests/validation_old/dataset/FullyConnectedLayerDataset.h b/tests/validation_old/dataset/FullyConnectedLayerDataset.h new file mode 100644 index 0000000000..3564560788 --- /dev/null +++ b/tests/validation_old/dataset/FullyConnectedLayerDataset.h @@ -0,0 +1,155 @@ +/* + * 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_DATASET_FULLY_CONNECTED_LAYER_DATASET_H__ +#define __ARM_COMPUTE_TEST_DATASET_FULLY_CONNECTED_LAYER_DATASET_H__ + +#include "TypePrinter.h" + +#include "arm_compute/core/TensorShape.h" +#include "tests/validation_old/dataset/GenericDataset.h" + +#include <sstream> +#include <type_traits> + +#ifdef BOOST +#include "tests/validation_old/boost_wrapper.h" +#endif /* BOOST */ + +namespace arm_compute +{ +namespace test +{ +class FullyConnectedLayerDataObject +{ +public: + operator std::string() const + { + std::stringstream ss; + ss << "FullyConnectedLayer"; + ss << "_I" << src_shape; + ss << "_K" << weights_shape; + return ss.str(); + } + + friend std::ostream &operator<<(std::ostream &os, const FullyConnectedLayerDataObject &obj) + { + os << static_cast<std::string>(obj); + return os; + } + +public: + TensorShape src_shape; + TensorShape weights_shape; + TensorShape bias_shape; + TensorShape dst_shape; + bool transpose_weights; + bool are_weights_reshaped; +}; + +template <unsigned int Size> +using FullyConnectedLayerDataset = GenericDataset<FullyConnectedLayerDataObject, Size>; + +class SmallFullyConnectedLayerDataset final : public FullyConnectedLayerDataset<5> +{ +public: + SmallFullyConnectedLayerDataset() + : GenericDataset + { + FullyConnectedLayerDataObject{ TensorShape(9U, 5U, 7U), TensorShape(315U, 271U), TensorShape(271U), TensorShape(271U), true, false }, + FullyConnectedLayerDataObject{ TensorShape(9U, 5U, 7U, 3U), TensorShape(315U, 271U), TensorShape(271U), TensorShape(271U, 3U), true, false }, + FullyConnectedLayerDataObject{ TensorShape(201U), TensorShape(201U, 529U), TensorShape(529U), TensorShape(529U), true, false }, + FullyConnectedLayerDataObject{ TensorShape(9U, 5U, 7U), TensorShape(315U, 271U), TensorShape(271U), TensorShape(271U), true, true }, + FullyConnectedLayerDataObject{ TensorShape(201U), TensorShape(201U, 529U), TensorShape(529U), TensorShape(529U), true, true }, + } + { + } + + ~SmallFullyConnectedLayerDataset() = default; +}; + +class LargeFullyConnectedLayerDataset final : public FullyConnectedLayerDataset<5> +{ +public: + LargeFullyConnectedLayerDataset() + : GenericDataset + { + FullyConnectedLayerDataObject{ TensorShape(9U, 5U, 257U), TensorShape(11565U, 2123U), TensorShape(2123U), TensorShape(2123U), true, false }, + FullyConnectedLayerDataObject{ TensorShape(9U, 5U, 257U, 2U), TensorShape(11565U, 2123U), TensorShape(2123U), TensorShape(2123U, 2U), true, false }, + FullyConnectedLayerDataObject{ TensorShape(3127U), TensorShape(3127U, 989U), TensorShape(989U), TensorShape(989U), true, false }, + FullyConnectedLayerDataObject{ TensorShape(9U, 5U, 257U), TensorShape(11565U, 2123U), TensorShape(2123U), TensorShape(2123U), true, true }, + FullyConnectedLayerDataObject{ TensorShape(3127U), TensorShape(3127U, 989U), TensorShape(989U), TensorShape(989U), true, true }, + } + { + } + + ~LargeFullyConnectedLayerDataset() = default; +}; + +class AlexNetFullyConnectedLayerDataset final : public FullyConnectedLayerDataset<3> +{ +public: + AlexNetFullyConnectedLayerDataset() + : GenericDataset + { + FullyConnectedLayerDataObject{ TensorShape(6U, 6U, 256U), TensorShape(9216U, 4096U), TensorShape(4096U), TensorShape(4096U), true }, + FullyConnectedLayerDataObject{ TensorShape(4096U), TensorShape(4096U, 4096U), TensorShape(4096U), TensorShape(4096U), true }, + FullyConnectedLayerDataObject{ TensorShape(4096U), TensorShape(4096U, 1000U), TensorShape(1000U), TensorShape(1000U), true }, + } + { + } + + ~AlexNetFullyConnectedLayerDataset() = default; +}; + +class LeNet5FullyConnectedLayerDataset final : public FullyConnectedLayerDataset<2> +{ +public: + LeNet5FullyConnectedLayerDataset() + : GenericDataset + { + FullyConnectedLayerDataObject{ TensorShape(4U, 4U, 50U), TensorShape(800U, 500U), TensorShape(500U), TensorShape(500U) }, + FullyConnectedLayerDataObject{ TensorShape(500U), TensorShape(500U, 10U), TensorShape(10U), TensorShape(10U) }, + } + { + } + + ~LeNet5FullyConnectedLayerDataset() = default; +}; + +class GoogLeNetFullyConnectedLayerDataset final : public FullyConnectedLayerDataset<1> +{ +public: + GoogLeNetFullyConnectedLayerDataset() + : GenericDataset + { + FullyConnectedLayerDataObject{ TensorShape(1024U), TensorShape(1024U, 1000U), TensorShape(1000U), TensorShape(1000U), true }, + } + { + } + + ~GoogLeNetFullyConnectedLayerDataset() = default; +}; +} // namespace test +} // namespace arm_compute +#endif /* __ARM_COMPUTE_TEST_DATASET_FULLY_CONNECTED_LAYER_DATASET_H__ */ diff --git a/tests/validation_old/dataset/GEMMDataset.h b/tests/validation_old/dataset/GEMMDataset.h new file mode 100644 index 0000000000..5250827340 --- /dev/null +++ b/tests/validation_old/dataset/GEMMDataset.h @@ -0,0 +1,220 @@ +/* + * 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_DATASET_GEMM_DATASET_H__ +#define __ARM_COMPUTE_TEST_DATASET_GEMM_DATASET_H__ + +#include "TypePrinter.h" + +#include "arm_compute/core/TensorShape.h" +#include "arm_compute/core/Types.h" +#include "tests/validation_old/dataset/GenericDataset.h" + +#include <ostream> +#include <sstream> + +#include <tuple> +#include <type_traits> + +#ifdef BOOST +#include "tests/validation_old/boost_wrapper.h" +#endif /* BOOST */ + +namespace arm_compute +{ +namespace test +{ +class GEMMDataObject +{ +public: + //Data object used for matrix multiple + //D = alpha * A * B + beta * C; + TensorShape shape_a; + TensorShape shape_b; + TensorShape shape_c; + TensorShape shape_d; + float alpha; + float beta; + + operator std::string() const + { + std::stringstream ss; + ss << "GEMM"; + ss << "_A" << shape_a; + ss << "_B" << shape_b; + ss << "_C" << shape_c; + ss << "_D" << shape_d; + ss << "_alpha" << alpha; + ss << "_beta" << beta; + return ss.str(); + } + + friend std::ostream &operator<<(std::ostream &os, const GEMMDataObject &obj) + { + os << static_cast<std::string>(obj); + return os; + } +}; + +class SmallGEMMDataset : public GenericDataset<GEMMDataObject, 4> +{ +public: + SmallGEMMDataset() + : GenericDataset + { + GEMMDataObject{ TensorShape(21U, 13U), TensorShape(33U, 21U), TensorShape(33U, 13U), TensorShape(33U, 13U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(31U, 1U), TensorShape(23U, 31U), TensorShape(23U, 1U), TensorShape(23U, 1U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(38U, 12U), TensorShape(21U, 38U), TensorShape(21U, 12U), TensorShape(21U, 12U), 0.2f, 1.2f }, + GEMMDataObject{ TensorShape(32U, 1U), TensorShape(17U, 32U), TensorShape(17U, 1U), TensorShape(17U, 1U), 0.4f, 0.7f }, + } + { + } + + ~SmallGEMMDataset() = default; +}; + +class LargeGEMMDataset : public GenericDataset<GEMMDataObject, 4> +{ +public: + LargeGEMMDataset() + : GenericDataset + { + GEMMDataObject{ TensorShape(923U, 429U), TensorShape(871U, 923U), TensorShape(871U, 429U), TensorShape(871U, 429U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(1021U, 1U), TensorShape(783U, 1021U), TensorShape(783U, 1U), TensorShape(783U, 1U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(681U, 1023U), TensorShape(213U, 681U), TensorShape(213U, 1023U), TensorShape(213U, 1023U), 0.2f, 1.2f }, + GEMMDataObject{ TensorShape(941U, 1U), TensorShape(623U, 941U), TensorShape(623U, 1U), TensorShape(623U, 1U), 0.4f, 0.7f }, + } + { + } + + ~LargeGEMMDataset() = default; +}; + +class GoogLeNetGEMMDataset1 : public GenericDataset<GEMMDataObject, 32> +{ +public: + GoogLeNetGEMMDataset1() + : GenericDataset + { + GEMMDataObject{ TensorShape(147U, 12544U), TensorShape(64U, 147U), TensorShape(64U, 12544U), TensorShape(64U, 12544U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(64U, 3136U), TensorShape(64U, 64U), TensorShape(64U, 3136U), TensorShape(64U, 3136U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(576U, 3136U), TensorShape(192U, 576U), TensorShape(192U, 3136U), TensorShape(192U, 3136U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(192U, 784U), TensorShape(64U, 192U), TensorShape(64U, 784U), TensorShape(64U, 784U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(192U, 784U), TensorShape(96U, 192U), TensorShape(96U, 784U), TensorShape(96U, 784U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(864U, 784U), TensorShape(128U, 864U), TensorShape(128U, 784U), TensorShape(128U, 784U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(192U, 784U), TensorShape(16U, 192U), TensorShape(16U, 784U), TensorShape(16U, 784U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(400U, 784U), TensorShape(32U, 400U), TensorShape(32U, 784U), TensorShape(32U, 784U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(192U, 784U), TensorShape(32U, 192U), TensorShape(32U, 784U), TensorShape(32U, 784U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(256U, 784U), TensorShape(128U, 256U), TensorShape(128U, 784U), TensorShape(128U, 784U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(256U, 784U), TensorShape(128U, 256U), TensorShape(128U, 784U), TensorShape(128U, 784U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(1152U, 784U), TensorShape(192U, 1152U), TensorShape(192U, 784U), TensorShape(192U, 784U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(256U, 784U), TensorShape(32U, 256U), TensorShape(32U, 784U), TensorShape(32U, 784U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(800U, 784U), TensorShape(96U, 800U), TensorShape(96U, 784U), TensorShape(96U, 784U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(256U, 784U), TensorShape(64U, 256U), TensorShape(64U, 784U), TensorShape(64U, 784U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(480U, 196U), TensorShape(192U, 480U), TensorShape(192U, 196U), TensorShape(192U, 196U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(480U, 196U), TensorShape(96U, 480U), TensorShape(96U, 196U), TensorShape(96U, 196U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(864U, 196U), TensorShape(204U, 864U), TensorShape(204U, 196U), TensorShape(204U, 196U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(480U, 196U), TensorShape(16U, 480U), TensorShape(16U, 196U), TensorShape(16U, 196U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(400U, 196U), TensorShape(48U, 400U), TensorShape(48U, 196U), TensorShape(48U, 196U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(480U, 196U), TensorShape(64U, 480U), TensorShape(64U, 196U), TensorShape(64U, 196U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(508U, 196U), TensorShape(160U, 508U), TensorShape(160U, 196U), TensorShape(160U, 196U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(508U, 196U), TensorShape(112U, 508U), TensorShape(112U, 196U), TensorShape(112U, 196U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(1008U, 196U), TensorShape(224U, 1008U), TensorShape(224U, 196U), TensorShape(224U, 196U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(508U, 196U), TensorShape(24U, 508U), TensorShape(24U, 196U), TensorShape(24U, 196U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(600U, 196U), TensorShape(64U, 600U), TensorShape(64U, 196U), TensorShape(64U, 196U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(508U, 196U), TensorShape(64U, 508U), TensorShape(64U, 196U), TensorShape(64U, 196U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(512U, 196U), TensorShape(128U, 512U), TensorShape(128U, 196U), TensorShape(128U, 196U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(512U, 196U), TensorShape(128U, 512U), TensorShape(128U, 196U), TensorShape(128U, 196U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(1152U, 196U), TensorShape(256U, 1152U), TensorShape(256U, 196U), TensorShape(256U, 196U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(512U, 196U), TensorShape(24U, 512U), TensorShape(24U, 196U), TensorShape(24U, 196U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(600U, 196U), TensorShape(64U, 600U), TensorShape(64U, 196U), TensorShape(64U, 196U), 1.0f, 0.0f } + } + { + } + + ~GoogLeNetGEMMDataset1() = default; +}; + +class GoogLeNetGEMMDataset2 : public GenericDataset<GEMMDataObject, 32> +{ +public: + GoogLeNetGEMMDataset2() + : GenericDataset + { + GEMMDataObject{ TensorShape(512U, 196U), TensorShape(64U, 512U), TensorShape(64U, 196U), TensorShape(64U, 196U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(512U, 196U), TensorShape(112U, 512U), TensorShape(112U, 196U), TensorShape(112U, 196U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(512U, 196U), TensorShape(144U, 512U), TensorShape(144U, 196U), TensorShape(144U, 196U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(1296U, 196U), TensorShape(288U, 1296U), TensorShape(288U, 196U), TensorShape(288U, 196U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(512U, 196U), TensorShape(32U, 512U), TensorShape(32U, 196U), TensorShape(32U, 196U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(800U, 196U), TensorShape(64U, 800U), TensorShape(64U, 196U), TensorShape(64U, 196U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(512U, 196U), TensorShape(64U, 512U), TensorShape(64U, 196U), TensorShape(64U, 196U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(528U, 196U), TensorShape(256U, 528U), TensorShape(256U, 196U), TensorShape(256U, 196U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(528U, 196U), TensorShape(160U, 528U), TensorShape(160U, 196U), TensorShape(160U, 196U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(1440U, 196U), TensorShape(320U, 1440U), TensorShape(320U, 196U), TensorShape(320U, 196U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(528U, 196U), TensorShape(32U, 528U), TensorShape(32U, 196U), TensorShape(32U, 196U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(800U, 196U), TensorShape(128U, 800U), TensorShape(128U, 196U), TensorShape(128U, 196U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(528U, 196U), TensorShape(128U, 528U), TensorShape(128U, 196U), TensorShape(128U, 196U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(832U, 49U), TensorShape(256U, 832U), TensorShape(256U, 49U), TensorShape(256U, 49U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(832U, 49U), TensorShape(160U, 832U), TensorShape(160U, 49U), TensorShape(160U, 49U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(1440U, 49U), TensorShape(320U, 1440U), TensorShape(320U, 49U), TensorShape(320U, 49U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(832U, 49U), TensorShape(48U, 832U), TensorShape(48U, 49U), TensorShape(48U, 49U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(1200U, 49U), TensorShape(128U, 1200U), TensorShape(128U, 49U), TensorShape(128U, 49U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(832U, 49U), TensorShape(128U, 832U), TensorShape(128U, 49U), TensorShape(128U, 49U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(832U, 49U), TensorShape(384U, 832U), TensorShape(384U, 49U), TensorShape(384U, 49U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(832U, 49U), TensorShape(192U, 832U), TensorShape(192U, 49U), TensorShape(192U, 49U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(1728U, 49U), TensorShape(384U, 1728U), TensorShape(384U, 49U), TensorShape(384U, 49U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(832U, 49U), TensorShape(48U, 832U), TensorShape(48U, 49U), TensorShape(48U, 49U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(1200U, 49U), TensorShape(128U, 1200U), TensorShape(128U, 49U), TensorShape(128U, 49U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(832U, 49U), TensorShape(128U, 832U), TensorShape(128U, 49U), TensorShape(128U, 49U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(508U, 16U), TensorShape(128U, 508U), TensorShape(128U, 16U), TensorShape(128U, 16U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(2048U, 1U), TensorShape(1024U, 2048U), TensorShape(1024U, 1U), TensorShape(1024U, 1U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(1024U, 1U), TensorShape(1008U, 1024U), TensorShape(1008U, 1U), TensorShape(1008U, 1U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(528U, 16U), TensorShape(128U, 528U), TensorShape(128U, 16U), TensorShape(128U, 16U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(2048U, 1U), TensorShape(1024U, 2048U), TensorShape(1024U, 1U), TensorShape(1024U, 1U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(1024U, 1U), TensorShape(1008U, 1024U), TensorShape(1008U, 1U), TensorShape(1008U, 1U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(1024U, 1U), TensorShape(1008U, 1024U), TensorShape(1008U, 1U), TensorShape(1008U, 1U), 1.0f, 0.0f } + } + { + } + + ~GoogLeNetGEMMDataset2() = default; +}; + +class MatrixMultiplyDataset : public GenericDataset<GEMMDataObject, 3> +{ +public: + MatrixMultiplyDataset() + : GenericDataset + { + GEMMDataObject{ TensorShape(1024U, 1U), TensorShape(1000U, 1024U), TensorShape(1000U, 1U), TensorShape(1000U, 1U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(256U, 784U), TensorShape(64U, 256U), TensorShape(64U, 784U), TensorShape(64U, 784U), 1.0f, 0.0f }, + GEMMDataObject{ TensorShape(1152U, 2704U), TensorShape(256U, 1152U), TensorShape(256U, 2704U), TensorShape(256U, 2704U), 1.0f, 0.0f }, + } + { + } + + ~MatrixMultiplyDataset() = default; +}; +} // namespace test +} // namespace arm_compute +#endif //__ARM_COMPUTE_TEST_DATASET_GEMM_DATASET_H__ diff --git a/tests/validation_old/dataset/GenericDataset.h b/tests/validation_old/dataset/GenericDataset.h new file mode 100644 index 0000000000..d2c9f2db34 --- /dev/null +++ b/tests/validation_old/dataset/GenericDataset.h @@ -0,0 +1,97 @@ +/* + * 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_DATASET_GENERIC_DATASET_H__ +#define __ARM_COMPUTE_TEST_DATASET_GENERIC_DATASET_H__ + +#include "arm_compute/core/TensorShape.h" +#include "arm_compute/core/Types.h" + +#include <type_traits> + +#ifdef BOOST +#include "tests/validation_old/boost_wrapper.h" +#endif /* BOOST */ + +namespace arm_compute +{ +namespace test +{ +/** Abstract data set containing multiple objects T. + * + * Can be used as input for Boost data test cases to automatically run a test + * case on different configurations. + */ +template <class T, unsigned int Size> +class GenericDataset +{ +public: + /** Type of the samples in the data set. */ + using sample = T; + + /** Dimensionality of the data set. */ + enum + { + arity = 1 + }; + + /** Number of samples in the data set. */ +#ifdef BOOST + boost::unit_test::data::size_t size() const +#else /* BOOST */ + unsigned int size() const +#endif /* BOOST */ + { + return _data.size(); + } + + /** Type of the iterator used to step through all samples in the data set. + * Needs to support operator*() and operator++() which a pointer does. + */ + using iterator = const T *; + + /** Iterator to the first sample in the data set. */ + iterator begin() const + { + return _data.data(); + } + +protected: + /** Protected constructor to make the class abstract. */ + template <typename... Ts> + GenericDataset(Ts... objs) + : _data{ { objs... } } + { + } + + /** Protected destructor to prevent deletion of derived class through a + * pointer to the base class. + */ + ~GenericDataset() = default; + +private: + std::array<T, Size> _data; +}; +} // namespace test +} // namespace arm_compute +#endif /* __ARM_COMPUTE_TEST_DATASET_GENERIC_DATASET_H__ */ diff --git a/tests/validation_old/dataset/ImageDatasets.h b/tests/validation_old/dataset/ImageDatasets.h new file mode 100644 index 0000000000..7fcd067e1b --- /dev/null +++ b/tests/validation_old/dataset/ImageDatasets.h @@ -0,0 +1,120 @@ +/* + * 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_IMAGE_DATASETS_H__ +#define __ARM_COMPUTE_TEST_IMAGE_DATASETS_H__ + +#include <string> +#include <type_traits> + +#ifdef BOOST +#include "tests/validation_old/boost_wrapper.h" +#endif /* BOOST */ + +namespace arm_compute +{ +namespace test +{ +/** Abstract data set containing image names. + * + * Can be used as input for Boost data test cases to automatically run a test + * case on different images. + */ +template <unsigned int Size> +class ImageDataset +{ +public: + /** Type of the samples in the data set. */ + using sample = const std::string; + + /** Dimensionality of the data set. */ + enum + { + arity = 1 + }; + + /** Number of samples in the data set. */ +#ifdef BOOST + boost::unit_test::data::size_t size() const +#else /* BOOST */ + unsigned int size() const +#endif /* BOOST */ + { + return _images.size(); + } + + /** Type of the iterator used to step through all samples in the data set. + * Needs to support operator*() and operator++() which a pointer does. + */ + using iterator = const std::string *; + + /** Iterator to the first sample in the data set. */ + iterator begin() const + { + return _images.data(); + } + +protected: + /** Protected constructor to make the class abstract. */ + template <typename... Ts> + ImageDataset(Ts... images) + : _images{ { images... } } + { + } + + /** Protected destructor to prevent deletion of derived class through a + * pointer to the base class. + */ + ~ImageDataset() = default; + +private: + std::array<std::string, Size> _images; +}; + +/** Data set containing names of small images. */ +class SmallImages final : public ImageDataset<2> +{ +public: + SmallImages() + : ImageDataset("128x128.ppm", "640x480.ppm") + { + } +}; + +/** Data set containing names of large images. */ +class LargeImages final : public ImageDataset<3> +{ +public: + LargeImages() +#ifdef INTERNAL_ONLY + : ImageDataset("1280x720.ppm", "1920x1080.ppm", "4160x3120.ppm") + // The 4k image is too large to distribute +#else /* INTERNAL_ONLY */ + : ImageDataset("1280x720.ppm", "1920x1080.ppm") +#endif /* INTERNAL_ONLY */ + { + } +}; +} // namespace test +} // namespace arm_compute +#endif /* __ARM_COMPUTE_TEST_IMAGE_DATASETS_H__ */ diff --git a/tests/validation_old/dataset/InterpolationPolicyDataset.h b/tests/validation_old/dataset/InterpolationPolicyDataset.h new file mode 100644 index 0000000000..64cc9bf239 --- /dev/null +++ b/tests/validation_old/dataset/InterpolationPolicyDataset.h @@ -0,0 +1,80 @@ +/* + * 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_INTERPOLATION_POLICY_DATASET_H__ +#define __ARM_COMPUTE_TEST_INTERPOLATION_POLICY_DATASET_H__ + +#include "arm_compute/core/Types.h" + +#ifdef BOOST +#include "tests/validation_old/boost_wrapper.h" +#endif /* BOOST */ + +namespace arm_compute +{ +namespace test +{ +/** Data set containing all possible interpolation policies. + * + * Can be used as input for Boost data test cases to automatically run a test + * case on all interpolation policies. + */ +class InterpolationPolicies +{ +public: + /** Type of the samples in the data set. */ + using sample = InterpolationPolicy; + + /** Dimensionality of the data set. */ + enum + { + arity = 1 + }; + + /** Number of samples in the data set. */ +#ifdef BOOST + boost::unit_test::data::size_t size() const +#else /* BOOST */ + unsigned int size() const +#endif /* BOOST */ + { + return _policies.size(); + } + + /** Type of the iterator used to step through all samples in the data set. + * Needs to support operator*() and operator++() which a pointer does. + */ + using iterator = const InterpolationPolicy *; + + /** Iterator to the first sample in the data set. */ + iterator begin() const + { + return _policies.data(); + } + +private: + std::array<InterpolationPolicy, 3> _policies{ { InterpolationPolicy::NEAREST_NEIGHBOR, InterpolationPolicy::BILINEAR, InterpolationPolicy::AREA } }; +}; +} // namespace test +} // namespace arm_compute +#endif /* __ARM_COMPUTE_TEST_INTERPOLATION_POLICY_DATASET_H__ */ diff --git a/tests/validation_old/dataset/MatrixPatternDataset.h b/tests/validation_old/dataset/MatrixPatternDataset.h new file mode 100644 index 0000000000..7d7d365d91 --- /dev/null +++ b/tests/validation_old/dataset/MatrixPatternDataset.h @@ -0,0 +1,82 @@ +/* + * 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_MATRIX_PATTERN_DATASET_H__ +#define __ARM_COMPUTE_TEST_MATRIX_PATTERN_DATASET_H__ + +#include "arm_compute/core/Types.h" + +#ifdef BOOST +#include "tests/validation_old/boost_wrapper.h" +#endif /* BOOST */ + +#include <array> + +namespace arm_compute +{ +namespace test +{ +/** Data set containing all possible border modes. + * + * Can be used as input for Boost data test cases to automatically run a test + * case on all border modes. + */ +class MatrixPatterns +{ +public: + /** Type of the samples in the data set. */ + using sample = MatrixPattern; + + /** Dimensionality of the data set. */ + enum + { + arity = 1 + }; + + /** Number of samples in the data set. */ +#ifdef BOOST + boost::unit_test::data::size_t size() const +#else /* BOOST */ + unsigned int size() const +#endif /* BOOST */ + { + return _patterns.size(); + } + + /** Type of the iterator used to step through all samples in the data set. + * Needs to support operator*() and operator++() which a pointer does. + */ + using iterator = const MatrixPattern *; + + /** Iterator to the first sample in the data set. */ + iterator begin() const + { + return _patterns.data(); + } + +private: + std::array<MatrixPattern, 4> _patterns{ { MatrixPattern::BOX, MatrixPattern::CROSS, MatrixPattern::DISK, MatrixPattern::OTHER } }; +}; +} // namespace test +} // namespace arm_compute +#endif /* __ARM_COMPUTE_TEST_MATRIX_PATTERN_DATASET_H__ */ diff --git a/tests/validation_old/dataset/NonLinearFilterFunctionDataset.h b/tests/validation_old/dataset/NonLinearFilterFunctionDataset.h new file mode 100644 index 0000000000..c961c84866 --- /dev/null +++ b/tests/validation_old/dataset/NonLinearFilterFunctionDataset.h @@ -0,0 +1,82 @@ +/* + * 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_NON_LINEAR_FILTER_FUNCTION_DATASET_H__ +#define __ARM_COMPUTE_TEST_NON_LINEAR_FILTER_FUNCTION_DATASET_H__ + +#include "arm_compute/core/Types.h" + +#ifdef BOOST +#include "tests/validation_old/boost_wrapper.h" +#endif /* BOOST */ + +#include <array> + +namespace arm_compute +{ +namespace test +{ +/** Data set containing all possible non linear filter function. + * + * Can be used as input for Boost data test cases to automatically run a test + * case on all border modes. + */ +class NonLinearFilterFunctions +{ +public: + /** Type of the samples in the data set. */ + using sample = NonLinearFilterFunction; + + /** Dimensionality of the data set. */ + enum + { + arity = 1 + }; + + /** Number of samples in the data set. */ +#ifdef BOOST + boost::unit_test::data::size_t size() const +#else /* BOOST */ + unsigned int size() const +#endif /* BOOST */ + { + return _functions.size(); + } + + /** Type of the iterator used to step through all samples in the data set. + * Needs to support operator*() and operator++() which a pointer does. + */ + using iterator = const NonLinearFilterFunction *; + + /** Iterator to the first sample in the data set. */ + iterator begin() const + { + return _functions.data(); + } + +private: + std::array<NonLinearFilterFunction, 3> _functions{ { NonLinearFilterFunction::MAX, NonLinearFilterFunction::MEDIAN, NonLinearFilterFunction::MIN } }; +}; +} // namespace test +} // namespace arm_compute +#endif /* __ARM_COMPUTE_TEST_NON_LINEAR_FILTER_FUNCTION_DATASET_H__ */ diff --git a/tests/validation_old/dataset/NormalizationLayerDataset.h b/tests/validation_old/dataset/NormalizationLayerDataset.h new file mode 100644 index 0000000000..cd3c14d948 --- /dev/null +++ b/tests/validation_old/dataset/NormalizationLayerDataset.h @@ -0,0 +1,99 @@ +/* + * 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_DATASET_NORMALIZATION_LAYER_DATASET_H__ +#define __ARM_COMPUTE_TEST_DATASET_NORMALIZATION_LAYER_DATASET_H__ + +#include "TypePrinter.h" + +#include "arm_compute/core/TensorShape.h" +#include "arm_compute/core/Types.h" +#include "tests/validation_old/dataset/GenericDataset.h" + +#include <sstream> +#include <type_traits> + +#ifdef BOOST +#include "tests/validation_old/boost_wrapper.h" +#endif /* BOOST */ + +namespace arm_compute +{ +namespace test +{ +class NormalizationLayerDataObject +{ +public: + operator std::string() const + { + std::stringstream ss; + ss << "NormalizationLayer"; + ss << "_I" << shape; + ss << "_F_" << info.type(); + ss << "_S_" << info.norm_size(); + return ss.str(); + } + +public: + TensorShape shape; + NormalizationLayerInfo info; +}; + +template <unsigned int Size> +using NormalizationLayerDataset = GenericDataset<NormalizationLayerDataObject, Size>; + +class GoogLeNetNormalizationLayerDataset final : public NormalizationLayerDataset<2> +{ +public: + GoogLeNetNormalizationLayerDataset() + : GenericDataset + { + // conv2/norm2 + NormalizationLayerDataObject{ TensorShape(56U, 56U, 192U), NormalizationLayerInfo(NormType::CROSS_MAP, 5, 0.0001f, 0.75f) }, + // pool1/norm1 + NormalizationLayerDataObject{ TensorShape(56U, 56U, 64U), NormalizationLayerInfo(NormType::CROSS_MAP, 5, 0.0001f, 0.75f) } + } + { + } + + ~GoogLeNetNormalizationLayerDataset() = default; +}; + +class AlexNetNormalizationLayerDataset final : public NormalizationLayerDataset<2> +{ +public: + AlexNetNormalizationLayerDataset() + : GenericDataset + { + NormalizationLayerDataObject{ TensorShape(55U, 55U, 96U), NormalizationLayerInfo(NormType::CROSS_MAP, 5, 0.0001f, 0.75f) }, + NormalizationLayerDataObject{ TensorShape(27U, 27U, 256U), NormalizationLayerInfo(NormType::CROSS_MAP, 5, 0.0001f, 0.75f) }, + } + { + } + + ~AlexNetNormalizationLayerDataset() = default; +}; + +} // namespace test +} // namespace arm_compute +#endif /* __ARM_COMPUTE_TEST_DATASET_NORMALIZATION_LAYER_DATASET_H__ */ diff --git a/tests/validation_old/dataset/NormalizationTypeDataset.h b/tests/validation_old/dataset/NormalizationTypeDataset.h new file mode 100644 index 0000000000..2a89dbea30 --- /dev/null +++ b/tests/validation_old/dataset/NormalizationTypeDataset.h @@ -0,0 +1,80 @@ +/* + * 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_NORMALIZATION_TYPE_DATASET_H__ +#define __ARM_COMPUTE_TEST_NORMALIZATION_TYPE_DATASET_H__ + +#include "arm_compute/core/Types.h" + +#ifdef BOOST +#include "tests/validation_old/boost_wrapper.h" +#endif /* BOOST */ + +namespace arm_compute +{ +namespace test +{ +/** Data set containing all possible normalization types. + * + * Can be used as input for Boost data test cases to automatically run a test + * case on all normalization types. + */ +class NormalizationTypes +{ +public: + /** Type of the samples in the data set. */ + using sample = NormType; + + /** Dimensionality of the data set. */ + enum + { + arity = 1 + }; + + /** Number of samples in the data set. */ +#ifdef BOOST + boost::unit_test::data::size_t size() const +#else /* BOOST */ + unsigned int size() const +#endif /* BOOST */ + { + return _types.size(); + } + + /** Type of the iterator used to step through all samples in the data set. + * Needs to support operator*() and operator++() which a pointer does. + */ + using iterator = const NormType *; + + /** Iterator to the first sample in the data set. */ + iterator begin() const + { + return _types.data(); + } + +private: + const std::array<NormType, 3> _types{ { NormType::IN_MAP_1D, NormType::IN_MAP_2D, NormType::CROSS_MAP } }; +}; +} // namespace test +} // namespace arm_compute +#endif /* __ARM_COMPUTE_TEST_NORMALIZATION_TYPE_DATASET_H__ */ diff --git a/tests/validation_old/dataset/PoolingLayerDataset.h b/tests/validation_old/dataset/PoolingLayerDataset.h new file mode 100644 index 0000000000..6895ae4fae --- /dev/null +++ b/tests/validation_old/dataset/PoolingLayerDataset.h @@ -0,0 +1,138 @@ +/* + * 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_DATASET_POOLING_LAYER_DATASET_H__ +#define __ARM_COMPUTE_TEST_DATASET_POOLING_LAYER_DATASET_H__ + +#include "TypePrinter.h" + +#include "arm_compute/core/TensorShape.h" +#include "arm_compute/core/Types.h" +#include "tests/validation_old/dataset/GenericDataset.h" + +#include <type_traits> + +#ifdef BOOST +#include "tests/validation_old/boost_wrapper.h" +#endif /* BOOST */ + +namespace arm_compute +{ +namespace test +{ +class PoolingLayerDataObject +{ +public: + operator std::string() const + { + std::stringstream ss; + ss << "PoolingLayer"; + ss << "_I" << src_shape; + ss << "_S_" << info.pool_size(); + ss << "_F_" << info.pool_type(); + ss << "_PS" << info.pad_stride_info(); + return ss.str(); + } + + friend std::ostream &operator<<(std::ostream &s, const PoolingLayerDataObject &obj) + { + s << static_cast<std::string>(obj); + return s; + } + +public: + TensorShape src_shape; + TensorShape dst_shape; + PoolingLayerInfo info; +}; + +template <unsigned int Size> +using PoolingLayerDataset = GenericDataset<PoolingLayerDataObject, Size>; + +class AlexNetPoolingLayerDataset final : public PoolingLayerDataset<3> +{ +public: + AlexNetPoolingLayerDataset() + : GenericDataset + { + PoolingLayerDataObject{ TensorShape(55U, 55U, 96U), TensorShape(27U, 27U, 96U), PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0)) }, + PoolingLayerDataObject{ TensorShape(27U, 27U, 256U), TensorShape(13U, 13U, 256U), PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0)) }, + PoolingLayerDataObject{ TensorShape(13U, 13U, 256U), TensorShape(6U, 6U, 256U), PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0)) }, + } + { + } + + ~AlexNetPoolingLayerDataset() = default; +}; + +class LeNet5PoolingLayerDataset final : public PoolingLayerDataset<2> +{ +public: + LeNet5PoolingLayerDataset() + : GenericDataset + { + PoolingLayerDataObject{ TensorShape(24U, 24U, 20U), TensorShape(12U, 12U, 20U), PoolingLayerInfo(PoolingType::MAX, 2, PadStrideInfo(2, 2, 0, 0)) }, + PoolingLayerDataObject{ TensorShape(8U, 8U, 50U), TensorShape(4U, 4U, 50U), PoolingLayerInfo(PoolingType::MAX, 2, PadStrideInfo(2, 2, 0, 0)) }, + } + { + } + + ~LeNet5PoolingLayerDataset() = default; +}; + +class GoogLeNetPoolingLayerDataset final : public PoolingLayerDataset<10> +{ +public: + GoogLeNetPoolingLayerDataset() + : GenericDataset + { + // FIXME: Add support for 7x7 pooling layer pool5/7x7_s1 + // pool1/3x3_s2 + PoolingLayerDataObject{ TensorShape(112U, 112U, 64U), TensorShape(56U, 56U, 64U), PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0, DimensionRoundingType::CEIL)) }, + // pool2/3x3_s2 + PoolingLayerDataObject{ TensorShape(56U, 56U, 192U), TensorShape(28U, 28U, 192U), PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0, DimensionRoundingType::CEIL)) }, + // inception_3a/pool + PoolingLayerDataObject{ TensorShape(28U, 28U, 192U), TensorShape(28U, 28U, 192U), PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(1, 1, 1, 1, DimensionRoundingType::CEIL)) }, + // inception_3b/pool + PoolingLayerDataObject{ TensorShape(28U, 28U, 256U), TensorShape(28U, 28U, 256U), PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(1, 1, 1, 1, DimensionRoundingType::CEIL)) }, + // pool3/3x3_s2 + PoolingLayerDataObject{ TensorShape(28U, 28U, 480U), TensorShape(14U, 14U, 480U), PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0, DimensionRoundingType::CEIL)) }, + // inception_4a/pool + PoolingLayerDataObject{ TensorShape(14U, 14U, 480U), TensorShape(14U, 14U, 480U), PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(1, 1, 1, 1, DimensionRoundingType::CEIL)) }, + // inception_4b/pool, inception_4c/pool, inception_4d/pool + PoolingLayerDataObject{ TensorShape(14U, 14U, 512U), TensorShape(14U, 14U, 512U), PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(1, 1, 1, 1, DimensionRoundingType::CEIL)) }, + // inception_4e/pool + PoolingLayerDataObject{ TensorShape(14U, 14U, 528U), TensorShape(14U, 14U, 528U), PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(1, 1, 1, 1, DimensionRoundingType::CEIL)) }, + // pool4/3x3_s2 + PoolingLayerDataObject{ TensorShape(14U, 14U, 832U), TensorShape(7U, 7U, 832U), PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0, DimensionRoundingType::CEIL)) }, + // inception_5a/pool, inception_5b/pool + PoolingLayerDataObject{ TensorShape(7U, 7U, 832U), TensorShape(7U, 7U, 832U), PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(1, 1, 1, 1, DimensionRoundingType::CEIL)) }, + } + { + } + + ~GoogLeNetPoolingLayerDataset() = default; +}; +} // namespace test +} // namespace arm_compute +#endif //__ARM_COMPUTE_TEST_DATASET_POOLING_LAYER_DATASET_H__ diff --git a/tests/validation_old/dataset/PoolingTypesDataset.h b/tests/validation_old/dataset/PoolingTypesDataset.h new file mode 100644 index 0000000000..a826df35ce --- /dev/null +++ b/tests/validation_old/dataset/PoolingTypesDataset.h @@ -0,0 +1,55 @@ +/* + * 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_DATASET_POOLING_TYPE_DATASET_H__ +#define __ARM_COMPUTE_TEST_DATASET_POOLING_TYPE_DATASET_H__ + +#include "arm_compute/core/Types.h" +#include "tests/validation_old/dataset/GenericDataset.h" + +#ifdef BOOST +#include "tests/validation_old/boost_wrapper.h" +#endif /* BOOST */ + +namespace arm_compute +{ +namespace test +{ +/** Data set containing all possible pooling types. + * + * Can be used as input for Boost data test cases to automatically run a test + * case on all pooling types. + */ +class PoolingTypes final : public GenericDataset<PoolingType, 2> +{ +public: + PoolingTypes() + : GenericDataset{ PoolingType::MAX, PoolingType::AVG } + { + } + + ~PoolingTypes() = default; +}; +} // namespace test +} // namespace arm_compute +#endif //__ARM_COMPUTE_TEST_DATASET_POOLING_TYPE_DATASET_H__ diff --git a/tests/validation_old/dataset/RoundingPolicyDataset.h b/tests/validation_old/dataset/RoundingPolicyDataset.h new file mode 100644 index 0000000000..af946b41bd --- /dev/null +++ b/tests/validation_old/dataset/RoundingPolicyDataset.h @@ -0,0 +1,82 @@ +/* + * 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_ROUNDING_POLICY_DATASETS_H__ +#define __ARM_COMPUTE_TEST_ROUNDING_POLICY_DATASETS_H__ + +#include "arm_compute/core/Types.h" + +#include <type_traits> + +#ifdef BOOST +#include "tests/validation_old/boost_wrapper.h" +#endif /* BOOST */ + +namespace arm_compute +{ +namespace test +{ +/** Data set containing all possible rounding policies. + * + * Can be used as input for Boost data test cases to automatically run a test + * case on different rounding policies. + */ +class RoundingPolicies +{ +public: + /** Type of the samples in the data set. */ + using sample = RoundingPolicy; + + /** Dimensionality of the data set. */ + enum + { + arity = 1 + }; + + /** Number of samples in the data set. */ +#ifdef BOOST + boost::unit_test::data::size_t size() const +#else /* BOOST */ + unsigned int size() const +#endif /* BOOST */ + { + return _policies.size(); + } + + /** Type of the iterator used to step through all samples in the data set. + * Needs to support operator*() and operator++() which a pointer does. + */ + using iterator = const RoundingPolicy *; + + /** Iterator to the first sample in the data set. */ + iterator begin() const + { + return _policies.data(); + } + +private: + std::array<RoundingPolicy, 3> _policies{ { RoundingPolicy::TO_ZERO, RoundingPolicy::TO_NEAREST_UP, RoundingPolicy::TO_NEAREST_EVEN } }; +}; +} // namespace test +} // namespace arm_compute +#endif /* __ARM_COMPUTE_TEST_ROUNDING_POLICY_DATASETS_H__ */ diff --git a/tests/validation_old/dataset/ShapeDatasets.h b/tests/validation_old/dataset/ShapeDatasets.h new file mode 100644 index 0000000000..3c986ab7ae --- /dev/null +++ b/tests/validation_old/dataset/ShapeDatasets.h @@ -0,0 +1,152 @@ +/* + * 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_SHAPE_DATASETS_H__ +#define __ARM_COMPUTE_TEST_SHAPE_DATASETS_H__ + +#include "arm_compute/core/TensorShape.h" + +#include <type_traits> + +#ifdef BOOST +#include "tests/validation_old/boost_wrapper.h" +#endif /* BOOST */ + +namespace arm_compute +{ +namespace test +{ +/** Abstract data set containing tensor shapes. + * + * Can be used as input for Boost data test cases to automatically run a test + * case on different tensor shapes. + */ +template <unsigned int Size> +class ShapeDataset +{ +public: + /** Type of the samples in the data set. */ + using sample = TensorShape; + + /** Dimensionality of the data set. */ + enum + { + arity = 1 + }; + + /** Number of samples in the data set. */ +#ifdef BOOST + boost::unit_test::data::size_t size() const +#else /* BOOST */ + unsigned int size() const +#endif /* BOOST */ + { + return _shapes.size(); + } + + /** Type of the iterator used to step through all samples in the data set. + * Needs to support operator*() and operator++() which a pointer does. + */ + using iterator = const TensorShape *; + + /** Iterator to the first sample in the data set. */ + iterator begin() const + { + return _shapes.data(); + } + +protected: + /** Protected constructor to make the class abstract. */ + template <typename... Ts> + ShapeDataset(Ts... shapes) + : _shapes{ { shapes... } } + { + } + + /** Protected destructor to prevent deletion of derived class through a + * pointer to the base class. + */ + ~ShapeDataset() = default; + +private: + std::array<TensorShape, Size> _shapes; +}; + +/** Data set containing one 1D tensor shape. */ +class Small1DShape final : public ShapeDataset<1> +{ +public: + Small1DShape() + : ShapeDataset(TensorShape(256U)) + { + } +}; + +/** Data set containing two small 2D tensor shapes. */ +class Small2DShapes final : public ShapeDataset<2> +{ +public: + Small2DShapes() + : ShapeDataset(TensorShape(17U, 17U), + TensorShape(640U, 480U)) + { + } +}; + +/** Data set containing small tensor shapes. */ +class SmallShapes final : public ShapeDataset<3> +{ +public: + SmallShapes() + : ShapeDataset(TensorShape(7U, 7U), + TensorShape(27U, 13U, 2U), + TensorShape(128U, 64U, 1U, 3U)) + { + } +}; + +/** Data set containing large tensor shapes. */ +class LargeShapes final : public ShapeDataset<3> +{ +public: + LargeShapes() + : ShapeDataset(TensorShape(1920U, 1080U), + TensorShape(1245U, 652U, 1U, 3U), + TensorShape(4160U, 3120U)) + { + } +}; + +/** Data set containing two 2D large tensor shapes. */ +class Large2DShapes final : public ShapeDataset<2> +{ +public: + Large2DShapes() + : ShapeDataset(TensorShape(1920U, 1080U), + TensorShape(4160U, 3120U)) + { + } +}; +} // namespace test +} // namespace arm_compute +#endif /* __ARM_COMPUTE_TEST_SHAPE_DATASETS_H__ */ diff --git a/tests/validation_old/dataset/ThresholdDataset.h b/tests/validation_old/dataset/ThresholdDataset.h new file mode 100644 index 0000000000..74d0b9cfbe --- /dev/null +++ b/tests/validation_old/dataset/ThresholdDataset.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_DATASET_THRESHOLD_DATASET_H__ +#define __ARM_COMPUTE_TEST_DATASET_THRESHOLD_DATASET_H__ + +#include "TypePrinter.h" + +#include "arm_compute/core/TensorShape.h" +#include "arm_compute/core/Types.h" +#include "tests/validation_old/dataset/GenericDataset.h" + +#include <ostream> +#include <sstream> + +#include <tuple> +#include <type_traits> + +#ifdef BOOST +#include "tests/validation_old/boost_wrapper.h" +#endif /* BOOST */ + +namespace arm_compute +{ +namespace test +{ +class ThresholdDataObject +{ +public: + uint8_t threshold; + uint8_t false_value; + uint8_t true_value; + ThresholdType type; + uint8_t upper; + + operator std::string() const + { + std::stringstream ss; + ss << "Threshold"; + ss << "_threshold_value" << threshold; + ss << "_false_value" << std::boolalpha << false_value; + ss << "_true_value" << std::boolalpha << true_value; + ss << "_type"; + ss << ((type == ThresholdType::BINARY) ? "binary" : "range"); + ss << "_upper" << upper; + return ss.str(); + } + + friend std::ostream &operator<<(std::ostream &os, const ThresholdDataObject &obj) + { + os << static_cast<std::string>(obj); + return os; + } +}; + +class ThresholdDataset : public GenericDataset<ThresholdDataObject, 4> +{ +public: + ThresholdDataset() + : GenericDataset + { + ThresholdDataObject{ 10U, 25U, 3U, ThresholdType::BINARY, 0U }, + ThresholdDataObject{ 20U, 1U, 0U, ThresholdType::BINARY, 0U }, + ThresholdDataObject{ 30U, 1U, 0U, ThresholdType::RANGE, 100U }, + ThresholdDataObject{ 100U, 1U, 0U, ThresholdType::RANGE, 200U }, + } + { + } + + ~ThresholdDataset() = default; +}; + +} // namespace test +} // namespace arm_compute +#endif /* __ARM_COMPUTE_TEST_DATASET_THRESHOLD_DATASET_H__ */ diff --git a/tests/validation_old/half.h b/tests/validation_old/half.h new file mode 100644 index 0000000000..d8aa341068 --- /dev/null +++ b/tests/validation_old/half.h @@ -0,0 +1,37 @@ +/* + * 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_HALF_H__ +#define __ARM_COMPUTE_TEST_HALF_H__ + +#ifdef __ANDROID__ +// Android toolchain is broken and doesn't support all CPP11 math functions. +#define HALF_ENABLE_CPP11_CMATH 0 +#endif /* __ANDROID__ */ + +// Set style to round to nearest +#define HALF_ROUND_STYLE 1 +#define HALF_ROUND_TIES_TO_EVEN 1 + +#include "half/half.hpp" +#endif /* __ARM_COMPUTE_TEST_HALF_H__ */ diff --git a/tests/validation_old/main.cpp b/tests/validation_old/main.cpp new file mode 100644 index 0000000000..9f15c3a7bc --- /dev/null +++ b/tests/validation_old/main.cpp @@ -0,0 +1,97 @@ +/* + * 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. + */ +#define BOOST_TEST_ALTERNATIVE_INIT_API + +#include "Utils.h" +#include "ValidationProgramOptions.h" +#include "ValidationUserConfiguration.h" +#include "support/ToolchainSupport.h" +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" + +#include "arm_compute/runtime/Scheduler.h" + +#include "tests/validation_old/boost_wrapper.h" + +#include <iostream> +#include <memory> +#include <random> + +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace arm_compute +{ +namespace test +{ +ValidationUserConfiguration user_config; +std::unique_ptr<AssetsLibrary> library; +} // namespace test +} // namespace arm_compute + +struct GlobalFixture +{ + GlobalFixture() + { + library = arm_compute::support::cpp14::make_unique<AssetsLibrary>(user_config.path.get(), user_config.seed); + std::cout << "Seed: " << library->seed() << "\n"; + } +}; + +BOOST_GLOBAL_FIXTURE(GlobalFixture); + +bool init_unit_test() +{ + boost::unit_test::framework::master_test_suite().p_name.value = "Compute Library Validation Tests"; + + ValidationProgramOptions options; + + int &argc = boost::unit_test::framework::master_test_suite().argc; + char **argv = boost::unit_test::framework::master_test_suite().argv; + + try + { + options.parse_commandline(argc, argv); + + if(options.wants_help()) + { + std::cout << "Usage: " << argv[0] << " [options] PATH\n"; + std::cout << options.get_help() << "\n"; + return false; + } + + user_config = ValidationUserConfiguration(options); + } + catch(const boost::program_options::required_option &err) + { + std::cerr << "Error: " << err.what() << "\n"; + std::cout << "\nUsage: " << argv[0] << " [options] PATH\n"; + std::cout << options.get_help() << "\n"; + return false; + } + + std::cout << "Using " << user_config.threads << " CPU " << (user_config.threads == 1 ? "thread" : "threads") << "\n"; + arm_compute::Scheduler::get().set_num_threads(user_config.threads); + return true; +} diff --git a/tests/validation_old/model_objects/AlexNet.h b/tests/validation_old/model_objects/AlexNet.h new file mode 100644 index 0000000000..45622e2118 --- /dev/null +++ b/tests/validation_old/model_objects/AlexNet.h @@ -0,0 +1,585 @@ +/* + * 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_MODEL_OBJECTS_ALEXNET_H__ +#define __ARM_COMPUTE_TEST_MODEL_OBJECTS_ALEXNET_H__ + +#include "arm_compute/runtime/Tensor.h" + +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/Utils.h" + +#include <memory> + +using namespace arm_compute; +using namespace arm_compute::test; + +namespace arm_compute +{ +namespace test +{ +namespace model_objects +{ +/** AlexNet model object */ +template <typename ITensorType, + typename TensorType, + typename SubTensorType, + typename Accessor, + typename ActivationLayerFunction, + typename ConvolutionLayerFunction, + typename FullyConnectedLayerFunction, + typename NormalizationLayerFunction, + typename PoolingLayerFunction, + typename SoftmaxLayerFunction, + DataType dt = DataType::F32, + int fixed_point_position = 4> +class AlexNet +{ +public: + AlexNet() + : _batches(1), _reshaped_weights(false) + { + } + + void init_weights(unsigned int batches, bool reshaped_weights = false) + { + _batches = batches; + _reshaped_weights = reshaped_weights; + + // Initialize weights and biases + if(!_reshaped_weights) + { + for(auto &wi : w) + { + wi = std::unique_ptr<TensorType>(new TensorType()); + } + for(auto &bi : b) + { + bi = std::unique_ptr<TensorType>(new TensorType()); + } + w[0]->allocator()->init(TensorInfo(TensorShape(11U, 11U, 3U, 96U), 1, dt, fixed_point_position)); + b[0]->allocator()->init(TensorInfo(TensorShape(96U), 1, dt, fixed_point_position)); + w[1]->allocator()->init(TensorInfo(TensorShape(5U, 5U, 48U, 256U), 1, dt, fixed_point_position)); + b[1]->allocator()->init(TensorInfo(TensorShape(256U), 1, dt, fixed_point_position)); + w[2]->allocator()->init(TensorInfo(TensorShape(3U, 3U, 256U, 384U), 1, dt, fixed_point_position)); + b[2]->allocator()->init(TensorInfo(TensorShape(384U), 1, dt, fixed_point_position)); + w[3]->allocator()->init(TensorInfo(TensorShape(3U, 3U, 192U, 384U), 1, dt, fixed_point_position)); + b[3]->allocator()->init(TensorInfo(TensorShape(384U), 1, dt, fixed_point_position)); + w[4]->allocator()->init(TensorInfo(TensorShape(3U, 3U, 192U, 256U), 1, dt, fixed_point_position)); + b[4]->allocator()->init(TensorInfo(TensorShape(256U), 1, dt, fixed_point_position)); + w[5]->allocator()->init(TensorInfo(TensorShape(9216U, 4096U), 1, dt, fixed_point_position)); + b[5]->allocator()->init(TensorInfo(TensorShape(4096U), 1, dt, fixed_point_position)); + w[6]->allocator()->init(TensorInfo(TensorShape(4096U, 4096U), 1, dt, fixed_point_position)); + b[6]->allocator()->init(TensorInfo(TensorShape(4096U), 1, dt, fixed_point_position)); + w[7]->allocator()->init(TensorInfo(TensorShape(4096U, 1000U), 1, dt, fixed_point_position)); + b[7]->allocator()->init(TensorInfo(TensorShape(1000U), 1, dt, fixed_point_position)); + + w21 = std::unique_ptr<SubTensorType>(new SubTensorType(w[1].get(), TensorShape(5U, 5U, 48U, 128U), Coordinates())); + w22 = std::unique_ptr<SubTensorType>(new SubTensorType(w[1].get(), TensorShape(5U, 5U, 48U, 128U), Coordinates(0, 0, 0, 128))); + b21 = std::unique_ptr<SubTensorType>(new SubTensorType(b[1].get(), TensorShape(128U), Coordinates())); + b22 = std::unique_ptr<SubTensorType>(new SubTensorType(b[1].get(), TensorShape(128U), Coordinates(128))); + + w41 = std::unique_ptr<SubTensorType>(new SubTensorType(w[3].get(), TensorShape(3U, 3U, 192U, 192U), Coordinates())); + w42 = std::unique_ptr<SubTensorType>(new SubTensorType(w[3].get(), TensorShape(3U, 3U, 192U, 192U), Coordinates(0, 0, 0, 192))); + b41 = std::unique_ptr<SubTensorType>(new SubTensorType(b[3].get(), TensorShape(192U), Coordinates())); + b42 = std::unique_ptr<SubTensorType>(new SubTensorType(b[3].get(), TensorShape(192U), Coordinates(192))); + + w51 = std::unique_ptr<SubTensorType>(new SubTensorType(w[4].get(), TensorShape(3U, 3U, 192U, 128U), Coordinates())); + w52 = std::unique_ptr<SubTensorType>(new SubTensorType(w[4].get(), TensorShape(3U, 3U, 192U, 128U), Coordinates(0, 0, 0, 128))); + b51 = std::unique_ptr<SubTensorType>(new SubTensorType(b[4].get(), TensorShape(128U), Coordinates())); + b52 = std::unique_ptr<SubTensorType>(new SubTensorType(b[4].get(), TensorShape(128U), Coordinates(128))); + } + else + { + const unsigned int dt_size = 16 / arm_compute::data_size_from_type(dt); + + // Create tensor for the reshaped weights + w[0] = std::unique_ptr<TensorType>(new TensorType()); + auto w21_tensor = std::unique_ptr<TensorType>(new TensorType()); + auto w22_tensor = std::unique_ptr<TensorType>(new TensorType()); + w[2] = std::unique_ptr<TensorType>(new TensorType()); + auto w41_tensor = std::unique_ptr<TensorType>(new TensorType()); + auto w42_tensor = std::unique_ptr<TensorType>(new TensorType()); + auto w51_tensor = std::unique_ptr<TensorType>(new TensorType()); + auto w52_tensor = std::unique_ptr<TensorType>(new TensorType()); + + w[0]->allocator()->init(TensorInfo(TensorShape(366U * dt_size, 96U / dt_size), 1, dt, fixed_point_position)); + w21_tensor->allocator()->init(TensorInfo(TensorShape(1248U * dt_size, 128U / dt_size), 1, dt, fixed_point_position)); + w22_tensor->allocator()->init(TensorInfo(TensorShape(1248U * dt_size, 128U / dt_size), 1, dt, fixed_point_position)); + w[2]->allocator()->init(TensorInfo(TensorShape(2560U * dt_size, 384U / dt_size), 1, dt, fixed_point_position)); + w41_tensor->allocator()->init(TensorInfo(TensorShape(1920U * dt_size, 192U / dt_size), 1, dt, fixed_point_position)); + w42_tensor->allocator()->init(TensorInfo(TensorShape(1920U * dt_size, 192U / dt_size), 1, dt, fixed_point_position)); + w51_tensor->allocator()->init(TensorInfo(TensorShape(1920U * dt_size, 128U / dt_size), 1, dt, fixed_point_position)); + w52_tensor->allocator()->init(TensorInfo(TensorShape(1920U * dt_size, 128U / dt_size), 1, dt, fixed_point_position)); + + w21 = std::move(w21_tensor); + w22 = std::move(w22_tensor); + w41 = std::move(w41_tensor); + w42 = std::move(w42_tensor); + w51 = std::move(w51_tensor); + w52 = std::move(w52_tensor); + + w[5] = std::unique_ptr<TensorType>(new TensorType()); + w[6] = std::unique_ptr<TensorType>(new TensorType()); + w[7] = std::unique_ptr<TensorType>(new TensorType()); + b[5] = std::unique_ptr<TensorType>(new TensorType()); + b[6] = std::unique_ptr<TensorType>(new TensorType()); + b[7] = std::unique_ptr<TensorType>(new TensorType()); + + b[5]->allocator()->init(TensorInfo(TensorShape(4096U), 1, dt, fixed_point_position)); + b[6]->allocator()->init(TensorInfo(TensorShape(4096U), 1, dt, fixed_point_position)); + b[7]->allocator()->init(TensorInfo(TensorShape(1000U), 1, dt, fixed_point_position)); + + if(_batches > 1 && std::is_same<TensorType, Tensor>::value) + { + w[5]->allocator()->init(TensorInfo(TensorShape(9216U * dt_size, 4096U / dt_size), 1, dt, fixed_point_position)); + w[6]->allocator()->init(TensorInfo(TensorShape(4096U * dt_size, 4096U / dt_size), 1, dt, fixed_point_position)); + w[7]->allocator()->init(TensorInfo(TensorShape(4096U * dt_size, 1000U / dt_size), 1, dt, fixed_point_position)); + } + else + { + w[5]->allocator()->init(TensorInfo(TensorShape(4096U, 9216U), 1, dt, fixed_point_position)); + w[6]->allocator()->init(TensorInfo(TensorShape(4096U, 4096U), 1, dt, fixed_point_position)); + w[7]->allocator()->init(TensorInfo(TensorShape(1000U, 4096U), 1, dt, fixed_point_position)); + } + } + } + + void build() + { + input.allocator()->init(TensorInfo(TensorShape(227U, 227U, 3U, _batches), 1, dt, fixed_point_position)); + output.allocator()->init(TensorInfo(TensorShape(1000U, _batches), 1, dt, fixed_point_position)); + + // Initialize intermediate tensors + // Layer 1 + conv1_out.allocator()->init(TensorInfo(TensorShape(55U, 55U, 96U, _batches), 1, dt, fixed_point_position)); + act1_out.allocator()->init(TensorInfo(TensorShape(55U, 55U, 96U, _batches), 1, dt, fixed_point_position)); + norm1_out.allocator()->init(TensorInfo(TensorShape(55U, 55U, 96U, _batches), 1, dt, fixed_point_position)); + pool1_out.allocator()->init(TensorInfo(TensorShape(27U, 27U, 96U, _batches), 1, dt, fixed_point_position)); + pool11_out = std::unique_ptr<SubTensorType>(new SubTensorType(&pool1_out, TensorShape(27U, 27U, 48U, _batches), Coordinates())); + pool12_out = std::unique_ptr<SubTensorType>(new SubTensorType(&pool1_out, TensorShape(27U, 27U, 48U, _batches), Coordinates(0, 0, 48))); + // Layer 2 + conv2_out.allocator()->init(TensorInfo(TensorShape(27U, 27U, 256U, _batches), 1, dt, fixed_point_position)); + conv21_out = std::unique_ptr<SubTensorType>(new SubTensorType(&conv2_out, TensorShape(27U, 27U, 128U, _batches), Coordinates())); + conv22_out = std::unique_ptr<SubTensorType>(new SubTensorType(&conv2_out, TensorShape(27U, 27U, 128U, _batches), Coordinates(0, 0, 128))); + act2_out.allocator()->init(TensorInfo(TensorShape(27U, 27U, 256U, _batches), 1, dt, fixed_point_position)); + norm2_out.allocator()->init(TensorInfo(TensorShape(27U, 27U, 256U, _batches), 1, dt, fixed_point_position)); + pool2_out.allocator()->init(TensorInfo(TensorShape(13U, 13U, 256U, _batches), 1, dt, fixed_point_position)); + // Layer 3 + conv3_out.allocator()->init(TensorInfo(TensorShape(13U, 13U, 384U, _batches), 1, dt, fixed_point_position)); + act3_out.allocator()->init(TensorInfo(TensorShape(13U, 13U, 384U, _batches), 1, dt, fixed_point_position)); + act31_out = std::unique_ptr<SubTensorType>(new SubTensorType(&act3_out, TensorShape(13U, 13U, 192U, _batches), Coordinates())); + act32_out = std::unique_ptr<SubTensorType>(new SubTensorType(&act3_out, TensorShape(13U, 13U, 192U, _batches), Coordinates(0, 0, 192))); + // Layer 4 + conv4_out.allocator()->init(TensorInfo(TensorShape(13U, 13U, 384U, _batches), 1, dt, fixed_point_position)); + conv41_out = std::unique_ptr<SubTensorType>(new SubTensorType(&conv4_out, TensorShape(13U, 13U, 192U, _batches), Coordinates())); + conv42_out = std::unique_ptr<SubTensorType>(new SubTensorType(&conv4_out, TensorShape(13U, 13U, 192U, _batches), Coordinates(0, 0, 192))); + act4_out.allocator()->init(TensorInfo(TensorShape(13U, 13U, 384U, _batches), 1, dt, fixed_point_position)); + act41_out = std::unique_ptr<SubTensorType>(new SubTensorType(&act4_out, TensorShape(13U, 13U, 192U, _batches), Coordinates())); + act42_out = std::unique_ptr<SubTensorType>(new SubTensorType(&act4_out, TensorShape(13U, 13U, 192U, _batches), Coordinates(0, 0, 192))); + // Layer 5 + conv5_out.allocator()->init(TensorInfo(TensorShape(13U, 13U, 256U, _batches), 1, dt, fixed_point_position)); + conv51_out = std::unique_ptr<SubTensorType>(new SubTensorType(&conv5_out, TensorShape(13U, 13U, 128U, _batches), Coordinates())); + conv52_out = std::unique_ptr<SubTensorType>(new SubTensorType(&conv5_out, TensorShape(13U, 13U, 128U, _batches), Coordinates(0, 0, 128))); + act5_out.allocator()->init(TensorInfo(TensorShape(13U, 13U, 256U, _batches), 1, dt, fixed_point_position)); + pool5_out.allocator()->init(TensorInfo(TensorShape(6U, 6U, 256U, _batches), 1, dt, fixed_point_position)); + // Layer 6 + fc6_out.allocator()->init(TensorInfo(TensorShape(4096U, _batches), 1, dt, fixed_point_position)); + act6_out.allocator()->init(TensorInfo(TensorShape(4096U, _batches), 1, dt, fixed_point_position)); + // Layer 7 + fc7_out.allocator()->init(TensorInfo(TensorShape(4096U, _batches), 1, dt, fixed_point_position)); + act7_out.allocator()->init(TensorInfo(TensorShape(4096U, _batches), 1, dt, fixed_point_position)); + // Layer 8 + fc8_out.allocator()->init(TensorInfo(TensorShape(1000U, _batches), 1, dt, fixed_point_position)); + + // Allocate layers + { + // Layer 1 + conv1 = std::unique_ptr<ConvolutionLayerFunction>(new ConvolutionLayerFunction()); + act1 = std::unique_ptr<ActivationLayerFunction>(new ActivationLayerFunction()); + norm1 = std::unique_ptr<NormalizationLayerFunction>(new NormalizationLayerFunction()); + pool1 = std::unique_ptr<PoolingLayerFunction>(new PoolingLayerFunction()); + // Layer 2 + conv21 = std::unique_ptr<ConvolutionLayerFunction>(new ConvolutionLayerFunction()); + conv22 = std::unique_ptr<ConvolutionLayerFunction>(new ConvolutionLayerFunction()); + act2 = std::unique_ptr<ActivationLayerFunction>(new ActivationLayerFunction()); + norm2 = std::unique_ptr<NormalizationLayerFunction>(new NormalizationLayerFunction()); + pool2 = std::unique_ptr<PoolingLayerFunction>(new PoolingLayerFunction()); + // Layer 3 + conv3 = std::unique_ptr<ConvolutionLayerFunction>(new ConvolutionLayerFunction()); + act3 = std::unique_ptr<ActivationLayerFunction>(new ActivationLayerFunction()); + // Layer 4 + conv41 = std::unique_ptr<ConvolutionLayerFunction>(new ConvolutionLayerFunction()); + conv42 = std::unique_ptr<ConvolutionLayerFunction>(new ConvolutionLayerFunction()); + act4 = std::unique_ptr<ActivationLayerFunction>(new ActivationLayerFunction()); + // Layer 5 + conv51 = std::unique_ptr<ConvolutionLayerFunction>(new ConvolutionLayerFunction()); + conv52 = std::unique_ptr<ConvolutionLayerFunction>(new ConvolutionLayerFunction()); + act5 = std::unique_ptr<ActivationLayerFunction>(new ActivationLayerFunction()); + pool5 = std::unique_ptr<PoolingLayerFunction>(new PoolingLayerFunction()); + // Layer 6 + fc6 = std::unique_ptr<FullyConnectedLayerFunction>(new FullyConnectedLayerFunction()); + act6 = std::unique_ptr<ActivationLayerFunction>(new ActivationLayerFunction()); + // Layer 7 + fc7 = std::unique_ptr<FullyConnectedLayerFunction>(new FullyConnectedLayerFunction()); + act7 = std::unique_ptr<ActivationLayerFunction>(new ActivationLayerFunction()); + // Layer 8 + fc8 = std::unique_ptr<FullyConnectedLayerFunction>(new FullyConnectedLayerFunction()); + // Softmax + smx = std::unique_ptr<SoftmaxLayerFunction>(new SoftmaxLayerFunction()); + } + + // Configure Layers + { + // Layer 1 + conv1->configure(&input, w[0].get(), b[0].get(), &conv1_out, PadStrideInfo(4, 4, 0, 0), WeightsInfo(_reshaped_weights, 11U, 11U, 96U)); + act1->configure(&conv1_out, &act1_out, ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)); + norm1->configure(&act1_out, &norm1_out, NormalizationLayerInfo(NormType::CROSS_MAP, 5, 0.0001f, 0.75f)); + pool1->configure(&norm1_out, &pool1_out, PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0))); + // Layer 2 + conv21->configure(pool11_out.get(), w21.get(), b21.get(), conv21_out.get(), PadStrideInfo(1, 1, 2, 2), WeightsInfo(_reshaped_weights, 5U, 5U, 128U)); + conv22->configure(pool12_out.get(), w22.get(), b22.get(), conv22_out.get(), PadStrideInfo(1, 1, 2, 2), WeightsInfo(_reshaped_weights, 5U, 5U, 128U)); + act2->configure(&conv2_out, &act2_out, ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)); + norm2->configure(&act2_out, &norm2_out, NormalizationLayerInfo(NormType::CROSS_MAP, 5, 0.0001f, 0.75f)); + pool2->configure(&norm2_out, &pool2_out, PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0))); + // Layer 3 + conv3->configure(&pool2_out, w[2].get(), b[2].get(), &conv3_out, PadStrideInfo(1, 1, 1, 1), WeightsInfo(_reshaped_weights, 3U, 3U, 384U)); + act3->configure(&conv3_out, &act3_out, ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)); + // Layer 4 + conv41->configure(act31_out.get(), w41.get(), b41.get(), conv41_out.get(), PadStrideInfo(1, 1, 1, 1), WeightsInfo(_reshaped_weights, 3U, 3U, 192U)); + conv42->configure(act32_out.get(), w42.get(), b42.get(), conv42_out.get(), PadStrideInfo(1, 1, 1, 1), WeightsInfo(_reshaped_weights, 3U, 3U, 192U)); + act4->configure(&conv4_out, &act4_out, ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)); + // Layer 5 + conv51->configure(act41_out.get(), w51.get(), b51.get(), conv51_out.get(), PadStrideInfo(1, 1, 1, 1), WeightsInfo(_reshaped_weights, 3U, 3U, 128U)); + conv52->configure(act42_out.get(), w52.get(), b52.get(), conv52_out.get(), PadStrideInfo(1, 1, 1, 1), WeightsInfo(_reshaped_weights, 3U, 3U, 128U)); + act5->configure(&conv5_out, &act5_out, ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)); + pool5->configure(&act5_out, &pool5_out, PoolingLayerInfo(PoolingType::MAX, 3, PadStrideInfo(2, 2, 0, 0))); + // Layer 6 + fc6->configure(&pool5_out, w[5].get(), b[5].get(), &fc6_out, true, _reshaped_weights); + act6->configure(&fc6_out, &act6_out, ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)); + // Layer 7 + fc7->configure(&act6_out, w[6].get(), b[6].get(), &fc7_out, true, _reshaped_weights); + act7->configure(&fc7_out, &act7_out, ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)); + // Layer 8 + fc8->configure(&act7_out, w[7].get(), b[7].get(), &fc8_out, true, _reshaped_weights); + // Softmax + smx->configure(&fc8_out, &output); + } + } + + void allocate() + { + input.allocator()->allocate(); + output.allocator()->allocate(); + for(auto &wi : w) + { + if(wi.get()) + { + wi->allocator()->allocate(); + } + } + for(auto &bi : b) + { + if(bi.get()) + { + bi->allocator()->allocate(); + } + } + if(_reshaped_weights) + { + dynamic_cast<TensorType *>(w21.get())->allocator()->allocate(); + dynamic_cast<TensorType *>(w22.get())->allocator()->allocate(); + dynamic_cast<TensorType *>(w41.get())->allocator()->allocate(); + dynamic_cast<TensorType *>(w42.get())->allocator()->allocate(); + dynamic_cast<TensorType *>(w51.get())->allocator()->allocate(); + dynamic_cast<TensorType *>(w52.get())->allocator()->allocate(); + } + conv1_out.allocator()->allocate(); + act1_out.allocator()->allocate(); + norm1_out.allocator()->allocate(); + pool1_out.allocator()->allocate(); + conv2_out.allocator()->allocate(); + act2_out.allocator()->allocate(); + norm2_out.allocator()->allocate(); + pool2_out.allocator()->allocate(); + conv3_out.allocator()->allocate(); + act3_out.allocator()->allocate(); + conv4_out.allocator()->allocate(); + act4_out.allocator()->allocate(); + conv5_out.allocator()->allocate(); + act5_out.allocator()->allocate(); + pool5_out.allocator()->allocate(); + fc6_out.allocator()->allocate(); + act6_out.allocator()->allocate(); + fc7_out.allocator()->allocate(); + act7_out.allocator()->allocate(); + fc8_out.allocator()->allocate(); + } + + /** Fills the trainable parameters and input with random data. */ + void fill_random() + { + library->fill_tensor_uniform(Accessor(input), 0); + if(!_reshaped_weights) + { + for(unsigned int i = 0; i < w.size(); ++i) + { + library->fill_tensor_uniform(Accessor(*w[i]), i + 1); + library->fill_tensor_uniform(Accessor(*b[i]), i + 10); + } + } + else + { + library->fill_tensor_uniform(Accessor(*w[0]), 1); + library->fill_tensor_uniform(Accessor(*w[2]), 2); + + library->fill_tensor_uniform(Accessor(*w[5]), 3); + library->fill_tensor_uniform(Accessor(*b[5]), 4); + library->fill_tensor_uniform(Accessor(*w[6]), 5); + library->fill_tensor_uniform(Accessor(*b[6]), 6); + library->fill_tensor_uniform(Accessor(*w[7]), 7); + library->fill_tensor_uniform(Accessor(*b[7]), 8); + + library->fill_tensor_uniform(Accessor(*dynamic_cast<TensorType *>(w21.get())), 9); + library->fill_tensor_uniform(Accessor(*dynamic_cast<TensorType *>(w22.get())), 10); + library->fill_tensor_uniform(Accessor(*dynamic_cast<TensorType *>(w41.get())), 11); + library->fill_tensor_uniform(Accessor(*dynamic_cast<TensorType *>(w42.get())), 12); + library->fill_tensor_uniform(Accessor(*dynamic_cast<TensorType *>(w51.get())), 13); + library->fill_tensor_uniform(Accessor(*dynamic_cast<TensorType *>(w52.get())), 14); + } + } + +#ifdef INTERNAL_ONLY + /** Fills the trainable parameters from binary files + * + * @param weights Files names containing the weights data + * @param biases Files names containing the bias data + */ + void fill(std::vector<std::string> weights, std::vector<std::string> biases) + { + ARM_COMPUTE_ERROR_ON(weights.size() != w.size()); + ARM_COMPUTE_ERROR_ON(biases.size() != b.size()); + ARM_COMPUTE_ERROR_ON(_reshaped_weights); + + for(unsigned int i = 0; i < weights.size(); ++i) + { + library->fill_layer_data(Accessor(*w[i]), weights[i]); + library->fill_layer_data(Accessor(*b[i]), biases[i]); + } + } + + /** Feed input to network from file. + * + * @param name File name of containing the input data. + */ + void feed(std::string name) + { + library->fill_layer_data(Accessor(input), name); + } +#endif /* INTERNAL_ONLY */ + + /** Get the classification results. + * + * @return Vector containing the classified labels + */ + std::vector<unsigned int> get_classifications() + { + std::vector<unsigned int> classified_labels; + Accessor output_accessor(output); + + Window window; + window.set(Window::DimX, Window::Dimension(0, 1, 1)); + for(unsigned int d = 1; d < output_accessor.shape().num_dimensions(); ++d) + { + window.set(d, Window::Dimension(0, output_accessor.shape()[d], 1)); + } + + execute_window_loop(window, [&](const Coordinates & id) + { + int max_idx = 0; + float val = 0; + const void *const out_ptr = output_accessor(id); + for(unsigned int l = 0; l < output_accessor.shape().x(); ++l) + { + float curr_val = reinterpret_cast<const float *>(out_ptr)[l]; + if(curr_val > val) + { + max_idx = l; + val = curr_val; + } + } + classified_labels.push_back(max_idx); + }); + return classified_labels; + } + + /** Clear all allocated memory from the tensor objects */ + void clear() + { + conv1.reset(); + act1.reset(); + norm1.reset(); + pool1.reset(); + conv21.reset(); + conv22.reset(); + act2.reset(); + norm2.reset(); + pool2.reset(); + conv3.reset(); + act3.reset(); + conv41.reset(); + conv42.reset(); + act4.reset(); + conv51.reset(); + conv52.reset(); + act5.reset(); + pool5.reset(); + fc6.reset(); + act6.reset(); + fc7.reset(); + act7.reset(); + fc8.reset(); + smx.reset(); + + // Free allocations + input.allocator()->free(); + output.allocator()->free(); + for(auto &wi : w) + { + wi.reset(); + } + for(auto &bi : b) + { + bi.reset(); + } + + w21.reset(); + w22.reset(); + b21.reset(); + b21.reset(); + w41.reset(); + w42.reset(); + b41.reset(); + b42.reset(); + w51.reset(); + w52.reset(); + b51.reset(); + b52.reset(); + + conv1_out.allocator()->free(); + act1_out.allocator()->free(); + norm1_out.allocator()->free(); + pool1_out.allocator()->free(); + conv2_out.allocator()->free(); + act2_out.allocator()->free(); + norm2_out.allocator()->free(); + pool2_out.allocator()->free(); + conv3_out.allocator()->free(); + act3_out.allocator()->free(); + conv4_out.allocator()->free(); + act4_out.allocator()->free(); + conv5_out.allocator()->free(); + act5_out.allocator()->free(); + pool5_out.allocator()->free(); + fc6_out.allocator()->free(); + act6_out.allocator()->free(); + fc7_out.allocator()->free(); + act7_out.allocator()->free(); + fc8_out.allocator()->free(); + } + + /** Runs the model */ + void run() + { + // Layer 1 + conv1->run(); + act1->run(); + norm1->run(); + pool1->run(); + // Layer 2 + conv21->run(); + conv22->run(); + act2->run(); + norm2->run(); + pool2->run(); + // Layer 3 + conv3->run(); + act3->run(); + // Layer 4 + conv41->run(); + conv42->run(); + act4->run(); + // Layer 5 + conv51->run(); + conv52->run(); + act5->run(); + pool5->run(); + // Layer 6 + fc6->run(); + act6->run(); + // Layer 7 + fc7->run(); + act7->run(); + // Layer 8 + fc8->run(); + // Softmax + smx->run(); + } + +private: + unsigned int _batches; + bool _reshaped_weights; + + std::unique_ptr<ActivationLayerFunction> act1{ nullptr }, act2{ nullptr }, act3{ nullptr }, act4{ nullptr }, act5{ nullptr }, act6{ nullptr }, act7{ nullptr }; + std::unique_ptr<ConvolutionLayerFunction> conv1{ nullptr }, conv21{ nullptr }, conv22{ nullptr }, conv3{ nullptr }, conv41{ nullptr }, conv42{ nullptr }, conv51{ nullptr }, conv52{ nullptr }; + std::unique_ptr<FullyConnectedLayerFunction> fc6{ nullptr }, fc7{ nullptr }, fc8{}; + std::unique_ptr<NormalizationLayerFunction> norm1{ nullptr }, norm2{ nullptr }; + std::unique_ptr<PoolingLayerFunction> pool1{ nullptr }, pool2{ nullptr }, pool5{ nullptr }; + std::unique_ptr<SoftmaxLayerFunction> smx{ nullptr }; + + TensorType input{}, output{}; + std::array<std::unique_ptr<TensorType>, 8> w{}, b{}; + std::unique_ptr<ITensorType> w21{ nullptr }, w22{ nullptr }, b21{ nullptr }, b22{ nullptr }; + std::unique_ptr<ITensorType> w41{ nullptr }, w42{ nullptr }, b41{ nullptr }, b42{ nullptr }; + std::unique_ptr<ITensorType> w51{ nullptr }, w52{ nullptr }, b51{ nullptr }, b52{ nullptr }; + + TensorType conv1_out{}, act1_out{}, norm1_out{}, pool1_out{}; + TensorType conv2_out{}, act2_out{}, pool2_out{}, norm2_out{}; + TensorType conv3_out{}, act3_out{}; + TensorType conv4_out{}, act4_out{}; + TensorType conv5_out{}, act5_out{}, pool5_out{}; + TensorType fc6_out{}, act6_out{}; + TensorType fc7_out{}, act7_out{}; + TensorType fc8_out{}; + + std::unique_ptr<SubTensorType> pool11_out{ nullptr }, pool12_out{ nullptr }; + std::unique_ptr<SubTensorType> conv21_out{ nullptr }, conv22_out{ nullptr }; + std::unique_ptr<SubTensorType> act31_out{ nullptr }, act32_out{ nullptr }; + std::unique_ptr<SubTensorType> conv41_out{ nullptr }, conv42_out{ nullptr }, act41_out{ nullptr }, act42_out{ nullptr }; + std::unique_ptr<SubTensorType> conv51_out{ nullptr }, conv52_out{ nullptr }; +}; +} // namespace model_objects +} // namespace test +} // namespace arm_compute +#endif //__ARM_COMPUTE_TEST_MODEL_OBJECTS_ALEXNET_H__ diff --git a/tests/validation_old/model_objects/LeNet5.h b/tests/validation_old/model_objects/LeNet5.h new file mode 100644 index 0000000000..d3e72b0010 --- /dev/null +++ b/tests/validation_old/model_objects/LeNet5.h @@ -0,0 +1,278 @@ +/* + * 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_MODEL_OBJECTS_LENET5_H__ +#define __ARM_COMPUTE_TEST_MODEL_OBJECTS_LENET5_H__ + +#include "tests/AssetsLibrary.h" +#include "tests/Globals.h" +#include "tests/Utils.h" + +#include <memory> + +using namespace arm_compute; +using namespace arm_compute::test; + +namespace arm_compute +{ +namespace test +{ +namespace model_objects +{ +/** Lenet5 model object */ +template <typename TensorType, + typename Accessor, + typename ActivationLayerFunction, + typename ConvolutionLayerFunction, + typename FullyConnectedLayerFunction, + typename PoolingLayerFunction, + typename SoftmaxLayerFunction> +class LeNet5 +{ +public: + /** Initialize and build the model. + * + * @param batches Number of batches should handle + */ + void build(unsigned int batches) + { + // Initialize input, output, weights and biases + input.allocator()->init(TensorInfo(TensorShape(28U, 28U, 1U, batches), 1, DataType::F32)); + output.allocator()->init(TensorInfo(TensorShape(10U, batches), 1, DataType::F32)); + w[0].allocator()->init(TensorInfo(TensorShape(5U, 5U, 1U, 20U), 1, DataType::F32)); + b[0].allocator()->init(TensorInfo(TensorShape(20U), 1, DataType::F32)); + w[1].allocator()->init(TensorInfo(TensorShape(5U, 5U, 20U, 50U), 1, DataType::F32)); + b[1].allocator()->init(TensorInfo(TensorShape(50U), 1, DataType::F32)); + w[2].allocator()->init(TensorInfo(TensorShape(800U, 500U), 1, DataType::F32)); + b[2].allocator()->init(TensorInfo(TensorShape(500U), 1, DataType::F32)); + w[3].allocator()->init(TensorInfo(TensorShape(500U, 10U), 1, DataType::F32)); + b[3].allocator()->init(TensorInfo(TensorShape(10U), 1, DataType::F32)); + + // Initialize intermediate tensors + // Layer 1 + conv1_out.allocator()->init(TensorInfo(TensorShape(24U, 24U, 20U, batches), 1, DataType::F32)); + pool1_out.allocator()->init(TensorInfo(TensorShape(12U, 12U, 20U, batches), 1, DataType::F32)); + // Layer 2 + conv2_out.allocator()->init(TensorInfo(TensorShape(8U, 8U, 50U, batches), 1, DataType::F32)); + pool2_out.allocator()->init(TensorInfo(TensorShape(4U, 4U, 50U, batches), 1, DataType::F32)); + // Layer 3 + fc1_out.allocator()->init(TensorInfo(TensorShape(500U, batches), 1, DataType::F32)); + act1_out.allocator()->init(TensorInfo(TensorShape(500U, batches), 1, DataType::F32)); + // Layer 6 + fc2_out.allocator()->init(TensorInfo(TensorShape(10U, batches), 1, DataType::F32)); + + // Allocate layers + { + // Layer 1 + conv1 = std::unique_ptr<ConvolutionLayerFunction>(new ConvolutionLayerFunction()); + pool1 = std::unique_ptr<PoolingLayerFunction>(new PoolingLayerFunction()); + // Layer 2 + conv2 = std::unique_ptr<ConvolutionLayerFunction>(new ConvolutionLayerFunction()); + pool2 = std::unique_ptr<PoolingLayerFunction>(new PoolingLayerFunction()); + // Layer 3 + fc1 = std::unique_ptr<FullyConnectedLayerFunction>(new FullyConnectedLayerFunction()); + act1 = std::unique_ptr<ActivationLayerFunction>(new ActivationLayerFunction()); + // Layer 4 + fc2 = std::unique_ptr<FullyConnectedLayerFunction>(new FullyConnectedLayerFunction()); + // Softmax + smx = std::unique_ptr<SoftmaxLayerFunction>(new SoftmaxLayerFunction()); + } + + // Configure Layers + { + conv1->configure(&input, &w[0], &b[0], &conv1_out, PadStrideInfo(1, 1, 0, 0)); + pool1->configure(&conv1_out, &pool1_out, PoolingLayerInfo(PoolingType::MAX, 2, PadStrideInfo(2, 2, 0, 0))); + conv2->configure(&pool1_out, &w[1], &b[1], &conv2_out, PadStrideInfo(1, 1, 0, 0)); + pool2->configure(&conv2_out, &pool2_out, PoolingLayerInfo(PoolingType::MAX, 2, PadStrideInfo(2, 2, 0, 0))); + fc1->configure(&pool2_out, &w[2], &b[2], &fc1_out); + act1->configure(&fc1_out, &act1_out, ActivationLayerInfo(ActivationLayerInfo::ActivationFunction::RELU)); + fc2->configure(&act1_out, &w[3], &b[3], &fc2_out); + smx->configure(&fc2_out, &output); + } + + // Allocate tensors + { + input.allocator()->allocate(); + output.allocator()->allocate(); + for(auto &wi : w) + { + wi.allocator()->allocate(); + } + for(auto &bi : b) + { + bi.allocator()->allocate(); + } + conv1_out.allocator()->allocate(); + pool1_out.allocator()->allocate(); + conv2_out.allocator()->allocate(); + pool2_out.allocator()->allocate(); + fc1_out.allocator()->allocate(); + act1_out.allocator()->allocate(); + fc2_out.allocator()->allocate(); + } + } + + /** Fills the trainable parameters and input with random data. */ + void fill_random() + { + std::uniform_real_distribution<> distribution(-1, 1); + library->fill(Accessor(input), distribution, 0); + for(unsigned int i = 0; i < w.size(); ++i) + { + library->fill(Accessor(w[i]), distribution, i + 1); + library->fill(Accessor(b[i]), distribution, i + 10); + } + } + +#ifdef INTERNAL_ONLY + /** Fills the trainable parameters from binary files + * + * @param weights Files names containing the weights data + * @param biases Files names containing the bias data + */ + void fill(std::vector<std::string> weights, std::vector<std::string> biases) + { + ARM_COMPUTE_ERROR_ON(weights.size() != w.size()); + ARM_COMPUTE_ERROR_ON(biases.size() != b.size()); + + for(unsigned int i = 0; i < weights.size(); ++i) + { + library->fill_layer_data(Accessor(w[i]), weights[i]); + library->fill_layer_data(Accessor(b[i]), biases[i]); + } + } + + /** Feed input to network from file. + * + * @param name File name of containing the input data. + */ + void feed(std::string name) + { + library->fill_layer_data(Accessor(input), name); + } +#endif /* INTERNAL_ONLY */ + + /** Get the classification results. + * + * @return Vector containing the classified labels + */ + std::vector<unsigned int> get_classifications() + { + std::vector<unsigned int> classified_labels; + Accessor output_accessor(output); + + Window window; + window.set(Window::DimX, Window::Dimension(0, 1, 1)); + for(unsigned int d = 1; d < output_accessor.shape().num_dimensions(); ++d) + { + window.set(d, Window::Dimension(0, output_accessor.shape()[d], 1)); + } + + execute_window_loop(window, [&](const Coordinates & id) + { + int max_idx = 0; + float val = 0; + const void *const out_ptr = output_accessor(id); + for(unsigned int l = 0; l < output_accessor.shape().x(); ++l) + { + float curr_val = reinterpret_cast<const float *>(out_ptr)[l]; + if(curr_val > val) + { + max_idx = l; + val = curr_val; + } + } + classified_labels.push_back(max_idx); + }); + return classified_labels; + } + + /** Clear all allocated memory from the tensor objects */ + void clear() + { + conv1.reset(); + pool1.reset(); + conv2.reset(); + pool2.reset(); + fc1.reset(); + act1.reset(); + fc2.reset(); + smx.reset(); + + input.allocator()->free(); + output.allocator()->free(); + for(auto &wi : w) + { + wi.allocator()->free(); + } + for(auto &bi : b) + { + bi.allocator()->free(); + } + + conv1_out.allocator()->free(); + pool1_out.allocator()->free(); + conv2_out.allocator()->free(); + pool2_out.allocator()->free(); + fc1_out.allocator()->free(); + act1_out.allocator()->free(); + fc2_out.allocator()->free(); + } + + /** Runs the model */ + void run() + { + // Layer 1 + conv1->run(); + pool1->run(); + // Layer 2 + conv2->run(); + pool2->run(); + // Layer 3 + fc1->run(); + act1->run(); + // Layer 4 + fc2->run(); + // Softmax + smx->run(); + } + +private: + std::unique_ptr<ActivationLayerFunction> act1{ nullptr }; + std::unique_ptr<ConvolutionLayerFunction> conv1{ nullptr }, conv2{ nullptr }; + std::unique_ptr<FullyConnectedLayerFunction> fc1{ nullptr }, fc2{ nullptr }; + std::unique_ptr<PoolingLayerFunction> pool1{ nullptr }, pool2{ nullptr }; + std::unique_ptr<SoftmaxLayerFunction> smx{ nullptr }; + + TensorType input{}, output{}; + std::array<TensorType, 4> w{}, b{}; + + TensorType conv1_out{}, pool1_out{}; + TensorType conv2_out{}, pool2_out{}; + TensorType fc1_out{}, act1_out{}; + TensorType fc2_out{}; +}; +} // namespace model_objects +} // namespace test +} // namespace arm_compute +#endif //__ARM_COMPUTE_TEST_MODEL_OBJECTS_LENET5_H__ diff --git a/tests/validation_old/system_tests/CL/AlexNet.cpp b/tests/validation_old/system_tests/CL/AlexNet.cpp new file mode 100644 index 0000000000..b403b6e93c --- /dev/null +++ b/tests/validation_old/system_tests/CL/AlexNet.cpp @@ -0,0 +1,132 @@ +/* + * 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. + */ +#ifdef INTERNAL_ONLY //FIXME Delete this file before the release +/* + * 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 "tests/validation_old/Validation.h" + +#include "arm_compute/runtime/CL/CLSubTensor.h" +#include "arm_compute/runtime/CL/functions/CLActivationLayer.h" +#include "arm_compute/runtime/CL/functions/CLConvolutionLayer.h" +#include "arm_compute/runtime/CL/functions/CLFullyConnectedLayer.h" +#include "arm_compute/runtime/CL/functions/CLNormalizationLayer.h" +#include "arm_compute/runtime/CL/functions/CLPoolingLayer.h" +#include "arm_compute/runtime/CL/functions/CLSoftmaxLayer.h" + +#include "tests/validation_old/model_objects/AlexNet.h" + +#include <array> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +using CLAlexNetModel = model_objects::AlexNet<ICLTensor, + CLTensor, + CLSubTensor, + CLAccessor, + CLActivationLayer, + CLConvolutionLayer, + CLFullyConnectedLayer, + CLNormalizationLayer, + CLPoolingLayer, + CLSoftmaxLayer>; +std::vector<unsigned int> compute_alexnet(unsigned int batches, std::string input_file) +{ + std::vector<std::string> weight_files = { "cnn_data/alexnet_model/conv1_w.dat", + "cnn_data/alexnet_model/conv2_w.dat", + "cnn_data/alexnet_model/conv3_w.dat", + "cnn_data/alexnet_model/conv4_w.dat", + "cnn_data/alexnet_model/conv5_w.dat", + "cnn_data/alexnet_model/fc6_w.dat", + "cnn_data/alexnet_model/fc7_w.dat", + "cnn_data/alexnet_model/fc8_w.dat" + }; + + std::vector<std::string> bias_files = { "cnn_data/alexnet_model/conv1_b.dat", + "cnn_data/alexnet_model/conv2_b.dat", + "cnn_data/alexnet_model/conv3_b.dat", + "cnn_data/alexnet_model/conv4_b.dat", + "cnn_data/alexnet_model/conv5_b.dat", + "cnn_data/alexnet_model/fc6_b.dat", + "cnn_data/alexnet_model/fc7_b.dat", + "cnn_data/alexnet_model/fc8_b.dat" + }; + CLAlexNetModel network{}; + network.init_weights(batches); + network.build(); + network.allocate(); + network.fill(weight_files, bias_files); + network.feed(std::move(input_file)); + network.run(); + + return network.get_classifications(); +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(SYSTEM_TESTS) +BOOST_AUTO_TEST_SUITE(CL) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_AUTO_TEST_CASE(AlexNet) +{ + // Compute alexnet + std::vector<unsigned int> classified_labels = compute_alexnet(1, "cnn_data/imagenet_data/shark.dat"); + + // Expected labels + std::vector<unsigned int> expected_labels = { 2 }; + + // Validate labels + validate(classified_labels, expected_labels); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ +#endif /* INTERNAL_ONLY */ diff --git a/tests/validation_old/system_tests/CL/LeNet5.cpp b/tests/validation_old/system_tests/CL/LeNet5.cpp new file mode 100644 index 0000000000..0f34dd1ae7 --- /dev/null +++ b/tests/validation_old/system_tests/CL/LeNet5.cpp @@ -0,0 +1,115 @@ +/* + * 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. + */ +#ifdef INTERNAL_ONLY //FIXME Delete this file before the release +/* + * 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 "tests/validation_old/Validation.h" + +#include "arm_compute/runtime/CL/functions/CLActivationLayer.h" +#include "arm_compute/runtime/CL/functions/CLConvolutionLayer.h" +#include "arm_compute/runtime/CL/functions/CLFullyConnectedLayer.h" +#include "arm_compute/runtime/CL/functions/CLPoolingLayer.h" +#include "arm_compute/runtime/CL/functions/CLSoftmaxLayer.h" + +#include "tests/validation_old/model_objects/LeNet5.h" + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +using CLLeNet5Model = model_objects::LeNet5<CLTensor, + CLAccessor, + CLActivationLayer, + CLConvolutionLayer, + CLFullyConnectedLayer, + CLPoolingLayer, + CLSoftmaxLayer>; +std::vector<unsigned int> compute_lenet5(unsigned int batches, std::string input_file) +{ + std::vector<std::string> weight_files = { "cnn_data/lenet_model/conv1_w.dat", + "cnn_data/lenet_model/conv2_w.dat", + "cnn_data/lenet_model/ip1_w.dat", + "cnn_data/lenet_model/ip2_w.dat" + }; + + std::vector<std::string> bias_files = { "cnn_data/lenet_model/conv1_b.dat", + "cnn_data/lenet_model/conv2_b.dat", + "cnn_data/lenet_model/ip1_b.dat", + "cnn_data/lenet_model/ip2_b.dat" + }; + CLLeNet5Model network{}; + network.build(batches); + network.fill(weight_files, bias_files); + network.feed(std::move(input_file)); + network.run(); + + return network.get_classifications(); +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(SYSTEM_TESTS) +BOOST_AUTO_TEST_SUITE(CL) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_AUTO_TEST_CASE(LeNet5) +{ + // Compute alexnet + std::vector<unsigned int> classified_labels = compute_lenet5(10, "cnn_data/mnist_data/input100.dat"); + + // Expected labels + std::vector<unsigned int> expected_labels = { 7, 2, 1, 0, 4, 1, 4, 9, 5, 9 }; + + // Validate labels + validate(classified_labels, expected_labels); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ +#endif /* INTERNAL_ONLY */ diff --git a/tests/validation_old/system_tests/NEON/AlexNet.cpp b/tests/validation_old/system_tests/NEON/AlexNet.cpp new file mode 100644 index 0000000000..9697cf35e8 --- /dev/null +++ b/tests/validation_old/system_tests/NEON/AlexNet.cpp @@ -0,0 +1,133 @@ +/* + * 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. + */ +#ifdef INTERNAL_ONLY //FIXME Delete this file before the release +/* + * 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 "NEON/Accessor.h" +#include "tests/validation_old/Validation.h" + +#include "arm_compute/runtime/NEON/functions/NEActivationLayer.h" +#include "arm_compute/runtime/NEON/functions/NEConvolutionLayer.h" +#include "arm_compute/runtime/NEON/functions/NEFullyConnectedLayer.h" +#include "arm_compute/runtime/NEON/functions/NENormalizationLayer.h" +#include "arm_compute/runtime/NEON/functions/NEPoolingLayer.h" +#include "arm_compute/runtime/NEON/functions/NESoftmaxLayer.h" +#include "arm_compute/runtime/SubTensor.h" + +#include "tests/validation_old/model_objects/AlexNet.h" + +#include <array> + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +using NEAlexNetModel = model_objects::AlexNet<ITensor, + Tensor, + SubTensor, + Accessor, + NEActivationLayer, + NEConvolutionLayer, + NEFullyConnectedLayer, + NENormalizationLayer, + NEPoolingLayer, + NESoftmaxLayer>; +std::vector<unsigned int> compute_alexnet(unsigned int batches, std::string input_file) +{ + std::vector<std::string> weight_files = { "cnn_data/alexnet_model/conv1_w.dat", + "cnn_data/alexnet_model/conv2_w.dat", + "cnn_data/alexnet_model/conv3_w.dat", + "cnn_data/alexnet_model/conv4_w.dat", + "cnn_data/alexnet_model/conv5_w.dat", + "cnn_data/alexnet_model/fc6_w.dat", + "cnn_data/alexnet_model/fc7_w.dat", + "cnn_data/alexnet_model/fc8_w.dat" + }; + + std::vector<std::string> bias_files = { "cnn_data/alexnet_model/conv1_b.dat", + "cnn_data/alexnet_model/conv2_b.dat", + "cnn_data/alexnet_model/conv3_b.dat", + "cnn_data/alexnet_model/conv4_b.dat", + "cnn_data/alexnet_model/conv5_b.dat", + "cnn_data/alexnet_model/fc6_b.dat", + "cnn_data/alexnet_model/fc7_b.dat", + "cnn_data/alexnet_model/fc8_b.dat" + }; + NEAlexNetModel network{}; + + network.init_weights(batches); + network.build(); + network.allocate(); + network.fill(weight_files, bias_files); + network.feed(std::move(input_file)); + network.run(); + + return network.get_classifications(); +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(SYSTEM_TESTS) +BOOST_AUTO_TEST_SUITE(NEON) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_AUTO_TEST_CASE(AlexNet) +{ + // Compute alexnet + std::vector<unsigned int> classified_labels = compute_alexnet(1, "cnn_data/imagenet_data/shark.dat"); + + // Expected labels + std::vector<unsigned int> expected_labels = { 2 }; + + // Validate labels + validate(classified_labels, expected_labels); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ +#endif /* INTERNAL_ONLY */ diff --git a/tests/validation_old/system_tests/NEON/LeNet5.cpp b/tests/validation_old/system_tests/NEON/LeNet5.cpp new file mode 100644 index 0000000000..916df98eb6 --- /dev/null +++ b/tests/validation_old/system_tests/NEON/LeNet5.cpp @@ -0,0 +1,115 @@ +/* + * 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. + */ +#ifdef INTERNAL_ONLY //FIXME Delete this file before the release +/* + * 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 "NEON/Accessor.h" +#include "tests/validation_old/Validation.h" + +#include "arm_compute/runtime/NEON/functions/NEActivationLayer.h" +#include "arm_compute/runtime/NEON/functions/NEConvolutionLayer.h" +#include "arm_compute/runtime/NEON/functions/NEFullyConnectedLayer.h" +#include "arm_compute/runtime/NEON/functions/NEPoolingLayer.h" +#include "arm_compute/runtime/NEON/functions/NESoftmaxLayer.h" + +#include "tests/validation_old/model_objects/LeNet5.h" + +using namespace arm_compute; +using namespace arm_compute::test; +using namespace arm_compute::test::validation; + +namespace +{ +using NELeNet5Model = model_objects::LeNet5<Tensor, + Accessor, + NEActivationLayer, + NEConvolutionLayer, + NEFullyConnectedLayer, + NEPoolingLayer, + NESoftmaxLayer>; +std::vector<unsigned int> compute_lenet5(unsigned int batches, std::string input_file) +{ + std::vector<std::string> weight_files = { "cnn_data/lenet_model/conv1_w.dat", + "cnn_data/lenet_model/conv2_w.dat", + "cnn_data/lenet_model/ip1_w.dat", + "cnn_data/lenet_model/ip2_w.dat" + }; + + std::vector<std::string> bias_files = { "cnn_data/lenet_model/conv1_b.dat", + "cnn_data/lenet_model/conv2_b.dat", + "cnn_data/lenet_model/ip1_b.dat", + "cnn_data/lenet_model/ip2_b.dat" + }; + NELeNet5Model network{}; + network.build(batches); + network.fill(weight_files, bias_files); + network.feed(std::move(input_file)); + network.run(); + + return network.get_classifications(); +} +} // namespace + +#ifndef DOXYGEN_SKIP_THIS +BOOST_AUTO_TEST_SUITE(SYSTEM_TESTS) +BOOST_AUTO_TEST_SUITE(NEON) + +BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit")) +BOOST_AUTO_TEST_CASE(LeNet5) +{ + // Compute alexnet + std::vector<unsigned int> classified_labels = compute_lenet5(10, "cnn_data/mnist_data/input100.dat"); + + // Expected labels + std::vector<unsigned int> expected_labels = { 7, 2, 1, 0, 4, 1, 4, 9, 5, 9 }; + + // Validate labels + validate(classified_labels, expected_labels); +} + +BOOST_AUTO_TEST_SUITE_END() +BOOST_AUTO_TEST_SUITE_END() +#endif /* DOXYGEN_SKIP_THIS */ +#endif /* INTERNAL_ONLY */ |