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.
std::map< std::string, armnn::TensorShape > m_InputShapes
void TrackOutputBinding(armnn::IConnectableLayer *layer, armnn::LayerBindingId id, const armnn::TensorInfo &tensorInfo)
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).
std::unordered_map< std::string, BindingPointInfo > m_NetworkOutputsBindingInfo
maps output layer names to their corresponding ids and tensor infos
armnn::IOutputSlot & GetArmnnOutputSlotForCaffeTop(const std::string &caffeTopName) const
Retrieves the Armnn IOutputSlot representing the given Caffe top.
RecordByRecordCaffeParser()
An output connection slot for a layer.
static const std::map< std::string, OperationParsingFunction > ms_CaffeLayerNameToParsingFunctions
Maps Caffe layer names to parsing member functions.
std::unordered_map< std::string, BindingPointInfo > m_NetworkInputsBindingInfo
maps input layer names to their corresponding ids and tensor infos
void ResolveInPlaceLayers(caffe::NetParameter &netParameter)
Modifies the Caffe network to replace "in-place" layers (whose top() and bottom() are both the same) ...
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)
armnn::INetworkPtr m_Network
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