blob: ca2e7e316752e91d20580b277dba1de645895fc9 [file] [log] [blame]
Kevin May43a799c2019-02-08 16:31:42 +00001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#include "DeserializeParser.hpp"
7
8#include <armnn/ArmNN.hpp>
9#include <armnn/Exceptions.hpp>
10
11#include <ParserHelper.hpp>
12#include <Permute.hpp>
13#include <VerificationHelpers.hpp>
14
15#include <boost/filesystem.hpp>
16#include <boost/format.hpp>
17#include <boost/core/ignore_unused.hpp>
18#include <boost/assert.hpp>
19#include <boost/format.hpp>
20#include <boost/log/trivial.hpp>
21
22// The generated code based on the Serialize schema:
23#include <Schema_generated.h>
24
25#include <fstream>
26
27using armnn::ParseException;
28using namespace armnn;
29using namespace armnn::armnnSerializer;
30
31namespace armnnDeserializeParser {
32
33namespace {
34
35const uint32_t VIRTUAL_LAYER_ID = std::numeric_limits<uint32_t>::max();
36
37 void CheckGraph(const DeserializeParser::GraphPtr& graph,
38 unsigned int layersIndex,
39 const CheckLocation& location)
40{
41 if (graph->layers() == nullptr)
42 {
43 throw ParseException(
44 boost::str(
45 boost::format("%1% was called with invalid (null) graph. "
46 "Possible reason is that the graph is not yet loaded and Unpack(ed). "
47 "layers:%2% at %3%") %
48 location.m_Function %
49 layersIndex %
50 location.FileLine()));
51 }
52 else if (layersIndex >= graph->layers()->size())
53 {
54 throw ParseException(
55 boost::str(
56 boost::format("%1% was called with an invalid layers index. "
57 "layers:%2% at %3%") %
58 location.m_Function %
59 layersIndex %
60 location.FileLine()));
61 }
62}
63
64void CheckLayers(const DeserializeParser::GraphPtr& graph,
65 unsigned int layersIndex,
66 unsigned int layerIndex,
67 const CheckLocation& location)
68{
69 if (graph->layers() == nullptr)
70 {
71 throw ParseException(
72 boost::str(
73 boost::format("%1% was called with invalid (null) graph. "
74 "Possible reason is that the graph is not yet loaded and Unpack(ed). "
75 "layers:%2% at %4%") %
76 location.m_Function %
77 layersIndex %
78 location.FileLine()));
79 }
80 else if (layersIndex >= graph->layers()->size())
81 {
82 throw ParseException(
83 boost::str(
84 boost::format("%1% was called with an invalid layers index. "
85 "layers:%2% at %4%") %
86 location.m_Function %
87 layersIndex %
88 location.FileLine()));
89 }
90 else if (layerIndex >= graph->layers()[layersIndex].size()
91 && layerIndex != VIRTUAL_LAYER_ID)
92 {
93 throw ParseException(
94 boost::str(
95 boost::format("%1% was called with an invalid layer index. "
96 "layers:%2% layer:%3% at %4%") %
97 location.m_Function %
98 layersIndex %
99 layerIndex %
100 location.FileLine()));
101 }
102}
103
104void CheckTensorPtr(DeserializeParser::TensorRawPtr rawPtr,
105 const CheckLocation& location)
106{
107 if (rawPtr == nullptr)
108 {
109 throw ParseException(
110 boost::str(
111 boost::format("%1% was called with a null tensor pointer. "
112 "at %2%") %
113 location.m_Function %
114 location.FileLine()));
115
116 }
117}
118
119#define CHECK_TENSOR_PTR(TENSOR_PTR) \
120 CheckTensorPtr(TENSOR_PTR, CHECK_LOCATION())
121
122#define CHECK_LAYERS(GRAPH, LAYERS_INDEX, LAYER_INDEX) \
123 CheckLayers(GRAPH, LAYERS_INDEX, LAYER_INDEX, CHECK_LOCATION())
124
125#define CHECK_GRAPH(GRAPH, LAYERS_INDEX) \
126 CheckGraph(GRAPH, LAYERS_INDEX, CHECK_LOCATION())
127}
128
129DeserializeParser::DeserializeParser()
130: m_Network(nullptr, nullptr),
131//May require LayerType_Max to be included
132m_ParserFunctions(Layer_MAX+1, &DeserializeParser::ParseUnsupportedLayer)
133{
134 // register supported layers
135 m_ParserFunctions[Layer_AdditionLayer] = &DeserializeParser::ParseAdd;
136}
137
138DeserializeParser::LayerBaseRawPtr DeserializeParser::GetBaseLayer(const GraphPtr& graphPtr, unsigned int layerIndex)
139{
140 auto layerType = graphPtr->layers()->Get(layerIndex)->layer_type();
141
142 switch(layerType)
143 {
144 case Layer::Layer_AdditionLayer:
145 return graphPtr->layers()->Get(layerIndex)->layer_as_AdditionLayer()->base();
146 case Layer::Layer_InputLayer:
147 return graphPtr->layers()->Get(layerIndex)->layer_as_InputLayer()->base()->base();
148 case Layer::Layer_OutputLayer:
149 return graphPtr->layers()->Get(layerIndex)->layer_as_OutputLayer()->base()->base();
150 case Layer::Layer_NONE:
151 default:
152 throw ParseException(boost::str(
153 boost::format("Layer must have a type %1%") %
154 Layer::Layer_NONE));
155 }
156}
157
158int32_t DeserializeParser::GetBindingLayerInfo(const GraphPtr& graphPtr, unsigned int layerIndex)
159{
160 auto layerType = graphPtr->layers()->Get(layerIndex)->layer_type();
161
162 if (layerType == Layer::Layer_InputLayer)
163 {
164 return graphPtr->layers()->Get(layerIndex)->layer_as_InputLayer()->base()->layerBindingId();
165 }
166 else if ( layerType == Layer::Layer_OutputLayer )
167 {
168 return graphPtr->layers()->Get(layerIndex)->layer_as_OutputLayer()->base()->layerBindingId();
169 }
170 return 0;
171}
172
173armnn::TensorInfo ToTensorInfo(DeserializeParser::TensorRawPtr tensorPtr)
174{
175 armnn::DataType type;
176 CHECK_TENSOR_PTR(tensorPtr);
177
178 switch (tensorPtr->dataType())
179 {
180 case DataType_QuantisedAsymm8:
181 type = armnn::DataType::QuantisedAsymm8;
182 break;
183 case DataType_Float32:
184 type = armnn::DataType::Float32;
185 break;
186 case DataType_Float16:
187 type = armnn::DataType::Float16;
188 break;
189 case DataType_Boolean:
190 type = armnn::DataType::Boolean;
191 break;
192 default:
193 {
194 CheckLocation location = CHECK_LOCATION();
195 throw ParseException(
196 boost::str(
197 boost::format("Unsupported data type %1% = %2%. %3%") %
198 tensorPtr->dataType() %
199 EnumNameDataType(tensorPtr->dataType()) %
200 location.AsString()));
201 }
202 }
203 float quantizationScale = tensorPtr->quantizationScale();
204 int32_t quantizationOffset = tensorPtr->quantizationOffset();
205
206 auto dimensions = tensorPtr->dimensions();
207 unsigned int size = dimensions->size();
208 std::vector<unsigned int> outputDims(dimensions->begin(), dimensions->begin() + size);
209
210 // two statements (on purpose) for easier debugging:
211 armnn::TensorInfo result(size,
212 outputDims.data(),
213 type,
214 quantizationScale,
215 quantizationOffset);
216 return result;
217}
218
219DeserializeParser::LayerBaseRawPtrVector DeserializeParser::GetGraphInputs(const GraphPtr& graphPtr)
220{
221
222 CHECK_GRAPH(graphPtr, 0);
223 const auto& numInputs = graphPtr->inputIds()->size();
224
225 LayerBaseRawPtrVector result(numInputs);
226
227 for (unsigned int i=0; i<numInputs; ++i)
228 {
229 uint32_t inputId = CHECKED_NON_NEGATIVE(graphPtr->inputIds()->Get(i));
230 result[i] = GetBaseLayer(graphPtr, static_cast<uint32_t>(inputId));
231 }
232 return result;
233}
234
235DeserializeParser::LayerBaseRawPtrVector DeserializeParser::GetGraphOutputs(const GraphPtr& graphPtr)
236{
237 CHECK_GRAPH(graphPtr, 0);
238 const auto& numOutputs = graphPtr->outputIds()->size();
239
240 LayerBaseRawPtrVector result(numOutputs);
241
242 for (unsigned int i=0; i<numOutputs; ++i)
243 {
244 uint32_t outputId = CHECKED_NON_NEGATIVE(graphPtr->outputIds()->Get(i));
245 result[i] = GetBaseLayer(graphPtr, static_cast<uint32_t>(outputId));
246 }
247 return result;
248}
249
250DeserializeParser::TensorRawPtrVector DeserializeParser::GetInputs(const GraphPtr& graphPtr,
251 unsigned int layerIndex)
252{
253 CHECK_LAYERS(graphPtr, 0, layerIndex);
254 auto layer = GetBaseLayer(graphPtr, layerIndex);
255 const auto& numInputs = layer->inputSlots()->size();
256
257 TensorRawPtrVector result(numInputs);
258
259 for (unsigned int i=0; i<numInputs; ++i)
260 {
261 auto inputId = CHECKED_NON_NEGATIVE(static_cast<int32_t>
262 (layer->inputSlots()->Get(i)->connection()->sourceLayerIndex()));
263 result[i] = GetBaseLayer(graphPtr, inputId)->outputSlots()->Get(0)->tensorInfo();
264 }
265 return result;
266}
267
268DeserializeParser::TensorRawPtrVector DeserializeParser::GetOutputs(const GraphPtr& graphPtr,
269 unsigned int layerIndex)
270{
271 CHECK_LAYERS(graphPtr, 0, layerIndex);
272 auto layer = GetBaseLayer(graphPtr, layerIndex);
273 const auto& numOutputs = layer->outputSlots()->size();
274
275 TensorRawPtrVector result(numOutputs);
276
277 for (unsigned int i=0; i<numOutputs; ++i)
278 {
279 result[i] = layer->outputSlots()->Get(i)->tensorInfo();
280 }
281 return result;
282}
283
284void DeserializeParser::ParseUnsupportedLayer(unsigned int layerIndex)
285{
286 CHECK_LAYERS(m_Graph, 0, layerIndex);
287 const auto layerName = GetBaseLayer(m_Graph, layerIndex)->layerName()->c_str();
288 throw ParseException(
289 boost::str(
290 boost::format("Layer not supported. "
291 "layerIndex: %1% "
292 "layerName: %2% / %3%") %
293 layerIndex %
294 layerName %
295 CHECK_LOCATION().AsString()));
296}
297
298void DeserializeParser::ResetParser()
299{
300 m_Network = armnn::INetworkPtr(nullptr, nullptr);
301 m_Graph = nullptr;
302}
303
304IDeserializeParser* IDeserializeParser::CreateRaw()
305{
306 return new DeserializeParser();
307}
308
309IDeserializeParserPtr IDeserializeParser::Create()
310{
311 return IDeserializeParserPtr(CreateRaw(), &IDeserializeParser::Destroy);
312}
313
314void IDeserializeParser::Destroy(IDeserializeParser* parser)
315{
316 delete parser;
317}
318
319INetworkPtr DeserializeParser::CreateNetworkFromBinaryFile(const char* graphFile)
320{
321 ResetParser();
322 m_Graph = LoadGraphFromFile(graphFile);
323 return CreateNetworkFromGraph();
324}
325
326INetworkPtr DeserializeParser::CreateNetworkFromBinary(const std::vector<uint8_t>& binaryContent)
327{
328 ResetParser();
329 m_Graph = LoadGraphFromBinary(binaryContent.data(), binaryContent.size());
330 return CreateNetworkFromGraph();
331}
332
333DeserializeParser::GraphPtr DeserializeParser::LoadGraphFromFile(const char* fileName)
334{
335 if (fileName == nullptr)
336 {
337 throw InvalidArgumentException(boost::str(boost::format("Invalid (null) file name %1%") %
338 CHECK_LOCATION().AsString()));
339 }
340 boost::system::error_code errorCode;
341 boost::filesystem::path pathToFile(fileName);
342 if (!boost::filesystem::exists(pathToFile, errorCode))
343 {
344 throw FileNotFoundException(boost::str(boost::format("Cannot find the file (%1%) errorCode: %2% %3%") %
345 fileName %
346 errorCode %
347 CHECK_LOCATION().AsString()));
348 }
349 std::ifstream file(fileName, std::ios::binary);
350 std::string fileContent((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
351 return LoadGraphFromBinary(reinterpret_cast<const uint8_t*>(fileContent.c_str()), fileContent.size());
352}
353
354DeserializeParser::GraphPtr DeserializeParser::LoadGraphFromBinary(const uint8_t* binaryContent, size_t len)
355{
356 if (binaryContent == nullptr)
357 {
358 throw InvalidArgumentException(boost::str(boost::format("Invalid (null) binary content %1%") %
359 CHECK_LOCATION().AsString()));
360 }
361 flatbuffers::Verifier verifier(binaryContent, len);
362 if (verifier.VerifyBuffer<SerializedGraph>() == false)
363 {
364 throw ParseException(
365 boost::str(boost::format("Buffer doesn't conform to the expected Armnn "
366 "flatbuffers format. size:%1% %2%") %
367 len %
368 CHECK_LOCATION().AsString()));
369 }
370 return GetSerializedGraph(binaryContent);
371}
372
373INetworkPtr DeserializeParser::CreateNetworkFromGraph()
374{
375 m_Network = INetwork::Create();
376 BOOST_ASSERT(m_Graph != nullptr);
377 unsigned int layerIndex = 0;
378 m_GraphConnections.emplace_back(m_Graph->layers()->size());
379 for (AnyLayer const* layer : *m_Graph->layers())
380 {
381 if (layer->layer_type() != Layer_InputLayer &&
382 layer->layer_type() != Layer_OutputLayer)
383 {
384 // lookup and call the parser function
385 auto& parserFunction = m_ParserFunctions[layer->layer_type()];
386 (this->*parserFunction)(layerIndex);
387 }
388 ++layerIndex;
389 }
390
391 SetupInputLayers();
392 SetupOutputLayers();
393
394 // establish the connections from the layer outputs to the inputs of the subsequent layers
395 for (size_t connectionIndex = 0; connectionIndex < m_GraphConnections[0].size(); ++connectionIndex)
396 {
397 if (m_GraphConnections[0][connectionIndex].outputSlot != nullptr)
398 {
399 for (size_t inputSlotIdx = 0;
400 inputSlotIdx < m_GraphConnections[0][connectionIndex].inputSlots.size();
401 ++inputSlotIdx)
402 {
403 m_GraphConnections[0][connectionIndex].outputSlot->Connect(
404 *(m_GraphConnections[0][connectionIndex].inputSlots[inputSlotIdx]));
405 }
406 }
407 }
408
409 return std::move(m_Network);
410}
411
412BindingPointInfo DeserializeParser::GetNetworkInputBindingInfo(unsigned int layerIndex,
413 const std::string& name) const
414{
415 CHECK_LAYERS(m_Graph, 0, layerIndex);
416 auto inputs = GetGraphInputs(m_Graph);
417
418 for (auto const& input : inputs)
419 {
420 if (input->layerName()->c_str() == name)
421 {
422 int bindingId = reinterpret_cast<armnn::LayerBindingId>(GetBindingLayerInfo(m_Graph, input->index()));
423 auto layerBase = GetBaseLayer(m_Graph,input->index())->outputSlots()->Get(layerIndex);
424 return std::make_pair(bindingId, ToTensorInfo(layerBase->tensorInfo()));
425 }
426 }
427 throw ParseException(
428 boost::str(
429 boost::format("No input binding found for layer:%1% / %2%") %
430 name %
431 CHECK_LOCATION().AsString()));
432}
433
434BindingPointInfo DeserializeParser::GetNetworkOutputBindingInfo(unsigned int layerIndex,
435 const std::string& name) const
436{
437 CHECK_LAYERS(m_Graph, 0, layerIndex);
438 auto outputs = GetGraphOutputs(m_Graph);
439
440 for (auto const& output : outputs)
441 {
442 if (output->layerName()->c_str() == name)
443 {
444 int bindingId = reinterpret_cast<armnn::LayerBindingId>(GetBindingLayerInfo(m_Graph, output->index()));
445 auto layer = GetBaseLayer(m_Graph, output->index());
446 auto sourceLayerIndex = layer->inputSlots()->Get(0)->connection()->sourceLayerIndex();
447 auto sourceLayer = GetBaseLayer(m_Graph, sourceLayerIndex);
448 return std::make_pair(bindingId, ToTensorInfo(sourceLayer->outputSlots()->Get(0)->tensorInfo()));
449 }
450 }
451 throw ParseException(
452 boost::str(
453 boost::format("No output binding found for layer:%1% / %2%") %
454 name %
455 CHECK_LOCATION().AsString()));
456}
457
458void DeserializeParser::SetupInputLayers()
459{
460 CHECK_GRAPH(m_Graph, 0);
461 auto inputs = GetGraphInputs(m_Graph);
462 for (auto const& input : inputs)
463 {
464 IConnectableLayer* layer =
465 m_Network->AddInputLayer(static_cast<int>(input->index()), input->layerName()->c_str());
466
467 auto tensorInfo = ToTensorInfo(input->outputSlots()->Get(0)->tensorInfo());
468 layer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
469
470 RegisterOutputSlots(input->index(), layer);
471 }
472}
473
474void DeserializeParser::SetupOutputLayers()
475{
476 CHECK_GRAPH(m_Graph, 0);
477 auto outputs = GetGraphOutputs(m_Graph);
478 for (auto const& output : outputs)
479 {
480 IConnectableLayer* layer =
481 m_Network->AddOutputLayer(static_cast<int>(output->index()), output->layerName()->c_str());
482
483 RegisterInputSlots(output->index(), layer);
484 }
485}
486
487void DeserializeParser::RegisterOutputSlots(uint32_t layerIndex,
488 IConnectableLayer* layer)
489{
490 CHECK_LAYERS(m_Graph, 0, layerIndex);
491 BOOST_ASSERT(layer != nullptr);
492 auto parsedLayer = GetBaseLayer(m_Graph, layerIndex);
493 if (parsedLayer->outputSlots()->size() != layer->GetNumOutputSlots())
494 {
495 throw ParseException(
496 boost::str(boost::format("The number of outputslots (%1%) does not match the number expected (%2%)"
497 " for layer index: %3% %4%") %
498 parsedLayer->outputSlots()->size() %
499 layer->GetNumOutputSlots() %
500 layerIndex %
501 CHECK_LOCATION().AsString()));
502 }
503
504 for (unsigned int slotIndex = 0; slotIndex < layer->GetNumOutputSlots(); ++slotIndex)
505 {
506 armnn::IOutputSlot* slot = &(layer->GetOutputSlot(slotIndex));
507 RegisterOutputSlotOfConnection(layerIndex, slot);
508 }
509}
510
511void DeserializeParser::RegisterInputSlots(uint32_t layerIndex,
512 armnn::IConnectableLayer* layer)
513{
514 CHECK_LAYERS(m_Graph, 0, layerIndex);
515 BOOST_ASSERT(layer != nullptr);
516 auto parsedLayer = GetBaseLayer(m_Graph, layerIndex);
517 if (parsedLayer->inputSlots()->size() != layer->GetNumInputSlots())
518 {
519 throw ParseException(
520 boost::str(boost::format("The number of inputslots (%1%) does not match the number expected (%2%)"
521 " for layer index:%3% %4%") %
522 parsedLayer->inputSlots()->size() %
523 layer->GetNumInputSlots() %
524 layerIndex %
525 CHECK_LOCATION().AsString()));
526 }
527
528 for (unsigned int slotIndex = 0; slotIndex < layer->GetNumInputSlots(); ++slotIndex)
529 {
530 armnn::IInputSlot* slot = &(layer->GetInputSlot(slotIndex));
531 uint32_t sourceLayerIndex = parsedLayer->inputSlots()->Get(slotIndex)->connection()->sourceLayerIndex();
532 RegisterInputSlotOfConnection(sourceLayerIndex, slot);
533 }
534}
535
536void DeserializeParser::RegisterInputSlotOfConnection(uint32_t connectionIndex,
537 armnn::IInputSlot* slot)
538{
539 BOOST_ASSERT(m_GraphConnections[0].size() > connectionIndex);
540
541 Slots& slots = m_GraphConnections[0][connectionIndex];
542 slots.inputSlots.push_back(slot);
543}
544
545void DeserializeParser::RegisterOutputSlotOfConnection(uint32_t connectionIndex,
546 armnn::IOutputSlot* slot)
547{
548 BOOST_ASSERT(m_GraphConnections[0].size() > connectionIndex);
549
550 Slots& slots = m_GraphConnections[0][connectionIndex];
551
552 // assuming there is only one producer for that tensor
553 if (slots.outputSlot != nullptr)
554 {
555 throw ParseException(boost::str(
556 boost::format("Another layer has already registered itself as the producer of "
557 "connection:%1% / %2%") %
558 connectionIndex %
559 CHECK_LOCATION().AsString()));
560 }
561
562 slots.outputSlot = slot;
563}
564
565void DeserializeParser::ParseAdd(unsigned int layerIndex)
566{
567 CHECK_LAYERS(m_Graph, 0, layerIndex);
568 auto inputs = GetInputs(m_Graph, layerIndex);
569 CHECK_LOCATION();
570 CHECK_VALID_SIZE(inputs.size(), 2);
571
572 auto outputs = GetOutputs(m_Graph, layerIndex);
573 CHECK_VALID_SIZE(outputs.size(), 1);
574
575 auto layerName = boost::str(boost::format("Addition:%1%") % layerIndex);
576 IConnectableLayer* layer = m_Network->AddAdditionLayer(layerName.c_str());
577
578 armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
579 layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
580
581 RegisterInputSlots(layerIndex, layer);
582 RegisterOutputSlots(layerIndex, layer);
583}
584
585}
586
587