ArmNN
 21.02
ParserPrototxtFixture.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 <armnn/IRuntime.hpp>
9 #include <test/TensorHelpers.hpp>
10 
11 #include <Network.hpp>
12 #include <VerificationHelpers.hpp>
13 
14 #include <fmt/format.h>
15 
16 #include <iomanip>
17 #include <string>
18 
19 namespace armnnUtils
20 {
21 
22 template<typename TParser>
24 {
26  : m_Parser(TParser::Create())
27  , m_Runtime(armnn::IRuntime::Create(armnn::IRuntime::CreationOptions()))
29  {
30  }
31 
32  /// Parses and loads the network defined by the m_Prototext string.
33  /// @{
34  void SetupSingleInputSingleOutput(const std::string& inputName, const std::string& outputName);
35  void SetupSingleInputSingleOutput(const armnn::TensorShape& inputTensorShape,
36  const std::string& inputName,
37  const std::string& outputName);
38  void SetupSingleInputSingleOutput(const armnn::TensorShape& inputTensorShape,
39  const armnn::TensorShape& outputTensorShape,
40  const std::string& inputName,
41  const std::string& outputName);
42  void Setup(const std::map<std::string, armnn::TensorShape>& inputShapes,
43  const std::vector<std::string>& requestedOutputs);
44  void Setup();
46  const std::map<std::string,armnn::TensorShape>& inputShapes,
47  const std::vector<std::string>& requestedOutputs);
48  /// @}
49 
50  /// Executes the network with the given input tensor and checks the result against the given output tensor.
51  /// This overload assumes that the network has a single input and a single output.
52  template <std::size_t NumOutputDimensions>
53  void RunTest(const std::vector<float>& inputData, const std::vector<float>& expectedOutputData);
54 
55  /// Executes the network with the given input tensor and checks the result against the given output tensor.
56  /// Calls RunTest with output type of uint8_t for checking comparison operators.
57  template <std::size_t NumOutputDimensions>
58  void RunComparisonTest(const std::map<std::string, std::vector<float>>& inputData,
59  const std::map<std::string, std::vector<uint8_t>>& expectedOutputData);
60 
61  /// Executes the network with the given input tensors and checks the results against the given output tensors.
62  /// This overload supports multiple inputs and multiple outputs, identified by name.
63  template <std::size_t NumOutputDimensions, typename T = float>
64  void RunTest(const std::map<std::string, std::vector<float>>& inputData,
65  const std::map<std::string, std::vector<T>>& expectedOutputData);
66 
67  std::string m_Prototext;
68  std::unique_ptr<TParser, void(*)(TParser* parser)> m_Parser;
71 
72  /// If the single-input-single-output overload of Setup() is called, these will store the input and output name
73  /// so they don't need to be passed to the single-input-single-output overload of RunTest().
74  /// @{
75  std::string m_SingleInputName;
76  std::string m_SingleOutputName;
77  /// @}
78 
79  /// This will store the output shape so it don't need to be passed to the single-input-single-output overload
80  /// of RunTest().
82 };
83 
84 template<typename TParser>
86  const std::string& outputName)
87 {
88  // Stores the input and output name so they don't need to be passed to the single-input-single-output RunTest().
89  m_SingleInputName = inputName;
90  m_SingleOutputName = outputName;
91  Setup({ }, { outputName });
92 }
93 
94 template<typename TParser>
96  const std::string& inputName,
97  const std::string& outputName)
98 {
99  // Stores the input and output name so they don't need to be passed to the single-input-single-output RunTest().
100  m_SingleInputName = inputName;
101  m_SingleOutputName = outputName;
102  Setup({ { inputName, inputTensorShape } }, { outputName });
103 }
104 
105 template<typename TParser>
107  const armnn::TensorShape& outputTensorShape,
108  const std::string& inputName,
109  const std::string& outputName)
110 {
111  // Stores the input name, the output name and the output tensor shape
112  // so they don't need to be passed to the single-input-single-output RunTest().
113  m_SingleInputName = inputName;
114  m_SingleOutputName = outputName;
115  m_SingleOutputShape = outputTensorShape;
116  Setup({ { inputName, inputTensorShape } }, { outputName });
117 }
118 
119 template<typename TParser>
120 void ParserPrototxtFixture<TParser>::Setup(const std::map<std::string, armnn::TensorShape>& inputShapes,
121  const std::vector<std::string>& requestedOutputs)
122 {
123  std::string errorMessage;
124 
125  armnn::INetworkPtr network =
126  m_Parser->CreateNetworkFromString(m_Prototext.c_str(), inputShapes, requestedOutputs);
127  auto optimized = Optimize(*network, { armnn::Compute::CpuRef }, m_Runtime->GetDeviceSpec());
128  armnn::Status ret = m_Runtime->LoadNetwork(m_NetworkIdentifier, move(optimized), errorMessage);
129  if (ret != armnn::Status::Success)
130  {
131  throw armnn::Exception(fmt::format("LoadNetwork failed with error: '{0}' {1}",
132  errorMessage,
133  CHECK_LOCATION().AsString()));
134  }
135 }
136 
137 template<typename TParser>
139 {
140  std::string errorMessage;
141 
142  armnn::INetworkPtr network =
143  m_Parser->CreateNetworkFromString(m_Prototext.c_str());
144  auto optimized = Optimize(*network, { armnn::Compute::CpuRef }, m_Runtime->GetDeviceSpec());
145  armnn::Status ret = m_Runtime->LoadNetwork(m_NetworkIdentifier, move(optimized), errorMessage);
146  if (ret != armnn::Status::Success)
147  {
148  throw armnn::Exception(fmt::format("LoadNetwork failed with error: '{0}' {1}",
149  errorMessage,
150  CHECK_LOCATION().AsString()));
151  }
152 }
153 
154 template<typename TParser>
156  const std::map<std::string,armnn::TensorShape>& inputShapes,
157  const std::vector<std::string>& requestedOutputs)
158 {
159  armnn::INetworkPtr network =
160  m_Parser->CreateNetworkFromString(m_Prototext.c_str(), inputShapes, requestedOutputs);
161  auto optimized = Optimize(*network, { armnn::Compute::CpuRef }, m_Runtime->GetDeviceSpec());
162  return optimized;
163 }
164 
165 template<typename TParser>
166 template <std::size_t NumOutputDimensions>
167 void ParserPrototxtFixture<TParser>::RunTest(const std::vector<float>& inputData,
168  const std::vector<float>& expectedOutputData)
169 {
170  RunTest<NumOutputDimensions>({ { m_SingleInputName, inputData } }, { { m_SingleOutputName, expectedOutputData } });
171 }
172 
173 template<typename TParser>
174 template <std::size_t NumOutputDimensions>
175 void ParserPrototxtFixture<TParser>::RunComparisonTest(const std::map<std::string, std::vector<float>>& inputData,
176  const std::map<std::string, std::vector<uint8_t>>&
177  expectedOutputData)
178 {
179  RunTest<NumOutputDimensions, uint8_t>(inputData, expectedOutputData);
180 }
181 
182 template<typename TParser>
183 template <std::size_t NumOutputDimensions, typename T>
184 void ParserPrototxtFixture<TParser>::RunTest(const std::map<std::string, std::vector<float>>& inputData,
185  const std::map<std::string, std::vector<T>>& expectedOutputData)
186 {
187  // Sets up the armnn input tensors from the given vectors.
188  armnn::InputTensors inputTensors;
189  for (auto&& it : inputData)
190  {
191  armnn::BindingPointInfo bindingInfo = m_Parser->GetNetworkInputBindingInfo(it.first);
192  inputTensors.push_back({ bindingInfo.first, armnn::ConstTensor(bindingInfo.second, it.second.data()) });
193  }
194 
195  // Allocates storage for the output tensors to be written to and sets up the armnn output tensors.
196  std::map<std::string, boost::multi_array<T, NumOutputDimensions>> outputStorage;
197  armnn::OutputTensors outputTensors;
198  for (auto&& it : expectedOutputData)
199  {
200  armnn::BindingPointInfo bindingInfo = m_Parser->GetNetworkOutputBindingInfo(it.first);
201  outputStorage.emplace(it.first, MakeTensor<T, NumOutputDimensions>(bindingInfo.second));
202  outputTensors.push_back(
203  { bindingInfo.first, armnn::Tensor(bindingInfo.second, outputStorage.at(it.first).data()) });
204  }
205 
206  m_Runtime->EnqueueWorkload(m_NetworkIdentifier, inputTensors, outputTensors);
207 
208  // Compares each output tensor to the expected values.
209  for (auto&& it : expectedOutputData)
210  {
211  armnn::BindingPointInfo bindingInfo = m_Parser->GetNetworkOutputBindingInfo(it.first);
212  if (bindingInfo.second.GetNumElements() != it.second.size())
213  {
214  throw armnn::Exception(fmt::format("Output tensor {0} is expected to have {1} elements. "
215  "{2} elements supplied. {3}",
216  it.first,
217  bindingInfo.second.GetNumElements(),
218  it.second.size(),
219  CHECK_LOCATION().AsString()));
220  }
221 
222  // If the expected output shape is set, the output tensor checks will be carried out.
224  {
225 
226  if (bindingInfo.second.GetShape().GetNumDimensions() == NumOutputDimensions &&
227  bindingInfo.second.GetShape().GetNumDimensions() == m_SingleOutputShape.GetNumDimensions())
228  {
229  for (unsigned int i = 0; i < m_SingleOutputShape.GetNumDimensions(); ++i)
230  {
231  if (m_SingleOutputShape[i] != bindingInfo.second.GetShape()[i])
232  {
233  // This exception message could not be created by fmt:format because of an oddity in
234  // the operator << of TensorShape.
235  std::stringstream message;
236  message << "Output tensor " << it.first << " is expected to have "
237  << bindingInfo.second.GetShape() << "shape. "
238  << m_SingleOutputShape << " shape supplied. "
239  << CHECK_LOCATION().AsString();
240  throw armnn::Exception(message.str());
241  }
242  }
243  }
244  else
245  {
246  throw armnn::Exception(fmt::format("Output tensor {0} is expected to have {1} dimensions. "
247  "{2} dimensions supplied. {3}",
248  it.first,
249  bindingInfo.second.GetShape().GetNumDimensions(),
250  NumOutputDimensions,
251  CHECK_LOCATION().AsString()));
252  }
253  }
254 
255  auto outputExpected = MakeTensor<T, NumOutputDimensions>(bindingInfo.second, it.second);
256  if (std::is_same<T, uint8_t>::value)
257  {
258  BOOST_TEST(CompareTensors(outputExpected, outputStorage[it.first], true));
259  }
260  else
261  {
262  BOOST_TEST(CompareTensors(outputExpected, outputStorage[it.first]));
263  }
264  }
265 }
266 
267 } // namespace armnnUtils
CPU Execution: Reference C++ kernels.
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)
armnn::TensorShape m_SingleOutputShape
This will store the output shape so it don&#39;t need to be passed to the single-input-single-output over...
std::unique_ptr< IRuntime, void(*)(IRuntime *runtime)> IRuntimePtr
Definition: IRuntime.hpp:26
void RunComparisonTest(const std::map< std::string, std::vector< float >> &inputData, const std::map< std::string, std::vector< uint8_t >> &expectedOutputData)
Executes the network with the given input tensor and checks the result against the given output tenso...
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.
A tensor defined by a TensorInfo (shape and data type) and a mutable backing store.
Definition: Tensor.hpp:306
std::unique_ptr< TParser, void(*)(TParser *parser)> m_Parser
armnn::IOptimizedNetworkPtr SetupOptimizedNetwork(const std::map< std::string, armnn::TensorShape > &inputShapes, const std::vector< std::string > &requestedOutputs)
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
std::string m_SingleInputName
If the single-input-single-output overload of Setup() is called, these will store the input and outpu...
void RunTest(const std::vector< float > &inputData, const std::vector< float > &expectedOutputData)
Executes the network with the given input tensor and checks the result against the given output tenso...
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::unique_ptr< IOptimizedNetwork, void(*)(IOptimizedNetwork *network)> IOptimizedNetworkPtr
Definition: INetwork.hpp:174
#define CHECK_LOCATION()
Definition: Exceptions.hpp:197
std::pair< armnn::LayerBindingId, armnn::TensorInfo > BindingPointInfo
Definition: Tensor.hpp:261
void SetupSingleInputSingleOutput(const std::string &inputName, const std::string &outputName)
Parses and loads the network defined by the m_Prototext string.
Base class for all ArmNN exceptions so that users can filter to just those.
Definition: Exceptions.hpp:46
unsigned int GetNumDimensions() const
Function that returns the tensor rank.
Definition: Tensor.cpp:174
std::unique_ptr< INetwork, void(*)(INetwork *network)> INetworkPtr
Definition: INetwork.hpp:173