blob: 7f9ff19d29d588c6e904532cc33d7e791e20e6f4 [file] [log] [blame]
Richard Burton00553462021-11-10 16:27:14 +00001/*
Kshitij Sisodia2ea46232022-12-19 16:37:33 +00002 * SPDX-FileCopyrightText: Copyright 2021-2022 Arm Limited and/or its affiliates
3 * <open-source-office@arm.com> SPDX-License-Identifier: Apache-2.0
Richard Burton00553462021-11-10 16:27:14 +00004 *
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 */
Kshitij Sisodia2ea46232022-12-19 16:37:33 +000017#include "BufAttributes.hpp"
18#include "InputFiles.hpp"
19#include "Profiler.hpp"
20#include "RNNUCTestCaseData.hpp"
Richard Burton00553462021-11-10 16:27:14 +000021#include "RNNoiseModel.hpp"
22#include "UseCaseHandler.hpp"
Richard Burtonec5e99b2022-10-05 11:00:37 +010023#include "hal.h"
Richard Burton00553462021-11-10 16:27:14 +000024
25#include <catch.hpp>
Richard Burton033c9152021-12-07 14:04:44 +000026
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +010027namespace arm {
Liam Barry213a5432022-05-09 17:06:19 +010028namespace app {
29 static uint8_t tensorArena[ACTIVATION_BUF_SZ] ACTIVATION_BUF_ATTRIBUTE;
30 namespace rnn {
31 extern uint8_t* GetModelPointer();
32 extern size_t GetModelLen();
33 } /* namespace rnn */
34} /* namespace app */
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +010035} /* namespace arm */
36
Kshitij Sisodia2ea46232022-12-19 16:37:33 +000037#define PLATFORM hal_platform_init();
Richard Burton00553462021-11-10 16:27:14 +000038
Kshitij Sisodia2ea46232022-12-19 16:37:33 +000039#define CONTEXT \
40 arm::app::ApplicationContext caseContext; \
41 arm::app::Profiler profiler{"noise_reduction"}; \
42 caseContext.Set<arm::app::Profiler&>("profiler", profiler); \
43 caseContext.Set<arm::app::RNNoiseModel&>("model", model);
Richard Burton00553462021-11-10 16:27:14 +000044
45TEST_CASE("Verify output tensor memory dump")
46{
47 constexpr size_t maxMemDumpSz = 0x100000; /* 1 MiB worth of space */
48 std::vector<uint8_t> memPool(maxMemDumpSz); /* Memory pool */
49 arm::app::RNNoiseModel model{};
50
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +010051 REQUIRE(model.Init(arm::app::tensorArena,
Liam Barry213a5432022-05-09 17:06:19 +010052 sizeof(arm::app::tensorArena),
53 arm::app::rnn::GetModelPointer(),
54 arm::app::rnn::GetModelLen()));
Richard Burton00553462021-11-10 16:27:14 +000055 REQUIRE(model.IsInited());
56
57 /* Populate the output tensors */
58 const size_t numOutputs = model.GetNumOutputs();
Kshitij Sisodia2ea46232022-12-19 16:37:33 +000059 size_t sizeToWrite = 0;
60 size_t lastTensorSize = model.GetOutputTensor(numOutputs - 1)->bytes;
Richard Burton00553462021-11-10 16:27:14 +000061
62 for (size_t i = 0; i < numOutputs; ++i) {
63 TfLiteTensor* tensor = model.GetOutputTensor(i);
Kshitij Sisodia2ea46232022-12-19 16:37:33 +000064 auto* tData = tflite::GetTensorData<uint8_t>(tensor);
Richard Burton00553462021-11-10 16:27:14 +000065
66 if (tensor->bytes > 0) {
67 memset(tData, static_cast<uint8_t>(i), tensor->bytes);
68 sizeToWrite += tensor->bytes;
69 }
70 }
71
Richard Burton00553462021-11-10 16:27:14 +000072 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);
Kshitij Sisodia2ea46232022-12-19 16:37:33 +000082 auto* tData = tflite::GetTensorData<uint8_t>(tensor);
Richard Burton00553462021-11-10 16:27:14 +000083
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);
Liam Barry213a5432022-05-09 17:06:19 +0100115 caseContext.Set<uint32_t>("numInputFeatures", arm::app::rnn::g_NumInputFeatures);
116 caseContext.Set<uint32_t>("frameLength", arm::app::rnn::g_FrameLength);
117 caseContext.Set<uint32_t>("frameStride", arm::app::rnn::g_FrameStride);
Richard Burton00553462021-11-10 16:27:14 +0000118
119 /* Load the model. */
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +0100120 REQUIRE(model.Init(arm::app::tensorArena,
Liam Barry213a5432022-05-09 17:06:19 +0100121 sizeof(arm::app::tensorArena),
122 arm::app::rnn::GetModelPointer(),
123 arm::app::rnn::GetModelLen()));
Richard Burton00553462021-11-10 16:27:14 +0000124
125 REQUIRE(arm::app::NoiseReductionHandler(caseContext, true));
126}
127
Kshitij Sisodia2ea46232022-12-19 16:37:33 +0000128std::function<uint32_t(const uint32_t)>
129get_golden_input_p232_208_array_size(const uint32_t numberOfFeatures)
130{
Richard Burton00553462021-11-10 16:27:14 +0000131
Kshitij Sisodia2ea46232022-12-19 16:37:33 +0000132 return [numberOfFeatures](const uint32_t) -> uint32_t { return numberOfFeatures; };
Richard Burton00553462021-11-10 16:27:14 +0000133}
134
Kshitij Sisodia2ea46232022-12-19 16:37:33 +0000135const char* get_test_filename(const uint32_t idx)
136{
137 auto name = GetFilename(idx);
Richard Burton00553462021-11-10 16:27:14 +0000138 REQUIRE(std::string("p232_208.wav") == name);
139 return "p232_208.wav";
140}
141
Kshitij Sisodia2ea46232022-12-19 16:37:33 +0000142void testInfByIndex(std::vector<uint32_t>& numberOfInferences)
143{
Richard Burton00553462021-11-10 16:27:14 +0000144 PLATFORM
145
146 arm::app::RNNoiseModel model;
147
148 CONTEXT
149
Kshitij Sisodia2ea46232022-12-19 16:37:33 +0000150 caseContext.Set<std::function<const int16_t*(const uint32_t)>>("features", GetAudioArray);
151 caseContext.Set<std::function<const char*(const uint32_t)>>("featureFileNames",
152 get_test_filename);
Liam Barry213a5432022-05-09 17:06:19 +0100153 caseContext.Set<uint32_t>("frameLength", arm::app::rnn::g_FrameLength);
154 caseContext.Set<uint32_t>("frameStride", arm::app::rnn::g_FrameStride);
155 caseContext.Set<uint32_t>("numInputFeatures", arm::app::rnn::g_NumInputFeatures);
Richard Burton00553462021-11-10 16:27:14 +0000156 /* Load the model. */
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +0100157 REQUIRE(model.Init(arm::app::tensorArena,
Liam Barry213a5432022-05-09 17:06:19 +0100158 sizeof(arm::app::tensorArena),
159 arm::app::rnn::GetModelPointer(),
160 arm::app::rnn::GetModelLen()));
Richard Burton00553462021-11-10 16:27:14 +0000161
Liam Barry213a5432022-05-09 17:06:19 +0100162 size_t oneInferenceOutSizeBytes = arm::app::rnn::g_FrameLength * sizeof(int16_t);
Richard Burton00553462021-11-10 16:27:14 +0000163
164 auto infIndex = 0;
Kshitij Sisodia2ea46232022-12-19 16:37:33 +0000165 for (auto numInf : numberOfInferences) {
166 DYNAMIC_SECTION("Number of features: " << numInf)
167 {
168 caseContext.Set<uint32_t>("clipIndex", 1); /* Only getting p232_208.wav for tests. */
Liam Barry213a5432022-05-09 17:06:19 +0100169 uint32_t audioSizeInput = numInf * arm::app::rnn::g_FrameLength;
Kshitij Sisodia2ea46232022-12-19 16:37:33 +0000170 caseContext.Set<std::function<uint32_t(const uint32_t)>>(
171 "featureSizes", get_golden_input_p232_208_array_size(audioSizeInput));
Richard Burton00553462021-11-10 16:27:14 +0000172
Kshitij Sisodia2ea46232022-12-19 16:37:33 +0000173 size_t headerNumBytes =
174 4 + 12 + 4; /* Filename length, filename (12 for p232_208.wav), dump size. */
175 size_t footerNumBytes = 4; /* Eof value. */
176 size_t memDumpMaxLenBytes =
177 headerNumBytes + footerNumBytes + oneInferenceOutSizeBytes * numInf;
Richard Burton00553462021-11-10 16:27:14 +0000178
Kshitij Sisodia2ea46232022-12-19 16:37:33 +0000179 std::vector<uint8_t> memDump(memDumpMaxLenBytes);
Richard Burton00553462021-11-10 16:27:14 +0000180 size_t undefMemDumpBytesWritten = 0;
181 caseContext.Set<size_t>("MEM_DUMP_LEN", memDumpMaxLenBytes);
182 caseContext.Set<uint8_t*>("MEM_DUMP_BASE_ADDR", memDump.data());
183 caseContext.Set<size_t*>("MEM_DUMP_BYTE_WRITTEN", &undefMemDumpBytesWritten);
184
185 /* Inference. */
186 REQUIRE(arm::app::NoiseReductionHandler(caseContext, false));
187
188 /* The expected output after post-processing. */
Liam Barry213a5432022-05-09 17:06:19 +0100189 std::vector<int16_t> golden(&ofms[infIndex][0],
190 &ofms[infIndex][0] + arm::app::rnn::g_FrameLength);
Richard Burton00553462021-11-10 16:27:14 +0000191
192 size_t startOfLastInfOut = undefMemDumpBytesWritten - oneInferenceOutSizeBytes;
193
194 /* The actual result from the usecase handler. */
Liam Barry213a5432022-05-09 17:06:19 +0100195 std::vector<int16_t> runtime(arm::app::rnn::g_FrameLength);
Richard Burton00553462021-11-10 16:27:14 +0000196 std::memcpy(runtime.data(), &memDump[startOfLastInfOut], oneInferenceOutSizeBytes);
197
Richard Burton033c9152021-12-07 14:04:44 +0000198 /* Margin of 43 is 0.07% error. */
199 REQUIRE_THAT(golden, Catch::Matchers::Approx(runtime).margin(43));
Richard Burton00553462021-11-10 16:27:14 +0000200 }
201 ++infIndex;
202 }
203}
204
205TEST_CASE("Inference by index - one inference", "[RNNoise]")
206{
Kshitij Sisodia2ea46232022-12-19 16:37:33 +0000207 auto totalAudioSize = GetAudioArraySize(1);
208 REQUIRE(64757 ==
209 totalAudioSize); /* Checking that the input file is as expected and has not changed. */
Richard Burton00553462021-11-10 16:27:14 +0000210
211 /* Run 1 inference */
212 std::vector<uint32_t> numberOfInferences = {1};
213 testInfByIndex(numberOfInferences);
214}
215
216TEST_CASE("Inference by index - several inferences", "[RNNoise]")
217{
Kshitij Sisodia2ea46232022-12-19 16:37:33 +0000218 auto totalAudioSize = GetAudioArraySize(1);
219 REQUIRE(64757 ==
220 totalAudioSize); /* Checking that the input file is as expected and has not changed. */
Richard Burton00553462021-11-10 16:27:14 +0000221
222 /* 3 different inference amounts: 1, 2 and all inferences required to cover total feature set */
Liam Barry213a5432022-05-09 17:06:19 +0100223 uint32_t totalInferences = totalAudioSize / arm::app::rnn::g_FrameLength;
Richard Burton00553462021-11-10 16:27:14 +0000224 std::vector<uint32_t> numberOfInferences = {1, 2, totalInferences};
225 testInfByIndex(numberOfInferences);
226}