• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #include "NetworkExecutionUtils.hpp"
7 
8 #include <Filesystem.hpp>
9 #include <InferenceTest.hpp>
10 #include <ResolveType.hpp>
11 
12 #if defined(ARMNN_SERIALIZER)
13 #include "armnnDeserializer/IDeserializer.hpp"
14 #endif
15 #if defined(ARMNN_CAFFE_PARSER)
16 #include "armnnCaffeParser/ICaffeParser.hpp"
17 #endif
18 #if defined(ARMNN_TF_PARSER)
19 #include "armnnTfParser/ITfParser.hpp"
20 #endif
21 #if defined(ARMNN_TF_LITE_PARSER)
22 #include "armnnTfLiteParser/ITfLiteParser.hpp"
23 #endif
24 #if defined(ARMNN_ONNX_PARSER)
25 #include "armnnOnnxParser/IOnnxParser.hpp"
26 #endif
27 
28 template<armnn::DataType NonQuantizedType>
29 auto ParseDataArray(std::istream& stream);
30 
31 template<armnn::DataType QuantizedType>
32 auto ParseDataArray(std::istream& stream,
33                     const float& quantizationScale,
34                     const int32_t& quantizationOffset);
35 
36 template<>
ParseDataArray(std::istream & stream)37 auto ParseDataArray<armnn::DataType::Float32>(std::istream& stream)
38 {
39     return ParseArrayImpl<float>(stream, [](const std::string& s) { return std::stof(s); });
40 }
41 
42 template<>
ParseDataArray(std::istream & stream)43 auto ParseDataArray<armnn::DataType::Signed32>(std::istream& stream)
44 {
45     return ParseArrayImpl<int>(stream, [](const std::string& s) { return std::stoi(s); });
46 }
47 
48 template<>
ParseDataArray(std::istream & stream)49 auto ParseDataArray<armnn::DataType::QAsymmU8>(std::istream& stream)
50 {
51     return ParseArrayImpl<uint8_t>(stream,
52                                    [](const std::string& s) { return armnn::numeric_cast<uint8_t>(std::stoi(s)); });
53 }
54 
55 template<>
ParseDataArray(std::istream & stream,const float & quantizationScale,const int32_t & quantizationOffset)56 auto ParseDataArray<armnn::DataType::QAsymmU8>(std::istream& stream,
57                                                const float& quantizationScale,
58                                                const int32_t& quantizationOffset)
59 {
60     return ParseArrayImpl<uint8_t>(stream,
61                                    [&quantizationScale, &quantizationOffset](const std::string& s)
62                                    {
63                                        return armnn::numeric_cast<uint8_t>(
64                                                armnn::Quantize<uint8_t>(std::stof(s),
65                                                                         quantizationScale,
66                                                                         quantizationOffset));
67                                    });
68 }
69 
70 template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
GenerateDummyTensorData(unsigned int numElements)71 std::vector<T> GenerateDummyTensorData(unsigned int numElements)
72 {
73     return std::vector<T>(numElements, static_cast<T>(0));
74 }
75 
76 
ParseArray(std::istream & stream)77 std::vector<unsigned int> ParseArray(std::istream& stream)
78 {
79     return ParseArrayImpl<unsigned int>(
80             stream,
81             [](const std::string& s) { return armnn::numeric_cast<unsigned int>(std::stoi(s)); });
82 }
83 
ParseStringList(const std::string & inputString,const char * delimiter)84 std::vector<std::string> ParseStringList(const std::string& inputString, const char* delimiter)
85 {
86     std::stringstream stream(inputString);
87     return ParseArrayImpl<std::string>(stream, [](const std::string& s) {
88         return armnn::stringUtils::StringTrimCopy(s); }, delimiter);
89 }
90 
91 
TensorPrinter(const std::string & binding,const armnn::TensorInfo & info,const std::string & outputTensorFile,bool dequantizeOutput)92 TensorPrinter::TensorPrinter(const std::string& binding,
93                              const armnn::TensorInfo& info,
94                              const std::string& outputTensorFile,
95                              bool dequantizeOutput)
96                              : m_OutputBinding(binding)
97                              , m_Scale(info.GetQuantizationScale())
98                              , m_Offset(info.GetQuantizationOffset())
99                              , m_OutputTensorFile(outputTensorFile)
100                              , m_DequantizeOutput(dequantizeOutput) {}
101 
operator ()(const std::vector<float> & values)102 void TensorPrinter::operator()(const std::vector<float>& values)
103 {
104     ForEachValue(values, [](float value)
105     {
106         printf("%f ", value);
107     });
108     WriteToFile(values);
109 }
110 
operator ()(const std::vector<uint8_t> & values)111 void TensorPrinter::operator()(const std::vector<uint8_t>& values)
112 {
113     if(m_DequantizeOutput)
114     {
115         auto& scale = m_Scale;
116         auto& offset = m_Offset;
117         std::vector<float> dequantizedValues;
118         ForEachValue(values, [&scale, &offset, &dequantizedValues](uint8_t value)
119         {
120             auto dequantizedValue = armnn::Dequantize(value, scale, offset);
121             printf("%f ", dequantizedValue);
122             dequantizedValues.push_back(dequantizedValue);
123         });
124         WriteToFile(dequantizedValues);
125     }
126     else
127     {
128         const std::vector<int> intValues(values.begin(), values.end());
129         operator()(intValues);
130     }
131 }
132 
operator ()(const std::vector<int> & values)133 void TensorPrinter::operator()(const std::vector<int>& values)
134 {
135     ForEachValue(values, [](int value)
136     {
137         printf("%d ", value);
138     });
139     WriteToFile(values);
140 }
141 
142 template<typename Container, typename Delegate>
ForEachValue(const Container & c,Delegate delegate)143 void TensorPrinter::ForEachValue(const Container& c, Delegate delegate)
144 {
145     std::cout << m_OutputBinding << ": ";
146     for (const auto& value : c)
147     {
148         delegate(value);
149     }
150     printf("\n");
151 }
152 
153 template<typename T>
WriteToFile(const std::vector<T> & values)154 void TensorPrinter::WriteToFile(const std::vector<T>& values)
155 {
156     if (!m_OutputTensorFile.empty())
157     {
158         std::ofstream outputTensorFile;
159         outputTensorFile.open(m_OutputTensorFile, std::ofstream::out | std::ofstream::trunc);
160         if (outputTensorFile.is_open())
161         {
162             outputTensorFile << m_OutputBinding << ": ";
163             std::copy(values.begin(), values.end(), std::ostream_iterator<T>(outputTensorFile, " "));
164         }
165         else
166         {
167             ARMNN_LOG(info) << "Output Tensor File: " << m_OutputTensorFile << " could not be opened!";
168         }
169         outputTensorFile.close();
170     }
171 }
172 
173 using TContainer         = mapbox::util::variant<std::vector<float>, std::vector<int>, std::vector<unsigned char>>;
174 using QuantizationParams = std::pair<float, int32_t>;
175 
PopulateTensorWithData(TContainer & tensorData,unsigned int numElements,const std::string & dataTypeStr,const armnn::Optional<QuantizationParams> & qParams,const armnn::Optional<std::string> & dataFile)176 void PopulateTensorWithData(TContainer& tensorData,
177                             unsigned int numElements,
178                             const std::string& dataTypeStr,
179                             const armnn::Optional<QuantizationParams>& qParams,
180                             const armnn::Optional<std::string>& dataFile)
181 {
182     const bool readFromFile = dataFile.has_value() && !dataFile.value().empty();
183     const bool quantizeData = qParams.has_value();
184 
185     std::ifstream inputTensorFile;
186     if (readFromFile)
187     {
188         inputTensorFile = std::ifstream(dataFile.value());
189     }
190 
191     if (dataTypeStr.compare("float") == 0)
192     {
193         if (quantizeData)
194         {
195             const float qScale  = qParams.value().first;
196             const int   qOffset = qParams.value().second;
197 
198             tensorData = readFromFile ?
199                          ParseDataArray<armnn::DataType::QAsymmU8>(inputTensorFile, qScale, qOffset) :
200                          GenerateDummyTensorData<armnn::DataType::QAsymmU8>(numElements);
201         }
202         else
203         {
204             tensorData = readFromFile ?
205                          ParseDataArray<armnn::DataType::Float32>(inputTensorFile) :
206                          GenerateDummyTensorData<armnn::DataType::Float32>(numElements);
207         }
208     }
209     else if (dataTypeStr.compare("int") == 0)
210     {
211         tensorData = readFromFile ?
212                      ParseDataArray<armnn::DataType::Signed32>(inputTensorFile) :
213                      GenerateDummyTensorData<armnn::DataType::Signed32>(numElements);
214     }
215     else if (dataTypeStr.compare("qasymm8") == 0)
216     {
217         tensorData = readFromFile ?
218                      ParseDataArray<armnn::DataType::QAsymmU8>(inputTensorFile) :
219                      GenerateDummyTensorData<armnn::DataType::QAsymmU8>(numElements);
220     }
221     else
222     {
223         std::string errorMessage = "Unsupported tensor data type " + dataTypeStr;
224         ARMNN_LOG(fatal) << errorMessage;
225 
226         inputTensorFile.close();
227         throw armnn::Exception(errorMessage);
228     }
229 
230     inputTensorFile.close();
231 }
232 
ValidatePath(const std::string & file,const bool expectFile)233 bool ValidatePath(const std::string& file, const bool expectFile)
234 {
235     if (!fs::exists(file))
236     {
237         std::cerr << "Given file path '" << file << "' does not exist" << std::endl;
238         return false;
239     }
240     if (!fs::is_regular_file(file) && expectFile)
241     {
242         std::cerr << "Given file path '" << file << "' is not a regular file" << std::endl;
243         return false;
244     }
245     return true;
246 }
247 
ValidatePaths(const std::vector<std::string> & fileVec,const bool expectFile)248 bool ValidatePaths(const std::vector<std::string>& fileVec, const bool expectFile)
249 {
250     bool allPathsValid = true;
251     for (auto const& file : fileVec)
252     {
253         if(!ValidatePath(file, expectFile))
254         {
255             allPathsValid = false;
256         }
257     }
258     return allPathsValid;
259 }
260 
261 
262 
263