Этот пример показывает, как классифицировать пол докладчика, использующего глубокое обучение. В частности, пример использует сеть Bidirectional Long Short-Term Memory (BiLSTM) и Коэффициенты Gammatone Cepstral (gtcc), подачу, гармоническое отношение и несколько спектральных дескрипторов формы.
Классификация полов на основе речевых сигналов является важной составляющей многих аудиосистем, таких как автоматическое распознавание речи, распознавание динамика и мультимедийная индексация на основе содержимого.
Этот пример использует сети долгой краткосрочной памяти (LSTM), тип рекуррентной нейронной сети (RNN), подходящей, чтобы изучить данные timeseries и последовательность. Сеть LSTM может изучить долгосрочные зависимости между временными шагами последовательности. Слой LSTM (lstmLayer
) может посмотреть в то время последовательность в прямом направлении, в то время как двунаправленный слой LSTM (bilstmLayer
) может посмотреть в то время последовательность и во вперед и в обратные направления. Этот пример использует двунаправленный слой LSTM.
Этот пример обучает сеть LSTM с последовательностями Коэффициентов Кепстра Gammatone (gtcc), оценок подачи, гармонического отношения и нескольких спектральных дескрипторов формы.
Пример проходит следующие шаги:
Создайте audioDatastore
, который указывает на аудио речевые файлы, используемые, чтобы обучить сеть LSTM.
Удалите тишину и неречевые сегменты из речевых файлов с помощью простого метода пороговой обработки.
Извлеките последовательности функции, состоящие из коэффициентов GTCC, подачи, гармонического отношения и нескольких спектральных дескрипторов формы от речевых сигналов.
Обучите сеть LSTM с помощью последовательностей функции.
Измерьте и визуализируйте точность классификатора на данных тренировки.
Создайте audioDatastore
речевых файлов, используемых, чтобы протестировать обучивший сеть.
Удалите неречевые сегменты из этих файлов, сгенерируйте последовательности функции, передайте их через сеть и протестируйте ее точность путем сравнения предсказанного и фактического пола докладчиков.
Чтобы ускорить учебный процесс, запустите этот пример на машине с графическим процессором. Если ваша машина имеет графический процессор и 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, оценки подачи, гармоническое отношение и несколько спектральных дескрипторов формы:
gtcc
- 13 GTCC, 13 дельт GTCC, 13 дельт дельты GTCC
pitch
- 1 оценка подачи
harmonicRatio
- 1 гармоническое отношение
spectralSlope
- 1 спектральный наклон
spectralSkewness
- 1 скошенность
spectralFlux
- 1 поток
spectralCentroid
- 1 центроид
spectralRolloffPoint
1 - точка спада
spectralDecrease
- спектральное уменьшение
spectralFlatness
- 1 спектральная плоскость
spectralKurtosis
- 1 спектральный эксцесс
Для каждого речевого сегмента характеристические векторы конкатенированы в последовательности с 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 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 с заданными опциями обучения и архитектурой слоя с помощью 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.
lstmLayer
| trainNetwork
| trainingOptions