aboutsummaryrefslogtreecommitdiff
path: root/src/armnnTfLiteParser/TfLiteParser.cpp
diff options
context:
space:
mode:
authorMatteo Martincigh <matteo.martincigh@arm.com>2018-12-18 09:26:39 +0000
committerMatteo Martincigh <matteo.martincigh@arm.com>2019-01-04 17:28:07 +0000
commit747ef82c88f9afe14a8b80b6b3b34118353e97f2 (patch)
treea29ac33b84fb96a41103a0a97327189495374cc9 /src/armnnTfLiteParser/TfLiteParser.cpp
parent760892724d131c7da4b9baad05cddd49276ad6bb (diff)
downloadarmnn-747ef82c88f9afe14a8b80b6b3b34118353e97f2.tar.gz
MLCE-77 Depthwise Convolution with depth multiplier > 1 doesn't work
* Unified ArmNN's weight format to [ M, I, H, W ] for the depthwise convolution * Added conversion utilities to permute/reshape the weights as appropriate when using CL and Neon backends * Updated the reference implementation of the convolution * Updated the relevant unit tests accordingly !android-nn-driver:459 Change-Id: I07d0818efa9d1ca1e5dad82983aac1fe78eadb18
Diffstat (limited to 'src/armnnTfLiteParser/TfLiteParser.cpp')
-rw-r--r--src/armnnTfLiteParser/TfLiteParser.cpp105
1 files changed, 73 insertions, 32 deletions
diff --git a/src/armnnTfLiteParser/TfLiteParser.cpp b/src/armnnTfLiteParser/TfLiteParser.cpp
index 49bc73708f..3b50476ca2 100644
--- a/src/armnnTfLiteParser/TfLiteParser.cpp
+++ b/src/armnnTfLiteParser/TfLiteParser.cpp
@@ -401,7 +401,8 @@ template<typename T>
std::pair<armnn::ConstTensor, std::unique_ptr<T[]>>
CreateConstTensorImpl(TfLiteParser::BufferRawPtr bufferPtr,
TfLiteParser::TensorRawPtr tensorPtr,
- armnn::TensorInfo & tensorInfo)
+ armnn::TensorInfo& tensorInfo,
+ armnn::Optional<armnn::PermutationVector&> permutationVector)
{
BOOST_ASSERT_MSG(tensorPtr != nullptr, "tensorPtr is null");
BOOST_ASSERT_MSG(bufferPtr != nullptr,
@@ -409,7 +410,20 @@ CreateConstTensorImpl(TfLiteParser::BufferRawPtr bufferPtr,
boost::format("Buffer for buffer:%1% is null") % tensorPtr->buffer).c_str());
std::unique_ptr<T[]> data(new T[tensorInfo.GetNumElements()]);
- ::memcpy(data.get(), bufferPtr->data.data(), tensorInfo.GetNumBytes());
+
+ if (permutationVector.has_value() && permutationVector.value().GetSize() > 0)
+ {
+ tensorInfo = armnnUtils::Permuted(tensorInfo, permutationVector.value());
+ armnnUtils::Permute(tensorInfo.GetShape(),
+ permutationVector.value(),
+ reinterpret_cast<const T *>(bufferPtr->data.data()),
+ data.get());
+ }
+ else
+ {
+ ::memcpy(data.get(), bufferPtr->data.data(), tensorInfo.GetNumBytes());
+ }
+
return std::make_pair(ConstTensor(tensorInfo, data.get()), std::move(data));
}
@@ -660,7 +674,9 @@ void TfLiteParser::ParseConv2D(size_t subgraphIndex, size_t operatorIndex)
CalcPadding(inputHeight, filterHeight, desc.m_StrideY, desc.m_PadTop, desc.m_PadBottom, options->padding);
CalcPadding(inputWidth, filterWidth, desc.m_StrideX, desc.m_PadLeft, desc.m_PadRight, options->padding);
- auto filterTensorAndData = CreateConstTensor(inputs[1], filterTensorInfo);
+ auto filterTensorAndData = CreateConstTensor(inputs[1],
+ filterTensorInfo,
+ armnn::Optional<armnn::PermutationVector&>());
armnn::IConnectableLayer* layer;
auto layerName = boost::str(boost::format("Conv2D:%1%:%2%") % subgraphIndex % operatorIndex);
@@ -669,7 +685,9 @@ void TfLiteParser::ParseConv2D(size_t subgraphIndex, size_t operatorIndex)
{
desc.m_BiasEnabled = true;
armnn::TensorInfo biasTensorInfo = ToTensorInfo(inputs[2]);
- auto biasTensorAndData = CreateConstTensor(inputs[2], biasTensorInfo);
+ auto biasTensorAndData = CreateConstTensor(inputs[2],
+ biasTensorInfo,
+ armnn::Optional<armnn::PermutationVector&>());
layer = m_Network->AddConvolution2dLayer(desc,
filterTensorAndData.first,
biasTensorAndData.first,
@@ -723,17 +741,27 @@ void TfLiteParser::ParseDepthwiseConv2D(size_t subgraphIndex, size_t operatorInd
armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
armnn::TensorInfo filterTensorInfo = ToTensorInfo(inputs[1]);
- // assuming input is NHWC
+ // Assuming input is NHWC
unsigned int inputHeight = inputTensorInfo.GetShape()[1];
unsigned int inputWidth = inputTensorInfo.GetShape()[2];
- // assuming the filter is OHWI : Output, H, W, Input
+
+ // TensorflowLite weights come in the format [1, H, W, I * M]
unsigned int filterHeight = filterTensorInfo.GetShape()[1];
unsigned int filterWidth = filterTensorInfo.GetShape()[2];
+ // Reshape weights as [ H, W, I, M ]
+ filterTensorInfo.SetShape({ filterHeight,
+ filterWidth,
+ inputTensorInfo.GetShape()[3],
+ filterTensorInfo.GetShape()[3] / inputTensorInfo.GetShape()[3] });
+
+ // Mappings from TensorflowLite filter tensors to the ArmNN filter tensors (ArmNN weights have to be [M, I, H, W])
+ PermutationVector permutationVector{ 2, 3, 1, 0 }; // [H, W, I, M] -> [M, I, H, W]
+
CalcPadding(inputHeight, filterHeight, desc.m_StrideY, desc.m_PadTop, desc.m_PadBottom, options->padding);
CalcPadding(inputWidth, filterWidth, desc.m_StrideX, desc.m_PadLeft, desc.m_PadRight, options->padding);
- auto filterTensorAndData = CreateConstTensor(inputs[1], filterTensorInfo);
+ auto filterTensorAndData = CreateConstTensor(inputs[1], filterTensorInfo, permutationVector);
armnn::IConnectableLayer* layer;
auto layerName = boost::str(boost::format("DepthwiseConv2D:%1%:%2%") % subgraphIndex % operatorIndex);
@@ -741,7 +769,9 @@ void TfLiteParser::ParseDepthwiseConv2D(size_t subgraphIndex, size_t operatorInd
{
desc.m_BiasEnabled = true;
TensorInfo biasTensorInfo = ToTensorInfo(inputs[2]);
- auto biasTensorAndData = CreateConstTensor(inputs[2], biasTensorInfo);
+ auto biasTensorAndData = CreateConstTensor(inputs[2],
+ biasTensorInfo,
+ armnn::Optional<armnn::PermutationVector&>());
layer = m_Network->AddDepthwiseConvolution2dLayer(desc,
filterTensorAndData.first,
biasTensorAndData.first,
@@ -1228,7 +1258,9 @@ void TfLiteParser::ParseFullyConnected(size_t subgraphIndex, size_t operatorInde
% CHECK_LOCATION().AsString()));
}
- auto filterTensorAndData = CreateConstTensor(inputs[1], filterTensorInfo);
+ auto filterTensorAndData = CreateConstTensor(inputs[1],
+ filterTensorInfo,
+ armnn::Optional<armnn::PermutationVector&>());
armnn::IConnectableLayer* layer;
auto layerName = boost::str(boost::format("FullyConnected:%1%:%2%") % subgraphIndex % operatorIndex);
@@ -1236,7 +1268,9 @@ void TfLiteParser::ParseFullyConnected(size_t subgraphIndex, size_t operatorInde
{
desc.m_BiasEnabled = true;
TensorInfo biasTensorInfo = ToTensorInfo(inputs[2]);
- auto biasTensorAndData = CreateConstTensor(inputs[2], biasTensorInfo);
+ auto biasTensorAndData = CreateConstTensor(inputs[2],
+ biasTensorInfo,
+ armnn::Optional<armnn::PermutationVector&>());
layer = m_Network->AddFullyConnectedLayer(desc,
filterTensorAndData.first,
biasTensorAndData.first,
@@ -1561,9 +1595,25 @@ TfLiteParser::BufferRawPtr TfLiteParser::GetBuffer(const ModelPtr& model, size_t
return model->buffers[bufferIndex].get();
}
+template<typename T>
+std::pair<armnn::ConstTensor, TfLiteParser::SupportedDataStorage>
+TfLiteParser::CreateConstTensorAndStoreData(TfLiteParser::BufferRawPtr bufferPtr,
+ TfLiteParser::TensorRawPtr tensorPtr,
+ armnn::TensorInfo& tensorInfo,
+ armnn::Optional<armnn::PermutationVector&> permutationVector)
+{
+ auto constData = CreateConstTensorImpl<T>(bufferPtr,
+ tensorPtr,
+ tensorInfo,
+ permutationVector);
+ TfLiteParser::SupportedDataStorage storage(std::move(constData.second));
+ return std::make_pair(constData.first, std::move(storage));
+}
+
std::pair<armnn::ConstTensor, TfLiteParser::SupportedDataStorage>
TfLiteParser::CreateConstTensor(TensorRawPtr tensorPtr,
- armnn::TensorInfo & tensorInfo)
+ armnn::TensorInfo& tensorInfo,
+ armnn::Optional<armnn::PermutationVector&> permutationVector)
{
CHECK_TENSOR_PTR(tensorPtr);
auto bufferPtr = GetBuffer(m_Model, tensorPtr->buffer);
@@ -1572,29 +1622,20 @@ TfLiteParser::CreateConstTensor(TensorRawPtr tensorPtr,
switch (tensorInfo.GetDataType())
{
case armnn::DataType::Float32:
- {
- auto constData = CreateConstTensorImpl<float>(bufferPtr,
- tensorPtr,
- tensorInfo);
- SupportedDataStorage storage(std::move(constData.second));
- return std::make_pair(constData.first, std::move(storage));
- }
+ return CreateConstTensorAndStoreData<float>(bufferPtr,
+ tensorPtr,
+ tensorInfo,
+ permutationVector);
case armnn::DataType::QuantisedAsymm8:
- {
- auto constData = CreateConstTensorImpl<uint8_t>(bufferPtr,
- tensorPtr,
- tensorInfo);
- SupportedDataStorage storage(std::move(constData.second));
- return std::make_pair(constData.first, std::move(storage));
- }
+ return CreateConstTensorAndStoreData<uint8_t>(bufferPtr,
+ tensorPtr,
+ tensorInfo,
+ permutationVector);
case armnn::DataType::Signed32:
- {
- auto constData = CreateConstTensorImpl<int32_t>(bufferPtr,
- tensorPtr,
- tensorInfo);
- SupportedDataStorage storage(std::move(constData.second));
- return std::make_pair(constData.first, std::move(storage));
- }
+ return CreateConstTensorAndStoreData<int32_t>(bufferPtr,
+ tensorPtr,
+ tensorInfo,
+ permutationVector);
default:
{
std::stringstream errString;