IVGCVSW-5200 Update pyarmnn
authorJan Eilers <jan.eilers@arm.com>
Wed, 12 Aug 2020 13:59:06 +0000 (14:59 +0100)
committerTeresaARM <teresa.charlinreyes@arm.com>
Mon, 17 Aug 2020 16:10:54 +0000 (16:10 +0000)
 * Add HalfPixelCenters to Resize
 * Update pyarmnn version to semantic versioning
 * Add fill operator
 * Add Bf16 optimization
 * Add Gather operator
 * Update TransposeConvolution2d descriptor
 * Add Rank operator
 * Add load dynamic tensor support of TfLiteParser

Signed-off-by: Jan Eilers <jan.eilers@arm.com>
Change-Id: I7e76ed286ab87bd97a65ff62868ba7db7967376f

python/pyarmnn/examples/example_utils.py
python/pyarmnn/src/pyarmnn/__init__.py
python/pyarmnn/src/pyarmnn/swig/armnn_tfliteparser.i
python/pyarmnn/src/pyarmnn/swig/armnn_version.i
python/pyarmnn/src/pyarmnn/swig/modules/armnn_descriptors.i
python/pyarmnn/src/pyarmnn/swig/modules/armnn_network.i
python/pyarmnn/test/test_descriptors.py
python/pyarmnn/test/test_network.py
python/pyarmnn/test/test_tflite_parser.py

index f4d1e4e..5ef30f2 100644 (file)
@@ -73,7 +73,7 @@ def __create_network(model_file: str, backends: list, parser=None):
 
 
 def create_tflite_network(model_file: str, backends: list = ['CpuAcc', 'CpuRef']):
-    """Creates a network from an onnx model file.
+    """Creates a network from a tflite model file.
 
     Args:
         model_file (str): Path of the model file.
@@ -92,7 +92,7 @@ def create_tflite_network(model_file: str, backends: list = ['CpuAcc', 'CpuRef']
 
 
 def create_onnx_network(model_file: str, backends: list = ['CpuAcc', 'CpuRef']):
-    """Creates a network from a tflite model file.
+    """Creates a network from an onnx model file.
 
     Args:
         model_file (str): Path of the model file.
index 265880f..b1aa81f 100644 (file)
@@ -47,7 +47,7 @@ except ImportError as err:
         raise RuntimeError(message)
 
 try:
-    from ._generated.pyarmnn_tfliteparser import ITfLiteParser
+    from ._generated.pyarmnn_tfliteparser import ITfLiteParser, TfLiteParserOptions
 except ImportError as err:
     logger = logging.getLogger(__name__)
     message = "Your ArmNN library instance does not support TF lite models parser functionality. "
@@ -92,8 +92,8 @@ from ._generated.pyarmnn import ComparisonDescriptor, ComparisonOperation_Equal,
 from ._generated.pyarmnn import UnaryOperation_Abs, UnaryOperation_Exp, UnaryOperation_Sqrt, UnaryOperation_Rsqrt, \
     UnaryOperation_Neg, ElementwiseUnaryDescriptor
 from ._generated.pyarmnn import Convolution2dDescriptor, DepthToSpaceDescriptor, DepthwiseConvolution2dDescriptor, \
-    DetectionPostProcessDescriptor, FakeQuantizationDescriptor, FullyConnectedDescriptor, \
-    InstanceNormalizationDescriptor, LstmDescriptor, L2NormalizationDescriptor, MeanDescriptor
+    DetectionPostProcessDescriptor, FakeQuantizationDescriptor, FillDescriptor, FullyConnectedDescriptor, \
+    GatherDescriptor, InstanceNormalizationDescriptor, LstmDescriptor, L2NormalizationDescriptor, MeanDescriptor
 from ._generated.pyarmnn import NormalizationAlgorithmChannel_Across, NormalizationAlgorithmChannel_Within, \
     NormalizationAlgorithmMethod_LocalBrightness, NormalizationAlgorithmMethod_LocalContrast, NormalizationDescriptor
 from ._generated.pyarmnn import PadDescriptor
index 825b104..3ed5d6b 100644 (file)
@@ -87,14 +87,37 @@ public:
             list: A list of the output tensor names for the given model.
         ") GetSubgraphOutputTensorNames;
     std::vector<std::string> GetSubgraphOutputTensorNames(size_t subgraphId);
+
+    %feature("flatnested");
+    %feature("docstring",
+             "
+    Options for TfLiteParser.
+
+            Contains:
+    m_StandInLayerForUnsupported (bool): Add StandInLayers as placeholders for unsupported operators.
+            Default: False
+    m_InferAndValidate (bool): Infer output shape of operations based on their input shape. Default: False
+    ")TfLiteParserOptions;
+    struct TfLiteParserOptions
+    {
+        TfLiteParserOptions();
+
+        bool m_StandInLayerForUnsupported;
+        bool m_InferAndValidate;
+    };
 };
 
 %extend ITfLiteParser {
 // This is not a substitution of the default constructor of the Armnn class. It tells swig to create custom __init__
 // method for ITfLiteParser python object that will use static factory method to do the job.
 
-    ITfLiteParser() {
-        return armnnTfLiteParser::ITfLiteParser::CreateRaw();
+    ITfLiteParser(const armnnTfLiteParser::ITfLiteParser::TfLiteParserOptions* options = nullptr) {
+        if (options) {
+            return armnnTfLiteParser::ITfLiteParser::CreateRaw(
+                    armnn::Optional<armnnTfLiteParser::ITfLiteParser::TfLiteParserOptions>(*options));
+        } else {
+            return armnnTfLiteParser::ITfLiteParser::CreateRaw();
+        }
     }
 
 // The following does not replace a real destructor of the Armnn class.
@@ -127,6 +150,7 @@ public:
 
 }
 
-}
+} // end of namespace armnnTfLiteParser
+
 // Clear exception typemap.
 %exception;
index b21fbb1..039b166 100644 (file)
@@ -39,7 +39,7 @@ std::string GetVersion();
 
 %feature("docstring",
 "
-    Returns Arm NN library major version. The year of the release.
+    Returns Arm NN library major version.
 
     Returns:
         str: Major version of Arm NN installed.
@@ -49,7 +49,7 @@ std::string GetMajorVersion();
 
 %feature("docstring",
 "
-    Returns Arm NN library minor version. Month of the year of the release.
+    Returns Arm NN library minor version.
 
     Returns:
         str: Minor version of Arm NN installed.
index 9a01a52..a050722 100644 (file)
@@ -15,6 +15,7 @@ namespace std {
 }
 
 %include "typemaps/vectors.i"
+%include "stdint.i"
 
 %typemap(out) const uint32_t*
 %{
@@ -388,6 +389,46 @@ struct FakeQuantizationDescriptor
 
 %feature("docstring",
     "
+    A descriptor for the Fill layer. Creates a tensor filled with a scalar value.
+
+    Contains:
+        m_Value (float): Value the tensor will be filled with.
+
+    ") FillDescriptor;
+struct FillDescriptor
+{
+    FillDescriptor();
+    FillDescriptor(const float& value);
+
+    bool operator ==(const FillDescriptor& rhs) const;
+
+    float m_Value;
+};
+
+%feature("docstring",
+    "
+    A descriptor for the Gather layer.
+
+    Contains:
+        m_Axis (int32_t): The axis from where to gather values from.
+
+    ") GatherDescriptor;
+struct GatherDescriptor
+{
+    GatherDescriptor();
+
+    GatherDescriptor(int32_t axis);
+
+    bool operator ==(const GatherDescriptor& rhs) const
+    {
+        return m_Axis == rhs.m_Axis;
+    }
+
+    int32_t m_Axis;
+};
+
+%feature("docstring",
+    "
     A descriptor for the FullyConnected layer. See `INetwork.AddFullyConnectedLayer()`.
 
     Contains:
@@ -661,7 +702,9 @@ struct ReshapeDescriptor
                         Default: `ResizeMethod_NearestNeighbor`.
         m_DataLayout (int): The data layout to be used (`DataLayout_NCHW`, `DataLayout_NHWC`). Default: `DataLayout_NCHW`.
         m_AlignCorners (bool):  Align corners or not when resizing. If True, corner pixel values are preserved after resizing.
-                                        Default: False
+                                        Default: False.
+        m_HalfPixelCenters (bool): If true, calculates the pixels from the center instead of from the edge.
+                                    Default: False.
 
     ") ResizeDescriptor;
 struct ResizeDescriptor
@@ -673,6 +716,7 @@ struct ResizeDescriptor
     ResizeMethod m_Method;
     DataLayout m_DataLayout;
     bool m_AlignCorners;
+    bool m_HalfPixelCenters;
 
     bool operator ==(const ResizeDescriptor& rhs) const;
 };
@@ -970,20 +1014,24 @@ struct SoftmaxDescriptor
         m_StrideY (int): Underlying C++ data type is uint32_t. Stride value when proceeding through input for the height dimension. Default: 0.
         m_BiasEnabled (bool): Enable/disable bias. Default: false.
         m_DataLayout (int): The data layout to be used (`DataLayout_NCHW`, `DataLayout_NHWC`). Default: `DataLayout_NCHW`.
+        m_OutputShapeEnabled (bool): Set to true if output shape is specified. Will prevent output shape inference.
+        m_OutputShape (list of int): Output shape if it has been specified.
 
     ") TransposeConvolution2dDescriptor;
 struct TransposeConvolution2dDescriptor
 {
     TransposeConvolution2dDescriptor();
 
-    uint32_t   m_PadLeft;
-    uint32_t   m_PadRight;
-    uint32_t   m_PadTop;
-    uint32_t   m_PadBottom;
-    uint32_t   m_StrideX;
-    uint32_t   m_StrideY;
-    bool       m_BiasEnabled;
-    DataLayout m_DataLayout;
+    uint32_t                  m_PadLeft;
+    uint32_t                  m_PadRight;
+    uint32_t                  m_PadTop;
+    uint32_t                  m_PadBottom;
+    uint32_t                  m_StrideX;
+    uint32_t                  m_StrideY;
+    bool                      m_BiasEnabled;
+    DataLayout                m_DataLayout;
+    bool                      m_OutputShapeEnabled;
+    std::vector<unsigned int> m_OutputShape;
 
     bool operator ==(const TransposeConvolution2dDescriptor& rhs) const;
 };
index b065331..4665e60 100644 (file)
@@ -20,15 +20,21 @@ Struct for holding options relating to the Arm NN optimizer. See `Optimize`.
 
 Contains:
     m_debug (bool): Add debug data for easier troubleshooting.
-    m_ReduceFp32ToFp16 (bool): Reduce Fp32 data to Fp16 for faster processing.
+    m_ReduceFp32ToBf16 (bool): Reduces Fp32 network to BFloat16 (Bf16) for faster processing. Layers
+                               that can not be reduced will be left in Fp32.
+    m_ReduceFp32ToFp16 (bool): Reduces Fp32 network to Fp16 for faster processing. Layers
+                               that can not be reduced will be left in Fp32.
 
 ") OptimizerOptions;
 struct OptimizerOptions
 {
     OptimizerOptions();
 
-    OptimizerOptions(bool reduceFp32ToFp16, bool debug);
+    OptimizerOptions(bool reduceFp32ToFp16,
+                     bool debug,
+                     bool reduceFp32ToBf16 = false);
 
+    bool m_ReduceFp32ToBf16;
     bool m_ReduceFp32ToFp16;
     bool m_Debug;
 };
@@ -501,21 +507,35 @@ public:
     armnn::IConnectableLayer* AddDivisionLayer(const char* name = nullptr);
 
     %feature("docstring",
-    "
-    Adds an Elementwise Unary layer to the network. Type of unary operation to use is decided by elementwiseUnaryDescriptor. Unary operations supported are (Abs, Exp, Neg, Rsqrt, Sqrt)
+        "
+        Adds an Elementwise Unary layer to the network. Type of unary operation to use is decided by elementwiseUnaryDescriptor. Unary operations supported are (Abs, Exp, Neg, Rsqrt, Sqrt)
 
-    Args:
-        elementwiseUnaryDescriptor (ElementwiseUnaryDescriptor): ElementwiseUnaryDescriptor to configure the choice of unary operation added to the network.
-        name (str): Optional name for the layer.
+        Args:
+            elementwiseUnaryDescriptor (ElementwiseUnaryDescriptor): ElementwiseUnaryDescriptor to configure the choice of unary operation added to the network.
+            name (str): Optional name for the layer.
 
-    Returns:
-        IConnectableLayer: Interface for configuring the layer.
-    ") AddElementwiseUnaryLayer;
+        Returns:
+            IConnectableLayer: Interface for configuring the layer.
+        ") AddElementwiseUnaryLayer;
     armnn::IConnectableLayer* AddElementwiseUnaryLayer(const ElementwiseUnaryDescriptor& elementwiseUnaryDescriptor,
                                                        const char* name = nullptr);
 
     %feature("docstring",
         "
+        Add a Fill layer to the network.
+
+        Args:
+            FillDescriptor (FillDescriptor): Descriptor for the fill operation.
+            name (str): Optional name for the layer.
+
+        Returns:
+            IConnectableLayer: Interface for configuring the layer.
+        ") AddFillLayer;
+    armnn::IConnectableLayer* AddFillLayer(const FillDescriptor& fillDescriptor,
+                                           const char* name = nullptr);
+
+    %feature("docstring",
+        "
         Adds a Floor layer to the network.
 
         Args:
@@ -531,12 +551,14 @@ public:
         Add Gather layer to the network.
 
         Args:
+            descriptor (GatherDescriptor): Descriptor for the gather operation.
             name (str): Optional name for the layer.
 
         Returns:
             IConnectableLayer: Interface for configuring the layer.
         ") AddGatherLayer;
-    armnn::IConnectableLayer* AddGatherLayer(const char* name = nullptr);
+    armnn::IConnectableLayer* AddGatherLayer(const GatherDescriptor& descriptor,
+                                             const char* name = nullptr);
 
     %feature("docstring",
         "
@@ -752,6 +774,20 @@ public:
     armnn::IConnectableLayer* AddQuantizedLstmLayer(const armnn::QuantizedLstmInputParams& params,
                                                      const char* name = nullptr);
 
+
+    %feature("docstring",
+        "
+        Adds a Rank layer to the network.
+
+        Args:
+            name (str): Optional name for the layer.
+
+        Returns:
+            IConnectableLayer: Interface for configuring the layer.
+        ") AddRankLayer;
+    armnn::IConnectableLayer* AddRankLayer(const char* name = nullptr);
+
+    
     %feature("docstring",
         "
         Adds a Reshape layer to the network.
index 6d49747..b0574a1 100644 (file)
@@ -143,6 +143,16 @@ def test_fakequantization_descriptor_default_values():
     np.allclose(-6, desc.m_Min)
 
 
+def test_fill_descriptor_default_values():
+    desc = ann.FillDescriptor()
+    np.allclose(0, desc.m_Value)
+
+
+def test_gather_descriptor_default_values():
+    desc = ann.GatherDescriptor()
+    assert desc.m_Axis == 0
+
+
 def test_fully_connected_descriptor_default_values():
     desc = ann.FullyConnectedDescriptor()
     assert desc.m_BiasEnabled == False
@@ -370,7 +380,7 @@ def test_space_to_batch_nd_descriptor_ctor():
 
 
 def test_transpose_convolution2d_descriptor_default_values():
-    desc = ann.DepthwiseConvolution2dDescriptor()
+    desc = ann.TransposeConvolution2dDescriptor()
     assert desc.m_PadLeft == 0
     assert desc.m_PadTop == 0
     assert desc.m_PadRight == 0
@@ -379,6 +389,7 @@ def test_transpose_convolution2d_descriptor_default_values():
     assert desc.m_StrideY == 0
     assert desc.m_BiasEnabled == False
     assert desc.m_DataLayout == ann.DataLayout_NCHW
+    assert desc.m_OutputShapeEnabled == False
 
 
 def test_view_descriptor_default_values():
@@ -480,7 +491,9 @@ generated_classes_names = list(map(lambda x: x[0], generated_classes))
                                        'StackDescriptor',
                                        'StridedSliceDescriptor',
                                        'TransposeConvolution2dDescriptor',
-                                       'ElementwiseUnaryDescriptor'])
+                                       'ElementwiseUnaryDescriptor',
+                                       'FillDescriptor',
+                                       'GatherDescriptor'])
 class TestDescriptorMassChecks:
 
     def test_desc_implemented(self, desc_name):
@@ -522,7 +535,9 @@ generated_classes_names = list(map(lambda x: x[0], generated_classes))
                                        'StackDescriptor',
                                        'StridedSliceDescriptor',
                                        'TransposeConvolution2dDescriptor',
-                                       'ElementwiseUnaryDescriptor'])
+                                       'ElementwiseUnaryDescriptor',
+                                       'FillDescriptor',
+                                       'GatherDescriptor'])
 class TestDescriptorMassChecks:
 
     def test_desc_implemented(self, desc_name):
index fc2591c..679e640 100644 (file)
@@ -6,6 +6,23 @@ import stat
 import pytest
 import pyarmnn as ann
 
+def test_optimizer_options_default_values():
+    opt = ann.OptimizerOptions()
+    assert opt.m_ReduceFp32ToFp16 == False
+    assert opt.m_Debug == False
+    assert opt.m_ReduceFp32ToBf16 == False
+
+def test_optimizer_options_set_values1():
+    opt = ann.OptimizerOptions(True, True)
+    assert opt.m_ReduceFp32ToFp16 == True
+    assert opt.m_Debug == True
+    assert opt.m_ReduceFp32ToBf16 == False
+
+def test_optimizer_options_set_values2():
+    opt = ann.OptimizerOptions(False, False, True)
+    assert opt.m_ReduceFp32ToFp16 == False
+    assert opt.m_Debug == False
+    assert opt.m_ReduceFp32ToBf16 == True
 
 @pytest.fixture(scope="function")
 def get_runtime(shared_data_folder, network_file):
@@ -166,6 +183,7 @@ def test_serialize_to_dot_mode_readonly(network_file, get_runtime, tmpdir):
     'AddDivisionLayer',
     'AddElementwiseUnaryLayer',
     'AddFloorLayer',
+    'AddFillLayer',
     'AddFullyConnectedLayer',
     'AddGatherLayer',
     'AddInputLayer',
@@ -186,6 +204,7 @@ def test_serialize_to_dot_mode_readonly(network_file, get_runtime, tmpdir):
     'AddPreluLayer',
     'AddQuantizeLayer',
     'AddQuantizedLstmLayer',
+    'AddRankLayer',
     'AddReshapeLayer',
     'AddResizeLayer',
     'AddSliceLayer',
index 344ec7c..8735eef 100644 (file)
@@ -7,6 +7,12 @@ import pyarmnn as ann
 import numpy as np
 
 
+def test_TfLiteParserOptions_default_values():
+    parserOptions = ann.TfLiteParserOptions()
+    assert parserOptions.m_InferAndValidate == False
+    assert parserOptions.m_StandInLayerForUnsupported == False
+
+
 @pytest.fixture()
 def parser(shared_data_folder):
     """
@@ -30,6 +36,42 @@ def test_check_tflite_parser_swig_ownership(parser):
     assert parser.thisown
 
 
+def test_tflite_parser_with_optional_options():
+    parserOptions = ann.TfLiteParserOptions()
+    parserOptions.m_InferAndValidate = True
+    parser = ann.ITfLiteParser(parserOptions)
+    assert parser.thisown
+
+
+def create_with_opt() :
+    parserOptions = ann.TfLiteParserOptions()
+    parserOptions.m_InferAndValidate = True
+    return ann.ITfLiteParser(parserOptions)
+
+def test_tflite_parser_with_optional_options_out_of_scope(shared_data_folder):
+    parser = create_with_opt()
+    network = parser.CreateNetworkFromBinaryFile(os.path.join(shared_data_folder, "mock_model.tflite"))
+
+    graphs_count = parser.GetSubgraphCount()
+    graph_id = graphs_count - 1
+
+    input_names = parser.GetSubgraphInputTensorNames(graph_id)
+    input_binding_info = parser.GetNetworkInputBindingInfo(graph_id, input_names[0])
+
+    output_names = parser.GetSubgraphOutputTensorNames(graph_id)
+
+    preferred_backends = [ann.BackendId('CpuAcc'), ann.BackendId('CpuRef')]
+
+    options = ann.CreationOptions()
+    runtime = ann.IRuntime(options)
+
+    opt_network, messages = ann.Optimize(network, preferred_backends, runtime.GetDeviceSpec(), ann.OptimizerOptions())
+    assert 0 == len(messages)
+
+    net_id, messages = runtime.LoadNetwork(opt_network)
+    assert "" == messages
+
+
 def test_tflite_get_sub_graph_count(parser):
     graphs_count = parser.GetSubgraphCount()
     assert graphs_count == 1