blob: 9943946222589d136691c41930301e7c5a6fd6a0 [file] [log] [blame]
alexander3c798932021-03-26 21:42:19 +00001/*
Richard Burtonc2911442022-04-22 09:08:21 +01002 * Copyright (c) 2021-2022 Arm Limited. All rights reserved.
alexander3c798932021-03-26 21:42:19 +00003 * 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#ifndef ASR_WAV2LETTER_PREPROCESS_HPP
18#define ASR_WAV2LETTER_PREPROCESS_HPP
19
Kshitij Sisodiaaa4bcb12022-05-06 09:13:03 +010020#include "TensorFlowLiteMicro.hpp"
alexander3c798932021-03-26 21:42:19 +000021#include "Wav2LetterMfcc.hpp"
22#include "AudioUtils.hpp"
23#include "DataStructures.hpp"
Richard Burtonc2911442022-04-22 09:08:21 +010024#include "BaseProcessing.hpp"
alexander31ae9f02022-02-10 16:15:54 +000025#include "log_macros.h"
alexander3c798932021-03-26 21:42:19 +000026
27namespace arm {
28namespace app {
alexander3c798932021-03-26 21:42:19 +000029
30 /* Class to facilitate pre-processing calculation for Wav2Letter model
31 * for ASR. */
Richard Burtonc2911442022-04-22 09:08:21 +010032 using AudioWindow = audio::SlidingWindow<const int16_t>;
alexander3c798932021-03-26 21:42:19 +000033
Richard Burtonb40ecf82022-04-22 16:14:57 +010034 class AsrPreProcess : public BasePreProcess {
alexander3c798932021-03-26 21:42:19 +000035 public:
36 /**
37 * @brief Constructor.
Richard Burtonc2911442022-04-22 09:08:21 +010038 * @param[in] inputTensor Pointer to the TFLite Micro input Tensor.
39 * @param[in] numMfccFeatures Number of MFCC features per window.
Richard Burtonb40ecf82022-04-22 16:14:57 +010040 * @param[in] numFeatureFrames Number of MFCC vectors that need to be calculated
41 * for an inference.
Richard Burtonc2911442022-04-22 09:08:21 +010042 * @param[in] mfccWindowLen Number of audio elements to calculate MFCC features per window.
43 * @param[in] mfccWindowStride Stride (in number of elements) for moving the MFCC window.
alexander3c798932021-03-26 21:42:19 +000044 */
Richard Burtonb40ecf82022-04-22 16:14:57 +010045 AsrPreProcess(TfLiteTensor* inputTensor,
46 uint32_t numMfccFeatures,
47 uint32_t numFeatureFrames,
48 uint32_t mfccWindowLen,
49 uint32_t mfccWindowStride);
alexander3c798932021-03-26 21:42:19 +000050
51 /**
52 * @brief Calculates the features required from audio data. This
53 * includes MFCC, first and second order deltas,
54 * normalisation and finally, quantisation. The tensor is
Richard Burtonc2911442022-04-22 09:08:21 +010055 * populated with features from a given window placed along
alexander3c798932021-03-26 21:42:19 +000056 * in a single row.
57 * @param[in] audioData Pointer to the first element of audio data.
58 * @param[in] audioDataLen Number of elements in the audio data.
alexander3c798932021-03-26 21:42:19 +000059 * @return true if successful, false in case of error.
60 */
Richard Burtonc2911442022-04-22 09:08:21 +010061 bool DoPreProcess(const void* audioData, size_t audioDataLen) override;
alexander3c798932021-03-26 21:42:19 +000062
63 protected:
64 /**
65 * @brief Computes the first and second order deltas for the
66 * MFCC buffers - they are assumed to be populated.
67 *
68 * @param[in] mfcc MFCC buffers.
69 * @param[out] delta1 Result of the first diff computation.
70 * @param[out] delta2 Result of the second diff computation.
71 * @return true if successful, false otherwise.
72 */
alexanderc350cdc2021-04-29 20:36:09 +010073 static bool ComputeDeltas(Array2d<float>& mfcc,
74 Array2d<float>& delta1,
75 Array2d<float>& delta2);
alexander3c798932021-03-26 21:42:19 +000076
77 /**
Richard Burtonc2911442022-04-22 09:08:21 +010078 * @brief Given a 2D vector of floats, rescale it to have mean of 0 and
79 * standard deviation of 1.
alexander3c798932021-03-26 21:42:19 +000080 * @param[in,out] vec Vector of vector of floats.
81 */
Richard Burtonc2911442022-04-22 09:08:21 +010082 static void StandardizeVecF32(Array2d<float>& vec);
alexander3c798932021-03-26 21:42:19 +000083
84 /**
Richard Burtonc2911442022-04-22 09:08:21 +010085 * @brief Standardizes all the MFCC and delta buffers to have mean 0 and std. dev 1.
alexander3c798932021-03-26 21:42:19 +000086 */
Richard Burtonc2911442022-04-22 09:08:21 +010087 void Standarize();
alexander3c798932021-03-26 21:42:19 +000088
89 /**
90 * @brief Given the quantisation and data type limits, computes
91 * the quantised values of a floating point input data.
92 * @param[in] elem Element to be quantised.
93 * @param[in] quantScale Scale.
94 * @param[in] quantOffset Offset.
95 * @param[in] minVal Numerical limit - minimum.
96 * @param[in] maxVal Numerical limit - maximum.
97 * @return Floating point quantised value.
98 */
alexanderc350cdc2021-04-29 20:36:09 +010099 static float GetQuantElem(
alexander3c798932021-03-26 21:42:19 +0000100 float elem,
101 float quantScale,
102 int quantOffset,
103 float minVal,
104 float maxVal);
105
106 /**
107 * @brief Quantises the MFCC and delta buffers, and places them
108 * in the output buffer. While doing so, it transposes
109 * the data. Reason: Buffers in this class are arranged
110 * for "time" axis to be row major. Primary reason for
111 * this being the convolution speed up (as we can use
112 * contiguous memory). The output, however, requires the
113 * time axis to be in column major arrangement.
114 * @param[in] outputBuf Pointer to the output buffer.
115 * @param[in] outputBufSz Output buffer's size.
116 * @param[in] quantScale Quantisation scale.
117 * @param[in] quantOffset Quantisation offset.
118 */
119 template <typename T>
alexanderc350cdc2021-04-29 20:36:09 +0100120 bool Quantise(
Richard Burtonc2911442022-04-22 09:08:21 +0100121 T* outputBuf,
alexander3c798932021-03-26 21:42:19 +0000122 const uint32_t outputBufSz,
123 const float quantScale,
124 const int quantOffset)
125 {
126 /* Check the output size will fit everything. */
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100127 if (outputBufSz < (this->m_mfccBuf.size(0) * 3 * sizeof(T))) {
alexander3c798932021-03-26 21:42:19 +0000128 printf_err("Tensor size too small for features\n");
129 return false;
130 }
131
132 /* Populate. */
Richard Burtonb40ecf82022-04-22 16:14:57 +0100133 T* outputBufMfcc = outputBuf;
134 T* outputBufD1 = outputBuf + this->m_numMfccFeats;
135 T* outputBufD2 = outputBufD1 + this->m_numMfccFeats;
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100136 const uint32_t ptrIncr = this->m_numMfccFeats * 2; /* (3 vectors - 1 vector) */
alexander3c798932021-03-26 21:42:19 +0000137
138 const float minVal = std::numeric_limits<T>::min();
139 const float maxVal = std::numeric_limits<T>::max();
140
141 /* Need to transpose while copying and concatenating the tensor. */
Richard Burtonc2911442022-04-22 09:08:21 +0100142 for (uint32_t j = 0; j < this->m_numFeatureFrames; ++j) {
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100143 for (uint32_t i = 0; i < this->m_numMfccFeats; ++i) {
Richard Burtonb40ecf82022-04-22 16:14:57 +0100144 *outputBufMfcc++ = static_cast<T>(AsrPreProcess::GetQuantElem(
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100145 this->m_mfccBuf(i, j), quantScale,
alexanderc350cdc2021-04-29 20:36:09 +0100146 quantOffset, minVal, maxVal));
Richard Burtonb40ecf82022-04-22 16:14:57 +0100147 *outputBufD1++ = static_cast<T>(AsrPreProcess::GetQuantElem(
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100148 this->m_delta1Buf(i, j), quantScale,
alexanderc350cdc2021-04-29 20:36:09 +0100149 quantOffset, minVal, maxVal));
Richard Burtonb40ecf82022-04-22 16:14:57 +0100150 *outputBufD2++ = static_cast<T>(AsrPreProcess::GetQuantElem(
Isabella Gottardi56ee6202021-05-12 08:27:15 +0100151 this->m_delta2Buf(i, j), quantScale,
alexanderc350cdc2021-04-29 20:36:09 +0100152 quantOffset, minVal, maxVal));
alexander3c798932021-03-26 21:42:19 +0000153 }
154 outputBufMfcc += ptrIncr;
155 outputBufD1 += ptrIncr;
156 outputBufD2 += ptrIncr;
157 }
158
159 return true;
160 }
161
162 private:
Richard Burtonc2911442022-04-22 09:08:21 +0100163 audio::Wav2LetterMFCC m_mfcc; /* MFCC instance. */
164 TfLiteTensor* m_inputTensor; /* Model input tensor. */
alexander3c798932021-03-26 21:42:19 +0000165
166 /* Actual buffers to be populated. */
Richard Burtonc2911442022-04-22 09:08:21 +0100167 Array2d<float> m_mfccBuf; /* Contiguous buffer 1D: MFCC */
168 Array2d<float> m_delta1Buf; /* Contiguous buffer 1D: Delta 1 */
169 Array2d<float> m_delta2Buf; /* Contiguous buffer 1D: Delta 2 */
alexander3c798932021-03-26 21:42:19 +0000170
Richard Burtonc2911442022-04-22 09:08:21 +0100171 uint32_t m_mfccWindowLen; /* Window length for MFCC. */
172 uint32_t m_mfccWindowStride; /* Window stride len for MFCC. */
173 uint32_t m_numMfccFeats; /* Number of MFCC features per window. */
174 uint32_t m_numFeatureFrames; /* How many sets of m_numMfccFeats. */
175 AudioWindow m_mfccSlidingWindow; /* Sliding window to calculate MFCCs. */
alexander3c798932021-03-26 21:42:19 +0000176
177 };
178
alexander3c798932021-03-26 21:42:19 +0000179} /* namespace app */
180} /* namespace arm */
181
182#endif /* ASR_WAV2LETTER_PREPROCESS_HPP */