1# About PyArmNN 2 3PyArmNN is a python extension for [Arm NN SDK](https://developer.arm.com/ip-products/processors/machine-learning/arm-nn). 4PyArmNN provides interface similar to Arm NN C++ Api. 5Before you proceed with the project setup, you will need to checkout and build a corresponding Arm NN version. 6 7PyArmNN is built around public headers from the armnn/include folder of Arm NN. PyArmNN does not implement any computation kernels itself, all operations are 8delegated to the Arm NN library. 9 10The [SWIG](http://www.swig.org/) project is used to generate the Arm NN python shadow classes and C wrapper. 11 12The following diagram shows the conceptual architecture of this library: 13 14 15# Setup development environment 16 17Before, proceeding to the next steps, make sure that: 18 191. You have Python 3.6+ installed system-side. The package is not compatible with older Python versions. 202. You have python3.6-dev installed system-side. This contains header files needed to build PyArmNN extension module. 213. In case you build Python from sources manually, make sure that the following libraries are installed and available in you system: 22``python3.6-dev build-essential checkinstall libreadline-gplv2-dev libncursesw5-dev libssl-dev libsqlite3-dev tk-dev libgdbm-dev libc6-dev libbz2-dev`` 234. Install SWIG 4.x. Only 3.x version is typically available in Linux package managers, so you will have to build it and install it from sources. It can be downloaded from the [SWIG project website](http://www.swig.org/download.html) or from [SWIG GitHub](https://github.com/swig/swig). To install it follow the guide on [SWIG GitHub](https://github.com/swig/swig/wiki/Getting-Started). 24 25## Setup virtual environment 26 27Now you can proceed with setting up workspace. It is recommended to create a python virtual environment, so you do not pollute your working folder: 28```bash 29python -m venv env 30source env/bin/activate 31``` 32 33You may run into missing python modules such as *wheel*. Make sure to install those using pip: 34```bash 35pip install wheel 36``` 37 38## Build python distr 39 40Python supports source and binary distribution packages. 41 42Source distr contains setup.py script that is executed on the users machine during package installation. 43When preparing binary distr (wheel), setup.py is executed on the build machine and the resulting package contains only the result 44of the build (generated files and resources, test results etc). 45 46In our case, PyArmNN depends on Arm NN installation. Thus, binary distr will be linked with 47the local build machine libraries and runtime. 48 49There are 2 ways to build the python packages. Either directly using the python scripts or using CMake. 50 51### CMake build 52 53The recommended aproach is to build PyArmNN together with Arm NN by adding the following options to your CMake command: 54``` 55-DBUILD_PYTHON_SRC=1 56-DBUILD_PYTHON_WHL=1 57``` 58This will build either the source package or the wheel or both. Current project headers and build libraries will be used, so there is no need to provide them. 59 60SWIG is required to generate the wrappers. If CMake did not find the executable during the configure step or it has found an older version, you may provide it manually: 61``` 62-DSWIG_EXECUTABLE=<path_to_swig_executable> 63``` 64 65After the build finishes, you will find the python packages in `<build_folder>/python/pyarmnn/dist`. 66 67### Standalone build 68 69PyArmNN can also be built using the provided python scripts only. The advantage of that is that you may use prebuilt Arm NN libraries and it is generally much faster if you do not want to build all the Arm NN libraries. 70 71##### 1. Set environment: 72 73*ARMNN_INCLUDE* and *ARMNN_LIB* are mandatory and should point to Arm NN includes and libraries against which you will be generating the wrappers. *SWIG_EXECUTABLE* should only be set if you have multiple versions of SWIG installed or you used a custom location for your installation: 74```bash 75$ export SWIG_EXECUTABLE=<path_to_swig> 76$ export ARMNN_INCLUDE=<path_to_armnn_include> 77$ export ARMNN_LIB=<path_to_armnn_libraries> 78``` 79 80##### 2. Clean and build SWIG wrappers: 81 82```bash 83$ python setup.py clean --all 84$ python swig_generate.py -v 85$ python setup.py build_ext --inplace 86``` 87This step will put all generated files under `./src/pyarmnn/_generated` folder and can be used repeatedly to re-generate the wrappers. 88 89##### 4. Build the source package 90 91```bash 92$ python setup.py sdist 93``` 94As the result you will get `./dist/pyarmnn-23.0.0.tar.gz` file. As you can see it is platform independent. 95 96##### 5. Build the binary package 97 98```bash 99$ python setup.py bdist_wheel 100``` 101As the result you will get something like `./dist/pyarmnn-23.0.0-cp36-cp36m-linux_x86_64.whl` file. As you can see it 102 is platform dependent. 103 104# PyArmNN installation 105 106PyArmNN can be distributed as a source package or a binary package (wheel). 107 108Binary package is platform dependent, the name of the package will indicate the platform it was built for, e.g.: 109 110* Linux x86 64bit machine: pyarmnn-23.0.0-cp36-cp36m-*linux_x86_64*.whl 111* Linux Aarch 64 bit machine: pyarmnn-23.0.0-cp36-cp36m-*linux_aarch64*.whl 112 113The source package is platform independent but installation involves compilation of Arm NN python extension. You will need to have g++ compatible with C++ 14 standard and a python development library installed on the build machine. 114 115Both of them, source and binary package, require the Arm NN library to be present on the target/build machine. 116 117It is strongly suggested to work within a python virtual environment. The further steps assume that the virtual environment was created and activated before running PyArmNN installation commands. 118 119PyArmNN also depends on the NumPy python library. It will be automatically downloaded and installed alongside PyArmNN. If your machine does not have access to Python pip repositories you might need to install NumPy in advance by following public instructions: https://scipy.org/install.html 120 121## Installing from wheel 122 123Make sure that Arm NN binaries and Arm NN dependencies are installed and can be found in one of the system default library locations. You can check default locations by executing the following command: 124```bash 125$ gcc --print-search-dirs 126``` 127Install PyArmNN from binary by pointing to the wheel file: 128```bash 129$ pip install /path/to/pyarmnn-23.0.0-cp36-cp36m-linux_aarch64.whl 130``` 131 132## Installing from source package 133 134Alternatively, you can install from source. This is the more reliable way but requires a little more effort on the users part. 135 136While installing from sources, you have the freedom of choosing Arm NN libraries location. Set environment variables *ARMNN_LIB* and *ARMNN_INCLUDE* to point to Arm NN libraries and headers. 137If you want to use system default locations, just set *ARMNN_INCLUDE* to point to Arm NN headers. 138 139```bash 140$ export ARMNN_LIB=/path/to/libs 141$ export ARMNN_INCLUDE=/path/to/headers 142``` 143 144Install PyArmNN as follows: 145```bash 146$ pip install /path/to/pyarmnn-23.0.0.tar.gz 147``` 148 149If PyArmNN installation script fails to find Arm NN libraries it will raise an error like this 150 151`RuntimeError: ArmNN library was not found in ('/usr/lib/gcc/aarch64-linux-gnu/8/', <...> ,'/lib/', '/usr/lib/'). Please install ArmNN to one of the standard locations or set correct ARMNN_INCLUDE and ARMNN_LIB env variables.` 152 153You can now verify that PyArmNN library is installed and check PyArmNN version using: 154```bash 155$ pip show pyarmnn 156``` 157You can also verify it by running the following and getting output similar to below: 158```bash 159$ python -c "import pyarmnn as ann;print(ann.GetVersion())" 160'23.0.0' 161``` 162 163# PyArmNN API overview 164 165#### Getting started 166The easiest way to begin using PyArmNN is by using the Parsers. We will demonstrate how to use them below: 167 168Create a parser object and load your model file. 169```python 170import pyarmnn as ann 171import imageio 172 173# ONNX, Caffe and TF parsers also exist. 174parser = ann.ITfLiteParser() 175network = parser.CreateNetworkFromBinaryFile('./model.tflite') 176``` 177 178Get the input binding information by using the name of the input layer. 179```python 180input_binding_info = parser.GetNetworkInputBindingInfo(0, 'model/input') 181 182# Create a runtime object that will perform inference. 183options = ann.CreationOptions() 184runtime = ann.IRuntime(options) 185``` 186Choose preferred backends for execution and optimize the network. 187```python 188# Backend choices earlier in the list have higher preference. 189preferredBackends = [ann.BackendId('CpuAcc'), ann.BackendId('CpuRef')] 190opt_network, messages = ann.Optimize(network, preferredBackends, runtime.GetDeviceSpec(), ann.OptimizerOptions()) 191 192# Load the optimized network into the runtime. 193net_id, _ = runtime.LoadNetwork(opt_network) 194``` 195Make workload tensors using input and output binding information. 196```python 197# Load an image and create an inputTensor for inference. 198img = imageio.imread('./image.png') 199input_tensors = ann.make_input_tensors([input_binding_info], [img]) 200 201# Get output binding information for an output layer by using the layer name. 202output_binding_info = parser.GetNetworkOutputBindingInfo(0, 'model/output') 203output_tensors = ann.make_output_tensors([output_binding_info]) 204``` 205 206Perform inference and get the results back into a numpy array. 207```python 208runtime.EnqueueWorkload(0, input_tensors, output_tensors) 209 210results = ann.workload_tensors_to_ndarray(output_tensors) 211print(results) 212``` 213 214#### Examples 215 216To further explore PyArmNN API there are several examples provided in the `/examples` folder for you to explore. 217 218##### Image Classification 219 220This sample application performs image classification on an image and outputs the <i>Top N</i> results, listing the classes and probabilities associated with the classified image. All resources are downloaded during execution, so if you do not have access to the internet, you may need to download these manually. 221 222Sample scripts are provided for performing image classification with TFLite and ONNX models with `tflite_mobilenetv1_quantized.py` and `onnx_mobilenetv2.py`. 223 224##### Object Detection 225 226This sample application guides the user and shows how to perform object detection using PyArmNN API. By taking a model and video file or camera feed as input, and running inference on each frame, we are able to interpret the output to draw bounding boxes around detected objects and overlay the corresponding labels and confidence scores. 227 228Sample scripts are provided for performing object detection from video file and video stream with `run_video_file.py` and `run_video_stream.py`. 229 230 231## Tox for automation 232 233To make things easier *tox* is available for automating individual tasks or running multiple commands at once such as generating wrappers, running unit tests using multiple python versions or generating documentation. To run it use: 234 235```bash 236$ tox <task_name> 237``` 238 239See *tox.ini* for the list of tasks. You may also modify it for your own purposes. To dive deeper into tox read through https://tox.readthedocs.io/en/latest/ 240 241## Running unit-tests 242 243Download resources required to run unit tests by executing the script in the scripts folder: 244 245``` 246$ python ./scripts/download_test_resources.py 247``` 248 249The script will download an archive from the Linaro server and extract it. A folder `test/testdata/shared` will be created. Execute `pytest` from the project root dir: 250```bash 251$ python -m pytest test/ -v 252``` 253or run tox which will do both: 254```bash 255$ tox 256``` 257