В этом примере показано, как создать последнюю систему сплава мультимодели для акустического распознавания сцены. Пример обучает сверточную нейронную сеть (CNN) с помощью mel спектрограммы и классификатор ансамбля с помощью рассеивания вейвлета. Пример использует набор данных TUT в обучении и оценке [1].
Акустическая классификация сцен (ASC) является задачей классификации сред от звуков, которые они производят. ASC является типовой проблемой классификации, которая является основополагающей для осведомленности контекста в устройствах, роботах и многих других приложениях [1]. Ранние попытки ASC использовали mel-частоту cepstral коэффициенты (mfcc) и смешанные гауссовские модели (GMMs), чтобы описать их статистическое распределение. Другие популярные функции, использованные для ASC, включают нулевой уровень пересечения, спектральный центроид (spectralCentroid), спектральный спад (spectralRolloffPoint), спектральный поток (spectralFlux ), и коэффициенты линейного предсказания (lpc) [5]. Скрытые модели Маркова (HMMs) были обучены описать временную эволюцию GMMs. Позже, лучшие системы выполнения использовали глубокое обучение, обычно CNNs и сплав многоуровневых моделей. Самой популярной функцией находящихся на вершине рейтинга систем в конкурсе DCASE 2017 была mel спектрограмма (melSpectrogram). Находящиеся на вершине рейтинга системы в проблеме использовали последний сплав и увеличение данных, чтобы помочь их системам сделать вывод.
Чтобы проиллюстрировать простой подход, который приводит к разумным результатам, этот пример обучает CNN с помощью mel спектрограммы и классификатор ансамбля с помощью рассеивания вейвлета. CNN и классификатор ансамбля производят примерно эквивалентную общую точность, но выполняют лучше при различении различных акустических сцен. Чтобы увеличить общую точность, вы объединяете CNN и результаты классификатора ансамбля с помощью последнего сплава.
Чтобы запустить пример, необходимо сначала загрузить набор данных [1]. Набор данных состоит из набора разработки для обучения и валидации и протянутого набора данных оценки для тестирования.
Установите folder к местоположению загруженного набора данных.
folder = PathToDatabase;
Читайте в метаданных набора разработки как таблица. Назовите табличные переменные FileName, AcousticScene, и SpecificLocation.
metadata_train = readtable([folder,'\TUT-acoustic-scenes-2017-development\meta\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([folder,'\TUT-acoustic-scenes-2017-evaluation\meta\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_datafolder = [folder,'\TUT-acoustic-scenes-2017-development']; train_filePaths = strcat(train_datafolder,'\',metadata_train.FileName); test_datafolder = [folder,'\TUT-acoustic-scenes-2017-evaluation']; test_filePaths = strcat(test_datafolder,'\',metadata_test.FileName);
Создайте аудио хранилища данных для обучения и наборов тестов. Установите Labels свойство audioDatastore к акустической сцене. Вызовите countEachLabel проверять ровное распределение меток и в обучении и в наборах тестов.
train_set = audioDatastore(train_filePaths, ... 'Labels',categorical(metadata_train.AcousticScene)); display(countEachLabel(train_set))
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
test_set = audioDatastore(test_filePaths, ... 'Labels',categorical(metadata_test.AcousticScene)); display(countEachLabel(test_set))
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
Вызовите read получить данные и частоту дискретизации файла от состава. Аудио в базе данных имеет сопоставимую частоту дискретизации и длительность. Нормируйте аудио и слушайте его. Отобразите соответствующую метку.
[data,info] = read(train_set); data = data./max(data,[],'all'); fs = info.SampleRate; sound(data,fs) fprintf('Acoustic scene = %s\n',train_set.Labels(1))
Acoustic scene = beach
Вызовите reset возвратить datastore в его начальное условие.
reset(train_set)
Каждый аудиоклип в наборе данных состоит из 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 преобразовать данные в компактное представление частотного диапазона. Задайте параметры для mel спектрограммы, как предложено [3].
windowLength = 2048; samplesPerHop = 1024; samplesOverlap = windowLength - samplesPerHop; fftLength = 2*windowLength; numBands = 128;
melSpectrogram действует вдоль каналов независимо. Чтобы оптимизировать время вычислений, вызовите melSpectrogram с целым буферизированным сигналом.
spec = melSpectrogram(dataBuffered,fs, ... 'WindowLength',windowLength, ... 'OverlapLength',samplesOverlap, ... 'FFTLength',fftLength, ... 'NumBands',numBands);
Преобразуйте mel спектрограмму в логарифмический масштаб.
spec = log10(spec+eps);
Измените размерность массива к размерностям (Количество полос) (Количество транзитных участков) (Количество каналов) (Количество сегментов). Когда вы подаете изображение в нейронную сеть, первые две размерности являются высотой и шириной изображения, третья размерность является каналами, и четвертая размерность разделяет отдельные изображения.
X = reshape(spec,size(spec,1),size(spec,2),size(data,2),[]);
Вызовите melSpectrogram без выходных аргументов, чтобы построить mel спектрограмму середины канала для первых шести из одного второго шага.
for channel = 1:2:11 figure melSpectrogram(dataBuffered(:,channel),fs, ... 'WindowLength',windowLength, ... 'OverlapLength',samplesOverlap, ... 'FFTLength',fftLength, ... 'NumBands',numBands); title(sprintf('Segment %d',ceil(channel/2))) end






Функция помощника getSegmentedMelSpectrograms выполняет шаги извлечения признаков, обрисованные в общих чертах выше.
function X = getSegmentedMelSpectrograms(x,fs,varargin) % This function is for example purposes only. It may change or be removed % in a future release. % Copyright 2019 The MathWorks, Inc. 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, ... 'WindowLength',params.WindowLength, ... '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
Чтобы ускорить обработку, извлеките mel спектрограммы всех звуковых файлов в хранилищах данных с помощью tall массивы. В отличие от массивов в оперативной памяти, длинные массивы остаются неоцененными, пока вы не запрашиваете, чтобы вычисления были выполнены с помощью gather функция. Эта отсроченная оценка позволяет вам работать быстро с большими наборами данных. Когда вы в конечном счете запрашиваете выход с помощью gather, MATLAB комбинирует вычисления в очереди, где возможный и берет минимальное количество проходов через данные. Если у вас есть Parallel Computing Toolbox™, можно использовать длинные массивы в локальном сеансе работы с MATLAB, или на локальном параллельном пуле. Можно также выполнить вычисления длинного массива на кластере, если вам установили MATLAB® Parallel Server™.
Если у вас нет Parallel Computing Toolbox™, код в этом примере все еще запускается.
pp = parpool('IdleTimeout',inf); train_set_tall = tall(train_set); xTrain = cellfun(@(x)getSegmentedMelSpectrograms(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(test_set); xTest = cellfun(@(x)getSegmentedMelSpectrograms(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 6 min 28 sec Evaluation completed in 6 min 28 sec Evaluating tall expression using the Parallel Pool 'local': - Pass 1 of 1: Completed in 1 min 52 sec Evaluation completed in 1 min 52 sec
Реплицируйте метки набора обучающих данных так, чтобы они были во взаимно-однозначном соответствии с сегментами.
numSegmentsPer10seconds = size(dataBuffered,2)/2; yTrain = repmat(train_set.Labels,1,numSegmentsPer10seconds)'; yTrain = yTrain(:);
Набор данных DCASE 2017 содержит относительно небольшое количество акустических записей для задачи, и набор разработки и набор оценки были зарегистрированы в различных определенных местоположениях. В результате легко сверхсоответствовать к данным во время обучения. Один популярный метод, чтобы уменьшать сверхподбор кривой является путаницей. В путанице вы увеличиваете свой набор данных путем смешивания функций двух различных классов. Когда вы смешиваете функции, вы смешиваете метки в равной пропорции. Это:

Путаница была повторно сформулирована [2] как метки, чертившие от вероятностного распределения вместо смешанных меток. Реализация путаницы в этом примере является упрощенной версией путаницы: каждая спектрограмма смешана со спектрограммой различной метки с набором lambda к 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 11769
bus 11904
cafe/restaurant 11873
car 11820
city_center 11886
forest_path 11936
grocery_store 11914
home 11923
library 11817
metro_station 11804
office 11922
park 11871
residential_area 11704
train 11773
tram 11924
Задайте архитектуру 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 averagePooling2dLayer(ceil(imgSize(1:2)/8)) dropoutLayer(0.5) fullyConnectedLayer(15) softmaxLayer classificationLayer];
Задайте trainingOptions для 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 обучать сеть.
trainedNet = trainNetwork(xTrain,yTrain,layers,options);

Вызовите predict предсказать ответы от обучившего сеть использования протянутого набора тестов.
cnnResponsesPerSegment = predict(trainedNet,xTest);
Насчитайте ответы по каждым 10 вторым аудиоклипам.
classes = trainedNet.Layers(end).Classes; numFiles = numel(test_set.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 визуализировать точность на наборе тестов. Возвратите среднюю точность в Командное окно.
figure cm = confusionchart(test_set.Labels,cnnPredictedLabels,'title','Test Accuracy - CNN'); cm.ColumnSummary = 'column-normalized'; cm.RowSummary = 'row-normalized'; fprintf('Average accuracy of CNN = %0.2f\n',mean(test_set.Labels==cnnPredictedLabels)*100)
Average accuracy of CNN = 73.21

Рассеивание вейвлета, как показывали, в [4] обеспечило хорошее представление акустических сцен. Задайте waveletScattering объект. Масштабные коэффициенты инвариантности и добротности были определены методом проб и ошибок.
sf = waveletScattering('SignalLength',size(data,1), ... 'SamplingFrequency',fs, ... 'InvarianceScale',0.75, ... 'QualityFactors',[4 1]);
Преобразуйте звуковой сигнал в моно, и затем вызовите featureMatrix возвратить рассеивающиеся коэффициенты для рассеивающейся среды разложения, 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
Функция помощника getWaveletFeatureVector выполняет перечисленные выше шаги. Используйте tall массив с cellfun и getWaveletFeatureVector параллелизировать извлечение признаков. Извлеките характеристические векторы вейвлета для обучения и наборов тестов.
scatteringTrain = cellfun(@(x)getWaveletFeatureVector(x,sf),train_set_tall,'UniformOutput',false); xTrain = gather(scatteringTrain); xTrain = cell2mat(xTrain')'; scatteringTest = cellfun(@(x)getWaveletFeatureVector(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 30 min 8 sec Evaluation completed in 30 min 8 sec Evaluating tall expression using the Parallel Pool 'local': - Pass 1 of 1: Completed in 10 min 17 sec Evaluation completed in 10 min 17 sec

Используйте fitcensemble создать обученную модель ансамбля классификации (ClassificationEnsemble).
subspaceDimension = min(150,size(xTrain,2) - 1); numLearningCycles = 30; classificationEnsemble = fitcensemble(xTrain,train_set.Labels, ... 'Method','Subspace', ... 'NumLearningCycles',numLearningCycles, ... 'Learners','discriminant', ... 'NPredToSample',subspaceDimension, ... 'ClassNames',removecats(unique(train_set.Labels)));
Для каждых 10 вторых аудиоклипов вызовите predict чтобы возвратить метки и веса, затем сопоставьте его с соответствующим предсказанным местоположением. Вызовите confusionchart визуализировать точность на наборе тестов. Распечатайте среднее значение.
[waveletPredictedLabels,waveletResponses] = predict(classificationEnsemble,xTest); figure cm = confusionchart(test_set.Labels,waveletPredictedLabels,'title','Test Accuracy - Wavelet Scattering'); cm.ColumnSummary = 'column-normalized'; cm.RowSummary = 'row-normalized'; fprintf('Average accuracy of classifier = %0.2f\n',mean(test_set.Labels==waveletPredictedLabels)*100)
Average accuracy of classifier = 76.23

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

Закройте параллельный пул.
delete(pp)
Parallel pool using the 'local' profile is shutting down.
[1] А. Мезэрос, Т. Хейттола и Т. Виртэнен. Акустическая Классификация Сцен: Обзор записей DCASE 2017 проблемы. В материалах Международный семинар на Акустическом Улучшении Сигнала, 2018.
[2] Huszar, Ференц. "Путаница: информационно-зависимое Увеличение Данных". InFERENCe. 03 ноября 2017. Полученный доступ 15 января 2019. https://www.inference.vc/mixup-data-dependent-data-augmentation/.
[3] Ханьцы, Yoonchang, парк Jeongsoo и Киогу Ли. "Сверточные нейронные сети с бинауральными представлениями и фоновым вычитанием для акустической классификации сцен". Обнаружение и Классификация Акустических Сцен и Событий (DCASE) (2017): 1-5.
[4] Lostanlen, Винсент и Джоуким Анден. Бинауральная классификация сцен с рассеиванием вейвлета. Технический отчет, проблема DCASE2016, 2016.
[5] А. Дж. Эронен, В. Т. Пелтонен, Дж. Т. Туоми, А. П. Клапури, С. Фэджерланд, Т. Сорса, Г. Лорхо и Дж. Хуопэними, "Основанное на аудио распознавание контекста", Сделка IEEE на Аудио, Речи, и Обработке Языка, vol 14, № 1, стр 321-329, январь 2006.