1648 TEST_CASE(
"SingleSubgraph")
1680 SubgraphViewSelector::SelectSubgraphs(
1683 [](
const Layer & l){
1688 CHECK(subgraphs.size() == 1);
1689 if(subgraphs.size() == 1)
1691 CHECK((subgraphs[0] !=
nullptr));
1693 if (subgraphs[0].
get() !=
nullptr)
1695 unsigned int numInputSlots =
armnn::numeric_cast<
unsigned int>(subgraphs[0]->GetIInputSlots().size());
1696 unsigned int numOutputSlots =
armnn::numeric_cast<
unsigned int>(subgraphs[0]->GetIOutputSlots().size());
1698 CHECK((numInputSlots == 1));
1699 CHECK((numOutputSlots == 1));
1720 TEST_CASE(
"MultipleSubgraphs")
1750 weights1->GetOutputSlot(0).Connect(convLayer1->
GetInputSlot(1));
1752 weights2->GetOutputSlot(0).Connect(convLayer2->GetInputSlot(1));
1753 convLayer2->GetOutputSlot(0).Connect(pConcatLayer->
GetInputSlot(1));
1758 SubgraphViewSelector::SelectSubgraphs(
1761 [](
const Layer & l){
1766 CHECK(subgraphs.size() == 2);
1767 if(subgraphs.size() == 2)
1769 CHECK((subgraphs[0] !=
nullptr));
1770 CHECK((subgraphs[1] !=
nullptr));
1772 if (subgraphs[0].
get() !=
nullptr && subgraphs[1].
get() !=
nullptr)
1775 std::sort(subgraphs.begin(), subgraphs.end(),
1778 return (lhs->GetIInputSlots().size() < rhs->GetIInputSlots().size());
1782 unsigned int numInputSlots1 =
armnn::numeric_cast<
unsigned int>(subgraphs[0]->GetIInputSlots().size());
1783 unsigned int numOutputSlots1 =
armnn::numeric_cast<
unsigned int>(subgraphs[0]->GetIOutputSlots().size());
1785 unsigned int numInputSlots2 =
armnn::numeric_cast<
unsigned int>(subgraphs[1]->GetIInputSlots().size());
1786 unsigned int numOutputSlots2 =
armnn::numeric_cast<
unsigned int>(subgraphs[1]->GetIOutputSlots().size());
1820 TEST_CASE(
"SubgraphCycles")
1862 SubgraphViewSelector::SelectSubgraphs(
1867 bool toSelect = (l.
GetNameStr().find(
'm') != std::string::npos);
1880 CHECK(subgraphs.size() == 2);
1881 if (subgraphs.size() == 2)
1884 CHECK((subgraphs[0] !=
nullptr));
1885 CHECK((subgraphs[1] !=
nullptr));
1887 if (subgraphs[0].
get() !=
nullptr && subgraphs[1].
get() !=
nullptr)
1890 std::sort(subgraphs.begin(), subgraphs.end(),
1893 return (lhs->GetIConnectableLayers().size() < rhs->GetIConnectableLayers().size());
1898 CHECK(subgraphs[0]->GetIConnectableLayers().size() == 1);
1899 CHECK(subgraphs[1]->GetIConnectableLayers().size() == 2);
1901 CompareSubgraphViews(subgraphs[0], outputSubgraph);
1902 CompareSubgraphViews(subgraphs[1], inputSubgraph);
1907 TEST_CASE(
"SubgraphOrder")
1921 {output, input, activation});
1926 view->ForEachLayer([&idx, &expectedSorted](
const Layer* l)
1928 CHECK((expectedSorted[idx] == l->
GetType()));
1934 TEST_CASE(
"SubgraphViewWorkingCopy")
1955 workingCopy.ForEachIConnectableLayer([&idx, &expectedSorted](
const IConnectableLayer* l)
1957 CHECK((expectedSorted[idx] == l->
GetType()));
1963 bool ReplaceConstantMultiplicationWithDepthwise(
SubgraphView& subgraph,
1966 if (layer->
GetType() == LayerType::Multiplication)
1975 if (constantLayer->
GetType() != LayerType::Constant)
1977 std::swap(patternSubgraphInput, patternSubgraphConstant);
1981 if (constantLayer->
GetType() == LayerType::Constant)
1990 auto replacementGraph = INetwork::Create();
1998 ARMNN_ASSERT_MSG(M == 1,
"Constant multiplication only support 1x1x1xC, so M should always be 1 here");
2001 const void* weightData = PolymorphicPointerDowncast<const ConstantLayer>(constantLayer)
2002 ->m_LayerOutput->GetConstTensor<
void>();
2006 const auto depthwiseLayer = replacementGraph->AddDepthwiseConvolution2dLayer(
2007 desc,
"Replacement for Constant-Multiplication");
2012 layers.push_back(layer);
2013 layers.push_back(const_cast<IConnectableLayer*>(constantLayer));
2016 {patternSubgraphInput, patternSubgraphConstant},
2031 if (layer->
GetType() == LayerType::Multiplication)
2036 case LayerType::Multiplication:
2037 return ReplaceConstantMultiplicationWithDepthwise(subgraph, layer);
2040 throw Exception(
"Found unknown MultiplicationSupportedMode value");
2050 const ReplacementFunc replacementFuncs[] = {
2051 &ReplaceTestMultiplication,
2056 auto madeChange =
false;
2057 for (
const ReplacementFunc f : replacementFuncs)
2059 madeChange = f(subgraph, layer);
2070 TEST_CASE(
"SubgraphViewWorkingCopyReplacementFunc")
2074 const TensorInfo inputInfo({ 1, 8, 8, 16 }, DataType::QAsymmU8, 1.0f, 0);
2075 const TensorInfo constInfo({ 1, 1, 1, 16 }, DataType::QAsymmU8, 0.9f, 0,
true);
2076 const TensorInfo outputInfo({ 1, 8, 8, 16 }, DataType::QAsymmU8, 1.0f, 0);
2079 std::iota(constData.begin(), constData.end(), 0);
2086 constant->m_LayerOutput = std::make_shared<ScopedTensorHandle>(constTensor);
2093 mul->GetOutputSlot(0).SetTensorInfo(outputInfo);
2097 mul->GetOutputSlot(0).Connect(output->GetInputSlot(0));
2107 CHECK(workingCopy.GetIConnectableLayers().size() == 4);
2109 LayerType expectedSorted[] = {LayerType::Input, LayerType::Constant, LayerType::Multiplication, LayerType::Output};
2112 CHECK((expectedSorted[idx] == l->
GetType()));
2118 ReplaceUnsupportedLayers(workingCopy);
2121 CHECK(workingCopy.GetIConnectableLayers().size() == 3);
2123 LayerType expectedSortedReplaced[] = {LayerType::Input, LayerType::DepthwiseConvolution2d, LayerType::Output};
2124 workingCopy.ForEachIConnectableLayer([&idx, &expectedSortedReplaced](
const IConnectableLayer* l)
2126 CHECK((expectedSortedReplaced[idx] == l->
GetType()));
2132 TEST_CASE(
"SubgraphViewWorkingCopySubstituteSubgraph")
2153 auto workingCopy = view->GetWorkingCopy();
2154 CHECK_THROWS_AS(workingCopy.GetWorkingCopy(),
Exception);
2157 TEST_CASE(
"SubgraphViewWorkingCopyOptimizationViews")
2161 const TensorInfo inputInfo({ 1, 8, 8, 16 }, DataType::QAsymmU8, 1.0f, 0);
2162 const TensorInfo constInfo({ 1, 1, 1, 16 }, DataType::QAsymmU8, 0.9f, 0,
true);
2163 const TensorInfo outputInfo({ 1, 8, 8, 16 }, DataType::QAsymmU8, 1.0f, 0);
2166 std::iota(constData.begin(), constData.end(), 0);
2173 constant->m_LayerOutput = std::make_shared<ScopedTensorHandle>(constTensor);
2180 mul->GetOutputSlot(0).SetTensorInfo(outputInfo);
2184 mul->GetOutputSlot(0).Connect(output->GetInputSlot(0));
2195 LayerType expectedSorted[] = {LayerType::Input, LayerType::Constant, LayerType::Multiplication, LayerType::Output};
2198 CHECK((expectedSorted[idx] == l->
GetType()));
2204 ReplaceUnsupportedLayers(workingCopy);
2208 LayerType expectedSortedReplaced[] = {LayerType::Input, LayerType::DepthwiseConvolution2d, LayerType::Output};
2209 workingCopy.ForEachIConnectableLayer([&idx, &expectedSortedReplaced](
const IConnectableLayer* l)
2211 CHECK((expectedSortedReplaced[idx] == l->
GetType()));
2231 CHECK(optimizationViews.
Validate(*view));
2234 TEST_CASE(
"SubgraphViewWorkingCopyReplaceSlots")
2237 const TensorInfo inputInfo({ 1, 8, 8, 16 }, DataType::QAsymmU8, 1.0f, 0);
2238 const TensorInfo constInfo({ 1, 1, 1, 16 }, DataType::QAsymmU8, 0.9f, 0,
true);
2239 const TensorInfo outputInfo({ 1, 8, 8, 16 }, DataType::QAsymmU8, 1.0f, 0);
2242 std::iota(constData.begin(), constData.end(), 0);
2249 constant->m_LayerOutput = std::make_shared<ScopedTensorHandle>(constTensor);
2256 mul->GetOutputSlot(0).SetTensorInfo(outputInfo);
2260 mul->GetOutputSlot(0).Connect(output->GetInputSlot(0));
2263 CreateIInputsFrom({mul}),
2264 CreateIOutputsFrom({mul}));
2271 LayerType expectedSorted[] = {LayerType::Input, LayerType::Constant, LayerType::Multiplication, LayerType::Output};
2274 CHECK((expectedSorted[idx] == l->
GetType()));
2280 ReplaceUnsupportedLayers(workingCopy);
2284 LayerType expectedSortedReplaced[] = {LayerType::Input, LayerType::DepthwiseConvolution2d, LayerType::Output};
2288 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.
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...
SubgraphView::InputSlots CreateInputsFrom(Layer *layer, std::vector< unsigned int > ignoreSlots)
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...