Признание спикера отвечает на вопрос «Кто говорит?». Распознавание говорящих обычно делится на две задачи: идентификация говорящих и верификация говорящих. При идентификации говорящего распознается говорящий путем сравнения его речи с закрытым набором шаблонов. При проверке говорящего распознается говорящий путем сравнения вероятности того, что речь принадлежит конкретному говорящему, с заранее определенным порогом. Традиционные методы машинного обучения хорошо выполняют эти задачи в идеальных условиях. Примеры идентификации говорящих с использованием традиционных методов машинного обучения см. в разделах Идентификация говорящих с использованием основного тона и Проверка говорящих с использованием i-векторов. Аудио Toolbox™ обеспечивает ivectorSystem который включает в себя способность обучать i-векторную систему, регистрировать динамики или другие звуковые метки, оценивать систему для порога принятия решения и идентифицировать или проверять динамики или другие звуковые метки.
В неблагоприятных условиях было показано, что подход глубокого обучения х-векторов позволяет получить самые современные результаты для многих сценариев и применений [1]. X-векторная система - это эволюция i-векторов, первоначально разработанная для задачи проверки говорящего.
В этом примере разрабатывается система x-векторов. Во-первых, вы обучаете нейронную сеть с временной задержкой (TDNN) выполнять идентификацию динамика. Затем вы тренируете традиционные бэкенды для системы верификации динамиков на основе x-вектора: матрицу проекции LDA и модель PLDA. Затем выполняется проверка динамика с использованием TDNN и уменьшения размерности и оценки бэкэнда. Бэкенд x-векторной системы, или классификатор, является тем же, что разработан для i-векторных систем. Дополнительные сведения о бэкэнд-системе см. в разделе Проверка динамики с использованием i-векторов и ivectorSystem.
В разделе Диаризация динамика с помощью x-векторов используется система x-векторов, обученная в этом примере, для выполнения диаризации динамика. Диаризация спикера отвечает на вопрос «Кто говорил, когда?».
В этом примере можно найти динамические элементы управления настраиваемыми параметрами. Изменение элементов управления не приводит к повторному запуску примера. При изменении элемента управления необходимо повторно запустить пример.
В этом примере используется база данных отслеживания основного тона Грацского технологического университета (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 и внутреннего классификатора.
adsValidation - Содержит набор проверки для оценки хода обучения TDNN.
adsTest - Содержит тестовый набор для оценки производительности TDNN для идентификации громкоговорителя.
adsEnroll - содержит набор регистрации для оценки компромисса ошибок обнаружения x-векторной системы для проверки говорящего.
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 из 30 мс окон Hann с 10 мс перехода. Частота дискретизации набора данных составляет 48 кГц, но вы понизите выборку набора данных до 16 кГц. Проектирование audioFeatureExtractor предполагая желаемую частоту дискретизации, 16 кГц.
desiredFs = 16e3; windowDuration =0.03; hopDuration =
0.005; windowSamples = round(windowDuration*desiredFs); hopSamples = round(hopDuration*desiredFs); overlapSamples = windowSamples - hopSamples; numCoeffs =
30; afe = audioFeatureExtractor( ... 'SampleRate',desiredFs, ... 'Window',hann(windowSamples,'periodic'), ... 'OverlapLength',overlapSamples, ... ... 'mfcc',true, ... 'pitch',false, ... 'spectralEntropy',false, ... 'spectralFlux',false); setExtractorParams(afe,'mfcc','NumCoeffs',numCoeffs)
Выполните пониженную выборку аудиоданных до 16 кГц и извлеките характеристики из наборов данных поезда и проверки. Набор учебных данных используется для определения среднего и стандартного отклонения элементов для выполнения стандартизации элементов. Вспомогательная функция xVectorPreprocessBatch использует параллельный пул по умолчанию при наличии Toolbox™ Parallel Computing.
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);В этом примере модель извлечения x-векторной функции [1] реализуется с использованием парадигмы функционального программирования, предоставляемой 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;
[parameters,state] = 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 = floor(numel(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-vector для верификации динамика только что обученный TDNN используется для вывода уровня встраивания. Выходные данные слоя внедрения (слой 7 в этом примере, после пакетной нормализации и перед активацией) являются «x-векторами» в системе x-векторов.

Бэкэнд (или классификатор) x-векторной системы совпадает с бэкендом i-векторной системы. Для получения подробной информации о алгоритмах см. ivectorSystem и верификация динамика с использованием i-векторов.
Извлеките векторы X из комплекта поездов. Вспомогательная функция, 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), в соответствии с требованиями вашей заявки. Для определения порогового значения, соответствующего требованиям ОС/ФР, проанализируйте компромисс ошибок обнаружения в системе.
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] Снайдер, Дэвид, и др. IEEE 2018 Международная конференция по акустике, обработке речи и сигналов (ICASSP), IEEE, 2018, стр. 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