blob: 00ed55caaf2e67e9206fd0f1ecebdc9674c0c302 [file] [log] [blame]
Jan Eilers45274902020-10-15 18:34:43 +01001//
2// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#include "NetworkExecutionUtils.hpp"
7
Rob Hughes9542f902021-07-14 09:48:54 +01008#include <armnnUtils/Filesystem.hpp>
Jan Eilers45274902020-10-15 18:34:43 +01009#include <InferenceTest.hpp>
10#include <ResolveType.hpp>
11
12#if defined(ARMNN_SERIALIZER)
13#include "armnnDeserializer/IDeserializer.hpp"
14#endif
Jan Eilers45274902020-10-15 18:34:43 +010015#if defined(ARMNN_TF_LITE_PARSER)
16#include "armnnTfLiteParser/ITfLiteParser.hpp"
17#endif
18#if defined(ARMNN_ONNX_PARSER)
19#include "armnnOnnxParser/IOnnxParser.hpp"
20#endif
21
Jan Eilers45274902020-10-15 18:34:43 +010022template<armnn::DataType NonQuantizedType>
23auto ParseDataArray(std::istream& stream);
24
25template<armnn::DataType QuantizedType>
26auto ParseDataArray(std::istream& stream,
27 const float& quantizationScale,
28 const int32_t& quantizationOffset);
29
30template<>
31auto ParseDataArray<armnn::DataType::Float32>(std::istream& stream)
32{
33 return ParseArrayImpl<float>(stream, [](const std::string& s) { return std::stof(s); });
34}
35
36template<>
David Monahan2d995612021-11-01 10:16:37 +000037auto ParseDataArray<armnn::DataType::Float16>(std::istream& stream)
38{
39 return ParseArrayImpl<armnn::Half>(stream, [](const std::string& s)
40 {
41 return armnn::Half(std::stof(s));
42 });
43}
44
45template<>
Jan Eilers45274902020-10-15 18:34:43 +010046auto ParseDataArray<armnn::DataType::Signed32>(std::istream& stream)
47{
48 return ParseArrayImpl<int>(stream, [](const std::string& s) { return std::stoi(s); });
49}
50
51template<>
Mike Kellyd7ed6d42021-07-21 09:42:43 +010052auto ParseDataArray<armnn::DataType::QAsymmS8>(std::istream& stream)
53{
54 return ParseArrayImpl<int8_t>(stream,
55 [](const std::string& s) { return armnn::numeric_cast<int8_t>(std::stoi(s)); });
56}
57
58template<>
Jan Eilers45274902020-10-15 18:34:43 +010059auto ParseDataArray<armnn::DataType::QAsymmU8>(std::istream& stream)
60{
61 return ParseArrayImpl<uint8_t>(stream,
62 [](const std::string& s) { return armnn::numeric_cast<uint8_t>(std::stoi(s)); });
63}
64
Finn Williamsf806c4d2021-02-22 15:13:12 +000065
66template<>
67auto ParseDataArray<armnn::DataType::QSymmS8>(std::istream& stream)
68{
69 return ParseArrayImpl<int8_t>(stream,
70 [](const std::string& s) { return armnn::numeric_cast<int8_t>(std::stoi(s)); });
71}
72
Mike Kellyd7ed6d42021-07-21 09:42:43 +010073template<>
74auto ParseDataArray<armnn::DataType::QAsymmS8>(std::istream& stream,
75 const float& quantizationScale,
76 const int32_t& quantizationOffset)
77{
78 return ParseArrayImpl<int8_t>(stream,
79 [&quantizationScale, &quantizationOffset](const std::string& s)
80 {
81 return armnn::numeric_cast<int8_t>(
82 armnn::Quantize<int8_t>(std::stof(s),
83 quantizationScale,
84 quantizationOffset));
85 });
86}
Finn Williamsf806c4d2021-02-22 15:13:12 +000087
Jan Eilers45274902020-10-15 18:34:43 +010088template<>
89auto ParseDataArray<armnn::DataType::QAsymmU8>(std::istream& stream,
90 const float& quantizationScale,
91 const int32_t& quantizationOffset)
92{
93 return ParseArrayImpl<uint8_t>(stream,
94 [&quantizationScale, &quantizationOffset](const std::string& s)
95 {
96 return armnn::numeric_cast<uint8_t>(
97 armnn::Quantize<uint8_t>(std::stof(s),
98 quantizationScale,
99 quantizationOffset));
100 });
101}
102
103template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
104std::vector<T> GenerateDummyTensorData(unsigned int numElements)
105{
106 return std::vector<T>(numElements, static_cast<T>(0));
107}
108
109
110std::vector<unsigned int> ParseArray(std::istream& stream)
111{
112 return ParseArrayImpl<unsigned int>(
113 stream,
114 [](const std::string& s) { return armnn::numeric_cast<unsigned int>(std::stoi(s)); });
115}
116
117std::vector<std::string> ParseStringList(const std::string& inputString, const char* delimiter)
118{
119 std::stringstream stream(inputString);
120 return ParseArrayImpl<std::string>(stream, [](const std::string& s) {
121 return armnn::stringUtils::StringTrimCopy(s); }, delimiter);
122}
123
124
125TensorPrinter::TensorPrinter(const std::string& binding,
126 const armnn::TensorInfo& info,
127 const std::string& outputTensorFile,
Jan Eilers284b5d12021-09-07 12:46:15 +0100128 bool dequantizeOutput,
129 const bool printToConsole)
Jan Eilers45274902020-10-15 18:34:43 +0100130 : m_OutputBinding(binding)
131 , m_Scale(info.GetQuantizationScale())
132 , m_Offset(info.GetQuantizationOffset())
133 , m_OutputTensorFile(outputTensorFile)
Jan Eilers284b5d12021-09-07 12:46:15 +0100134 , m_DequantizeOutput(dequantizeOutput)
135 , m_PrintToConsole(printToConsole) {}
Jan Eilers45274902020-10-15 18:34:43 +0100136
137void TensorPrinter::operator()(const std::vector<float>& values)
138{
Jan Eilers284b5d12021-09-07 12:46:15 +0100139 if (m_PrintToConsole)
Jan Eilers45274902020-10-15 18:34:43 +0100140 {
Jan Eilers284b5d12021-09-07 12:46:15 +0100141 std::cout << m_OutputBinding << ": ";
142 ForEachValue(values, [](float value)
143 {
144 printf("%f ", value);
145 });
146 printf("\n");
147 }
Jan Eilers45274902020-10-15 18:34:43 +0100148 WriteToFile(values);
149}
150
David Monahan2d995612021-11-01 10:16:37 +0000151void TensorPrinter::operator()(const std::vector<armnn::Half>& values)
152{
153 if (m_PrintToConsole)
154 {
155 std::cout << m_OutputBinding << ": ";
156 ForEachValue(values, [](armnn::Half value)
157 {
158 printf("%f ", static_cast<float>(value));
159 });
160 printf("\n");
161 }
162 WriteToFile(values);
163}
164
Jan Eilers45274902020-10-15 18:34:43 +0100165void TensorPrinter::operator()(const std::vector<uint8_t>& values)
166{
167 if(m_DequantizeOutput)
168 {
169 auto& scale = m_Scale;
170 auto& offset = m_Offset;
171 std::vector<float> dequantizedValues;
172 ForEachValue(values, [&scale, &offset, &dequantizedValues](uint8_t value)
173 {
174 auto dequantizedValue = armnn::Dequantize(value, scale, offset);
Jan Eilers45274902020-10-15 18:34:43 +0100175 dequantizedValues.push_back(dequantizedValue);
176 });
Jan Eilers284b5d12021-09-07 12:46:15 +0100177
178 if (m_PrintToConsole)
179 {
180 std::cout << m_OutputBinding << ": ";
181 ForEachValue(dequantizedValues, [](float value)
182 {
183 printf("%f ", value);
184 });
185 printf("\n");
186 }
187
Jan Eilers45274902020-10-15 18:34:43 +0100188 WriteToFile(dequantizedValues);
189 }
190 else
191 {
192 const std::vector<int> intValues(values.begin(), values.end());
193 operator()(intValues);
194 }
195}
196
Finn Williamsf806c4d2021-02-22 15:13:12 +0000197void TensorPrinter::operator()(const std::vector<int8_t>& values)
198{
Jan Eilers284b5d12021-09-07 12:46:15 +0100199 if (m_PrintToConsole)
Finn Williamsf806c4d2021-02-22 15:13:12 +0000200 {
Jan Eilers284b5d12021-09-07 12:46:15 +0100201 std::cout << m_OutputBinding << ": ";
202 ForEachValue(values, [](int8_t value)
203 {
204 printf("%d ", value);
205 });
206 printf("\n");
207 }
Finn Williamsf806c4d2021-02-22 15:13:12 +0000208 WriteToFile(values);
209}
210
Jan Eilers45274902020-10-15 18:34:43 +0100211void TensorPrinter::operator()(const std::vector<int>& values)
212{
Jan Eilers284b5d12021-09-07 12:46:15 +0100213 if (m_PrintToConsole)
Jan Eilers45274902020-10-15 18:34:43 +0100214 {
Jan Eilers284b5d12021-09-07 12:46:15 +0100215 std::cout << m_OutputBinding << ": ";
216 ForEachValue(values, [](int value)
217 {
218 printf("%d ", value);
219 });
220 printf("\n");
221 }
Jan Eilers45274902020-10-15 18:34:43 +0100222 WriteToFile(values);
223}
224
225template<typename Container, typename Delegate>
226void TensorPrinter::ForEachValue(const Container& c, Delegate delegate)
227{
Jan Eilers45274902020-10-15 18:34:43 +0100228 for (const auto& value : c)
229 {
230 delegate(value);
231 }
Jan Eilers45274902020-10-15 18:34:43 +0100232}
233
234template<typename T>
235void TensorPrinter::WriteToFile(const std::vector<T>& values)
236{
237 if (!m_OutputTensorFile.empty())
238 {
239 std::ofstream outputTensorFile;
240 outputTensorFile.open(m_OutputTensorFile, std::ofstream::out | std::ofstream::trunc);
241 if (outputTensorFile.is_open())
242 {
243 outputTensorFile << m_OutputBinding << ": ";
244 std::copy(values.begin(), values.end(), std::ostream_iterator<T>(outputTensorFile, " "));
245 }
246 else
247 {
248 ARMNN_LOG(info) << "Output Tensor File: " << m_OutputTensorFile << " could not be opened!";
249 }
250 outputTensorFile.close();
251 }
252}
253
Francis Murtagh40d27412021-10-28 11:11:35 +0100254void PopulateTensorWithData(armnnUtils::TContainer& tensorData,
Jan Eilers45274902020-10-15 18:34:43 +0100255 unsigned int numElements,
256 const std::string& dataTypeStr,
257 const armnn::Optional<QuantizationParams>& qParams,
258 const armnn::Optional<std::string>& dataFile)
259{
260 const bool readFromFile = dataFile.has_value() && !dataFile.value().empty();
261 const bool quantizeData = qParams.has_value();
262
263 std::ifstream inputTensorFile;
264 if (readFromFile)
265 {
266 inputTensorFile = std::ifstream(dataFile.value());
267 }
268
269 if (dataTypeStr.compare("float") == 0)
270 {
271 if (quantizeData)
272 {
273 const float qScale = qParams.value().first;
274 const int qOffset = qParams.value().second;
275
276 tensorData = readFromFile ?
277 ParseDataArray<armnn::DataType::QAsymmU8>(inputTensorFile, qScale, qOffset) :
278 GenerateDummyTensorData<armnn::DataType::QAsymmU8>(numElements);
279 }
280 else
281 {
282 tensorData = readFromFile ?
283 ParseDataArray<armnn::DataType::Float32>(inputTensorFile) :
284 GenerateDummyTensorData<armnn::DataType::Float32>(numElements);
285 }
286 }
David Monahan2d995612021-11-01 10:16:37 +0000287 else if (dataTypeStr.compare("float16") == 0)
288 {
289 tensorData = readFromFile ?
290 ParseDataArray<armnn::DataType::Float16>(inputTensorFile) :
291 GenerateDummyTensorData<armnn::DataType::Float16>(numElements);
292 }
Jan Eilers45274902020-10-15 18:34:43 +0100293 else if (dataTypeStr.compare("int") == 0)
294 {
295 tensorData = readFromFile ?
296 ParseDataArray<armnn::DataType::Signed32>(inputTensorFile) :
297 GenerateDummyTensorData<armnn::DataType::Signed32>(numElements);
298 }
Finn Williamsf806c4d2021-02-22 15:13:12 +0000299 else if (dataTypeStr.compare("qsymms8") == 0)
300 {
301 tensorData = readFromFile ?
302 ParseDataArray<armnn::DataType::QSymmS8>(inputTensorFile) :
303 GenerateDummyTensorData<armnn::DataType::QSymmS8>(numElements);
304 }
Mike Kellyd7ed6d42021-07-21 09:42:43 +0100305 else if (dataTypeStr.compare("qasymm8") == 0 || dataTypeStr.compare("qasymmu8") == 0)
Jan Eilers45274902020-10-15 18:34:43 +0100306 {
307 tensorData = readFromFile ?
308 ParseDataArray<armnn::DataType::QAsymmU8>(inputTensorFile) :
309 GenerateDummyTensorData<armnn::DataType::QAsymmU8>(numElements);
310 }
Mike Kellyd7ed6d42021-07-21 09:42:43 +0100311 else if (dataTypeStr.compare("qasymms8") == 0)
312 {
313 tensorData = readFromFile ?
314 ParseDataArray<armnn::DataType::QAsymmS8>(inputTensorFile) :
315 GenerateDummyTensorData<armnn::DataType::QAsymmS8>(numElements);
316 }
Jan Eilers45274902020-10-15 18:34:43 +0100317 else
318 {
319 std::string errorMessage = "Unsupported tensor data type " + dataTypeStr;
320 ARMNN_LOG(fatal) << errorMessage;
321
322 inputTensorFile.close();
323 throw armnn::Exception(errorMessage);
324 }
325
326 inputTensorFile.close();
327}
328
329bool ValidatePath(const std::string& file, const bool expectFile)
330{
331 if (!fs::exists(file))
332 {
333 std::cerr << "Given file path '" << file << "' does not exist" << std::endl;
334 return false;
335 }
336 if (!fs::is_regular_file(file) && expectFile)
337 {
338 std::cerr << "Given file path '" << file << "' is not a regular file" << std::endl;
339 return false;
340 }
341 return true;
342}
343
344bool ValidatePaths(const std::vector<std::string>& fileVec, const bool expectFile)
345{
346 bool allPathsValid = true;
347 for (auto const& file : fileVec)
348 {
349 if(!ValidatePath(file, expectFile))
350 {
351 allPathsValid = false;
352 }
353 }
354 return allPathsValid;
355}
356
357
358