blob: bebfdfd86804105b756c9811bff829aca5292825 [file] [log] [blame]
Richard Burton00553462021-11-10 16:27:14 +00001/*
2 * Copyright (c) 2021 Arm Limited. All rights reserved.
3 * SPDX-License-Identifier: Apache-2.0
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17#include "RNNoiseModel.hpp"
18#include "UseCaseHandler.hpp"
19#include "InputFiles.hpp"
20#include "RNNUCTestCaseData.hpp"
21#include "UseCaseCommonUtils.hpp"
22
23#include <catch.hpp>
24#include <hal.h>
25#include <Profiler.hpp>
Richard Burton033c9152021-12-07 14:04:44 +000026
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +010027namespace arm {
28 namespace app {
29 static uint8_t tensorArena[ACTIVATION_BUF_SZ] ACTIVATION_BUF_ATTRIBUTE;
30 } /* namespace app */
31} /* namespace arm */
32
33extern uint8_t* GetModelPointer();
34extern size_t GetModelLen();
35
Kshitij Sisodia4cc40212022-04-08 09:54:53 +010036#define PLATFORM hal_platform_init();
Richard Burton00553462021-11-10 16:27:14 +000037
38#define CONTEXT \
39arm::app::ApplicationContext caseContext; \
Kshitij Sisodia4cc40212022-04-08 09:54:53 +010040arm::app::Profiler profiler{"noise_reduction"}; \
Richard Burton00553462021-11-10 16:27:14 +000041caseContext.Set<arm::app::Profiler&>("profiler", profiler); \
Richard Burton00553462021-11-10 16:27:14 +000042caseContext.Set<arm::app::RNNoiseModel&>("model", model);
43
44TEST_CASE("Verify output tensor memory dump")
45{
46 constexpr size_t maxMemDumpSz = 0x100000; /* 1 MiB worth of space */
47 std::vector<uint8_t> memPool(maxMemDumpSz); /* Memory pool */
48 arm::app::RNNoiseModel model{};
49
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +010050 REQUIRE(model.Init(arm::app::tensorArena,
51 sizeof(arm::app::tensorArena),
52 GetModelPointer(),
53 GetModelLen()));
Richard Burton00553462021-11-10 16:27:14 +000054 REQUIRE(model.IsInited());
55
56 /* Populate the output tensors */
57 const size_t numOutputs = model.GetNumOutputs();
58 size_t sizeToWrite = 0;
59 size_t lastTensorSize = model.GetOutputTensor(numOutputs - 1)->bytes;
60
61 for (size_t i = 0; i < numOutputs; ++i) {
62 TfLiteTensor* tensor = model.GetOutputTensor(i);
63 auto* tData = tflite::GetTensorData<uint8_t>(tensor);
64
65 if (tensor->bytes > 0) {
66 memset(tData, static_cast<uint8_t>(i), tensor->bytes);
67 sizeToWrite += tensor->bytes;
68 }
69 }
70
71
72 SECTION("Positive use case")
73 {
74 /* Run the memory dump */
75 auto bytesWritten = DumpOutputTensorsToMemory(model, memPool.data(), memPool.size());
76 REQUIRE(sizeToWrite == bytesWritten);
77
78 /* Verify the dump */
79 size_t k = 0;
80 for (size_t i = 0; i < numOutputs && k < memPool.size(); ++i) {
81 TfLiteTensor* tensor = model.GetOutputTensor(i);
82 auto* tData = tflite::GetTensorData<uint8_t>(tensor);
83
84 for (size_t j = 0; j < tensor->bytes && k < memPool.size(); ++j) {
85 REQUIRE(tData[j] == memPool[k++]);
86 }
87 }
88 }
89
90 SECTION("Limited memory - skipping last tensor")
91 {
92 /* Run the memory dump */
93 auto bytesWritten = DumpOutputTensorsToMemory(model, memPool.data(), sizeToWrite - 1);
94 REQUIRE(lastTensorSize > 0);
95 REQUIRE(bytesWritten == sizeToWrite - lastTensorSize);
96 }
97
98 SECTION("Zero memory")
99 {
100 /* Run the memory dump */
101 auto bytesWritten = DumpOutputTensorsToMemory(model, memPool.data(), 0);
102 REQUIRE(bytesWritten == 0);
103 }
104}
105
106TEST_CASE("Inference run all clips", "[RNNoise]")
107{
108 PLATFORM
109
110 arm::app::RNNoiseModel model;
111
112 CONTEXT
113
114 caseContext.Set<uint32_t>("clipIndex", 0);
115 caseContext.Set<uint32_t>("numInputFeatures", g_NumInputFeatures);
116 caseContext.Set<uint32_t>("frameLength", g_FrameLength);
117 caseContext.Set<uint32_t>("frameStride", g_FrameStride);
118
119 /* Load the model. */
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +0100120 REQUIRE(model.Init(arm::app::tensorArena,
121 sizeof(arm::app::tensorArena),
122 GetModelPointer(),
123 GetModelLen()));
Richard Burton00553462021-11-10 16:27:14 +0000124
125 REQUIRE(arm::app::NoiseReductionHandler(caseContext, true));
126}
127
128std::function<uint32_t(const uint32_t)> get_golden_input_p232_208_array_size(const uint32_t numberOfFeatures) {
129
130 return [numberOfFeatures](const uint32_t) -> uint32_t{
131 return numberOfFeatures;
132 };
133}
134
135const char* get_test_filename(const uint32_t idx) {
136 auto name = get_filename(idx);
137 REQUIRE(std::string("p232_208.wav") == name);
138 return "p232_208.wav";
139}
140
141void testInfByIndex(std::vector<uint32_t>& numberOfInferences) {
142 PLATFORM
143
144 arm::app::RNNoiseModel model;
145
146 CONTEXT
147
148 caseContext.Set<std::function<const int16_t*(const uint32_t)>>("features", get_audio_array);
149 caseContext.Set<std::function<const char* (const uint32_t)>>("featureFileNames", get_test_filename);
150 caseContext.Set<uint32_t>("frameLength", g_FrameLength);
151 caseContext.Set<uint32_t>("frameStride", g_FrameStride);
152 caseContext.Set<uint32_t>("numInputFeatures", g_NumInputFeatures);
153 /* Load the model. */
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +0100154 REQUIRE(model.Init(arm::app::tensorArena,
155 sizeof(arm::app::tensorArena),
156 GetModelPointer(),
157 GetModelLen()));
Richard Burton00553462021-11-10 16:27:14 +0000158
159 size_t oneInferenceOutSizeBytes = g_FrameLength * sizeof(int16_t);
160
161 auto infIndex = 0;
162 for (auto numInf: numberOfInferences) {
163 DYNAMIC_SECTION("Number of features: "<< numInf) {
164 caseContext.Set<uint32_t>("clipIndex", 1); /* Only getting p232_208.wav for tests. */
165 uint32_t audioSizeInput = numInf*g_FrameLength;
166 caseContext.Set<std::function<uint32_t(const uint32_t)>>("featureSizes",
167 get_golden_input_p232_208_array_size(audioSizeInput));
168
169 size_t headerNumBytes = 4 + 12 + 4; /* Filename length, filename (12 for p232_208.wav), dump size. */
170 size_t footerNumBytes = 4; /* Eof value. */
171 size_t memDumpMaxLenBytes = headerNumBytes + footerNumBytes + oneInferenceOutSizeBytes * numInf;
172
173 std::vector<uint8_t > memDump(memDumpMaxLenBytes);
174 size_t undefMemDumpBytesWritten = 0;
175 caseContext.Set<size_t>("MEM_DUMP_LEN", memDumpMaxLenBytes);
176 caseContext.Set<uint8_t*>("MEM_DUMP_BASE_ADDR", memDump.data());
177 caseContext.Set<size_t*>("MEM_DUMP_BYTE_WRITTEN", &undefMemDumpBytesWritten);
178
179 /* Inference. */
180 REQUIRE(arm::app::NoiseReductionHandler(caseContext, false));
181
182 /* The expected output after post-processing. */
183 std::vector<int16_t> golden(&ofms[infIndex][0], &ofms[infIndex][0] + g_FrameLength);
184
185 size_t startOfLastInfOut = undefMemDumpBytesWritten - oneInferenceOutSizeBytes;
186
187 /* The actual result from the usecase handler. */
188 std::vector<int16_t> runtime(g_FrameLength);
189 std::memcpy(runtime.data(), &memDump[startOfLastInfOut], oneInferenceOutSizeBytes);
190
Richard Burton033c9152021-12-07 14:04:44 +0000191 /* Margin of 43 is 0.07% error. */
192 REQUIRE_THAT(golden, Catch::Matchers::Approx(runtime).margin(43));
Richard Burton00553462021-11-10 16:27:14 +0000193 }
194 ++infIndex;
195 }
196}
197
198TEST_CASE("Inference by index - one inference", "[RNNoise]")
199{
200 auto totalAudioSize = get_audio_array_size(1);
201 REQUIRE(64757 == totalAudioSize); /* Checking that the input file is as expected and has not changed. */
202
203 /* Run 1 inference */
204 std::vector<uint32_t> numberOfInferences = {1};
205 testInfByIndex(numberOfInferences);
206}
207
208TEST_CASE("Inference by index - several inferences", "[RNNoise]")
209{
210 auto totalAudioSize = get_audio_array_size(1);
211 REQUIRE(64757 == totalAudioSize); /* Checking that the input file is as expected and has not changed. */
212
213 /* 3 different inference amounts: 1, 2 and all inferences required to cover total feature set */
214 uint32_t totalInferences = totalAudioSize / g_FrameLength;
215 std::vector<uint32_t> numberOfInferences = {1, 2, totalInferences};
216 testInfByIndex(numberOfInferences);
217}