1622 TEST_CASE(
"SingleSubgraph")
1647 SubgraphViewSelector::SelectSubgraphs(
1650 [](
const Layer & l){
1655 CHECK(subgraphs.size() == 1);
1656 if(subgraphs.size() == 1)
1658 CHECK((subgraphs[0] !=
nullptr));
1660 if (subgraphs[0].
get() !=
nullptr)
1662 unsigned int numInputSlots =
armnn::numeric_cast<
unsigned int>(subgraphs[0]->GetIInputSlots().size());
1663 unsigned int numOutputSlots =
armnn::numeric_cast<
unsigned int>(subgraphs[0]->GetIOutputSlots().size());
1665 CHECK((numInputSlots == 1));
1666 CHECK((numOutputSlots == 1));
1687 TEST_CASE(
"MultipleSubgraphs")
1715 convLayer2->GetOutputSlot(0).Connect(pConcatLayer->
GetInputSlot(1));
1720 SubgraphViewSelector::SelectSubgraphs(
1723 [](
const Layer & l){
1728 CHECK(subgraphs.size() == 2);
1729 if(subgraphs.size() == 2)
1731 CHECK((subgraphs[0] !=
nullptr));
1732 CHECK((subgraphs[1] !=
nullptr));
1734 if (subgraphs[0].
get() !=
nullptr && subgraphs[1].
get() !=
nullptr)
1737 std::sort(subgraphs.begin(), subgraphs.end(),
1740 return (lhs->GetIInputSlots().size() < rhs->GetIInputSlots().size());
1744 unsigned int numInputSlots1 =
armnn::numeric_cast<
unsigned int>(subgraphs[0]->GetIInputSlots().size());
1745 unsigned int numOutputSlots1 =
armnn::numeric_cast<
unsigned int>(subgraphs[0]->GetIOutputSlots().size());
1747 unsigned int numInputSlots2 =
armnn::numeric_cast<
unsigned int>(subgraphs[1]->GetIInputSlots().size());
1748 unsigned int numOutputSlots2 =
armnn::numeric_cast<
unsigned int>(subgraphs[1]->GetIOutputSlots().size());
1782 TEST_CASE(
"SubgraphCycles")
1824 SubgraphViewSelector::SelectSubgraphs(
1829 bool toSelect = (l.
GetNameStr().find(
'm') != std::string::npos);
1842 CHECK(subgraphs.size() == 2);
1843 if (subgraphs.size() == 2)
1846 CHECK((subgraphs[0] !=
nullptr));
1847 CHECK((subgraphs[1] !=
nullptr));
1849 if (subgraphs[0].
get() !=
nullptr && subgraphs[1].
get() !=
nullptr)
1852 std::sort(subgraphs.begin(), subgraphs.end(),
1855 return (lhs->GetIConnectableLayers().size() < rhs->GetIConnectableLayers().size());
1860 CHECK(subgraphs[0]->GetIConnectableLayers().size() == 1);
1861 CHECK(subgraphs[1]->GetIConnectableLayers().size() == 2);
1863 CompareSubgraphViews(subgraphs[0], outputSubgraph);
1864 CompareSubgraphViews(subgraphs[1], inputSubgraph);
1869 TEST_CASE(
"SubgraphOrder")
1883 {output, input, activation});
1888 view->ForEachLayer([&idx, &expectedSorted](
const Layer* l)
1890 CHECK((expectedSorted[idx] == l->
GetType()));
1896 TEST_CASE(
"SubgraphViewWorkingCopy")
1917 workingCopy.ForEachIConnectableLayer([&idx, &expectedSorted](
const IConnectableLayer* l)
1919 CHECK((expectedSorted[idx] == l->
GetType()));
1925 bool ReplaceConstantMultiplicationWithDepthwise(
SubgraphView& subgraph,
1928 if (layer->
GetType() == LayerType::Multiplication)
1936 if (constantLayer->
GetType() != LayerType::Constant)
1942 if (constantLayer->
GetType() == LayerType::Constant)
1951 auto replacementGraph = INetwork::Create();
1959 ARMNN_ASSERT_MSG(M == 1,
"Constant multiplication only support 1x1x1xC, so M should always be 1 here");
1962 const void* weightData = PolymorphicPointerDowncast<const ConstantLayer>(constantLayer)
1963 ->m_LayerOutput->GetConstTensor<
void>();
1967 const auto depthwiseLayer = replacementGraph->AddDepthwiseConvolution2dLayer(
1973 layers.push_back(layer);
1974 layers.push_back(const_cast<IConnectableLayer*>(constantLayer));
1990 if (layer->
GetType() == LayerType::Multiplication)
1995 case LayerType::Multiplication:
1996 return ReplaceConstantMultiplicationWithDepthwise(subgraph, layer);
1999 throw Exception(
"Found unknown MultiplicationSupportedMode value");
2009 const ReplacementFunc replacementFuncs[] = {
2010 &ReplaceTestMultiplication,
2015 auto madeChange =
false;
2016 for (
const ReplacementFunc f : replacementFuncs)
2018 madeChange = f(subgraph, layer);
2029 TEST_CASE(
"SubgraphViewWorkingCopyReplacementFunc")
2033 const TensorInfo inputInfo({ 1, 8, 8, 16 }, DataType::QAsymmU8, 1.0f, 0);
2034 const TensorInfo constInfo({ 1, 1, 1, 16 }, DataType::QAsymmU8, 0.9f, 0,
true);
2035 const TensorInfo outputInfo({ 1, 8, 8, 16 }, DataType::QAsymmU8, 1.0f, 0);
2038 std::iota(constData.begin(), constData.end(), 0);
2045 constant->m_LayerOutput = std::make_shared<ScopedTensorHandle>(constTensor);
2052 mul->GetOutputSlot(0).SetTensorInfo(outputInfo);
2056 mul->GetOutputSlot(0).Connect(output->GetInputSlot(0));
2066 CHECK(workingCopy.GetIConnectableLayers().size() == 4);
2068 LayerType expectedSorted[] = {LayerType::Input, LayerType::Constant, LayerType::Multiplication, LayerType::Output};
2071 CHECK((expectedSorted[idx] == l->
GetType()));
2077 ReplaceUnsupportedLayers(workingCopy);
2080 CHECK(workingCopy.GetIConnectableLayers().size() == 3);
2082 LayerType expectedSortedReplaced[] = {LayerType::Input, LayerType::DepthwiseConvolution2d, LayerType::Output};
2083 workingCopy.ForEachIConnectableLayer([&idx, &expectedSortedReplaced](
const IConnectableLayer* l)
2085 CHECK((expectedSortedReplaced[idx] == l->
GetType()));
2091 TEST_CASE(
"SubgraphViewWorkingCopySubstituteSubgraph")
2112 auto workingCopy = view->GetWorkingCopy();
2113 CHECK_THROWS_AS(workingCopy.GetWorkingCopy(),
Exception);
2116 TEST_CASE(
"SubgraphViewWorkingCopyOptimizationViews")
2120 const TensorInfo inputInfo({ 1, 8, 8, 16 }, DataType::QAsymmU8, 1.0f, 0);
2121 const TensorInfo constInfo({ 1, 1, 1, 16 }, DataType::QAsymmU8, 0.9f, 0,
true);
2122 const TensorInfo outputInfo({ 1, 8, 8, 16 }, DataType::QAsymmU8, 1.0f, 0);
2125 std::iota(constData.begin(), constData.end(), 0);
2132 constant->m_LayerOutput = std::make_shared<ScopedTensorHandle>(constTensor);
2139 mul->GetOutputSlot(0).SetTensorInfo(outputInfo);
2143 mul->GetOutputSlot(0).Connect(output->GetInputSlot(0));
2154 LayerType expectedSorted[] = {LayerType::Input, LayerType::Constant, LayerType::Multiplication, LayerType::Output};
2157 CHECK((expectedSorted[idx] == l->
GetType()));
2163 ReplaceUnsupportedLayers(workingCopy);
2167 LayerType expectedSortedReplaced[] = {LayerType::Input, LayerType::DepthwiseConvolution2d, LayerType::Output};
2168 workingCopy.ForEachIConnectableLayer([&idx, &expectedSortedReplaced](
const IConnectableLayer* l)
2170 CHECK((expectedSortedReplaced[idx] == l->
GetType()));
2190 CHECK(optimizationViews.
Validate(*view));
2193 TEST_CASE(
"SubgraphViewWorkingCopyReplaceSlots")
2196 const TensorInfo inputInfo({ 1, 8, 8, 16 }, DataType::QAsymmU8, 1.0f, 0);
2197 const TensorInfo constInfo({ 1, 1, 1, 16 }, DataType::QAsymmU8, 0.9f, 0,
true);
2198 const TensorInfo outputInfo({ 1, 8, 8, 16 }, DataType::QAsymmU8, 1.0f, 0);
2201 std::iota(constData.begin(), constData.end(), 0);
2208 constant->m_LayerOutput = std::make_shared<ScopedTensorHandle>(constTensor);
2215 mul->GetOutputSlot(0).SetTensorInfo(outputInfo);
2219 mul->GetOutputSlot(0).Connect(output->GetInputSlot(0));
2222 CreateIInputsFrom({mul}),
2223 CreateIOutputsFrom({mul}));
2230 LayerType expectedSorted[] = {LayerType::Input, LayerType::Constant, LayerType::Multiplication, LayerType::Output};
2233 CHECK((expectedSorted[idx] == l->
GetType()));
2239 ReplaceUnsupportedLayers(workingCopy);
2243 LayerType expectedSortedReplaced[] = {LayerType::Input, LayerType::DepthwiseConvolution2d, LayerType::Output};
2247 CHECK((expectedSortedReplaced[idx] == l->
GetType()));
A layer that the constant data can be bound to.
This layer represents a split operation.
A ViewsDescriptor for the SplitterLayer.
Interface for a layer that is connectable to other layers via InputSlots and OutputSlots.
const TensorShape & GetShape() const
void swap(OriginsDescriptor &first, OriginsDescriptor &second)
const IConnectableLayers & GetIConnectableLayers() const
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
LayerT * AddLayer(Args &&... args)
Adds a new layer, of type LayerType, to the graph constructed with the arguments passed.
A Convolution2dDescriptor for the Convolution2dLayer.
int Connect(InputSlot &destination)
void AddSubstitution(SubstitutionPair &&substitution)
This layer represents an activation operation with the specified activation function.
void SetBackendId(const BackendId &id)
virtual const IInputSlot * GetConnection(unsigned int index) const =0
void SubstituteSubgraph(SubgraphView &, IConnectableLayer *)
These methods should be called on a working copy subgraph created from GetWorkingCopy.
virtual void SetTensorInfo(const TensorInfo &tensorInfo)=0
void SetShape(const TensorShape &newShape)
std::unique_ptr< void, CompiledBlobDeleter > CompiledBlobPtr
The SubgraphView class represents a subgraph of a Graph.
const InputSlot & GetInputSlot(unsigned int index) const override
Get a const input slot handle by slot index.
A layer user-provided data can be bound to (e.g. inputs, outputs).
std::list< IConnectableLayer * > IConnectableLayers
#define ARMNN_ASSERT_MSG(COND, MSG)
An output connection slot for a layer.
SubgraphView::InputSlots CreateInputsFrom(const std::vector< Layer *> &layers)
An OriginsDescriptor for the ConcatLayer.
std::vector< IOutputSlot * > IOutputSlots
A tensor defined by a TensorInfo (shape and data type) and an immutable backing store.
This layer represents a merge operation.
void ForEachIConnectableLayer(Func func) const
const std::string & GetNameStr() const
LayerType GetType() const override
Returns the armnn::LayerType of this layer.
float Activation(float in, ActivationFunction function, float a, float b)
std::vector< SubgraphViewPtr > Subgraphs
virtual const IConnectableLayer & GetOwningIConnectableLayer() const =0
INetworkPtr & GetINetwork()
bool Validate(const SubgraphView &originalSubgraph) const
An ActivationDescriptor for the ActivationLayer.
const BackendId & GetBackendId() const
virtual LayerType GetType() const =0
Returns the armnn::LayerType of this layer.
This layer represents an addition operation.
void SubstituteSubgraph(SubgraphView &subgraph, IConnectableLayer *substituteLayer)
Substitutes the given sub-graph with either a new layer or a new sub-graph.
std::unique_ptr< SubgraphView > SubgraphViewPtr
EmptyOptional is used to initialize the Optional class in case we want to have default value for an O...
SubgraphView::SubgraphViewPtr CreateSubgraphViewFrom(SubgraphView::InputSlots &&inputs, SubgraphView::OutputSlots &&outputs, SubgraphView::Layers &&layers)
SubgraphView::OutputSlots CreateOutputsFrom(const std::vector< Layer *> &layers)
Base class for all ArmNN exceptions so that users can filter to just those.
void SetTensorInfo(const TensorInfo &tensorInfo) override
virtual const IInputSlot & GetInputSlot(unsigned int index) const =0
Get a const input slot handle by slot index.
std::enable_if_t< std::is_unsigned< Source >::value &&std::is_unsigned< Dest >::value, Dest > numeric_cast(Source source)
const OutputSlot & GetOutputSlot(unsigned int index=0) const override
Get the const output slot handle by slot index.
virtual const TensorInfo & GetTensorInfo() const =0
virtual const IOutputSlot & GetOutputSlot(unsigned int index) const =0
Get the const output slot handle by slot index.
This layer represents a convolution 2d operation.
virtual int Connect(IInputSlot &destination)=0
void ForEachLayer(Func func) const
A PreCompiledDescriptor for the PreCompiledLayer.
This layer represents a multiplication operation.
SubgraphView GetWorkingCopy()
This method returns a copy of the original SubgraphView provided by OptimizeSubgraphView with a separ...
A DepthwiseConvolution2dDescriptor for the DepthwiseConvolution2dLayer.
const InputSlot * GetConnection(unsigned int index) const override
unsigned int GetNumElements() const
LayerType
When adding a new layer, adapt also the LastLayer enum value in the enum class LayerType below...