/* * Copyright (c) 2021 Arm Limited. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "Wav2LetterPreprocess.hpp" #include #include #include constexpr uint32_t numMfccFeatures = 13; constexpr uint32_t numMfccVectors = 10; /* Test vector output: generated using test-asr-preprocessing.py. */ int8_t expectedResult[numMfccVectors][numMfccFeatures * 3] = { /* Feature vec 0. */ -32, 4, -9, -8, -10, -10, -11, -11, -11, -11, -12, -11, -11, /* MFCCs. */ -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, /* Delta 1. */ -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, /* Delta 2. */ /* Feature vec 1. */ -31, 4, -9, -8, -10, -10, -11, -11, -11, -11, -12, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, /* Feature vec 2. */ -31, 4, -9, -9, -10, -10, -11, -11, -11, -11, -12, -12, -12, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, /* Feature vec 3. */ -31, 4, -9, -9, -10, -10, -11, -11, -11, -11, -11, -12, -12, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, /* Feature vec 4 : this should have valid delta 1 and delta 2. */ -31, 4, -9, -9, -10, -10, -11, -11, -11, -11, -11, -12, -12, -38, -29, -9, 1, -2, -7, -8, -8, -12, -16, -14, -5, 5, -68, -50, -13, 5, 0, -9, -9, -8, -13, -20, -19, -3, 15, /* Feature vec 5 : this should have valid delta 1 and delta 2. */ -31, 4, -9, -8, -10, -10, -11, -11, -11, -11, -11, -12, -12, -62, -45, -11, 5, 0, -8, -9, -8, -12, -19, -17, -3, 13, -27, -22, -13, -9, -11, -12, -12, -11, -11, -13, -13, -10, -6, /* Feature vec 6. */ -31, 4, -9, -8, -10, -10, -11, -11, -11, -11, -12, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, /* Feature vec 7. */ -32, 4, -9, -8, -10, -10, -11, -11, -11, -12, -12, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, /* Feature vec 8. */ -32, 4, -9, -8, -10, -10, -11, -11, -11, -12, -12, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, /* Feature vec 9. */ -31, 4, -9, -8, -10, -10, -11, -11, -11, -11, -12, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10 }; void PopulateTestWavVector(std::vector& vec) { constexpr int int16max = std::numeric_limits::max(); int val = 0; for (size_t i = 0; i < vec.size(); ++i, ++val) { /* We want a differential filter response from both - order 1 * and 2 => Don't have a linear signal here - we use a signal * using squares for example. Alternate sign flips might work * just as well and will be computationally less work! */ int valsq = val * val; if (valsq > int16max) { val = 0; valsq = 0; } vec[i] = valsq; } } TEST_CASE("Preprocessing calculation INT8") { /* Initialise the HAL and platform. */ hal_platform platform; data_acq_module data_acq; data_psn_module data_psn; platform_timer timer; hal_init(&platform, &data_acq, &data_psn, &timer); hal_platform_init(&platform); /* Constants. */ const uint32_t windowLen = 512; const uint32_t windowStride = 160; const int dimArray[] = {3, 1, numMfccFeatures * 3, numMfccVectors}; const float quantScale = 0.1410219967365265; const int quantOffset = -11; /* Test wav memory. */ std::vector testWav((windowStride * numMfccVectors) + (windowLen - windowStride)); /* Populate with dummy input. */ PopulateTestWavVector(testWav); /* Allocate mem for tensor. */ std::vector tensorVec(dimArray[1]*dimArray[2]*dimArray[3]); /* Initialise dimensions and the test tensor. */ TfLiteIntArray* dims= tflite::testing::IntArrayFromInts(dimArray); TfLiteTensor tensor = tflite::testing::CreateQuantizedTensor( tensorVec.data(), dims, quantScale, quantOffset, "preprocessedInput"); /* Initialise pre-processing module. */ arm::app::audio::asr::Preprocess prep{ numMfccFeatures, windowLen, windowStride, numMfccVectors}; /* Invoke pre-processing. */ REQUIRE(prep.Invoke(testWav.data(), testWav.size(), &tensor)); /* Wrap the tensor with a std::vector for ease. */ int8_t * tensorData = tflite::GetTensorData(&tensor); std::vector vecResults = std::vector(tensorData, tensorData + tensor.bytes); /* Check sizes. */ REQUIRE(vecResults.size() == sizeof(expectedResult)); /* Check that the elements have been calculated correctly. */ for (uint32_t j = 0; j < numMfccVectors; ++j) { for (uint32_t i = 0; i < numMfccFeatures * 3; ++i) { size_t tensorIdx = (j * numMfccFeatures * 3) + i; CHECK(vecResults[tensorIdx] == expectedResult[j][i]); } } }