Классификация жанра музыки с использованием вейвлета вейвлет-времени

Этот пример показов, как классифицировать жанр музыкального отрывка с помощью вейвлета рассеяния времени и audio datastore. При вейвлет данные распространяются через ряд вейвлет, нелинейностей и усреднения, чтобы получить низкодисперсные представления данных. Эти представления с низкой дисперсией затем используются в качестве входов для классификатора.

Набор данных GTZAN

В этом примере используется набор данных GTZAN Ganre Collection [7] [8]. Данные предоставляются в виде архива zipped tar, который составляет приблизительно 1,2 ГБ. Несжатый набор данных требует около 3 ГБ дискового пространства. Извлечение сжатого файла tar из ссылки, представленной в ссылках, создает папку с десятью подпапками. Каждая подпапка названа по содержащемуся в ней жанру музыкальных выборок. Жанры: блюз, классика, кантри, диско, хипхоп, джаз, метал, поп, регги и рок. Существует 100 примеров каждого жанра, и каждый аудио файла состоит примерно из 30 секунд данных, дискретизированных с частотой дискретизации 22050 Гц. В оригинальной статье авторы использовали ряд функций временной области и частотного диапазона, включая коэффициенты mel-frequency (MFC), извлеченные из каждого музыкального примера, и классификацию Гауссовой смешанной модели (GMM), чтобы достичь точности 61 процент [7]. Впоследствии к этим данным были применены нейронные сети для глубокого обучения. В большинстве случаев эти подходы к глубокому обучению состоят из сверточных нейронных сетей (CNN) с коэффициентами MFC или спектрограммами в качестве входов для глубокого CNN. Эти подходы привели к эффективности около 84% [4]. Подход LSTM со срезов времени спектрограммы привел к точности 79% и временной области и частотного диапазона функций в сочетании с подходом обучения ансамбля (AdaBoost) привел к точности 82% на тестовом наборе [2] [3]. Недавно подход разреженного машинного обучения с представлением достиг приблизительно 89% точности [6].

Загрузка данных

Первым шагом является загрузка GTZAN Ganre Набора [7] [8]. Инструкции в этом примере предполагают, что вы загружаете набор данных на свою временную директорию, tempdir, в MATLAB ®. Если вы принимаете решение загрузить данные в папку, отличную от tempdirизмените имя директории в последующих инструкциях. Использование gunzip для загрузки и распаковки набора данных. Затем используйте untar для извлечения содержимого файла tar. Папка genres создается в tempdir. Внутренние genres это десять подпапок, по одной для каждого музыкального жанра.

dataURL = 'http://opihi.cs.uvic.ca/sound/genres.tar.gz';
gunzip(dataURL,tempdir)                       % creates genres.tar in tempdir
untar(fullfile(tempdir,'genres.tar'),tempdir) % creates genres folder

Вейвлет

Единственными параметрами, которые нужно задать в сети вейвлет-рассеяния времени, являются длительность инвариации времени, количество банков вейвлет-фильтров и количество вейвлеты на октаву. Для большинства приложений достаточно каскадирования данных через два вейвлета фильтра. В этом примере мы используем сеть рассеяния по умолчанию, которая использует две группы вейвлет. Первая группа фильтров имеет 8 вейвлет на октаву, а вторая группа фильтров имеет 1 вейвлет на октаву. В этом примере установите инвариантную шкалу равной 0,5 секунды, что соответствует немного более чем 11000 выборок для заданной частоты дискретизации. Создайте вейвлет сеть разложения рассеяния во время.

sn = waveletScattering('SignalLength',2^19,'SamplingFrequency',22050,...
    'InvarianceScale',0.5);

Чтобы понять роль инвариационной шкалы, получите и постройте график масштабирующего фильтра во времени вместе с действительной и мнимой частями наиболее грубого вейвлета из первой группы фильтров. Обратите внимание, что временная поддержка масштабирующего фильтра составляет по существу 0,5 секунды, как предусмотрено. Кроме того, временная поддержка наиболее грубого вейвлета не превышает инвариантную шкалу разложения вейвлет-рассеяния.

[fb,f,filterparams] = filterbank(sn);
phi = ifftshift(ifft(fb{1}.phift));
psiL1 = ifftshift(ifft(fb{2}.psift(:,end)));
dt = 1/22050;
time = -2^18*dt:dt:2^18*dt-dt;
scalplt = plot(time,phi,'linewidth',1.5);
hold on
grid on
ylimits = [-3e-4 3e-4];
ylim(ylimits);
plot([-0.25 -0.25],ylimits,'k--');
plot([0.25 0.25],ylimits,'k--');
xlim([-0.6 0.6]);
xlabel('Seconds'); ylabel('Amplitude');
wavplt = plot(time,[real(psiL1) imag(psiL1)]);
legend([scalplt wavplt(1) wavplt(2)],...
    {'Scaling Function','Wavelet-Real Part','Wavelet-Imaginary Part'});
title({'Scaling Function';'Coarsest-Scale Wavelet First Filter Bank'})
hold off

Audio Datastore

audio datastore позволяет управлять наборы аудио файлов данных. Для машинного или глубокого обучения audio datastore не только управляет потоком аудиоданных из файлов и папок, audio datastore также управляет ассоциацией меток с данными и предоставляет возможность случайным образом разбить ваши данные на различные наборы для обучения, валидации и проверки. В этом примере используйте audio datastore для управления набором жанра музыки GTZAN. Напомним, каждая подпапка набора названа в честь жанра, который она представляет. Установите 'IncludeSubFolders' свойство к true чтобы дать команду audio datastore использовать подпапки и задать 'LabelSource' свойство к 'foldernames' создание меток данных на основе имен подпапок. Этот пример предполагает, что директория верхнего уровня находится внутри вашего MATLAB tempdir директория и называется 'genres'. Убедитесь, что location - правильный путь к папке данных верхнего уровня на вашем компьютере. Папка данных верхнего уровня на вашем компьютере должна содержать десять подпапок, каждая из которых называется для десяти жанров, и должна содержать только аудио- файлы, соответствующие этим жанрам.

location = fullfile(tempdir,'genres');
ads = audioDatastore(location,'IncludeSubFolders',true,...
    'LabelSource','foldernames');

Выполните следующее, чтобы получить количество музыкальных жанров в наборе данных.

countEachLabel(ads)
ans=10×2 table
      Label      Count
    _________    _____

    blues         100 
    classical     100 
    country       100 
    disco         100 
    hiphop        100 
    jazz          100 
    metal         100 
    pop           100 
    reggae        100 
    rock          100 

Как говорилось ранее, существует 10 жанров со 100 файлами каждый.

Наборы для обучения и тестирования

Создайте обучающие и тестовые наборы для разработки и тестирования нашего классификатора. Мы используем 80% данных для обучения и удерживаем оставшиеся 20% для проверки. The shuffle функция audio datastore случайным образом тасует данные. Сделайте это до разделения данных по меткам, чтобы рандомизировать данные. В этом примере мы устанавливаем seed генератора случайных чисел для воспроизводимости. Используйте audio datastore splitEachLabel функция для выполнения разделения 80-20. splitEachLabel обеспечивает равное представление всех классов.

rng(100)
ads = shuffle(ads);
[adsTrain,adsTest] = splitEachLabel(ads,0.8);
countEachLabel(adsTrain)
ans=10×2 table
      Label      Count
    _________    _____

    blues         80  
    classical     80  
    country       80  
    disco         80  
    hiphop        80  
    jazz          80  
    metal         80  
    pop           80  
    reggae        80  
    rock          80  

countEachLabel(adsTest)
ans=10×2 table
      Label      Count
    _________    _____

    blues         20  
    classical     20  
    country       20  
    disco         20  
    hiphop        20  
    jazz          20  
    metal         20  
    pop           20  
    reggae        20  
    rock          20  

Вы видите, что в обучающих данных 800 записей, как ожидалось, и 200 записей в тестовых данных. Кроме того, существует 80 примеров каждого жанра в набор обучающих данных и 20 примеров каждого жанра в тестовом наборе.

Чтобы получить функции рассеяния, используйте вспомогательную функцию, helperbatchscatfeatures, который получает естественный логарифм функций рассеяния для 219 выборки каждого аудио файла и подвыборок количество окон рассеяния на 6. Исходный код для helperbatchscatfeatures приведено в приложении. Функции вейвлет вычисляются с помощью пакета размером 64 сигнала.

Если у вас есть Parallel Computing Toolbox™ и поддерживаемый графический процессор, установите useGPU на true в следующем коде и преобразование рассеяния будет вычислено с помощью графический процессор. Используя графический процессор NVIDIA Titan V с размером пакета 64, функции рассеяния в этом примере вычислялись примерно в 9 раз быстрее, чем при использовании центрального процессора.

N = 2^19;
batchsize = 64;
scTrain = [];
useGPU = false; % Set to true to use the GPU

while hasdata(adsTrain)
    sc = helperbatchscatfeatures(adsTrain,sn,N,batchsize,useGPU);
    scTrain = cat(3,scTrain,sc);
end

Запишите количество временных окон в преобразовании рассеяния для создания метки.

numTimeWindows = size(scTrain,2);

В этом примере для каждого пути рассеяния существует 43 временных интервала или системы координат.

Повторите тот же процесс редукции данных для тестовых данных.

scTest = [];

while hasdata(adsTest)
   sc = helperbatchscatfeatures(adsTest,sn,N,batchsize,useGPU);
   scTest = cat(3,scTest,sc); 
end

Определите количество путей в сети рассеяния и измените структуру обучающих и тестовых функций на 2-D матрицы.

[~,npaths] = sn.paths();
Npaths = sum(npaths);
TrainFeatures = permute(scTrain,[2 3 1]);
TrainFeatures = reshape(TrainFeatures,[],Npaths,1);
TestFeatures = permute(scTest,[2 3 1]);
TestFeatures = reshape(TestFeatures,[],Npaths,1);

Каждая строка TrainFeatures и TestFeatures является одним временным окном рассеяния через 334 пути в преобразовании рассеяния каждого аудиосигнала. Для каждой выборки у нас 43 таких временных окна. Соответственно, матрица функций для обучающих данных является 34400 334. Количество строк равно количеству обучающих примеров (800), умноженному на количество окон рассеяния в каждом примере (43). Точно так же матрица функций рассеяния для тестовых данных является 8600 334. В каждом примере существует 200 тестовых примеров и 43 окна. Создайте жанровую метку для каждого из 43 окон в матрице функций вейвлет для обучающих данных.

trainLabels = adsTrain.Labels;
numTrainSignals = numel(trainLabels);
trainLabels = repmat(trainLabels,1,numTimeWindows);
trainLabels = reshape(trainLabels',numTrainSignals*numTimeWindows,1);

Повторите процесс для тестовых данных.

testLabels = adsTest.Labels;
numTestSignals = numel(testLabels);
testLabels = repmat(testLabels,1,numTimeWindows);
testLabels = reshape(testLabels',numTestSignals*numTimeWindows,1);

В этом примере используйте классификатор мультикласса машины опорных векторов (SVM) с кубическим полиномиальным ядром. Подбор SVM к обучающим данным.

template = templateSVM(...
    'KernelFunction', 'polynomial', ...
    'PolynomialOrder', 3, ...
    'KernelScale', 'auto', ...
    'BoxConstraint', 1, ...
    'Standardize', true);
Classes = {'blues','classical','country','disco','hiphop','jazz',...
    'metal','pop','reggae','rock'};
classificationSVM = fitcecoc(...
    TrainFeatures, ...
    trainLabels, ...
    'Learners', template, ...
    'Coding', 'onevsone','ClassNames',categorical(Classes));

Предсказание тестового набора

Используйте модель SVM в подгонку с преобразованиями рассеяния обучающих данных, чтобы предсказать жанры музыки для тестовых данных. Напомним, что для каждого сигнала в преобразовании рассеяния существует 43 временных окна. Используйте простое большинство голосов, чтобы предсказать жанр. Функция помощника helperMajorityVote получает режим жанровых меток по всем 43 окнам рассеяния. Если уникального режима нет, helperMajorityVote возвращает ошибку классификации, обозначенную 'NoUniqueMode'. Это приводит к появлению дополнительного столбца в матрице неточностей. Исходный код для helperMajorityVote приведено в приложении.

predLabels = predict(classificationSVM,TestFeatures);
[TestVotes,TestCounts] = helperMajorityVote(predLabels,adsTest.Labels,categorical(Classes));
testAccuracy = sum(eq(TestVotes,adsTest.Labels))/numTestSignals*100
testAccuracy = 87.5000

Точность теста, testAccuracy, составляет примерно 88 процентов. Эта точность сопоставима с состоянием техники набора данных GTZAN.

Отобразите матрицу неточностей, чтобы просмотреть жанровые показатели точности. Напомним, в каждом классе 20 примеров.

confusionchart(TestVotes,adsTest.Labels)

Диагональ матричного графика путаницы показывает, что точности классификации для отдельных жанров в целом довольно хороши. Извлечь эти жанровые точности и построить отдельно.

cm = confusionmat(TestVotes,adsTest.Labels);
cm(:,end) = [];
genreAccuracy = diag(cm)./20*100;
figure;
bar(genreAccuracy)
set(gca,'XTickLabels',Classes);
xtickangle(gca,30);
title('Percentage Correct by Genre - Test Set');

Сводные данные

Этот пример продемонстрировал использование вейвлет рассеяния и audio datastore в классификации жанра музыки. В этом примере рассеяние вейвлета времени достигло точности классификации, сопоставимой с состоянием из эффективности уровня техники для набора данных GTZAN. В отличие от других подходов, требующих извлечения ряда функций временной области и частотного диапазона, вейвлет требовало только спецификации одного параметра, шкалы инварианта времени. Audio datastore позволил нам эффективно управлять передачей большого набора данных с диска в MATLAB и позволил нам рандомизировать данные и точно сохранить жанровую принадлежность рандомизированных данных через рабочий процесс классификации.

Ссылки

  1. Анден, Дж. И Маллат, С. 2014. Спектр глубокого рассеяния. Транзакции IEEE по обработке сигналов, том 62, 16, стр. 4114-4128.

  2. Bergstra, J., Casagrande, N., Erhan, D., Eck, D., and Kegl, B. Aggregate features and AdaBoost for music classification. Машинное обучение, том 65, выпуск 2-3, стр. 473-484.

  3. Irvin, J., Chartock, E., and Hollander, N. 2016. Рекуррентные нейронные сети с вниманием к жанровой классификации. https://www.semanticscholar.org/paper/Recurrent-Neural-Networks-with-Attention-for-Genre-Irvin/6da301817851f19107447e4c72e682e3f183ae8a

  4. Li, T., Chan, A.B., and Chun, A. 2010. Автоматическая редукция данных музыкального шаблона с использованием сверточной нейронной сети. Международная конференция по майнингу данных и применениям.

  5. Маллат. S. 2012. Групповое инвариантное рассеяние. Сообщения по чистой и прикладной математике, том 65, 10, стр. 1331-1398.

  6. Panagakis, Y., Kotropoulos, C.L., and Arce, G.R. 2014. Классификация жанра музыки через совместное разреженное низкоранговое представление аудио функций. Транзакции IEEE по обработке звука, речи и языка, 22, 12, стр. 1905-1917.

  7. Tzanetakis, G. and Cook, P. 2002. Музыкальная жанровая классификация аудиосигналов. Транзакции IEEE по обработке речи и аудио, том 10, № 5, стр. 293-302.

  8. GTZAN Жанровый набор. http://marsyas.info/downloads/datasets.html

Приложение -- Вспомогательные функции

helperMightageVote - Эта функция возвращает режим меток классов, предсказанных для ряда векторов признаков. При вейвлет рассеянии мы получаем метку класса для каждого временного окна. Если уникальный режим не найден, метка 'NoUniqueMode' возвращается для обозначения ошибки классификации.

type helperMajorityVote
function [ClassVotes,ClassCounts] = helperMajorityVote(predLabels,origLabels,classes)
% This function is in support of wavelet scattering examples only. It may
% change or be removed in a future release.

% Make categorical arrays if the labels are not already categorical
predLabels = categorical(predLabels);
origLabels = categorical(origLabels);
% Expects both predLabels and origLabels to be categorical vectors
Npred = numel(predLabels);
Norig = numel(origLabels);
Nwin = Npred/Norig;
predLabels = reshape(predLabels,Nwin,Norig);
ClassCounts = countcats(predLabels);
[mxcount,idx] = max(ClassCounts);
ClassVotes = classes(idx);
% Check for any ties in the maximum values and ensure they are marked as
% error if the mode occurs more than once
tmpsum = sum(ClassCounts == mxcount);
ClassVotes(tmpsum > 1) = categorical({'NoUniqueMode'});
ClassVotes = ClassVotes(:);

helperbatchscatfeatures - Эта функция возвращает матрицу признаков вейвлет для заданного входного сигнала. В этом случае мы используем естественный логарифм коэффициентов вейвлет. Матрица функций рассеяния вычисляется на 219 выборки сигнала. Рассеивающие функции субдискретизированы в 6 раз. Если useGPU установлено в true, преобразование рассеяния вычисляется на графическом процессоре.

function sc = helperbatchscatfeatures(ds,sn,N,batchsize,useGPU)
% This function is only intended to support examples in the Wavelet
% Toolbox. It may be changed or removed in a future release.

% Read batch of data from audio datastore
batch = helperReadBatch(ds,N,batchsize);
if useGPU
    batch = gpuArray(batch);
end

% Obtain scattering features
S = sn.featureMatrix(batch,'transform','log');
gather(batch);
S = gather(S);
    
% Subsample the features
sc = S(:,1:6:end,:);
end

helperReadBatch - эта функция считывает пакеты заданного размера из datastore и возвращает выход с одинарной точностью. Каждый столбец выхода является отдельным сигналом от datastore. Если у datastore недостаточно записей, у выход может быть меньше столбцов, чем у batchsize.

function batchout = helperReadBatch(ds,N,batchsize)
% This function is only in support of Wavelet Toolbox examples. It may
% change or be removed in a future release.
%
% batchout = readReadBatch(ds,N,batchsize) where ds is the Datastore and
%   ds is the Datastore
%   batchsize is the batchsize

kk = 1;

while(hasdata(ds)) && kk <= batchsize
    tmpRead = read(ds);
    batchout(:,kk) = cast(tmpRead(1:N),'single'); %#ok<AGROW>
    kk = kk+1;
end

end
Для просмотра документации необходимо авторизоваться на сайте