15 #include <google/protobuf/wire_format.h> 31 VarLenDataInfo(std::streamoff positionOfData,
size_t sizeOfData) :
32 m_PositionOfData(positionOfData), m_SizeOfData(sizeOfData) {}
34 VarLenDataInfo(
const VarLenDataInfo& x) :
35 m_PositionOfData(x.PositionOfData()), m_SizeOfData (x.SizeOfData()) {}
37 VarLenDataInfo& operator=(
const VarLenDataInfo& x)
43 m_PositionOfData = x.PositionOfData(); m_SizeOfData = x.SizeOfData();
return *
this;
46 std::streamoff PositionOfData()
const {
return m_PositionOfData;}
47 size_t SizeOfData()
const {
return m_SizeOfData;}
50 std::streamoff m_PositionOfData;
60 class LayerParameterInfo :
public VarLenDataInfo
63 static const std::string INPUT;
64 LayerParameterInfo(
const VarLenDataInfo& varLenDataInfo) :
65 VarLenDataInfo(varLenDataInfo.PositionOfData(), varLenDataInfo.SizeOfData()),
68 LayerParameterInfo(std::streamoff positionOfData,
size_t sizeOfData) :
69 VarLenDataInfo(positionOfData, sizeOfData), m_newTops(
false), m_newBottoms(
false) {}
71 LayerParameterInfo(
const LayerParameterInfo& x) :
72 VarLenDataInfo(x.PositionOfData(), x.SizeOfData()),
76 m_bottoms(x.m_bottoms),
77 m_newTops(x.m_newTops),
78 m_newBottoms(x.m_newBottoms) {}
80 LayerParameterInfo& operator=(
const LayerParameterInfo& x)
85 VarLenDataInfo::operator=(x);
89 m_bottoms = x.m_bottoms;
90 m_newTops = x.m_newTops;
91 m_newBottoms = x.m_newBottoms;
95 const std::string name()
const {
return m_name;}
96 void set_name(
const std::unique_ptr<
char[]>& theName,
size_t length)
98 m_name = std::string(theName.get(), length);
100 void set_name(
const std::string& theName) {m_name = theName;}
102 const std::string type()
const {
return m_type;}
103 void set_type(
const std::unique_ptr<
char[]>& theType,
size_t length)
105 m_type = std::string(theType.get(), length);
107 void set_type(
const std::string& theType) {m_type = theType;}
109 void add_top(
const std::unique_ptr<
char[]>& top,
size_t length)
111 std::string topName(top.get(), length);
112 m_tops.push_back(topName);
114 void add_top(
const std::string& topName)
116 m_tops.push_back(topName);
118 const std::string top(
unsigned long i)
const {
return m_tops[i];}
119 unsigned long top_size()
const {
return m_tops.size();}
120 void set_top(
unsigned long i,
const std::string& newName) {m_tops[i] = newName; m_newTops =
true;}
121 bool new_tops()
const {
return m_newTops;}
123 void add_bottom(
const std::unique_ptr<
char[]>& bottom,
size_t length)
125 std::string bottomName(bottom.get(), length);
126 m_bottoms.push_back(bottomName);
128 unsigned long bottom_size()
const {
return m_bottoms.size();}
129 const std::string bottom(
unsigned long i)
const {
return m_bottoms[i];}
130 void set_bottom(
unsigned long i,
const std::string& newName) {m_bottoms[i] = newName; m_newBottoms =
true;}
131 bool new_bottoms()
const {
return m_newBottoms;}
135 bool isImplicitInputLayer()
const 137 if ((PositionOfData() == 0) && (SizeOfData() == 0) && INPUT.compare(type()) == 0)
138 {
return true;}
else {
return false;}
144 std::vector<std::string> m_tops;
145 std::vector<std::string> m_bottoms;
157 class ProtobufFieldInfo
160 ProtobufFieldInfo(
int field_type,
int field_id) :
161 m_eof(
false), m_field_type(field_type), m_field_id(field_id) {}
162 ProtobufFieldInfo() : m_eof(
true), m_field_type(0), m_field_id(0) {}
164 bool eof() {
return m_eof;}
165 int field_type() {
return m_field_type;}
166 int field_id() {
return m_field_id;}
180 class NetParameterInfo
183 const std::string name()
const {
return m_name;}
184 void set_name(
const std::unique_ptr<
char[]>& theName,
size_t length)
186 m_name = std::string(theName.get(), length);
189 void add_input(
const std::unique_ptr<
char[]>& input,
size_t length)
191 std::string inputName(input.get(), length);
192 m_inputs.push_back(inputName);
194 const std::string input(
unsigned long i)
const {
return m_inputs[i];}
195 unsigned long input_size()
const {
return m_inputs.size();}
197 void add_input_dimension(
int input_dimension) {
198 m_input_dimensions.push_back(input_dimension);
200 int input_dimension(
unsigned long i)
const {
return m_input_dimensions[i];}
201 unsigned long input_dimensions_size()
const {
return m_input_dimensions.size();}
203 void add_blob_shape(caffe::BlobShape shape) {
204 m_blob_shapes.push_back(shape);
206 const caffe::BlobShape blob_shape(
unsigned long i)
const {
return m_blob_shapes[i];}
207 unsigned long blob_shapes_size()
const {
return m_blob_shapes.size();}
211 std::vector<std::string> m_inputs;
212 std::vector<int> m_input_dimensions;
213 std::vector<caffe::BlobShape> m_blob_shapes;
222 const std::string LayerParameterInfo::INPUT =
"Input";
227 ProtobufFieldInfo readFieldInfo(std::ifstream& ifs)
229 unsigned char first_byte =
static_cast<unsigned char>(ifs.get());
232 ProtobufFieldInfo eof;
235 int field_type = first_byte&7;
236 int field_id = first_byte>>3;
237 if ((field_id & 16) == 16)
239 unsigned char second_byte =
static_cast<unsigned char>(ifs.get());
242 ProtobufFieldInfo eof;
245 field_id = (field_id-16) + ((second_byte&127)<<4);
247 ProtobufFieldInfo fieldInfo(field_type, field_id);
251 const static int MAX_NUM_BYTES = 5;
253 int ReadBase128(std::ifstream& ifs)
256 unsigned int shift_by = 0;
260 unsigned char a_byte =
static_cast<unsigned char>(ifs.get());
262 if (bytesRead > MAX_NUM_BYTES)
265 "ReadBase128 exceeded the maximum number of bytes expected for an integer representation");
267 result += (a_byte & 127) << shift_by;
269 if ((a_byte & 128) != 128)
278 std::unique_ptr<char[]> AllocateBuffer(std::ifstream& ifs, VarLenDataInfo& dataInfo)
280 std::unique_ptr<char[]> ptr(
new char[dataInfo.SizeOfData()]);
282 ifs.seekg(dataInfo.PositionOfData(), std::ios_base::beg);
287 VarLenDataInfo CreateVarLenDataInfo(std::streamoff bufferStart, std::streamoff endOfLayer) {
288 std::streamoff sizeOfLayer = endOfLayer - bufferStart;
291 std::stringstream ss;
292 ss <<
"error when determining buffer size, negative value [" << sizeOfLayer <<
"]";
300 if (armnn::numeric_cast<size_t>(sizeOfLayer) > SIZE_MAX) {
301 std::stringstream ss;
302 ss <<
"layer is greater than " << SIZE_MAX <<
" in size cannot process. layer size = [" << sizeOfLayer <<
"]";
305 LayerParameterInfo
info(bufferStart, armnn::numeric_cast<size_t>(sizeOfLayer));
309 void ReadTopologicalInfoForLayerParameter(LayerParameterInfo& layerInfo, std::ifstream& ifs)
313 ifs.seekg(layerInfo.PositionOfData(), std::ios_base::beg);
314 std::streamoff endOfLayer = layerInfo.PositionOfData() +
319 std::streamoff currentPosition = ifs.tellg();
320 if (currentPosition >= endOfLayer) {
324 ProtobufFieldInfo fieldInfo = readFieldInfo(ifs);
332 switch (fieldInfo.field_type())
341 int size = ReadBase128(ifs);
342 std::streamoff posStartOfData = ifs.tellg();
343 VarLenDataInfo dataInfo(posStartOfData, armnn::numeric_cast<size_t>(size));
348 if (fieldInfo.field_id() == 1)
351 auto layerName = AllocateBuffer(ifs, dataInfo);
352 layerInfo.set_name(layerName, dataInfo.SizeOfData());
354 else if (fieldInfo.field_id() == 2)
357 auto layerType = AllocateBuffer(ifs, dataInfo);
358 layerInfo.set_type(layerType, dataInfo.SizeOfData());
360 else if (fieldInfo.field_id() == 3)
363 auto bottom = AllocateBuffer(ifs, dataInfo);
364 layerInfo.add_bottom(bottom, dataInfo.SizeOfData());
366 else if (fieldInfo.field_id() == 4)
369 auto top = AllocateBuffer(ifs, dataInfo);
370 layerInfo.add_top(top, dataInfo.SizeOfData());
374 ifs.seekg(size, std::ios_base::cur);
387 ifs.seekg(8, std::ios_base::cur);
399 ifs.seekg(4, std::ios_base::cur);
416 void ResolveInPlaceLayers(std::vector<LayerParameterInfo>& layerInfo)
418 std::map<std::string, std::vector<LayerParameterInfo*>> layersByTop;
419 for (
auto& info : layerInfo)
421 for (
unsigned long i = 0; i <
info.top_size(); ++i)
423 layersByTop[
info.top(i)].push_back(&info);
428 for (
auto& layersWithSameTopIterator : layersByTop)
430 const std::string& top = layersWithSameTopIterator.first;
431 const std::vector<LayerParameterInfo*> layersWithSameTop = layersWithSameTopIterator.second;
435 for (
unsigned int layerIdx = 0; layerIdx < layersWithSameTop.size() - 1; ++layerIdx)
437 LayerParameterInfo* layer1 = layersWithSameTop[layerIdx];
438 LayerParameterInfo* layer2 = layersWithSameTop[layerIdx + 1];
439 if (layer1->top_size() != 1)
442 "doesn't have exactly one top.");
444 std::string newTop = layer1->name() +
"_top";
445 layer1->set_top(0, newTop);
446 if (layer2->bottom_size() != 1 || layer2->bottom(0) != top)
449 " doesn't have exactly one bottom, or it doesn't match its top.");
451 layer2->set_bottom(0, newTop);
463 const char* graphFile,
464 const std::map<std::string, armnn::TensorShape>& inputShapes,
465 const std::vector<std::string>& requestedOutputs)
469 if (requestedOutputs.size() == 0)
473 m_RequestedOutputs = requestedOutputs;
475 std::ifstream ifs(graphFile, std::ifstream::in|std::ifstream::binary);
481 std::vector<LayerParameterInfo> layerInfo;
482 NetParameterInfo netParameterInfo;
485 ProtobufFieldInfo fieldInfo = readFieldInfo(ifs);
490 switch(fieldInfo.field_type())
519 int size = ReadBase128(ifs);
520 std::streamoff posStartOfData = ifs.tellg();
521 ifs.seekg(size, std::ios_base::cur);
526 std::streamoff endOfLayer = ifs.tellg();
527 if (fieldInfo.field_id() == 1)
529 VarLenDataInfo dataInfo = CreateVarLenDataInfo(posStartOfData, endOfLayer);
530 auto graphName = AllocateBuffer(ifs, dataInfo);
531 netParameterInfo.set_name(graphName, dataInfo.SizeOfData());
533 if (fieldInfo.field_id() == 3)
535 VarLenDataInfo dataInfo = CreateVarLenDataInfo(posStartOfData, endOfLayer);
536 auto inputName = AllocateBuffer(ifs, dataInfo);
537 netParameterInfo.add_input(inputName, dataInfo.SizeOfData());
539 if (fieldInfo.field_id() == 8)
541 VarLenDataInfo dataInfo = CreateVarLenDataInfo(posStartOfData, endOfLayer);
542 auto inputShape = AllocateBuffer(ifs, dataInfo);
543 caffe::BlobShape blobShape;
544 bool bRet = blobShape.ParseFromArray(inputShape.get(),
static_cast<int>(dataInfo.SizeOfData()));
549 netParameterInfo.add_blob_shape(blobShape);
551 if (fieldInfo.field_id() == 4)
553 int input_dim = ReadBase128(ifs);
554 netParameterInfo.add_input_dimension(input_dim);
556 if (fieldInfo.field_id() == 100)
558 LayerParameterInfo
info(CreateVarLenDataInfo(posStartOfData, endOfLayer));
559 ReadTopologicalInfoForLayerParameter(info, ifs);
560 layerInfo.push_back(info);
570 std::vector<const LayerParameterInfo*> sortedNodes;
571 ProcessLayers(netParameterInfo, layerInfo, m_RequestedOutputs, sortedNodes);
577 void RecordByRecordCaffeParser::ProcessLayers(
578 const NetParameterInfo& netParameterInfo,
579 std::vector<LayerParameterInfo>& layerInfo,
580 const std::vector<std::string>& m_RequestedOutputs,
581 std::vector<const LayerParameterInfo*>& sortedNodes)
584 if (netParameterInfo.input_size() > 0)
586 LayerParameterInfo implicitInputLayer(0, 0);
587 implicitInputLayer.set_type(LayerParameterInfo::INPUT);
588 implicitInputLayer.set_name(netParameterInfo.input(0));
589 implicitInputLayer.add_top(netParameterInfo.input(0));
590 layerInfo.push_back(implicitInputLayer);
594 for (LayerParameterInfo&
info : layerInfo)
596 for (
unsigned long i = 0; i <
info.top_size(); ++i)
598 m_CaffeLayersByTopName[
info.top(i)] = &
info;
603 std::vector<const LayerParameterInfo*> targetLayers;
604 for (
const std::string& requestedOutputName : m_RequestedOutputs)
606 auto nodeIt = m_CaffeLayersByTopName.find(requestedOutputName);
607 if (nodeIt == m_CaffeLayersByTopName.end())
610 "Couldn't find requested output layer '" + requestedOutputName +
"' in graph");
612 targetLayers.push_back(nodeIt->second);
616 if (!armnnUtils::GraphTopologicalSort<const LayerParameterInfo*>(
618 [
this](
const LayerParameterInfo* node)
620 return GetInputs(*node);
629 std::vector<const LayerParameterInfo*> RecordByRecordCaffeParser::GetInputs(
630 const LayerParameterInfo& layerParam)
632 std::vector<const LayerParameterInfo*> ret;
633 ret.reserve(layerParam.bottom_size());
634 for (
unsigned long j = 0; j < layerParam.bottom_size(); ++j)
636 std::string inputName = layerParam.bottom(j);
637 auto inputIt = m_CaffeLayersByTopName.find(inputName);
638 if (inputIt == m_CaffeLayersByTopName.end())
641 "Can't find Caffe layer with top called '" + inputName +
"', which is listed as an input of '" +
642 layerParam.name() +
"'");
644 ret.push_back(inputIt->second);
651 std::vector<const LayerParameterInfo *>& sortedNodes,
652 const NetParameterInfo& netParameterInfo)
660 for (
auto info : sortedNodes)
662 caffe::LayerParameter layer;
663 if (
info->isImplicitInputLayer())
667 layer.set_type(LayerParameterInfo::INPUT);
668 layer.set_name(netParameterInfo.input(0));
669 layer.add_top(netParameterInfo.input(0));
671 caffe::InputParameter* inputParam = layer.mutable_input_param();
672 caffe::BlobShape* shape = inputParam->add_shape();
674 long unsigned int dim_size = netParameterInfo.input_dimensions_size();
675 for (
long unsigned int i = 0; i < dim_size; ++i)
677 shape->add_dim(netParameterInfo.input_dimension(i));
682 char *buffer =
new char[
info->SizeOfData()];
684 ifs.seekg(
info->PositionOfData(), std::ios_base::beg);
685 ifs.read(buffer, armnn::numeric_cast<std::streamsize>(
info->SizeOfData()));
686 bool bRet = layer.ParseFromArray(buffer, static_cast<int>(
info->SizeOfData()));
694 if (
info->new_tops())
697 layer.set_top(0,
info->top(0));
699 if (
info->new_bottoms())
702 layer.set_bottom(0,
info->bottom(0));
710 auto func = it->second;
711 (this->*func)(layer);
716 for (
const std::string& requestedOutput : m_RequestedOutputs)
723 outputSlot.
Connect(outputLayer->GetInputSlot(0));
725 TrackOutputBinding(outputLayer, outputId, outputLayer->GetInputSlot(0).GetConnection()->GetTensorInfo());
Interface for a layer that is connectable to other layers via InputSlots and OutputSlots.
armnn::IOutputSlot & GetArmnnOutputSlotForCaffeTop(const std::string &caffeTopName) const
Retrieves the Armnn IOutputSlot representing the given Caffe top.
static const std::map< std::string, OperationParsingFunction > ms_CaffeLayerNameToParsingFunctions
Maps Caffe layer names to parsing member functions.
Caffe networks are loaded from protobuf files (binary or text) using the protobuf library and the gen...
int LayerBindingId
Type of identifiers for bindable layers (inputs, outputs).
void TrackOutputBinding(armnn::IConnectableLayer *layer, armnn::LayerBindingId id, const armnn::TensorInfo &tensorInfo)
void ResolveInPlaceLayers(caffe::NetParameter &netParameter)
Modifies the Caffe network to replace "in-place" layers (whose top() and bottom() are both the same) ...
RecordByRecordCaffeParser()
An output connection slot for a layer.
std::unordered_map< std::string, BindingPointInfo > m_NetworkInputsBindingInfo
maps input layer names to their corresponding ids and tensor infos
std::unordered_map< std::string, BindingPointInfo > m_NetworkOutputsBindingInfo
maps output layer names to their corresponding ids and tensor infos
std::map< std::string, armnn::TensorShape > m_InputShapes
virtual armnn::INetworkPtr CreateNetworkFromBinaryFile(const char *graphFile, const std::map< std::string, armnn::TensorShape > &inputShapes, const std::vector< std::string > &requestedOutputs) override
Create the network from a protobuf binary file on disk.
std::enable_if_t< std::is_unsigned< Source >::value &&std::is_unsigned< Dest >::value, Dest > numeric_cast(Source source)
std::unique_ptr< INetwork, void(*)(INetwork *network)> INetworkPtr
virtual int Connect(IInputSlot &destination)=0
static INetworkPtr Create(NetworkOptions networkOptions={})
DataLayout::NCHW DataLayout::NCHW DataLayout::NHWC DataLayout::NHWC true
armnn::INetworkPtr m_Network