From 88d5b22eb5574d8b564474df2c758d222b3b5547 Mon Sep 17 00:00:00 2001 From: Isabella Gottardi Date: Fri, 6 Apr 2018 12:24:55 +0100 Subject: COMPMID-1035 - Add ResneXt50 as a graph example Change-Id: I42f0e7dab38e45b5eecfe6858eaecee8939c8585 Reviewed-on: https://eu-gerrit-1.euhpc.arm.com/129291 Reviewed-by: Georgios Pinitas Reviewed-by: Anthony Barbier Tested-by: Jenkins --- utils/GraphUtils.cpp | 39 ++++++++++++++++++++++++++++++++ utils/GraphUtils.h | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++- utils/Utils.h | 37 ++++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/GraphUtils.cpp b/utils/GraphUtils.cpp index 145e44950b..0edb6f2a56 100644 --- a/utils/GraphUtils.cpp +++ b/utils/GraphUtils.cpp @@ -129,6 +129,45 @@ bool DummyAccessor::access_tensor(ITensor &tensor) return ret; } +NumPyAccessor::NumPyAccessor(std::string npy_path, TensorShape shape, DataType data_type, std::ostream &output_stream) + : _npy_tensor(), _filename(std::move(npy_path)), _output_stream(output_stream) +{ + NumPyBinLoader loader(_filename); + + TensorInfo info(shape, 1, data_type); + _npy_tensor.allocator()->init(info); + _npy_tensor.allocator()->allocate(); + + loader.access_tensor(_npy_tensor); +} + +template +void NumPyAccessor::access_numpy_tensor(ITensor &tensor) +{ + const int num_elements = tensor.info()->total_size(); + int num_mismatches = utils::compare_tensor(tensor, _npy_tensor); + float percentage_mismatches = static_cast(num_mismatches) / num_elements; + + _output_stream << "Results: " << 100.f - (percentage_mismatches * 100) << " % matches with the provided output[" << _filename << "]." << std::endl; +} + +bool NumPyAccessor::access_tensor(ITensor &tensor) +{ + ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(&tensor, 1, DataType::F32); + ARM_COMPUTE_ERROR_ON(_npy_tensor.info()->dimension(0) != tensor.info()->dimension(0)); + + switch(tensor.info()->data_type()) + { + case DataType::F32: + access_numpy_tensor(tensor); + break; + default: + ARM_COMPUTE_ERROR("NOT SUPPORTED!"); + } + + return false; +} + PPMAccessor::PPMAccessor(std::string ppm_path, bool bgr, std::unique_ptr preprocessor) : _ppm_path(std::move(ppm_path)), _bgr(bgr), _preprocessor(std::move(preprocessor)) { diff --git a/utils/GraphUtils.h b/utils/GraphUtils.h index a8507b1ac7..597708369d 100644 --- a/utils/GraphUtils.h +++ b/utils/GraphUtils.h @@ -25,9 +25,11 @@ #define __ARM_COMPUTE_GRAPH_UTILS_H__ #include "arm_compute/core/PixelValue.h" +#include "arm_compute/core/utils/misc/Utility.h" #include "arm_compute/graph/Graph.h" #include "arm_compute/graph/ITensorAccessor.h" #include "arm_compute/graph/Types.h" +#include "arm_compute/runtime/Tensor.h" #include #include @@ -117,6 +119,37 @@ private: unsigned int _maximum; }; +/** NumPy accessor class */ +class NumPyAccessor final : public graph::ITensorAccessor +{ +public: + /** Constructor + * + * @param[in] npy_path Path to npy file. + * @param[in] shape Shape of the numpy tensor data. + * @param[in] data_type DataType of the numpy tensor data. + * @param[out] output_stream (Optional) Output stream + */ + NumPyAccessor(std::string npy_path, TensorShape shape, DataType data_type, std::ostream &output_stream = std::cout); + /** Allow instances of this class to be move constructed */ + NumPyAccessor(NumPyAccessor &&) = default; + /** Prevent instances of this class from being copied (As this class contains pointers) */ + NumPyAccessor(const NumPyAccessor &) = delete; + /** Prevent instances of this class from being copied (As this class contains pointers) */ + NumPyAccessor &operator=(const NumPyAccessor &) = delete; + + // Inherited methods overriden: + bool access_tensor(ITensor &tensor) override; + +private: + template + void access_numpy_tensor(ITensor &tensor); + + Tensor _npy_tensor; + const std::string _filename; + std::ostream &_output_stream; +}; + /** PPM accessor class */ class PPMAccessor final : public graph::ITensorAccessor { @@ -273,7 +306,14 @@ inline std::unique_ptr get_input_accessor(const std::str } else { - return arm_compute::support::cpp14::make_unique(ppm_path, bgr, std::move(preprocessor)); + if(arm_compute::utility::endswith(ppm_path, ".npy")) + { + return arm_compute::support::cpp14::make_unique(ppm_path); + } + else + { + return arm_compute::support::cpp14::make_unique(ppm_path, bgr, std::move(preprocessor)); + } } } @@ -298,6 +338,28 @@ inline std::unique_ptr get_output_accessor(const std::st return arm_compute::support::cpp14::make_unique(labels_path, top_n, output_stream); } } +/** Generates appropriate npy output accessor according to the specified npy_path + * + * @note If npy_path is empty will generate a DummyAccessor else will generate a NpyAccessor + * + * @param[in] npy_path Path to npy file. + * @param[in] shape Shape of the numpy tensor data. + * @param[in] data_type DataType of the numpy tensor data. + * @param[out] output_stream (Optional) Output stream + * + * @return An appropriate tensor accessor + */ +inline std::unique_ptr get_npy_output_accessor(const std::string &npy_path, TensorShape shape, DataType data_type, std::ostream &output_stream = std::cout) +{ + if(npy_path.empty()) + { + return arm_compute::support::cpp14::make_unique(0); + } + else + { + return arm_compute::support::cpp14::make_unique(npy_path, shape, data_type, output_stream); + } +} /** Utility function to return the TargetHint * diff --git a/utils/Utils.h b/utils/Utils.h index cadba3a088..6cb71fd3ba 100644 --- a/utils/Utils.h +++ b/utils/Utils.h @@ -924,6 +924,43 @@ void init_sgemm_output(T &dst, T &src0, T &src1, arm_compute::DataType dt) * @return The free memory in kB */ uint64_t get_mem_free_from_meminfo(); + +/** Compare to tensor + * + * @param[in] tensor1 First tensor to be compared. + * @param[in] tensor2 Second tensor to be compared. + * + * @return The number of mismatches + */ +template +int compare_tensor(ITensor &tensor1, ITensor &tensor2) +{ + ARM_COMPUTE_ERROR_ON_MISMATCHING_DATA_TYPES(&tensor1, &tensor2); + ARM_COMPUTE_ERROR_ON_MISMATCHING_SHAPES(&tensor1, &tensor2); + + int num_mismatches = 0; + Window window; + window.use_tensor_dimensions(tensor1.info()->tensor_shape()); + + map(tensor1, true); + map(tensor2, true); + Iterator itensor1(&tensor1, window); + Iterator itensor2(&tensor2, window); + + execute_window_loop(window, [&](const Coordinates & id) + { + if(std::abs(*reinterpret_cast(itensor1.ptr()) - *reinterpret_cast(itensor2.ptr())) > 0.00001) + { + ++num_mismatches; + } + }, + itensor1, itensor2); + + unmap(itensor1); + unmap(itensor2); + + return num_mismatches; +} } // namespace utils } // namespace arm_compute #endif /* __UTILS_UTILS_H__*/ -- cgit v1.2.1