1*89c4ff92SAndroid Build Coastguard Worker //
2*89c4ff92SAndroid Build Coastguard Worker // Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
3*89c4ff92SAndroid Build Coastguard Worker // SPDX-License-Identifier: MIT
4*89c4ff92SAndroid Build Coastguard Worker //
5*89c4ff92SAndroid Build Coastguard Worker
6*89c4ff92SAndroid Build Coastguard Worker #pragma once
7*89c4ff92SAndroid Build Coastguard Worker
8*89c4ff92SAndroid Build Coastguard Worker #include <armnn/BackendRegistry.hpp> // for BackendRegistryInstance
9*89c4ff92SAndroid Build Coastguard Worker #include <armnn/Logging.hpp> // for ScopedRecord, ARMNN_LOG
10*89c4ff92SAndroid Build Coastguard Worker #include <armnn/utility/NumericCast.hpp> // for numeric_cast
11*89c4ff92SAndroid Build Coastguard Worker #include <armnn/utility/StringUtils.hpp> // for StringTokenizer
12*89c4ff92SAndroid Build Coastguard Worker #include <armnn/BackendId.hpp> // for BackendId, BackendIdSet
13*89c4ff92SAndroid Build Coastguard Worker #include <armnn/Optional.hpp> // for Optional, EmptyOptional
14*89c4ff92SAndroid Build Coastguard Worker #include <armnn/Tensor.hpp> // for Tensor, TensorInfo
15*89c4ff92SAndroid Build Coastguard Worker #include <armnn/TypesUtils.hpp> // for Dequantize
16*89c4ff92SAndroid Build Coastguard Worker #include <chrono> // for duration
17*89c4ff92SAndroid Build Coastguard Worker #include <functional> // for function
18*89c4ff92SAndroid Build Coastguard Worker #include <fstream>
19*89c4ff92SAndroid Build Coastguard Worker #include <iomanip>
20*89c4ff92SAndroid Build Coastguard Worker #include <iostream> // for ofstream, basic_istream
21*89c4ff92SAndroid Build Coastguard Worker #include <ratio> // for milli
22*89c4ff92SAndroid Build Coastguard Worker #include <string> // for string, getline, basic_string
23*89c4ff92SAndroid Build Coastguard Worker #include <type_traits> // for enable_if_t, is_floating_point
24*89c4ff92SAndroid Build Coastguard Worker #include <unordered_set> // for operator!=, operator==, _No...
25*89c4ff92SAndroid Build Coastguard Worker #include <vector> // for vector
26*89c4ff92SAndroid Build Coastguard Worker #include <math.h> // for pow, sqrt
27*89c4ff92SAndroid Build Coastguard Worker #include <stdint.h> // for int32_t
28*89c4ff92SAndroid Build Coastguard Worker #include <stdio.h> // for printf, size_t
29*89c4ff92SAndroid Build Coastguard Worker #include <stdlib.h> // for abs
30*89c4ff92SAndroid Build Coastguard Worker #include <algorithm> // for find, for_each
31*89c4ff92SAndroid Build Coastguard Worker
32*89c4ff92SAndroid Build Coastguard Worker /**
33*89c4ff92SAndroid Build Coastguard Worker * Given a measured duration and a threshold time tell the user whether we succeeded or not.
34*89c4ff92SAndroid Build Coastguard Worker *
35*89c4ff92SAndroid Build Coastguard Worker * @param duration the measured inference duration.
36*89c4ff92SAndroid Build Coastguard Worker * @param thresholdTime the threshold time in milliseconds.
37*89c4ff92SAndroid Build Coastguard Worker * @return false if the measured time exceeded the threshold.
38*89c4ff92SAndroid Build Coastguard Worker */
39*89c4ff92SAndroid Build Coastguard Worker bool CheckInferenceTimeThreshold(const std::chrono::duration<double, std::milli>& duration,
40*89c4ff92SAndroid Build Coastguard Worker const double& thresholdTime);
41*89c4ff92SAndroid Build Coastguard Worker
CheckRequestedBackendsAreValid(const std::vector<armnn::BackendId> & backendIds,armnn::Optional<std::string &> invalidBackendIds=armnn::EmptyOptional ())42*89c4ff92SAndroid Build Coastguard Worker inline bool CheckRequestedBackendsAreValid(const std::vector<armnn::BackendId>& backendIds,
43*89c4ff92SAndroid Build Coastguard Worker armnn::Optional<std::string&> invalidBackendIds = armnn::EmptyOptional())
44*89c4ff92SAndroid Build Coastguard Worker {
45*89c4ff92SAndroid Build Coastguard Worker if (backendIds.empty())
46*89c4ff92SAndroid Build Coastguard Worker {
47*89c4ff92SAndroid Build Coastguard Worker return false;
48*89c4ff92SAndroid Build Coastguard Worker }
49*89c4ff92SAndroid Build Coastguard Worker
50*89c4ff92SAndroid Build Coastguard Worker armnn::BackendIdSet validBackendIds = armnn::BackendRegistryInstance().GetBackendIds();
51*89c4ff92SAndroid Build Coastguard Worker
52*89c4ff92SAndroid Build Coastguard Worker bool allValid = true;
53*89c4ff92SAndroid Build Coastguard Worker for (const auto& backendId : backendIds)
54*89c4ff92SAndroid Build Coastguard Worker {
55*89c4ff92SAndroid Build Coastguard Worker if (std::find(validBackendIds.begin(), validBackendIds.end(), backendId) == validBackendIds.end())
56*89c4ff92SAndroid Build Coastguard Worker {
57*89c4ff92SAndroid Build Coastguard Worker allValid = false;
58*89c4ff92SAndroid Build Coastguard Worker if (invalidBackendIds)
59*89c4ff92SAndroid Build Coastguard Worker {
60*89c4ff92SAndroid Build Coastguard Worker if (!invalidBackendIds.value().empty())
61*89c4ff92SAndroid Build Coastguard Worker {
62*89c4ff92SAndroid Build Coastguard Worker invalidBackendIds.value() += ", ";
63*89c4ff92SAndroid Build Coastguard Worker }
64*89c4ff92SAndroid Build Coastguard Worker invalidBackendIds.value() += backendId;
65*89c4ff92SAndroid Build Coastguard Worker }
66*89c4ff92SAndroid Build Coastguard Worker }
67*89c4ff92SAndroid Build Coastguard Worker }
68*89c4ff92SAndroid Build Coastguard Worker return allValid;
69*89c4ff92SAndroid Build Coastguard Worker }
70*89c4ff92SAndroid Build Coastguard Worker
71*89c4ff92SAndroid Build Coastguard Worker std::vector<unsigned int> ParseArray(std::istream& stream);
72*89c4ff92SAndroid Build Coastguard Worker
73*89c4ff92SAndroid Build Coastguard Worker /// Splits a given string at every accurance of delimiter into a vector of string
74*89c4ff92SAndroid Build Coastguard Worker std::vector<std::string> ParseStringList(const std::string& inputString, const char* delimiter);
75*89c4ff92SAndroid Build Coastguard Worker
76*89c4ff92SAndroid Build Coastguard Worker double ComputeByteLevelRMSE(const void* expected, const void* actual, const size_t size);
77*89c4ff92SAndroid Build Coastguard Worker
78*89c4ff92SAndroid Build Coastguard Worker /// Dequantize an array of a given type
79*89c4ff92SAndroid Build Coastguard Worker /// @param array Type erased array to dequantize
80*89c4ff92SAndroid Build Coastguard Worker /// @param numElements Elements in the array
81*89c4ff92SAndroid Build Coastguard Worker /// @param array Type erased array to dequantize
82*89c4ff92SAndroid Build Coastguard Worker template <typename T>
DequantizeArray(const void * array,unsigned int numElements,float scale,int32_t offset)83*89c4ff92SAndroid Build Coastguard Worker std::vector<float> DequantizeArray(const void* array, unsigned int numElements, float scale, int32_t offset)
84*89c4ff92SAndroid Build Coastguard Worker {
85*89c4ff92SAndroid Build Coastguard Worker const T* quantizedArray = reinterpret_cast<const T*>(array);
86*89c4ff92SAndroid Build Coastguard Worker std::vector<float> dequantizedVector;
87*89c4ff92SAndroid Build Coastguard Worker dequantizedVector.reserve(numElements);
88*89c4ff92SAndroid Build Coastguard Worker for (unsigned int i = 0; i < numElements; ++i)
89*89c4ff92SAndroid Build Coastguard Worker {
90*89c4ff92SAndroid Build Coastguard Worker float f = armnn::Dequantize(*(quantizedArray + i), scale, offset);
91*89c4ff92SAndroid Build Coastguard Worker dequantizedVector.push_back(f);
92*89c4ff92SAndroid Build Coastguard Worker }
93*89c4ff92SAndroid Build Coastguard Worker return dequantizedVector;
94*89c4ff92SAndroid Build Coastguard Worker }
95*89c4ff92SAndroid Build Coastguard Worker
96*89c4ff92SAndroid Build Coastguard Worker void LogAndThrow(std::string eMsg);
97*89c4ff92SAndroid Build Coastguard Worker
98*89c4ff92SAndroid Build Coastguard Worker /**
99*89c4ff92SAndroid Build Coastguard Worker * Verifies if the given string is a valid path. Reports invalid paths to std::err.
100*89c4ff92SAndroid Build Coastguard Worker * @param file string - A string containing the path to check
101*89c4ff92SAndroid Build Coastguard Worker * @param expectFile bool - If true, checks for a regular file.
102*89c4ff92SAndroid Build Coastguard Worker * @return bool - True if given string is a valid path., false otherwise.
103*89c4ff92SAndroid Build Coastguard Worker * */
104*89c4ff92SAndroid Build Coastguard Worker bool ValidatePath(const std::string& file, const bool expectFile);
105*89c4ff92SAndroid Build Coastguard Worker
106*89c4ff92SAndroid Build Coastguard Worker /**
107*89c4ff92SAndroid Build Coastguard Worker * Verifies if a given vector of strings are valid paths. Reports invalid paths to std::err.
108*89c4ff92SAndroid Build Coastguard Worker * @param fileVec vector of string - A vector of string containing the paths to check
109*89c4ff92SAndroid Build Coastguard Worker * @param expectFile bool - If true, checks for a regular file.
110*89c4ff92SAndroid Build Coastguard Worker * @return bool - True if all given strings are valid paths., false otherwise.
111*89c4ff92SAndroid Build Coastguard Worker * */
112*89c4ff92SAndroid Build Coastguard Worker bool ValidatePaths(const std::vector<std::string>& fileVec, const bool expectFile);
113*89c4ff92SAndroid Build Coastguard Worker
114*89c4ff92SAndroid Build Coastguard Worker /// Returns a function of read the given type as a string
115*89c4ff92SAndroid Build Coastguard Worker template <typename Integer, typename std::enable_if_t<std::is_integral<Integer>::value>* = nullptr>
GetParseElementFunc()116*89c4ff92SAndroid Build Coastguard Worker std::function<Integer(const std::string&)> GetParseElementFunc()
117*89c4ff92SAndroid Build Coastguard Worker {
118*89c4ff92SAndroid Build Coastguard Worker return [](const std::string& s) { return armnn::numeric_cast<Integer>(std::stoi(s)); };
119*89c4ff92SAndroid Build Coastguard Worker }
120*89c4ff92SAndroid Build Coastguard Worker
121*89c4ff92SAndroid Build Coastguard Worker template <typename Float, std::enable_if_t<std::is_floating_point<Float>::value>* = nullptr>
GetParseElementFunc()122*89c4ff92SAndroid Build Coastguard Worker std::function<Float(const std::string&)> GetParseElementFunc()
123*89c4ff92SAndroid Build Coastguard Worker {
124*89c4ff92SAndroid Build Coastguard Worker return [](const std::string& s) { return std::stof(s); };
125*89c4ff92SAndroid Build Coastguard Worker }
126*89c4ff92SAndroid Build Coastguard Worker
127*89c4ff92SAndroid Build Coastguard Worker template <typename T>
PopulateTensorWithData(T * tensor,const unsigned int numElements,const armnn::Optional<std::string> & dataFile,const std::string & inputName)128*89c4ff92SAndroid Build Coastguard Worker void PopulateTensorWithData(T* tensor,
129*89c4ff92SAndroid Build Coastguard Worker const unsigned int numElements,
130*89c4ff92SAndroid Build Coastguard Worker const armnn::Optional<std::string>& dataFile,
131*89c4ff92SAndroid Build Coastguard Worker const std::string& inputName)
132*89c4ff92SAndroid Build Coastguard Worker {
133*89c4ff92SAndroid Build Coastguard Worker const bool readFromFile = dataFile.has_value() && !dataFile.value().empty();
134*89c4ff92SAndroid Build Coastguard Worker
135*89c4ff92SAndroid Build Coastguard Worker std::ifstream inputTensorFile;
136*89c4ff92SAndroid Build Coastguard Worker if (!readFromFile)
137*89c4ff92SAndroid Build Coastguard Worker {
138*89c4ff92SAndroid Build Coastguard Worker std::fill(tensor, tensor + numElements, 0);
139*89c4ff92SAndroid Build Coastguard Worker return;
140*89c4ff92SAndroid Build Coastguard Worker }
141*89c4ff92SAndroid Build Coastguard Worker else
142*89c4ff92SAndroid Build Coastguard Worker {
143*89c4ff92SAndroid Build Coastguard Worker inputTensorFile = std::ifstream(dataFile.value());
144*89c4ff92SAndroid Build Coastguard Worker }
145*89c4ff92SAndroid Build Coastguard Worker
146*89c4ff92SAndroid Build Coastguard Worker auto parseElementFunc = GetParseElementFunc<T>();
147*89c4ff92SAndroid Build Coastguard Worker std::string line;
148*89c4ff92SAndroid Build Coastguard Worker unsigned int index = 0;
149*89c4ff92SAndroid Build Coastguard Worker while (std::getline(inputTensorFile, line))
150*89c4ff92SAndroid Build Coastguard Worker {
151*89c4ff92SAndroid Build Coastguard Worker std::vector<std::string> tokens = armnn::stringUtils::StringTokenizer(line, "\t ,:");
152*89c4ff92SAndroid Build Coastguard Worker for (const std::string& token : tokens)
153*89c4ff92SAndroid Build Coastguard Worker {
154*89c4ff92SAndroid Build Coastguard Worker if (!token.empty()) // See https://stackoverflow.com/questions/10437406/
155*89c4ff92SAndroid Build Coastguard Worker {
156*89c4ff92SAndroid Build Coastguard Worker try
157*89c4ff92SAndroid Build Coastguard Worker {
158*89c4ff92SAndroid Build Coastguard Worker if (index == numElements)
159*89c4ff92SAndroid Build Coastguard Worker {
160*89c4ff92SAndroid Build Coastguard Worker ARMNN_LOG(error) << "Number of elements: " << (index +1) << " in file \"" << dataFile.value()
161*89c4ff92SAndroid Build Coastguard Worker << "\" does not match number of elements: " << numElements
162*89c4ff92SAndroid Build Coastguard Worker << " for input \"" << inputName << "\".";
163*89c4ff92SAndroid Build Coastguard Worker }
164*89c4ff92SAndroid Build Coastguard Worker *(tensor + index) = parseElementFunc(token);
165*89c4ff92SAndroid Build Coastguard Worker index++;
166*89c4ff92SAndroid Build Coastguard Worker }
167*89c4ff92SAndroid Build Coastguard Worker catch (const std::exception&)
168*89c4ff92SAndroid Build Coastguard Worker {
169*89c4ff92SAndroid Build Coastguard Worker ARMNN_LOG(error) << "'" << token << "' is not a valid number. It has been ignored.";
170*89c4ff92SAndroid Build Coastguard Worker }
171*89c4ff92SAndroid Build Coastguard Worker }
172*89c4ff92SAndroid Build Coastguard Worker }
173*89c4ff92SAndroid Build Coastguard Worker }
174*89c4ff92SAndroid Build Coastguard Worker
175*89c4ff92SAndroid Build Coastguard Worker if (index != numElements)
176*89c4ff92SAndroid Build Coastguard Worker {
177*89c4ff92SAndroid Build Coastguard Worker ARMNN_LOG(error) << "Number of elements: " << (index +1) << " in file \"" << inputName
178*89c4ff92SAndroid Build Coastguard Worker << "\" does not match number of elements: " << numElements
179*89c4ff92SAndroid Build Coastguard Worker << " for input \"" << inputName << "\".";
180*89c4ff92SAndroid Build Coastguard Worker }
181*89c4ff92SAndroid Build Coastguard Worker }
182*89c4ff92SAndroid Build Coastguard Worker
183*89c4ff92SAndroid Build Coastguard Worker template<typename T>
WriteToFile(const std::string & outputTensorFileName,const std::string & outputName,const T * const array,const unsigned int numElements)184*89c4ff92SAndroid Build Coastguard Worker void WriteToFile(const std::string& outputTensorFileName,
185*89c4ff92SAndroid Build Coastguard Worker const std::string& outputName,
186*89c4ff92SAndroid Build Coastguard Worker const T* const array,
187*89c4ff92SAndroid Build Coastguard Worker const unsigned int numElements)
188*89c4ff92SAndroid Build Coastguard Worker {
189*89c4ff92SAndroid Build Coastguard Worker std::ofstream outputTensorFile;
190*89c4ff92SAndroid Build Coastguard Worker outputTensorFile.open(outputTensorFileName, std::ofstream::out | std::ofstream::trunc);
191*89c4ff92SAndroid Build Coastguard Worker if (outputTensorFile.is_open())
192*89c4ff92SAndroid Build Coastguard Worker {
193*89c4ff92SAndroid Build Coastguard Worker outputTensorFile << outputName << ": ";
194*89c4ff92SAndroid Build Coastguard Worker for (std::size_t i = 0; i < numElements; ++i)
195*89c4ff92SAndroid Build Coastguard Worker {
196*89c4ff92SAndroid Build Coastguard Worker outputTensorFile << +array[i] << " ";
197*89c4ff92SAndroid Build Coastguard Worker }
198*89c4ff92SAndroid Build Coastguard Worker }
199*89c4ff92SAndroid Build Coastguard Worker else
200*89c4ff92SAndroid Build Coastguard Worker {
201*89c4ff92SAndroid Build Coastguard Worker ARMNN_LOG(info) << "Output Tensor File: " << outputTensorFileName << " could not be opened!";
202*89c4ff92SAndroid Build Coastguard Worker }
203*89c4ff92SAndroid Build Coastguard Worker outputTensorFile.close();
204*89c4ff92SAndroid Build Coastguard Worker }
205*89c4ff92SAndroid Build Coastguard Worker
206*89c4ff92SAndroid Build Coastguard Worker struct OutputWriteInfo
207*89c4ff92SAndroid Build Coastguard Worker {
208*89c4ff92SAndroid Build Coastguard Worker const armnn::Optional<std::string>& m_OutputTensorFile;
209*89c4ff92SAndroid Build Coastguard Worker const std::string& m_OutputName;
210*89c4ff92SAndroid Build Coastguard Worker const armnn::Tensor& m_Tensor;
211*89c4ff92SAndroid Build Coastguard Worker const bool m_PrintTensor;
212*89c4ff92SAndroid Build Coastguard Worker };
213*89c4ff92SAndroid Build Coastguard Worker
214*89c4ff92SAndroid Build Coastguard Worker template <typename T>
PrintTensor(OutputWriteInfo & info,const char * formatString)215*89c4ff92SAndroid Build Coastguard Worker void PrintTensor(OutputWriteInfo& info, const char* formatString)
216*89c4ff92SAndroid Build Coastguard Worker {
217*89c4ff92SAndroid Build Coastguard Worker const T* array = reinterpret_cast<const T*>(info.m_Tensor.GetMemoryArea());
218*89c4ff92SAndroid Build Coastguard Worker
219*89c4ff92SAndroid Build Coastguard Worker if (info.m_OutputTensorFile.has_value())
220*89c4ff92SAndroid Build Coastguard Worker {
221*89c4ff92SAndroid Build Coastguard Worker WriteToFile(info.m_OutputTensorFile.value(),
222*89c4ff92SAndroid Build Coastguard Worker info.m_OutputName,
223*89c4ff92SAndroid Build Coastguard Worker array,
224*89c4ff92SAndroid Build Coastguard Worker info.m_Tensor.GetNumElements());
225*89c4ff92SAndroid Build Coastguard Worker }
226*89c4ff92SAndroid Build Coastguard Worker
227*89c4ff92SAndroid Build Coastguard Worker if (info.m_PrintTensor)
228*89c4ff92SAndroid Build Coastguard Worker {
229*89c4ff92SAndroid Build Coastguard Worker for (unsigned int i = 0; i < info.m_Tensor.GetNumElements(); i++)
230*89c4ff92SAndroid Build Coastguard Worker {
231*89c4ff92SAndroid Build Coastguard Worker printf(formatString, array[i]);
232*89c4ff92SAndroid Build Coastguard Worker }
233*89c4ff92SAndroid Build Coastguard Worker }
234*89c4ff92SAndroid Build Coastguard Worker }
235*89c4ff92SAndroid Build Coastguard Worker
236*89c4ff92SAndroid Build Coastguard Worker template <typename T>
PrintQuantizedTensor(OutputWriteInfo & info)237*89c4ff92SAndroid Build Coastguard Worker void PrintQuantizedTensor(OutputWriteInfo& info)
238*89c4ff92SAndroid Build Coastguard Worker {
239*89c4ff92SAndroid Build Coastguard Worker std::vector<float> dequantizedValues;
240*89c4ff92SAndroid Build Coastguard Worker auto tensor = info.m_Tensor;
241*89c4ff92SAndroid Build Coastguard Worker dequantizedValues = DequantizeArray<T>(tensor.GetMemoryArea(),
242*89c4ff92SAndroid Build Coastguard Worker tensor.GetNumElements(),
243*89c4ff92SAndroid Build Coastguard Worker tensor.GetInfo().GetQuantizationScale(),
244*89c4ff92SAndroid Build Coastguard Worker tensor.GetInfo().GetQuantizationOffset());
245*89c4ff92SAndroid Build Coastguard Worker
246*89c4ff92SAndroid Build Coastguard Worker if (info.m_OutputTensorFile.has_value())
247*89c4ff92SAndroid Build Coastguard Worker {
248*89c4ff92SAndroid Build Coastguard Worker WriteToFile(info.m_OutputTensorFile.value(),
249*89c4ff92SAndroid Build Coastguard Worker info.m_OutputName,
250*89c4ff92SAndroid Build Coastguard Worker dequantizedValues.data(),
251*89c4ff92SAndroid Build Coastguard Worker tensor.GetNumElements());
252*89c4ff92SAndroid Build Coastguard Worker }
253*89c4ff92SAndroid Build Coastguard Worker
254*89c4ff92SAndroid Build Coastguard Worker if (info.m_PrintTensor)
255*89c4ff92SAndroid Build Coastguard Worker {
256*89c4ff92SAndroid Build Coastguard Worker std::for_each(dequantizedValues.begin(), dequantizedValues.end(), [&](float value)
257*89c4ff92SAndroid Build Coastguard Worker {
258*89c4ff92SAndroid Build Coastguard Worker printf("%f ", value);
259*89c4ff92SAndroid Build Coastguard Worker });
260*89c4ff92SAndroid Build Coastguard Worker }
261*89c4ff92SAndroid Build Coastguard Worker }
262*89c4ff92SAndroid Build Coastguard Worker
263*89c4ff92SAndroid Build Coastguard Worker template<typename T, typename TParseElementFunc>
ParseArrayImpl(std::istream & stream,TParseElementFunc parseElementFunc,const char * chars="\\t ,:")264*89c4ff92SAndroid Build Coastguard Worker std::vector<T> ParseArrayImpl(std::istream& stream, TParseElementFunc parseElementFunc, const char* chars = "\t ,:")
265*89c4ff92SAndroid Build Coastguard Worker {
266*89c4ff92SAndroid Build Coastguard Worker std::vector<T> result;
267*89c4ff92SAndroid Build Coastguard Worker // Processes line-by-line.
268*89c4ff92SAndroid Build Coastguard Worker std::string line;
269*89c4ff92SAndroid Build Coastguard Worker while (std::getline(stream, line))
270*89c4ff92SAndroid Build Coastguard Worker {
271*89c4ff92SAndroid Build Coastguard Worker std::vector<std::string> tokens = armnn::stringUtils::StringTokenizer(line, chars);
272*89c4ff92SAndroid Build Coastguard Worker for (const std::string& token : tokens)
273*89c4ff92SAndroid Build Coastguard Worker {
274*89c4ff92SAndroid Build Coastguard Worker if (!token.empty()) // See https://stackoverflow.com/questions/10437406/
275*89c4ff92SAndroid Build Coastguard Worker {
276*89c4ff92SAndroid Build Coastguard Worker try
277*89c4ff92SAndroid Build Coastguard Worker {
278*89c4ff92SAndroid Build Coastguard Worker result.push_back(parseElementFunc(token));
279*89c4ff92SAndroid Build Coastguard Worker }
280*89c4ff92SAndroid Build Coastguard Worker catch (const std::exception&)
281*89c4ff92SAndroid Build Coastguard Worker {
282*89c4ff92SAndroid Build Coastguard Worker ARMNN_LOG(error) << "'" << token << "' is not a valid number. It has been ignored.";
283*89c4ff92SAndroid Build Coastguard Worker }
284*89c4ff92SAndroid Build Coastguard Worker }
285*89c4ff92SAndroid Build Coastguard Worker }
286*89c4ff92SAndroid Build Coastguard Worker }
287*89c4ff92SAndroid Build Coastguard Worker
288*89c4ff92SAndroid Build Coastguard Worker return result;
289*89c4ff92SAndroid Build Coastguard Worker }
290