19 #include <fmt/format.h> 22 #include "caffe/proto/caffe.pb.h" 25 #include <google/protobuf/io/coded_stream.h> 26 #include <google/protobuf/io/zero_copy_stream.h> 27 #include <google/protobuf/io/zero_copy_stream_impl.h> 28 #include <google/protobuf/text_format.h> 29 #include <google/protobuf/stubs/common.h> 30 #include <google/protobuf/stubs/once.h> 31 #include <google/protobuf/io/coded_stream.h> 32 #include <google/protobuf/descriptor.h> 33 #include <google/protobuf/generated_message_reflection.h> 34 #include <google/protobuf/reflection_ops.h> 35 #include <google/protobuf/wire_format.h> 58 using namespace armnn;
59 using namespace caffe;
66 const float* GetArrayPtrFromBlob(
const LayerParameter& layerParam,
unsigned int blobIndex)
68 auto nBlobs = layerParam.blobs_size();
69 if (blobIndex >= armnn::numeric_cast<unsigned int>(nBlobs))
72 fmt::format(
"Expected data blob at index {} in layer {} not found. nBlobs={}. {}",
79 const BlobProto& blob = layerParam.blobs(armnn::numeric_cast<int>(blobIndex));
81 const float* arrayPtr = blob.data().data();
85 void GetDataFromBlob(
const LayerParameter& layerParam, vector<float>& outData,
unsigned int blobIndex)
87 auto nBlobs = layerParam.blobs_size();
88 if (blobIndex >= armnn::numeric_cast<unsigned int>(nBlobs))
91 fmt::format(
"Expected data blob at index {} in layer {} not found. {}",
97 const BlobProto& blob = layerParam.blobs(armnn::numeric_cast<int>(blobIndex));
100 if (blobSize != outData.size())
103 fmt::format(
"Data blob at index {} in layer {} has an unexpected size. " 104 "Expected {} elements but got {} elements. {}",
113 for (
int i = 0; i < outSizeInt; ++i)
115 outData[
static_cast<size_t>(i)] = blob.data(i);
119 template <
typename T>
120 size_t SizeOfVectorData(
const vector<T>& vec)
122 return vec.size() *
sizeof(T);
125 void ValidateNumInputsOutputs(
const caffe::LayerParameter& layerParameter,
126 unsigned int numInputs,
127 unsigned int numOutputs)
129 int numInputsActual = layerParameter.bottom_size();
130 if (numInputs != armnn::numeric_cast<unsigned int>(numInputsActual))
133 fmt::format(
"Invalid number of inputs requested {} for layer {} " 134 "while only {} present. {}",
136 layerParameter.name(),
141 int numOutputsActual = layerParameter.top_size();
142 if (numOutputs != armnn::numeric_cast<unsigned int>(numOutputsActual))
145 fmt::format(
"Invalid number of outputs requested {} for layer {} " 146 "while only {} present. {}",
148 layerParameter.name(),
154 template <
typename ParamType,
typename ExtractOptional,
typename ExtractFallback,
typename ValueType>
155 ValueType GetOptionalWithFallback(
const ParamType& param,
156 ExtractOptional extractOptional,
157 ExtractFallback extractFallback,
158 ValueType defaultValue)
160 auto optValue = extractOptional(param, defaultValue);
163 return optValue.second;
165 auto fallbackValue = extractFallback(param, defaultValue);
166 return fallbackValue.second;
169 #define GET_OPTIONAL_WITH_VECTOR_FALLBACK(PARAM, \ 175 GetOptionalWithFallback( \ 177 [](const PARAM_TYPE & param, VALUE_TYPE defaultValue) \ 179 if (param.has_##OPTIONAL_VALUE ()) \ 181 return std::make_pair(true, param.OPTIONAL_VALUE ()); \ 185 return std::make_pair(false, defaultValue); \ 188 [](const PARAM_TYPE & param, VALUE_TYPE defaultValue) \ 190 if (param.FALLBACK_VECTOR##_size() > 0) \ 192 return std::make_pair(true, (param.FALLBACK_VECTOR ()).Get(0)); \ 196 return std::make_pair(false, defaultValue); \ 201 #define GET_OPTIONAL_WITH_FALLBACK(PARAM, \ 207 GetOptionalWithFallback( \ 209 [](const PARAM_TYPE & param, VALUE_TYPE defaultValue) \ 211 if (param.has_##OPTIONAL_VALUE ()) \ 213 return std::make_pair(true, param.OPTIONAL_VALUE ()); \ 217 return std::make_pair(false, defaultValue); \ 220 [](const PARAM_TYPE & param, VALUE_TYPE defaultValue) \ 222 if (param.has_##FALLBACK_VALUE ()) \ 224 return std::make_pair(true, param.FALLBACK_VALUE ()); \ 228 return std::make_pair(false, defaultValue); \ 235 const std::map<std::string, CaffeParserBase::OperationParsingFunction>
268 : m_Network(nullptr, nullptr)
290 const char* bindingPointDesc,
291 const std::unordered_map<std::string, BindingPointInfo>& nameToBindingInfo)
293 auto it = nameToBindingInfo.find(layerName);
294 if (it == nameToBindingInfo.end())
297 fmt::format(
"Unknown binding {} for layer '{}'. {}",
307 std::vector<unsigned int> shape;
308 for (
int j = 0; j < blobShape.dim_size(); ++j)
310 shape.push_back(static_cast<unsigned int>(blobShape.dim(j)));
313 return TensorInfo(armnn::numeric_cast<unsigned int>(shape.size()), shape.data(), DataType::Float32);
322 ret.set_dim(armnn::numeric_cast<int>(i), desc.
GetShape()[i]);
332 std::vector<const caffe::LayerParameter*> ret;
333 ret.reserve(armnn::numeric_cast<size_t>(layerParam.bottom_size()));
334 for (
int j = 0; j < layerParam.bottom_size(); ++j)
336 std::string inputName = layerParam.bottom(j);
341 fmt::format(
"Can't find Caffe layer with top called '{}', " 342 "which is listed as an input of '{}'. {}",
347 ret.push_back(inputIt->second);
356 ValidateNumInputsOutputs(layerParam, 0, 1);
358 const InputParameter& param = layerParam.input_param();
368 const BlobShape* originalShape = param.shape_size() > 0 && param.shape(0).dim_size() > 0 ?
369 ¶m.shape(0) :
nullptr;
378 const TensorShape& overrideShape = overrideIt->second;
380 ( originalShape->dim(1) != overrideShape[1]
381 || originalShape->dim(2) != overrideShape[2]
382 || originalShape->dim(3) != overrideShape[3]))
385 fmt::format(
"Parsed input shape for '{}' is incompatible with the override provided. {}",
389 inputTensorInfo.
SetShape(overrideShape);
391 else if (!originalShape)
394 fmt::format(
"No input descriptor given for '{}' and no input shape found in caffe model. {}",
400 inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
406 unsigned int kernelW,
407 unsigned int kernelH)
410 ValidateNumInputsOutputs(layerParam, 1, 1);
412 ConvolutionParameter convParam = layerParam.convolution_param();
414 const unsigned int numGroups = convParam.has_group() ? convParam.group() : 1;
423 vector<string> convLayerNames(numGroups);
424 vector<armnn::IConnectableLayer*> convLayers(numGroups);
425 convLayerNames[0] = layerParam.name();
430 unsigned int splitterDimSizes[4] = {
static_cast<unsigned int>(inputShape.dim(0)),
431 static_cast<unsigned int>(inputShape.dim(1)),
432 static_cast<unsigned int>(inputShape.dim(2)),
433 static_cast<unsigned int>(inputShape.dim(3))};
438 splitterDimSizes[1] /= numGroups;
439 inputShape.set_dim(1, splitterDimSizes[1]);
445 for (
unsigned int g = 0; g < numGroups; ++g)
449 ss << layerParam.name() <<
"_" << g;
450 convLayerNames[g] = ss.str();
455 for (
unsigned int dimIdx=0; dimIdx < 4; dimIdx++)
457 splitterDesc.
SetViewSize(g, dimIdx, splitterDimSizes[dimIdx]);
461 const std::string splitterLayerName = std::string(
"splitter_") + layerParam.bottom(0);
470 unsigned int numFilters = convParam.num_output();
473 BlobShape outputShape;
474 outputShape.add_dim(0);
475 outputShape.set_dim(0, inputShape.dim(0));
476 outputShape.add_dim(1);
478 outputShape.set_dim(1, numFilters / numGroups);
479 outputShape.add_dim(2);
481 2, (static_cast<int>(
482 static_cast<float>(inputShape.dim(2) + 2 * desc.
m_PadBottom - kernelH) /
483 static_cast<float>(desc.
m_StrideY)) + 1));
484 outputShape.add_dim(3);
486 3, (static_cast<int>(
487 static_cast<float>(inputShape.dim(3) + 2 * desc.
m_PadRight - kernelW) /
488 static_cast<float>(desc.
m_StrideX)) + 1));
491 vector<float> weightData(armnn::numeric_cast<size_t>(numGroups *
496 GetDataFromBlob(layerParam, weightData, 0);
498 const unsigned int weightDimSizes[4] = {
499 static_cast<unsigned int>(outputShape.dim(1)),
500 static_cast<unsigned int>(inputShape.dim(1)),
505 vector<float> biasData;
509 biasData.resize(armnn::numeric_cast<size_t>(numGroups * outputShape.dim(1)), 1.f);
510 GetDataFromBlob(layerParam, biasData, 1);
512 const unsigned int biasDimSizes[1] = {
static_cast<unsigned int>(outputShape.dim(1))};
513 biasInfo =
TensorInfo(1, biasDimSizes, DataType::Float32);
516 const unsigned int numWeightsPerGroup =
armnn::numeric_cast<
unsigned int>(weightData.size()) / numGroups;
517 const unsigned int numBiasesPerGroup =
armnn::numeric_cast<
unsigned int>(biasData.size()) / numGroups;
519 for (
unsigned int g = 0; g < numGroups; ++g)
526 weightData.data() + numWeightsPerGroup * g);
533 ConstTensor biases(biasInfo, biasData.data() + numBiasesPerGroup * g);
536 convLayer =
m_Network->AddConvolution2dLayer(desc,
539 convLayerNames[g].c_str());
540 convLayers[g] = convLayer;
545 splitterLayer ? splitterLayer->
GetOutputSlot(g) : inputConnection;
546 splitterInputConnection.
Connect(convLayer->GetInputSlot(0));
553 unsigned int concatDimSizes[4] = {
static_cast<unsigned int>(outputShape.dim(0)),
554 static_cast<unsigned int>(outputShape.dim(1)),
555 static_cast<unsigned int>(outputShape.dim(2)),
556 static_cast<unsigned int>(outputShape.dim(3))};
563 for (
unsigned int g = 0; g < numGroups; ++g)
569 concatDimSizes[1] *= numGroups;
570 outputShape.set_dim(1, concatDimSizes[1]);
578 fmt::format(
"Failed to create final concat layer for Split+Convolution+Concat. " 579 "Layer={} #groups={} #filters={} {}",
586 for (
unsigned int g = 0; g < numGroups; ++g)
588 convLayers[g]->GetOutputSlot(0).Connect(concatLayer->
GetInputSlot(g));
596 unsigned int kernelW,
597 unsigned int kernelH)
600 ValidateNumInputsOutputs(layerParam, 1, 1);
602 ConvolutionParameter convParam = layerParam.convolution_param();
614 unsigned int numFilters = convParam.num_output();
616 BlobShape outputShape;
617 outputShape.add_dim(0);
618 outputShape.set_dim(0, inputShape.dim(0));
619 outputShape.add_dim(1);
620 outputShape.set_dim(1, numFilters);
621 outputShape.add_dim(2);
623 2, (static_cast<int>(
624 static_cast<float>(inputShape.dim(2) + 2 * desc.m_PadBottom - kernelH) /
625 static_cast<float>(desc.m_StrideY)) + 1));
626 outputShape.add_dim(3);
628 3, (static_cast<int>(
629 static_cast<float>(inputShape.dim(3) + 2 * desc.m_PadRight - kernelW) /
630 static_cast<float>(desc.m_StrideX)) + 1));
633 size_t allWeightsSize =
armnn::numeric_cast<
size_t>(inputShape.dim(1) * kernelH * kernelW);
634 vector<float> weightData(allWeightsSize);
636 GetDataFromBlob(layerParam, weightData, 0);
639 const unsigned int weightDimSizes[4] = {
640 static_cast<unsigned int>(1),
641 static_cast<unsigned int>(inputShape.dim(1)),
648 vector<float> biasData;
649 if (desc.m_BiasEnabled)
653 biasData.resize(armnn::numeric_cast<size_t>(outputShape.dim(1)), 1.f);
654 GetDataFromBlob(layerParam, biasData, 1);
656 const unsigned int biasDimSizes[1] = {
static_cast<unsigned int>(outputShape.dim(1))};
657 biasInfo =
TensorInfo(1, biasDimSizes, DataType::Float32);
662 returnLayer =
m_Network->AddDepthwiseConvolution2dLayer(desc,
665 layerParam.name().c_str());
670 fmt::format(
"Failed to create depthwise convolution layer. " 671 "Layer={} #filters={} {}",
677 inputConnection.
Connect(returnLayer->GetInputSlot(0));
696 ValidateNumInputsOutputs(layerParam, 1, 1);
698 ConvolutionParameter convParam = layerParam.convolution_param();
700 const unsigned int numGroups = convParam.has_group() ? convParam.group() : 1;
701 unsigned int numFilters = convParam.num_output();
703 const auto notFound = std::numeric_limits<unsigned int>::max();
706 kernel_h, kernel_size,
unsigned int, notFound);
708 kernel_w, kernel_size,
unsigned int, notFound);
711 stride_h, stride,
unsigned int, 1u);
713 stride_w, stride,
unsigned int, 1u);
716 pad_h, pad,
unsigned int, 0u);
718 pad_w, pad,
unsigned int, 0u);
721 convolution2dDescriptor.
m_PadLeft = padW;
723 convolution2dDescriptor.
m_PadTop = padH;
725 convolution2dDescriptor.
m_StrideX = strideW;
726 convolution2dDescriptor.
m_StrideY = strideH;
727 convolution2dDescriptor.
m_BiasEnabled = convParam.has_bias_term() ? convParam.bias_term() :
true;
729 if (numGroups > numFilters)
732 fmt::format(
"Error parsing Convolution: {}. " 733 "The 'group'={} parameter cannot be larger than the " 734 "number of filters supplied ='{}'. {}",
741 if (inputShape.dim_size() != 4)
744 fmt::format(
"Convolution input shape is expected to have 4 dimensions. " 745 "{}'s input has only {}. {}",
747 inputShape.dim_size(),
753 if (numGroups > inputShape.dim(1))
756 fmt::format(
"Error parsing Convolution: {}. " 757 "The 'group'={} parameter cannot be larger than the " 758 "channel of the input shape={} (in NCHW format). {}",
764 else if (numGroups == inputShape.dim(1))
784 BlobShape outputShape;
785 outputShape.add_dim(0);
786 outputShape.set_dim(0, inputShape.dim(0));
787 outputShape.add_dim(1);
788 outputShape.set_dim(1, numFilters);
789 outputShape.add_dim(2);
791 2, (static_cast<int>(
792 static_cast<float>(inputShape.dim(2) + 2 * padH - kernelH) /
793 static_cast<float>(strideH)) + 1));
794 outputShape.add_dim(3);
796 3, (static_cast<int>(
797 static_cast<float>(inputShape.dim(3) + 2 * padW - kernelW) /
798 static_cast<float>(strideW)) + 1));
801 vector<float> weightData(armnn::numeric_cast<size_t>(inputShape.dim(1) *
805 GetDataFromBlob(layerParam, weightData, 0);
807 const unsigned int weightDimSizes[4] = {
808 static_cast<unsigned int>(outputShape.dim(1)),
809 static_cast<unsigned int>(inputShape.dim(1)),
818 vector<float> biasData;
823 biasData.resize(armnn::numeric_cast<size_t>(outputShape.dim(1)), 1.f);
824 GetDataFromBlob(layerParam, biasData, 1);
826 const unsigned int biasDimSizes[1] = {
static_cast<unsigned int>(outputShape.dim(1))};
827 biasInfo =
TensorInfo(1, biasDimSizes, DataType::Float32);
833 returnLayer =
m_Network->AddConvolution2dLayer(convolution2dDescriptor,
836 layerParam.name().c_str());
839 inputConnection.
Connect(returnLayer->GetInputSlot(0));
845 fmt::format(
"Failed to create Convolution layer. " 846 "Layer={} #groups={} #filters={} {}",
862 ValidateNumInputsOutputs(layerParam, 1, 1);
863 PoolingParameter param = layerParam.pooling_param();
866 const auto notFound = std::numeric_limits<unsigned int>::max();
869 kernel_h, kernel_size,
unsigned int, notFound);
871 kernel_w, kernel_size,
unsigned int, notFound);
873 if ((kernel_h == notFound || kernel_w == notFound) && param.has_global_pooling())
880 stride_h, stride,
unsigned int, notFound);
882 stride_h, stride,
unsigned int, notFound);
884 if ((stride_h == notFound || stride_w == notFound) && param.has_global_pooling())
891 pad_h, pad,
unsigned int, 0u);
893 pad_w, pad,
unsigned int, 0u);
897 if (param.has_pool())
899 PoolingParameter_PoolMethod p = param.pool();
902 case PoolingParameter_PoolMethod_MAX:
907 case PoolingParameter_PoolMethod_AVE:
909 pooling2dDescriptor.
m_PoolType = PoolingAlgorithm::Average;
912 case PoolingParameter_PoolMethod_STOCHASTIC:
915 fmt::format(
"Pooling Layer: Stochastic Pooling Not Supported. Layer={} {}",
922 fmt::format(
"Pooling Layer: unknown pooling method: {} for layer: {} {}",
932 fmt::format(
"No Pooling Method Defined for {} {}",
939 pooling2dDescriptor.
m_PadTop = pad_h;
941 pooling2dDescriptor.
m_StrideX = stride_w;
942 pooling2dDescriptor.
m_StrideY = stride_h;
950 layerParam.name().c_str());
955 static_cast<unsigned int>(ceil(
956 static_cast<float>(inputInfo.
GetShape()[2] + 2 * pad_h - kernel_h) /
957 armnn::numeric_cast<float>(stride_h))) + 1,
958 static_cast<unsigned int>(ceil(
959 static_cast<float>(inputInfo.
GetShape()[3] + 2 * pad_w - kernel_w) /
960 armnn::numeric_cast<float>(stride_w))) + 1 },
970 ValidateNumInputsOutputs(layerParam, 1, 1);
972 const string& name = layerParam.name();
973 const ReLUParameter& param = layerParam.relu_param();
976 const float negativeSlope = param.negative_slope();
977 if (negativeSlope == 0.0f)
979 activationDescriptor.
m_Function = ActivationFunction::ReLu;
983 activationDescriptor.
m_Function = ActivationFunction::LeakyReLu;
984 activationDescriptor.
m_A = negativeSlope;
996 ValidateNumInputsOutputs(layerParam, 1, 1);
998 LRNParameter param = layerParam.lrn_param();
1008 if (param.has_norm_region())
1010 LRNParameter_NormRegion n = param.norm_region();
1013 case LRNParameter_NormRegion_ACROSS_CHANNELS:
1015 normalizationDescriptor.
m_NormChannelType = NormalizationAlgorithmChannel::Across;
1018 case LRNParameter_NormRegion_WITHIN_CHANNEL:
1020 normalizationDescriptor.
m_NormChannelType = NormalizationAlgorithmChannel::Within;
1026 fmt::format(
"Unknown region {} for LRN layer {} {}",
1036 normalizationDescriptor.
m_NormChannelType = NormalizationAlgorithmChannel::Across;
1039 normalizationDescriptor.
m_NormMethodType = NormalizationAlgorithmMethod::LocalBrightness;
1040 if (param.has_local_size())
1042 normalizationDescriptor.
m_NormSize = param.local_size();
1047 fmt::format(
"local_size not defined for LRN layer {} {}",
1052 if (param.has_alpha())
1054 normalizationDescriptor.
m_Alpha = param.alpha();
1060 fmt::format(
"Alpha not defined for LRN layer {} {}",
1064 if (param.has_beta())
1066 normalizationDescriptor.
m_Beta = param.beta();
1071 fmt::format(
"Beta not defined for LRN layer {} {}",
1078 normalizationDescriptor.
m_K = param.k();
1082 normalizationDescriptor.
m_K = 1;
1086 layerParam.name().c_str());
1095 InnerProductParameter param = layerParam.inner_product_param();
1097 ValidateNumInputsOutputs(layerParam, 1, 1);
1099 unsigned int outputSize = param.num_output();
1109 if (param.has_transpose())
1126 unsigned int inputSize = inputInfo.
GetShape()[1];
1129 inputSize *= inputInfo.
GetShape()[i];
1132 const float* weightDataPtr = GetArrayPtrFromBlob(layerParam, 0);
1133 const unsigned int swTD[2] = { outputSize, inputSize };
1142 const float* biasDataPtr = GetArrayPtrFromBlob(layerParam, 1);
1144 const unsigned int sbTD[1] = { outputSize };
1148 fullyConnectedLayer =
m_Network->AddFullyConnectedLayer(tensorFullyConnectedDescriptor,
1151 layerParam.name().c_str());
1155 fullyConnectedLayer =
m_Network->AddFullyConnectedLayer(tensorFullyConnectedDescriptor,
1158 layerParam.name().c_str());
1169 ValidateNumInputsOutputs(layerParam, 1, 1);
1171 SoftmaxParameter param = layerParam.softmax_param();
1180 softmaxDescriptor.
m_Axis = 1;
1183 layerParam.name().c_str());
1191 ValidateNumInputsOutputs(layerParam, 2, 1);
1198 EltwiseParameter_EltwiseOp operation = EltwiseParameter_EltwiseOp_SUM;
1200 if (layerParam.has_eltwise_param() && layerParam.eltwise_param().has_operation())
1202 operation = layerParam.eltwise_param().operation();
1208 case EltwiseParameter_EltwiseOp_SUM:
1210 newLayer =
m_Network->AddAdditionLayer(layerParam.name().c_str());
1213 case EltwiseParameter_EltwiseOp_PROD:
1215 newLayer =
m_Network->AddMultiplicationLayer(layerParam.name().c_str());
1221 fmt::format(
"Unsupported operation {} in Eltwise layer {} {}",
1236 unsigned int numInputs =
static_cast<unsigned int>(layerParam.bottom_size());
1238 unsigned int concatDim = 1;
1239 unsigned int numOfDims = 4;
1242 OriginsDescriptor concatDescriptor(static_cast<uint32_t>(numInputs), numOfDims);
1243 std::vector<unsigned int>mergeDimSizes(numOfDims, 0u);
1245 unsigned int mergeDim = 0;
1246 for (
unsigned int viewIndex = 0; viewIndex < numInputs; ++viewIndex)
1249 layerParam.bottom(armnn::numeric_cast<int>(viewIndex))).
GetTensorInfo();
1254 fmt::format(
"The number of dimensions for input tensors of " 1255 "the concatenation op should be 4. Inputs of {} has " 1256 "{} dimensions. {}",
1262 mergeDimSizes[0] = inputInfo.
GetShape()[0];
1263 mergeDimSizes[1] = inputInfo.
GetShape()[1];
1264 mergeDimSizes[2] = inputInfo.
GetShape()[2];
1265 mergeDimSizes[3] = inputInfo.
GetShape()[3];
1267 for (
unsigned int j = 0; j < concatDim; ++j)
1273 mergeDim += mergeDimSizes[concatDim];
1275 for (
unsigned int j = concatDim+1; j < numOfDims; ++j)
1280 mergeDimSizes[concatDim] = mergeDim;
1283 for (
unsigned int i = 0; i < numInputs; ++i)
1295 ValidateNumInputsOutputs(layerParam, 1, 1);
1299 string name = layerParam.name();
1301 BatchNormParameter param = layerParam.batch_norm_param();
1304 if (param.has_use_global_stats())
1306 if (!param.use_global_stats())
1309 fmt::format(
"Error parsing Batch Norm layer '{}': " 1310 "Parameter 'use_global_stats' is set to false, which is " 1311 "unsupported (value used for training). {}",
1318 desc.
m_Eps = param.eps();
1320 unsigned int channels = inputInfo.
GetShape()[1];
1321 unsigned int shape[] = {channels};
1323 vector<float> meanData(channels);
1324 GetDataFromBlob(layerParam, meanData, 0);
1326 vector<float> varianceData(channels);
1327 GetDataFromBlob(layerParam, varianceData, 1);
1330 const BlobProto& blob = layerParam.blobs(armnn::numeric_cast<int>(2));
1331 const float movingAverageFactor = blob.data(armnn::numeric_cast<int>(0));
1332 if(movingAverageFactor != 0.0f)
1334 const float scaleFactor = 1.0f / movingAverageFactor;
1335 auto scaleFunction = [scaleFactor](
float f) ->
float {
return f * scaleFactor; };
1337 std::transform(varianceData.begin(), varianceData.end(), varianceData.begin(), scaleFunction);
1338 std::transform(meanData.begin(), meanData.end(), meanData.begin(), scaleFunction);
1342 vector<float> betaData(channels, 0.0f);
1343 vector<float> gammaData(channels, 1.0f);
1351 mean, variance, beta, gamma, name.c_str());
1360 ValidateNumInputsOutputs(layerParam, 1, 1);
1364 string name = layerParam.name();
1366 ScaleParameter param = layerParam.scale_param();
1367 if (param.axis() != 1)
1371 fmt::format(
"Loading Scale Layer: Only axis 1 is supported currently. " 1372 "Layer={} Axis={} {}",
1378 unsigned int channels = inputInfo.
GetShape()[1];
1379 unsigned int shape[] = {channels};
1383 vector<float> meanData(channels, 0.0f);
1384 vector<float> varianceData(channels, 1.0f);
1385 vector<float> betaData(channels, 0.0f);
1386 vector<float> gammaData(channels);
1388 GetDataFromBlob(layerParam, gammaData, 0);
1390 if(param.has_bias_term())
1392 GetDataFromBlob(layerParam, betaData, 1);
1401 mean, variance, beta, gamma, name.c_str());
1410 if (layerParam.bottom_size() != 1)
1413 fmt::format(
"Split layer '{}' should have exactly 1 bottom. " 1416 layerParam.bottom_size(),
1420 for (
int i = 0; i < layerParam.top_size(); i++)
1429 if (layerParam.bottom_size() != 1 || layerParam.top_size() != 1)
1432 fmt::format(
"Dropout layer '{}' should have exactly 1 bottom and 1 top. " 1433 "#bottoms={} #tops={} {}",
1435 layerParam.bottom_size(),
1436 layerParam.top_size(),
1459 const char* bindingPointDesc,
1460 std::unordered_map<std::string, BindingPointInfo>& nameToBindingInfo)
1462 const std::string layerName = layer->
GetName();
1463 auto it = nameToBindingInfo.find(layerName);
1464 if (it == nameToBindingInfo.end())
1466 nameToBindingInfo[layerName] = std::make_pair(
id, tensorInfo);
1471 fmt::format(
"Id {} used by more than one {} layer {}",
1488 fmt::format(
"Could not find armnn output slot for Caffe top '{}' {}",
1505 fmt::format(
"Attempting to add duplicate entry for Caffe top '{}' {}",
1516 std::map<std::string, std::vector<caffe::LayerParameter*>> layersByTop;
1517 for (
int layerIdx = 0; layerIdx < netParameter.layer_size(); ++layerIdx)
1519 caffe::LayerParameter& layer = *netParameter.mutable_layer(layerIdx);
1520 std::string name = layer.name();
1521 for (
int i = 0; i < layer.top_size(); ++i)
1523 layersByTop[layer.top(i)].push_back(&layer);
1529 for (
auto layersWithSameTopIt : layersByTop)
1531 const std::string& top = layersWithSameTopIt.first;
1532 const std::vector<caffe::LayerParameter*>& layersWithSameTop = layersWithSameTopIt.second;
1536 for (
unsigned int layerIdx = 0; layerIdx < layersWithSameTop.size() - 1; ++layerIdx)
1538 caffe::LayerParameter& layer1 = *layersWithSameTop[layerIdx];
1539 caffe::LayerParameter& layer2 = *layersWithSameTop[layerIdx+1];
1540 if (layer1.top_size() != 1)
1543 fmt::format(
"Node '{}' is an in-place layer but doesn't have exactly one " 1544 "top. It has {} instead. {}",
1549 std::string newTop = layer1.name() +
"_top";
1550 layer1.set_top(0, newTop);
1551 if (layer2.bottom_size() != 1 || layer2.bottom(0) != top)
1554 fmt::format(
"Node '{}' is an in-place layer but " 1555 "doesn't have exactly one bottom, or it doesn't match its top. " 1556 "#bottoms={}, first bottom is {}, top is {} {}",
1562 layer2.set_bottom(0, newTop);
1573 if (netParameter.input_size() > 0)
1575 LayerParameter* newLayer = netParameter.add_layer();
1577 newLayer->set_type(
"Input");
1578 newLayer->set_name(netParameter.input(0));
1579 newLayer->add_top(netParameter.input(0));
1581 InputParameter* inputParam = newLayer->mutable_input_param();
1582 BlobShape* shape = inputParam->add_shape();
1584 int dim_size = netParameter.input_dim_size();
1585 for (
int i = 0; i < dim_size; ++i)
1587 shape->add_dim(netParameter.input_dim(i));
1595 for (
int i = 0; i < netParameter.layer_size(); ++i)
1597 const caffe::LayerParameter& layer = netParameter.layer(i);
1598 for (
int i = 0; i < layer.top_size(); ++i)
1605 std::vector<const caffe::LayerParameter*> targetLayers;
1612 fmt::format(
"Couldn't find requested output layer '{}' in graph {}",
1613 requestedOutputName,
1616 targetLayers.push_back(nodeIt->second);
1620 std::vector<const caffe::LayerParameter*> sortedNodes;
1621 if (!armnnUtils::GraphTopologicalSort<const caffe::LayerParameter*>(
1623 [
this](
const caffe::LayerParameter* node)
1630 fmt::format(
"Cycle detected in graph. #nodes: {} {}",
1636 for (
const caffe::LayerParameter* current : sortedNodes)
1642 fmt::format(
"Unsupported layer type: '{}' for layer {} {}",
1647 auto func = it->second;
1648 (this->*func)(*current);
1652 for (
const std::string& requestedOutput : m_RequestedOutputs)
1659 outputSlot.
Connect(outputLayer->GetInputSlot(0));
1661 TrackOutputBinding(outputLayer, outputId, outputLayer->GetInputSlot(0).GetConnection()->GetTensorInfo());
1666 const std::map<std::string, armnn::TensorShape>& inputShapes,
1667 const std::vector<std::string>& requestedOutputs)
1669 FILE* fd = fopen(graphFile,
"r");
1674 fmt::format(
"Failed to open graph file: {} {}",
1680 NetParameter netParam;
1681 auto input =
new google::protobuf::io::FileInputStream(fileno(fd));
1682 bool success = google::protobuf::TextFormat::Parse(input, &netParam);
1689 fmt::format(
"Failed to parse graph file: {} {}",
1698 const std::map<std::string, armnn::TensorShape>& inputShapes,
1699 const std::vector<std::string>& requestedOutputs)
1702 NetParameter netParam;
1703 bool success = google::protobuf::TextFormat::ParseFromString(protoText, &netParam);
1708 fmt::format(
"Failed to parse graph string {}",
1716 const std::map<std::string, armnn::TensorShape>& inputShapes,
1717 const std::vector<std::string>& requestedOutputs)
1719 FILE* fd = fopen(graphFile,
"rb");
1724 fmt::format(
"Failed to open graph file at: {} {}",
1730 NetParameter netParam;
1732 FileInputStream inStream(fileno(fd));
1733 CodedInputStream codedStream(&inStream);
1734 codedStream.SetTotalBytesLimit(INT_MAX);
1735 bool success = netParam.ParseFromCodedStream(&codedStream);
1741 fmt::format(
"Failed to parse protobuf file: {} {}",
1752 const std::map<std::string, armnn::TensorShape>& inputShapes,
1753 const std::vector<std::string>& requestedOutputs)
1761 if (requestedOutputs.size() == 0)
1763 throw ParseException(
"requestedOutputs must have at least one entry");
uint32_t m_PadBottom
Padding bottom value in the height dimension.
bool m_BiasEnabled
Enable/disable bias.
virtual unsigned int GetNumOutputSlots() const =0
Returns the number of connectable output slots.
A ViewsDescriptor for the SplitterLayer.
Interface for a layer that is connectable to other layers via InputSlots and OutputSlots.
void ParseConvLayer(const caffe::LayerParameter &layerParam)
uint32_t m_PadBottom
Padding bottom value in the height dimension.
virtual BindingPointInfo GetNetworkInputBindingInfo(const std::string &name) const override
Retrieves binding info (layer id and tensor info) for the network input identified by the given layer...
float m_K
Kappa value used for the across channel normalization equation.
int m_Axis
Scalar, defaulted to the last index (-1), specifying the dimension the activation will be performed o...
const TensorShape & GetShape() const
static void Destroy(ICaffeParser *parser)
uint32_t m_PadLeft
Padding left value in the width dimension.
armnn::IOutputSlot & GetArmnnOutputSlotForCaffeTop(const std::string &caffeTopName) const
Retrieves the Armnn IOutputSlot representing the given Caffe top.
virtual armnn::INetworkPtr CreateNetworkFromString(const char *protoText, const std::map< std::string, armnn::TensorShape > &inputShapes, const std::vector< std::string > &requestedOutputs) override
Creates the network directly from protobuf text in a string. Useful for debugging/testing.
bool m_TransposeWeightMatrix
Enable/disable transpose weight matrix.
uint32_t m_PoolWidth
Pooling width value.
A Convolution2dDescriptor for the Convolution2dLayer.
float m_Alpha
Alpha value for the normalization equation.
uint32_t m_PadLeft
Padding left value in the width dimension.
static const std::map< std::string, OperationParsingFunction > ms_CaffeLayerNameToParsingFunctions
Maps Caffe layer names to parsing member functions.
float m_Eps
Value to add to the variance. Used to avoid dividing by zero.
PaddingMethod m_PaddingMethod
The padding method to be used. (Exclude, IgnoreValue).
void LoadNetParam(caffe::NetParameter &netParameter)
does the actual conversion from caffe::NetParameter to armnn::INetwork
void ParseInputLayer(const caffe::LayerParameter &layerParam)
Adds an armnn layer to m_Network given a Caffe LayerParameter of the correct type and is responsible ...
uint32_t m_PadTop
Padding top value in the height dimension.
uint32_t m_PadRight
Padding right value in the width dimension.
Copyright (c) 2020 ARM Limited.
static std::pair< armnn::LayerBindingId, armnn::TensorInfo > GetBindingInfo(const std::string &layerName, const char *bindingPointDesc, const std::unordered_map< std::string, BindingPointInfo > &bindingInfos)
std::vector< std::string > m_RequestedOutputs
Caffe networks are loaded from protobuf files (binary or text) using the protobuf library and the gen...
uint32_t m_StrideX
Stride value when proceeding through input for the width dimension.
int LayerBindingId
Type of identifiers for bindable layers (inputs, outputs).
virtual void SetTensorInfo(const TensorInfo &tensorInfo)=0
NormalizationAlgorithmMethod m_NormMethodType
Normalization method algorithm to use (LocalBrightness, LocalContrast).
virtual armnn::INetworkPtr CreateNetworkFromTextFile(const char *graphFile, const std::map< std::string, armnn::TensorShape > &inputShapes, const std::vector< std::string > &requestedOutputs) override
Create the network from a protobuf text file on disk.
void SetShape(const TensorShape &newShape)
void ParseBatchNormLayer(const caffe::LayerParameter &layerParam)
void TrackOutputBinding(armnn::IConnectableLayer *layer, armnn::LayerBindingId id, const armnn::TensorInfo &tensorInfo)
uint32_t m_PoolHeight
Pooling height value.
uint32_t m_PadTop
Padding top value in the height dimension.
uint32_t m_StrideX
Stride value when proceeding through input for the width dimension.
void ResolveInPlaceLayers(caffe::NetParameter &netParameter)
Modifies the Caffe network to replace "in-place" layers (whose top() and bottom() are both the same) ...
uint32_t m_PadRight
Padding right value in the width dimension.
Status SetViewSize(uint32_t view, uint32_t coord, uint32_t value)
Set the size of the views.
static ICaffeParserPtr Create()
An output connection slot for a layer.
An OriginsDescriptor for the ConcatLayer.
std::unordered_map< std::string, armnn::IOutputSlot * > m_ArmnnOutputSlotForCaffeTop
As we add armnn layers we store the armnn IOutputSlot which corresponds to the Caffe tops...
A FullyConnectedDescriptor for the FullyConnectedLayer.
bool m_BiasEnabled
Enable/disable bias.
A tensor defined by a TensorInfo (shape and data type) and an immutable backing store.
std::unordered_map< std::string, BindingPointInfo > m_NetworkInputsBindingInfo
maps input layer names to their corresponding ids and tensor infos
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.
#define ARMNN_ASSERT(COND)
#define GET_OPTIONAL_WITH_FALLBACK(PARAM, PARAM_TYPE, OPTIONAL_VALUE, FALLBACK_VALUE, VALUE_TYPE, DEFAULT_VALUE)
std::unordered_map< std::string, BindingPointInfo > m_NetworkOutputsBindingInfo
maps output layer names to their corresponding ids and tensor infos
std::unique_ptr< ICaffeParser, void(*)(ICaffeParser *parser)> ICaffeParserPtr
armnn::TensorInfo BlobShapeToTensorInfo(const caffe::BlobShape &blobShape) const
Converts Caffe's protobuf tensor shape format to ArmNN's.
std::map< std::string, armnn::TensorShape > m_InputShapes
An ActivationDescriptor for the ActivationLayer.
void ParseInnerProductLayer(const caffe::LayerParameter &layerParam)
void ParseSoftmaxLayer(const caffe::LayerParameter &layerParam)
armnn::INetworkPtr CreateNetworkFromNetParameter(caffe::NetParameter &netParam, const std::map< std::string, armnn::TensorShape > &inputShapes, const std::vector< std::string > &requestedOutputs)
Parses a NetParameter loaded into memory from one of the other CreateNetwork*.
void ParseReluLayer(const caffe::LayerParameter &layerParam)
uint32_t m_StrideY
Stride value when proceeding through input for the height dimension.
void AddConvLayerWithSplits(const caffe::LayerParameter &layerParam, const armnn::Convolution2dDescriptor &desc, unsigned int kernelW, unsigned int kernelH)
ParseConv may use these helpers depending on the group parameter.
static void TrackBindingPoint(armnn::IConnectableLayer *layer, armnn::LayerBindingId id, const armnn::TensorInfo &tensorInfo, const char *bindingPointDesc, std::unordered_map< std::string, BindingPointInfo > &nameToBindingInfo)
void ParseScaleLayer(const caffe::LayerParameter &layerParam)
void ParseDropoutLayer(const caffe::LayerParameter &layerParam)
NormalizationAlgorithmChannel m_NormChannelType
Normalization channel algorithm to use (Across, Within).
float m_A
Alpha upper bound value used by the activation functions. (BoundedReLu, Linear, TanH, Elu).
virtual BindingPointInfo GetNetworkOutputBindingInfo(const std::string &name) const override
Retrieves binding info (layer id and tensor info) for the network output identified by the given laye...
EmptyOptional is used to initialize the Optional class in case we want to have default value for an O...
std::pair< armnn::LayerBindingId, armnn::TensorInfo > BindingPointInfo
void TrackInputBinding(armnn::IConnectableLayer *layer, armnn::LayerBindingId id, const armnn::TensorInfo &tensorInfo)
PoolingAlgorithm m_PoolType
The pooling algorithm to use (Max. Average, L2).
void ParseEltwiseLayer(const caffe::LayerParameter &layerParam)
static ICaffeParser * CreateRaw()
OutputShapeRounding m_OutputShapeRounding
The rounding method for the output shape. (Floor, Ceiling).
std::vector< const caffe::LayerParameter * > GetInputs(const caffe::LayerParameter &layerParam)
Find the Caffe layers listed as inputs (bottoms) for a given layer.
virtual const IInputSlot & GetInputSlot(unsigned int index) const =0
Get a const input slot handle by slot index.
std::enable_if_t< std::is_unsigned< Source >::value &&std::is_unsigned< Dest >::value, Dest > numeric_cast(Source source)
armnn::TensorInfo GetTensorInfo(unsigned int numberOfBatches, unsigned int numberOfChannels, unsigned int height, unsigned int width, const armnn::DataLayout dataLayout, const armnn::DataType dataType)
virtual const IOutputSlot & GetOutputSlot(unsigned int index) const =0
Get the const output slot handle by slot index.
void ParseLRNLayer(const caffe::LayerParameter &layerParam)
virtual const char * GetName() const =0
Returns the name of the layer.
#define GET_OPTIONAL_WITH_VECTOR_FALLBACK(PARAM, PARAM_TYPE, OPTIONAL_VALUE, FALLBACK_VECTOR, VALUE_TYPE, DEFAULT_VALUE)
void Connect(armnn::IConnectableLayer *from, armnn::IConnectableLayer *to, const armnn::TensorInfo &tensorInfo, unsigned int fromIndex, unsigned int toIndex)
std::unique_ptr< INetwork, void(*)(INetwork *network)> INetworkPtr
virtual int Connect(IInputSlot &destination)=0
A Pooling2dDescriptor for the Pooling2dLayer.
void SetArmnnOutputSlotForCaffeTop(const std::string &caffeTopName, armnn::IOutputSlot &armnnOutputSlot)
A NormalizationDescriptor for the NormalizationLayer.
static INetworkPtr Create(NetworkOptions networkOptions={})
unsigned int GetNumDimensions() const
void AddConvLayerWithDepthwiseConv(const caffe::LayerParameter &layerParam, const armnn::Convolution2dDescriptor &desc, unsigned int kernelW, unsigned int kernelH)
A SoftmaxDescriptor for the SoftmaxLayer.
float m_Beta
Beta value for the normalization equation.
void ParsePoolingLayer(const caffe::LayerParameter &layerParam)
uint32_t m_NormSize
Depth radius value.
Status SetViewOriginCoord(uint32_t view, uint32_t coord, uint32_t value)
Set the view origin coordinates.
std::map< std::string, const caffe::LayerParameter * > m_CaffeLayersByTopName
ActivationFunction m_Function
The activation function to use (Sigmoid, TanH, Linear, ReLu, BoundedReLu, SoftReLu, LeakyReLu, Abs, Sqrt, Square, Elu).
armnn::INetworkPtr m_Network
void ParseConcatLayer(const caffe::LayerParameter &layerParam)
uint32_t m_StrideY
Stride value when proceeding through input for the height dimension.
A DepthwiseConvolution2dDescriptor for the DepthwiseConvolution2dLayer.
A BatchNormalizationDescriptor for the BatchNormalizationLayer.
uint32_t m_PadLeft
Padding left value in the width dimension.
BlobShape TensorDescToBlobShape(const TensorInfo &desc)
void ParseSplitLayer(const caffe::LayerParameter &layerParam)
Status SetViewOriginCoord(uint32_t view, uint32_t coord, uint32_t value)
Set the view origin coordinates.