В этом примере показано, как создать многомодельную систему позднего слияния для распознавания акустических сцен. Пример обучает сверточную нейронную сеть (CNN) с использованием спектрограмм mel и ансамблевого классификатора с использованием вейвлет-рассеяния. В примере используется набор данных TUT для обучения и оценки [1].
Классификация акустических сцен (ASC) - задача классификации сред по производимым ими звукам. ASC - это общая проблема классификации, которая является основой для понимания контекста в устройствах, роботах и многих других приложениях [1]. В ранних попытках ASC использовались кепстральные коэффициенты мел-частоты (mfcc) и модели гауссовой смеси (GMM) для описания их статистического распределения. Другие популярные особенности, используемые для ASC, включают нулевую скорость пересечения, спектральный центроид (spectralCentroid), спектральный откат (spectralRolloffPoint), спектральный поток (spectralFlux ) и коэффициенты линейного прогнозирования (lpc) [5]. Скрытые модели Маркова (HMM) были обучены описывать временную эволюцию GMM. В последнее время в наиболее эффективных системах используется глубокое обучение, обычно CNN, и слияние нескольких моделей. Самой популярной функцией для топовых систем в конкурсе DCASE 2017 стала спектрограмма mel (melSpectrogram). Топовые системы в проблеме использовали поздний синтез и увеличение данных, чтобы помочь их системам обобщить.
Чтобы проиллюстрировать простой подход, который дает разумные результаты, этот пример обучает CNN с использованием спектрограмм и ансамблевого классификатора с использованием вейвлет-рассеяния. Классификатор CNN и ансамбля производит примерно эквивалентную общую точность, но лучше работает при различении различных акустических сцен. Для повышения общей точности необходимо объединить результаты классификации CNN и ensemble с помощью позднего слияния.
Для выполнения примера необходимо сначала загрузить набор данных [1]. Полный набор данных составляет приблизительно 15,5 ГБ. В зависимости от компьютера и подключения к Интернету загрузка данных может занять около 4 часов.
downloadFolder = tempdir; datasetFolder = fullfile(downloadFolder,'TUT-acoustic-scenes-2017'); if ~exist(datasetFolder,'dir') disp('Downloading TUT-acoustic-scenes-2017 (15.5 GB)...') HelperDownload_TUT_acoustic_scenes_2017(datasetFolder); end
Считывание метаданных набора разработок в виде таблицы. Назовите переменные таблицы FileName, AcousticScene, и SpecificLocation.
metadata_train = readtable(fullfile(datasetFolder,'TUT-acoustic-scenes-2017-development','meta.txt'), ... 'Delimiter',{'\t'}, ... 'ReadVariableNames',false); metadata_train.Properties.VariableNames = {'FileName','AcousticScene','SpecificLocation'}; head(metadata_train)
ans =
8×3 table
FileName AcousticScene SpecificLocation
__________________________ _____________ ________________
{'audio/b020_90_100.wav' } {'beach'} {'b020'}
{'audio/b020_110_120.wav'} {'beach'} {'b020'}
{'audio/b020_100_110.wav'} {'beach'} {'b020'}
{'audio/b020_40_50.wav' } {'beach'} {'b020'}
{'audio/b020_50_60.wav' } {'beach'} {'b020'}
{'audio/b020_30_40.wav' } {'beach'} {'b020'}
{'audio/b020_160_170.wav'} {'beach'} {'b020'}
{'audio/b020_170_180.wav'} {'beach'} {'b020'}
metadata_test = readtable(fullfile(datasetFolder,'TUT-acoustic-scenes-2017-evaluation','meta.txt'), ... 'Delimiter',{'\t'}, ... 'ReadVariableNames',false); metadata_test.Properties.VariableNames = {'FileName','AcousticScene','SpecificLocation'}; head(metadata_test)
ans =
8×3 table
FileName AcousticScene SpecificLocation
__________________ _____________ ________________
{'audio/1245.wav'} {'beach'} {'b174'}
{'audio/1456.wav'} {'beach'} {'b174'}
{'audio/1318.wav'} {'beach'} {'b174'}
{'audio/967.wav' } {'beach'} {'b174'}
{'audio/203.wav' } {'beach'} {'b174'}
{'audio/777.wav' } {'beach'} {'b174'}
{'audio/231.wav' } {'beach'} {'b174'}
{'audio/768.wav' } {'beach'} {'b174'}
Следует отметить, что конкретные местоположения записи в тестовом наборе не пересекаются с конкретными местоположениями записи в наборе разработок. Это упрощает проверку того, что обученные модели могут быть обобщены в реальных сценариях.
sharedRecordingLocations = intersect(metadata_test.SpecificLocation,metadata_train.SpecificLocation);
fprintf('Number of specific recording locations in both train and test sets = %d\n',numel(sharedRecordingLocations))
Number of specific recording locations in both train and test sets = 0
Первая переменная таблиц метаданных содержит имена файлов. Соедините имена файлов с путями к файлам.
train_filePaths = fullfile(datasetFolder,'TUT-acoustic-scenes-2017-development',metadata_train.FileName); test_filePaths = fullfile(datasetFolder,'TUT-acoustic-scenes-2017-evaluation',metadata_test.FileName);
Создайте хранилища аудиоданных для поезда и тестовых наборов. Установите Labels имущества audioDatastore на акустическую сцену. Звонить countEachLabel для проверки равномерного распределения меток как в поездах, так и в тестовых наборах.
adsTrain = audioDatastore(train_filePaths, ... 'Labels',categorical(metadata_train.AcousticScene), ... 'IncludeSubfolders',true); display(countEachLabel(adsTrain)) adsTest = audioDatastore(test_filePaths, ... 'Labels',categorical(metadata_test.AcousticScene), ... 'IncludeSubfolders',true); display(countEachLabel(adsTest))
15×2 table
Label Count
________________ _____
beach 312
bus 312
cafe/restaurant 312
car 312
city_center 312
forest_path 312
grocery_store 312
home 312
library 312
metro_station 312
office 312
park 312
residential_area 312
train 312
tram 312
15×2 table
Label Count
________________ _____
beach 108
bus 108
cafe/restaurant 108
car 108
city_center 108
forest_path 108
grocery_store 108
home 108
library 108
metro_station 108
office 108
park 108
residential_area 108
train 108
tram 108
Можно уменьшить набор данных, используемый в этом примере, чтобы ускорить время выполнения при затратах на производительность. В целом сокращение набора данных является хорошей практикой для разработки и отладки. Набор reduceDataset кому true для уменьшения набора данных.
reduceDataset = false; if reduceDataset adsTrain = splitEachLabel(adsTrain,20); adsTest = splitEachLabel(adsTest,10); end
Звонить read для получения данных и частоты дискретизации файла из набора поездов. Звук в базе данных имеет согласованную частоту дискретизации и длительность. Нормализуйте звук и слушайте его. Отображение соответствующей метки.
[data,adsInfo] = read(adsTrain); data = data./max(data,[],'all'); fs = adsInfo.SampleRate; sound(data,fs) fprintf('Acoustic scene = %s\n',adsTrain.Labels(1))
Acoustic scene = beach
Звонить reset для возврата хранилища данных в исходное состояние.
reset(adsTrain)
Каждый аудиоклип в наборе данных состоит из 10 секунд стереофонического (левого-правого) звука. Конвейер извлечения элементов и архитектура CNN в этом примере основаны на [3]. Гиперпараметры для извлечения элементов, архитектура CNN и варианты обучения были изменены из исходной статьи с использованием систематического рабочего процесса оптимизации гиперпараметров.
Сначала преобразуйте аудио в срединное кодирование. [3] предполагает, что срединные кодированные данные обеспечивают лучшую пространственную информацию, которую CNN может использовать для идентификации движущихся источников (таких как поезд, движущийся по акустической сцене).
dataMidSide = [sum(data,2),data(:,1)-data(:,2)];
Разделите сигнал на односекундные сегменты с перекрытием. Конечная система использует взвешенное по вероятности среднее на сегментах с одной секундой для прогнозирования сцены для каждого 10-секундного аудиоклипа в тестовом наборе. Разделение аудиоклипов на сегменты в одну секунду облегчает обучение в сети и помогает предотвратить переоснащение на конкретные акустические события в обучающем наборе. Перекрытие помогает гарантировать, что все комбинации элементов относительно друг друга захватываются учебными данными. Он также предоставляет системе дополнительные данные, которые можно однозначно смешивать во время увеличения.
segmentLength = 1; segmentOverlap = 0.5; [dataBufferedMid,~] = buffer(dataMidSide(:,1),round(segmentLength*fs),round(segmentOverlap*fs),'nodelay'); [dataBufferedSide,~] = buffer(dataMidSide(:,2),round(segmentLength*fs),round(segmentOverlap*fs),'nodelay'); dataBuffered = zeros(size(dataBufferedMid,1),size(dataBufferedMid,2)+size(dataBufferedSide,2)); dataBuffered(:,1:2:end) = dataBufferedMid; dataBuffered(:,2:2:end) = dataBufferedSide;
Использовать melSpectrogram преобразование данных в компактное представление частотной области. Определите параметры спектрограммы в соответствии с [3].
windowLength = 2048; samplesPerHop = 1024; samplesOverlap = windowLength - samplesPerHop; fftLength = 2*windowLength; numBands = 128;
melSpectrogram работает по каналам самостоятельно. Для оптимизации времени обработки звоните melSpectrogram со всем буферизованным сигналом.
spec = melSpectrogram(dataBuffered,fs, ... 'Window',hamming(windowLength,'periodic'), ... 'OverlapLength',samplesOverlap, ... 'FFTLength',fftLength, ... 'NumBands',numBands);
Преобразование спектрограммы в логарифмическую шкалу.
spec = log10(spec+eps);
Измените форму массива на размеры (Число полос) -by- (Количество транзитных участков) -by- (Количество каналов) -by- (Количество сегментов). При подаче изображения в нейронную сеть первые два измерения - высота и ширина изображения, третье измерение - каналы, а четвертое измерение разделяет отдельные изображения.
X = reshape(spec,size(spec,1),size(spec,2),size(data,2),[]);
Звонить melSpectrogram без выходных аргументов для построения диаграммы mel-спектрограммы среднего канала для первых шести из односекундных приращений.
for channel = 1:2:11 figure melSpectrogram(dataBuffered(:,channel),fs, ... 'Window',hamming(windowLength,'periodic'), ... 'OverlapLength',samplesOverlap, ... 'FFTLength',fftLength, ... 'NumBands',numBands); title(sprintf('Segment %d',ceil(channel/2))) end






Вспомогательная функция HelperSegmentedMelSpectrograms выполняет описанные выше шаги извлечения признаков.
Для ускорения обработки извлеките спектрограммы всех аудиофайлов в хранилищах данных с помощью tall массивы. В отличие от массивов в памяти, массивы tall остаются невысокими до тех пор, пока вы не запросите выполнение вычислений с помощью gather функция. Этот отложенный анализ позволяет быстро работать с большими наборами данных. При конечном запросе выходных данных с помощью gatherMATLAB объединяет вычисления в очереди, где это возможно, и принимает минимальное количество проходов через данные. При наличии Toolbox™ параллельных вычислений можно использовать массивы tall в локальной сессии MATLAB или в локальном пуле параллельных вычислений. Можно также выполнить вычисления массива высокого уровня в кластере, если установлен MATLAB ® Parallel Server™.
Если у вас нет Toolbox™ Parallel Computing, код в этом примере все еще выполняется.
pp = parpool('IdleTimeout',inf); train_set_tall = tall(adsTrain); xTrain = cellfun(@(x)HelperSegmentedMelSpectrograms(x,fs, ... 'SegmentLength',segmentLength, ... 'SegmentOverlap',segmentOverlap, ... 'WindowLength',windowLength, ... 'HopLength',samplesPerHop, ... 'NumBands',numBands, ... 'FFTLength',fftLength), ... train_set_tall, ... 'UniformOutput',false); xTrain = gather(xTrain); xTrain = cat(4,xTrain{:}); test_set_tall = tall(adsTest); xTest = cellfun(@(x)HelperSegmentedMelSpectrograms(x,fs, ... 'SegmentLength',segmentLength, ... 'SegmentOverlap',segmentOverlap, ... 'WindowLength',windowLength, ... 'HopLength',samplesPerHop, ... 'NumBands',numBands, ... 'FFTLength',fftLength), ... test_set_tall, ... 'UniformOutput',false); xTest = gather(xTest); xTest = cat(4,xTest{:});
Starting parallel pool (parpool) using the 'local' profile ... Connected to the parallel pool (number of workers: 6). Evaluating tall expression using the Parallel Pool 'local': - Pass 1 of 1: Completed in 3 min 45 sec Evaluation completed in 3 min 45 sec Evaluating tall expression using the Parallel Pool 'local': - Pass 1 of 1: Completed in 1 min 22 sec Evaluation completed in 1 min 22 sec
Реплицируйте метки обучающего набора таким образом, чтобы они соответствовали сегментам один к одному.
numSegmentsPer10seconds = size(dataBuffered,2)/2; yTrain = repmat(adsTrain.Labels,1,numSegmentsPer10seconds)'; yTrain = yTrain(:);
Набор данных DCASE 2017 содержит относительно небольшое количество акустических записей для задачи, а набор разработок и набор оценок были записаны в разных конкретных местах. В результате во время тренировок легко поддаваться данным. Одним из популярных способов уменьшения переоборудования является смешение. В mixup вы дополняете свой набор данных, смешивая особенности двух разных классов. При смешивании элементов метки смешиваются в равной пропорции. То есть:

Смешение было переформулировано [2] как метки, взятые из распределения вероятностей вместо смешанных меток. Реализация миксапа в данном примере является упрощённым вариантом миксапа: каждая спектрограмма смешивается со спектрограммой разной метки с лямбдой, установленной на 0,5. Исходный и смешанный наборы данных объединяются для обучения.
xTrainExtra = xTrain; yTrainExtra = yTrain; lambda = 0.5; for i = 1:size(xTrain,4) % Find all available spectrograms with different labels. availableSpectrograms = find(yTrain~=yTrain(i)); % Randomly choose one of the available spectrograms with a different label. numAvailableSpectrograms = numel(availableSpectrograms); idx = randi([1,numAvailableSpectrograms]); % Mix. xTrainExtra(:,:,:,i) = lambda*xTrain(:,:,:,i) + (1-lambda)*xTrain(:,:,:,availableSpectrograms(idx)); % Specify the label as randomly set by lambda. if rand > lambda yTrainExtra(i) = yTrain(availableSpectrograms(idx)); end end xTrain = cat(4,xTrain,xTrainExtra); yTrain = [yTrain;yTrainExtra];
Звонить summary для отображения распределения меток для дополнительного обучающего набора.
summary(yTrain)
beach 11749
bus 11870
cafe/restaurant 11860
car 11873
city_center 11789
forest_path 12023
grocery_store 11850
home 11877
library 11756
metro_station 11912
office 11940
park 11895
residential_area 11875
train 11795
tram 11776
Определите архитектуру CNN. Эта архитектура основана на [1] и модифицирована методом проб и ошибок. Дополнительные сведения о слоях глубокого обучения, доступных в MATLAB ®, см. в разделе Список слоев глубокого обучения (панель инструментов глубокого обучения).
imgSize = [size(xTrain,1),size(xTrain,2),size(xTrain,3)]; numF = 32; layers = [ ... imageInputLayer(imgSize) batchNormalizationLayer convolution2dLayer(3,numF,'Padding','same') batchNormalizationLayer reluLayer convolution2dLayer(3,numF,'Padding','same') batchNormalizationLayer reluLayer maxPooling2dLayer(3,'Stride',2,'Padding','same') convolution2dLayer(3,2*numF,'Padding','same') batchNormalizationLayer reluLayer convolution2dLayer(3,2*numF,'Padding','same') batchNormalizationLayer reluLayer maxPooling2dLayer(3,'Stride',2,'Padding','same') convolution2dLayer(3,4*numF,'Padding','same') batchNormalizationLayer reluLayer convolution2dLayer(3,4*numF,'Padding','same') batchNormalizationLayer reluLayer maxPooling2dLayer(3,'Stride',2,'Padding','same') convolution2dLayer(3,8*numF,'Padding','same') batchNormalizationLayer reluLayer convolution2dLayer(3,8*numF,'Padding','same') batchNormalizationLayer reluLayer globalAveragePooling2dLayer dropoutLayer(0.5) fullyConnectedLayer(15) softmaxLayer classificationLayer];
Определить trainingOptions (Deep Learning Toolbox) для CNN. Эти опции основаны на [3] и изменены с помощью систематического процесса оптимизации гиперпараметров.
miniBatchSize = 128; tuneme = 128; lr = 0.05*miniBatchSize/tuneme; options = trainingOptions('sgdm', ... 'InitialLearnRate',lr, ... 'MiniBatchSize',miniBatchSize, ... 'Momentum',0.9, ... 'L2Regularization',0.005, ... 'MaxEpochs',8, ... 'Shuffle','every-epoch', ... 'Plots','training-progress', ... 'Verbose',false, ... 'LearnRateSchedule','piecewise', ... 'LearnRateDropPeriod',2, ... 'LearnRateDropFactor',0.2);
Звонить trainNetwork (Deep Learning Toolbox) для обучения сети.
trainedNet = trainNetwork(xTrain,yTrain,layers,options);

Звонить predict (Deep Learning Toolbox), чтобы предсказать ответы от обученной сети, используя задержанный набор тестов.
cnnResponsesPerSegment = predict(trainedNet,xTest);
Среднее значение откликов для каждого 10-секундного аудиоклипа.
classes = trainedNet.Layers(end).Classes; numFiles = numel(adsTest.Files); counter = 1; cnnResponses = zeros(numFiles,numel(classes)); for channel = 1:numFiles cnnResponses(channel,:) = sum(cnnResponsesPerSegment(counter:counter+numSegmentsPer10seconds-1,:),1)/numSegmentsPer10seconds; counter = counter + numSegmentsPer10seconds; end
Для каждого 10-секундного аудиоклипа выберите максимум предсказаний, затем сопоставьте его с соответствующим предсказанным местоположением.
[~,classIdx] = max(cnnResponses,[],2); cnnPredictedLabels = classes(classIdx);
Звонить confusionchart (Deep Learning Toolbox) для визуализации точности набора тестов. Возврат средней точности в окно команд.
figure('Units','normalized','Position',[0.2 0.2 0.5 0.5]) cm = confusionchart(adsTest.Labels,cnnPredictedLabels,'title','Test Accuracy - CNN'); cm.ColumnSummary = 'column-normalized'; cm.RowSummary = 'row-normalized'; fprintf('Average accuracy of CNN = %0.2f\n',mean(adsTest.Labels==cnnPredictedLabels)*100)
Average accuracy of CNN = 73.33

Вейвлет-рассеяние показано в [4] для обеспечения хорошего представления акустических сцен. Определение waveletScattering (Wavelet Toolbox) объект. Шкала инвариантности и коэффициенты качества определялись методом проб и ошибок.
sf = waveletScattering('SignalLength',size(data,1), ... 'SamplingFrequency',fs, ... 'InvarianceScale',0.75, ... 'QualityFactors',[4 1]);
Преобразуйте звуковой сигнал в моно, а затем вызовите featureMatrix (Vavelet Toolbox) для возврата коэффициентов рассеяния для структуры разложения рассеяния, sf.
dataMono = mean(data,2); scatteringCoeffients = featureMatrix(sf,dataMono,'Transform','log');
Среднее значение коэффициентов рассеяния по 10-секундному аудиоклипу.
featureVector = mean(scatteringCoeffients,2);
fprintf('Number of wavelet features per 10-second clip = %d\n',numel(featureVector))
Number of wavelet features per 10-second clip = 290
Вспомогательная функция HelperWaveletFeatureVector выполняет указанные выше шаги. Использовать tall массив с cellfun и HelperWaveletFeatureVector для параллелизма извлечения элемента. Извлеките векторы вейвлет-признаков для последовательности и тестовых наборов.
scatteringTrain = cellfun(@(x)HelperWaveletFeatureVector(x,sf),train_set_tall,'UniformOutput',false); xTrain = gather(scatteringTrain); xTrain = cell2mat(xTrain')'; scatteringTest = cellfun(@(x)HelperWaveletFeatureVector(x,sf),test_set_tall,'UniformOutput',false); xTest = gather(scatteringTest); xTest = cell2mat(xTest')';
Evaluating tall expression using the Parallel Pool 'local': - Pass 1 of 1: Completed in 25 min 15 sec Evaluation completed in 25 min 15 sec Evaluating tall expression using the Parallel Pool 'local': - Pass 1 of 1: Completed in 8 min 2 sec Evaluation completed in 8 min 2 sec
Использовать fitcensemble для создания обучаемой модели классификационного ансамбля (ClassificationEnsemble).
subspaceDimension = min(150,size(xTrain,2) - 1); numLearningCycles = 30; classificationEnsemble = fitcensemble(xTrain,adsTrain.Labels, ... 'Method','Subspace', ... 'NumLearningCycles',numLearningCycles, ... 'Learners','discriminant', ... 'NPredToSample',subspaceDimension, ... 'ClassNames',removecats(unique(adsTrain.Labels)));
Для каждого 10-секундного аудиоклипа звоните predict чтобы вернуть метки и веса, затем сопоставьте их с соответствующим прогнозируемым местоположением. Звонить confusionchart (Deep Learning Toolbox) для визуализации точности набора тестов. Распечатайте среднее значение.
[waveletPredictedLabels,waveletResponses] = predict(classificationEnsemble,xTest); figure('Units','normalized','Position',[0.2 0.2 0.5 0.5]) cm = confusionchart(adsTest.Labels,waveletPredictedLabels,'title','Test Accuracy - Wavelet Scattering'); cm.ColumnSummary = 'column-normalized'; cm.RowSummary = 'row-normalized'; fprintf('Average accuracy of classifier = %0.2f\n',mean(adsTest.Labels==waveletPredictedLabels)*100)
Average accuracy of classifier = 76.05

Для каждого 10-секундного клипа вызов предсказания по вейвлет-классификатору и CNN возвращает вектор, указывающий относительную уверенность в их решении. Умножьте значение waveletResponses с cnnResponses для создания системы позднего слияния.
fused = waveletResponses .* cnnResponses; [~,classIdx] = max(fused,[],2); predictedLabels = classes(classIdx);
Звонить confusionchart для визуализации точности конденсированной классификации. Печать средней точности в окне команд.
figure('Units','normalized','Position',[0.2 0.2 0.5 0.5]) cm = confusionchart(adsTest.Labels,predictedLabels,'title','Test Accuracy - Fusion'); cm.ColumnSummary = 'column-normalized'; cm.RowSummary = 'row-normalized'; fprintf('Average accuracy of fused models = %0.2f\n',mean(adsTest.Labels==predictedLabels)*100)
Average accuracy of fused models = 78.21

Закройте параллельный пул.
delete(pp)
Parallel pool using the 'local' profile is shutting down.
[1] А. Месарош, Т. Хейттола и Т. Виртанен. Классификация акустических сцен: обзор записей вызова DCASE 2017. В proc. Международный семинар по усилению акустического сигнала, 2018 год.
[2] Гусар, Ференц. «Микширование: увеличение данных, зависящее от данных». InFERENCe. 03 ноября 2017 года. Доступ состоялся 15 января 2019 года. https://www.inference.vc/mixup-data-dependent-data-augmentation/.
[3] Хан, Йончан, Чонсу Парк и Кёгу Ли. «Сверточные нейронные сети с бинауральными представлениями и фоновым вычитанием для классификации акустических сцен». Обнаружение и классификация акустических сцен и событий (DCASE) (2017): 1-5.
[4] Лоштанлен, Винсент и Йоаким Анден. Бинауральная классификация сцены с вейвлет-рассеянием. Технический отчет, DCASE2016 Challenge, 2016.
[5] А. Ж. Эронен, В. Т. Пелтонен, Ж. Т. Туоми, А. П. Клапури, С. Фагерлунд, Т. Сорса, Г. Лорхо и Ж. Хуопаниеми, «Распознавание контекста на основе аудио», IEEE Trans. по аудио, речи и языку
[6] Акустические сцены TUT 2017, набор данных разработки
[7] Акустические сцены TUT 2017, оценочный набор данных
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %HelperSegmentedMelSpectrograms function X = HelperSegmentedMelSpectrograms(x,fs,varargin) p = inputParser; addParameter(p,'WindowLength',1024); addParameter(p,'HopLength',512); addParameter(p,'NumBands',128); addParameter(p,'SegmentLength',1); addParameter(p,'SegmentOverlap',0); addParameter(p,'FFTLength',1024); parse(p,varargin{:}) params = p.Results; x = [sum(x,2),x(:,1)-x(:,2)]; x = x./max(max(x)); [xb_m,~] = buffer(x(:,1),round(params.SegmentLength*fs),round(params.SegmentOverlap*fs),'nodelay'); [xb_s,~] = buffer(x(:,2),round(params.SegmentLength*fs),round(params.SegmentOverlap*fs),'nodelay'); xb = zeros(size(xb_m,1),size(xb_m,2)+size(xb_s,2)); xb(:,1:2:end) = xb_m; xb(:,2:2:end) = xb_s; spec = melSpectrogram(xb,fs, ... 'Window',hamming(params.WindowLength,'periodic'), ... 'OverlapLength',params.WindowLength - params.HopLength, ... 'FFTLength',params.FFTLength, ... 'NumBands',params.NumBands, ... 'FrequencyRange',[0,floor(fs/2)]); spec = log10(spec+eps); X = reshape(spec,size(spec,1),size(spec,2),size(x,2),[]); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %HelperWaveletFeatureVector function features = HelperWaveletFeatureVector(x,sf) x = mean(x,2); features = featureMatrix(sf,x,'Transform','log'); features = mean(features,2); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%