1 // 2 // Copyright © 2017 Arm Ltd. All rights reserved. 3 // SPDX-License-Identifier: MIT 4 // 5 #pragma once 6 #include "armnnCaffeParser/ICaffeParser.hpp" 7 8 #include "armnn/Types.hpp" 9 #include "armnn/NetworkFwd.hpp" 10 #include "armnn/Tensor.hpp" 11 12 #include <memory> 13 #include <vector> 14 #include <unordered_map> 15 16 namespace caffe 17 { 18 class BlobShape; 19 class LayerParameter; 20 class NetParameter; 21 } 22 23 namespace armnnCaffeParser 24 { 25 26 class CaffeParserBase: public ICaffeParser 27 { 28 public: 29 30 // Because we haven't looked at reducing the memory usage when loading from Text/String 31 // have to retain these functions here for the moment. 32 /// Create the network from a protobuf text file on disk 33 virtual armnn::INetworkPtr CreateNetworkFromTextFile( 34 const char* graphFile, 35 const std::map<std::string, armnn::TensorShape>& inputShapes, 36 const std::vector<std::string>& requestedOutputs) override; 37 38 39 /// Creates the network directly from protobuf text in a string. Useful for debugging/testing. 40 virtual armnn::INetworkPtr CreateNetworkFromString( 41 const char* protoText, 42 const std::map<std::string, armnn::TensorShape>& inputShapes, 43 const std::vector<std::string>& requestedOutputs) override; 44 45 /// Retrieves binding info (layer id and tensor info) for the network input identified by the given layer name. 46 virtual BindingPointInfo GetNetworkInputBindingInfo(const std::string& name) const override; 47 48 /// Retrieves binding info (layer id and tensor info) for the network output identified by the given layer name. 49 virtual BindingPointInfo GetNetworkOutputBindingInfo(const std::string& name) const override; 50 51 CaffeParserBase(); 52 53 protected: 54 /// Adds an armnn layer to m_Network given a Caffe LayerParameter of the correct type 55 /// and is responsible for recording any newly created IOutputSlots using SetArmnnOutputSlotForCaffeTop(). 56 /// @{ 57 void ParseInputLayer(const caffe::LayerParameter& layerParam); 58 void ParseConvLayer(const caffe::LayerParameter& layerParam); 59 void ParsePoolingLayer(const caffe::LayerParameter& layerParam); 60 void ParseReluLayer(const caffe::LayerParameter& layerParam); 61 void ParseLRNLayer(const caffe::LayerParameter& layerParam); 62 void ParseInnerProductLayer(const caffe::LayerParameter& layerParam); 63 void ParseSoftmaxLayer(const caffe::LayerParameter& layerParam); 64 void ParseEltwiseLayer(const caffe::LayerParameter& layerParam); 65 void ParseConcatLayer(const caffe::LayerParameter& layerParam); 66 void ParseBatchNormLayer(const caffe::LayerParameter& layerParam); 67 void ParseScaleLayer(const caffe::LayerParameter& layerParam); 68 void ParseSplitLayer(const caffe::LayerParameter& layerParam); 69 void ParseDropoutLayer(const caffe::LayerParameter& layerParam); 70 /// @} 71 72 /// ParseConv may use these helpers depending on the group parameter 73 /// @{ 74 void AddConvLayerWithSplits(const caffe::LayerParameter& layerParam, 75 const armnn::Convolution2dDescriptor & desc, 76 unsigned int kernelW, 77 unsigned int kernelH); 78 void AddConvLayerWithDepthwiseConv(const caffe::LayerParameter& layerParam, 79 const armnn::Convolution2dDescriptor & desc, 80 unsigned int kernelW, 81 unsigned int kernelH); 82 /// @} 83 84 /// Converts Caffe's protobuf tensor shape format to ArmNN's 85 armnn::TensorInfo BlobShapeToTensorInfo(const caffe::BlobShape& blobShape) const; 86 87 void TrackInputBinding(armnn::IConnectableLayer* layer, 88 armnn::LayerBindingId id, 89 const armnn::TensorInfo& tensorInfo); 90 91 static void TrackBindingPoint(armnn::IConnectableLayer* layer, armnn::LayerBindingId id, 92 const armnn::TensorInfo& tensorInfo, 93 const char* bindingPointDesc, 94 std::unordered_map<std::string, BindingPointInfo>& nameToBindingInfo); 95 96 void TrackOutputBinding(armnn::IConnectableLayer* layer, 97 armnn::LayerBindingId id, 98 const armnn::TensorInfo& tensorInfo); 99 100 101 void SetArmnnOutputSlotForCaffeTop(const std::string& caffeTopName, armnn::IOutputSlot& armnnOutputSlot); 102 103 /// Retrieves the Armnn IOutputSlot representing the given Caffe top. 104 /// Throws if it cannot be found (e.g. not parsed yet). 105 armnn::IOutputSlot& GetArmnnOutputSlotForCaffeTop(const std::string& caffeTopName) const; 106 107 static std::pair<armnn::LayerBindingId, armnn::TensorInfo> GetBindingInfo( 108 const std::string& layerName, 109 const char* bindingPointDesc, 110 const std::unordered_map<std::string, BindingPointInfo>& bindingInfos); 111 112 113 void Cleanup(); 114 115 using OperationParsingFunction = void(CaffeParserBase::*)(const caffe::LayerParameter& layerParam); 116 117 /// Maps Caffe layer names to parsing member functions. 118 static const std::map<std::string, OperationParsingFunction> ms_CaffeLayerNameToParsingFunctions; 119 120 /// maps input layer names to their corresponding ids and tensor infos 121 std::unordered_map<std::string, BindingPointInfo> m_NetworkInputsBindingInfo; 122 123 /// maps output layer names to their corresponding ids and tensor infos 124 std::unordered_map<std::string, BindingPointInfo> m_NetworkOutputsBindingInfo; 125 126 armnn::INetworkPtr m_Network; 127 128 std::map<std::string, armnn::TensorShape> m_InputShapes; 129 130 /// As we add armnn layers we store the armnn IOutputSlot which corresponds to the Caffe tops. 131 std::unordered_map<std::string, armnn::IOutputSlot*> m_ArmnnOutputSlotForCaffeTop; 132 133 std::vector<std::string> m_RequestedOutputs; 134 135 136 // Stuff which has gone to base class simply because we haven't done any 137 // memory optimisation on the text/string format. If we move this to a layer 138 // by layer parse as well these can move to the CaffeParser class. 139 std::map<std::string, const caffe::LayerParameter*> m_CaffeLayersByTopName; 140 141 /// Parses a NetParameter loaded into memory from one of the other CreateNetwork* 142 armnn::INetworkPtr CreateNetworkFromNetParameter( 143 caffe::NetParameter& netParam, 144 const std::map<std::string, armnn::TensorShape>& inputShapes, 145 const std::vector<std::string>& requestedOutputs); 146 147 /// does the actual conversion from caffe::NetParameter to armnn::INetwork 148 void LoadNetParam(caffe::NetParameter& netParameter); 149 150 /// Find the Caffe layers listed as inputs (bottoms) for a given layer. 151 std::vector<const caffe::LayerParameter*> GetInputs(const caffe::LayerParameter& layerParam); 152 153 /// Modifies the Caffe network to replace "in-place" layers (whose top() and bottom() are both the same) 154 /// with regular layers. This simplifies further parsing. 155 void ResolveInPlaceLayers(caffe::NetParameter& netParameter); 156 157 }; 158 159 class CaffeParser : public CaffeParserBase 160 { 161 public: 162 163 /// Create the network from a protobuf binary file on disk 164 virtual armnn::INetworkPtr CreateNetworkFromBinaryFile( 165 const char* graphFile, 166 const std::map<std::string, armnn::TensorShape>& inputShapes, 167 const std::vector<std::string>& requestedOutputs) override; 168 169 public: 170 CaffeParser(); 171 172 }; 173 }