Признание спикера отвечает на вопрос «Кто говорит?». Распознавание динамика обычно делится на две задачи: идентификация динамика и верификация динамика. При идентификации динамика динамик распознается путем сравнения их речи с закрытым набором шаблонов. При верификации динамика динамик распознается путем сравнения вероятности того, что речь принадлежит конкретному динамику, с заранее заданным порогом. Традиционные методы машинного обучения хорошо выполняют эти задачи в идеальных условиях. Для примеров идентификации динамика с помощью традиционных методов машинного обучения смотрите Идентификацию динамика с использованием тангажа и MFCC и Верификацию динамика с использованием i-векторов. Audio Toolbox™ обеспечивает ivectorSystem
который инкапсулирует возможность обучать i-векторную систему, регистрировать динамики или другие звуковые метки, оценивать систему на предмет порога принятия решений и идентифицировать или проверить динамики или другие аудио метки.
В неблагоприятных условиях было показано, что подход глубокого обучения x-векторов достигает состояния результатов из уровня техники для многих сценариев и приложений [1]. Система x-векторов является эволюцией i-векторов, первоначально разработанных для задачи верификации диктора.
В этом примере вы разрабатываете систему x-векторов. Во-первых, вы обучаете нейронную сеть с задержкой по времени (TDNN), чтобы выполнить идентификацию динамика. Затем вы обучаете традиционные бэкенды для системы верификации динамика на основе x-векторов: LDA-проекционная матрица и PLDA- модели. Затем вы выполняете верификацию динамика, используя TDNN и снижение размерности и оценку бэкэнда. Бэкенд x-векторной системы, или классификатор, аналогичен разработанному для i-векторных систем. Для получения дополнительной информации о бэкэнде смотрите Верификация динамика с использованием i-векторов и ivectorSystem
.
В Diarization динамика Используя x-векторы, вы используете x-векторную систему, обученную в этом примере, чтобы выполнить diarization динамика. Диаризация спикера отвечает на вопрос «Кто когда говорил?».
На протяжении всего этого примера вы найдете живые элементы управления настраиваемыми параметрами. Изменение элементов управления не приводит к повторному запуску примера. Если вы меняете элемент управления, необходимо перезапустить пример.
Этот пример использует базу данных отслеживания тангажа из Технологического университета Граца (PTDB-TUG) [2]. Набор данных состоит из 20 носителей английского языка, читающих 2342 фонетически богатых предложения из корпуса TIMIT. Загрузите и извлеките набор данных. В зависимости от вашей системы, загрузка и извлечение набора данных может занять приблизительно 1,5 часов.
url = 'https://www2.spsc.tugraz.at/databases/PTDB-TUG/SPEECH_DATA_ZIPPED.zip'; downloadFolder = tempdir; datasetFolder = fullfile(downloadFolder,'PTDB-TUG'); if ~exist(datasetFolder,'dir') disp('Downloading PTDB-TUG (3.9 G) ...') unzip(url,datasetFolder) end
Создайте audioDatastore
объект, который указывает на набор данных. Набор данных первоначально предназначался для использования в обучении и оценке отслеживания основного тона и включает показания ларингографика и решения о базовом тангаже. Используйте только оригинальные аудиозаписи.
ads = audioDatastore([fullfile(datasetFolder,"SPEECH DATA","FEMALE","MIC"),fullfile(datasetFolder,"SPEECH DATA","MALE","MIC")], ... 'IncludeSubfolders',true, ... 'FileExtensions','.wav'); fileNames = ads.Files;
Прочтите аудио файла с обучающими данными набора, послушайте его, а затем постройте график.
[audioIn,audioInfo] = read(ads); fs = audioInfo.SampleRate; t = (0:size(audioIn,1)-1)/fs; sound(audioIn,fs) plot(t,audioIn) xlabel('Time (s)') ylabel('Amplitude') axis([0 t(end) -1 1]) title('Sample Utterance from Training Set')
Имена файлов содержат идентификаторы динамиков. Декодируйте имена файлов, чтобы задать метки на audioDatastore
объект.
speakerIDs = extractBetween(fileNames,'mic_','_'); ads.Labels = categorical(speakerIDs);
Разделите audioDatastore
объект в пять наборов:
adsTrain
- Содержит набор обучающих данных для TDNN и backend классификатора.
adsValidation
- Содержит набор валидации для оценки процесса обучения TDNN.
adsTest
- Содержит тестовый набор для оценки эффективности TDNN для идентификации динамика.
adsEnroll
- Содержит набор регистрации для оценки компромисса ошибок обнаружения векторной системы x-vector для верификации динамика.
adsDET
- Содержит оценочный набор, используемый для определения компромисса ошибок обнаружения x-векторной системы для верификации динамика.
developmentLabels = categorical(["M01","M02","M03","M04","M06","M07","M08","M09","F01","F02","F03","F04","F06","F07","F08","F09"]); evaluationLabels = categorical(["M05","M010","F05","F010"]); adsTrain = subset(ads,ismember(ads.Labels,developmentLabels)); [adsTrain,adsValidation,adsTest] = splitEachLabel(adsTrain,0.8,0.1,0.1); adsEvaluate = subset(ads,ismember(ads.Labels,evaluationLabels)); [adsEnroll,adsDET] = splitEachLabel(adsEvaluate,3);
Отображение распределений меток полученной audioDatastore
объекты.
countEachLabel(adsTrain)
ans=16×2 table
Label Count
_____ _____
F01 170
F02 170
F03 170
F04 170
F06 170
F07 170
F08 168
F09 170
M01 170
M02 170
M03 170
M04 170
M06 170
M07 170
M08 170
M09 170
countEachLabel(adsValidation)
ans=16×2 table
Label Count
_____ _____
F01 22
F02 22
F03 22
F04 22
F06 22
F07 22
F08 21
F09 22
M01 22
M02 22
M03 22
M04 22
M06 22
M07 22
M08 22
M09 22
countEachLabel(adsTest)
ans=16×2 table
Label Count
_____ _____
F01 21
F02 21
F03 21
F04 21
F06 21
F07 21
F08 21
F09 21
M01 21
M02 21
M03 21
M04 21
M06 21
M07 21
M08 21
M09 21
countEachLabel(adsEnroll)
ans=2×2 table
Label Count
_____ _____
F05 3
M05 3
countEachLabel(adsDET)
ans=2×2 table
Label Count
_____ _____
F05 231
M05 231
Можно уменьшить количество наборов данных компромисса при обучении и обнаружении ошибок, используемых в этом примере, чтобы ускорить выполнение за счет эффективности. В целом сокращение набора данных является хорошей практикой для разработки и отладки.
speedUpExample = false; if speedUpExample adsTrain = splitEachLabel (adsTrain, 20); adsDET = splitEachLabel (adsDET, 20); end
Создайте audioFeatureExtractor
объект - извлечь 30 MFCC из окон Hann 30 мс с хмелем 10 мс. Частота дискретизации набора данных составляет 48 кГц, но вы будете понижать частоту набора данных до 16 кГц. Проектируйте audioFeatureExtractor
принимая желаемую частоту дискретизации, 16 кГц.
desiredFs = 16e3; windowDuration = 0.03; hopDuration = 0.005; windowSamples = round (windowDuration * designedFs); hopSamples = round (hopDuration * designedFs); overlapSamples = windowSamples - hopSamples; numCoeffs = 30; afe = audioFeatureExtractor (... 'SampleRate', желаемые Fs ,... 'Window', hann (windowSamples,'periodic'), ... 'OverlapLength', overlapSamples ,... ... 'mfcc'Правда, ... 'pitch', ложные ,... 'spectralEntropy', ложные ,... 'spectralFlux', ложный); setExtractorParams (afe,'mfcc','NumCoeffs', numCoeffs)
Понижайте частоту аудиоданных до 16 кГц и извлекайте функции из наборов данных train и валидации. Используйте набор обучающих данных, чтобы определить среднее и стандартное отклонение функций для выполнения стандартизации функций. Вспомогательная функция xVectorPreprocessBatch использует ваш параллельный пул по умолчанию, если у вас есть Parallel Computing Toolbox™.
adsTrain = transform(adsTrain,@(x)resample(x,desiredFs,fs)); [features,YTrain] = xVectorPreprocessBatch(adsTrain,afe); featuresMAT = cat(1,features{:}); numFeatures = size(featuresMAT,2); factors = struct('Mean',mean(featuresMAT,1),'STD',std(featuresMAT,1)); XTrain = cellfun(@(x)(x-factors.Mean)./factors.STD,features,'UniformOutput',false); XTrain = cellfun(@(x)x-mean(x(:)),XTrain,'UniformOutput',false); adsValidation = transform(adsValidation,@(x)resample(x,desiredFs,fs)); [XValidation,YValidation] = xVectorPreprocessBatch(adsTrain,afe,'Factors',factors); classes = unique(YTrain); numClasses = numel(classes);
В этом примере вы реализуете модель извлечения функций [1] с помощью парадигмы функционального программирования, предоставленной Deep Learning Toolbox™. Эта парадигма позволяет полностью контролировать проект вашей модели глубокого обучения. Для руководства, посвященного функциональному программированию в Deep Learning Toolbox, смотрите Define Model Gradients Function for Custom Training Loop (Deep Learning Toolbox). Вспомогательная функция, xvecModel
, помещается в текущую папку, когда вы открываете этот пример. Отображение содержимого xvecModel
функция.
type('xvecModel')
function [Y,state] = xvecModel(X,parameters,state,nvargs) % This function is only for use in this example. It may be changed or % removed in a future release. arguments X parameters state nvargs.DoTraining = false nvargs.OutputLayer = 'final' nvargs.Dropout = 0.2; end % LAYER 1 ----------------------------------------------------------------- Y = dlconv(X,parameters.conv1.Weights,parameters.conv1.Bias,'DilationFactor',1); if nvargs.DoTraining [Y,state.batchnorm1.TrainedMean,state.batchnorm1.TrainedVariance] = ... batchnorm(Y, ... parameters.batchnorm1.Offset, ... parameters.batchnorm1.Scale, ... state.batchnorm1.TrainedMean, ... state.batchnorm1.TrainedVariance); Y(rand(size(Y))<nvargs.Dropout) = 0; else Y = batchnorm(Y, ... parameters.batchnorm1.Offset, ... parameters.batchnorm1.Scale, ... state.batchnorm1.TrainedMean, ... state.batchnorm1.TrainedVariance); end if nvargs.OutputLayer==1 return end Y = relu(Y); % ------------------------------------------------------------------------- % LAYER 2 ----------------------------------------------------------------- Y = dlconv(Y,parameters.conv2.Weights,parameters.conv2.Bias,'DilationFactor',2); if nvargs.DoTraining [Y,state.batchnorm2.TrainedMean,state.batchnorm2.TrainedVariance] = ... batchnorm(Y, ... parameters.batchnorm2.Offset, ... parameters.batchnorm2.Scale, ... state.batchnorm2.TrainedMean, ... state.batchnorm2.TrainedVariance); Y(rand(size(Y))<nvargs.Dropout) = 0; else Y = batchnorm(Y, ... parameters.batchnorm2.Offset, ... parameters.batchnorm2.Scale, ... state.batchnorm2.TrainedMean, ... state.batchnorm2.TrainedVariance); end if nvargs.OutputLayer==2 return end Y = relu(Y); % ------------------------------------------------------------------------- % LAYER 3 ----------------------------------------------------------------- Y = dlconv(Y,parameters.conv3.Weights,parameters.conv3.Bias,'DilationFactor',3); if nvargs.DoTraining [Y,state.batchnorm3.TrainedMean,state.batchnorm3.TrainedVariance] = ... batchnorm(Y, ... parameters.batchnorm3.Offset, ... parameters.batchnorm3.Scale, ... state.batchnorm3.TrainedMean, ... state.batchnorm3.TrainedVariance); Y(rand(size(Y))<nvargs.Dropout) = 0; else Y = batchnorm(Y, ... parameters.batchnorm3.Offset, ... parameters.batchnorm3.Scale, ... state.batchnorm3.TrainedMean, ... state.batchnorm3.TrainedVariance); end if nvargs.OutputLayer==3 return end Y = relu(Y); % ------------------------------------------------------------------------- % LAYER 4 ----------------------------------------------------------------- Y = dlconv(Y,parameters.conv4.Weights,parameters.conv4.Bias,'DilationFactor',1); if nvargs.DoTraining [Y,state.batchnorm4.TrainedMean,state.batchnorm4.TrainedVariance] = ... batchnorm(Y, ... parameters.batchnorm4.Offset, ... parameters.batchnorm4.Scale, ... state.batchnorm4.TrainedMean, ... state.batchnorm4.TrainedVariance); Y(rand(size(Y))<nvargs.Dropout) = 0; else Y = batchnorm(Y, ... parameters.batchnorm4.Offset, ... parameters.batchnorm4.Scale, ... state.batchnorm4.TrainedMean, ... state.batchnorm4.TrainedVariance); end if nvargs.OutputLayer==4 return end Y = relu(Y); % ------------------------------------------------------------------------- % LAYER 5 ----------------------------------------------------------------- Y = dlconv(Y,parameters.conv5.Weights,parameters.conv5.Bias,'DilationFactor',1); if nvargs.DoTraining [Y,state.batchnorm5.TrainedMean,state.batchnorm5.TrainedVariance] = ... batchnorm(Y, ... parameters.batchnorm5.Offset, ... parameters.batchnorm5.Scale, ... state.batchnorm5.TrainedMean, ... state.batchnorm5.TrainedVariance); Y(rand(size(Y))<nvargs.Dropout) = 0; else Y = batchnorm(Y, ... parameters.batchnorm5.Offset, ... parameters.batchnorm5.Scale, ... state.batchnorm5.TrainedMean, ... state.batchnorm5.TrainedVariance); end if nvargs.OutputLayer==5 return end Y = relu(Y); % ------------------------------------------------------------------------- % Layer 6: Statistical pooling -------------------------------------------- if nvargs.DoTraining Y = Y + 0.0001*rand(size(Y)); end Y = cat(2,mean(Y,1),std(Y,[],1)); if nvargs.OutputLayer==6 return end % ------------------------------------------------------------------------- % LAYER 7 ----------------------------------------------------------------- Y = fullyconnect(Y,parameters.fc7.Weights,parameters.fc7.Bias); if nvargs.DoTraining [Y,state.batchnorm7.TrainedMean,state.batchnorm6.TrainedVariance] = ... batchnorm(Y, ... parameters.batchnorm7.Offset, ... parameters.batchnorm7.Scale, ... state.batchnorm7.TrainedMean, ... state.batchnorm7.TrainedVariance); Y(rand(size(Y))<nvargs.Dropout) = 0; else Y = batchnorm(Y, ... parameters.batchnorm7.Offset, ... parameters.batchnorm7.Scale, ... state.batchnorm7.TrainedMean, ... state.batchnorm7.TrainedVariance); end if nvargs.OutputLayer==7 return end Y = relu(Y); % ------------------------------------------------------------------------- % LAYER 8 ----------------------------------------------------------------- Y = fullyconnect(Y,parameters.fc8.Weights,parameters.fc8.Bias); if nvargs.DoTraining [Y,state.batchnorm8.TrainedMean,state.batchnorm8.TrainedVariance] = ... batchnorm(Y, ... parameters.batchnorm8.Offset, ... parameters.batchnorm8.Scale, ... state.batchnorm8.TrainedMean, ... state.batchnorm8.TrainedVariance); Y(rand(size(Y))<nvargs.Dropout) = 0; else Y = batchnorm(Y, ... parameters.batchnorm8.Offset, ... parameters.batchnorm8.Scale, ... state.batchnorm8.TrainedMean, ... state.batchnorm8.TrainedVariance); end if nvargs.OutputLayer==8 return end Y = relu(Y); % ------------------------------------------------------------------------- % LAYER 9 (softmax)-------------------------------------------------------- Y = fullyconnect(Y,parameters.fc9.Weights,parameters.fc9.Bias); if nvargs.OutputLayer==9 return end Y = softmax(Y); % ------------------------------------------------------------------------- end
Инициализируйте структуры, которые содержат параметры и состояние модели TDNN, используя вспомогательную функцию, initializexVecModelLayers. [1] задает количество фильтров между большинством слоев, включая встраиваемый слой, равное 512. Поскольку набор обучающих данных в этом примере маленькая, используйте размер представления 128.
numFilters = 128;
[параметры, состояние] = initializexVecModelLayers (numFeatures, numFilters, numClasses)
parameters = struct with fields:
conv1: [1×1 struct]
batchnorm1: [1×1 struct]
conv2: [1×1 struct]
batchnorm2: [1×1 struct]
conv3: [1×1 struct]
batchnorm3: [1×1 struct]
conv4: [1×1 struct]
batchnorm4: [1×1 struct]
conv5: [1×1 struct]
batchnorm5: [1×1 struct]
fc7: [1×1 struct]
batchnorm7: [1×1 struct]
fc8: [1×1 struct]
batchnorm8: [1×1 struct]
fc9: [1×1 struct]
state = struct with fields:
batchnorm1: [1×1 struct]
batchnorm2: [1×1 struct]
batchnorm3: [1×1 struct]
batchnorm4: [1×1 struct]
batchnorm5: [1×1 struct]
batchnorm7: [1×1 struct]
batchnorm8: [1×1 struct]
Таблица суммирует архитектуру сети, описанную в [1] и реализованную в этом примере. T - общее количество систем координат (функций с течением времени) в аудиосигнале. N - количество классов (дикторов) в набор обучающих данных.
Использование arrayDatastore
и minibatchqueue
(Deep Learning Toolbox), чтобы создать мини-очередь пакетов для обучающих данных.
dsXTrain = arrayDatastore(XTrain,'OutputType','same'); dsYTrain = arrayDatastore(YTrain','OutputType','cell'); dsTrain = combine(dsXTrain,dsYTrain); miniBatchSize = 128; numOutputs = 2; mbq = minibatchqueue (dsTrain, numOutputs,... 'MiniBatchSize', miniBatchSize ,... 'MiniBatchFormat',{'SCB','CB'}, ... 'MiniBatchFcn', @ preprocessMiniBatch);
Установите количество циклов обучения, начальный темп обучения, период падения скорости обучения, коэффициент падения скорости обучения и валидации за эпоху.
numEpochs = 6; learnRate = 0.001; gradDecay = 0,5; sqGradDecay = 0,999; trailingAvg = []; trailingAvgSq = []; LearnRateDropPeriod = 2; LearnRateDropFactor = 0.1; ValidationsPerEpoch = 2; iterationsPerEpoch = этаж (число (XTrain )/miniBatchSize); iterationsPerValidation = round (iterationsPerEpoch/ValidationsPerEpoch);
Если у вас есть доступ к вычислительному графическому процессору, задайте ExecutionEnvironment
на gpu
. В противном случае задайте ExecutionEnvironment
на cpu
.
ExecutionEnvironment = 'gpu';
При выполнении валидации во время обучения предварительно обработайте набор валидации для более высокой эффективности в цикле.
if ValidationsPerEpoch ~= 0 [XValidation,YValidation] = preprocessMiniBatch(XValidation,{YValidation}); XValidation = dlarray(XValidation,'SCB'); if strcmp(ExecutionEnvironment,'gpu') XValidation = gpuArray(XValidation); end end
Чтобы отобразить процесс обучения, инициализируйте вспомогательный объект progressPlotter
. Вспомогательный объект, progressPlotter
, помещается в текущую папку, когда вы открываете этот пример.
Запустите цикл обучения.
pp = progressPlotter(categories(classes)); iteration = 0; for epoch = 1:numEpochs % Shuffle mini-batch queue shuffle(mbq) while hasdata(mbq) % Update iteration counter iteration = iteration + 1; % Get mini-batch from mini-batch queue [dlX,Y] = next(mbq); % Place mini-batch on GPU if requested if strcmp(ExecutionEnvironment,'gpu') dlX = gpuArray(dlX); end % Evaluate the model gradients, state, and loss using dlfeval and the modelGradients function [gradients,state,loss,predictions] = dlfeval(@modelGradients,dlX,Y,parameters,state); % Update the network parameters using the Adam optimizer [parameters,trailingAvg,trailingAvgSq] = adamupdate(parameters,gradients, ... trailingAvg,trailingAvgSq,iteration,learnRate,gradDecay,sqGradDecay,eps('single')); % Update the training progress plot updateTrainingProgress(pp,'Epoch',epoch,'Iteration',iteration,'LearnRate',learnRate,'Predictions',predictions,'Targets',Y,'Loss',loss) % Update the validation plot if ~rem(iteration,iterationsPerValidation) % Pass validation data through x-vector model predictions = xvecModel(XValidation,parameters,state,'DoTraining',false); % Update plot updateValidation(pp,'Iteration',iteration,'Predictions',predictions,'Targets',YValidation) end end % Update learn rate if rem(epoch,LearnRateDropPeriod)==0 learnRate = learnRate*LearnRateDropFactor; end end
Оцените точность распознавания динамика TDNN, используя задержанный тестовый набор. Для каждого файла в тестовом наборе:
Повторно отобразите аудио на 16 кГц
Извлечение функций с помощью xVectorPreprocess
вспомогательная функция. Функции возвращаются в массивах ячеек, где количество элементов в массиве ячеек равно количеству отдельных сегментов речи.
Чтобы получить предсказанную метку динамика, передайте каждый сегмент через модель.
Если в аудиосигнале присутствовало более одного сегмента речи, среднее значение предсказаний.
Использование onehotdecode
(Deep Learning Toolbox), чтобы преобразовать предсказание в метку.
Использование confusionchart
(Deep Learning Toolbox) для оценки производительности системы.
predictedLabels = classes; predictedLabels(:) = []; for sample = 1:numel(adsTest.Files) [audioIn,xInfo] = read(adsTest); audioIn = resample(audioIn,desiredFs,fs); f = xVectorPreprocess(audioIn,afe,'Factors',factors,'MinimumDuration',0); predictions = zeros(numel(classes),numel(f)); for segment = 1:numel(f) dlX = dlarray(f{segment},'SCB'); predictions(:,segment) = extractdata(xvecModel(dlX,parameters,state,'DoTraining',false)); end predictedLabels(sample) = onehotdecode(mean(predictions,2),categories(classes),1); end trueLabels = adsTest.Labels; accuracy = mean(trueLabels==predictedLabels'); figure('Units','normalized','Position',[0.2 0.2 0.6 0.6]); confusionchart(trueLabels,predictedLabels', ... 'ColumnSummary','column-normalized', ... 'RowSummary','row-normalized', ... 'Title',sprintf('x-vector Speaker Recognition\nAccuracy = %0.2f%%',accuracy*100))
В системе x-векторов для верификации динамика TDNN, который вы только что обучили, используется для вывода слоя встраивания. Выходы слоя встраивания (слой 7 в этом примере, после нормализации партии . и перед активацией) являются 'x-векторами' в системе x-векторов.
Бэкэнд (или классификатор) системы x-векторов аналогичен бэкэнду системы i-векторов. Для получения дополнительной информации об алгоритмах смотрите ivectorSystem
и верификация динамика с использованием i-векторов.
Извлеките x-векторы из train. Вспомогательная функция, xvecModel
, имеет опциональную пару "имя-значение" 'OutputLayer'
. Задайте 'OutputLayer'
на 7
для возврата выхода седьмого слоя. В [1] выход из слоя 7 или из слоя 8 предлагается как возможные слои встраивания.
xvecs = zeros(numFilters,numel(YTrain)); for sample = 1:size(YTrain,2) dlX = dlarray(XTrain{sample},'SCB'); embedding = xvecModel(dlX,parameters,state,'DoTraining',false,'OutputLayer',7); xvecs(:,sample) = extractdata(embedding); end
Создайте проекционную матрицу линейного дискриминантного анализа (LDA), чтобы уменьшить размерность x-векторов до 32. LDA пытается минимизировать отклонение внутри внутрикласса и максимизировать отклонение между динамиками.
numEigenvectors = 32;
projMat = helperTrainProjectionMatrix (xvecs, YTrain, numEigenvectors);
Примените матрицу проекции LDA к x-векторам.
xvecs = projMat*xvecs;
Обучите модель G-PLDA для выполнения оценки.
numIterations = 3; numDimensions = 32; plda = helperTrainPLDA (xvecs, YTrain, numIterations, numDimensions);
Системы верификации динамиков проверяют, что динамик является тем, кем они считаются. Перед проверкой докладчика они должны быть зачислены в систему. Регистрация в системе означает, что система имеет шаблон x-векторного представления динамика.
Извлеките x-векторы из удерживаемого набора данных, adsEnroll
. Установите минимальную длительность аудиосегмента в эквивалент 15 переходов функций (минимальное число, необходимое для вычисления векторов x).
minDur = (numel(afe.Window)+14*(numel(afe.Window)-afe.OverlapLength)+1)/desiredFs; xvecs = zeros(numEigenvectors,numel(adsEnroll.Files)); reset(adsEnroll) for sample = 1:numel(adsEnroll.Files) [audioIn,xInfo] = read(adsEnroll); audioIn = resample(audioIn,desiredFs,fs); f = xVectorPreprocess(audioIn,afe,'Factors',factors,'MinimumDuration',minDur); embeddings = zeros(numFilters,numel(f)); for segment = 1:numel(f) dlX = dlarray(f{segment},'SCB'); embeddings(:,segment) = extractdata(xvecModel(dlX,parameters,state,'DoTraining',false,'OutputLayer',7)); end xvecs(:,sample) = mean(projMat*embeddings,2); end
Создайте шаблоны x-векторов для каждого динамика путем усреднения x-векторов отдельных динамиков по файлам регистрации.
labels = adsEnroll.Labels; uniqueLabels = unique(labels); atable = cell2table(cell(0,2),'VariableNames',{'xvector','NumSamples'}); for ii = 1:numel(uniqueLabels) idx = uniqueLabels(ii)==labels; wLocalMean = mean(xvecs(:,idx),2); localTable = table({wLocalMean},(sum(idx)), ... 'VariableNames',{'xvector','NumSamples'}, ... 'RowNames',string(uniqueLabels(ii))); atable = [atable;localTable]; %#ok<AGROW> end enrolledLabels = atable
enrolledLabels=2×2 table
xvector NumSamples
_____________ __________
F05 {32×1 double} 3
M05 {32×1 double} 3
Системы верификации спикера требуют, чтобы вы установили порог, который балансирует вероятность ложного принятия (FA) и вероятность ложного отклонения (FR), согласно требованиям вашего приложения. Чтобы определить порог, соответствующее вашим требованиям FA/FR, оцените компромисс ошибок обнаружения системы.
xvecs = zeros(numEigenvectors,numel(adsDET.Files)); reset(adsDET) for sample = 1:numel(adsDET.Files) [audioIn,xInfo] = read(adsDET); audioIn = resample(audioIn,desiredFs,fs); f = xVectorPreprocess(audioIn,afe,'Factors',factors,'MinimumDuration',minDur); embeddings = zeros(numFilters,numel(f)); for segment = 1:numel(f) dlX = dlarray(f{segment},'SCB'); embeddings(:,segment) = extractdata(xvecModel(dlX,parameters,state,'DoTraining',false,'OutputLayer',7)); end xvecs(:,sample) = mean(projMat*embeddings,2); end labels = adsDET.Labels; [detTable,scoreRange] = helperDetectionErrorTradeoff(xvecs,labels,enrolledLabels,plda);
Постройте график результатов оценки компромисса ошибок обнаружения как для оценки PLDA, так и для оценки косинусоидальности (CSS).
plot(detTable.PLDA.Threshold,detTable.PLDA.FAR, ... detTable.PLDA.Threshold,detTable.PLDA.FRR) eer = helperEqualErrorRate(detTable.PLDA); title(sprintf('Speaker Verification\nDetection Error Tradeoff\nPLDA Scoring\nEqual Error Rate = %0.2f',eer)); xlabel('Threshold') ylabel('Error Rate') legend({'FAR','FRR'})
plot(detTable.CSS.Threshold,detTable.CSS.FAR, ... detTable.CSS.Threshold,detTable.CSS.FRR) eer = helperEqualErrorRate(detTable.CSS); title(sprintf('Speaker Verification\nDetection Error Tradeoff\nCosine Similarity Scoring\nEqual Error Rate = %0.2f',eer)); xlabel('Threshold') ylabel('Error Rate') legend({'FAR','FRR'})
[1] Snyder, David, et al. «x-vectors: Robust DNN Embeddings for Speaker Recognition». 2018 IEEE International Conference on Acoustics, Speech and Signal Processing (ICASSP), IEEE, 2018, pp. 5329-33. DOI.org (Crossref), doi:10.1109/ICASSP.2018.8461375.
[2] Лаборатория обработки сигналов и речевой связи. Доступ к 12 декабря 2019 года. https://www.spsc.tugraz.at/databases-and-tools/ptdb-tug-pitch-tracking-database-from-graz-university-of-technology.html.
function [parameters,state] = initializexVecModelLayers(numFeatures,numFilters,numClasses) % This function is only for use in this example. It may be changed or % removed in a future release. % Initialize Layer 1 (1-D Convolutional) filterSize1 = 5; numChannels1 = numFeatures; numFilters1 = numFilters; numIn1 = filterSize1*numFilters1; numOut1 = filterSize1*numFilters1; parameters.conv1.Weights = initializeGlorot([filterSize1,numChannels1,numFilters1],numOut1,numIn1); parameters.conv1.Bias = dlarray(zeros([numFilters1,1],'single')); parameters.batchnorm1.Offset = dlarray(zeros([numFilters1,1],'single')); parameters.batchnorm1.Scale = dlarray(ones([numFilters1,1],'single')); state.batchnorm1.TrainedMean = zeros(numFilters1,1,'single'); state.batchnorm1.TrainedVariance = ones(numFilters1,1,'single'); % Initialize Layer 2 (1-D Convolutional) filterSize2 = 3; numChannels2 = numFilters1; numFilters2 = numFilters; numIn2 = filterSize2*numFilters2; numOut2 = filterSize2*numFilters2; parameters.conv2.Weights = initializeGlorot([filterSize2,numChannels2,numFilters2],numOut2,numIn2); parameters.conv2.Bias = dlarray(zeros([numFilters2,1],'single')); parameters.batchnorm2.Offset = dlarray(zeros([numFilters2,1],'single')); parameters.batchnorm2.Scale = dlarray(ones([numFilters2,1],'single')); state.batchnorm2.TrainedMean = zeros(numFilters2,1,'single'); state.batchnorm2.TrainedVariance = ones(numFilters2,1,'single'); % Initialize Layer 3 (1-D Convolutional) filterSize3 = 3; numChannels3 = numFilters2; numFilters3 = numFilters; numIn3 = filterSize3*numFilters3; numOut3 = filterSize3*numFilters3; parameters.conv3.Weights = initializeGlorot([filterSize3,numChannels3,numFilters3],numOut3,numIn3); parameters.conv3.Bias = dlarray(zeros([numFilters3,1],'single')); parameters.batchnorm3.Offset = dlarray(zeros([numFilters3,1],'single')); parameters.batchnorm3.Scale = dlarray(ones([numFilters3,1],'single')); state.batchnorm3.TrainedMean = zeros(numFilters3,1,'single'); state.batchnorm3.TrainedVariance = ones(numFilters3,1,'single'); % Initialize Layer 4 (1-D Convolutional) filterSize4 = 1; numChannels4 = numFilters3; numFilters4 = numFilters; numIn4 = filterSize4*numFilters4; numOut4 = filterSize4*numFilters4; parameters.conv4.Weights = initializeGlorot([filterSize4,numChannels4,numFilters4],numOut4,numIn4); parameters.conv4.Bias = dlarray(zeros([numFilters4,1],'single')); parameters.batchnorm4.Offset = dlarray(zeros([numFilters4,1],'single')); parameters.batchnorm4.Scale = dlarray(ones([numFilters4,1],'single')); state.batchnorm4.TrainedMean = zeros(numFilters4,1,'single'); state.batchnorm4.TrainedVariance = ones(numFilters4,1,'single'); % Initialize Layer 5 (1-D Convolutional) filterSize5 = 1; numChannels5 = numFilters4; numFilters5 = 1500; numOut5 = filterSize5*numFilters5; numIn5 = filterSize5*numFilters5; parameters.conv5.Weights = initializeGlorot([filterSize5,numChannels5,numFilters5],numOut5,numIn5); parameters.conv5.Bias = dlarray(zeros([numFilters5,1],'single')); parameters.batchnorm5.Offset = dlarray(zeros([numFilters5,1],'single')); parameters.batchnorm5.Scale = dlarray(ones([numFilters5,1],'single')); state.batchnorm5.TrainedMean = zeros(numFilters5,1,'single'); state.batchnorm5.TrainedVariance = ones(numFilters5,1,'single'); % Initialize Layer 6 (Statistical Pooling) numIn6 = numOut5; numOut6 = 2*numIn6; % Initialize Layer 7 (Fully Connected) numIn7 = numOut6; numOut7 = numFilters; parameters.fc7.Weights = initializeGlorot([numFilters,numIn7],numOut7,numIn7); parameters.fc7.Bias = dlarray(zeros([numOut7,1],'single')); parameters.batchnorm7.Offset = dlarray(zeros([numOut7,1],'single')); parameters.batchnorm7.Scale = dlarray(ones([numOut7,1],'single')); state.batchnorm7.TrainedMean = zeros(numOut7,1,'single'); state.batchnorm7.TrainedVariance = ones(numOut7,1,'single'); % Initialize Layer 8 (Fully Connected) numIn8 = numOut7; numOut8 = numFilters; parameters.fc8.Weights = initializeGlorot([numOut8,numIn8],numOut8,numIn8); parameters.fc8.Bias = dlarray(zeros([numOut8,1],'single')); parameters.batchnorm8.Offset = dlarray(zeros([numOut8,1],'single')); parameters.batchnorm8.Scale = dlarray(ones([numOut8,1],'single')); state.batchnorm8.TrainedMean = zeros(numOut8,1,'single'); state.batchnorm8.TrainedVariance = ones(numOut8,1,'single'); % Initialize Layer 9 (Fully Connected) numIn9 = numOut8; numOut9 = numClasses; parameters.fc9.Weights = initializeGlorot([numOut9,numIn9],numOut9,numIn9); parameters.fc9.Bias = dlarray(zeros([numOut9,1],'single')); end
function weights = initializeGlorot(sz,numOut,numIn) % This function is only for use in this example. It may be changed or % removed in a future release. Z = 2*rand(sz,'single') - 1; bound = sqrt(6 / (numIn + numOut)); weights = bound*Z; weights = dlarray(weights); end
function [gradients,state,loss,Y] = modelGradients(X,target,parameters,state) % This function is only for use in this example. It may be changed or % removed in a future release. [Y,state] = xvecModel(X,parameters,state,'DoTraining',true); loss = crossentropy(Y,target); gradients = dlgradient(loss,parameters); end
function [sequences,labels] = preprocessMiniBatch(sequences,labels) % This function is only for use in this example. It may be changed or % removed in a future release. lengths = cellfun(@(x)size(x,1),sequences); minLength = min(lengths); sequences = cellfun(@(x)randomTruncate(x,1,minLength),sequences,'UniformOutput',false); sequences = cat(3,sequences{:}); labels = cat(2,labels{:}); labels = onehotencode(labels,1); labels(isnan(labels)) = 0; end
function y = randomTruncate(x,dim,minLength) % This function is only for use in this example. It may be changed or % removed in a future release. N = size(x,dim); if N > minLength start = randperm(N-minLength,1); if dim==1 y = x(start:start+minLength-1,:); elseif dim ==2 y = x(:,start:start+minLength-1); end else y = x; end end
function [features,labels] = xVectorPreprocessBatch(ads,afe,nvargs) % This function is only for use in this example. It may be changed or % removed in a future release. arguments ads afe nvargs.Factors = [] nvargs.Segment = true; end if ~isempty(ver('parallel')) pool = gcp; numpar = numpartitions(ads,pool); else numpar = 1; end labels = []; features = []; parfor ii = 1:numpar adsPart = partition(ads,numpar,ii); numFiles = numel(adsPart.UnderlyingDatastores{1}.Files); localFeatures = cell(numFiles,1); localLabels = []; for jj = 1:numFiles [audioIn,xInfo] = read(adsPart); label = xInfo.Label; [f,ns] = xVectorPreprocess(audioIn,afe,'Factors',nvargs.Factors,'Segment',nvargs.Segment); %#ok<PFBNS> localFeatures{jj} = f; localLabels = [localLabels,repelem(label,ns)]; end features = [features;localFeatures]; labels = [labels,localLabels]; end features = cat(1,features{:}); labels = removecats(labels); end
function [features,numSegments] = xVectorPreprocess(audioData,afe,nvargs) % This function is only for use in this example. It may be changed or % removed in a future release. arguments audioData afe nvargs.Factors = [] nvargs.Segment = true; nvargs.MinimumDuration = 1; end % Scale audioData = audioData/max(abs(audioData(:))); % Protect against NaNs audioData(isnan(audioData)) = 0; % Determine regions of speech mergeDur = 0.5; % seconds idx = detectSpeech(audioData,afe.SampleRate,'MergeDistance',afe.SampleRate*mergeDur); % If a region is less than MinimumDuration seconds, drop it. if nvargs.Segment idxToRemove = (idx(:,2)-idx(:,1))<afe.SampleRate*nvargs.MinimumDuration; idx(idxToRemove,:) = []; end % Extract features numSegments = size(idx,1); features = cell(numSegments,1); for ii = 1:numSegments features{ii} = single(extract(afe,audioData(idx(ii,1):idx(ii,2)))); end % Standardize features if ~isempty(nvargs.Factors) features = cellfun(@(x)(x-nvargs.Factors.Mean)./nvargs.Factors.STD,features,'UniformOutput',false); end % Cepstral mean subtraction (for channel noise) if ~isempty(nvargs.Factors) fileMean = mean(cat(1,features{:}),'all'); features = cellfun(@(x)x - fileMean,features,'UniformOutput',false); end if ~nvargs.Segment features = cat(1,features{:}); end end