aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSadik Armagan <sadik.armagan@arm.com>2021-03-25 07:46:55 +0000
committerSadik Armagan <sadik.armagan@arm.com>2021-03-25 07:46:55 +0000
commitf0a6dec75832604d5ab18242dc216852821a8279 (patch)
treeff25e64c62c63975a54abd16a8bff744be70d7c0 /src
parent16fb1a2d9c1d3d80c0f0b6ab549919fbabd2a0b9 (diff)
downloadarmnn-f0a6dec75832604d5ab18242dc216852821a8279.tar.gz
IVGCVSW-5736 and IVGCVSW-5743 'NonConstWeights: Update front-end and TfLiteDelegate support for FullyConnected Operator'
* Added front-end support for non-const weights for FULLY_CONNECTED operator * Added FULLY_CONNECTED end-to-end test * Updated FULLY_CONNECTED operator support in TfLite Arm NN Delegate for non-const weights * Updated the version numbers Signed-off-by: Sadik Armagan <sadik.armagan@arm.com> Change-Id: Iffa5b9aa9297aca4c02d923cce4636c88ac21faa
Diffstat (limited to 'src')
-rw-r--r--src/armnn/BackendHelper.cpp26
-rw-r--r--src/armnn/Descriptors.cpp17
-rw-r--r--src/armnn/Network.cpp69
-rw-r--r--src/armnn/Network.hpp7
-rw-r--r--src/armnn/layers/FullyConnectedLayer.cpp82
-rw-r--r--src/armnn/test/OptimizerTests.cpp8
-rw-r--r--src/armnn/test/UtilsTests.cpp12
-rw-r--r--src/armnnDeserializer/Deserializer.cpp37
-rw-r--r--src/armnnSerializer/ArmnnSchema.fbs1
-rw-r--r--src/armnnSerializer/ArmnnSchema_generated.h14
-rw-r--r--src/armnnSerializer/Serializer.cpp24
-rw-r--r--src/armnnSerializer/test/SerializerTests.cpp48
-rw-r--r--src/backends/backendsCommon/WorkloadData.cpp38
-rw-r--r--src/backends/backendsCommon/WorkloadFactory.cpp408
-rw-r--r--src/backends/backendsCommon/test/CMakeLists.txt1
-rw-r--r--src/backends/backendsCommon/test/CompatibilityTests.cpp16
-rw-r--r--src/backends/backendsCommon/test/FullyConnectedEndToEndTestImpl.hpp97
-rw-r--r--src/backends/backendsCommon/test/layerTests/FullyConnectedTestImpl.cpp105
-rw-r--r--src/backends/backendsCommon/test/layerTests/FullyConnectedTestImpl.hpp3
-rw-r--r--src/backends/cl/test/ClLayerTests.cpp4
-rw-r--r--src/backends/neon/test/NeonLayerTests.cpp4
-rw-r--r--src/backends/reference/RefBackend.cpp10
-rw-r--r--src/backends/reference/RefBackend.hpp6
-rw-r--r--src/backends/reference/test/RefEndToEndTests.cpp6
-rw-r--r--src/backends/reference/test/RefLayerTests.cpp14
-rw-r--r--src/backends/reference/workloads/RefFullyConnectedWorkload.cpp45
26 files changed, 796 insertions, 306 deletions
diff --git a/src/armnn/BackendHelper.cpp b/src/armnn/BackendHelper.cpp
index 1467366323..1c926f4d30 100644
--- a/src/armnn/BackendHelper.cpp
+++ b/src/armnn/BackendHelper.cpp
@@ -23,7 +23,21 @@ LayerSupportHandle GetILayerSupportByBackendId(const armnn::BackendId& backend)
auto factoryFunc = backendRegistry.GetFactory(backend);
auto backendObject = factoryFunc();
- return LayerSupportHandle(backendObject->GetLayerSupport());
+ return LayerSupportHandle(backendObject->GetLayerSupport(), backend);
+}
+
+/// Convenience function to check a capability on a backend
+bool IsCapabilitySupported(const armnn::BackendId& backend, armnn::BackendCapability capability)
+{
+ bool hasCapability = false;
+ auto const& backendRegistry = armnn::BackendRegistryInstance();
+ if (backendRegistry.IsBackendRegistered(backend))
+ {
+ auto factoryFunc = backendRegistry.GetFactory(backend);
+ auto backendObject = factoryFunc();
+ hasCapability = backendObject->HasCapability(capability);
+ }
+ return hasCapability;
}
bool LayerSupportHandle::IsBackendRegistered() const
@@ -293,6 +307,16 @@ bool LayerSupportHandle::IsFullyConnectedSupported(const TensorInfo& input,
const FullyConnectedDescriptor& descriptor,
Optional<std::string&> reasonIfUnsupported)
{
+ if(!descriptor.m_ConstantWeights && !m_BackendId.IsUndefined())
+ {
+ bool result = false;
+ result = IsCapabilitySupported(m_BackendId, BackendCapability::NonConstWeights);
+ if (!result)
+ {
+ return result;
+ }
+ }
+
return m_LayerSupport->IsFullyConnectedSupported(input,
output,
weights,
diff --git a/src/armnn/Descriptors.cpp b/src/armnn/Descriptors.cpp
index 881023e968..706992ccb0 100644
--- a/src/armnn/Descriptors.cpp
+++ b/src/armnn/Descriptors.cpp
@@ -425,4 +425,21 @@ int StridedSliceDescriptor::GetStopForAxis(const TensorShape& inputShape,
}
+uint32_t FullyConnectedDescriptor::GetNumViews() const
+{
+ // Return 1 with constant weights, otherwise check if bias is enabled
+ uint32_t numInputs = 1;
+ if (!m_ConstantWeights)
+ {
+ // non-const weights
+ numInputs = 2;
+ if (m_BiasEnabled)
+ {
+ // non-const bias
+ numInputs = 3;
+ }
+ }
+ return numInputs;
+}
+
}
diff --git a/src/armnn/Network.cpp b/src/armnn/Network.cpp
index 9373a6ac15..18a4d02fca 100644
--- a/src/armnn/Network.cpp
+++ b/src/armnn/Network.cpp
@@ -171,21 +171,26 @@ IConnectableLayer* INetwork::AddFillLayer(const FillDescriptor& fillDescriptor,
return pNetworkImpl->AddFillLayer(fillDescriptor, name);
}
-
IConnectableLayer* INetwork::AddFullyConnectedLayer(const FullyConnectedDescriptor& fullyConnectedDescriptor,
const ConstTensor& weights,
const Optional<ConstTensor>& biases,
const char* name)
{
- return pNetworkImpl->AddFullyConnectedLayer(fullyConnectedDescriptor, weights, biases, name);
+ return pNetworkImpl->AddFullyConnectedLayer(fullyConnectedDescriptor,
+ armnn::Optional<ConstTensor>(weights),
+ biases,
+ name);
}
IConnectableLayer* INetwork::AddFullyConnectedLayer(const FullyConnectedDescriptor& fullyConnectedDescriptor,
const ConstTensor& weights,
const char* name)
{
- Optional<ConstTensor> biases;
- return pNetworkImpl->AddFullyConnectedLayer(fullyConnectedDescriptor, weights, biases, name);
+ armnn::Optional<ConstTensor> biases;
+ return pNetworkImpl->AddFullyConnectedLayer(fullyConnectedDescriptor,
+ armnn::Optional<ConstTensor>(weights),
+ biases,
+ name);
}
IConnectableLayer* INetwork::AddFullyConnectedLayer(const FullyConnectedDescriptor& fullyConnectedDescriptor,
@@ -193,8 +198,18 @@ IConnectableLayer* INetwork::AddFullyConnectedLayer(const FullyConnectedDescript
const ConstTensor& biases,
const char* name)
{
- return pNetworkImpl->AddFullyConnectedLayer(fullyConnectedDescriptor, weights,
- armnn::Optional<ConstTensor>(biases), name);
+ return pNetworkImpl->AddFullyConnectedLayer(fullyConnectedDescriptor,
+ armnn::Optional<ConstTensor>(weights),
+ armnn::Optional<ConstTensor>(biases),
+ name);
+}
+
+IConnectableLayer* INetwork::AddFullyConnectedLayer(const FullyConnectedDescriptor& fullyConnectedDescriptor,
+ const Optional<ConstTensor>& weights,
+ const Optional<ConstTensor>& biases,
+ const char* name)
+{
+ return pNetworkImpl->AddFullyConnectedLayer(fullyConnectedDescriptor, weights, biases, name);
}
IConnectableLayer* INetwork::AddPermuteLayer(const PermuteDescriptor& permuteDescriptor,
@@ -1709,41 +1724,58 @@ IConnectableLayer* NetworkImpl::AddFillLayer(const FillDescriptor& fillDescripto
}
IConnectableLayer* NetworkImpl::AddFullyConnectedLayerImpl(const FullyConnectedDescriptor& fullyConnectedDescriptor,
- const ConstTensor& weights,
- const Optional<ConstTensor>& biases,
- const char* name)
+ const Optional<ConstTensor>& weights,
+ const Optional<ConstTensor>& biases,
+ const char* name)
{
- if (fullyConnectedDescriptor.m_BiasEnabled && !biases.has_value())
+ if (fullyConnectedDescriptor.m_ConstantWeights && !weights.has_value())
{
- throw InvalidArgumentException("AddFullyConnectedLayer: biases cannot be empty");
+ throw InvalidArgumentException("AddFullyConnectedLayer: weights cannot be empty");
+
+ if (fullyConnectedDescriptor.m_BiasEnabled && !biases.has_value())
+ {
+ throw InvalidArgumentException("AddFullyConnectedLayer: biases cannot be empty");
+ }
}
const auto layer = m_Graph->AddLayer<FullyConnectedLayer>(fullyConnectedDescriptor, name);
- layer->m_Weight = std::make_unique<ScopedCpuTensorHandle>(weights);
-
- if (fullyConnectedDescriptor.m_BiasEnabled)
+ if (fullyConnectedDescriptor.m_ConstantWeights)
{
- layer->m_Bias = std::make_unique<ScopedCpuTensorHandle>(biases.value());
+ layer->m_Weight = std::make_unique<ScopedCpuTensorHandle>(weights.value());
+ if (fullyConnectedDescriptor.m_BiasEnabled)
+ {
+ layer->m_Bias = std::make_unique<ScopedCpuTensorHandle>(biases.value());
+ }
}
return layer;
}
IConnectableLayer* NetworkImpl::AddFullyConnectedLayer(const FullyConnectedDescriptor& fullyConnectedDescriptor,
+ const Optional<ConstTensor>& weights,
+ const Optional<ConstTensor>& biases,
+ const char* name)
+{
+ return AddFullyConnectedLayerImpl(fullyConnectedDescriptor, weights, biases, name);
+}
+
+IConnectableLayer* NetworkImpl::AddFullyConnectedLayer(const FullyConnectedDescriptor& fullyConnectedDescriptor,
const ConstTensor& weights,
const Optional<ConstTensor>& biases,
const char* name)
{
- return AddFullyConnectedLayerImpl(fullyConnectedDescriptor, weights, biases, name);
+ Optional<ConstTensor> optionalWeights(weights);
+ return AddFullyConnectedLayerImpl(fullyConnectedDescriptor, optionalWeights, biases, name);
}
IConnectableLayer* NetworkImpl::AddFullyConnectedLayer(const FullyConnectedDescriptor& fullyConnectedDescriptor,
const ConstTensor& weights,
const char* name)
{
+ Optional<ConstTensor> optionalWeights(weights);
Optional<ConstTensor> biases;
- return AddFullyConnectedLayerImpl(fullyConnectedDescriptor, weights, biases, name);
+ return AddFullyConnectedLayerImpl(fullyConnectedDescriptor, optionalWeights, biases, name);
}
IConnectableLayer* NetworkImpl::AddFullyConnectedLayer(const FullyConnectedDescriptor& fullyConnectedDescriptor,
@@ -1751,8 +1783,9 @@ IConnectableLayer* NetworkImpl::AddFullyConnectedLayer(const FullyConnectedDescr
const ConstTensor& biases,
const char* name)
{
+ Optional<ConstTensor> optionalWeights(weights);
Optional<ConstTensor> optionalBiases(biases);
- return AddFullyConnectedLayerImpl(fullyConnectedDescriptor, weights, optionalBiases, name);
+ return AddFullyConnectedLayerImpl(fullyConnectedDescriptor, optionalWeights, optionalBiases, name);
}
IConnectableLayer* NetworkImpl::AddConcatLayer(const ConcatDescriptor& concatDescriptor,
diff --git a/src/armnn/Network.hpp b/src/armnn/Network.hpp
index 8f16be1684..30941ca9e4 100644
--- a/src/armnn/Network.hpp
+++ b/src/armnn/Network.hpp
@@ -104,6 +104,11 @@ public:
const char* name = nullptr);
IConnectableLayer* AddFullyConnectedLayer(const FullyConnectedDescriptor& fullyConnectedDescriptor,
+ const Optional<ConstTensor>& weights,
+ const Optional<ConstTensor>& biases,
+ const char* name = nullptr);
+
+ IConnectableLayer* AddFullyConnectedLayer(const FullyConnectedDescriptor& fullyConnectedDescriptor,
const ConstTensor& weights,
const Optional<ConstTensor>& biases,
const char* name = nullptr);
@@ -265,7 +270,7 @@ public:
private:
IConnectableLayer* AddFullyConnectedLayerImpl(const FullyConnectedDescriptor& fullyConnectedDescriptor,
- const ConstTensor& weights,
+ const Optional<ConstTensor>& weights,
const Optional<ConstTensor>& biases,
const char* name);
diff --git a/src/armnn/layers/FullyConnectedLayer.cpp b/src/armnn/layers/FullyConnectedLayer.cpp
index 0e5e5942de..6d0b57a84c 100644
--- a/src/armnn/layers/FullyConnectedLayer.cpp
+++ b/src/armnn/layers/FullyConnectedLayer.cpp
@@ -15,24 +15,25 @@ namespace armnn
{
FullyConnectedLayer::FullyConnectedLayer(const FullyConnectedDescriptor& param, const char* name)
- : LayerWithParameters(1, 1, LayerType::FullyConnected, param, name)
+ : LayerWithParameters(param.GetNumViews(), 1, LayerType::FullyConnected, param, name)
{
}
std::unique_ptr<IWorkload> FullyConnectedLayer::CreateWorkload(const IWorkloadFactory& factory) const
{
// on this level constant data should not be released..
- ARMNN_ASSERT_MSG(m_Weight != nullptr, "FullyConnectedLayer: Weights data should not be null.");
-
FullyConnectedQueueDescriptor descriptor;
-
- descriptor.m_Weight = m_Weight.get();
- if (m_Param.m_BiasEnabled)
+ if (m_Param.m_ConstantWeights)
{
- ARMNN_ASSERT_MSG(m_Bias != nullptr, "FullyConnectedLayer: Bias data should not be null.");
- descriptor.m_Bias = m_Bias.get();
+ ARMNN_ASSERT_MSG(m_Weight != nullptr, "FullyConnectedLayer: Weights data should not be null.");
+ descriptor.m_Weight = m_Weight.get();
+
+ if (m_Param.m_BiasEnabled)
+ {
+ ARMNN_ASSERT_MSG(m_Bias != nullptr, "FullyConnectedLayer: Bias data should not be null.");
+ descriptor.m_Bias = m_Bias.get();
+ }
}
-
SetAdditionalInfo(descriptor);
return factory.CreateFullyConnected(descriptor, PrepInfoAndDesc(descriptor));
@@ -41,13 +42,15 @@ std::unique_ptr<IWorkload> FullyConnectedLayer::CreateWorkload(const IWorkloadFa
FullyConnectedLayer* FullyConnectedLayer::Clone(Graph& graph) const
{
auto layer = CloneBase<FullyConnectedLayer>(graph, m_Param, GetName());
-
- layer->m_Weight = m_Weight ? std::make_unique<ScopedCpuTensorHandle>(*m_Weight) : nullptr;
- if (layer->m_Param.m_BiasEnabled)
+ if (m_Param.m_ConstantWeights)
{
- layer->m_Bias = m_Bias ? std::make_unique<ScopedCpuTensorHandle>(*m_Bias) : nullptr;
- }
+ layer->m_Weight = m_Weight ? std::make_unique<ScopedCpuTensorHandle>(*m_Weight) : nullptr;
+ if (layer->m_Param.m_BiasEnabled)
+ {
+ layer->m_Bias = m_Bias ? std::make_unique<ScopedCpuTensorHandle>(*m_Bias) : nullptr;
+ }
+ }
return std::move(layer);
}
@@ -70,11 +73,20 @@ void FullyConnectedLayer::ValidateTensorShapesFromInputs()
VerifyShapeInferenceType(outputShape, m_ShapeInferenceMethod);
- // check if we m_Weight data is not nullptr
- ARMNN_ASSERT_MSG(m_Weight != nullptr, "FullyConnectedLayer: Weights data should not be null.");
+ std::vector<TensorShape> inferredShapes;
+ if (m_Param.m_ConstantWeights)
+ {
+ // check if m_Weight data is not nullptr
+ ARMNN_ASSERT_MSG(m_Weight != nullptr, "FullyConnectedLayer: Weights data should not be null.");
- auto inferredShapes = InferOutputShapes({GetInputSlot(0).GetConnection()->GetTensorInfo().GetShape(),
- m_Weight->GetTensorInfo().GetShape() });
+ inferredShapes = InferOutputShapes({GetInputSlot(0).GetConnection()->GetTensorInfo().GetShape(),
+ m_Weight->GetTensorInfo().GetShape()});
+ }
+ else
+ {
+ inferredShapes = InferOutputShapes({GetInputSlot(0).GetConnection()->GetTensorInfo().GetShape(),
+ GetInputSlot(1).GetConnection()->GetTensorInfo().GetShape()});
+ }
ARMNN_ASSERT(inferredShapes.size() == 1);
ARMNN_ASSERT(inferredShapes[0].GetDimensionality() == Dimensionality::Specified);
@@ -89,27 +101,37 @@ Layer::ConstantTensors FullyConnectedLayer::GetConstantTensorsByRef()
void FullyConnectedLayer::Accept(ILayerVisitor& visitor) const
{
- ConstTensor weightsTensor(m_Weight->GetTensorInfo(), m_Weight->Map(true));
+ Optional<ConstTensor> optionalWeightsTensor = EmptyOptional();
Optional<ConstTensor> optionalBiasTensor = EmptyOptional();
-
- if (GetParameters().m_BiasEnabled)
+ if(GetParameters().m_ConstantWeights)
{
- ConstTensor biasTensor(m_Bias->GetTensorInfo(), m_Bias->GetConstTensor<void>());
- optionalBiasTensor = Optional<ConstTensor>(biasTensor);
+ ConstTensor weightsTensor(m_Weight->GetTensorInfo(), m_Weight->GetConstTensor<void>());
+ optionalWeightsTensor = Optional<ConstTensor>(weightsTensor);
+
+ if (GetParameters().m_BiasEnabled)
+ {
+ ConstTensor biasTensor(m_Bias->GetTensorInfo(), m_Bias->GetConstTensor<void>());
+ optionalBiasTensor = Optional<ConstTensor>(biasTensor);
+ }
}
-
- visitor.VisitFullyConnectedLayer(this, GetParameters(), weightsTensor, optionalBiasTensor, GetName());
+ visitor.VisitFullyConnectedLayer(this,
+ GetParameters(),
+ optionalWeightsTensor.value(),
+ optionalBiasTensor,
+ GetName());
}
void FullyConnectedLayer::ExecuteStrategy(IStrategy& strategy) const
{
- std::vector<armnn::ConstTensor> constTensors { {m_Weight->GetTensorInfo(), m_Weight->Map(true)} };
-
- if (GetParameters().m_BiasEnabled)
+ std::vector <armnn::ConstTensor> constTensors;
+ if(GetParameters().m_ConstantWeights)
{
- constTensors.emplace_back(ConstTensor(m_Bias->GetTensorInfo(), m_Bias->Map(true)));
+ constTensors.emplace_back(ConstTensor(m_Weight->GetTensorInfo(), m_Weight->Map(true)));
+ if (GetParameters().m_BiasEnabled)
+ {
+ constTensors.emplace_back(ConstTensor(m_Bias->GetTensorInfo(), m_Bias->Map(true)));
+ }
}
-
strategy.ExecuteStrategy(this, GetParameters(), constTensors, GetName());
}
diff --git a/src/armnn/test/OptimizerTests.cpp b/src/armnn/test/OptimizerTests.cpp
index fa860abb64..896fdfd68c 100644
--- a/src/armnn/test/OptimizerTests.cpp
+++ b/src/armnn/test/OptimizerTests.cpp
@@ -10,6 +10,7 @@
#include <Network.hpp>
#include <Optimizer.hpp>
+#include <armnn/BackendHelper.hpp>
#include <armnn/BackendRegistry.hpp>
#include <armnn/INetwork.hpp>
#include <armnn/LayerVisitorBase.hpp>
@@ -679,6 +680,13 @@ public:
};
};
+BOOST_AUTO_TEST_CASE(BackendCapabilityTest)
+{
+ BackendId backendId ="MockBackend";
+ // MockBackend does not support the NonConstWeights capability
+ BOOST_CHECK(!armnn::IsCapabilitySupported(backendId, armnn::BackendCapability::NonConstWeights));
+}
+
BOOST_AUTO_TEST_CASE(BackendHintTest)
{
class TestBackendAssignment : public LayerVisitorBase<VisitorNoThrowPolicy>
diff --git a/src/armnn/test/UtilsTests.cpp b/src/armnn/test/UtilsTests.cpp
index 7776a2d3cf..f0198cb9d4 100644
--- a/src/armnn/test/UtilsTests.cpp
+++ b/src/armnn/test/UtilsTests.cpp
@@ -278,6 +278,18 @@ BOOST_AUTO_TEST_CASE(LayerSupportHandle)
BOOST_CHECK(layerSupportObject.IsBackendRegistered());
}
+
+BOOST_AUTO_TEST_CASE(IsCapabilitySupported_CpuRef)
+{
+ BOOST_CHECK(armnn::IsCapabilitySupported(armnn::Compute::CpuRef, armnn::BackendCapability::NonConstWeights));
+}
+#endif
+
+#if defined(ARMCOMPUTENEON_ENABLED)
+BOOST_AUTO_TEST_CASE(IsCapabilitySupported_CpuAcc)
+{
+ BOOST_CHECK(!armnn::IsCapabilitySupported(armnn::Compute::CpuAcc, armnn::BackendCapability::NonConstWeights));
+}
#endif
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/armnnDeserializer/Deserializer.cpp b/src/armnnDeserializer/Deserializer.cpp
index c34797725f..633c272f00 100644
--- a/src/armnnDeserializer/Deserializer.cpp
+++ b/src/armnnDeserializer/Deserializer.cpp
@@ -1841,7 +1841,6 @@ void IDeserializer::DeserializerImpl::ParseFullyConnected(GraphPtr graph, unsign
CHECK_LAYERS(graph, 0, layerIndex);
auto inputs = GetInputs(graph, layerIndex);
CHECK_LOCATION();
- CHECK_VALID_SIZE(inputs.size(), 1);
auto outputs = GetOutputs(graph, layerIndex);
CHECK_VALID_SIZE(outputs.size(), 1);
@@ -1853,20 +1852,36 @@ void IDeserializer::DeserializerImpl::ParseFullyConnected(GraphPtr graph, unsign
armnn::FullyConnectedDescriptor fullyConnectedDescriptor;
fullyConnectedDescriptor.m_BiasEnabled = flatBufferDescriptor->biasEnabled();
fullyConnectedDescriptor.m_TransposeWeightMatrix = flatBufferDescriptor->transposeWeightsMatrix();
+ fullyConnectedDescriptor.m_ConstantWeights = flatBufferDescriptor->constantWeights();
+ uint32_t numInputs = 1;
+ if (!fullyConnectedDescriptor.m_ConstantWeights)
+ {
+ numInputs = 2;
+ if (fullyConnectedDescriptor.m_BiasEnabled)
+ {
+ numInputs = 3;
+ }
+ }
+ CHECK_VALID_SIZE(inputs.size(), numInputs);
- armnn::ConstTensor weightsTensor = ToConstTensor(flatBufferLayer->weights());
-
- armnn::IConnectableLayer* layer;
+ armnn::Optional <armnn::ConstTensor> optionalWeights = armnn::EmptyOptional();
armnn::Optional<armnn::ConstTensor> optionalBiases = armnn::EmptyOptional();
- if (flatBufferDescriptor->biasEnabled())
+ if (fullyConnectedDescriptor.m_ConstantWeights)
{
- armnn::ConstTensor biasTensorData = ToConstTensor(flatBufferLayer->biases());
- optionalBiases = armnn::Optional<armnn::ConstTensor>(biasTensorData);
+ armnn::ConstTensor weightsTensorData = ToConstTensor(flatBufferLayer->weights());
+ optionalWeights = armnn::Optional<armnn::ConstTensor>(weightsTensorData);
+
+ if (flatBufferDescriptor->biasEnabled())
+ {
+ armnn::ConstTensor biasTensorData = ToConstTensor(flatBufferLayer->biases());
+ optionalBiases = armnn::Optional<armnn::ConstTensor>(biasTensorData);
+ }
}
- layer = m_Network->AddFullyConnectedLayer(fullyConnectedDescriptor,
- weightsTensor,
- optionalBiases,
- layerName.c_str());
+
+ armnn::IConnectableLayer* layer = m_Network->AddFullyConnectedLayer(fullyConnectedDescriptor,
+ optionalWeights,
+ optionalBiases,
+ layerName.c_str());
armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
diff --git a/src/armnnSerializer/ArmnnSchema.fbs b/src/armnnSerializer/ArmnnSchema.fbs
index e2b3a3c288..88d66f76f5 100644
--- a/src/armnnSerializer/ArmnnSchema.fbs
+++ b/src/armnnSerializer/ArmnnSchema.fbs
@@ -321,6 +321,7 @@ table FullyConnectedLayer {
table FullyConnectedDescriptor {
biasEnabled:bool = false;
transposeWeightsMatrix:bool = false;
+ constantWeights:bool = true;
}
table GatherLayer {
diff --git a/src/armnnSerializer/ArmnnSchema_generated.h b/src/armnnSerializer/ArmnnSchema_generated.h
index 524ffb0182..99ab0dc78a 100644
--- a/src/armnnSerializer/ArmnnSchema_generated.h
+++ b/src/armnnSerializer/ArmnnSchema_generated.h
@@ -3504,7 +3504,8 @@ struct FullyConnectedDescriptor FLATBUFFERS_FINAL_CLASS : private flatbuffers::T
typedef FullyConnectedDescriptorBuilder Builder;
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
VT_BIASENABLED = 4,
- VT_TRANSPOSEWEIGHTSMATRIX = 6
+ VT_TRANSPOSEWEIGHTSMATRIX = 6,
+ VT_CONSTANTWEIGHTS = 8
};
bool biasEnabled() const {
return GetField<uint8_t>(VT_BIASENABLED, 0) != 0;
@@ -3512,10 +3513,14 @@ struct FullyConnectedDescriptor FLATBUFFERS_FINAL_CLASS : private flatbuffers::T
bool transposeWeightsMatrix() const {
return GetField<uint8_t>(VT_TRANSPOSEWEIGHTSMATRIX, 0) != 0;
}
+ bool constantWeights() const {
+ return GetField<uint8_t>(VT_CONSTANTWEIGHTS, 1) != 0;
+ }
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyField<uint8_t>(verifier, VT_BIASENABLED) &&
VerifyField<uint8_t>(verifier, VT_TRANSPOSEWEIGHTSMATRIX) &&
+ VerifyField<uint8_t>(verifier, VT_CONSTANTWEIGHTS) &&
verifier.EndTable();
}
};
@@ -3530,6 +3535,9 @@ struct FullyConnectedDescriptorBuilder {
void add_transposeWeightsMatrix(bool transposeWeightsMatrix) {
fbb_.AddElement<uint8_t>(FullyConnectedDescriptor::VT_TRANSPOSEWEIGHTSMATRIX, static_cast<uint8_t>(transposeWeightsMatrix), 0);
}
+ void add_constantWeights(bool constantWeights) {
+ fbb_.AddElement<uint8_t>(FullyConnectedDescriptor::VT_CONSTANTWEIGHTS, static_cast<uint8_t>(constantWeights), 1);
+ }
explicit FullyConnectedDescriptorBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
@@ -3545,8 +3553,10 @@ struct FullyConnectedDescriptorBuilder {
inline flatbuffers::Offset<FullyConnectedDescriptor> CreateFullyConnectedDescriptor(
flatbuffers::FlatBufferBuilder &_fbb,
bool biasEnabled = false,
- bool transposeWeightsMatrix = false) {
+ bool transposeWeightsMatrix = false,
+ bool constantWeights = true) {
FullyConnectedDescriptorBuilder builder_(_fbb);
+ builder_.add_constantWeights(constantWeights);
builder_.add_transposeWeightsMatrix(transposeWeightsMatrix);
builder_.add_biasEnabled(biasEnabled);
return builder_.Finish();
diff --git a/src/armnnSerializer/Serializer.cpp b/src/armnnSerializer/Serializer.cpp
index 0586700ada..ae9ddf29f2 100644
--- a/src/armnnSerializer/Serializer.cpp
+++ b/src/armnnSerializer/Serializer.cpp
@@ -1118,12 +1118,8 @@ void SerializerStrategy::SerializeQuantizeLayer(const armnn::IConnectableLayer *
void SerializerStrategy::SerializeFullyConnectedLayer(const armnn::IConnectableLayer* layer,
const armnn::FullyConnectedDescriptor& fullyConnectedDescriptor,
const std::vector<armnn::ConstTensor>& constants,
- const char* name)
+ const char*)
{
- IgnoreUnused(name);
-
- const armnn::ConstTensor& weights = constants.at(0);
-
// Create FlatBuffer BaseLayer
auto flatBufferBaseLayer = CreateLayerBase(layer, serializer::LayerType::LayerType_FullyConnected);
@@ -1131,17 +1127,23 @@ void SerializerStrategy::SerializeFullyConnectedLayer(const armnn::IConnectableL
auto flatBufferDescriptor =
serializer::CreateFullyConnectedDescriptor(m_flatBufferBuilder,
fullyConnectedDescriptor.m_BiasEnabled,
- fullyConnectedDescriptor.m_TransposeWeightMatrix);
+ fullyConnectedDescriptor.m_TransposeWeightMatrix,
+ fullyConnectedDescriptor.m_ConstantWeights);
// Create FlatBuffer weights data
- auto flatBufferWeights = CreateConstTensorInfo(weights);
-
+ flatbuffers::Offset<serializer::ConstTensor> flatBufferWeights;
// Create FlatBuffer bias data
flatbuffers::Offset<serializer::ConstTensor> flatBufferBiases;
- if (fullyConnectedDescriptor.m_BiasEnabled)
+ if (fullyConnectedDescriptor.m_ConstantWeights && !constants.empty())
{
- armnn::ConstTensor biases = constants.at(1);
- flatBufferBiases = CreateConstTensorInfo(biases);
+ armnn::ConstTensor weights = constants.at(0);
+ flatBufferWeights = CreateConstTensorInfo(weights);
+
+ if (fullyConnectedDescriptor.m_BiasEnabled)
+ {
+ armnn::ConstTensor biases = constants.at(1);
+ flatBufferBiases = CreateConstTensorInfo(biases);
+ }
}
// Create FlatBuffer FullyConnectedLayer
diff --git a/src/armnnSerializer/test/SerializerTests.cpp b/src/armnnSerializer/test/SerializerTests.cpp
index f261731a75..d7c10cb599 100644
--- a/src/armnnSerializer/test/SerializerTests.cpp
+++ b/src/armnnSerializer/test/SerializerTests.cpp
@@ -748,6 +748,7 @@ BOOST_AUTO_TEST_CASE(SerializeFullyConnected)
armnn::FullyConnectedDescriptor descriptor;
descriptor.m_BiasEnabled = true;
descriptor.m_TransposeWeightMatrix = false;
+ descriptor.m_ConstantWeights = true;
armnn::INetworkPtr network = armnn::INetwork::Create();
armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
@@ -773,6 +774,53 @@ BOOST_AUTO_TEST_CASE(SerializeFullyConnected)
deserializedNetwork->ExecuteStrategy(verifier);
}
+BOOST_AUTO_TEST_CASE(SerializeFullyConnectedWeightsAsInputs)
+{
+ const std::string layerName("fullyConnected_weights_as_inputs");
+ const armnn::TensorInfo inputInfo ({ 2, 5, 1, 1 }, armnn::DataType::Float32);
+ const armnn::TensorInfo outputInfo({ 2, 3 }, armnn::DataType::Float32);
+
+ const armnn::TensorInfo weightsInfo({ 5, 3 }, armnn::DataType::Float32);
+ const armnn::TensorInfo biasesInfo ({ 3 }, armnn::DataType::Float32);
+
+ armnn::Optional<armnn::ConstTensor> weights = armnn::EmptyOptional();
+ armnn::Optional<armnn::ConstTensor> bias = armnn::EmptyOptional();
+
+ armnn::FullyConnectedDescriptor descriptor;
+ descriptor.m_BiasEnabled = true;
+ descriptor.m_TransposeWeightMatrix = false;
+ descriptor.m_ConstantWeights = false;
+
+ armnn::INetworkPtr network = armnn::INetwork::Create();
+ armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
+ armnn::IConnectableLayer* const weightsInputLayer = network->AddInputLayer(1);
+ armnn::IConnectableLayer* const biasInputLayer = network->AddInputLayer(2);
+ armnn::IConnectableLayer* const fullyConnectedLayer =
+ network->AddFullyConnectedLayer(descriptor,
+ weights,
+ bias,
+ layerName.c_str());
+ armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
+
+ inputLayer->GetOutputSlot(0).Connect(fullyConnectedLayer->GetInputSlot(0));
+ weightsInputLayer->GetOutputSlot(0).Connect(fullyConnectedLayer->GetInputSlot(1));
+ biasInputLayer->GetOutputSlot(0).Connect(fullyConnectedLayer->GetInputSlot(2));
+ fullyConnectedLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
+
+ inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
+ weightsInputLayer->GetOutputSlot(0).SetTensorInfo(weightsInfo);
+ biasInputLayer->GetOutputSlot(0).SetTensorInfo(biasesInfo);
+ fullyConnectedLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
+
+ armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
+ BOOST_CHECK(deserializedNetwork);
+
+ const std::vector<armnn::ConstTensor> constants {};
+ LayerVerifierBaseWithDescriptorAndConstants<armnn::FullyConnectedDescriptor> verifier(
+ layerName, {inputInfo, weightsInfo, biasesInfo}, {outputInfo}, descriptor, constants);
+ deserializedNetwork->ExecuteStrategy(verifier);
+}
+
BOOST_AUTO_TEST_CASE(SerializeGather)
{
using GatherDescriptor = armnn::GatherDescriptor;
diff --git a/src/backends/backendsCommon/WorkloadData.cpp b/src/backends/backendsCommon/WorkloadData.cpp
index 90db57f953..2c5303c019 100644
--- a/src/backends/backendsCommon/WorkloadData.cpp
+++ b/src/backends/backendsCommon/WorkloadData.cpp
@@ -1022,7 +1022,16 @@ void FullyConnectedQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) c
{
const std::string descriptorName{"FullyConnectedQueueDescriptor"};
- ValidateNumInputs(workloadInfo, descriptorName, 1);
+ uint32_t numInputs = 1;
+ if (!m_Parameters.m_ConstantWeights)
+ {
+ numInputs = 2;
+ if (m_Parameters.m_BiasEnabled)
+ {
+ numInputs = 3;
+ }
+ }
+ ValidateNumInputs(workloadInfo, descriptorName, numInputs);
ValidateNumOutputs(workloadInfo, descriptorName, 1);
const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
@@ -1035,19 +1044,32 @@ void FullyConnectedQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) c
throw InvalidArgumentException(descriptorName + ": Input tensor must have 2 or 4 dimensions.");
}
- ValidatePointer(m_Weight, descriptorName, "weight");
-
- const TensorInfo& weightTensorInfo = m_Weight->GetTensorInfo();
+ TensorInfo weightTensorInfo;
+ if (m_Parameters.m_ConstantWeights)
+ {
+ ValidatePointer(m_Weight, descriptorName, "weight");
+ weightTensorInfo = m_Weight->GetTensorInfo();
+ }
+ else
+ {
+ weightTensorInfo = workloadInfo.m_InputTensorInfos[1];
+ }
ValidateTensorNumDimensions(weightTensorInfo, descriptorName, 2, "weight");
if (m_Parameters.m_BiasEnabled)
{
- ValidatePointer(m_Bias, descriptorName, "bias");
-
+ TensorInfo biasTensorInfo;
+ if (m_Parameters.m_ConstantWeights)
+ {
+ ValidatePointer(m_Bias, descriptorName, "bias");
+ biasTensorInfo = m_Bias->GetTensorInfo();
+ }
+ else
+ {
+ biasTensorInfo = workloadInfo.m_InputTensorInfos[2];
+ }
// Validates type and quantization values.
- const TensorInfo& biasTensorInfo = m_Bias->GetTensorInfo();
ValidateBiasTensorQuantization(biasTensorInfo, inputTensorInfo, weightTensorInfo, descriptorName);
-
ValidateTensorDataType(biasTensorInfo, GetBiasDataType(inputTensorInfo.GetDataType()), descriptorName, "bias");
ValidateTensorNumDimensions(biasTensorInfo, descriptorName, 1, "bias");
}
diff --git a/src/backends/backendsCommon/WorkloadFactory.cpp b/src/backends/backendsCommon/WorkloadFactory.cpp
index 19281a82e9..20d7134c3a 100644
--- a/src/backends/backendsCommon/WorkloadFactory.cpp
+++ b/src/backends/backendsCommon/WorkloadFactory.cpp
@@ -9,6 +9,7 @@
#include <armnn/Types.hpp>
#include <armnn/LayerSupport.hpp>
#include <armnn/ILayerSupport.hpp>
+#include <armnn/BackendHelper.hpp>
#include <armnn/BackendRegistry.hpp>
#include <armnn/utility/PolymorphicDowncast.hpp>
#include <armnn/utility/TransformIterator.hpp>
@@ -63,7 +64,7 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
auto backendFactory = backendRegistry.GetFactory(backendId);
auto backendObject = backendFactory();
- auto layerSupportObject = backendObject->GetLayerSupport(modelOptions);
+ auto layerSupportObject = LayerSupportHandle(backendObject->GetLayerSupport(modelOptions), backendId);
switch(layer.GetType())
{
@@ -72,7 +73,7 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
auto cLayer = PolymorphicDowncast<const ActivationLayer*>(&layer);
const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsActivationSupported(
+ result = layerSupportObject.IsActivationSupported(
OverrideDataType(input, dataType),
OverrideDataType(output, dataType),
cLayer->GetParameters(),
@@ -84,7 +85,7 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
const TensorInfo& input0 = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& input1 = layer.GetInputSlot(1).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsAdditionSupported(
+ result = layerSupportObject.IsAdditionSupported(
OverrideDataType(input0, dataType),
OverrideDataType(input1, dataType),
OverrideDataType(output, dataType),
@@ -98,7 +99,7 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsArgMinMaxSupported(
+ result = layerSupportObject.IsArgMinMaxSupported(
OverrideDataType(input, dataType),
OverrideDataType(output, DataType::Signed32),
descriptor,
@@ -114,7 +115,7 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
const TensorInfo& var = cLayer->m_Variance->GetTensorInfo();
const TensorInfo& beta = cLayer->m_Beta->GetTensorInfo();
const TensorInfo& gamma = cLayer->m_Gamma->GetTensorInfo();
- result = layerSupportObject->IsBatchNormalizationSupported(
+ result = layerSupportObject.IsBatchNormalizationSupported(
OverrideDataType(input, dataType),
OverrideDataType(output, dataType),
OverrideDataType(mean, dataType),
@@ -131,10 +132,10 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
auto cLayer = PolymorphicDowncast<const BatchToSpaceNdLayer*>(&layer);
- result = layerSupportObject->IsBatchToSpaceNdSupported(OverrideDataType(input, dataType),
- OverrideDataType(output, dataType),
- cLayer->GetParameters(),
- reason);
+ result = layerSupportObject.IsBatchToSpaceNdSupported(OverrideDataType(input, dataType),
+ OverrideDataType(output, dataType),
+ cLayer->GetParameters(),
+ reason);
break;
}
case LayerType::Comparison:
@@ -145,45 +146,45 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
const TensorInfo& input1 = layer.GetInputSlot(1).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsComparisonSupported(OverrideDataType(input0, dataType),
- OverrideDataType(input1, dataType),
- OverrideDataType(output, DataType::Boolean),
- cLayer->GetParameters(),
- reason);
+ result = layerSupportObject.IsComparisonSupported(OverrideDataType(input0, dataType),
+ OverrideDataType(input1, dataType),
+ OverrideDataType(output, DataType::Boolean),
+ cLayer->GetParameters(),
+ reason);
break;
}
case LayerType::Constant:
{
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsConstantSupported(OverrideDataType(output, dataType), reason);
+ result = layerSupportObject.IsConstantSupported(OverrideDataType(output, dataType), reason);
break;
}
case LayerType::ConvertBf16ToFp32:
{
const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsConvertBf16ToFp32Supported(input, output, reason);
+ result = layerSupportObject.IsConvertBf16ToFp32Supported(input, output, reason);
break;
}
case LayerType::ConvertFp16ToFp32:
{
const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsConvertFp16ToFp32Supported(input, output, reason);
+ result = layerSupportObject.IsConvertFp16ToFp32Supported(input, output, reason);
break;
}
case LayerType::ConvertFp32ToBf16:
{
const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsConvertFp32ToBf16Supported(input, output, reason);
+ result = layerSupportObject.IsConvertFp32ToBf16Supported(input, output, reason);
break;
}
case LayerType::ConvertFp32ToFp16:
{
const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsConvertFp32ToFp16Supported(input, output, reason);
+ result = layerSupportObject.IsConvertFp32ToFp16Supported(input, output, reason);
break;
}
case LayerType::Convolution2d:
@@ -205,7 +206,7 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
OverrideDataType(cLayer->m_Bias->GetTensorInfo(), GetBiasTypeFromWeightsType(dataType));
}
- result = layerSupportObject->IsConvolution2dSupported(
+ result = layerSupportObject.IsConvolution2dSupported(
input,
output,
descriptor,
@@ -219,7 +220,7 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsDebugSupported(OverrideDataType(input, dataType),
+ result = layerSupportObject.IsDebugSupported(OverrideDataType(input, dataType),
OverrideDataType(output, dataType),
reason);
break;
@@ -231,7 +232,7 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsDepthToSpaceSupported(OverrideDataType(input, dataType),
+ result = layerSupportObject.IsDepthToSpaceSupported(OverrideDataType(input, dataType),
OverrideDataType(output, dataType),
cLayer->GetParameters(),
reason);
@@ -255,7 +256,7 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
OverrideDataType(cLayer->m_Bias->GetTensorInfo(), GetBiasTypeFromWeightsType(dataType));
}
- result = layerSupportObject->IsDepthwiseConvolutionSupported(
+ result = layerSupportObject.IsDepthwiseConvolutionSupported(
input,
output,
descriptor,
@@ -269,9 +270,9 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsDequantizeSupported(input,
- OverrideDataType(output, dataType),
- reason);
+ result = layerSupportObject.IsDequantizeSupported(input,
+ OverrideDataType(output, dataType),
+ reason);
break;
}
case LayerType::DetectionPostProcess:
@@ -287,15 +288,15 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
const TensorInfo& numDetections = layer.GetOutputSlot(3).GetTensorInfo();
const DetectionPostProcessDescriptor& descriptor = cLayer->GetParameters();
- result = layerSupportObject->IsDetectionPostProcessSupported(boxEncodings,
- scores,
- anchors,
- detectionBoxes,
- detectionClasses,
- detectionScores,
- numDetections,
- descriptor,
- reason);
+ result = layerSupportObject.IsDetectionPostProcessSupported(boxEncodings,
+ scores,
+ anchors,
+ detectionBoxes,
+ detectionClasses,
+ detectionScores,
+ numDetections,
+ descriptor,
+ reason);
break;
}
case LayerType::ElementwiseUnary:
@@ -305,10 +306,10 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsElementwiseUnarySupported(OverrideDataType(input, dataType),
- OverrideDataType(output, dataType),
- cLayer->GetParameters(),
- reason);
+ result = layerSupportObject.IsElementwiseUnarySupported(OverrideDataType(input, dataType),
+ OverrideDataType(output, dataType),
+ cLayer->GetParameters(),
+ reason);
break;
}
case LayerType::Fill:
@@ -318,7 +319,7 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
const FillDescriptor& descriptor = cLayer->GetParameters();
- result = layerSupportObject->IsFillSupported(
+ result = layerSupportObject.IsFillSupported(
OverrideDataType(input, dataType),
OverrideDataType(output, dataType),
descriptor,
@@ -329,18 +330,18 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
{
auto cLayer = PolymorphicDowncast<const FakeQuantizationLayer*>(&layer);
const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
- result = layerSupportObject->IsFakeQuantizationSupported(OverrideDataType(input, dataType),
- cLayer->GetParameters(),
- reason);
+ result = layerSupportObject.IsFakeQuantizationSupported(OverrideDataType(input, dataType),
+ cLayer->GetParameters(),
+ reason);
break;
}
case LayerType::Floor:
{
const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsFloorSupported(OverrideDataType(input, dataType),
- OverrideDataType(output, dataType),
- reason);
+ result = layerSupportObject.IsFloorSupported(OverrideDataType(input, dataType),
+ OverrideDataType(output, dataType),
+ reason);
break;
}
case LayerType::FullyConnected:
@@ -348,21 +349,43 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
auto cLayer = PolymorphicDowncast<const FullyConnectedLayer*>(&layer);
const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- ARMNN_ASSERT(cLayer->m_Weight.get() != nullptr);
+
+ const FullyConnectedDescriptor& descriptor = cLayer->GetParameters();
+ TensorInfo weightsInfo;
+ const TensorInfo* weightsInfoPtr = nullptr;
+
+ if (descriptor.m_ConstantWeights)
+ {
+ ARMNN_ASSERT(cLayer->m_Weight.get() != nullptr);
+ weightsInfo = OverrideDataType(cLayer->m_Weight->GetTensorInfo(), dataType);
+ }
+ else
+ {
+ weightsInfo = OverrideDataType(layer.GetInputSlot(1).GetConnection()->GetTensorInfo(), dataType);
+
+ }
+ weightsInfoPtr = &weightsInfo;
TensorInfo biasInfo;
- const TensorInfo * biasInfoPtr = nullptr;
+ const TensorInfo* biasInfoPtr = nullptr;
static const TensorInfo dummyBFloat16Bias(TensorShape({1,1,1,1}), DataType::BFloat16);
static const TensorInfo dummyFloat16Bias(TensorShape({1,1,1,1}), DataType::Float16);
static const TensorInfo dummyFloat32Bias(TensorShape({1,1,1,1}), DataType::Float32);
static const TensorInfo dummyQA8Bias(TensorShape({1,1,1,1}), DataType::Signed32);
- const FullyConnectedDescriptor& descriptor = cLayer->GetParameters();
if (descriptor.m_BiasEnabled)
{
- ARMNN_ASSERT(cLayer->m_Bias.get() != nullptr);
- biasInfo = OverrideDataType(cLayer->m_Bias->GetTensorInfo(), GetBiasTypeFromWeightsType(dataType));
- biasInfoPtr = &biasInfo;
+ if(descriptor.m_ConstantWeights)
+ {
+ ARMNN_ASSERT(cLayer->m_Bias.get() != nullptr);
+ biasInfo = OverrideDataType(cLayer->m_Bias->GetTensorInfo(), GetBiasTypeFromWeightsType(dataType));
+ biasInfoPtr = &biasInfo;
+ }
+ else
+ {
+ biasInfo = OverrideDataType(layer.GetInputSlot(2).GetConnection()->GetTensorInfo(), dataType);
+ biasInfoPtr = &biasInfo;
+ }
}
else
{
@@ -398,11 +421,10 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
}
}
}
-
- result = layerSupportObject->IsFullyConnectedSupported(
+ result = layerSupportObject.IsFullyConnectedSupported(
OverrideDataType(input, dataType),
OverrideDataType(output, dataType),
- OverrideDataType(cLayer->m_Weight->GetTensorInfo(), dataType),
+ *weightsInfoPtr,
*biasInfoPtr,
descriptor,
reason);
@@ -415,17 +437,17 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
auto cLayer = PolymorphicDowncast<const GatherLayer*>(&layer);
const GatherDescriptor& descriptor = cLayer->GetParameters();
- result = layerSupportObject->IsGatherSupported(OverrideDataType(input0, dataType),
- input1,
- OverrideDataType(output, dataType),
- descriptor,
- reason);
+ result = layerSupportObject.IsGatherSupported(OverrideDataType(input0, dataType),
+ input1,
+ OverrideDataType(output, dataType),
+ descriptor,
+ reason);
break;
}
case LayerType::Input:
{
const TensorInfo& input = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsInputSupported(OverrideDataType(input, dataType), reason);
+ result = layerSupportObject.IsInputSupported(OverrideDataType(input, dataType), reason);
break;
}
case LayerType::InstanceNormalization:
@@ -436,7 +458,7 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsInstanceNormalizationSupported(
+ result = layerSupportObject.IsInstanceNormalizationSupported(
OverrideDataType(input, dataType),
OverrideDataType(output, dataType),
descriptor,
@@ -451,7 +473,7 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsL2NormalizationSupported(
+ result = layerSupportObject.IsL2NormalizationSupported(
OverrideDataType(input, dataType),
OverrideDataType(output, dataType),
descriptor,
@@ -466,11 +488,11 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
const TensorInfo& input1 = layer.GetInputSlot(1).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsLogicalBinarySupported(input0,
- input1,
- output,
- cLayer->GetParameters(),
- reason);
+ result = layerSupportObject.IsLogicalBinarySupported(input0,
+ input1,
+ output,
+ cLayer->GetParameters(),
+ reason);
break;
}
case LayerType::LogSoftmax:
@@ -480,10 +502,10 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsLogSoftmaxSupported(OverrideDataType(input, dataType),
- OverrideDataType(output, dataType),
- cLayer->GetParameters(),
- reason);
+ result = layerSupportObject.IsLogSoftmaxSupported(OverrideDataType(input, dataType),
+ OverrideDataType(output, dataType),
+ cLayer->GetParameters(),
+ reason);
break;
}
case LayerType::Lstm:
@@ -617,7 +639,7 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
paramsInfo.m_OutputLayerNormWeights = &optOutputLayerNormWeights;
}
- result = layerSupportObject->IsLstmSupported(
+ result = layerSupportObject.IsLstmSupported(
input,
outputStateIn,
cellStateIn,
@@ -636,10 +658,10 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
const TensorInfo& input1 = layer.GetInputSlot(1).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsMaximumSupported(OverrideDataType(input0, dataType),
- OverrideDataType(input1, dataType),
- OverrideDataType(output, dataType),
- reason);
+ result = layerSupportObject.IsMaximumSupported(OverrideDataType(input0, dataType),
+ OverrideDataType(input1, dataType),
+ OverrideDataType(output, dataType),
+ reason);
break;
}
case LayerType::MemCopy:
@@ -647,9 +669,9 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsMemCopySupported(OverrideDataType(input, dataType),
- OverrideDataType(output, dataType),
- reason);
+ result = layerSupportObject.IsMemCopySupported(OverrideDataType(input, dataType),
+ OverrideDataType(output, dataType),
+ reason);
break;
}
case LayerType::MemImport:
@@ -657,9 +679,9 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsMemImportSupported(OverrideDataType(input, dataType),
- OverrideDataType(output, dataType),
- reason);
+ result = layerSupportObject.IsMemImportSupported(OverrideDataType(input, dataType),
+ OverrideDataType(output, dataType),
+ reason);
break;
}
case LayerType::Merge:
@@ -668,10 +690,10 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
const TensorInfo& input1 = layer.GetInputSlot(1).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsMergeSupported(OverrideDataType(input0, dataType),
- OverrideDataType(input1, dataType),
- OverrideDataType(output, dataType),
- reason);
+ result = layerSupportObject.IsMergeSupported(OverrideDataType(input0, dataType),
+ OverrideDataType(input1, dataType),
+ OverrideDataType(output, dataType),
+ reason);
break;
}
case LayerType::Concat:
@@ -699,7 +721,7 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsConcatSupported(inputPtrs, output, cLayer->GetParameters(), reason);
+ result = layerSupportObject.IsConcatSupported(inputPtrs, output, cLayer->GetParameters(), reason);
break;
@@ -709,7 +731,7 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
const TensorInfo& input0 = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& input1 = layer.GetInputSlot(1).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsMultiplicationSupported(
+ result = layerSupportObject.IsMultiplicationSupported(
OverrideDataType(input0, dataType),
OverrideDataType(input1, dataType),
OverrideDataType(output, dataType),
@@ -721,16 +743,16 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
auto cLayer = PolymorphicDowncast<const NormalizationLayer*>(&layer);
const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsNormalizationSupported(OverrideDataType(input, dataType),
- OverrideDataType(output, dataType),
- cLayer->GetParameters(),
- reason);
+ result = layerSupportObject.IsNormalizationSupported(OverrideDataType(input, dataType),
+ OverrideDataType(output, dataType),
+ cLayer->GetParameters(),
+ reason);
break;
}
case LayerType::Output:
{
const TensorInfo& output = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
- result = layerSupportObject->IsOutputSupported(OverrideDataType(output, dataType), reason);
+ result = layerSupportObject.IsOutputSupported(OverrideDataType(output, dataType), reason);
break;
}
case LayerType::Permute:
@@ -738,10 +760,10 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
auto cLayer = PolymorphicDowncast<const PermuteLayer*>(&layer);
const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsPermuteSupported(OverrideDataType(input, dataType),
- OverrideDataType(output, dataType),
- cLayer->GetParameters(),
- reason);
+ result = layerSupportObject.IsPermuteSupported(OverrideDataType(input, dataType),
+ OverrideDataType(output, dataType),
+ cLayer->GetParameters(),
+ reason);
break;
}
case LayerType::Pad:
@@ -749,7 +771,7 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
auto cLayer = PolymorphicDowncast<const PadLayer*>(&layer);
const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsPadSupported(
+ result = layerSupportObject.IsPadSupported(
OverrideDataType(input, dataType),
OverrideDataType(output, dataType),
cLayer->GetParameters(),
@@ -761,26 +783,26 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
auto cLayer = PolymorphicDowncast<const Pooling2dLayer*>(&layer);
const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsPooling2dSupported(OverrideDataType(input, dataType),
- OverrideDataType(output, dataType),
- cLayer->GetParameters(),
- reason);
+ result = layerSupportObject.IsPooling2dSupported(OverrideDataType(input, dataType),
+ OverrideDataType(output, dataType),
+ cLayer->GetParameters(),
+ reason);
break;
}
case LayerType::PreCompiled:
{
auto cLayer = PolymorphicDowncast<const PreCompiledLayer*>(&layer);
const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
- result = layerSupportObject->IsPreCompiledSupported(OverrideDataType(input, dataType),
- cLayer->GetParameters(),
- reason);
+ result = layerSupportObject.IsPreCompiledSupported(OverrideDataType(input, dataType),
+ cLayer->GetParameters(),
+ reason);
break;
}
case LayerType::Quantize:
{
const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsQuantizeSupported(input, output, reason);
+ result = layerSupportObject.IsQuantizeSupported(input, output, reason);
break;
}
case LayerType::QLstm:
@@ -865,15 +887,15 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
&cLayer->m_LayerNormParameters.m_OutputLayerNormWeights->GetTensorInfo();
}
- result = layerSupportObject->IsQLstmSupported(input,
- previousOutputIn,
- previousCellStateIn,
- outputStateOut,
- cellStateOut,
- output,
- descriptor,
- paramsInfo,
- reason);
+ result = layerSupportObject.IsQLstmSupported(input,
+ previousOutputIn,
+ previousCellStateIn,
+ outputStateOut,
+ cellStateOut,
+ output,
+ descriptor,
+ paramsInfo,
+ reason);
break;
}
case LayerType::QuantizedLstm:
@@ -919,13 +941,13 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
paramsInfo.m_OutputGateBias =
&cLayer->m_QuantizedLstmParameters.m_OutputGateBias->GetTensorInfo();;
- result = layerSupportObject->IsQuantizedLstmSupported(input,
- previousCellStateIn,
- previousOutputIn,
- cellStateOut,
- output,
- paramsInfo,
- reason);
+ result = layerSupportObject.IsQuantizedLstmSupported(input,
+ previousCellStateIn,
+ previousOutputIn,
+ cellStateOut,
+ output,
+ paramsInfo,
+ reason);
break;
}
case LayerType::Division:
@@ -933,7 +955,7 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
const TensorInfo& input0 = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& input1 = layer.GetInputSlot(1).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsDivisionSupported(
+ result = layerSupportObject.IsDivisionSupported(
OverrideDataType(input0, dataType),
OverrideDataType(input1, dataType),
OverrideDataType(output, dataType),
@@ -944,9 +966,9 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
{
const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsRankSupported(OverrideDataType(input, dataType),
- OverrideDataType(output, dataType),
- reason);
+ result = layerSupportObject.IsRankSupported(OverrideDataType(input, dataType),
+ OverrideDataType(output, dataType),
+ reason);
break;
}
case LayerType::Reshape:
@@ -954,10 +976,10 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
auto cLayer = PolymorphicDowncast<const ReshapeLayer*>(&layer);
const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsReshapeSupported(OverrideDataType(input, dataType),
- OverrideDataType(output, dataType),
- cLayer->GetParameters(),
- reason);
+ result = layerSupportObject.IsReshapeSupported(OverrideDataType(input, dataType),
+ OverrideDataType(output, dataType),
+ cLayer->GetParameters(),
+ reason);
break;
}
case LayerType::Resize:
@@ -965,10 +987,10 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
auto cLayer = PolymorphicDowncast<const ResizeLayer*>(&layer);
const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsResizeSupported(OverrideDataType(input, dataType),
- OverrideDataType(output, dataType),
- cLayer->GetParameters(),
- reason);
+ result = layerSupportObject.IsResizeSupported(OverrideDataType(input, dataType),
+ OverrideDataType(output, dataType),
+ cLayer->GetParameters(),
+ reason);
break;
}
case LayerType::Slice:
@@ -978,10 +1000,10 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsSliceSupported(OverrideDataType(input, dataType),
- OverrideDataType(output, dataType),
- cLayer->GetParameters(),
- reason);
+ result = layerSupportObject.IsSliceSupported(OverrideDataType(input, dataType),
+ OverrideDataType(output, dataType),
+ cLayer->GetParameters(),
+ reason);
break;
}
case LayerType::Softmax:
@@ -989,10 +1011,10 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
auto cLayer = PolymorphicDowncast<const SoftmaxLayer*>(&layer);
const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsSoftmaxSupported(OverrideDataType(input, dataType),
- OverrideDataType(output, dataType),
- cLayer->GetParameters(),
- reason);
+ result = layerSupportObject.IsSoftmaxSupported(OverrideDataType(input, dataType),
+ OverrideDataType(output, dataType),
+ cLayer->GetParameters(),
+ reason);
break;
}
case LayerType::SpaceToBatchNd:
@@ -1000,10 +1022,10 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
auto cLayer = PolymorphicDowncast<const SpaceToBatchNdLayer*>(&layer);
const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsSpaceToBatchNdSupported(OverrideDataType(input, dataType),
- OverrideDataType(output, dataType),
- cLayer->GetParameters(),
- reason);
+ result = layerSupportObject.IsSpaceToBatchNdSupported(OverrideDataType(input, dataType),
+ OverrideDataType(output, dataType),
+ cLayer->GetParameters(),
+ reason);
break;
}
case LayerType::SpaceToDepth:
@@ -1013,10 +1035,10 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsSpaceToDepthSupported(OverrideDataType(input, dataType),
- OverrideDataType(output, dataType),
- cLayer->GetParameters(),
- reason);
+ result = layerSupportObject.IsSpaceToDepthSupported(OverrideDataType(input, dataType),
+ OverrideDataType(output, dataType),
+ cLayer->GetParameters(),
+ reason);
break;
}
case LayerType::Splitter:
@@ -1035,10 +1057,10 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
const std::vector<std::reference_wrapper<TensorInfo>> outputPtrs(outputs.begin(), outputs.end());
- result = layerSupportObject->IsSplitterSupported(OverrideDataType(input, dataType),
- outputPtrs,
- cLayer->GetParameters(),
- reason);
+ result = layerSupportObject.IsSplitterSupported(OverrideDataType(input, dataType),
+ outputPtrs,
+ cLayer->GetParameters(),
+ reason);
break;
}
case LayerType::Stack:
@@ -1064,7 +1086,7 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsStackSupported(inputPtrs, output, cLayer->GetParameters(), reason);
+ result = layerSupportObject.IsStackSupported(inputPtrs, output, cLayer->GetParameters(), reason);
break;
}
@@ -1103,10 +1125,10 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
std::vector<const TensorInfo*> outputPtrs(beginPtrO, endPtrO);
- result = layerSupportObject->IsStandInSupported(inputPtrs,
- outputPtrs,
- cLayer->GetParameters(),
- reason);
+ result = layerSupportObject.IsStandInSupported(inputPtrs,
+ outputPtrs,
+ cLayer->GetParameters(),
+ reason);
break;
}
case LayerType::StridedSlice:
@@ -1114,10 +1136,10 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
auto cLayer = PolymorphicDowncast<const StridedSliceLayer*>(&layer);
const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsStridedSliceSupported(OverrideDataType(input, dataType),
- OverrideDataType(output, dataType),
- cLayer->GetParameters(),
- reason);
+ result = layerSupportObject.IsStridedSliceSupported(OverrideDataType(input, dataType),
+ OverrideDataType(output, dataType),
+ cLayer->GetParameters(),
+ reason);
break;
}
case LayerType::Subtraction:
@@ -1125,7 +1147,7 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
const TensorInfo& input0 = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& input1 = layer.GetInputSlot(1).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsSubtractionSupported(
+ result = layerSupportObject.IsSubtractionSupported(
OverrideDataType(input0, dataType),
OverrideDataType(input1, dataType),
OverrideDataType(output, dataType),
@@ -1138,11 +1160,11 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
const TensorInfo& input1 = layer.GetInputSlot(1).GetConnection()->GetTensorInfo();
const TensorInfo& output0 = layer.GetOutputSlot(0).GetTensorInfo();
const TensorInfo& output1 = layer.GetOutputSlot(1).GetTensorInfo();
- result = layerSupportObject->IsSwitchSupported(OverrideDataType(input0, dataType),
- OverrideDataType(input1, dataType),
- OverrideDataType(output0, dataType),
- OverrideDataType(output1, dataType),
- reason);
+ result = layerSupportObject.IsSwitchSupported(OverrideDataType(input0, dataType),
+ OverrideDataType(input1, dataType),
+ OverrideDataType(output0, dataType),
+ OverrideDataType(output1, dataType),
+ reason);
break;
}
case LayerType::Mean:
@@ -1150,7 +1172,7 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
auto cLayer = PolymorphicDowncast<const MeanLayer*>(&layer);
const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsMeanSupported(
+ result = layerSupportObject.IsMeanSupported(
OverrideDataType(input, dataType),
OverrideDataType(output, dataType),
cLayer->GetParameters(),
@@ -1162,10 +1184,10 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
const TensorInfo& input0 = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& input1 = layer.GetInputSlot(1).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsMinimumSupported(OverrideDataType(input0, dataType),
- OverrideDataType(input1, dataType),
- OverrideDataType(output, dataType),
- reason);
+ result = layerSupportObject.IsMinimumSupported(OverrideDataType(input0, dataType),
+ OverrideDataType(input1, dataType),
+ OverrideDataType(output, dataType),
+ reason);
break;
}
case LayerType::Prelu:
@@ -1173,10 +1195,10 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& alpha = layer.GetInputSlot(1).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsPreluSupported(OverrideDataType(input, dataType),
- OverrideDataType(alpha, dataType),
- OverrideDataType(output, dataType),
- reason);
+ result = layerSupportObject.IsPreluSupported(OverrideDataType(input, dataType),
+ OverrideDataType(alpha, dataType),
+ OverrideDataType(output, dataType),
+ reason);
break;
}
case LayerType::Transpose:
@@ -1184,10 +1206,10 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
auto cLayer = PolymorphicDowncast<const TransposeLayer*>(&layer);
const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsTransposeSupported(OverrideDataType(input, dataType),
- OverrideDataType(output, dataType),
- cLayer->GetParameters(),
- reason);
+ result = layerSupportObject.IsTransposeSupported(OverrideDataType(input, dataType),
+ OverrideDataType(output, dataType),
+ cLayer->GetParameters(),
+ reason);
break;
}
case LayerType::TransposeConvolution2d:
@@ -1211,12 +1233,12 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
ARMNN_ASSERT(cLayer->m_Weight.get() != nullptr);
const TensorInfo weights = OverrideDataType(cLayer->m_Weight->GetTensorInfo(), dataType);
- result = layerSupportObject->IsTransposeConvolution2dSupported(input,
- output,
- descriptor,
- weights,
- biases,
- reason);
+ result = layerSupportObject.IsTransposeConvolution2dSupported(input,
+ output,
+ descriptor,
+ weights,
+ biases,
+ reason);
break;
}
@@ -1226,10 +1248,10 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
- result = layerSupportObject->IsReduceSupported(OverrideDataType(input, dataType),
- OverrideDataType(output, dataType),
- cLayer->GetParameters(),
- reason);
+ result = layerSupportObject.IsReduceSupported(OverrideDataType(input, dataType),
+ OverrideDataType(output, dataType),
+ cLayer->GetParameters(),
+ reason);
break;
}
default:
diff --git a/src/backends/backendsCommon/test/CMakeLists.txt b/src/backends/backendsCommon/test/CMakeLists.txt
index f92e0745d3..d3857b8357 100644
--- a/src/backends/backendsCommon/test/CMakeLists.txt
+++ b/src/backends/backendsCommon/test/CMakeLists.txt
@@ -23,6 +23,7 @@ list(APPEND armnnBackendsCommonUnitTests_sources
ElementwiseUnaryEndToEndTestImpl.hpp
EndToEndTestImpl.hpp
FillEndToEndTestImpl.hpp
+ FullyConnectedEndToEndTestImpl.hpp
GatherEndToEndTestImpl.hpp
InstanceNormalizationEndToEndTestImpl.cpp
InstanceNormalizationEndToEndTestImpl.hpp
diff --git a/src/backends/backendsCommon/test/CompatibilityTests.cpp b/src/backends/backendsCommon/test/CompatibilityTests.cpp
index b69e11253d..1c4ff709fa 100644
--- a/src/backends/backendsCommon/test/CompatibilityTests.cpp
+++ b/src/backends/backendsCommon/test/CompatibilityTests.cpp
@@ -7,6 +7,7 @@
#include <cl/ClBackend.hpp>
#include <neon/NeonBackend.hpp>
+#include <reference/RefBackend.hpp>
#include <Network.hpp>
@@ -115,3 +116,18 @@ BOOST_AUTO_TEST_CASE(Neon_Cl_DirectCompatibility_Test)
}
BOOST_AUTO_TEST_SUITE_END()
+
+BOOST_AUTO_TEST_SUITE(BackendCapability)
+
+BOOST_AUTO_TEST_CASE(Backends_Capability_Test)
+{
+ auto neonBackend = std::make_unique<NeonBackend>();
+ auto clBackend = std::make_unique<ClBackend>();
+ auto refBackend = std::make_unique<RefBackend>();
+
+ BOOST_CHECK(!neonBackend->HasCapability(armnn::BackendCapability::NonConstWeights));
+ BOOST_CHECK(!clBackend->HasCapability(armnn::BackendCapability::NonConstWeights));
+ BOOST_CHECK(refBackend->HasCapability(armnn::BackendCapability::NonConstWeights));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/backends/backendsCommon/test/FullyConnectedEndToEndTestImpl.hpp b/src/backends/backendsCommon/test/FullyConnectedEndToEndTestImpl.hpp
new file mode 100644
index 0000000000..5a618c32e1
--- /dev/null
+++ b/src/backends/backendsCommon/test/FullyConnectedEndToEndTestImpl.hpp
@@ -0,0 +1,97 @@
+//
+// Copyright © 2021 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+#pragma once
+
+#include "CommonTestUtils.hpp"
+
+#include <ResolveType.hpp>
+
+#include <armnn/INetwork.hpp>
+
+#include <armnn/utility/NumericCast.hpp>
+
+#include <boost/test/unit_test.hpp>
+
+#include <vector>
+
+namespace
+{
+
+armnn::INetworkPtr CreateFullyConnectedNetworkNonConstWeights(const armnn::TensorInfo& inputTensorInfo,
+ const armnn::TensorInfo& outputTensorInfo,
+ const armnn::TensorInfo& weightsTensorInfo,
+ armnn::FullyConnectedDescriptor descriptor)
+{
+ armnn::INetworkPtr network(armnn::INetwork::Create());
+
+ armnn::IConnectableLayer* inputLayer = network->AddInputLayer(0, "Input");
+ armnn::IConnectableLayer* weightsInputLayer = network->AddInputLayer(1, "Weights_Input");
+ armnn::IConnectableLayer* fullyConnectedLayer = network->AddFullyConnectedLayer(descriptor,
+ armnn::EmptyOptional(),
+ armnn::EmptyOptional(),
+ "Fully_Connected");
+ armnn::IConnectableLayer* outputLayer = network->AddOutputLayer(0, "Output");
+
+ Connect(inputLayer, fullyConnectedLayer, inputTensorInfo, 0, 0);
+ Connect(weightsInputLayer, fullyConnectedLayer, weightsTensorInfo, 0, 1);
+ Connect(fullyConnectedLayer, outputLayer, outputTensorInfo, 0, 0);
+
+ return network;
+}
+
+template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
+void FullyConnectedWithDynamicWeightsEndToEnd(const std::vector<armnn::BackendId>& backends)
+{
+ using namespace armnn;
+
+ armnn::TensorInfo inputTensorInfo({ 1, 1, 2, 3 }, ArmnnType);
+ inputTensorInfo.SetQuantizationScale(0.1f);
+ inputTensorInfo.SetQuantizationOffset(63);
+
+ armnn::TensorInfo outputTensorInfo({ 1, 2 }, ArmnnType);
+ outputTensorInfo.SetQuantizationScale(5.f);
+ outputTensorInfo.SetQuantizationOffset(10);
+
+ armnn::TensorInfo weightsTensorInfo({ 2, 6 }, ArmnnType);
+ weightsTensorInfo.SetQuantizationScale(0.2f);
+ weightsTensorInfo.SetQuantizationOffset(93);
+
+ FullyConnectedDescriptor descriptor;
+ descriptor.m_ConstantWeights = false;
+ descriptor.m_BiasEnabled = false;
+ descriptor.m_TransposeWeightMatrix = true;
+
+ std::vector<T> inputData {
+ -1.2f, 6.1f, -3.5f,
+ 18.8f, -5.5f, 2.9f
+ };
+
+ std::vector<T> weightsData {
+ -8.4f, 20.0f, -10.4f, -8, 16.4f, -11.8f,
+ 23.4f, 10.4f, -14.0f, -3.8f, -11.8f, 11.4f
+ };
+
+ std::vector<T> floatExpectedOutputData {
+ -107.04f, 110.f
+ };
+ std::vector<T> expectedOutputData = armnnUtils::QuantizedVector<T>(floatExpectedOutputData);
+
+ armnn::INetworkPtr network = CreateFullyConnectedNetworkNonConstWeights(inputTensorInfo,
+ outputTensorInfo,
+ weightsTensorInfo,
+ descriptor);
+
+ BOOST_TEST_CHECKPOINT("create a network");
+
+ std::map<int, std::vector<T>> inputTensorData = {{ 0, inputData }, {1, weightsData}};
+ std::map<int, std::vector<T>> expectedOutputTensorData = {{ 0, expectedOutputData }};
+
+ EndToEndLayerTestImpl<ArmnnType, ArmnnType>(move(network),
+ inputTensorData,
+ expectedOutputTensorData,
+ backends,
+ 1.0f);
+}
+} // anonymous namespace
diff --git a/src/backends/backendsCommon/test/layerTests/FullyConnectedTestImpl.cpp b/src/backends/backendsCommon/test/layerTests/FullyConnectedTestImpl.cpp
index c9e2e1602d..9176094eb2 100644
--- a/src/backends/backendsCommon/test/layerTests/FullyConnectedTestImpl.cpp
+++ b/src/backends/backendsCommon/test/layerTests/FullyConnectedTestImpl.cpp
@@ -67,12 +67,70 @@ LayerTestResult<T, 2> SimpleFullyConnectedTestImpl(
return result;
}
+template<typename T, typename B>
+LayerTestResult<T, 2> SimpleFullyConnectedTestWeightsAsInputsImpl(
+ armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::ITensorHandleFactory& tensorHandleFactory,
+ armnn::TensorInfo inputTensorInfo,
+ armnn::TensorInfo outputTensorInfo,
+ armnn::TensorInfo weightsTensorInfo,
+ armnn::TensorInfo biasesTensorInfo,
+ boost::multi_array<T, 2>& weights,
+ boost::multi_array<B, 1>& bias,
+ boost::multi_array<T, 4>& input,
+ bool biasEnabled,
+ bool transposeWeights)
+{
+ std::unique_ptr<armnn::ITensorHandle> input0Handle = tensorHandleFactory.CreateTensorHandle(inputTensorInfo);
+ std::unique_ptr<armnn::ITensorHandle> input1Handle = tensorHandleFactory.CreateTensorHandle(weightsTensorInfo);
+ std::unique_ptr<armnn::ITensorHandle> outputHandle = tensorHandleFactory.CreateTensorHandle(outputTensorInfo);
+
+ armnn::FullyConnectedQueueDescriptor data;
+ armnn::WorkloadInfo info;
+
+ AddInputToWorkload(data, info, inputTensorInfo, input0Handle.get());
+ AddInputToWorkload(data, info, weightsTensorInfo, input1Handle.get());
+ AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
+ data.m_Parameters.m_BiasEnabled = biasEnabled;
+ data.m_Parameters.m_TransposeWeightMatrix = transposeWeights;
+ data.m_Parameters.m_ConstantWeights = false;
+
+ std::unique_ptr<armnn::ITensorHandle> input2Handle = nullptr;
+ if (biasEnabled)
+ {
+ input2Handle = tensorHandleFactory.CreateTensorHandle(biasesTensorInfo);
+ AddInputToWorkload(data, info, biasesTensorInfo, input2Handle.get());
+ }
+
+ std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreateFullyConnected(data, info);
+ LayerTestResult<T, 2> result(outputTensorInfo);
+
+ input0Handle->Allocate();
+ input1Handle->Allocate();
+ outputHandle->Allocate();
+ CopyDataToITensorHandle(input0Handle.get(), &input[0][0][0][0]);
+ CopyDataToITensorHandle(input1Handle.get(), &weights[0][0]);
+ if (biasEnabled)
+ {
+ input2Handle->Allocate();
+ CopyDataToITensorHandle(input2Handle.get(), &bias[0]);
+ }
+
+ ExecuteWorkload(*workload, memoryManager);
+
+ CopyDataFromITensorHandle(&result.output[0][0], outputHandle.get());
+
+ return result;
+}
+
template<armnn::DataType ArmnnType, typename T>
LayerTestResult<T, 2> FullyConnectedTest(
armnn::IWorkloadFactory& workloadFactory,
const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
const armnn::ITensorHandleFactory& tensorHandleFactory,
- bool biasEnabled)
+ bool biasEnabled,
+ bool constantWeights)
{
constexpr static unsigned int inputWidth = 3u;
constexpr static unsigned int inputHeight = 2u;
@@ -116,15 +174,36 @@ LayerTestResult<T, 2> FullyConnectedTest(
auto bias = MakeTensor<int32_t, 1>(biasesDesc, std::vector<int32_t>{9250, 67500});
- result = SimpleFullyConnectedTestImpl<T>(
- workloadFactory,
- memoryManager,
- tensorHandleFactory,
- inputTensorInfo, outputTensorInfo,
- weightsDesc, biasesDesc,
- weights, bias, input,
- biasEnabled, true
- );
+ if (constantWeights)
+ {
+ result = SimpleFullyConnectedTestImpl<T>(workloadFactory,
+ memoryManager,
+ tensorHandleFactory,
+ inputTensorInfo,
+ outputTensorInfo,
+ weightsDesc,
+ biasesDesc,
+ weights,
+ bias,
+ input,
+ biasEnabled,
+ true);
+ }
+ else
+ {
+ result = SimpleFullyConnectedTestWeightsAsInputsImpl<T>(workloadFactory,
+ memoryManager,
+ tensorHandleFactory,
+ inputTensorInfo,
+ outputTensorInfo,
+ weightsDesc,
+ biasesDesc,
+ weights,
+ bias,
+ input,
+ biasEnabled,
+ true);
+ }
if (biasEnabled)
{
@@ -237,14 +316,16 @@ FullyConnectedTest<armnn::DataType::QAsymmU8>(
armnn::IWorkloadFactory& workloadFactory,
const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
const armnn::ITensorHandleFactory& tensorHandleFactory,
- bool biasEnabled);
+ bool biasEnabled,
+ bool constWeights);
template LayerTestResult<armnn::ResolveType<armnn::DataType::QSymmS16>, 2>
FullyConnectedTest<armnn::DataType::QSymmS16>(
armnn::IWorkloadFactory& workloadFactory,
const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
const armnn::ITensorHandleFactory& tensorHandleFactory,
- bool biasEnabled);
+ bool biasEnabled,
+ bool constWeights);
//
// Implementation functions
diff --git a/src/backends/backendsCommon/test/layerTests/FullyConnectedTestImpl.hpp b/src/backends/backendsCommon/test/layerTests/FullyConnectedTestImpl.hpp
index c2d53a5178..ec921f7dd5 100644
--- a/src/backends/backendsCommon/test/layerTests/FullyConnectedTestImpl.hpp
+++ b/src/backends/backendsCommon/test/layerTests/FullyConnectedTestImpl.hpp
@@ -17,7 +17,8 @@ LayerTestResult<T, 2> FullyConnectedTest(
armnn::IWorkloadFactory& workloadFactory,
const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
const armnn::ITensorHandleFactory& tensorHandleFactory,
- bool biasEnabled);
+ bool biasEnabled,
+ bool constantWeights);
LayerTestResult<float, 2> FullyConnectedFloat32Test(
armnn::IWorkloadFactory& workloadFactory,
diff --git a/src/backends/cl/test/ClLayerTests.cpp b/src/backends/cl/test/ClLayerTests.cpp
index 013965c445..2c6ebf9dc0 100644
--- a/src/backends/cl/test/ClLayerTests.cpp
+++ b/src/backends/cl/test/ClLayerTests.cpp
@@ -101,8 +101,8 @@ ARMNN_AUTO_TEST_CASE_WITH_THF(BatchToSpaceNdNchwUint3, BatchToSpaceNdNchwTest3<D
ARMNN_AUTO_TEST_CASE_WITH_THF(SimpleFullyConnected, FullyConnectedFloat32Test, false, false)
ARMNN_AUTO_TEST_CASE_WITH_THF(SimpleFullyConnectedWithBias, FullyConnectedFloat32Test, true, false)
ARMNN_AUTO_TEST_CASE_WITH_THF(SimpleFullyConnectedWithTranspose, FullyConnectedFloat32Test, false, true)
-ARMNN_AUTO_TEST_CASE_WITH_THF(FullyConnectedUint8, FullyConnectedTest<DataType::QAsymmU8>, false)
-ARMNN_AUTO_TEST_CASE_WITH_THF(FullyConnectedBiasedUint8, FullyConnectedTest<DataType::QAsymmU8>, true)
+ARMNN_AUTO_TEST_CASE_WITH_THF(FullyConnectedUint8, FullyConnectedTest<DataType::QAsymmU8>, false, true)
+ARMNN_AUTO_TEST_CASE_WITH_THF(FullyConnectedBiasedUint8, FullyConnectedTest<DataType::QAsymmU8>, true, true)
ARMNN_AUTO_TEST_CASE_WITH_THF(FullyConnectedLarge, FullyConnectedLargeTest, false)
ARMNN_AUTO_TEST_CASE_WITH_THF(FullyConnectedLargeTransposed, FullyConnectedLargeTest, true)
diff --git a/src/backends/neon/test/NeonLayerTests.cpp b/src/backends/neon/test/NeonLayerTests.cpp
index 8434a67082..8cccf6f780 100644
--- a/src/backends/neon/test/NeonLayerTests.cpp
+++ b/src/backends/neon/test/NeonLayerTests.cpp
@@ -574,8 +574,8 @@ ARMNN_AUTO_TEST_CASE_WITH_THF(SimpleFullyConnectedWithBias, FullyConnectedFloat3
ARMNN_AUTO_TEST_CASE_WITH_THF(SimpleFullyConnectedWithTranspose, FullyConnectedFloat32Test, false, true)
ARMNN_AUTO_TEST_CASE_WITH_THF(FullyConnectedLarge, FullyConnectedLargeTest, false)
ARMNN_AUTO_TEST_CASE_WITH_THF(FullyConnectedLargeTransposed, FullyConnectedLargeTest, true)
-ARMNN_AUTO_TEST_CASE_WITH_THF(FullyConnectedUint8, FullyConnectedTest<DataType::QAsymmU8>, false)
-ARMNN_AUTO_TEST_CASE_WITH_THF(FullyConnectedBiasedUint8, FullyConnectedTest<DataType::QAsymmU8>, true)
+ARMNN_AUTO_TEST_CASE_WITH_THF(FullyConnectedUint8, FullyConnectedTest<DataType::QAsymmU8>, false, true)
+ARMNN_AUTO_TEST_CASE_WITH_THF(FullyConnectedBiasedUint8, FullyConnectedTest<DataType::QAsymmU8>, true, true)
// Add
ARMNN_AUTO_TEST_CASE_WITH_THF(SimpleAdd, AdditionTest)
diff --git a/src/backends/reference/RefBackend.cpp b/src/backends/reference/RefBackend.cpp
index e93b317dce..53c55ab26a 100644
--- a/src/backends/reference/RefBackend.cpp
+++ b/src/backends/reference/RefBackend.cpp
@@ -69,6 +69,16 @@ IBackendInternal::ILayerSupportSharedPtr RefBackend::GetLayerSupport() const
return layerSupport;
}
+bool RefBackend::HasCapability(BackendCapability capabilityClass) const
+{
+ auto search = backendCapabilities.find(capabilityClass);
+ if (search != backendCapabilities.end())
+ {
+ return true;
+ }
+ return false;
+}
+
OptimizationViews RefBackend::OptimizeSubgraphView(const SubgraphView& subgraph) const
{
OptimizationViews optimizationViews;
diff --git a/src/backends/reference/RefBackend.hpp b/src/backends/reference/RefBackend.hpp
index 92d392dde6..c92936ca0c 100644
--- a/src/backends/reference/RefBackend.hpp
+++ b/src/backends/reference/RefBackend.hpp
@@ -9,6 +9,10 @@
namespace armnn
{
+const std::set<armnn::BackendCapability> backendCapabilities {
+ armnn::BackendCapability::NonConstWeights,
+};
+
class RefBackend : public IBackendInternal
{
public:
@@ -39,6 +43,8 @@ public:
std::vector<ITensorHandleFactory::FactoryId> GetHandleFactoryPreferences() const override;
void RegisterTensorHandleFactories(class TensorHandleFactoryRegistry& registry) override;
+
+ bool HasCapability(BackendCapability capabilityClass) const override;
};
} // namespace armnn
diff --git a/src/backends/reference/test/RefEndToEndTests.cpp b/src/backends/reference/test/RefEndToEndTests.cpp
index 4598568070..b6974811ef 100644
--- a/src/backends/reference/test/RefEndToEndTests.cpp
+++ b/src/backends/reference/test/RefEndToEndTests.cpp
@@ -15,6 +15,7 @@
#include <backendsCommon/test/DetectionPostProcessEndToEndTestImpl.hpp>
#include <backendsCommon/test/ElementwiseUnaryEndToEndTestImpl.hpp>
#include <backendsCommon/test/FillEndToEndTestImpl.hpp>
+#include <backendsCommon/test/FullyConnectedEndToEndTestImpl.hpp>
#include <backendsCommon/test/GatherEndToEndTestImpl.hpp>
#include <backendsCommon/test/InstanceNormalizationEndToEndTestImpl.hpp>
#include <backendsCommon/test/LogSoftmaxEndToEndTestImpl.hpp>
@@ -599,6 +600,11 @@ BOOST_AUTO_TEST_CASE(RefFillEndToEndTestInt32)
FillEndToEnd<armnn::DataType::Signed32>(defaultBackends);
}
+BOOST_AUTO_TEST_CASE(RefFullyConnectedEndToEndTestInt32)
+{
+ FullyConnectedWithDynamicWeightsEndToEnd<armnn::DataType::Float32>(defaultBackends);
+}
+
BOOST_AUTO_TEST_CASE(RefGatherFloatTest)
{
GatherEndToEnd<armnn::DataType::Float32>(defaultBackends);
diff --git a/src/backends/reference/test/RefLayerTests.cpp b/src/backends/reference/test/RefLayerTests.cpp
index 161476ed98..7371692d0e 100644
--- a/src/backends/reference/test/RefLayerTests.cpp
+++ b/src/backends/reference/test/RefLayerTests.cpp
@@ -579,16 +579,22 @@ ARMNN_AUTO_TEST_CASE_WITH_THF(HardSwishInt16, HardSwishInt16Test)
// Fully Connected
ARMNN_AUTO_TEST_CASE_WITH_THF(SimpleFullyConnected, FullyConnectedFloat32Test, false, false)
-ARMNN_AUTO_TEST_CASE_WITH_THF(FullyConnectedUint8, FullyConnectedTest<DataType::QAsymmU8>, false)
-ARMNN_AUTO_TEST_CASE_WITH_THF(FullyConnectedQSymm16, FullyConnectedTest<DataType::QSymmS16>, false)
+ARMNN_AUTO_TEST_CASE_WITH_THF(FullyConnectedUint8, FullyConnectedTest<DataType::QAsymmU8>, false, true)
+ARMNN_AUTO_TEST_CASE_WITH_THF(FullyConnectedQSymm16, FullyConnectedTest<DataType::QSymmS16>, false, true)
ARMNN_AUTO_TEST_CASE_WITH_THF(SimpleFullyConnectedWithBias, FullyConnectedFloat32Test, true, false)
-ARMNN_AUTO_TEST_CASE_WITH_THF(FullyConnectedBiasedUint8, FullyConnectedTest<DataType::QAsymmU8>, true)
-ARMNN_AUTO_TEST_CASE_WITH_THF(FullyConnectedBiasedQSymm16, FullyConnectedTest<DataType::QSymmS16>, true)
+ARMNN_AUTO_TEST_CASE_WITH_THF(FullyConnectedBiasedUint8, FullyConnectedTest<DataType::QAsymmU8>, true, true)
+ARMNN_AUTO_TEST_CASE_WITH_THF(FullyConnectedBiasedQSymm16, FullyConnectedTest<DataType::QSymmS16>, true, true)
ARMNN_AUTO_TEST_CASE_WITH_THF(SimpleFullyConnectedWithTranspose, FullyConnectedFloat32Test, false, true)
ARMNN_AUTO_TEST_CASE_WITH_THF(FullyConnectedLarge, FullyConnectedLargeTest, false)
ARMNN_AUTO_TEST_CASE_WITH_THF(FullyConnectedLargeTransposed, FullyConnectedLargeTest, true)
+
+ARMNN_AUTO_TEST_CASE_WITH_THF(FullyConnectedWeightsAsInputsUint8,
+ FullyConnectedTest<DataType::QAsymmU8>,
+ false,
+ false)
+
// Splitter
ARMNN_AUTO_TEST_CASE_WITH_THF(SimpleSplitterFloat32, SplitterFloat32Test)
ARMNN_AUTO_TEST_CASE_WITH_THF(SimpleSplitterFloat16, SplitterFloat16Test)
diff --git a/src/backends/reference/workloads/RefFullyConnectedWorkload.cpp b/src/backends/reference/workloads/RefFullyConnectedWorkload.cpp
index 9acca219b5..49e105f206 100644
--- a/src/backends/reference/workloads/RefFullyConnectedWorkload.cpp
+++ b/src/backends/reference/workloads/RefFullyConnectedWorkload.cpp
@@ -14,18 +14,21 @@ namespace armnn
{
RefFullyConnectedWorkload::RefFullyConnectedWorkload(
const FullyConnectedQueueDescriptor& descriptor, const WorkloadInfo& info)
- : BaseWorkload<FullyConnectedQueueDescriptor>(descriptor, info),
- m_Weight(std::make_unique<ScopedCpuTensorHandle>(*(descriptor.m_Weight)))
+ : BaseWorkload<FullyConnectedQueueDescriptor>(descriptor, info)
{
- const TensorInfo& rWeightInfo = m_Weight->GetTensorInfo();
- m_WeightShape = rWeightInfo.GetShape();
- m_WeightDecoder = MakeDecoder<float>(rWeightInfo, m_Weight->Map(true));
-
- if (descriptor.m_Parameters.m_BiasEnabled)
+ if (descriptor.m_Parameters.m_ConstantWeights)
{
- m_Bias = std::make_unique<ScopedCpuTensorHandle>(*(descriptor.m_Bias));
- const TensorInfo& biasInfo = m_Bias->GetTensorInfo();
- m_BiasDecoder = MakeDecoder<float>(biasInfo, m_Bias->Map(true));
+ m_Weight = std::make_unique<ScopedCpuTensorHandle>(*(descriptor.m_Weight));
+ const TensorInfo& rWeightInfo = m_Weight->GetTensorInfo();
+ m_WeightShape = rWeightInfo.GetShape();
+ m_WeightDecoder = MakeDecoder<float>(rWeightInfo, m_Weight->Map(true));
+
+ if (descriptor.m_Parameters.m_BiasEnabled)
+ {
+ m_Bias = std::make_unique<ScopedCpuTensorHandle>(*(descriptor.m_Bias));
+ const TensorInfo& biasInfo = m_Bias->GetTensorInfo();
+ m_BiasDecoder = MakeDecoder<float>(biasInfo, m_Bias->Map(true));
+ }
}
}
@@ -36,6 +39,20 @@ void RefFullyConnectedWorkload::PostAllocationConfigure()
m_InputShape = inputInfo.GetShape();
m_InputDecoder = MakeDecoder<float>(inputInfo);
+ if (!m_Data.m_Parameters.m_ConstantWeights)
+ {
+ const TensorInfo& rWeightInfo = GetTensorInfo(m_Data.m_Inputs[1]);
+ ARMNN_ASSERT(inputInfo.GetNumDimensions() > 1);
+ m_WeightShape = rWeightInfo.GetShape();
+ m_WeightDecoder = MakeDecoder<float>(rWeightInfo);
+
+ if (m_Data.m_Parameters.m_BiasEnabled)
+ {
+ const TensorInfo& biasInfo = GetTensorInfo(m_Data.m_Inputs[2]);
+ m_BiasDecoder = MakeDecoder<float>(biasInfo);
+ }
+ }
+
const TensorInfo& outputInfo = GetTensorInfo(m_Data.m_Outputs[0]);
m_OutputShape = outputInfo.GetShape();
m_OutputEncoder = MakeEncoder<float>(outputInfo);
@@ -52,6 +69,14 @@ void RefFullyConnectedWorkload::Execute() const
ARMNN_SCOPED_PROFILING_EVENT(Compute::CpuRef, "RefFullyConnectedWorkload_Execute");
m_InputDecoder->Reset(m_Data.m_Inputs[0]->Map());
+ if (!m_Data.m_Parameters.m_ConstantWeights)
+ {
+ m_WeightDecoder->Reset(m_Data.m_Inputs[1]->Map());
+ if (m_Data.m_Parameters.m_BiasEnabled)
+ {
+ m_BiasDecoder->Reset(m_Data.m_Inputs[2]->Map());
+ }
+ }
m_OutputEncoder->Reset(m_Data.m_Outputs[0]->Map());
FullyConnected(m_InputShape,