В этом примере показано, как создать мультимодельную систему позднего слияния для распознавания акустической сцены. Пример обучает сверточную нейронную сеть (CNN), используя mel spectrogram и ансамблевый классификатор, использующий вейвлет. Пример использует набор данных TUT для обучения и оценки [1].
Классификация акустических сцен (ASC) - это задача классификации окружений от звуков, которые они производят. ASC является типовой задачей классификации, которая является основой для осознания контекста в устройствах, роботах и многих других приложениях [1]. Ранние попытки ASC использовали мел-частотные кепстральные коэффициенты (mfcc
) и Гауссовы смешанные модели (GMM) для описания их статистического распределения. Другие популярные функции, используемые для ASC, включают нулевую скорость пересечения, спектральный центроид (spectralCentroid
), спектральное срабатывание (spectralRolloffPoint
), спектральный поток (spectralFlux
) и коэффициенты линейного предсказания (lpc
) [5]. Скрытые модели Маркова (HMMs) были обучены описывать временную эволюцию GMMs. Совсем недавно лучшие производительные системы использовали глубокое обучение, обычно CNN, и слияние нескольких моделей. Самой популярной функцией для систем с самым высоким рейтингом в конкурсе DCASE 2017 стала mel spectrogram (melSpectrogram
). Самые высокие системы в проблеме использовали позднее слияние и увеличение данных, чтобы помочь их системам обобщить.
Чтобы проиллюстрировать простой подход, который дает разумные результаты, этот пример обучает CNN с помощью спектрограмм mel и классификатора ансамбля, используя вейвлет. CNN и классификатор ансамбля дают примерно эквивалентную общую точность, но лучше работают в различении различных акустических сцен. Чтобы повысить общую точность, вы объединяете результаты классификатора CNN и ансамбля с помощью позднего слияния.
Чтобы запустить пример, необходимо сначала загрузить набор данных [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);
Создайте аудиоданные для train и тестовых наборов. Установите Labels
свойство audioDatastore
в акустическую сцену. Функции countEachLabel
для проверки четного распределения меток как в train, так и в тестовых наборах.
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
чтобы получить данные и частоту дискретизации файла из train. Аудио в базе данных имеет допустимую частоту и длительность дискретизации. Нормализуйте аудио и слушайте его. Отобразите соответствующую метку.
[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
для возврата datastore к его начальному условию.
reset(adsTrain)
Каждый аудиоролик в наборе данных состоит из 10 секунд стерео (слева справа) аудио. Конвейер редукции данных и архитектура CNN в этом примере основаны на [3]. Гиперпараметры для редукции данных, архитектуры CNN и опций обучения были изменены из исходной статьи с помощью систематического рабочего процесса оптимизации гипероптимизации параметров управления.
Сначала преобразуйте аудио в среднее кодирование. [3] предполагает, что закодированные данные средней стороны обеспечивают лучшую пространственную информацию, которую CNN может использовать для идентификации движущихся источников (таких как train, перемещающийся через акустическую сцену).
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
чтобы преобразовать данные в компактное представление частотного диапазона. Задайте параметры для mel spectrogram как предложено в [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);
Преобразуйте спектрограмму mel в логарифмическую шкалу.
spec = log10(spec+eps);
Измените форму массива на размерности (Количество полос) -by- (Количество переходов) -by- (Количество каналов) -by- (Количество сегментов). Когда вы подаете изображение в нейронную сеть, первые две размерности являются высотой и шириной изображения, третья размерность - это каналы, а четвертая размерность разделяет отдельные изображения.
X = reshape(spec,size(spec,1),size(spec,2),size(data,2),[]);
Функции melSpectrogram
без выходных аргументов для построения графика mel spectrogram среднего канала для первых шести из односекундных шагов.
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
выполняет шаги редукции данных, описанные выше.
Чтобы ускорить обработку, извлечите mel спектрограммы всех аудио файлов в хранилищах данных, используя tall
массивы. В отличие от массивов в памяти, длинные массивы остаются недооцененными, пока вы не запросите, чтобы вычисления были выполнены с использованием gather
функция. Эта отсроченная оценка позволяет быстро работать с большими наборами данных. Когда вы в конечном счете запрашиваете выход с помощью gather
MATLAB объединяет вычисления в очереди, где это возможно, и принимает минимальное количество проходов через данные. Если у вас есть Parallel Computing Toolbox™, можно использовать длинные массивы в локальном Сеансе работы с MATLAB или в локальном параллельном пуле. Можно также запустить вычисления длинный массив на кластере, если установлена Server™ MATLAB ® Parallel.
Если у вас нет Parallel Computing Toolbox™, код в этом примере все еще запускается.
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 содержит относительно небольшое количество акустических записей для задачи, и набор разработки и набор оценки были записаны в различных конкретных местах. В результате легко перевыполнить данные во время обучения. Одним из популярных методов снижения сверхподбора кривой является микширование. В микшировании вы расширяете набор данных, смешивая функции двух разных классов. Когда вы смешиваете функции, вы смешиваете метки в равной пропорции. То есть:
Смешивание переформулировали с помощью [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] и изменена с помощью проб и ошибок. Смотрите Список слоев глубокого обучения (Deep Learning Toolbox), чтобы узнать больше о слоях глубокого обучения, доступных в 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
(Wavelet 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
для параллелизации редукции данных. Извлеките вейвлет функции векторы для train и тестовых наборов.
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-секундного клипа вызов predict на классификаторе вейвлет и 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] A. Mesaros, T. Heittola, and T. Virtanen. Классификация акустических сцен: Обзор записей вызова DCASE 2017. В проц. Международный семинар по усилению акустических сигналов, 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] A. J. Eronen, V. T. Peltonen, J. T. Tuomi, A. P. Klapuri, S. Fagerlund, T. Sorsa, G. Lorho, and J. Huopaniemi, «Audio-based context recognition», inition
[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 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%