ArmNN
 21.02
ParserFlatbuffersSerializeFixture.hpp
Go to the documentation of this file.
1 //
2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #pragma once
7 
8 #include "SchemaSerialize.hpp"
9 #include "test/TensorHelpers.hpp"
10 
11 #include "flatbuffers/idl.h"
12 #include "flatbuffers/util.h"
13 
14 #include <ArmnnSchema_generated.h>
15 #include <armnn/IRuntime.hpp>
17 #include <armnn/utility/Assert.hpp>
19 #include <ResolveType.hpp>
20 
21 #include <fmt/format.h>
22 
23 
25 using TensorRawPtr = armnnSerializer::TensorInfo*;
26 
28 {
30  m_Parser(IDeserializer::Create()),
31  m_Runtime(armnn::IRuntime::Create(armnn::IRuntime::CreationOptions())),
33  {
34  }
35 
36  std::vector<uint8_t> m_GraphBinary;
37  std::string m_JsonString;
38  std::unique_ptr<IDeserializer, void (*)(IDeserializer* parser)> m_Parser;
41 
42  /// If the single-input-single-output overload of Setup() is called, these will store the input and output name
43  /// so they don't need to be passed to the single-input-single-output overload of RunTest().
44  std::string m_SingleInputName;
45  std::string m_SingleOutputName;
46 
47  void Setup()
48  {
49  bool ok = ReadStringToBinary();
50  if (!ok)
51  {
52  throw armnn::Exception("LoadNetwork failed while reading binary input");
53  }
54 
55  armnn::INetworkPtr network =
56  m_Parser->CreateNetworkFromBinary(m_GraphBinary);
57 
58  if (!network)
59  {
60  throw armnn::Exception("The parser failed to create an ArmNN network");
61  }
62 
63  auto optimized = Optimize(*network, {armnn::Compute::CpuRef},
64  m_Runtime->GetDeviceSpec());
65 
66  std::string errorMessage;
67  armnn::Status ret = m_Runtime->LoadNetwork(m_NetworkIdentifier, move(optimized), errorMessage);
68 
69  if (ret != armnn::Status::Success)
70  {
71  throw armnn::Exception(fmt::format("The runtime failed to load the network. "
72  "Error was: {0}. in {1} [{2}:{3}]",
73  errorMessage,
74  __func__,
75  __FILE__,
76  __LINE__));
77  }
78 
79  }
80 
81  void SetupSingleInputSingleOutput(const std::string& inputName, const std::string& outputName)
82  {
83  // Store the input and output name so they don't need to be passed to the single-input-single-output RunTest().
84  m_SingleInputName = inputName;
85  m_SingleOutputName = outputName;
86  Setup();
87  }
88 
90  {
91  std::string schemafile(&deserialize_schema_start, &deserialize_schema_end);
92 
93  // parse schema first, so we can use it to parse the data after
94  flatbuffers::Parser parser;
95 
96  bool ok = parser.Parse(schemafile.c_str());
97  ARMNN_ASSERT_MSG(ok, "Failed to parse schema file");
98 
99  ok &= parser.Parse(m_JsonString.c_str());
100  ARMNN_ASSERT_MSG(ok, "Failed to parse json input");
101 
102  if (!ok)
103  {
104  return false;
105  }
106 
107  {
108  const uint8_t* bufferPtr = parser.builder_.GetBufferPointer();
109  size_t size = static_cast<size_t>(parser.builder_.GetSize());
110  m_GraphBinary.assign(bufferPtr, bufferPtr+size);
111  }
112  return ok;
113  }
114 
115  /// Executes the network with the given input tensor and checks the result against the given output tensor.
116  /// This overload assumes the network has a single input and a single output.
117  template<std::size_t NumOutputDimensions,
118  armnn::DataType ArmnnType,
120  void RunTest(unsigned int layersId,
121  const std::vector<DataType>& inputData,
122  const std::vector<DataType>& expectedOutputData);
123 
124  template<std::size_t NumOutputDimensions,
125  armnn::DataType ArmnnInputType,
126  armnn::DataType ArmnnOutputType,
127  typename InputDataType = armnn::ResolveType<ArmnnInputType>,
128  typename OutputDataType = armnn::ResolveType<ArmnnOutputType>>
129  void RunTest(unsigned int layersId,
130  const std::vector<InputDataType>& inputData,
131  const std::vector<OutputDataType>& expectedOutputData);
132 
133  /// Executes the network with the given input tensors and checks the results against the given output tensors.
134  /// This overload supports multiple inputs and multiple outputs, identified by name.
135  template<std::size_t NumOutputDimensions,
136  armnn::DataType ArmnnType,
137  typename DataType = armnn::ResolveType<ArmnnType>>
138  void RunTest(unsigned int layersId,
139  const std::map<std::string, std::vector<DataType>>& inputData,
140  const std::map<std::string, std::vector<DataType>>& expectedOutputData);
141 
142  template<std::size_t NumOutputDimensions,
143  armnn::DataType ArmnnInputType,
144  armnn::DataType ArmnnOutputType,
145  typename InputDataType = armnn::ResolveType<ArmnnInputType>,
146  typename OutputDataType = armnn::ResolveType<ArmnnOutputType>>
147  void RunTest(unsigned int layersId,
148  const std::map<std::string, std::vector<InputDataType>>& inputData,
149  const std::map<std::string, std::vector<OutputDataType>>& expectedOutputData);
150 
151  void CheckTensors(const TensorRawPtr& tensors, size_t shapeSize, const std::vector<int32_t>& shape,
152  armnnSerializer::TensorInfo tensorType, const std::string& name,
153  const float scale, const int64_t zeroPoint)
154  {
155  armnn::IgnoreUnused(name);
156  BOOST_CHECK_EQUAL(shapeSize, tensors->dimensions()->size());
157  BOOST_CHECK_EQUAL_COLLECTIONS(shape.begin(), shape.end(),
158  tensors->dimensions()->begin(), tensors->dimensions()->end());
159  BOOST_CHECK_EQUAL(tensorType.dataType(), tensors->dataType());
160  BOOST_CHECK_EQUAL(scale, tensors->quantizationScale());
161  BOOST_CHECK_EQUAL(zeroPoint, tensors->quantizationOffset());
162  }
163 };
164 
165 template<std::size_t NumOutputDimensions, armnn::DataType ArmnnType, typename DataType>
167  const std::vector<DataType>& inputData,
168  const std::vector<DataType>& expectedOutputData)
169 {
170  RunTest<NumOutputDimensions, ArmnnType, ArmnnType, DataType, DataType>(layersId, inputData, expectedOutputData);
171 }
172 
173 template<std::size_t NumOutputDimensions,
174  armnn::DataType ArmnnInputType,
175  armnn::DataType ArmnnOutputType,
176  typename InputDataType,
177  typename OutputDataType>
179  const std::vector<InputDataType>& inputData,
180  const std::vector<OutputDataType>& expectedOutputData)
181 {
182  RunTest<NumOutputDimensions, ArmnnInputType, ArmnnOutputType>(layersId,
183  { { m_SingleInputName, inputData } },
184  { { m_SingleOutputName, expectedOutputData } });
185 }
186 
187 template<std::size_t NumOutputDimensions, armnn::DataType ArmnnType, typename DataType>
189  const std::map<std::string, std::vector<DataType>>& inputData,
190  const std::map<std::string, std::vector<DataType>>& expectedOutputData)
191 {
192  RunTest<NumOutputDimensions, ArmnnType, ArmnnType, DataType, DataType>(layersId, inputData, expectedOutputData);
193 }
194 
195 template<std::size_t NumOutputDimensions,
196  armnn::DataType ArmnnInputType,
197  armnn::DataType ArmnnOutputType,
198  typename InputDataType,
199  typename OutputDataType>
201  unsigned int layersId,
202  const std::map<std::string, std::vector<InputDataType>>& inputData,
203  const std::map<std::string, std::vector<OutputDataType>>& expectedOutputData)
204 {
205  auto ConvertBindingInfo = [](const armnnDeserializer::BindingPointInfo& bindingInfo)
206  {
207  return std::make_pair(bindingInfo.m_BindingId, bindingInfo.m_TensorInfo);
208  };
209 
210  // Setup the armnn input tensors from the given vectors.
211  armnn::InputTensors inputTensors;
212  for (auto&& it : inputData)
213  {
214  armnn::BindingPointInfo bindingInfo = ConvertBindingInfo(
215  m_Parser->GetNetworkInputBindingInfo(layersId, it.first));
216  armnn::VerifyTensorInfoDataType(bindingInfo.second, ArmnnInputType);
217  inputTensors.push_back({ bindingInfo.first, armnn::ConstTensor(bindingInfo.second, it.second.data()) });
218  }
219 
220  // Allocate storage for the output tensors to be written to and setup the armnn output tensors.
221  std::map<std::string, boost::multi_array<OutputDataType, NumOutputDimensions>> outputStorage;
222  armnn::OutputTensors outputTensors;
223  for (auto&& it : expectedOutputData)
224  {
225  armnn::BindingPointInfo bindingInfo = ConvertBindingInfo(
226  m_Parser->GetNetworkOutputBindingInfo(layersId, it.first));
227  armnn::VerifyTensorInfoDataType(bindingInfo.second, ArmnnOutputType);
228  outputStorage.emplace(it.first, MakeTensor<OutputDataType, NumOutputDimensions>(bindingInfo.second));
229  outputTensors.push_back(
230  { bindingInfo.first, armnn::Tensor(bindingInfo.second, outputStorage.at(it.first).data()) });
231  }
232 
233  m_Runtime->EnqueueWorkload(m_NetworkIdentifier, inputTensors, outputTensors);
234 
235  // Compare each output tensor to the expected values
236  for (auto&& it : expectedOutputData)
237  {
238  armnn::BindingPointInfo bindingInfo = ConvertBindingInfo(
239  m_Parser->GetNetworkOutputBindingInfo(layersId, it.first));
240  auto outputExpected = MakeTensor<OutputDataType, NumOutputDimensions>(bindingInfo.second, it.second);
241  BOOST_TEST(CompareTensors(outputExpected, outputStorage[it.first]));
242  }
243 }
void CheckTensors(const TensorRawPtr &tensors, size_t shapeSize, const std::vector< int32_t > &shape, armnnSerializer::TensorInfo tensorType, const std::string &name, const float scale, const int64_t zeroPoint)
CPU Execution: Reference C++ kernels.
void RunTest(unsigned int layersId, const std::vector< DataType > &inputData, const std::vector< DataType > &expectedOutputData)
Executes the network with the given input tensor and checks the result against the given output tenso...
void SetupSingleInputSingleOutput(const std::string &inputName, const std::string &outputName)
boost::test_tools::predicate_result CompareTensors(const boost::multi_array< T, n > &a, const boost::multi_array< T, n > &b, bool compareBoolean=false, bool isDynamic=false)
std::unique_ptr< IRuntime, void(*)(IRuntime *runtime)> IRuntimePtr
Definition: IRuntime.hpp:26
typename ResolveTypeImpl< DT >::Type ResolveType
Definition: ResolveType.hpp:73
std::vector< std::pair< LayerBindingId, class ConstTensor > > InputTensors
Definition: Tensor.hpp:340
int NetworkId
Definition: IRuntime.hpp:20
Copyright (c) 2021 ARM Limited and Contributors.
void IgnoreUnused(Ts &&...)
std::unique_ptr< IDeserializer, void(*)(IDeserializer *parser)> m_Parser
A tensor defined by a TensorInfo (shape and data type) and a mutable backing store.
Definition: Tensor.hpp:306
DataType
Definition: Types.hpp:32
IOptimizedNetworkPtr Optimize(const INetwork &network, const std::vector< BackendId > &backendPreferences, const IDeviceSpec &deviceSpec, const OptimizerOptions &options=OptimizerOptions(), Optional< std::vector< std::string > &> messages=EmptyOptional())
Create an optimized version of the network.
Definition: Network.cpp:1502
#define ARMNN_ASSERT_MSG(COND, MSG)
Definition: Assert.hpp:15
armnnSerializer::TensorInfo * TensorRawPtr
A tensor defined by a TensorInfo (shape and data type) and an immutable backing store.
Definition: Tensor.hpp:314
std::vector< std::pair< LayerBindingId, class Tensor > > OutputTensors
Definition: Tensor.hpp:341
Status
enumeration
Definition: Types.hpp:26
std::pair< armnn::LayerBindingId, armnn::TensorInfo > BindingPointInfo
Definition: Tensor.hpp:261
const char deserialize_schema_start
Base class for all ArmNN exceptions so that users can filter to just those.
Definition: Exceptions.hpp:46
const char deserialize_schema_end
void VerifyTensorInfoDataType(const armnn::TensorInfo &info, armnn::DataType dataType)
Definition: TypesUtils.hpp:309
std::unique_ptr< INetwork, void(*)(INetwork *network)> INetworkPtr
Definition: INetwork.hpp:173
std::string m_SingleInputName
If the single-input-single-output overload of Setup() is called, these will store the input and outpu...