Классифицируйте пол Используя длинные краткосрочные сети памяти

Этот пример показывает, как классифицировать пол докладчика, использующего глубокое обучение. В частности, пример использует сеть Bidirectional Long Short-Term Memory (BiLSTM) и Коэффициенты Gammatone Cepstral (gtcc), подачу, гармоническое отношение и несколько спектральных дескрипторов формы.

Введение

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

Этот пример использует сети долгой краткосрочной памяти (LSTM), тип рекуррентной нейронной сети (RNN), подходящей, чтобы изучить данные timeseries и последовательность. Сеть LSTM может изучить долгосрочные зависимости между временными шагами последовательности. Слой LSTM (lstmLayer) может посмотреть в то время последовательность в прямом направлении, в то время как двунаправленный слой LSTM (bilstmLayer) может посмотреть в то время последовательность и во вперед и в обратные направления. Этот пример использует двунаправленный слой LSTM.

Этот пример обучает сеть LSTM с последовательностями Коэффициентов Кепстра Gammatone (gtcc), оценок подачи, гармонического отношения и нескольких спектральных дескрипторов формы.

Пример проходит следующие шаги:

  1. Создайте audioDatastore, который указывает на аудио речевые файлы, используемые, чтобы обучить сеть LSTM.

  2. Удалите тишину и неречевые сегменты из речевых файлов с помощью простого метода пороговой обработки.

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

  4. Обучите сеть LSTM с помощью последовательностей функции.

  5. Измерьте и визуализируйте точность классификатора на данных тренировки.

  6. Создайте audioDatastore речевых файлов, используемых, чтобы протестировать обучивший сеть.

  7. Удалите неречевые сегменты из этих файлов, сгенерируйте последовательности функции, передайте их через сеть и протестируйте ее точность путем сравнения предсказанного и фактического пола докладчиков.

Чтобы ускорить учебный процесс, запустите этот пример на машине с графическим процессором. Если ваша машина имеет графический процессор и Parallel Computing Toolbox™, то MATLAB® автоматически использует графический процессор для обучения; в противном случае это использует центральный процессор.

Исследуйте набор данных

Этот пример использует набор данных Mozilla Common Voice [1]. Набор данных содержит записи на 48 кГц предметов говорящие короткие предложения. Загрузите набор данных и untar загруженный файл. Установите datafolder на местоположение данных.

datafolder = PathToDatabase;

Используйте audioDatastore, чтобы создать datastore для файлов в папке cv-valid-train.

ads = audioDatastore(fullfile(datafolder,"cv-valid-train"));

Используйте readtable, чтобы считать метаданные, сопоставленные со звуковыми файлами. Метаданные содержатся в файле cv_valid-train.csv. Осмотрите первые несколько строк метаданных.

metadata = readtable(fullfile(datafolder,"cv-valid-train.csv"));
head(metadata)
ans =

  8×8 table

                 filename                                                           text                                              up_votes    down_votes       age         gender     accent    duration
    __________________________________    ________________________________________________________________________________________    ________    __________    __________    ________    ______    ________

    'cv-valid-train/sample-000000.mp3'    'learn to recognize omens and follow them the old king had said'                               1            0         ''            ''           ''         NaN   
    'cv-valid-train/sample-000001.mp3'    'everything in the universe evolved he said'                                                   1            0         ''            ''           ''         NaN   
    'cv-valid-train/sample-000002.mp3'    'you came so that you could learn about your dreams said the old woman'                        1            0         ''            ''           ''         NaN   
    'cv-valid-train/sample-000003.mp3'    'so now i fear nothing because it was those omens that brought you to me'                      1            0         ''            ''           ''         NaN   
    'cv-valid-train/sample-000004.mp3'    'if you start your emails with greetings let me be the first to welcome you to earth'          3            2         ''            ''           ''         NaN   
    'cv-valid-train/sample-000005.mp3'    'a shepherd may like to travel but he should never forget about his sheep'                     1            0         'twenties'    'female'     'us'       NaN   
    'cv-valid-train/sample-000006.mp3'    'night fell and an assortment of fighting men and merchants entered and exited the tent'       3            0         ''            ''           ''         NaN   
    'cv-valid-train/sample-000007.mp3'    'i heard a faint movement under my feet'                                                       2            1         ''            ''           ''         NaN   

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

csvFiles   = metadata.filename;
[~,csvInd] = sort(csvFiles);

% Read the gender variable from the table.
gender     = metadata.gender;
age        = metadata.age;

adsFiles   = ads.Files;
[~,adsInd] = sort(adsFiles);

% Re-arrange gender to ensure information is linked to the correct files.
gender     = gender(csvInd(adsInd));
age        = age(csvInd(adsInd));

Присвойте пол свойству Labels datastore.

ads.Labels = gender;

Используйте shuffle, чтобы рандомизировать порядок файлов в datastore.

ads = shuffle(ads);

Не все файлы в наборе данных аннотируются информацией о возрасте и полом. Создайте подмножество datastore, который только содержит файлы, где информация о поле доступна, и возраст больше, чем 19.

maleOrfemale = categorical(ads.Labels) == "male" | categorical(ads.Labels) == "female";
isAdult      = categorical(age) ~= "" & categorical(age) ~= "teens";
ads          = subset(ads,maleOrfemale & isAdult);

Используйте countEachLabel, чтобы осмотреть гендерный отказ файлов.

countEachLabel(ads)
ans =

  2×2 table

    Label     Count
    ______    _____

    female    17747
    male      53494

Вы обучите нейронную сеть для глубокого обучения на подмножестве файлов. Создайте подмножество datastore, содержащее 3 000 спикеров и 3 000 женщин-спикеров.

ismale   = find(categorical(ads.Labels) == "male");
isfemale = find(categorical(ads.Labels) == "female");
numFilesPerGender = 3000;
ads = subset(ads,[ismale(1:numFilesPerGender) isfemale(1:numFilesPerGender)]);

Используйте shuffle снова, чтобы рандомизировать порядок файлов в datastore.

ads = shuffle(ads);

Используйте countEachLabel, чтобы проверить гендерный отказ набора обучающих данных.

countEachLabel(ads)
ans =

  2×2 table

    Label     Count
    ______    _____

    female    3000 
    male      3000 

Изолированные речевые сегменты

Считайте содержимое звукового файла с помощью read.

[audio,info] = read(ads);
Fs           = info.SampleRate;

Постройте звуковой сигнал и затем слушайте его с помощью команды sound.

timeVector = (1/Fs) * (0:numel(audio)-1);
figure
plot(timeVector,audio)
ylabel("Amplitude")
xlabel("Time (s)")
title("Sample Audio")
grid on

sound(audio,Fs)

Речевой сигнал имеет сегменты тишины, которые не содержат полезную информацию, имеющую отношение к полу докладчика. Этот пример удаляет тишину с помощью упрощенной версии подхода пороговой обработки, описанного в [2]. Шаги алгоритма удаления тишины обрисованы в общих чертах ниже.

Во-первых, вычислите две функции по неперекрывающимся кадрам аудиоданных: энергия сигнала и спектральный центроид. Спектральный центроид является мерой "центра тяжести" спектра сигнала.

Повредите аудио в неперекрывающиеся кадры с 50 миллисекундами.

audio        = audio ./ max(abs(audio)); % Normalize amplitude
windowLength = 50e-3 * Fs;
segments     = buffer(audio,windowLength);

Вычислите энергию и спектральный центроид для каждого кадра.

win = hann(windowLength,'periodic');
signalEnergy = sum(segments.^2,1)/windowLength;
centroid = spectralCentroid(segments,Fs,'Window',win,'OverlapLength',0);

Затем, установите пороги для каждой функции. Игнорируются области, где значения функции падают ниже или выше их соответствующих порогов. В этом примере энергетический порог устанавливается к половине средней энергии, и спектральный центроидный порог устанавливается к 5 000 Гц.

T_E            = mean(signalEnergy)/2;
T_C            = 5000;
isSpeechRegion = (signalEnergy>=T_E) & (centroid<=T_C);

Визуализируйте вычисленную энергию и спектральный центроид в зависимости от времени.

% Hold the signal energy, spectral centroid, and speech decision values for
% plotting purposes.
CC = repmat(centroid,windowLength,1);
CC = CC(:);
EE = repmat(signalEnergy,windowLength,1);
EE = EE(:);
flags2 = repmat(isSpeechRegion,windowLength,1);
flags2 = flags2(:);

figure

subplot(3,1,1)
plot(timeVector, CC(1:numel(audio)), ...
     timeVector, repmat(T_C,1,numel(timeVector)), "LineWidth",2)
xlabel("Time (s)")
ylabel("Normalized Centroid")
legend("Centroid","Threshold")
title("Spectral Centroid")
grid on

subplot(3,1,2)
plot(timeVector, EE(1:numel(audio)), ...
     timeVector, repmat(T_E,1,numel(timeVector)),"LineWidth",2)
ylabel("Normalized Energy")
legend("Energy","Threshold")
title("Window Energy")
grid on

subplot(3,1,3)
plot(timeVector, audio, ...
     timeVector,flags2(1:numel(audio)),"LineWidth",2)
ylabel("Audio")
legend("Audio","Speech Region")
title("Audio")
grid on
ylim([-1 1.1])

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

% Get indices of frames where a speech-to-silence or silence-to-speech
% transition occurs.
regionStartPos = find(diff([isSpeechRegion(1)-1, isSpeechRegion]));

% Get the length of the all-silence or all-speech regions.
RegionLengths  = diff([regionStartPos, numel(isSpeechRegion)+1]);

% Get speech-only regions.
isSpeechRegion = isSpeechRegion(regionStartPos) == 1;
regionStartPos = regionStartPos(isSpeechRegion);
RegionLengths  = RegionLengths(isSpeechRegion);

% Get start and end indices for each speech region. Extend the region by 5
% windows on each side.
startIndices = zeros(1,numel(RegionLengths));
endIndices   = zeros(1,numel(RegionLengths));
for index=1:numel(RegionLengths)
   startIndices(index) = max(1, (regionStartPos(index) - 5) * windowLength + 1);
   endIndices(index)   = min(numel(audio), (regionStartPos(index) + RegionLengths(index) + 5) * windowLength);
end

Наконец, объедините пересекающиеся речевые сегменты.

activeSegment       = 1;
isSegmentsActive    = zeros(1,numel(startIndices));
isSegmentsActive(1) = 1;
for index = 2:numel(startIndices)
    if startIndices(index) <= endIndices(activeSegment)
        % Current segment intersects with previous segment
        if endIndices(index) > endIndices(activeSegment)
           endIndices(activeSegment) =  endIndices(index);
        end
    else
        % New speech segment detected
        activeSegment = index;
        isSegmentsActive(index) = 1;
    end
end
numSegments = sum(isSegmentsActive);
segments    = cell(1,numSegments);
limits      = zeros(2,numSegments);
speechSegmentsIndices  = find(isSegmentsActive);
for index = 1:length(speechSegmentsIndices)
    segments{index} = audio(startIndices(speechSegmentsIndices(index)): ...
                            endIndices(speechSegmentsIndices(index)));
    limits(:,index) = [startIndices(speechSegmentsIndices(index)) ; ...
                       endIndices(speechSegmentsIndices(index))];
end

Постройте исходное аудио наряду с обнаруженными речевыми сегментами.

figure

plot(timeVector,audio)
hold on
myLegend = cell(1,numel(segments)+1);
myLegend{1} = "Original Audio";
for index = 1:numel(segments)
    plot(timeVector(limits(1,index):limits(2,index)),segments{index});
    myLegend{index+1} = sprintf("Output Audio Segment %d",index);
end
xlabel("Time (s)")
ylabel("Audio")
grid on
legend(myLegend)

Функции аудио

Речевой сигнал является динамическим по своей природе и изменяется в зависимости от времени. Это принято, что речевые сигналы стационарные в кратковременных шкалах, и их обработка часто делается в окнах 20-40 мс. Для каждого речевого сегмента этот пример извлекает функции аудио для 30 MS Windows с 75%-м перекрытием.

win = hamming(0.03*Fs,"periodic");
overlapLength = 0.75*numel(win);
featureParams = struct("SampleRate",Fs, ...
                 "Window",win, ...
                 "OverlapLength",overlapLength);

Этот пример обучает сеть LSTM с помощью gammatone коэффициенты кепстра (GTCC), дельту и дельту дельты GTCC, оценки подачи, гармоническое отношение и несколько спектральных дескрипторов формы:

Для каждого речевого сегмента характеристические векторы конкатенированы в последовательности с 50%-м перекрытием. Каждый характеристический вектор содержит 50 функций. Каждая последовательность содержит 40 характеристических векторов. Задайте параметры последовательности как stuct.

sequenceParams = struct("NumFeatures",50, ...
                 "SequenceLength",40, ...
                 "HopLength",20);

Фигура предоставляет обзор выделения признаков, используемого в этом примере.

Извлеките функции Используя длинные массивы

Чтобы ускорить обработку, извлеките последовательности функции от речевых сегментов всех звуковых файлов в datastore с помощью массивов tall. В отличие от массивов в оперативной памяти, длинные массивы обычно остаются неоцененными, пока вы не запрашиваете, чтобы вычисления были выполнены с помощью функции gather. Эта отсроченная оценка позволяет вам работать быстро с большими наборами данных. Когда вы в конечном счете запрашиваете вывод с помощью gather, MATLAB® комбинирует вычисления в очереди, где возможный и берет минимальное количество проходов через данные. Если у вас есть Parallel Computing Toolbox™, можно использовать длинные массивы на локальном сеансе MATLAB®, или на локальном параллельном пуле. Можно также выполнить вычисления длинного массива на кластере, если вам установили MATLAB® Parallel Server™.

Во-первых, преобразуйте datastore в длинный массив:

T = tall(ads)
Starting parallel pool (parpool) using the 'local' profile ...
Connected to the parallel pool (number of workers: 12).

T =

  M×1 tall cell array

    { 55920×1 double}
    {236784×1 double}
    {380784×1 double}
    {440688×1 double}
    {277104×1 double}
    {130800×1 double}
    {222960×1 double}
    {123888×1 double}
        :        :
        :        :

Отображение указывает, что количество строк (соответствующий количеству файлов в datastore), M, еще не известно. M является заполнителем, пока вычисление не завершается.

Извлеките речевые сегменты от длинной таблицы. Это действие создает новую переменную длинного массива, чтобы использовать в последующих вычислениях. Функциональный HelperSegmentSpeech выполняет шаги, уже подсвеченные в разделе Isolate Speech Segments. Команда cellfun применяет HelperSegmentSpeech к содержимому каждого звукового файла в datastore.

segments = cellfun(@(x)HelperSegmentSpeech(x,Fs),T,"UniformOutput",false);

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

FeatureSequences = cellfun(@(x)HelperGetFeatureSequences(x,featureParams,sequenceParams),...
                           segments,"UniformOutput",false);

Используйте gather, чтобы оценить FeatureSequences:

FeatureSequences = gather(FeatureSequences);
Evaluating tall expression using the Parallel Pool 'local':
- Pass 1 of 1: Completed in 12 min 2 sec
Evaluation completed in 12 min 2 sec

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

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

featuresMatrix = cat(3,FeatureSequences{:});

sequencesMeans = zeros(1,sequenceParams.NumFeatures);
sequenceStds   = zeros(1,sequenceParams.NumFeatures);

for index = 1:sequenceParams.NumFeatures
    localFeatures             = featuresMatrix(:,index,:);
    sequencesMeans(index)     = mean(localFeatures(:));
    sequenceStds(index)       = std(localFeatures(:));
    featuresMatrix(:,index,:) = (localFeatures - sequencesMeans(index))/sequenceStds(index);
end

Создайте массив ячеек, features, содержа предикторы последовательности. Каждая запись в features является D-by-S матрицей, где D является количеством значений на временной шаг (количество функций), и S является длиной последовательности (в этом примере, 40).

features = cell(1,size(featuresMatrix,3));
for index = 1:size(featuresMatrix,3)
    features{index} = featuresMatrix(:,:,index).';
end

Создайте массив ячеек, gender, для ожидаемого пола, сопоставленного с каждой обучающей последовательностью.

numSequences = cellfun(@(x)size(x,3), FeatureSequences);
mylabels     = ads.Labels;
gender       = cell(sum(numSequences),1);
count        = 1;
for index1 = 1:numel(numSequences)
    for index2 = 1:numSequences(index1)
        gender{count} = mylabels{index1};
        count = count + 1;
    end
end

Задайте сетевую архитектуру LSTM

Сети LSTM могут изучить долгосрочные зависимости между временными шагами данных о последовательности. Этот пример использует двунаправленный слой LSTM bilstmLayer, чтобы посмотреть на последовательность и во вперед и в обратные направления.

Задайте входной размер, чтобы быть последовательностями размера NumFeatures. Задайте скрытый двунаправленный слой LSTM с выходным размером 100 и выведите последовательность. Эта команда дает двунаправленному слою LSTM команду сопоставлять входные временные ряды в 100 функций, которые передаются следующему слою. Затем задайте двунаправленный слой LSTM с выходным размером 100 и выведите последний элемент последовательности. Эта команда дает двунаправленному слою LSTM команду сопоставлять свой вход в 100 функций и затем готовит вывод к полносвязному слою. Наконец, задайте два класса включением полносвязного слоя размера 2, сопровождаемый softmax слоем и слоем классификации.

layers = [ ...
    sequenceInputLayer(sequenceParams.NumFeatures)
    bilstmLayer(100,"OutputMode","sequence")
    bilstmLayer(100,"OutputMode","last")
    fullyConnectedLayer(2)
    softmaxLayer
    classificationLayer];

Затем, задайте опции обучения для классификатора. Установите MaxEpochs на 10 так, чтобы сеть сделала 10, проходит через данные тренировки. Установите MiniBatchSize 128 так, чтобы сеть посмотрела на 128 учебных сигналов за один раз. Задайте Plots как "training-progress", чтобы сгенерировать графики, которые показывают учебный прогресс количеством увеличений итераций. Установите Verbose на false отключать печать таблицы вывод, который соответствует данным, показанным в графике. Задайте Shuffle как "every-epoch", чтобы переставить обучающую последовательность в начале каждой эпохи. Задайте LearnRateSchedule к "piecewise", чтобы уменьшить темп обучения заданным фактором (0.1) каждый раз, когда определенное число эпох (5) передало.

Этот пример использует адаптивную оценку момента (ADAM) решатель. ADAM выполняет лучше с рекуррентными нейронными сетями (RNNs) как LSTMs, чем стохастический спуск градиента по умолчанию с импульсом (SGDM) решатель.

options = trainingOptions("adam", ...
    "MaxEpochs",10, ...
    "MiniBatchSize",128, ...
    "Plots","training-progress", ...
    "Verbose",false, ...
    "Shuffle","every-epoch", ...
    "LearnRateSchedule","piecewise", ...
    "LearnRateDropFactor",0.1, ...
    "LearnRateDropPeriod",5);

Обучите сеть LSTM

Обучите сеть LSTM с заданными опциями обучения и архитектурой слоя с помощью trainNetwork. Поскольку набор обучающих данных является большим, учебный процесс может занять несколько минут.

net = trainNetwork(features,categorical(gender),layers,options);

Главный подграфик графика учебного прогресса представляет учебную точность, которая является точностью классификации на каждом мини-пакете. Когда обучение прогрессирует успешно, это значение обычно увеличивается к 100%. Нижний подграфик отображает учебную потерю, которая является перекрестной энтропийной потерей на каждом мини-пакете. Когда обучение прогрессирует успешно, это значение обычно уменьшается по направлению к нулю.

Если обучение не сходится, графики могут колебаться между значениями, не отклоняясь в определенном восходящем или нисходящем направлении. Это колебание означает, что учебная точность не улучшается, и учебная потеря не уменьшается. Эта ситуация может произойти в начале обучения, или после некоторого предварительного улучшения учебной точности. Во многих случаях изменение опций обучения может помочь сети достигнуть сходимости. Уменьшение MiniBatchSize или уменьшение InitialLearnRate могут закончиться в более длительное учебное время, но это может помочь сети учиться лучше.

В конце 10 эпох учебная точность превышает 95%.

Визуализируйте учебную точность

Вычислите учебную точность, которая представляет точность классификатора на сигналах, на которых это было обучено. Во-первых, классифицируйте данные тренировки.

trainPred = classify(net,features);

Постройте матрицу беспорядка. Отобразите точность и отзыв для этих двух классов при помощи сводных данных строки и столбца.

figure;
cm = confusionchart(categorical(gender),trainPred,'title','Training Accuracy');
cm.ColumnSummary = 'column-normalized';
cm.RowSummary = 'row-normalized';

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

Предскажите пол из каждого учебного файла путем считания выходных классов всех последовательностей сгенерированными из того же файла:

numFiles        = numel(numSequences);
actualGender    = categorical(ads.Labels);
predictedGender = actualGender;
counter         = 1;
for index = 1:numFiles
    % Get output classes from sequences corresponding to this file:
    predictions = trainPred(counter: counter + numSequences(index) - 1);
    % Set predicted gender to the most frequently predicted class
    predictedGender(index) = mode(predictions);
    counter = counter + numSequences(index);
end

Визуализируйте матрицу беспорядка на прогнозах принципа большинства.

figure
cm = confusionchart(actualGender,predictedGender,'title','Training Accuracy - Majority Rule');
cm.ColumnSummary = 'column-normalized';
cm.RowSummary = 'row-normalized';

Визуализируйте точность тестирования

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

Используйте audioDatastore, чтобы создать datastore для файлов в папке cv-valid-test.

ads = audioDatastore(fullfile(datafolder,"cv-valid-test"));

Используйте функцию readtable, чтобы считать метаданные, сопоставленные с этими файлами.

metadata = readtable(fullfile(datafolder,"cv-valid-test.csv"));

Считайте пол и переменные возраста из метаданных. Убедитесь, что файлы в метаданных и datastore располагаются в том же порядке.

csvFiles    = metadata.filename;
[~,csvInd]  = sort(csvFiles);

% Read the gender variable from the table.
gender     = metadata.gender;
age        = metadata.age;
adsFiles   = ads.Files;
[~,adsInd] = sort(adsFiles);

% Re-arrange gender to ensure information is linked to the correct files.
gender     = gender(csvInd(adsInd));
age        = age(csvInd(adsInd));

Присвойте пол свойству Labels datastore

ads.Labels = gender;

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

maleOrfemale = categorical(ads.Labels) == "male" | categorical(ads.Labels) == "female";
isAdult      = categorical(age) ~= "" & categorical(age) ~= "teens";
ads          = subset(ads,maleOrfemale & isAdult);

Используйте countEachLabel, чтобы осмотреть гендерный отказ файлов.

countEachLabel(ads)
ans =

  2×2 table

    Label     Count
    ______    _____

    female     358 
    male      1055 

Удалите тишину и извлеките функции от тестовых данных. Используйте gather, чтобы оценить FeatureSequences.

T                = tall(ads);
segments         = cellfun(@(x)HelperSegmentSpeech(x,Fs), T,"UniformOutput",false);
FeatureSequences = cellfun(@(x)HelperGetFeatureSequences(x,featureParams,sequenceParams),...
                           segments,"UniformOutput",false);

FeatureSequences = gather(FeatureSequences);
Starting parallel pool (parpool) using the 'local' profile ...
Connected to the parallel pool (number of workers: 12).
Evaluating tall expression using the Parallel Pool 'local':
- Pass 1 of 1: Completed in 3 min 2 sec
Evaluation completed in 3 min 2 sec

Нормируйте последовательность функции средними и стандартными отклонениями, вычисленными во время учебного этапа.

featuresMatrix = cat(3,FeatureSequences{:});
for index=1:sequenceParams.NumFeatures
    XI                        = featuresMatrix(:,index,:);
    featuresMatrix(:,index,:) = (XI - sequencesMeans(index))/sequenceStds(index);
end

Создайте массив ячеек, содержащий предикторы последовательности.

features = cell(1,size(featuresMatrix,3));
for index = 1:size(featuresMatrix,3)
    features{index} = featuresMatrix(:,:,index).';
end

% Create a cell array, |gender|, for the expected gender associated with
% each training sequence.
numSequences = cellfun(@(x)size(x,3),FeatureSequences);
mylabels     = ads.Labels;
gender       = cell(sum(numSequences),1);
count        = 1;
for index1 =1:numel(numSequences)
    for index2 = 1:numSequences(index1)
        gender{count} = mylabels{index1};
        count = count + 1;
    end
end

Предскажите пол для каждой последовательности.

testPred = classify(net,features);

Постройте матрицу беспорядка.

figure
cm = confusionchart(categorical(gender),testPred,'title','Testing Accuracy');
cm.ColumnSummary = 'column-normalized';
cm.RowSummary = 'row-normalized';

Предскажите пол из каждого учебного файла путем считания выходных классов всех последовательностей сгенерированными из того же файла:

numFiles        = numel(numSequences);
actualGender    = categorical(ads.Labels);
predictedGender = actualGender;
counter         = 1;
for index = 1:numFiles
    % Get output classes from sequences corresponding to this file:
    predictions = testPred(counter: counter + numSequences(index) - 1);

    % Set predicted gender to the most frequently predicted class
    predictedGender(index) = mode(predictions);

    counter = counter + numSequences(index);
end

Визуализируйте матрицу беспорядка на прогнозах принципа большинства.

figure
cm = confusionchart(actualGender,predictedGender,'title','Testing Accuracy - Majority Rule');
cm.ColumnSummary = 'column-normalized';
cm.RowSummary = 'row-normalized';

Ссылки

[1] https://www.kaggle.com/mozillaorg/common-voice

[2] Введение в аудио анализ: подход MATLAB, Джиэннэкопулос и Пикракис, Academic Press.

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