blob: da3188c1e72ae7d9e4b6b43d58ce28616d283c11 [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<>
37auto ParseDataArray<armnn::DataType::Signed32>(std::istream& stream)
38{
39 return ParseArrayImpl<int>(stream, [](const std::string& s) { return std::stoi(s); });
40}
41
42template<>
Mike Kellyd7ed6d42021-07-21 09:42:43 +010043auto ParseDataArray<armnn::DataType::QAsymmS8>(std::istream& stream)
44{
45 return ParseArrayImpl<int8_t>(stream,
46 [](const std::string& s) { return armnn::numeric_cast<int8_t>(std::stoi(s)); });
47}
48
49template<>
Jan Eilers45274902020-10-15 18:34:43 +010050auto ParseDataArray<armnn::DataType::QAsymmU8>(std::istream& stream)
51{
52 return ParseArrayImpl<uint8_t>(stream,
53 [](const std::string& s) { return armnn::numeric_cast<uint8_t>(std::stoi(s)); });
54}
55
Finn Williamsf806c4d2021-02-22 15:13:12 +000056
57template<>
58auto ParseDataArray<armnn::DataType::QSymmS8>(std::istream& stream)
59{
60 return ParseArrayImpl<int8_t>(stream,
61 [](const std::string& s) { return armnn::numeric_cast<int8_t>(std::stoi(s)); });
62}
63
Mike Kellyd7ed6d42021-07-21 09:42:43 +010064template<>
65auto ParseDataArray<armnn::DataType::QAsymmS8>(std::istream& stream,
66 const float& quantizationScale,
67 const int32_t& quantizationOffset)
68{
69 return ParseArrayImpl<int8_t>(stream,
70 [&quantizationScale, &quantizationOffset](const std::string& s)
71 {
72 return armnn::numeric_cast<int8_t>(
73 armnn::Quantize<int8_t>(std::stof(s),
74 quantizationScale,
75 quantizationOffset));
76 });
77}
Finn Williamsf806c4d2021-02-22 15:13:12 +000078
Jan Eilers45274902020-10-15 18:34:43 +010079template<>
80auto ParseDataArray<armnn::DataType::QAsymmU8>(std::istream& stream,
81 const float& quantizationScale,
82 const int32_t& quantizationOffset)
83{
84 return ParseArrayImpl<uint8_t>(stream,
85 [&quantizationScale, &quantizationOffset](const std::string& s)
86 {
87 return armnn::numeric_cast<uint8_t>(
88 armnn::Quantize<uint8_t>(std::stof(s),
89 quantizationScale,
90 quantizationOffset));
91 });
92}
93
94template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
95std::vector<T> GenerateDummyTensorData(unsigned int numElements)
96{
97 return std::vector<T>(numElements, static_cast<T>(0));
98}
99
100
101std::vector<unsigned int> ParseArray(std::istream& stream)
102{
103 return ParseArrayImpl<unsigned int>(
104 stream,
105 [](const std::string& s) { return armnn::numeric_cast<unsigned int>(std::stoi(s)); });
106}
107
108std::vector<std::string> ParseStringList(const std::string& inputString, const char* delimiter)
109{
110 std::stringstream stream(inputString);
111 return ParseArrayImpl<std::string>(stream, [](const std::string& s) {
112 return armnn::stringUtils::StringTrimCopy(s); }, delimiter);
113}
114
115
116TensorPrinter::TensorPrinter(const std::string& binding,
117 const armnn::TensorInfo& info,
118 const std::string& outputTensorFile,
Jan Eilers284b5d12021-09-07 12:46:15 +0100119 bool dequantizeOutput,
120 const bool printToConsole)
Jan Eilers45274902020-10-15 18:34:43 +0100121 : m_OutputBinding(binding)
122 , m_Scale(info.GetQuantizationScale())
123 , m_Offset(info.GetQuantizationOffset())
124 , m_OutputTensorFile(outputTensorFile)
Jan Eilers284b5d12021-09-07 12:46:15 +0100125 , m_DequantizeOutput(dequantizeOutput)
126 , m_PrintToConsole(printToConsole) {}
Jan Eilers45274902020-10-15 18:34:43 +0100127
128void TensorPrinter::operator()(const std::vector<float>& values)
129{
Jan Eilers284b5d12021-09-07 12:46:15 +0100130 if (m_PrintToConsole)
Jan Eilers45274902020-10-15 18:34:43 +0100131 {
Jan Eilers284b5d12021-09-07 12:46:15 +0100132 std::cout << m_OutputBinding << ": ";
133 ForEachValue(values, [](float value)
134 {
135 printf("%f ", value);
136 });
137 printf("\n");
138 }
Jan Eilers45274902020-10-15 18:34:43 +0100139 WriteToFile(values);
140}
141
142void TensorPrinter::operator()(const std::vector<uint8_t>& values)
143{
144 if(m_DequantizeOutput)
145 {
146 auto& scale = m_Scale;
147 auto& offset = m_Offset;
148 std::vector<float> dequantizedValues;
149 ForEachValue(values, [&scale, &offset, &dequantizedValues](uint8_t value)
150 {
151 auto dequantizedValue = armnn::Dequantize(value, scale, offset);
Jan Eilers45274902020-10-15 18:34:43 +0100152 dequantizedValues.push_back(dequantizedValue);
153 });
Jan Eilers284b5d12021-09-07 12:46:15 +0100154
155 if (m_PrintToConsole)
156 {
157 std::cout << m_OutputBinding << ": ";
158 ForEachValue(dequantizedValues, [](float value)
159 {
160 printf("%f ", value);
161 });
162 printf("\n");
163 }
164
Jan Eilers45274902020-10-15 18:34:43 +0100165 WriteToFile(dequantizedValues);
166 }
167 else
168 {
169 const std::vector<int> intValues(values.begin(), values.end());
170 operator()(intValues);
171 }
172}
173
Finn Williamsf806c4d2021-02-22 15:13:12 +0000174void TensorPrinter::operator()(const std::vector<int8_t>& values)
175{
Jan Eilers284b5d12021-09-07 12:46:15 +0100176 if (m_PrintToConsole)
Finn Williamsf806c4d2021-02-22 15:13:12 +0000177 {
Jan Eilers284b5d12021-09-07 12:46:15 +0100178 std::cout << m_OutputBinding << ": ";
179 ForEachValue(values, [](int8_t value)
180 {
181 printf("%d ", value);
182 });
183 printf("\n");
184 }
Finn Williamsf806c4d2021-02-22 15:13:12 +0000185 WriteToFile(values);
186}
187
Jan Eilers45274902020-10-15 18:34:43 +0100188void TensorPrinter::operator()(const std::vector<int>& values)
189{
Jan Eilers284b5d12021-09-07 12:46:15 +0100190 if (m_PrintToConsole)
Jan Eilers45274902020-10-15 18:34:43 +0100191 {
Jan Eilers284b5d12021-09-07 12:46:15 +0100192 std::cout << m_OutputBinding << ": ";
193 ForEachValue(values, [](int value)
194 {
195 printf("%d ", value);
196 });
197 printf("\n");
198 }
Jan Eilers45274902020-10-15 18:34:43 +0100199 WriteToFile(values);
200}
201
202template<typename Container, typename Delegate>
203void TensorPrinter::ForEachValue(const Container& c, Delegate delegate)
204{
Jan Eilers284b5d12021-09-07 12:46:15 +0100205 if (m_PrintToConsole)
206 {
207 std::cout << m_OutputBinding << ": ";
208 }
Jan Eilers45274902020-10-15 18:34:43 +0100209 for (const auto& value : c)
210 {
211 delegate(value);
212 }
Jan Eilers284b5d12021-09-07 12:46:15 +0100213 if (m_PrintToConsole)
214 {
215 printf("\n");
216 }
Jan Eilers45274902020-10-15 18:34:43 +0100217}
218
219template<typename T>
220void TensorPrinter::WriteToFile(const std::vector<T>& values)
221{
222 if (!m_OutputTensorFile.empty())
223 {
224 std::ofstream outputTensorFile;
225 outputTensorFile.open(m_OutputTensorFile, std::ofstream::out | std::ofstream::trunc);
226 if (outputTensorFile.is_open())
227 {
228 outputTensorFile << m_OutputBinding << ": ";
229 std::copy(values.begin(), values.end(), std::ostream_iterator<T>(outputTensorFile, " "));
230 }
231 else
232 {
233 ARMNN_LOG(info) << "Output Tensor File: " << m_OutputTensorFile << " could not be opened!";
234 }
235 outputTensorFile.close();
236 }
237}
238
Finn Williamsf806c4d2021-02-22 15:13:12 +0000239using TContainer =
240 mapbox::util::variant<std::vector<float>, std::vector<int>, std::vector<unsigned char>, std::vector<int8_t>>;
Jan Eilers45274902020-10-15 18:34:43 +0100241using QuantizationParams = std::pair<float, int32_t>;
242
243void PopulateTensorWithData(TContainer& tensorData,
244 unsigned int numElements,
245 const std::string& dataTypeStr,
246 const armnn::Optional<QuantizationParams>& qParams,
247 const armnn::Optional<std::string>& dataFile)
248{
249 const bool readFromFile = dataFile.has_value() && !dataFile.value().empty();
250 const bool quantizeData = qParams.has_value();
251
252 std::ifstream inputTensorFile;
253 if (readFromFile)
254 {
255 inputTensorFile = std::ifstream(dataFile.value());
256 }
257
258 if (dataTypeStr.compare("float") == 0)
259 {
260 if (quantizeData)
261 {
262 const float qScale = qParams.value().first;
263 const int qOffset = qParams.value().second;
264
265 tensorData = readFromFile ?
266 ParseDataArray<armnn::DataType::QAsymmU8>(inputTensorFile, qScale, qOffset) :
267 GenerateDummyTensorData<armnn::DataType::QAsymmU8>(numElements);
268 }
269 else
270 {
271 tensorData = readFromFile ?
272 ParseDataArray<armnn::DataType::Float32>(inputTensorFile) :
273 GenerateDummyTensorData<armnn::DataType::Float32>(numElements);
274 }
275 }
276 else if (dataTypeStr.compare("int") == 0)
277 {
278 tensorData = readFromFile ?
279 ParseDataArray<armnn::DataType::Signed32>(inputTensorFile) :
280 GenerateDummyTensorData<armnn::DataType::Signed32>(numElements);
281 }
Finn Williamsf806c4d2021-02-22 15:13:12 +0000282 else if (dataTypeStr.compare("qsymms8") == 0)
283 {
284 tensorData = readFromFile ?
285 ParseDataArray<armnn::DataType::QSymmS8>(inputTensorFile) :
286 GenerateDummyTensorData<armnn::DataType::QSymmS8>(numElements);
287 }
Mike Kellyd7ed6d42021-07-21 09:42:43 +0100288 else if (dataTypeStr.compare("qasymm8") == 0 || dataTypeStr.compare("qasymmu8") == 0)
Jan Eilers45274902020-10-15 18:34:43 +0100289 {
290 tensorData = readFromFile ?
291 ParseDataArray<armnn::DataType::QAsymmU8>(inputTensorFile) :
292 GenerateDummyTensorData<armnn::DataType::QAsymmU8>(numElements);
293 }
Mike Kellyd7ed6d42021-07-21 09:42:43 +0100294 else if (dataTypeStr.compare("qasymms8") == 0)
295 {
296 tensorData = readFromFile ?
297 ParseDataArray<armnn::DataType::QAsymmS8>(inputTensorFile) :
298 GenerateDummyTensorData<armnn::DataType::QAsymmS8>(numElements);
299 }
Jan Eilers45274902020-10-15 18:34:43 +0100300 else
301 {
302 std::string errorMessage = "Unsupported tensor data type " + dataTypeStr;
303 ARMNN_LOG(fatal) << errorMessage;
304
305 inputTensorFile.close();
306 throw armnn::Exception(errorMessage);
307 }
308
309 inputTensorFile.close();
310}
311
312bool ValidatePath(const std::string& file, const bool expectFile)
313{
314 if (!fs::exists(file))
315 {
316 std::cerr << "Given file path '" << file << "' does not exist" << std::endl;
317 return false;
318 }
319 if (!fs::is_regular_file(file) && expectFile)
320 {
321 std::cerr << "Given file path '" << file << "' is not a regular file" << std::endl;
322 return false;
323 }
324 return true;
325}
326
327bool ValidatePaths(const std::vector<std::string>& fileVec, const bool expectFile)
328{
329 bool allPathsValid = true;
330 for (auto const& file : fileVec)
331 {
332 if(!ValidatePath(file, expectFile))
333 {
334 allPathsValid = false;
335 }
336 }
337 return allPathsValid;
338}
339
340
341