Система i-вектора выводит необработанный счет, характерный для данных, и параметры раньше разрабатывали систему. Это делает интерпретацию счета и нахождение сопоставимого порога решения для задач верификации трудными.
Чтобы обратиться к этим трудностям, исследователи разработали нормализацию счета и калибровочные методы счета.
В нормализации счета необработанные баллы нормированы относительно 'когорты самозванца'. Выиграйте нормализация происходит прежде, чем оценить ошибочный компромисс обнаружения и может улучшить точность системы и ее способности адаптироваться к новым данным.
В калибровке счета необработанные баллы сопоставлены с вероятностями, которые используются, чтобы лучше изучить доверие системы к решениям.
В этом примере вы применяете нормализацию счета к системе i-вектора. Чтобы узнать о калибровке счета, смотрите Калибровку Счета i-вектора.
Например, цели, вы используете выигрыш подобия косинуса (CSS) в этом примере. Выигрыш вероятностного линейного дискриминантного анализа (PLDA) также улучшен нормализацией, несмотря на то, что менее существенно.
Чтобы загрузить предварительно обученную систему i-вектора, подходящую для распознавания динамика, вызовите speakerRecognition
. ivectorSystem
возвращенный был обучен на наборе данных LibriSpeech, который состоит из англоязычных записей на 16 кГц.
ivs = speakerRecognition();
Предварительно обученная система i-вектора достигает равного коэффициента ошибок (EER) использование на приблизительно 6,73% CSS на наборе тестов LibriSpeech. EER достиг использования, PLDA значительно лучше. Однако, потому что CSS более прост, в целях этого примера, вы исследуете CSS только.
detectionErrorTradeoff(ivs)
Коэффициент ошибок набора тестов LibriSpeech и сопроводительный порог решения по умолчанию для верификации динамика, не расширяют хорошо к невидимым данным. Чтобы подтвердить это, загрузите набор данных PTDB-TUG [3]. Функция поддержки, loadDataset
, загружает набор данных и затем передискретизирует его от 48 кГц до 16 кГц, который является частотой дискретизации, на которой была обучена система i-вектора. loadDataset
функция возвращает четыре audioDatastore
объекты:
adsEnroll
- Содержит файлы, чтобы зарегистрировать докладчиков в систему i-вектора.
adsTest
- Содержит файлы к эффективности выборочной проверки системы i-вектора.
adsDET
- Содержит большой набор файлов, чтобы анализировать ошибочный компромисс обнаружения системы i-вектора.
adsImposter - Содержит набор динамиков, не включенных в другие хранилища данных. Этот набор используется для нормализации счета.
targetSampleRate = ivs.SampleRate; [adsEnroll,adsTest,adsDET,adsImposter] = loadDataset(targetSampleRate);
Зарегистрируйте докладчиков от набора данных приема. Когда вы enroll
динамики, шаблон i-вектора создается для каждой уникальной марки докладчика.
enroll(ivs,adsEnroll,adsEnroll.Labels)
Extracting i-vectors ...done. Enrolling i-vectors ...................done. Enrollment complete.
enrolledLabels = categorical(ivs.EnrolledLabels.Properties.RowNames);
Выборочная проверка ложный уровень отклонения (FRR) и ложная пропускная способность (FAR) с помощью verify
объектная функция. verify
возразите функциональным баллам i-вектор, выведенный из аудиовхода против шаблона i-вектора, соответствующего заданной метке. Функция затем сравнивает счет с порогом решения и или принимает или отклоняет суждение, что аудиовход принадлежит заданной марке докладчика. Порог решения по умолчанию соответствует равному коэффициенту ошибок (EER), определил в прошлый раз, когда ошибочный компромисс обнаружения был оценен.
FA = 0; FR = 0; reset(adsTest) numToSpotCheck = 50; for ii = 1:numToSpotCheck [audioIn,fileInfo] = read(adsTest); targetLabel = fileInfo.Label; FR = FR + ~verify(ivs,audioIn,targetLabel,"css"); nontargetIdx = find(~ismember(enrolledLabels,targetLabel)); nontargetLabel = enrolledLabels(nontargetIdx(randperm(numel(nontargetIdx),1))); FA = FA + verify(ivs,audioIn,nontargetLabel,"css"); end FRR = FR./numToSpotCheck; FAR = FA./numToSpotCheck; fprintf('False Rejection Rate = %0.2f (%%)\nFalse Acceptance Rate = %0.2f (%%)\n',100*FRR,100*FAR)
False Rejection Rate = 0.00 (%) False Acceptance Rate = 44.00 (%)
Эффективность на этом новом наборе данных не совпадает с эффективностью, о которой сообщают когда обучение и оценка системы i-вектора на наборе данных LibriSpeech. Кроме того, порог решения по умолчанию на наборе данных LibriSpeech не соответствует равному коэффициенту ошибок набора данных PTDB-TUG.
Лучше оценить эффективность системы и выбрать новый порог решения, detectionErrorTradeoff
вызова снова. На этот раз вызовите
detectionErrorTradeoff
с новыми данными об оценке, которые больше подходят для целевого приложения. Данные об оценке должны быть максимально близки к данным, с которыми ваша развернутая система сталкивается в терминах словаря, просодии, длительности сигнала, уровня шума, шумового типа, диакритических знаков, характеристик канала, и так далее.
detectionErrorTradeoff(ivs,adsDET,adsDET.Labels,'Scorer',"css")
Extracting i-vectors ...done. Scoring i-vector pairs ...done. Detection error tradeoff evaluation complete.
Выборочная проверка FAR и FRR обновленной системы. FAR и FRR теперь обоснованно близко к EER, о котором сообщают в ошибочном сравнительном анализе обнаружения. Обратите внимание на то, что вызов detectionErrorTradeoff
не изменяет экстракцию i-вектора или выигрыш, только порог решения по умолчанию для верификации динамика. В следующих разделах вы улучшаете систему i-вектора, чтобы выполнить нормализацию счета. Выиграйте нормализация помогает системе i-вектора расширить к новым наборам данных без потребности переоценить ошибочный компромисс обнаружения. Выиграйте нормализация также помогает устранить разрыв эффективности между обучением система и развертыванием его.
FA = 0; FR = 0; reset(adsTest) for ii = 1:numToSpotCheck [audioIn,fileInfo] = read(adsTest); trueLabel = fileInfo.Label; FR = FR + ~verify(ivs,audioIn,trueLabel,"css"); imposterIdx = find(~ismember(enrolledLabels,trueLabel)); imposter = enrolledLabels(imposterIdx(randperm(numel(imposterIdx),1))); FA = FA + verify(ivs,audioIn,imposter,"css"); end FRR = FR./numToSpotCheck; FAR = FA./numToSpotCheck; fprintf('False Rejection Rate = %0.2f (%%)\nFalse Acceptance Rate = %0.2f (%%)\n',100*FRR,100*FAR)
False Rejection Rate = 6.00 (%) False Acceptance Rate = 4.00 (%)
Выиграйте нормализация является общим подходом, чтобы сделать целевые и нецелевые распределения счета через динамики более подобными. Это позволяет системе установить порог решения, который ближе к оптимальному для большего количества динамиков. В этом примере вы исследуете адаптивный симметричный вариант нормализации 1 (S-norm1) [1].
Чтобы мотивировать нормализацию счета, сначала смотрите целевые и нецелевые распределения счета для двух зарегистрированных меток против той же тестовой когорты.
Изолируйте два i-вектора шаблона, соответствующие двум динамикам.
enrolledIvecs = cat(2,ivs.EnrolledLabels.ivector{1},ivs.EnrolledLabels.ivector{9}); label_e = categorical([ivs.EnrolledLabels.Properties.RowNames(1),ivs.EnrolledLabels.Properties.RowNames(9)]);
Извлеките i-векторы из набора тестов. Набор тестов помечает перекрытие зарегистрированными метками.
testIvecs = ivector(ivs,adsTest); label_t = adsTest.Labels;
Создайте векторы индексации, чтобы отслеживать, из которых тестируют i-векторы, соответствуют, который зарегистрировал метку. В targets
матрица, столбцы соответствуют зарегистрированным докладчикам, и строки соответствуют тестовым файлам. Если тестовая метка соответствует зарегистрированной метке, значением в матрице является true
, в противном случае значением является false
.
targets = [ismember(label_t,label_e(1)),ismember(label_t,label_e(2))];
Выиграйте i-векторы шаблона против целевых и нецелевых i-векторов. Функция поддержки, scoreTargets
, баллы все комбинации зарегистрированных i-векторов против тестовых i-векторов и возвращают баллы, разделенные на целевые баллы (когда тест и регистрируется, метки являются тем же самым), и не предназначайтесь для баллов (когда тест и регистрируется, метки отличаются).
[targetScores,nontargetScores] = scoreTargets(enrolledIvecs,testIvecs,targets);
Используйте функцию поддержки, plotScoreDistributions
, отобразить целевую и нецелевую музыку к каждому из зарегистрированных докладчиков. Обратите внимание на то, что равный коэффициент ошибок (где целевой и нецелевой крест распределений) отличается для этих двух динамиков. Таким образом, принятие равного коэффициента ошибок является целью системы, один порог решения не может получить равный коэффициент ошибок для обоих динамиков.
plotScoreDistributions(targetScores,nontargetScores,'Analyze','label')
Анализируйте распределения счета с помощью графика EER. Графики EER показывают отношение между порогом решения и вероятностью ложного сигнального или ложного отклонения и часто анализируются, чтобы определить порог решения.
plotEER(targetScores,nontargetScores,'Analyze','label')
В этом примере вы используете адаптивный симметричный вариант нормализации 1 (S-norm1) [1]. S-norm1 вычисляет в среднем нормированные баллы из Z-нормы (нулевая нормализация счета) и T-нормы (нормализация экзаменационной отметки).
где
необработанный счет на основе приема и тест i-векторы.
набор выигрывающей верхнюю часть когорты самозванца с зарегистрированным i-вектором, .
набор выигрывающей верхнюю часть когорты самозванца с тестовым i-вектором, .
, набор баллов когорты, сформированных путем выигрыша произнесения приема с главными файлами от когорты самозванца .
, набор главных баллов между зарегистрированным i-вектором и i-векторами самозванца.
, набор главных баллов между тестовым i-вектором и i-векторами самозванца.
и среднее и стандартное отклонение .
Чтобы начаться, извлеките i-векторы из когорты самозванца ().
imposterIvecs = ivector(ivs,adsImposter);
Выиграйте зарегистрированные i-векторы против когорты самозванца () и затем изолируйте только K лучшие баллы (). [1] предлагает использовать главные 200-500 файлов выигрыша, чтобы создать зависящую от диктора когорту. Наконец, вычислите среднее значение () и стандартное отклонение ().
topK = 400; imposterScores = вид (cosineSimilarityScore (enrolledIvecs, imposterIvecs),'descend'); imposterScores = imposterScores (1:min (topK, размер (imposterScores, 1)), :); mu_e = среднее значение (imposterScores, 1); std_e = станд. (imposterScores, [], 1);
Вычислить и как выше.
imposterScores = sort(cosineSimilarityScore(testIvecs,imposterIvecs),'descend');
imposterScores = imposterScores(1:min(topK,size(imposterScores,1)),:);
mu_t = mean(imposterScores,1);
std_t = std(imposterScores,[],1);
Выиграйте тест и i-векторы приема снова, на этот раз задав необходимые коэффициенты нормализации, чтобы выполнить адаптивный s-norm1. Функция поддержки, scoreTargets
, применяет нормализацию на необработанные баллы.
normFactorsSe = struct('mu',mu_e,'std',std_e); normFactorsSt = struct('mu',mu_t,'std',std_t); [targetScores,nontargetScores] = scoreTargets(enrolledIvecs,testIvecs,targets, ... 'NormFactorsSe',normFactorsSe,'NormFactorsSt',normFactorsSt);
Постройте распределения счета баллов после применения адаптивного s-norm1.
plotScoreDistributions(targetScores,nontargetScores,'Analyze','label')
Анализируйте равные графики коэффициента ошибок после применения адаптивного s-norm1. Пороги, соответствующие равным коэффициентам ошибок для этих двух динамиков, теперь ближе вместе.
plotEER(targetScores,nontargetScores,'Analyze','label')
Извлеките i-векторы из набора DET.
testIvecs = ivector(ivs,adsDET);
Поместите все зарегистрированные i-векторы в матрицу.
enrolledIvecs = cat(2,ivs.EnrolledLabels.ivector{:});
Вычислите статистику нормализации для каждого зарегистрированного и протестируйте i-вектор. Функция поддержки, getNormFactors, выполняет те же операции, как в Анализируют Нормализацию Счета на Двух Динамиках.
topK = 100; normFactorsSe = getNormFactors (enrolledIvecs, imposterIvecs,'TopK', topK); normFactorsSt = getNormFactors (testIvecs, imposterIvecs,'TopK', topK);
Создайте целевую матрицу указание, какие пары i-вектора имеют соответствующие метки.
targets = true(numel(adsDET.Labels),height(ivs.EnrolledLabels)); for ii = 1:height(ivs.EnrolledLabels) targets(:,ii) = ismember(adsDET.Labels,ivs.EnrolledLabels.Properties.RowNames(ii)); end
Выиграйте каждый i-вектор приема против каждого тестового i-вектора.
[targetScores,nontargetScores] = scoreTargets(enrolledIvecs,testIvecs,targets, ... 'NormFactorsSe',normFactorsSe,'NormFactorsSt',normFactorsSt);
Постройте целевые и нецелевые распределения счета для группы.
plotScoreDistributions(targetScores,nontargetScores,'Analyze','group')
Постройте равный коэффициент ошибок этой новой системы. Равный коэффициент ошибок после применения адаптивного s-norm1 составляет приблизительно 5,49%. Равный коэффициент ошибок до адаптивного s-norm1 составляет приблизительно 8,4%.
plotEER(targetScores,nontargetScores,'Analyze','group')
function [adsEnroll,adsTest,adsDET,adsImposter] = loadDataset(targetSampleRate) %LOADDATASET Load PTDB-TUG data set % [adsEnroll,adsTest,adsDET,adsImposter] = loadDataset(targetSampleteRate) % downloads the PTDB-TUG data set, resamples it to the specified target % sample rate and save the results in your current folder. The function % then creates and returns four audioDatastore objects. The enrollment set % includes two utterances per speaker. The imposter set does not overlap % with the other data sets. % Copyright 2021 The MathWorks, Inc. arguments targetSampleRate (1,1) {mustBeNumeric,mustBePositive} end url = 'https://www2.spsc.tugraz.at/databases/PTDB-TUG/SPEECH_DATA_ZIPPED.zip'; downloadFolder = tempdir; datasetFolder = fullfile(downloadFolder,'PTDB-TUG'); % Download and unzip the dataset if it doesn't exist if ~isfolder(datasetFolder) disp('Downloading PTDB-TUG (3.9 G) ...') unzip(url,datasetFolder) end % Resample the dataset and save to current folder if it doesn't already % exist. if ~isfolder(fullfile(pwd,'MIC')) ads = audioDatastore([fullfile(datasetFolder,"SPEECH DATA","FEMALE","MIC"),fullfile(datasetFolder,"SPEECH DATA","MALE","MIC")], ... 'IncludeSubfolders',true, ... 'FileExtensions','.wav', ... 'LabelSource','foldernames'); reduceDataset = false; if reduceDataset ads = splitEachLabel(ads,55); end adsTransform = transform(ads,@(x,y)fileResampler(x,y,targetSampleRate),'IncludeInfo',true); writeall(adsTransform,pwd,'OutputFormat','flac','UseParallel',~isempty(ver('parallel'))) end % Create a datastore that points to the resampled dataset. Use the folder % names as the labels. ads = audioDatastore(fullfile(pwd,'MIC'),'IncludeSubfolders',true,'LabelSource',"foldernames"); % Split the data set into enrollment, test, DET, and imposter sets. imposterLabels = categorical(["M05","M10","F05","F10"]); adsImposter = subset(ads,ismember(ads.Labels,imposterLabels)); adsDev = subset(ads,~ismember(ads.Labels,imposterLabels)); rng default numToEnroll = 2; [adsEnroll,adsDev] = splitEachLabel(adsDev,numToEnroll); numToTest = 50; [adsTest,adsDET] = splitEachLabel(adsDev,numToTest); end
function [audioOut,adsInfo] = fileResampler(audioIn,adsInfo,targetSampleRate) %FILERESAMPLER Resample audio files % [audioOut,adsInfo] = fileResampler(audioIn,adsInfo,targetSampleRate) % resamples the input audio to the target sample rate and updates the info % passed through the datastore. % Copyright 2021 The MathWorks, Inc. arguments audioIn (:,1) {mustBeA(audioIn,{'single','double'})} adsInfo (1,1) {mustBeA(adsInfo,'struct')} targetSampleRate (1,1) {mustBeNumeric,mustBePositive} end % Isolate the original sample rate originalSampleRate = adsInfo.SampleRate; % Resample if necessary if originalSampleRate ~= targetSampleRate audioOut = resample(audioIn,targetSampleRate,originalSampleRate); amax = max(abs(audioOut)); if max(amax>1) audioOut = audioOut./amax; end end % Update the info passed through the datastore adsInfo.SampleRate = targetSampleRate; end
function [targetScores,nontargetScores] = scoreTargets(e,t,targetMap,nvargs) %SCORETARGETS Score i-vector pairs % [targetScores,nontargetScores] = scoreTargets(e,t,targetMap) exhaustively % scores i-vectors in e against i-vectors in t. Specify e as an M-by-N % matrix, where M corresponds to the i-vector dimension, and N corresponds % to the number of i-vectors in e. Specify t as an M-by-P matrix, where P % corresponds to the number of i-vectors in t. Specify targetMap as a % P-by-N logical matrix that maps which i-vectors in e and t are target % pairs (derived from the same speaker) and which i-vectors in e and t % are non-target pairs (derived from different speakers). The % outputs, targetScores and nontargetScores, are N-element cell arrays. % Each cell contains a vector of scores between the i-vector in e and % either all the targets or nontargets in t. % % [targetScores,nontargetScores] = % scoreTargets(e,t,targetMap,'NormFactorsSe',NFSe,'NormFactorsSt',NFSt) % normalizes the scores by the specified normalization statistics contained % in structs NFSe and NFSt. If unspecified, no normalization is applied. % Copyright 2021 The MathWorks, Inc. arguments e (:,:) {mustBeA(e,{'single','double'})} t (:,:) {mustBeA(t,{'single','double'})} targetMap (:,:) {mustBeA(targetMap,{'logical'})} nvargs.NormFactorsSe = []; nvargs.NormFactorsSt = []; end % Score the i-vector pairs scores = cosineSimilarityScore(e,t); % Apply as-norm1 if normalization factors supplied if ~isempty(nvargs.NormFactorsSe) && ~isempty(nvargs.NormFactorsSt) scores = 0.5*( (scores - nvargs.NormFactorsSe.mu)./nvargs.NormFactorsSe.std + (scores - nvargs.NormFactorsSt.mu')./nvargs.NormFactorsSt.std' ); end % Separate the scores into targets and non-targets targetScores = cell(size(targetMap,2),1); nontargetScores = cell(size(targetMap,2),1); for ii = 1:size(targetMap,2) targetScores{ii} = scores(targetMap(:,ii),ii); nontargetScores{ii} = scores(~targetMap(:,ii),ii); end end
function scores = cosineSimilarityScore(a,b) %COSINESIMILARITYSCORE Cosine similarity score % scores = cosineSimilarityScore(a,b) scores matrix of i-vectors, a, % against matrix of i-vectors b. Specify a as an M-by-N matrix of % i-vectors. Specify b as an M-by-P matrix of i-vectors. scores is returned % as a P-by-N matrix, where columns corresponds the i-vectors in a % and rows corresponds to the i-vectors in b and the elements of the array % are the cosine similarity scores between them. % Copyright 2021 The MathWorks, Inc. arguments a (:,:) {mustBeA(a,{'single','double'})} b (:,:) {mustBeA(b,{'single','double'})} end scores = squeeze(sum(a.*reshape(b,size(b,1),1,[]),1)./(vecnorm(a).*reshape(vecnorm(b),1,1,[]))); scores = scores'; end
function plotScoreDistributions(targetScores,nontargetScores,nvargs) %PLOTSCOREDISTRIBUTIONS Plot target and non-target score distributions % plotScoreDistribution(targetScores,nontargetScores) plots empirical % estimations of the distribution for target scores and nontarget scores. % Specify targetScores and nontargetScores as cell arrays where each % element contains a vector of speaker-specific scores. % % plotScoreDistrubtions(targetScores,nontargetScores,'Analyze',ANALYZE) % specifies the scope for analysis as either 'label' or 'group'. If ANALYZE % is set to 'label', then a score distribution plot is created for each % label. If ANALYZE is set to 'group', then a score distribution plot is % created for the entire group by combining scores across speakers. If % unspecified, ANALYZE defaults to 'group'. % Copyright 2021 The MathWorks, Inc. arguments targetScores (1,:) cell nontargetScores (1,:) cell nvargs.Analyze (1,:) char {mustBeMember(nvargs.Analyze,{'label','group'})} = 'group' end % Combine all scores to determine good bins for analyzing both the target % and non-target scores together. allScores = cat(1,targetScores{:},nontargetScores{:}); [~,edges] = histcounts(allScores); % Determine the center of each bin for plotting purposes. centers = movmedian(edges(:),2,'Endpoints','discard'); if strcmpi(nvargs.Analyze,'group') % Plot the score distributions for the group. targetScoresBinCounts = histcounts(cat(1,targetScores{:}),edges); targetScoresBinProb = targetScoresBinCounts(:)./sum(targetScoresBinCounts); nontargetScoresBinCounts = histcounts(cat(1,nontargetScores{:}),edges); nontargetScoresBinProb = nontargetScoresBinCounts(:)./sum(nontargetScoresBinCounts); figure plot(centers,[targetScoresBinProb,nontargetScoresBinProb]) title("Score Distributions") xlabel('Score') ylabel('Probability') legend(["target","non-target"],'Location','northwest') axis tight else % Create a tiled layout and plot the score distributions for each speaker. N = numel(targetScores); tiledlayout(N,1) for ii = 1:N targetScoresBinCounts = histcounts(targetScores{ii},edges); targetScoresBinProb = targetScoresBinCounts(:)./sum(targetScoresBinCounts); nontargetScoresBinCounts = histcounts(nontargetScores{ii},edges); nontargetScoresBinProb = nontargetScoresBinCounts(:)./sum(nontargetScoresBinCounts); nexttile hold on plot(centers,[targetScoresBinProb,nontargetScoresBinProb]) title("Score Distribution for Speaker " + string(ii)) xlabel('Score') ylabel('Probability') legend(["target","non-target"],'Location','northwest') axis tight end end end
function plotEER(targetScores,nontargetScores,nvargs) %PLOTEER Plot equal error rate (EER) % plotEER(targetScores,nontargetScores) creates an equal error rate plot % using the target scores and the non-target scores. Specify targetScores % and nontargetScores as cell arrays where each element contains a vector % of speaker-specific scores. % % plotEER(targetScores,nontargetScores,'Analyze',ANALYZE) specifies the % scope for analysis as either 'label' or 'group'. If ANALYZE is set to % 'label', then an equal error rate plot is created for each label. If % ANALYZE is set to 'group', then an equal error rate plot is created for % the entire group by combining scores across speakers. If unspecified, % ANALYZE defaults to 'group'. % Copyright 2021 The MathWorks, Inc. arguments targetScores (1,:) cell nontargetScores (1,:) cell nvargs.Analyze (1,:) char {mustBeMember(nvargs.Analyze,{'label','group'})} = 'group' end % Combine all scores to determine good bins for analyzing both the target % and non-target scores together. allScores = cat(1,targetScores{:},nontargetScores{:}); [~,edges] = histcounts(allScores,'BinWidth',0.002); % Determine the center of each bin for plotting purposes. centers = movmedian(edges(:),2,'Endpoints','discard'); if strcmpi(nvargs.Analyze,'group') % Plot the equal error rate for the group. targetScoresBinCounts = histcounts(cat(1,targetScores{:}),edges); targetScoresBinProb = targetScoresBinCounts(:)./sum(targetScoresBinCounts); nontargetScoresBinCounts = histcounts(cat(1,nontargetScores{:}),edges); nontargetScoresBinProb = nontargetScoresBinCounts(:)./sum(nontargetScoresBinCounts); targetScoresCDF = cumsum(targetScoresBinProb); nontargetScoresCDF = cumsum(nontargetScoresBinProb,'reverse'); [~,idx] = min(abs(targetScoresCDF(:) - nontargetScoresCDF)); figure plot(centers,[targetScoresCDF,nontargetScoresCDF]) xline(centers(idx),'-',num2str(centers(idx),3),'LabelOrientation','horizontal') legend(["FRR","FAR"],'Location','best') xlabel('Threshold Score') ylabel('Error Rate') title(sprintf("Equal Error Plot, EER = %0.2f (%%)",100*mean([targetScoresCDF(idx);nontargetScoresCDF(idx)]))) axis tight else % Create a tiled layout and plot the equal error rate for each speaker. N = numel(targetScores); f = figure; tiledlayout(f,N,1,'Padding','tight','TileSpacing','tight') for ii = 1:N targetScoresBinCounts = histcounts(targetScores{ii},edges); targetScoresBinProb = targetScoresBinCounts(:)./sum(targetScoresBinCounts); nontargetScoresBinCounts = histcounts(nontargetScores{ii},edges); nontargetScoresBinProb = nontargetScoresBinCounts(:)./sum(nontargetScoresBinCounts); targetScoresCDF = cumsum(targetScoresBinProb); nontargetScoresCDF = cumsum(nontargetScoresBinProb,'reverse'); [~,idx] = min(abs(targetScoresCDF(:) - nontargetScoresCDF)); nexttile plot(centers,[targetScoresCDF,nontargetScoresCDF]) xline(centers(idx),'-',num2str(centers(idx),3),'LabelOrientation','horizontal') legend(["FRR","FAR"],'Location','southwest') xlabel('Threshold Score') ylabel('Error Rate') title(sprintf("Equal Error Plot for Speaker " + string(ii) + ", EER = %0.2f (%%)", ... 100*mean([targetScoresCDF(idx);nontargetScoresCDF(idx)]))) axis tight end end end
function normFactors = getNormFactors(w,imposterCohort,nvargs) %GETNORMFACTORS Get norm factors % normFactors = getNormFactors(w,imposterCohort) returns the mean and % standard deviation of the scores between the i-vectors in w and the i-vectors % in the imposter cohort. Specify w as a matrix of i-vectors. Specify % imposterCohort as a matrix of i-vectors. Each column corresponds to an % i-vector the same length as w. % % normFactors = getNormFactors(w,imposterCohort,'TopK',TOPK) calculates the % normalization statistics using only the top K highest scores. If % unspecified, all scores are used. % Copyright 2021 The MathWorks, Inc. arguments w (:,:) {mustBeA(w,{'single','double'})} imposterCohort (:,:) {mustBeA(imposterCohort,{'single','double'})} nvargs.TopK (1,1) {mustBePositive} = inf end topK = min(ceil(nvargs.TopK),size(imposterCohort,2)); % Score the template i-vector against the imposter cohort. imposterScores = cosineSimilarityScore(w,imposterCohort); % Isolate the top K scores. imposterScores = sort(imposterScores,'descend'); imposterScores = imposterScores(1:topK,:); % Calculate the score normalization statistics MU = mean(imposterScores,1); STD = std(imposterScores,[],1); % Return normalization statistics as a struct normFactors = struct('mu',MU,'std',STD); end
[1] Matejka, Павел, Ondrej Novotny, Oldrich Plchot, Лукаш Бургет, Миреия Диз Санчес и Ян Серноки. "Анализ Нормализации Счета в Многоязычном Распознавании Динамика". Межречь 2017, 2017. https://doi.org/10.21437/interspeech.2017-803.
[2] ван Лиувен, Дэвид А. и Нико Браммер. "Введение в Не зависящую от приложения Оценку Систем Распознавания Динамика". Читайте лекции Примечаниям в Информатике, 2007, 330–53. https://doi.org/10.1007/978-3-540-74200-5_19.
[3] Г. Пиркер, М. Уохлмэр, С. Петрик и Ф. Пернкопф, "Корпус Отслеживания Тангажа с Оценкой на Сценарии Отслеживания Мультитангажа", Межречь, стр 1509-1512, 2011.