From 3fa2bf519a68f6f2e24be30a4367369912f306de Mon Sep 17 00:00:00 2001 From: "zhao.xia" Date: Tue, 29 Jun 2021 13:25:50 +0800 Subject: [PATCH] Add map for moments Signed-off-by: zhao.xia --- include/tim/vx/ops/moments.h | 56 +++++++++ src/tim/vx/ops/README.md | 1 + src/tim/vx/ops/mements.cc | 41 +++++++ src/tim/vx/ops/moments_test.cc | 200 +++++++++++++++++++++++++++++++++ 4 files changed, 298 insertions(+) create mode 100644 include/tim/vx/ops/moments.h create mode 100644 src/tim/vx/ops/mements.cc create mode 100644 src/tim/vx/ops/moments_test.cc diff --git a/include/tim/vx/ops/moments.h b/include/tim/vx/ops/moments.h new file mode 100644 index 0000000..e7a6191 --- /dev/null +++ b/include/tim/vx/ops/moments.h @@ -0,0 +1,56 @@ +/**************************************************************************** +* +* Copyright (c) 2021 Vivante Corporation +* +* 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 TIM_VX_OPS_MOMENTS_H_ +#define TIM_VX_OPS_MOMENTS_H_ +#include "tim/vx/operation.h" + +namespace tim { +namespace vx { +namespace ops { + +/** + * ## Moments + * + * The mean and variance are calculated by aggregating the contents of x across axes. + * If x is 1-D and axes = [0] this is just the mean and variance of a vector. + * + * - axes : Axes along which to compute mean and variance. + * - keep_dims : Produce moments with the same dimensionality as input. + */ + +class Moments : public Operation { + public: + Moments(Graph* graph, const std::vector& axes, + bool keep_dims = false); + + protected: + const std::vector axes_; + const bool keep_dims_; +}; + +} // namespace ops +} // namespace vx +} // namespace tim + +#endif /* TIM_VX_OPS_MEMONTS_H_ */ diff --git a/src/tim/vx/ops/README.md b/src/tim/vx/ops/README.md index 6660c99..82dc49a 100644 --- a/src/tim/vx/ops/README.md +++ b/src/tim/vx/ops/README.md @@ -83,6 +83,7 @@ LogSoftmax|LOG_SOFTMAX|Mapped|[tf.nn.log_softmax](https://tensorflow.google.cn/a HardSwish|SWISH|Mapped|[tf.keras.activations.swish](https://tensorflow.google.cn/api_docs/python/tf/keras/activations/swish) GatherNd|GATHER_ND|Mapped|[tf.gather_nd](https://tensorflow.google.cn/api_docs/python/tf/gather_nd) Cast|CAST|Mapped|[tf.cast](https://tensorflow.google.cn/api_docs/python/tf/cast) +Moments|MOMENTS|Mapped|[tf.moments](https://tensorflow.google.cn/api_docs/python/tf/nn/moments) Squeeze|SQUEEZE|Mapped|[tf.squeeze](https://tensorflow.google.cn/api_docs/python/tf/squeeze) HardSigmoid|HARD_SIGMOID|Mapped|[tf.keras.activations.hard_sigmoid](https://tensorflow.google.cn/api_docs/python/tf/keras/activations/hard_sigmoid) Mish|MISH|Mapped|[tfa.activations.mish](https://tensorflow.google.cn/addons/api_docs/python/tfa/activations/mish) diff --git a/src/tim/vx/ops/mements.cc b/src/tim/vx/ops/mements.cc new file mode 100644 index 0000000..f4670e4 --- /dev/null +++ b/src/tim/vx/ops/mements.cc @@ -0,0 +1,41 @@ +/**************************************************************************** +* +* Copyright (c) 2021 Vivante Corporation +* +* 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 "tim/vx/ops/moments.h" + +#include "operation_private.h" +#include "type_utils.h" +#include "vsi_nn_pub.h" + +namespace tim { +namespace vx { +namespace ops { + Moments::Moments(Graph* graph, const std::vector& axes, bool keep_dims) + : Operation(graph, VSI_NN_OP_MOMENTS), axes_(axes), keep_dims_(keep_dims) { + this->impl()->node()->nn_param.moments.axis = axes_.data(); + this->impl()->node()->nn_param.moments.axis_num = axes_.size(); + this->impl()->node()->nn_param.moments.keep_dim = ToVxBool(keep_dims_); + } +} // namespace ops +} // namespace vx +} // namespace tim \ No newline at end of file diff --git a/src/tim/vx/ops/moments_test.cc b/src/tim/vx/ops/moments_test.cc new file mode 100644 index 0000000..a03038f --- /dev/null +++ b/src/tim/vx/ops/moments_test.cc @@ -0,0 +1,200 @@ +/**************************************************************************** +* +* Copyright (c) 2021 Vivante Corporation +* +* 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 +#include "tim/vx/context.h" +#include "tim/vx/graph.h" +#include "tim/vx/ops/moments.h" + +#include "gtest/gtest.h" + +namespace { +template +::testing::AssertionResult ArraysMatch(const std::vector& expected, + const std::vector& actual, + T abs_error, + const std::string& msg){ + for (size_t i = 0; i < expected.size(); ++i){ + EXPECT_NEAR(expected[i], actual[i], abs_error) << msg << " at index:" << i; + } + + return ::testing::AssertionSuccess(); +} +} + +TEST(Moments, shape_6_3_1_float_axes_0_1) { + auto ctx = tim::vx::Context::Create(); + auto graph = ctx->CreateGraph(); + + tim::vx::ShapeType input_shape({6, 3, 1}); + tim::vx::ShapeType output_shape({1}); + tim::vx::TensorSpec input_spec(tim::vx::DataType::FLOAT32, + input_shape, tim::vx::TensorAttribute::INPUT); + tim::vx::TensorSpec output_spec(tim::vx::DataType::FLOAT32, + output_shape, tim::vx::TensorAttribute::OUTPUT); + + auto input_tensor = graph->CreateTensor(input_spec); + auto mean = graph->CreateTensor(output_spec); + auto variance = graph->CreateTensor(output_spec); + + std::vector in_data = { + -2, 0, 2, + -3, 0, 3, + -4, 0, 4, + -5, 0, 5, + -6, 0, 6, + -7, 0, 7 }; + + std::vector mean_golden = { + 0 + }; + + std::vector variance_golden = { + 15.444444 + }; + + EXPECT_TRUE(input_tensor->CopyDataToTensor(in_data.data(), in_data.size() * sizeof(float))); + + std::vector axes = { 0, 1 }; + auto op = graph->CreateOperation(axes); + (*op).BindInputs({input_tensor}).BindOutputs({mean, variance}); + + EXPECT_TRUE(graph->Compile()); + EXPECT_TRUE(graph->Run()); + + std::vector mean_output(mean_golden); + std::vector variance_output(variance_golden); + EXPECT_TRUE(mean->CopyDataFromTensor(mean_output.data())); + EXPECT_TRUE(variance->CopyDataFromTensor(variance_output.data())); + EXPECT_TRUE(ArraysMatch(mean_golden, mean_output, 1e-5f, "mean output")); + EXPECT_TRUE(ArraysMatch(variance_golden, variance_output, 1e-5f, "variance output")); +} + +TEST(Moments, shape_3_6_1_float_axes_1_keepdims) { + auto ctx = tim::vx::Context::Create(); + auto graph = ctx->CreateGraph(); + + tim::vx::ShapeType input_shape({3, 6, 1}); + tim::vx::ShapeType output_shape({3,1,1}); + tim::vx::TensorSpec input_spec(tim::vx::DataType::FLOAT32, + input_shape, tim::vx::TensorAttribute::INPUT); + tim::vx::TensorSpec mean_spec(tim::vx::DataType::FLOAT32, + output_shape, tim::vx::TensorAttribute::OUTPUT); + tim::vx::TensorSpec variance_spec(tim::vx::DataType::FLOAT32, + output_shape, tim::vx::TensorAttribute::OUTPUT); + + auto input_tensor = graph->CreateTensor(input_spec); + auto mean = graph->CreateTensor(mean_spec); + auto variance = graph->CreateTensor(variance_spec); + + std::vector in_data = { + -2, 0, 2, + -3, 0, 3, + -4, 0, 4, + -5, 0, 5, + -6, 0, 6, + -7, 0, 7 + }; + + std::vector mean_golden = { + -4.5, 0, 4.5 + }; + + std::vector variance_golden = { + 2.916666, 0, 2.916666 + }; + + EXPECT_TRUE(input_tensor->CopyDataToTensor( + in_data.data(), in_data.size() * sizeof(float))); + + std::vector axes = { 1 }; + auto op = graph->CreateOperation(axes, true); + (*op).BindInputs({input_tensor}).BindOutputs({mean, variance}); + + EXPECT_TRUE(graph->Compile()); + EXPECT_TRUE(graph->Run()); + + std::vector mean_output(mean_golden); + std::vector variance_output(variance_golden); + EXPECT_TRUE(mean->CopyDataFromTensor(mean_output.data())); + EXPECT_TRUE(variance->CopyDataFromTensor(variance_output.data())); + EXPECT_TRUE(ArraysMatch(mean_golden, mean_output, 1e-5f, "mean output")); + EXPECT_TRUE(ArraysMatch(variance_golden, variance_output, 1e-5f, "variance output")); +} + +#if 0 +// TODO: Support uint8 +TEST(Moments, shape_3_6_1_uint8_axes_1_keepdims) { + auto ctx = tim::vx::Context::Create(); + auto graph = ctx->CreateGraph(); + + tim::vx::ShapeType input_shape({3, 6, 1}); + tim::vx::ShapeType output_shape({3,1,1}); + tim::vx::Quantization input_quant(tim::vx::QuantType::ASYMMETRIC, 1, 7); + tim::vx::Quantization mean_quant(tim::vx::QuantType::ASYMMETRIC, 0.5, 9); + tim::vx::Quantization variance_quant(tim::vx::QuantType::ASYMMETRIC, 2.916666, 0); + tim::vx::TensorSpec input_spec(tim::vx::DataType::UINT8, + input_shape, tim::vx::TensorAttribute::INPUT, input_quant); + tim::vx::TensorSpec mean_spec(tim::vx::DataType::UINT8, + output_shape, tim::vx::TensorAttribute::OUTPUT, mean_quant); + tim::vx::TensorSpec variance_spec(tim::vx::DataType::UINT8, + output_shape, tim::vx::TensorAttribute::OUTPUT, variance_quant); + + auto input_tensor = graph->CreateTensor(input_spec); + auto mean = graph->CreateTensor(mean_spec); + auto variance = graph->CreateTensor(variance_spec); + + std::vector in_data = { + 5, 7, 9, + 4, 7, 10, + 3, 7, 11, + 2, 7, 12, + 1, 7, 13, + 0, 7, 14, + }; + + std::vector mean_golden = { + 0, 9, 18 + }; + + std::vector variance_golden = { + 1, 0, 1 + }; + + EXPECT_TRUE(input_tensor->CopyDataToTensor(in_data.data(), in_data.size())); + + std::vector axes = { 1 }; + auto op = graph->CreateOperation(axes, true); + (*op).BindInputs({input_tensor}).BindOutputs({mean, variance}); + + EXPECT_TRUE(graph->Compile()); + EXPECT_TRUE(graph->Run()); + + std::vector mean_output(mean_golden); + std::vector variance_output(variance_golden); + EXPECT_TRUE(mean->CopyDataFromTensor(mean_output.data())); + EXPECT_TRUE(variance->CopyDataFromTensor(variance_output.data())); + EXPECT_EQ(mean_golden, mean_output); + EXPECT_EQ(variance_golden, variance_output); +} +#endif