xref: /aosp_15_r20/external/armnn/samples/KeywordSpotting/Readme.md (revision 89c4ff92f2867872bb9e2354d150bf0c8c502810)
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