16 #include <boost/numeric/conversion/cast.hpp> 17 #include <boost/assert.hpp> 18 #include <boost/format.hpp> 21 #include "caffe/proto/caffe.pb.h" 24 #include <google/protobuf/io/coded_stream.h> 25 #include <google/protobuf/io/zero_copy_stream.h> 26 #include <google/protobuf/io/zero_copy_stream_impl.h> 27 #include <google/protobuf/text_format.h> 28 #include <google/protobuf/stubs/common.h> 29 #include <google/protobuf/stubs/once.h> 30 #include <google/protobuf/io/coded_stream.h> 31 #include <google/protobuf/descriptor.h> 32 #include <google/protobuf/generated_message_reflection.h> 33 #include <google/protobuf/reflection_ops.h> 34 #include <google/protobuf/wire_format.h> 57 using namespace armnn;
58 using namespace caffe;
65 const float* GetArrayPtrFromBlob(
const LayerParameter& layerParam,
unsigned int blobIndex)
67 auto nBlobs = layerParam.blobs_size();
68 if (blobIndex >= boost::numeric_cast<unsigned int>(nBlobs))
73 "Expected data blob at index %1% in layer %2% not found. nBlobs=%2%. %4%") %
80 const BlobProto& blob = layerParam.blobs(boost::numeric_cast<int>(blobIndex));
82 const float* arrayPtr = blob.data().data();
86 void GetDataFromBlob(
const LayerParameter& layerParam, vector<float>& outData,
unsigned int blobIndex)
88 auto nBlobs = layerParam.blobs_size();
89 if (blobIndex >= boost::numeric_cast<unsigned int>(nBlobs))
94 "Expected data blob at index %1% in layer %2% not found. %3%") %
100 const BlobProto& blob = layerParam.blobs(boost::numeric_cast<int>(blobIndex));
102 size_t blobSize = boost::numeric_cast<
size_t>(blob.data_size());
103 if (blobSize != outData.size())
108 "Data blob at index %1% in layer %2% has an unexpected size. " 109 "Expected %3% elements but got %4% elements. %5%") %
117 int outSizeInt = boost::numeric_cast<
int>(outData.size());
118 for (
int i = 0; i < outSizeInt; ++i)
120 outData[
static_cast<size_t>(i)] = blob.data(i);
124 template <
typename T>
125 size_t SizeOfVectorData(
const vector<T>& vec)
127 return vec.size() *
sizeof(T);
130 void ValidateNumInputsOutputs(
const caffe::LayerParameter& layerParameter,
131 unsigned int numInputs,
132 unsigned int numOutputs)
134 int numInputsActual = layerParameter.bottom_size();
135 if (numInputs != boost::numeric_cast<unsigned int>(numInputsActual))
139 boost::format(
"Invalid number of inputs requested %1% for layer %2% " 140 "while only %3% present. %4%") %
142 layerParameter.name() %
147 int numOutputsActual = layerParameter.top_size();
148 if (numOutputs != boost::numeric_cast<unsigned int>(numOutputsActual))
152 boost::format(
"Invalid number of outputs requested %1% for layer %2% " 153 "while only %3% present. %4%") %
155 layerParameter.name() %
161 template <
typename ParamType,
typename ExtractOptional,
typename ExtractFallback,
typename ValueType>
162 ValueType GetOptionalWithFallback(
const ParamType& param,
163 ExtractOptional extractOptional,
164 ExtractFallback extractFallback,
165 ValueType defaultValue)
167 auto optValue = extractOptional(param, defaultValue);
170 return optValue.second;
172 auto fallbackValue = extractFallback(param, defaultValue);
173 return fallbackValue.second;
176 #define GET_OPTIONAL_WITH_VECTOR_FALLBACK(PARAM, \ 182 GetOptionalWithFallback( \ 184 [](const PARAM_TYPE & param, VALUE_TYPE defaultValue) \ 186 if (param.has_##OPTIONAL_VALUE ()) \ 188 return std::make_pair(true, param.OPTIONAL_VALUE ()); \ 192 return std::make_pair(false, defaultValue); \ 195 [](const PARAM_TYPE & param, VALUE_TYPE defaultValue) \ 197 if (param.FALLBACK_VECTOR##_size() > 0) \ 199 return std::make_pair(true, (param.FALLBACK_VECTOR ()).Get(0)); \ 203 return std::make_pair(false, defaultValue); \ 208 #define GET_OPTIONAL_WITH_FALLBACK(PARAM, \ 214 GetOptionalWithFallback( \ 216 [](const PARAM_TYPE & param, VALUE_TYPE defaultValue) \ 218 if (param.has_##OPTIONAL_VALUE ()) \ 220 return std::make_pair(true, param.OPTIONAL_VALUE ()); \ 224 return std::make_pair(false, defaultValue); \ 227 [](const PARAM_TYPE & param, VALUE_TYPE defaultValue) \ 229 if (param.has_##FALLBACK_VALUE ()) \ 231 return std::make_pair(true, param.FALLBACK_VALUE ()); \ 235 return std::make_pair(false, defaultValue); \ 242 const std::map<std::string, CaffeParserBase::OperationParsingFunction>
275 : m_Network(nullptr, nullptr)
297 const char* bindingPointDesc,
298 const std::unordered_map<std::string, BindingPointInfo>& nameToBindingInfo)
300 auto it = nameToBindingInfo.find(layerName);
301 if (it == nameToBindingInfo.end())
306 "Unknown binding %1% for layer '%2%'. %3%") %
316 std::vector<unsigned int> shape;
317 for (
int j = 0; j < blobShape.dim_size(); ++j)
319 shape.push_back(static_cast<unsigned int>(blobShape.dim(j)));
322 return TensorInfo(boost::numeric_cast<unsigned int>(shape.size()), shape.data(), DataType::Float32);
331 ret.set_dim(boost::numeric_cast<int>(i), desc.
GetShape()[i]);
341 std::vector<const caffe::LayerParameter*> ret;
342 ret.reserve(boost::numeric_cast<size_t>(layerParam.bottom_size()));
343 for (
int j = 0; j < layerParam.bottom_size(); ++j)
345 std::string inputName = layerParam.bottom(j);
352 "Can't find Caffe layer with top called '%1%', " 353 "which is listed as an input of '%2%'. %3%") %
358 ret.push_back(inputIt->second);
366 BOOST_ASSERT(layerParam.type() ==
"Input");
367 ValidateNumInputsOutputs(layerParam, 0, 1);
369 const InputParameter& param = layerParam.input_param();
379 const BlobShape* originalShape = param.shape_size() > 0 && param.shape(0).dim_size() > 0 ?
380 ¶m.shape(0) :
nullptr;
389 const TensorShape& overrideShape = overrideIt->second;
391 ( originalShape->dim(1) != overrideShape[1]
392 || originalShape->dim(2) != overrideShape[2]
393 || originalShape->dim(3) != overrideShape[3]))
398 "Parsed input shape for '%1%' is incompatible with the override provided. %2%") %
402 inputTensorInfo.
SetShape(overrideShape);
404 else if (!originalShape)
409 "No input descriptor given for '%1%' and no input shape found in caffe model. %2%") %
415 inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo);
421 unsigned int kernelW,
422 unsigned int kernelH)
424 BOOST_ASSERT(layerParam.type() ==
"Convolution");
425 ValidateNumInputsOutputs(layerParam, 1, 1);
427 ConvolutionParameter convParam = layerParam.convolution_param();
429 const unsigned int numGroups = convParam.has_group() ? convParam.group() : 1;
432 BOOST_ASSERT(numGroups < inputShape.dim(1));
433 BOOST_ASSERT(numGroups > 1);
438 vector<string> convLayerNames(numGroups);
439 vector<armnn::IConnectableLayer*> convLayers(numGroups);
440 convLayerNames[0] = layerParam.name();
445 unsigned int splitterDimSizes[4] = {
static_cast<unsigned int>(inputShape.dim(0)),
446 static_cast<unsigned int>(inputShape.dim(1)),
447 static_cast<unsigned int>(inputShape.dim(2)),
448 static_cast<unsigned int>(inputShape.dim(3))};
453 splitterDimSizes[1] /= numGroups;
454 inputShape.set_dim(1, splitterDimSizes[1]);
460 for (
unsigned int g = 0; g < numGroups; ++g)
464 ss << layerParam.name() <<
"_" << g;
465 convLayerNames[g] = ss.str();
470 for (
unsigned int dimIdx=0; dimIdx < 4; dimIdx++)
472 splitterDesc.
SetViewSize(g, dimIdx, splitterDimSizes[dimIdx]);
476 const std::string splitterLayerName = std::string(
"splitter_") + layerParam.bottom(0);
485 unsigned int numFilters = convParam.num_output();
488 BlobShape outputShape;
489 outputShape.add_dim(0);
490 outputShape.set_dim(0, inputShape.dim(0));
491 outputShape.add_dim(1);
493 outputShape.set_dim(1, numFilters / numGroups);
494 outputShape.add_dim(2);
496 2, (static_cast<int>(
497 static_cast<float>(inputShape.dim(2) + 2 * desc.
m_PadBottom - kernelH) /
498 static_cast<float>(desc.
m_StrideY)) + 1));
499 outputShape.add_dim(3);
501 3, (static_cast<int>(
502 static_cast<float>(inputShape.dim(3) + 2 * desc.
m_PadRight - kernelW) /
503 static_cast<float>(desc.
m_StrideX)) + 1));
506 vector<float> weightData(boost::numeric_cast<size_t>(numGroups *
511 GetDataFromBlob(layerParam, weightData, 0);
513 const unsigned int weightDimSizes[4] = {
514 static_cast<unsigned int>(outputShape.dim(1)),
515 static_cast<unsigned int>(inputShape.dim(1)),
520 vector<float> biasData;
524 biasData.resize(boost::numeric_cast<size_t>(numGroups * outputShape.dim(1)), 1.f);
525 GetDataFromBlob(layerParam, biasData, 1);
527 const unsigned int biasDimSizes[1] = {
static_cast<unsigned int>(outputShape.dim(1))};
528 biasInfo =
TensorInfo(1, biasDimSizes, DataType::Float32);
531 const unsigned int numWeightsPerGroup = boost::numeric_cast<
unsigned int>(weightData.size()) / numGroups;
532 const unsigned int numBiasesPerGroup = boost::numeric_cast<
unsigned int>(biasData.size()) / numGroups;
534 for (
unsigned int g = 0; g < numGroups; ++g)
541 weightData.data() + numWeightsPerGroup * g);
548 ConstTensor biases(biasInfo, biasData.data() + numBiasesPerGroup * g);
551 convLayer =
m_Network->AddConvolution2dLayer(desc,
554 convLayerNames[g].c_str());
555 convLayers[g] = convLayer;
560 splitterLayer ? splitterLayer->
GetOutputSlot(g) : inputConnection;
561 splitterInputConnection.
Connect(convLayer->GetInputSlot(0));
568 unsigned int concatDimSizes[4] = {
static_cast<unsigned int>(outputShape.dim(0)),
569 static_cast<unsigned int>(outputShape.dim(1)),
570 static_cast<unsigned int>(outputShape.dim(2)),
571 static_cast<unsigned int>(outputShape.dim(3))};
578 for (
unsigned int g = 0; g < numGroups; ++g)
584 concatDimSizes[1] *= numGroups;
585 outputShape.set_dim(1, concatDimSizes[1]);
595 "Failed to create final concat layer for Split+Convolution+Concat. " 596 "Layer=%1% #groups=%2% #filters=%3% %4%") %
603 for (
unsigned int g = 0; g < numGroups; ++g)
605 convLayers[g]->GetOutputSlot(0).Connect(concatLayer->
GetInputSlot(g));
613 unsigned int kernelW,
614 unsigned int kernelH)
616 BOOST_ASSERT(layerParam.type() ==
"Convolution");
617 ValidateNumInputsOutputs(layerParam, 1, 1);
619 ConvolutionParameter convParam = layerParam.convolution_param();
631 unsigned int numFilters = convParam.num_output();
633 BlobShape outputShape;
634 outputShape.add_dim(0);
635 outputShape.set_dim(0, inputShape.dim(0));
636 outputShape.add_dim(1);
637 outputShape.set_dim(1, numFilters);
638 outputShape.add_dim(2);
640 2, (static_cast<int>(
641 static_cast<float>(inputShape.dim(2) + 2 * desc.m_PadBottom - kernelH) /
642 static_cast<float>(desc.m_StrideY)) + 1));
643 outputShape.add_dim(3);
645 3, (static_cast<int>(
646 static_cast<float>(inputShape.dim(3) + 2 * desc.m_PadRight - kernelW) /
647 static_cast<float>(desc.m_StrideX)) + 1));
650 size_t allWeightsSize = boost::numeric_cast<
size_t>(inputShape.dim(1) * kernelH * kernelW);
651 vector<float> weightData(allWeightsSize);
653 GetDataFromBlob(layerParam, weightData, 0);
656 const unsigned int weightDimSizes[4] = {
657 static_cast<unsigned int>(1),
658 static_cast<unsigned int>(inputShape.dim(1)),
665 vector<float> biasData;
666 if (desc.m_BiasEnabled)
670 biasData.resize(boost::numeric_cast<size_t>(outputShape.dim(1)), 1.f);
671 GetDataFromBlob(layerParam, biasData, 1);
673 const unsigned int biasDimSizes[1] = {
static_cast<unsigned int>(outputShape.dim(1))};
674 biasInfo =
TensorInfo(1, biasDimSizes, DataType::Float32);
679 returnLayer =
m_Network->AddDepthwiseConvolution2dLayer(desc,
682 layerParam.name().c_str());
689 "Failed to create depthwise convolution layer. " 690 "Layer=%1% #filters=%2% %3%") %
696 inputConnection.
Connect(returnLayer->GetInputSlot(0));
714 BOOST_ASSERT(layerParam.type() ==
"Convolution");
715 ValidateNumInputsOutputs(layerParam, 1, 1);
717 ConvolutionParameter convParam = layerParam.convolution_param();
719 const unsigned int numGroups = convParam.has_group() ? convParam.group() : 1;
720 unsigned int numFilters = convParam.num_output();
722 const auto notFound = std::numeric_limits<unsigned int>::max();
725 kernel_h, kernel_size,
unsigned int, notFound);
727 kernel_w, kernel_size,
unsigned int, notFound);
730 stride_h, stride,
unsigned int, 1u);
732 stride_w, stride,
unsigned int, 1u);
735 pad_h, pad,
unsigned int, 0u);
737 pad_w, pad,
unsigned int, 0u);
740 convolution2dDescriptor.
m_PadLeft = padW;
742 convolution2dDescriptor.
m_PadTop = padH;
744 convolution2dDescriptor.
m_StrideX = strideW;
745 convolution2dDescriptor.
m_StrideY = strideH;
746 convolution2dDescriptor.
m_BiasEnabled = convParam.has_bias_term() ? convParam.bias_term() :
true;
748 if (numGroups > numFilters)
753 "Error parsing Convolution: %1%. " 754 "The 'group'=%2% parameter cannot be larger than the " 755 "number of filters supplied ='%3%'. %4%") %
762 if (inputShape.dim_size() != 4)
767 "Convolution input shape is expected to have 4 dimensions. " 768 "%1%'s input has only %2%. %3%") %
770 inputShape.dim_size() %
776 if (numGroups > inputShape.dim(1))
781 "Error parsing Convolution: %1%. " 782 "The 'group'=%2% parameter cannot be larger than the " 783 "channel of the input shape=%3% (in NCHW format). %4%") %
789 else if (numGroups == inputShape.dim(1))
809 BlobShape outputShape;
810 outputShape.add_dim(0);
811 outputShape.set_dim(0, inputShape.dim(0));
812 outputShape.add_dim(1);
813 outputShape.set_dim(1, numFilters);
814 outputShape.add_dim(2);
816 2, (static_cast<int>(
817 static_cast<float>(inputShape.dim(2) + 2 * padH - kernelH) /
818 static_cast<float>(strideH)) + 1));
819 outputShape.add_dim(3);
821 3, (static_cast<int>(
822 static_cast<float>(inputShape.dim(3) + 2 * padW - kernelW) /
823 static_cast<float>(strideW)) + 1));
826 vector<float> weightData(boost::numeric_cast<size_t>(inputShape.dim(1) *
830 GetDataFromBlob(layerParam, weightData, 0);
832 const unsigned int weightDimSizes[4] = {
833 static_cast<unsigned int>(outputShape.dim(1)),
834 static_cast<unsigned int>(inputShape.dim(1)),
843 vector<float> biasData;
848 biasData.resize(boost::numeric_cast<size_t>(outputShape.dim(1)), 1.f);
849 GetDataFromBlob(layerParam, biasData, 1);
851 const unsigned int biasDimSizes[1] = {
static_cast<unsigned int>(outputShape.dim(1))};
852 biasInfo =
TensorInfo(1, biasDimSizes, DataType::Float32);
858 returnLayer =
m_Network->AddConvolution2dLayer(convolution2dDescriptor,
861 layerParam.name().c_str());
864 inputConnection.
Connect(returnLayer->GetInputSlot(0));
872 "Failed to create Convolution layer. " 873 "Layer=%1% #groups=%2% #filters=%3% %4%") %
889 ValidateNumInputsOutputs(layerParam, 1, 1);
890 PoolingParameter param = layerParam.pooling_param();
893 const auto notFound = std::numeric_limits<unsigned int>::max();
896 kernel_h, kernel_size,
unsigned int, notFound);
898 kernel_w, kernel_size,
unsigned int, notFound);
900 if ((kernel_h == notFound || kernel_w == notFound) && param.has_global_pooling())
907 stride_h, stride,
unsigned int, notFound);
909 stride_h, stride,
unsigned int, notFound);
911 if ((stride_h == notFound || stride_w == notFound) && param.has_global_pooling())
918 pad_h, pad,
unsigned int, 0u);
920 pad_w, pad,
unsigned int, 0u);
924 if (param.has_pool())
926 PoolingParameter_PoolMethod p = param.pool();
929 case PoolingParameter_PoolMethod_MAX:
931 pooling2dDescriptor.
m_PoolType = PoolingAlgorithm::Max;
934 case PoolingParameter_PoolMethod_AVE:
936 pooling2dDescriptor.
m_PoolType = PoolingAlgorithm::Average;
939 case PoolingParameter_PoolMethod_STOCHASTIC:
944 "Pooling Layer: Stochastic Pooling Not Supported. Layer=%1% %2%") %
953 "Pooling Layer: unknown pooling method: %1% for layer: %2% %3%") %
965 "No Pooling Method Defined for %1% %2%") %
972 pooling2dDescriptor.
m_PadTop = pad_h;
974 pooling2dDescriptor.
m_StrideX = stride_w;
975 pooling2dDescriptor.
m_StrideY = stride_h;
983 layerParam.name().c_str());
988 static_cast<unsigned int>(ceil(
989 static_cast<float>(inputInfo.
GetShape()[2] + 2 * pad_h - kernel_h) /
990 boost::numeric_cast<float>(stride_h))) + 1,
991 static_cast<unsigned int>(ceil(
992 static_cast<float>(inputInfo.
GetShape()[3] + 2 * pad_w - kernel_w) /
993 boost::numeric_cast<float>(stride_w))) + 1 },
1003 ValidateNumInputsOutputs(layerParam, 1, 1);
1005 const string& name = layerParam.name();
1006 const ReLUParameter& param = layerParam.relu_param();
1009 const float negativeSlope = param.negative_slope();
1010 if (negativeSlope == 0.0f)
1012 activationDescriptor.
m_Function = ActivationFunction::ReLu;
1016 activationDescriptor.
m_Function = ActivationFunction::LeakyReLu;
1017 activationDescriptor.
m_A = negativeSlope;
1029 ValidateNumInputsOutputs(layerParam, 1, 1);
1031 LRNParameter param = layerParam.lrn_param();
1041 if (param.has_norm_region())
1043 LRNParameter_NormRegion n = param.norm_region();
1046 case LRNParameter_NormRegion_ACROSS_CHANNELS:
1048 normalizationDescriptor.
m_NormChannelType = NormalizationAlgorithmChannel::Across;
1051 case LRNParameter_NormRegion_WITHIN_CHANNEL:
1053 normalizationDescriptor.
m_NormChannelType = NormalizationAlgorithmChannel::Within;
1061 "Unknown region %1% for LRN layer %2% %3%") %
1071 normalizationDescriptor.
m_NormChannelType = NormalizationAlgorithmChannel::Across;
1074 normalizationDescriptor.
m_NormMethodType = NormalizationAlgorithmMethod::LocalBrightness;
1075 if (param.has_local_size())
1077 normalizationDescriptor.
m_NormSize = param.local_size();
1084 "local_size not defined for LRN layer %1% %2%") %
1089 if (param.has_alpha())
1091 normalizationDescriptor.
m_Alpha = param.alpha();
1092 normalizationDescriptor.
m_Alpha /= boost::numeric_cast<
float>(param.local_size());
1099 "Alpha not defined for LRN layer %1% %2%") %
1103 if (param.has_beta())
1105 normalizationDescriptor.
m_Beta = param.beta();
1112 "Beta not defined for LRN layer %1% %2%") %
1119 normalizationDescriptor.
m_K = param.k();
1123 normalizationDescriptor.
m_K = 1;
1127 layerParam.name().c_str());
1136 InnerProductParameter param = layerParam.inner_product_param();
1138 ValidateNumInputsOutputs(layerParam, 1, 1);
1140 unsigned int outputSize = param.num_output();
1150 if (param.has_transpose())
1167 unsigned int inputSize = inputInfo.
GetShape()[1];
1170 inputSize *= inputInfo.
GetShape()[i];
1173 const float* weightDataPtr = GetArrayPtrFromBlob(layerParam, 0);
1174 const unsigned int swTD[2] = { outputSize, inputSize };
1183 const float* biasDataPtr = GetArrayPtrFromBlob(layerParam, 1);
1185 const unsigned int sbTD[1] = { outputSize };
1189 fullyConnectedLayer =
m_Network->AddFullyConnectedLayer(tensorFullyConnectedDescriptor,
1192 layerParam.name().c_str());
1196 fullyConnectedLayer =
m_Network->AddFullyConnectedLayer(tensorFullyConnectedDescriptor,
1199 layerParam.name().c_str());
1210 ValidateNumInputsOutputs(layerParam, 1, 1);
1212 SoftmaxParameter param = layerParam.softmax_param();
1221 softmaxDescriptor.
m_Axis = 1;
1224 layerParam.name().c_str());
1232 ValidateNumInputsOutputs(layerParam, 2, 1);
1239 EltwiseParameter_EltwiseOp operation = EltwiseParameter_EltwiseOp_SUM;
1241 if (layerParam.has_eltwise_param() && layerParam.eltwise_param().has_operation())
1243 operation = layerParam.eltwise_param().operation();
1249 case EltwiseParameter_EltwiseOp_SUM:
1251 newLayer =
m_Network->AddAdditionLayer(layerParam.name().c_str());
1254 case EltwiseParameter_EltwiseOp_PROD:
1256 newLayer =
m_Network->AddMultiplicationLayer(layerParam.name().c_str());
1264 "Unsupported operation %1% in Eltwise layer %2% %3%") %
1279 unsigned int numInputs =
static_cast<unsigned int>(layerParam.bottom_size());
1281 unsigned int concatDim = 1;
1282 unsigned int numOfDims = 4;
1285 OriginsDescriptor concatDescriptor(static_cast<uint32_t>(numInputs), numOfDims);
1286 std::vector<unsigned int>mergeDimSizes(numOfDims, 0u);
1288 unsigned int mergeDim = 0;
1289 for (
unsigned int viewIndex = 0; viewIndex < numInputs; ++viewIndex)
1292 layerParam.bottom(boost::numeric_cast<int>(viewIndex))).
GetTensorInfo();
1299 "The number of dimensions for input tensors of " 1300 "the concatenation op should be 4. Inputs of %1% has " 1301 "%2% dimensions. %3%") %
1307 mergeDimSizes[0] = inputInfo.
GetShape()[0];
1308 mergeDimSizes[1] = inputInfo.
GetShape()[1];
1309 mergeDimSizes[2] = inputInfo.
GetShape()[2];
1310 mergeDimSizes[3] = inputInfo.
GetShape()[3];
1312 for (
unsigned int j = 0; j < concatDim; ++j)
1318 mergeDim += mergeDimSizes[concatDim];
1320 for (
unsigned int j = concatDim+1; j < numOfDims; ++j)
1325 mergeDimSizes[concatDim] = mergeDim;
1328 for (
unsigned int i = 0; i < numInputs; ++i)
1340 ValidateNumInputsOutputs(layerParam, 1, 1);
1344 string name = layerParam.name();
1346 BatchNormParameter param = layerParam.batch_norm_param();
1349 if (param.has_use_global_stats())
1351 if (!param.use_global_stats())
1356 "Error parsing Batch Norm layer '%1%': " 1357 "Parameter 'use_global_stats' is set to false, which is " 1358 "unsupported (value used for training). %2%") %
1365 desc.
m_Eps = param.eps();
1367 unsigned int channels = inputInfo.
GetShape()[1];
1368 unsigned int shape[] = {channels};
1370 vector<float> meanData(channels);
1371 GetDataFromBlob(layerParam, meanData, 0);
1373 vector<float> varianceData(channels);
1374 GetDataFromBlob(layerParam, varianceData, 1);
1377 const BlobProto& blob = layerParam.blobs(boost::numeric_cast<int>(2));
1378 const float movingAverageFactor = blob.data(boost::numeric_cast<int>(0));
1379 if(movingAverageFactor != 0.0f)
1381 const float scaleFactor = 1.0f / movingAverageFactor;
1382 auto scaleFunction = [scaleFactor](
float f) ->
float {
return f * scaleFactor; };
1384 std::transform(varianceData.begin(), varianceData.end(), varianceData.begin(), scaleFunction);
1385 std::transform(meanData.begin(), meanData.end(), meanData.begin(), scaleFunction);
1389 vector<float> betaData(channels, 0.0f);
1390 vector<float> gammaData(channels, 1.0f);
1398 mean, variance, beta, gamma, name.c_str());
1407 ValidateNumInputsOutputs(layerParam, 1, 1);
1411 string name = layerParam.name();
1413 ScaleParameter param = layerParam.scale_param();
1414 if (param.axis() != 1)
1420 "Loading Scale Layer: Only axis 1 is supported currently. " 1421 "Layer=%1% Axis=%2% %3%") %
1427 unsigned int channels = inputInfo.
GetShape()[1];
1428 unsigned int shape[] = {channels};
1432 vector<float> meanData(channels, 0.0f);
1433 vector<float> varianceData(channels, 1.0f);
1434 vector<float> betaData(channels, 0.0f);
1435 vector<float> gammaData(channels);
1437 GetDataFromBlob(layerParam, gammaData, 0);
1439 if(param.has_bias_term())
1441 GetDataFromBlob(layerParam, betaData, 1);
1450 mean, variance, beta, gamma, name.c_str());
1459 if (layerParam.bottom_size() != 1)
1464 "Split layer '%1%' should have exactly 1 bottom. " 1465 "#bottoms=%2% %3%") %
1467 layerParam.bottom_size() %
1471 for (
int i = 0; i < layerParam.top_size(); i++)
1480 if (layerParam.bottom_size() != 1 || layerParam.top_size() != 1)
1485 "Dropout layer '%1%' should have exactly 1 bottom and 1 top. " 1486 "#bottoms=%2% #tops=%3% %4%") %
1488 layerParam.bottom_size() %
1489 layerParam.top_size() %
1512 const char* bindingPointDesc,
1513 std::unordered_map<std::string, BindingPointInfo>& nameToBindingInfo)
1515 const std::string layerName = layer->
GetName();
1516 auto it = nameToBindingInfo.find(layerName);
1517 if (it == nameToBindingInfo.end())
1519 nameToBindingInfo[layerName] = std::make_pair(
id, tensorInfo);
1526 "Id %1% used by more than one %2% layer %3%") %
1545 "Could not find armnn output slot for Caffe top '%1%' %2%") %
1564 "Attempting to add duplicate entry for Caffe top '%1%' %2%") %
1575 std::map<std::string, std::vector<caffe::LayerParameter*>> layersByTop;
1576 for (
int layerIdx = 0; layerIdx < netParameter.layer_size(); ++layerIdx)
1578 caffe::LayerParameter& layer = *netParameter.mutable_layer(layerIdx);
1579 std::string name = layer.name();
1580 for (
int i = 0; i < layer.top_size(); ++i)
1582 layersByTop[layer.top(i)].push_back(&layer);
1588 for (
auto layersWithSameTopIt : layersByTop)
1590 const std::string& top = layersWithSameTopIt.first;
1591 const std::vector<caffe::LayerParameter*>& layersWithSameTop = layersWithSameTopIt.second;
1595 for (
unsigned int layerIdx = 0; layerIdx < layersWithSameTop.size() - 1; ++layerIdx)
1597 caffe::LayerParameter& layer1 = *layersWithSameTop[layerIdx];
1598 caffe::LayerParameter& layer2 = *layersWithSameTop[layerIdx+1];
1599 if (layer1.top_size() != 1)
1604 "Node '%1%' is an in-place layer but doesn't have exactly one " 1605 "top. It has %2% instead. %3%") %
1610 std::string newTop = layer1.name() +
"_top";
1611 layer1.set_top(0, newTop);
1612 if (layer2.bottom_size() != 1 || layer2.bottom(0) != top)
1617 "Node '%1%' is an in-place layer but " 1618 "doesn't have exactly one bottom, or it doesn't match its top. " 1619 "#bottoms=%2%, first bottom is %3%, top is %4% %5%") %
1625 layer2.set_bottom(0, newTop);
1636 if (netParameter.input_size() > 0)
1638 LayerParameter* newLayer = netParameter.add_layer();
1640 newLayer->set_type(
"Input");
1641 newLayer->set_name(netParameter.input(0));
1642 newLayer->add_top(netParameter.input(0));
1644 InputParameter* inputParam = newLayer->mutable_input_param();
1645 BlobShape* shape = inputParam->add_shape();
1647 int dim_size = netParameter.input_dim_size();
1648 for (
int i = 0; i < dim_size; ++i)
1650 shape->add_dim(netParameter.input_dim(i));
1658 for (
int i = 0; i < netParameter.layer_size(); ++i)
1660 const caffe::LayerParameter& layer = netParameter.layer(i);
1661 for (
int i = 0; i < layer.top_size(); ++i)
1668 std::vector<const caffe::LayerParameter*> targetLayers;
1677 "Couldn't find requested output layer '%1%' in graph %2%") %
1678 requestedOutputName %
1681 targetLayers.push_back(nodeIt->second);
1685 std::vector<const caffe::LayerParameter*> sortedNodes;
1686 if (!armnnUtils::GraphTopologicalSort<const caffe::LayerParameter*>(
1688 [
this](
const caffe::LayerParameter* node)
1697 "Cycle detected in graph. #nodes: %1% %2%") %
1698 sortedNodes.size() %
1703 for (
const caffe::LayerParameter* current : sortedNodes)
1710 boost::format(
"Unsupported layer type: '%1%' for layer %2% %3%") %
1715 auto func = it->second;
1716 (this->*func)(*current);
1720 for (
const std::string& requestedOutput : m_RequestedOutputs)
1727 outputSlot.
Connect(outputLayer->GetInputSlot(0));
1729 TrackOutputBinding(outputLayer, outputId, outputLayer->GetInputSlot(0).GetConnection()->GetTensorInfo());
1734 const std::map<std::string, armnn::TensorShape>& inputShapes,
1735 const std::vector<std::string>& requestedOutputs)
1737 FILE* fd = fopen(graphFile,
"r");
1744 "Failed to open graph file: %1% %2%") %
1750 NetParameter netParam;
1751 auto input =
new google::protobuf::io::FileInputStream(fileno(fd));
1752 bool success = google::protobuf::TextFormat::Parse(input, &netParam);
1761 "Failed to parse graph file: %1% %2%") %
1770 const std::map<std::string, armnn::TensorShape>& inputShapes,
1771 const std::vector<std::string>& requestedOutputs)
1774 NetParameter netParam;
1775 bool success = google::protobuf::TextFormat::ParseFromString(protoText, &netParam);
1782 "Failed to parse graph string %1%") %
1790 const std::map<std::string, armnn::TensorShape>& inputShapes,
1791 const std::vector<std::string>& requestedOutputs)
1793 FILE* fd = fopen(graphFile,
"rb");
1800 "Failed to open graph file at: %1% %2%") %
1806 NetParameter netParam;
1808 FileInputStream inStream(fileno(fd));
1809 CodedInputStream codedStream(&inStream);
1810 codedStream.SetTotalBytesLimit(INT_MAX, INT_MAX);
1811 bool success = netParam.ParseFromCodedStream(&codedStream);
1819 "Failed to parse protobuf file: %1% %2%") %
1830 const std::map<std::string, armnn::TensorShape>& inputShapes,
1831 const std::vector<std::string>& requestedOutputs)
1839 if (requestedOutputs.size() == 0)
1841 throw ParseException(
"requestedOutputs must have at least one entry");
float m_A
Alpha upper bound value used by the activation functions. (BoundedReLu, Linear, TanH).
void ParseConcatLayer(const caffe::LayerParameter &layerParam)
virtual const IInputSlot & GetInputSlot(unsigned int index) const =0
uint32_t m_PadRight
Padding right value in the width dimension.
void ParseInnerProductLayer(const caffe::LayerParameter &layerParam)
A NormalizationDescriptor for the NormalizationLayer.
A tensor defined by a TensorInfo (shape and data type) and an immutable backing store.
float m_Alpha
Alpha value for the normalization equation.
void ParseSoftmaxLayer(const caffe::LayerParameter &layerParam)
BlobShape TensorDescToBlobShape(const TensorInfo &desc)
uint32_t m_PadLeft
Padding left value in the width dimension.
unsigned int GetNumDimensions() const
armnn::TensorInfo GetTensorInfo(unsigned int numberOfBatches, unsigned int numberOfChannels, unsigned int height, unsigned int width, const armnn::DataLayout dataLayout, const armnn::DataType dataType)
uint32_t m_PoolHeight
Pooling height value.
armnn::IOutputSlot & GetArmnnOutputSlotForCaffeTop(const std::string &caffeTopName) const
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 TrackOutputBinding(armnn::IConnectableLayer *layer, armnn::LayerBindingId id, const armnn::TensorInfo &tensorInfo)
void ParseConvLayer(const caffe::LayerParameter &layerParam)
uint32_t m_PadTop
Padding top value in the height dimension.
An ActivationDescriptor for the ActivationLayer.
A BatchNormalizationDescriptor for the BatchNormalizationLayer.
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. The arguments are: view, dimension, value. If the view is greater than or ...
std::pair< armnn::LayerBindingId, armnn::TensorInfo > BindingPointInfo
#define GET_OPTIONAL_WITH_FALLBACK(PARAM, PARAM_TYPE, OPTIONAL_VALUE, FALLBACK_VALUE, VALUE_TYPE, DEFAULT_VALUE)
void ResolveInPlaceLayers(caffe::NetParameter &netParameter)
std::unique_ptr< ICaffeParser, void(*)(ICaffeParser *parser)> ICaffeParserPtr
void ParseReluLayer(const caffe::LayerParameter &layerParam)
Status SetViewOriginCoord(uint32_t view, uint32_t coord, uint32_t value)
uint32_t m_PadBottom
Padding bottom value in the height dimension.
Status SetViewOriginCoord(uint32_t view, uint32_t coord, uint32_t value)
void AddConvLayerWithSplits(const caffe::LayerParameter &layerParam, const armnn::Convolution2dDescriptor &desc, unsigned int kernelW, unsigned int kernelH)
void ParseLRNLayer(const caffe::LayerParameter &layerParam)
bool m_BiasEnabled
Enable/disable bias.
A ViewsDescriptor for the SplitterLayer. Descriptor to configure the splitting process. Number of Views must be equal to the number of outputs, and their order must match - e.g. first view corresponds to the first output, second view to the second output, etc.
uint32_t m_StrideY
Stride value when proceeding through input for the height dimension.
static ICaffeParserPtr Create()
virtual const char * GetName() const =0
virtual void SetTensorInfo(const TensorInfo &tensorInfo)=0
uint32_t m_PadTop
Padding top value in the height dimension.
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...
std::vector< const caffe::LayerParameter * > GetInputs(const caffe::LayerParameter &layerParam)
Find the Caffe layers listed as inputs (bottoms) for a given layer.
uint32_t m_PadLeft
Padding left value in the width dimension.
static ICaffeParser * CreateRaw()
uint32_t m_PoolWidth
Pooling width value.
std::vector< std::string > m_RequestedOutputs
void ParseDropoutLayer(const caffe::LayerParameter &layerParam)
uint32_t m_StrideX
Stride value when proceeding through input for the width dimension.
void ParseSplitLayer(const caffe::LayerParameter &layerParam)
void ParseEltwiseLayer(const caffe::LayerParameter &layerParam)
#define GET_OPTIONAL_WITH_VECTOR_FALLBACK(PARAM, PARAM_TYPE, OPTIONAL_VALUE, FALLBACK_VECTOR, VALUE_TYPE, DEFAULT_VALUE)
uint32_t m_NormSize
Depth radius value.
void ParsePoolingLayer(const caffe::LayerParameter &layerParam)
void SetArmnnOutputSlotForCaffeTop(const std::string &caffeTopName, armnn::IOutputSlot &armnnOutputSlot)
static void TrackBindingPoint(armnn::IConnectableLayer *layer, armnn::LayerBindingId id, const armnn::TensorInfo &tensorInfo, const char *bindingPointDesc, std::unordered_map< std::string, BindingPointInfo > &nameToBindingInfo)
virtual unsigned int GetNumOutputSlots() const =0
uint32_t m_PadLeft
Padding left value in the width dimension.
float m_Beta
Beta value for the normalization equation.
static INetworkPtr Create()
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::unordered_map< std::string, BindingPointInfo > m_NetworkOutputsBindingInfo
maps output layer names to their corresponding ids and tensor infos
A FullyConnectedDescriptor for the FullyConnectedLayer.
static void Destroy(ICaffeParser *parser)
bool m_TransposeWeightMatrix
Enable/disable transpose weight matrix.
float m_Eps
Value to add to the variance. Used to avoid dividing by zero.
void ParseInputLayer(const caffe::LayerParameter &layerParam)
void SetShape(const TensorShape &newShape)
PaddingMethod m_PaddingMethod
The padding method to be used. (Exclude, IgnoreValue).
std::unique_ptr< INetwork, void(*)(INetwork *network)> INetworkPtr
bool m_BiasEnabled
Enable/disable bias.
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...
void TrackInputBinding(armnn::IConnectableLayer *layer, armnn::LayerBindingId id, const armnn::TensorInfo &tensorInfo)
OutputShapeRounding m_OutputShapeRounding
The rounding method for the output shape. (Floor, Ceiling).
void AddConvLayerWithDepthwiseConv(const caffe::LayerParameter &layerParam, const armnn::Convolution2dDescriptor &desc, unsigned int kernelW, unsigned int kernelH)
armnn::INetworkPtr m_Network
ActivationFunction m_Function
The activation function to use (Sigmoid, TanH, Linear, ReLu, BoundedReLu, SoftReLu, LeakyReLu, Abs, Sqrt, Square).
A SoftmaxDescriptor for the SoftmaxLayer.
An output connection slot for a layer. The output slot may be connected to 1 or more input slots of s...
NormalizationAlgorithmMethod m_NormMethodType
Normalization method algorithm to use (LocalBrightness, LocalContrast).
uint32_t m_StrideY
Stride value when proceeding through input for the height dimension.
void Connect(armnn::IConnectableLayer *from, armnn::IConnectableLayer *to, const armnn::TensorInfo &tensorInfo, unsigned int fromIndex, unsigned int toIndex)
PoolingAlgorithm m_PoolType
The pooling algorithm to use (Max. Average, L2).
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.
Interface for a layer that is connectable to other layers via InputSlots and OutputSlots.
std::unordered_map< std::string, BindingPointInfo > m_NetworkInputsBindingInfo
maps input layer names to their corresponding ids and tensor infos
A Pooling2dDescriptor for the Pooling2dLayer.
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 ParseBatchNormLayer(const caffe::LayerParameter &layerParam)
A DepthwiseConvolution2dDescriptor for the DepthwiseConvolution2dLayer.
A Convolution2dDescriptor for the Convolution2dLayer.
armnn::TensorInfo BlobShapeToTensorInfo(const caffe::BlobShape &blobShape) const
Converts Caffe's protobuf tensor shape format to ArmNN's.
virtual int Connect(IInputSlot &destination)=0
std::map< std::string, const caffe::LayerParameter * > m_CaffeLayersByTopName
uint32_t m_PadBottom
Padding bottom value in the height dimension.
int m_Axis
Scalar, defaulted to the last index (-1), specifying the dimension the activation will be performed o...
NormalizationAlgorithmChannel m_NormChannelType
Normalization channel algorithm to use (Across, Within).
const TensorShape & GetShape() const
static std::pair< armnn::LayerBindingId, armnn::TensorInfo > GetBindingInfo(const std::string &layerName, const char *bindingPointDesc, const std::unordered_map< std::string, BindingPointInfo > &bindingInfos)
uint32_t m_StrideX
Stride value when proceeding through input for the width dimension.
int LayerBindingId
Type of identifiers for bindable layers (inputs, outputs).
std::map< std::string, armnn::TensorShape > m_InputShapes
virtual const IOutputSlot & GetOutputSlot(unsigned int index) const =0
static const std::map< std::string, OperationParsingFunction > ms_CaffeLayerNameToParsingFunctions
Maps Caffe layer names to parsing member functions.
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.
void ParseScaleLayer(const caffe::LayerParameter &layerParam)
An OriginsDescriptor for the ConcatLayer. Descriptor to configure the concatenation process...
void LoadNetParam(caffe::NetParameter &netParameter)
does the actual conversion from caffe::NetParameter to armnn::INetwork