Этот пример показывает, как создать мультиобразцовую последнюю систему сплава для акустического распознавания сцены. Пример обучает сверточную нейронную сеть (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',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 может использовать, чтобы идентифицировать движущиеся источники (такие как 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 спектрограммы, как предложено [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: 8). Evaluating tall expression using the Parallel Pool 'local': - Pass 1 of 1: Completed in 8 min 49 sec Evaluation completed in 8 min 49 sec Evaluating tall expression using the Parallel Pool 'local': - Pass 1 of 1: Completed in 2 min 59 sec Evaluation completed in 2 min 59 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; lr = 0.05*miniBatchSize/128; 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 = 75.19
Рассеивание вейвлета, как показывали, в [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 35 min 54 sec Evaluation completed in 35 min 54 sec Evaluating tall expression using the Parallel Pool 'local': - Pass 1 of 1: Completed in 12 min 33 sec Evaluation completed in 12 min 33 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.95
Закройте параллельный пул.
delete(pp)
[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.