1*89c4ff92SAndroid Build Coastguard Worker# Keyword Spotting Example 2*89c4ff92SAndroid Build Coastguard Worker 3*89c4ff92SAndroid Build Coastguard Worker## Introduction 4*89c4ff92SAndroid Build Coastguard Worker 5*89c4ff92SAndroid Build Coastguard WorkerThis is a sample code showing keyword spotting using Arm NN public C++ API. The compiled application can take 6*89c4ff92SAndroid Build Coastguard Worker 7*89c4ff92SAndroid Build Coastguard Worker* an audio file 8*89c4ff92SAndroid Build Coastguard Worker 9*89c4ff92SAndroid Build Coastguard Workeras input and produce 10*89c4ff92SAndroid Build Coastguard Worker 11*89c4ff92SAndroid Build Coastguard Worker* recognised keyword in the audio file 12*89c4ff92SAndroid Build Coastguard Worker 13*89c4ff92SAndroid Build Coastguard Workeras output. The application works with the [fully quantised DS CNN Large model](https://github.com/ARM-software/ML-zoo/raw/68b5fbc77ed28e67b2efc915997ea4477c1d9d5b/models/keyword_spotting/ds_cnn_large/tflite_clustered_int8/) which is trained to recongize 12 keywords, including an unknown word. 14*89c4ff92SAndroid Build Coastguard Worker 15*89c4ff92SAndroid Build Coastguard Worker## Dependencies 16*89c4ff92SAndroid Build Coastguard Worker 17*89c4ff92SAndroid Build Coastguard WorkerThis example utilises `libsndfile`, `libasound` and `libsamplerate` libraries to capture the raw audio data from file, and to re-sample to the expected sample rate. Top level inference API is provided by Arm NN library. 18*89c4ff92SAndroid Build Coastguard Worker 19*89c4ff92SAndroid Build Coastguard Worker### Arm NN 20*89c4ff92SAndroid Build Coastguard Worker 21*89c4ff92SAndroid Build Coastguard WorkerKeyword spotting example build system does not trigger Arm NN compilation. Thus, before building the application, 22*89c4ff92SAndroid Build Coastguard Workerplease ensure that Arm NN libraries and header files are available on your build platform. 23*89c4ff92SAndroid Build Coastguard WorkerThe application executable binary dynamically links with the following Arm NN libraries: 24*89c4ff92SAndroid Build Coastguard Worker 25*89c4ff92SAndroid Build Coastguard Worker* libarmnn.so 26*89c4ff92SAndroid Build Coastguard Worker* libarmnnTfLiteParser.so 27*89c4ff92SAndroid Build Coastguard Worker 28*89c4ff92SAndroid Build Coastguard WorkerThe build script searches for available Arm NN libraries in the following order: 29*89c4ff92SAndroid Build Coastguard Worker 30*89c4ff92SAndroid Build Coastguard Worker1. Inside custom user directory specified by ARMNN_LIB_DIR cmake option. 31*89c4ff92SAndroid Build Coastguard Worker2. Inside the current Arm NN repository, assuming that Arm NN was built following [these instructions](../../BuildGuideCrossCompilation.md). 32*89c4ff92SAndroid Build Coastguard Worker3. Inside default locations for system libraries, assuming Arm NN was installed from deb packages. 33*89c4ff92SAndroid Build Coastguard Worker 34*89c4ff92SAndroid Build Coastguard WorkerArm NN header files will be searched in parent directory of found libraries files under `include` directory, i.e. 35*89c4ff92SAndroid Build Coastguard Workerlibraries found in `/usr/lib` or `/usr/lib64` and header files in `/usr/include` (or `${ARMNN_LIB_DIR}/include`). 36*89c4ff92SAndroid Build Coastguard Worker 37*89c4ff92SAndroid Build Coastguard WorkerPlease see [find_armnn.cmake](./cmake/find_armnn.cmake) for implementation details. 38*89c4ff92SAndroid Build Coastguard Worker 39*89c4ff92SAndroid Build Coastguard Worker## Building 40*89c4ff92SAndroid Build Coastguard Worker 41*89c4ff92SAndroid Build Coastguard WorkerThere is one flow for building this application: 42*89c4ff92SAndroid Build Coastguard Worker 43*89c4ff92SAndroid Build Coastguard Worker* native build on a host platform 44*89c4ff92SAndroid Build Coastguard Worker 45*89c4ff92SAndroid Build Coastguard Worker### Build Options 46*89c4ff92SAndroid Build Coastguard Worker 47*89c4ff92SAndroid Build Coastguard Worker* ARMNN_LIB_DIR - point to the custom location of the Arm NN libs and headers. 48*89c4ff92SAndroid Build Coastguard Worker* BUILD_UNIT_TESTS - set to `1` to build tests. Additionally to the main application, `keyword-spotting-example-tests` 49*89c4ff92SAndroid Build Coastguard Workerunit tests executable will be created. 50*89c4ff92SAndroid Build Coastguard Worker 51*89c4ff92SAndroid Build Coastguard Worker### Native Build 52*89c4ff92SAndroid Build Coastguard Worker 53*89c4ff92SAndroid Build Coastguard WorkerTo build this application on a host platform, firstly ensure that required dependencies are installed: 54*89c4ff92SAndroid Build Coastguard WorkerFor example, for raspberry PI: 55*89c4ff92SAndroid Build Coastguard Worker 56*89c4ff92SAndroid Build Coastguard Worker```commandline 57*89c4ff92SAndroid Build Coastguard Workersudo apt-get update 58*89c4ff92SAndroid Build Coastguard Workersudo apt-get -yq install libsndfile1-dev 59*89c4ff92SAndroid Build Coastguard Workersudo apt-get -yq install libasound2-dev 60*89c4ff92SAndroid Build Coastguard Workersudo apt-get -yq install libsamplerate-dev 61*89c4ff92SAndroid Build Coastguard Worker``` 62*89c4ff92SAndroid Build Coastguard Worker 63*89c4ff92SAndroid Build Coastguard WorkerTo build demo application, create a build directory: 64*89c4ff92SAndroid Build Coastguard Worker 65*89c4ff92SAndroid Build Coastguard Worker```commandline 66*89c4ff92SAndroid Build Coastguard Workermkdir build 67*89c4ff92SAndroid Build Coastguard Workercd build 68*89c4ff92SAndroid Build Coastguard Worker``` 69*89c4ff92SAndroid Build Coastguard Worker 70*89c4ff92SAndroid Build Coastguard WorkerIf you have already installed Arm NN and and the required libraries: 71*89c4ff92SAndroid Build Coastguard Worker 72*89c4ff92SAndroid Build Coastguard WorkerInside build directory, run cmake and make commands: 73*89c4ff92SAndroid Build Coastguard Worker 74*89c4ff92SAndroid Build Coastguard Worker```commandline 75*89c4ff92SAndroid Build Coastguard Workercmake .. 76*89c4ff92SAndroid Build Coastguard Workermake 77*89c4ff92SAndroid Build Coastguard Worker``` 78*89c4ff92SAndroid Build Coastguard Worker 79*89c4ff92SAndroid Build Coastguard WorkerThis will build the following in bin directory: 80*89c4ff92SAndroid Build Coastguard Worker 81*89c4ff92SAndroid Build Coastguard Worker* `keyword-spotting-example` - application executable 82*89c4ff92SAndroid Build Coastguard Worker 83*89c4ff92SAndroid Build Coastguard WorkerIf you have custom Arm NN location, use `ARMNN_LIB_DIR` options: 84*89c4ff92SAndroid Build Coastguard Worker 85*89c4ff92SAndroid Build Coastguard Worker```commandline 86*89c4ff92SAndroid Build Coastguard Workercmake -DARMNN_LIB_DIR=/path/to/armnn .. 87*89c4ff92SAndroid Build Coastguard Workermake 88*89c4ff92SAndroid Build Coastguard Worker``` 89*89c4ff92SAndroid Build Coastguard Worker 90*89c4ff92SAndroid Build Coastguard Worker## Executing 91*89c4ff92SAndroid Build Coastguard Worker 92*89c4ff92SAndroid Build Coastguard WorkerOnce the application executable is built, it can be executed with the following options: 93*89c4ff92SAndroid Build Coastguard Worker 94*89c4ff92SAndroid Build Coastguard Worker* --audio-file-path: Path to the audio file to run keyword spotting on **[REQUIRED]** 95*89c4ff92SAndroid Build Coastguard Worker* --model-file-path: Path to the Keyword Spotting model to use **[REQUIRED]** 96*89c4ff92SAndroid Build Coastguard Worker 97*89c4ff92SAndroid Build Coastguard Worker* --preferred-backends: Takes the preferred backends in preference order, separated by comma. 98*89c4ff92SAndroid Build Coastguard Worker For example: `CpuAcc,GpuAcc,CpuRef`. Accepted options: [`CpuAcc`, `CpuRef`, `GpuAcc`]. 99*89c4ff92SAndroid Build Coastguard Worker Defaults to `CpuRef` **[OPTIONAL]** 100*89c4ff92SAndroid Build Coastguard Worker 101*89c4ff92SAndroid Build Coastguard Worker### Keyword Spotting on a supplied audio file 102*89c4ff92SAndroid Build Coastguard Worker 103*89c4ff92SAndroid Build Coastguard WorkerA small selection of suitable wav files containing keywords can be found [here](https://git.mlplatform.org/ml/ethos-u/ml-embedded-evaluation-kit.git/plain/resources/kws/samples/). 104*89c4ff92SAndroid Build Coastguard WorkerTo run keyword spotting on a supplied audio file and output the result to console: 105*89c4ff92SAndroid Build Coastguard Worker 106*89c4ff92SAndroid Build Coastguard Worker```commandline 107*89c4ff92SAndroid Build Coastguard Worker./keyword-spotting-example --audio-file-path /path/to/audio/file --model-file-path /path/to/model/file 108*89c4ff92SAndroid Build Coastguard Worker``` 109*89c4ff92SAndroid Build Coastguard Worker 110*89c4ff92SAndroid Build Coastguard Worker# Application Overview 111*89c4ff92SAndroid Build Coastguard Worker 112*89c4ff92SAndroid Build Coastguard WorkerThis section provides a walkthrough of the application, explaining in detail the steps: 113*89c4ff92SAndroid Build Coastguard Worker 114*89c4ff92SAndroid Build Coastguard Worker1. Initialisation 115*89c4ff92SAndroid Build Coastguard Worker 1. Reading from Audio Source 116*89c4ff92SAndroid Build Coastguard Worker2. Creating a Network 117*89c4ff92SAndroid Build Coastguard Worker 1. Creating Parser and Importing Graph 118*89c4ff92SAndroid Build Coastguard Worker 2. Optimizing Graph for Compute Device 119*89c4ff92SAndroid Build Coastguard Worker 3. Creating Input and Output Binding Information 120*89c4ff92SAndroid Build Coastguard Worker3. Keyword spotting pipeline 121*89c4ff92SAndroid Build Coastguard Worker 1. Pre-processing the Captured Audio 122*89c4ff92SAndroid Build Coastguard Worker 2. Making Input and Output Tensors 123*89c4ff92SAndroid Build Coastguard Worker 3. Executing Inference 124*89c4ff92SAndroid Build Coastguard Worker 4. Postprocessing 125*89c4ff92SAndroid Build Coastguard Worker 5. Decoding and Processing Inference Output 126*89c4ff92SAndroid Build Coastguard Worker 127*89c4ff92SAndroid Build Coastguard Worker### Initialisation 128*89c4ff92SAndroid Build Coastguard Worker 129*89c4ff92SAndroid Build Coastguard Worker##### Reading from Audio Source 130*89c4ff92SAndroid Build Coastguard Worker 131*89c4ff92SAndroid Build Coastguard WorkerAfter parsing user arguments, the chosen audio file is loaded into an AudioCapture object. 132*89c4ff92SAndroid Build Coastguard WorkerWe use [`AudioCapture`](./include/AudioCapture.hpp) in our main function to capture appropriately sized audio blocks from the source using the 133*89c4ff92SAndroid Build Coastguard Worker`Next()` function. 134*89c4ff92SAndroid Build Coastguard Worker 135*89c4ff92SAndroid Build Coastguard WorkerThe `AudioCapture` object also re-samples the audio input to a desired sample rate, and sets the number of channels used to one channel (i.e `mono`) 136*89c4ff92SAndroid Build Coastguard Worker 137*89c4ff92SAndroid Build Coastguard Worker### Creating a Network 138*89c4ff92SAndroid Build Coastguard Worker 139*89c4ff92SAndroid Build Coastguard WorkerAll operations with Arm NN and networks are encapsulated in [`ArmnnNetworkExecutor`](./include/ArmnnNetworkExecutor.hpp) 140*89c4ff92SAndroid Build Coastguard Workerclass. 141*89c4ff92SAndroid Build Coastguard Worker 142*89c4ff92SAndroid Build Coastguard Worker##### Creating Parser and Importing Graph 143*89c4ff92SAndroid Build Coastguard Worker 144*89c4ff92SAndroid Build Coastguard WorkerThe first step with Arm NN SDK is to import a graph from file by using the appropriate parser. 145*89c4ff92SAndroid Build Coastguard Worker 146*89c4ff92SAndroid Build Coastguard WorkerThe Arm NN SDK provides parsers for reading graphs from a variety of model formats. In our application we specifically 147*89c4ff92SAndroid Build Coastguard Workerfocus on `.tflite, .pb, .onnx` models. 148*89c4ff92SAndroid Build Coastguard Worker 149*89c4ff92SAndroid Build Coastguard WorkerBased on the extension of the provided model file, the corresponding parser is created and the network file loaded with 150*89c4ff92SAndroid Build Coastguard Worker`CreateNetworkFromBinaryFile()` method. The parser will handle the creation of the underlying Arm NN graph. 151*89c4ff92SAndroid Build Coastguard Worker 152*89c4ff92SAndroid Build Coastguard WorkerCurrently this example only supports tflite format model files and uses `ITfLiteParser`: 153*89c4ff92SAndroid Build Coastguard Worker 154*89c4ff92SAndroid Build Coastguard Worker```c++ 155*89c4ff92SAndroid Build Coastguard Worker#include "armnnTfLiteParser/ITfLiteParser.hpp" 156*89c4ff92SAndroid Build Coastguard Worker 157*89c4ff92SAndroid Build Coastguard WorkerarmnnTfLiteParser::ITfLiteParserPtr parser = armnnTfLiteParser::ITfLiteParser::Create(); 158*89c4ff92SAndroid Build Coastguard Workerarmnn::INetworkPtr network = parser->CreateNetworkFromBinaryFile(modelPath.c_str()); 159*89c4ff92SAndroid Build Coastguard Worker``` 160*89c4ff92SAndroid Build Coastguard Worker 161*89c4ff92SAndroid Build Coastguard Worker##### Optimizing Graph for Compute Device 162*89c4ff92SAndroid Build Coastguard Worker 163*89c4ff92SAndroid Build Coastguard WorkerArm NN supports optimized execution on multiple CPU and GPU devices. Prior to executing a graph, we must select the 164*89c4ff92SAndroid Build Coastguard Workerappropriate device context. We do this by creating a runtime context with default options with `IRuntime()`. 165*89c4ff92SAndroid Build Coastguard Worker 166*89c4ff92SAndroid Build Coastguard WorkerFor example: 167*89c4ff92SAndroid Build Coastguard Worker 168*89c4ff92SAndroid Build Coastguard Worker```c++ 169*89c4ff92SAndroid Build Coastguard Worker#include "armnn/ArmNN.hpp" 170*89c4ff92SAndroid Build Coastguard Worker 171*89c4ff92SAndroid Build Coastguard Workerauto runtime = armnn::IRuntime::Create(armnn::IRuntime::CreationOptions()); 172*89c4ff92SAndroid Build Coastguard Worker``` 173*89c4ff92SAndroid Build Coastguard Worker 174*89c4ff92SAndroid Build Coastguard WorkerWe can optimize the imported graph by specifying a list of backends in order of preference and implement 175*89c4ff92SAndroid Build Coastguard Workerbackend-specific optimizations. The backends are identified by a string unique to the backend, 176*89c4ff92SAndroid Build Coastguard Workerfor example `CpuAcc, GpuAcc, CpuRef`. 177*89c4ff92SAndroid Build Coastguard Worker 178*89c4ff92SAndroid Build Coastguard WorkerFor example: 179*89c4ff92SAndroid Build Coastguard Worker 180*89c4ff92SAndroid Build Coastguard Worker```c++ 181*89c4ff92SAndroid Build Coastguard Workerstd::vector<armnn::BackendId> backends{"CpuAcc", "GpuAcc", "CpuRef"}; 182*89c4ff92SAndroid Build Coastguard Worker``` 183*89c4ff92SAndroid Build Coastguard Worker 184*89c4ff92SAndroid Build Coastguard WorkerInternally and transparently, Arm NN splits the graph into subgraph based on backends, it calls a optimize subgraphs 185*89c4ff92SAndroid Build Coastguard Workerfunction on each of them and, if possible, substitutes the corresponding subgraph in the original graph with 186*89c4ff92SAndroid Build Coastguard Workerits optimized version. 187*89c4ff92SAndroid Build Coastguard Worker 188*89c4ff92SAndroid Build Coastguard WorkerUsing the `Optimize()` function we optimize the graph for inference and load the optimized network onto the compute 189*89c4ff92SAndroid Build Coastguard Workerdevice with `LoadNetwork()`. This function creates the backend-specific workloads 190*89c4ff92SAndroid Build Coastguard Workerfor the layers and a backend specific workload factory which is called to create the workloads. 191*89c4ff92SAndroid Build Coastguard Worker 192*89c4ff92SAndroid Build Coastguard WorkerFor example: 193*89c4ff92SAndroid Build Coastguard Worker 194*89c4ff92SAndroid Build Coastguard Worker```c++ 195*89c4ff92SAndroid Build Coastguard Workerarmnn::IOptimizedNetworkPtr optNet = Optimize(*network, 196*89c4ff92SAndroid Build Coastguard Worker backends, 197*89c4ff92SAndroid Build Coastguard Worker m_Runtime->GetDeviceSpec(), 198*89c4ff92SAndroid Build Coastguard Worker armnn::OptimizerOptions()); 199*89c4ff92SAndroid Build Coastguard Workerstd::string errorMessage; 200*89c4ff92SAndroid Build Coastguard Workerruntime->LoadNetwork(0, std::move(optNet), errorMessage)); 201*89c4ff92SAndroid Build Coastguard Workerstd::cerr << errorMessage << std::endl; 202*89c4ff92SAndroid Build Coastguard Worker``` 203*89c4ff92SAndroid Build Coastguard Worker 204*89c4ff92SAndroid Build Coastguard Worker##### Creating Input and Output Binding Information 205*89c4ff92SAndroid Build Coastguard Worker 206*89c4ff92SAndroid Build Coastguard WorkerParsers can also be used to extract the input information for the network. By calling `GetSubgraphInputTensorNames` 207*89c4ff92SAndroid Build Coastguard Workerwe extract all the input names and, with `GetNetworkInputBindingInfo`, bind the input points of the graph. 208*89c4ff92SAndroid Build Coastguard WorkerFor example: 209*89c4ff92SAndroid Build Coastguard Worker 210*89c4ff92SAndroid Build Coastguard Worker```c++ 211*89c4ff92SAndroid Build Coastguard Workerstd::vector<std::string> inputNames = parser->GetSubgraphInputTensorNames(0); 212*89c4ff92SAndroid Build Coastguard Workerauto inputBindingInfo = parser->GetNetworkInputBindingInfo(0, inputNames[0]); 213*89c4ff92SAndroid Build Coastguard Worker``` 214*89c4ff92SAndroid Build Coastguard Worker 215*89c4ff92SAndroid Build Coastguard WorkerThe input binding information contains all the essential information about the input. It is a tuple consisting of 216*89c4ff92SAndroid Build Coastguard Workerinteger identifiers for bindable layers (inputs, outputs) and the tensor info (data type, quantization information, 217*89c4ff92SAndroid Build Coastguard Workernumber of dimensions, total number of elements). 218*89c4ff92SAndroid Build Coastguard Worker 219*89c4ff92SAndroid Build Coastguard WorkerSimilarly, we can get the output binding information for an output layer by using the parser to retrieve output 220*89c4ff92SAndroid Build Coastguard Workertensor names and calling `GetNetworkOutputBindingInfo()`. 221*89c4ff92SAndroid Build Coastguard Worker 222*89c4ff92SAndroid Build Coastguard Worker### Keyword Spotting pipeline 223*89c4ff92SAndroid Build Coastguard Worker 224*89c4ff92SAndroid Build Coastguard WorkerThe keyword spotting pipeline has 3 steps to perform: data pre-processing, run inference and decode inference results. 225*89c4ff92SAndroid Build Coastguard Worker 226*89c4ff92SAndroid Build Coastguard WorkerSee [`KeywordSpottingPipeline`](include/KeywordSpottingPipeline.hpp) for more details. 227*89c4ff92SAndroid Build Coastguard Worker 228*89c4ff92SAndroid Build Coastguard Worker#### Pre-processing the Audio Input 229*89c4ff92SAndroid Build Coastguard Worker 230*89c4ff92SAndroid Build Coastguard WorkerEach frame captured from source is read and stored by the AudioCapture object. 231*89c4ff92SAndroid Build Coastguard WorkerIt's `Next()` function provides us with the correctly positioned window of data, sized appropriately for the given model, to pre-process before inference. 232*89c4ff92SAndroid Build Coastguard Worker 233*89c4ff92SAndroid Build Coastguard Worker```c++ 234*89c4ff92SAndroid Build Coastguard Workerstd::vector<float> audioBlock = capture.Next(); 235*89c4ff92SAndroid Build Coastguard Worker... 236*89c4ff92SAndroid Build Coastguard Workerstd::vector<int8_t> preprocessedData = kwsPipeline->PreProcessing(audioBlock); 237*89c4ff92SAndroid Build Coastguard Worker``` 238*89c4ff92SAndroid Build Coastguard Worker 239*89c4ff92SAndroid Build Coastguard WorkerThe `MFCC` class is then used to extract the Mel-frequency Cepstral Coefficients (MFCCs, [see Wikipedia](https://en.wikipedia.org/wiki/Mel-frequency_cepstrum)) from each stored audio frame in the provided window of audio, to be used as features for the network. MFCCs are the result of computing the dot product of the Discrete Cosine Transform (DCT) Matrix and the log of the Mel energy. 240*89c4ff92SAndroid Build Coastguard Worker 241*89c4ff92SAndroid Build Coastguard WorkerAfter all the MFCCs needed for an inference have been extracted from the audio data they are concatenated to make the input tensor for the model. 242*89c4ff92SAndroid Build Coastguard Worker 243*89c4ff92SAndroid Build Coastguard Worker#### Executing Inference 244*89c4ff92SAndroid Build Coastguard Worker 245*89c4ff92SAndroid Build Coastguard Worker```c++ 246*89c4ff92SAndroid Build Coastguard Workercommon::InferenceResults results; 247*89c4ff92SAndroid Build Coastguard Worker... 248*89c4ff92SAndroid Build Coastguard WorkerkwsPipeline->Inference(preprocessedData, results); 249*89c4ff92SAndroid Build Coastguard Worker``` 250*89c4ff92SAndroid Build Coastguard Worker 251*89c4ff92SAndroid Build Coastguard WorkerInference step will call `ArmnnNetworkExecutor::Run` method that will prepare input tensors and execute inference. 252*89c4ff92SAndroid Build Coastguard WorkerA compute device performs inference for the loaded network using the `EnqueueWorkload()` function of the runtime context. 253*89c4ff92SAndroid Build Coastguard WorkerFor example: 254*89c4ff92SAndroid Build Coastguard Worker 255*89c4ff92SAndroid Build Coastguard Worker```c++ 256*89c4ff92SAndroid Build Coastguard Worker//const void* inputData = ...; 257*89c4ff92SAndroid Build Coastguard Worker//outputTensors were pre-allocated before 258*89c4ff92SAndroid Build Coastguard Worker 259*89c4ff92SAndroid Build Coastguard Workerarmnn::InputTensors inputTensors = {{ inputBindingInfo.first,armnn::ConstTensor(inputBindingInfo.second, inputData)}}; 260*89c4ff92SAndroid Build Coastguard Workerruntime->EnqueueWorkload(0, inputTensors, outputTensors); 261*89c4ff92SAndroid Build Coastguard Worker``` 262*89c4ff92SAndroid Build Coastguard Worker 263*89c4ff92SAndroid Build Coastguard WorkerWe allocate memory for output data once and map it to output tensor objects. After successful inference, we read data 264*89c4ff92SAndroid Build Coastguard Workerfrom the pre-allocated output data buffer. See [`ArmnnNetworkExecutor::ArmnnNetworkExecutor`](./src/ArmnnNetworkExecutor.cpp) 265*89c4ff92SAndroid Build Coastguard Workerand [`ArmnnNetworkExecutor::Run`](./src/ArmnnNetworkExecutor.cpp) for more details. 266*89c4ff92SAndroid Build Coastguard Worker 267*89c4ff92SAndroid Build Coastguard Worker#### Postprocessing 268*89c4ff92SAndroid Build Coastguard Worker 269*89c4ff92SAndroid Build Coastguard Worker##### Decoding 270*89c4ff92SAndroid Build Coastguard Worker 271*89c4ff92SAndroid Build Coastguard WorkerThe output from the inference is decoded to obtain the spotted keyword- the word with highest probability is outputted to the console. 272*89c4ff92SAndroid Build Coastguard Worker 273*89c4ff92SAndroid Build Coastguard Worker```c++ 274*89c4ff92SAndroid Build Coastguard WorkerkwsPipeline->PostProcessing(results, labels, 275*89c4ff92SAndroid Build Coastguard Worker [](int index, std::string& label, float prob) -> void { 276*89c4ff92SAndroid Build Coastguard Worker printf("Keyword \"%s\", index %d:, probability %f\n", 277*89c4ff92SAndroid Build Coastguard Worker label.c_str(), 278*89c4ff92SAndroid Build Coastguard Worker index, 279*89c4ff92SAndroid Build Coastguard Worker prob); 280*89c4ff92SAndroid Build Coastguard Worker }); 281*89c4ff92SAndroid Build Coastguard Worker``` 282*89c4ff92SAndroid Build Coastguard Worker 283*89c4ff92SAndroid Build Coastguard WorkerThe produced string is displayed on the console. 284