--- /dev/null
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "Mean.hpp"
+#include "backends/WorkloadData.hpp"
+
+#include <boost/numeric/conversion/cast.hpp>
+
+#include <cmath>
+#include <cstddef>
+#include <functional>
+#include <limits>
+
+namespace armnn
+{
+bool NextIndex(const unsigned int numDims, const armnn::TensorShape& dims, std::vector<unsigned int>& current)
+{
+ unsigned int carry = 1;
+
+ for (unsigned int idx = numDims; idx-- > 0; )
+ {
+ unsigned int current_val = current[idx] + carry;
+ if (dims[idx] == current_val)
+ {
+ current[idx] = 0;
+ }
+ else
+ {
+ current[idx] = current_val;
+ carry = 0;
+ break;
+ }
+ }
+ return (carry == 0);
+}
+
+std::size_t ReducedOutputOffset(const unsigned int numDims, const armnn::TensorShape& dims,
+ std::vector<unsigned int>& index, const unsigned int numAxis,
+ const std::vector<unsigned int>& axis) {
+ std::size_t offset = 0;
+ for (unsigned int idx = 0; idx < numDims; ++idx)
+ {
+ bool isAxis = false;
+ if (!axis.empty())
+ {
+ for (unsigned int axisIdx = 0; axisIdx < numAxis; ++axisIdx)
+ {
+ if (idx == axis[axisIdx])
+ {
+ isAxis = true;
+ break;
+ }
+ }
+ }
+ if (!isAxis)
+ {
+ offset = offset * boost::numeric_cast<size_t>(dims[idx]) + boost::numeric_cast<size_t>(index[idx]);
+ }
+ }
+ return offset;
+}
+} // namespace
+
+namespace armnn
+{
+void Mean(const armnn::TensorInfo& inputInfo,
+ const armnn::TensorInfo& outputInfo,
+ const std::vector<unsigned int>& axis,
+ const float* inputData,
+ float* outputData) {
+
+ unsigned int inputNumDims = inputInfo.GetNumDimensions();
+ unsigned int outputNumDims = outputInfo.GetNumDimensions();
+
+ armnn::TensorShape outputDims = outputInfo.GetShape();
+ armnn::TensorShape inputDims = inputInfo.GetShape();
+
+ // Initialise output data.
+ size_t numOutputs = 1;
+ for (unsigned int idx = 0; idx < outputNumDims; ++idx)
+ {
+ numOutputs *= boost::numeric_cast<size_t>(outputDims[idx]);
+ }
+
+ std::vector<float> tempSum(numOutputs);
+ for (size_t idx = 0; idx < numOutputs; ++idx)
+ {
+ outputData[idx] = 0.0f;
+ tempSum[idx] = 0.0f;
+ }
+
+ // Initialise temp index.
+ std::vector<unsigned int> tempIndex(inputNumDims);
+ for (unsigned int idx = 0; idx < inputNumDims; ++idx)
+ {
+ tempIndex[idx] = 0;
+ }
+
+ std::vector<unsigned int> resolvedAxis = axis;
+ if (resolvedAxis.empty())
+ {
+ for (unsigned int idx = 0; idx < inputNumDims; ++idx)
+ {
+ resolvedAxis.push_back(idx);
+ }
+ }
+ unsigned int numResolvedAxis = boost::numeric_cast<unsigned int>(resolvedAxis.size());
+
+ // Iterates through input_data and sum up the reduced axis.
+ for (bool hasNext = true; hasNext; hasNext = NextIndex(inputNumDims, inputDims, tempIndex))
+ {
+ size_t inputOffset = ReducedOutputOffset(inputNumDims, inputDims, tempIndex, 0, {});
+ size_t outputOffset = ReducedOutputOffset(inputNumDims, inputDims, tempIndex,
+ numResolvedAxis, resolvedAxis);
+ tempSum[outputOffset] += inputData[inputOffset];
+ }
+
+ // Takes average by num of elements added to get mean.
+ size_t numElementsInAxis = 1;
+ for (unsigned int idx = 0; idx < numResolvedAxis; ++idx)
+ {
+ size_t current = boost::numeric_cast<size_t>(inputDims[resolvedAxis[idx]]);
+ BOOST_ASSERT(boost::numeric_cast<float>(current) <
+ (std::numeric_limits<float>::max() / boost::numeric_cast<float>(numElementsInAxis)));
+ numElementsInAxis *= current;
+ }
+ if (numElementsInAxis > 0) {
+ for (size_t idx = 0; idx < numOutputs; ++idx)
+ {
+ outputData[idx] = tempSum[idx] / boost::numeric_cast<float>(numElementsInAxis);
+ }
+ }
+}
+} //namespace armnn
LayerTestResult<float, 4> PermuteFloat32ValueSet3Test(armnn::IWorkloadFactory& workloadFactory)
{
return PermuteFloat32ValueSet3TestCommon(workloadFactory);
-};
\ No newline at end of file
+};
+
+namespace
+{
+template <typename T, std::size_t InputDim, std::size_t OutputDim>
+LayerTestResult<T, OutputDim> MeanTestHelper(armnn::IWorkloadFactory& workloadFactory,
+ const unsigned int* inputShape,
+ const std::vector<T>& inputData,
+ const std::vector<unsigned int>& axis,
+ bool keepDims,
+ const unsigned int* outputShape,
+ const std::vector<T>& outputData,
+ float scale = 1.0f,
+ int32_t offset = 0)
+{
+ auto dataType = (std::is_same<T, uint8_t>::value ?
+ armnn::DataType::QuantisedAsymm8 :
+ armnn::DataType::Float32);
+
+ armnn::TensorInfo inputTensorInfo(InputDim, inputShape, dataType);
+ armnn::TensorInfo outputTensorInfo(OutputDim, outputShape, dataType);
+
+ inputTensorInfo.SetQuantizationScale(scale);
+ inputTensorInfo.SetQuantizationOffset(offset);
+
+ outputTensorInfo.SetQuantizationScale(scale);
+ outputTensorInfo.SetQuantizationOffset(offset);
+
+ auto input = MakeTensor<T, InputDim>(inputTensorInfo, inputData);
+
+ LayerTestResult<T, OutputDim> result(outputTensorInfo);
+ result.outputExpected = MakeTensor<T, OutputDim>(outputTensorInfo, outputData);
+
+ std::unique_ptr<armnn::ITensorHandle> inputHandle = workloadFactory.CreateTensorHandle(inputTensorInfo);
+ std::unique_ptr<armnn::ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(outputTensorInfo);
+
+ armnn::MeanQueueDescriptor data;
+ data.m_Parameters.m_Axis = axis;
+ data.m_Parameters.m_KeepDims = keepDims;
+ armnn::WorkloadInfo info;
+ AddInputToWorkload(data, info, inputTensorInfo, inputHandle.get());
+ AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
+
+ std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreateMean(data, info);
+
+ inputHandle->Allocate();
+ outputHandle->Allocate();
+
+ CopyDataToITensorHandle(inputHandle.get(), input.origin());
+
+ workloadFactory.Finalize();
+ workload->Execute();
+
+ CopyDataFromITensorHandle(result.output.origin(), outputHandle.get());
+
+ return result;
+}
+} // anonymous namespace
+
+LayerTestResult<uint8_t, 1> MeanUint8SimpleTest(armnn::IWorkloadFactory& workloadFactory)
+{
+ const unsigned int inputShape[] = { 3, 2 };
+ const unsigned int outputShape[] = { 1 };
+
+ std::vector<uint8_t> input({ 1, 1, 2, 2, 3, 3 });
+ std::vector<uint8_t> output({ 2 });
+
+ return MeanTestHelper<uint8_t, 2, 1>(workloadFactory, inputShape, input, {}, false, outputShape, output);
+}
+
+LayerTestResult<uint8_t, 3> MeanUint8SimpleAxisTest(armnn::IWorkloadFactory& workloadFactory)
+{
+ const unsigned int inputShape[] = { 1, 1, 3, 2 };
+ const unsigned int outputShape[] = { 1, 1, 2 };
+
+ std::vector<uint8_t> input({ 1, 1, 2, 2, 3, 3 });
+ std::vector<uint8_t> output({ 2, 2 });
+
+ return MeanTestHelper<uint8_t, 4, 3>(workloadFactory, inputShape, input, {2}, false, outputShape, output);
+}
+
+LayerTestResult<uint8_t, 4> MeanUint8KeepDimsTest(armnn::IWorkloadFactory& workloadFactory)
+{
+ const unsigned int inputShape[] = { 1, 1, 3, 2 };
+ const unsigned int outputShape[] = { 1, 1, 1, 2 };
+
+ std::vector<uint8_t> input({ 1, 1, 2, 2, 3, 3 });
+ std::vector<uint8_t> output({ 2, 2 });
+
+ return MeanTestHelper<uint8_t, 4, 4>(workloadFactory, inputShape, input, {2}, true, outputShape, output);
+}
+
+LayerTestResult<uint8_t, 4> MeanUint8MultipleDimsTest(armnn::IWorkloadFactory& workloadFactory)
+{
+ const unsigned int inputShape[] = { 2, 3, 1, 2 };
+ const unsigned int outputShape[] = { 1, 3, 1, 1 };
+
+ std::vector<uint8_t> input({ 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6});
+ std::vector<uint8_t> output({ 1, 3, 5 });
+
+ return MeanTestHelper<uint8_t, 4, 4>(workloadFactory, inputShape, input, {0, 3}, true, outputShape, output);
+}
+
+LayerTestResult<uint8_t, 1> MeanVtsUint8Test(armnn::IWorkloadFactory& workloadFactory)
+{
+ const unsigned int inputShape[] = {4, 3, 2};
+ const unsigned int outputShape[] = { 2 };
+
+ std::vector<uint8_t> input({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24});
+ std::vector<uint8_t> output({12, 13});
+
+ return MeanTestHelper<uint8_t, 3, 1>(workloadFactory, inputShape, input, {0, 1}, false, outputShape,
+ output, 0.8f, 5);
+}
+
+LayerTestResult<float, 1> MeanFloatSimpleTest(armnn::IWorkloadFactory& workloadFactory)
+{
+ const unsigned int inputShape[] = { 3, 2 };
+ const unsigned int outputShape[] = { 1 };
+
+ std::vector<float> input({ 1., 1., 2., 2., 3., 3. });
+ std::vector<float> output({ 2. });
+
+ return MeanTestHelper<float, 2, 1>(workloadFactory, inputShape, input, {}, false, outputShape, output);
+}
+
+LayerTestResult<float, 3> MeanFloatSimpleAxisTest(armnn::IWorkloadFactory& workloadFactory)
+{
+ const unsigned int inputShape[] = { 2, 3, 1, 2 };
+ const unsigned int outputShape[] = { 3, 1, 2 };
+
+ std::vector<float> input({ 1., 2., 3., 4., 5., 6., 1., 2., 3., 4., 5., 6.});
+ std::vector<float> output({ 1., 2., 3., 4., 5., 6. });
+
+ return MeanTestHelper<float, 4, 3>(workloadFactory, inputShape, input, {0}, false, outputShape, output);
+}
+
+LayerTestResult<float, 4> MeanFloatKeepDimsTest(armnn::IWorkloadFactory& workloadFactory)
+{
+ const unsigned int inputShape[] = { 1, 1, 3, 2 };
+ const unsigned int outputShape[] = { 1, 1, 1, 2 };
+
+ std::vector<float> input({ 1., 1., 2., 2., 3., 3. });
+ std::vector<float> output({ 2., 2. });
+
+ return MeanTestHelper<float, 4, 4>(workloadFactory, inputShape, input, {2}, true, outputShape, output);
+}
+
+LayerTestResult<float, 4> MeanFloatMultipleDimsTest(armnn::IWorkloadFactory& workloadFactory)
+{
+ const unsigned int inputShape[] = { 2, 3, 1, 2 };
+ const unsigned int outputShape[] = { 1, 3, 1, 1 };
+
+ std::vector<float> input({ 1., 2., 3., 4., 5., 6., 1., 2., 3., 4., 5., 6.});
+ std::vector<float> output({ 1.5, 3.5, 5.5 });
+
+ return MeanTestHelper<float, 4, 4>(workloadFactory, inputShape, input, {0, 3}, true, outputShape, output);
+}
+
+LayerTestResult<float, 1> MeanVtsFloat1Test(armnn::IWorkloadFactory& workloadFactory)
+{
+ const unsigned int inputShape[] = {4, 3, 2};
+ const unsigned int outputShape[] = { 2 };
+
+ std::vector<float> input({1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f,
+ 15.0f, 16.0f, 17.0f, 18.0f, 19.0f, 20.0f, 21.0f, 22.0f, 23.0f, 24.0f});
+ std::vector<float> output({12.0f, 13.0f});
+
+ return MeanTestHelper<float, 3, 1>(workloadFactory, inputShape, input, {0, 1}, false, outputShape, output);
+}
+
+LayerTestResult<float, 3> MeanVtsFloat2Test(armnn::IWorkloadFactory& workloadFactory)
+{
+ const unsigned int inputShape[] = {4, 3, 2};
+ const unsigned int outputShape[] = {1, 3, 1 };
+
+ std::vector<float> input({1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f,
+ 15.0f, 16.0f, 17.0f, 18.0f, 19.0f, 20.0f, 21.0f, 22.0f, 23.0f, 24.0f});
+ std::vector<float> output({10.5f, 12.5f, 14.5f});
+
+ return MeanTestHelper<float, 3, 3>(workloadFactory, inputShape, input, {0, 2}, true, outputShape, output);
+}