Верификация говорящего, или аутентификация, является задачей проверки принадлежности данного речевого сегмента данному говорящему. В системах верификации говорящих существует неизвестный набор всех других говорящих, поэтому вероятность того, что говорящее принадлежит цели верификации, сравнивается с вероятностью того, что оно это делает. Это контрастирует с задачами идентификации говорящих, где вычисляется вероятность каждого говорящего, и эти вероятности сравниваются. И проверка говорящего, и идентификация говорящего могут быть зависимыми от текста или независимыми от текста. В этом примере создается зависящая от текста система проверки говорящего с использованием модели гауссова смешения/универсальной фоновой модели (GMM-UBM).
Показан эскиз системы ГРМ-УБМ:

Чтобы мотивировать этот пример, сначала выполните верификацию динамика с использованием предварительно обученной универсальной фоновой модели (UBM). Модель была обучена с использованием слова «стоп» из набора данных Google Speech Commands [1].
Файл MAT, speakerVerficationExampleData.mat, включает UBM, сконфигурированный audioFeatureExtractor и коэффициенты нормализации, используемые для нормализации элементов.
load speakerVerificationExampleData.mat ubm afe normFactors
Если вы хотите проверить регистрацию самостоятельно, установите enrollYourself кому true. Вам будет предложено записать слова «стоп» несколько раз. Произнесите «стоп» только один раз за подсказку. Увеличение числа записей должно повысить точность проверки.
enrollYourself =false; if enrollYourself numToRecord =
5; ID =
'self'; helperAddUser(afe.SampleRate,numToRecord,ID); end
Создание audioDatastore объект для указания на пять аудиофайлов, включенных в этот пример, и, если вы зарегистрировались, только что записанные аудиофайлы. Аудиофайлы, включенные в этот пример, являются частью внутреннего набора данных и не использовались для обучения UBM.
ads = audioDatastore(pwd);
Файлы, включенные в этот пример, состоят из слова «стоп», произнесенного пять раз тремя разными ораторами: BFn (1), BHm (3), и RPalanim (1). Имена файлов имеют SpeakerID_RecordingNumber формат. Установите метки хранилища данных для соответствующего идентификатора громкоговорителя.
[~,fileName] = cellfun(@(x)fileparts(x),ads.Files,'UniformOutput',false); fileName = split(fileName,'_'); speaker = strcat(fileName(:,1)); ads.Labels = categorical(speaker);
Используйте все файлы, кроме одного, из динамика, который вы регистрируете для процесса регистрации. Остальные файлы используются для тестирования системы.
if enrollYourself enrollLabel = ID; else enrollLabel = 'BHm'; end forEnrollment = ads.Labels==enrollLabel; forEnrollment(find(forEnrollment==1,1)) = false; adsEnroll = subset(ads,forEnrollment); adsTest = subset(ads,~forEnrollment);
Зарегистрируйте выбранный громкоговоритель, используя максимальную адаптацию posteriori (MAP). Подробности алгоритма регистрации можно найти ниже в примере.
speakerGMM = helperEnroll(ubm,afe,normFactors,adsEnroll);
Для каждого из файлов в тестовом наборе используйте тест отношения правдоподобия и пороговое значение, чтобы определить, является ли оратор зарегистрированным оратором или самозванцем.
threshold =0.7; reset(adsTest) while hasdata(adsTest) fprintf('Identity to confirm: %s\n',enrollLabel) [audioData,adsInfo] = read(adsTest); fprintf(' | Speaker identity: %s\n',string(adsInfo.Label)) verificationStatus = helperVerify(audioData,afe,normFactors,speakerGMM,ubm,threshold); if verificationStatus fprintf(' | Confirmed.\n'); else fprintf(' | Imposter!\n'); end end
Identity to confirm: BHm
| Speaker identity: BFn
| Imposter!
Identity to confirm: BHm
| Speaker identity: BHm
| Confirmed.
Identity to confirm: BHm
| Speaker identity: RPalanim
| Imposter!
В оставшейся части примера подробно описывается создание UBM и алгоритма регистрации, а затем выполняется оценка системы с использованием обычно сообщаемых метрик.
UBM, используемый в этом примере, обучается с помощью [1]. Загрузите и извлеките набор данных.
url = 'https://storage.googleapis.com/download.tensorflow.org/data/speech_commands_v0.01.tar.gz'; downloadFolder = tempdir; datasetFolder = fullfile(downloadFolder,'google_speech'); if ~exist(datasetFolder,'dir') disp('Downloading Google speech commands data set (1.9 GB)...') untar(url,datasetFolder) end
Создание audioDatastore указывает на набор данных. Используйте имена папок в качестве меток. Имена папок указывают на слова, произнесенные в наборе данных.
ads = audioDatastore(datasetFolder,"Includesubfolders",true,'LabelSource','folderNames');
subset набор данных, включающий только слово «stop».
ads = subset(ads,ads.Labels==categorical("stop"));Установите метки для уникальных идентификаторов громкоговорителей, закодированных в именах файлов. Идентификаторы динамиков иногда начинаются с числа: добавить 'a' ко всем идентификаторам, чтобы сделать имена более понятными для переменных.
[~,fileName] = cellfun(@(x)fileparts(x),ads.Files,'UniformOutput',false); fileName = split(fileName,'_'); speaker = strcat('a',fileName(:,1)); ads.Labels = categorical(speaker);
Создайте три хранилища данных: одно для регистрации, одно для оценки системы проверки и одно для обучения UBM. Зарегистрируйте докладчиков, которые имеют не менее трех высказываний. Для каждого из докладчиков поместите два из высказываний в набор регистрации. Остальные пойдут в тестовом наборе. Тестовый набор состоит из высказываний всех динамиков, имеющих три или более высказываний в наборе данных. Учебный набор UBM состоит из оставшихся высказываний.
numSpeakersToEnroll =
10;
labelCount = countEachLabel(ads);
forEnrollAndTestSet = labelCount{:,1}(labelCount{:,2}>=3);
forEnroll = forEnrollAndTestSet(randi([1,numel(forEnrollAndTestSet)],numSpeakersToEnroll,1));
tf = ismember(ads.Labels,forEnroll);
adsEnrollAndValidate = subset(ads,tf);
adsEnroll = splitEachLabel(adsEnrollAndValidate,2);
adsTest = subset(ads,ismember(ads.Labels,forEnrollAndTestSet));
adsTest = subset(adsTest,~ismember(adsTest.Files,adsEnroll.Files));
forUBMTraining = ~(ismember(ads.Files,adsTest.Files) | ismember(ads.Files,adsEnroll.Files));
adsTrainUBM = subset(ads,forUBMTraining);Чтение из хранилища данных обучения и прослушивание файла. Сбросьте хранилище данных.
[audioData,audioInfo] = read(adsTrainUBM); fs = audioInfo.SampleRate; sound(audioData,fs) reset(adsTrainUBM)
В трубопроводе извлечения элементов для этого примера выполняется следующее:
Нормализация звука
Использовать detectSpeech для удаления из звука областей, отличных от области речи
Извлечение функций из звука
Нормализация элементов
Применить среднецепстральную нормализацию
Сначала создайте audioFeatureExtractor объект извлечения MFCC. Укажите длительность 40 мс и 10 мс транзитного участка для кадров.
windowDuration = 0.04; hopDuration = 0.01; windowSamples = round(windowDuration*fs); hopSamples = round(hopDuration*fs); overlapSamples = windowSamples - hopSamples; afe = audioFeatureExtractor( ... 'SampleRate',fs, ... 'Window',hann(windowSamples,'periodic'), ... 'OverlapLength',overlapSamples, ... ... 'mfcc',true);
Нормализуйте звук.
audioData = audioData./max(abs(audioData));
Используйте detectSpeech функция для определения местоположения области речи в аудиоклипе. Звонить detectSpeech без каких-либо выходных аргументов для визуализации обнаруженной области речи.
detectSpeech(audioData,fs);

Звонить detectSpeech снова. На этот раз верните индексы речевой области и используйте их для удаления не речевых областей из аудиоклипа.
idx = detectSpeech(audioData,fs); audioData = audioData(idx(1,1):idx(1,2));
Звонить extract на audioFeatureExtractor объект для извлечения элементов из аудиоданных. Размер выходных данных extract является numHopsоколо-numFeatures.
features = extract(afe,audioData); [numHops,numFeatures] = size(features)
numHops = 66
numFeatures = 13
Нормализуйте элементы по их глобальному среднему значению и дисперсии. В следующем разделе примера рассматривается расчет глобального среднего и отклонения. Пока просто используйте предварительно рассчитанное среднее и уже загруженное отклонение.
features = (features' - normFactors.Mean) ./ normFactors.Variance;
Примените локальную кепстральную среднюю нормализацию.
features = features - mean(features,'all');Конвейер извлечения элементов инкапсулируется в вспомогательную функцию helperFeatureExtraction.
Извлеките все элементы из набора данных. При наличии Toolbox™ Parallel Computing определите оптимальное количество разделов для набора данных и распределите вычисления по доступным работникам. Если у вас нет Toolbox™ Parallel Computing, используйте один раздел.
featuresAll = {};
if ~isempty(ver('parallel'))
numPar = 18;
else
numPar = 1;
endИспользуйте функцию помощника, helperFeatureExtraction, для извлечения всех элементов из набора данных. Запрос helperFeatureExtraction с пустым третьим аргументом выполняет шаги извлечения элемента, описанные в разделе Извлечение элемента, за исключением нормализации по глобальному среднему значению и дисперсии.
parfor ii = 1:numPar adsPart = partition(ads,numPar,ii); featuresPart = cell(0,numel(adsPart.Files)); for iii = 1:numel(adsPart.Files) audioData = read(adsPart); featuresPart{iii} = helperFeatureExtraction(audioData,afe,[]); end featuresAll = [featuresAll,featuresPart]; end
Starting parallel pool (parpool) using the 'local' profile ... Connected to the parallel pool (number of workers: 6).
allFeatures = cat(2,featuresAll{:});Рассчитайте среднее значение и дисперсию каждого элемента.
normFactors.Mean = mean(allFeatures,2,'omitnan'); normFactors.STD = std(allFeatures,[],2,'omitnan');
Универсальной фоновой моделью является гауссова модель смеси. Определите количество компонентов в смеси. [2] предлагает более 512 для текстовых независимых систем. Веса компонентов начинаются равномерно распределенными.
numComponents =
32;
alpha = ones(1,numComponents)/numComponents;Использовать случайную инициализацию для mu и sigma каждого компонента GMM. Создайте структуру для хранения необходимой информации UBM.
mu = randn(numFeatures,numComponents); sigma = rand(numFeatures,numComponents); ubm = struct('ComponentProportion',alpha,'mu',mu,'sigma',sigma);
Поместите GMM в учебный набор для создания UBM. Используйте алгоритм ожидания-максимизации.
Алгоритм ожидания-максимизации рекурсивен. Сначала определите критерии остановки.
maxIter = 20;
targetLogLikelihood = 0;
tol = 0.5;
pastL = -inf; % initialization of previous log-likelihoodВ цикле обучайте UBM, используя алгоритм ожидания-максимизации.
tic for iter = 1:maxIter % EXPECTATION N = zeros(1,numComponents); F = zeros(numFeatures,numComponents); S = zeros(numFeatures,numComponents); L = 0; parfor ii = 1:numPar adsPart = partition(adsTrainUBM,numPar,ii); while hasdata(adsPart) audioData = read(adsPart); % Extract features features = helperFeatureExtraction(audioData,afe,normFactors); % Compute a posteriori log-likelihood logLikelihood = helperGMMLogLikelihood(features,ubm); % Compute a posteriori normalized probability logLikelihoodSum = helperLogSumExp(logLikelihood); gamma = exp(logLikelihood - logLikelihoodSum)'; % Compute Baum-Welch statistics n = sum(gamma,1); f = features * gamma; s = (features.*features) * gamma; % Update the sufficient statistics over utterances N = N + n; F = F + f; S = S + s; % Update the log-likelihood L = L + sum(logLikelihoodSum); end end % Print current log-likelihood and stop if it meets criteria. L = L/numel(adsTrainUBM.Files); fprintf('\tIteration %d, Log-likelihood = %0.3f\n',iter,L) if L > targetLogLikelihood || abs(pastL - L) < tol break else pastL = L; end % MAXIMIZATION N = max(N,eps); ubm.ComponentProportion = max(N/sum(N),eps); ubm.ComponentProportion = ubm.ComponentProportion/sum(ubm.ComponentProportion); ubm.mu = bsxfun(@rdivide,F,N); ubm.sigma = max(bsxfun(@rdivide,S,N) - ubm.mu.^2,eps); end
Iteration 1, Log-likelihood = -826.174 Iteration 2, Log-likelihood = -538.546 Iteration 3, Log-likelihood = -522.670 Iteration 4, Log-likelihood = -517.458 Iteration 5, Log-likelihood = -514.852 Iteration 6, Log-likelihood = -513.068 Iteration 7, Log-likelihood = -511.644 Iteration 8, Log-likelihood = -510.588 Iteration 9, Log-likelihood = -509.788 Iteration 10, Log-likelihood = -509.135 Iteration 11, Log-likelihood = -508.529 Iteration 12, Log-likelihood = -508.032
fprintf('UBM training completed in %0.2f seconds.\n',toc)UBM training completed in 32.31 seconds.
После создания универсальной фоновой модели можно зарегистрировать динамики и адаптировать UBM к динамикам. [2] предлагает коэффициент релевантности адаптации 16. Коэффициент релевантности определяет степень перемещения каждого компонента UBM к громкоговорителю GMM.
relevanceFactor = 16; speakers = unique(adsEnroll.Labels); numSpeakers = numel(speakers); gmmCellArray = cell(numSpeakers,1); tic parfor ii = 1:numSpeakers % Subset the datastore to the speaker you are adapting. adsTrainSubset = subset(adsEnroll,adsEnroll.Labels==speakers(ii)); N = zeros(1,numComponents); F = zeros(numFeatures,numComponents); S = zeros(numFeatures,numComponents); while hasdata(adsTrainSubset) audioData = read(adsTrainSubset); features = helperFeatureExtraction(audioData,afe,normFactors); [n,f,s,l] = helperExpectation(features,ubm); N = N + n; F = F + f; S = S + s; end % Determine the maximum likelihood gmm = helperMaximization(N,F,S); % Determine adaption coefficient alpha = N ./ (N + relevanceFactor); % Adapt the means gmm.mu = alpha.*gmm.mu + (1-alpha).*ubm.mu; % Adapt the variances gmm.sigma = alpha.*(S./N) + (1-alpha).*(ubm.sigma + ubm.mu.^2) - gmm.mu.^2; gmm.sigma = max(gmm.sigma,eps); % Adapt the weights gmm.ComponentProportion = alpha.*(N/sum(N)) + (1-alpha).*ubm.ComponentProportion; gmm.ComponentProportion = gmm.ComponentProportion./sum(gmm.ComponentProportion); gmmCellArray{ii} = gmm; end fprintf('Enrollment completed in %0.2f seconds.\n',toc)
Enrollment completed in 0.27 seconds.
Для целей бухгалтерского учета преобразуйте массив ячеек GMM в структуру, где поля являются идентификаторами динамика, а значения - структурами GMM.
for i = 1:numel(gmmCellArray) enrolledGMMs.(string(speakers(i))) = gmmCellArray{i}; end
Частота ложного отклонения говорящего (FRR) - это частота неправильного отклонения говорящего. Используйте известный набор громкоговорителей для определения частоты ложного отклонения громкоговорителя для набора пороговых значений.
speakers = unique(adsEnroll.Labels); numSpeakers = numel(speakers); llr = cell(numSpeakers,1); tic parfor speakerIdx = 1:numSpeakers localGMM = enrolledGMMs.(string(speakers(speakerIdx))); adsTestSubset = subset(adsTest,adsTest.Labels==speakers(speakerIdx)); llrPerSpeaker = zeros(numel(adsTestSubset.Files),1); for fileIdx = 1:numel(adsTestSubset.Files) audioData = read(adsTestSubset); [x,numFrames] = helperFeatureExtraction(audioData,afe,normFactors); logLikelihood = helperGMMLogLikelihood(x,localGMM); Lspeaker = helperLogSumExp(logLikelihood); logLikelihood = helperGMMLogLikelihood(x,ubm); Lubm = helperLogSumExp(logLikelihood); llrPerSpeaker(fileIdx) = mean(movmedian(Lspeaker - Lubm,3)); end llr{speakerIdx} = llrPerSpeaker; end fprintf('False rejection rate computed in %0.2f seconds.\n',toc)
False rejection rate computed in 0.20 seconds.
Постройте график ложного отклонения в зависимости от порогового значения.
llr = cat(1,llr{:});
thresholds = -0.5:0.01:2.5;
FRR = mean(llr<thresholds);
plot(thresholds,FRR*100)
title('False Rejection Rate (FRR)')
xlabel('Threshold')
ylabel('Incorrectly Rejected (%)')
grid on
Коэффициент ложного принятия говорящего (FAR) - это коэффициент, при котором говорящие, не принадлежащие зарегистрированному говорящему, ошибочно принимаются как принадлежащие зарегистрированному говорящему. Используйте известный аппарат громкоговорителя для определения FAR громкоговорителя для набора пороговых значений. Используйте тот же набор пороговых значений, который используется для определения FRR.
speakersTest = unique(adsTest.Labels); llr = cell(numSpeakers,1); tic parfor speakerIdx = 1:numel(speakers) localGMM = enrolledGMMs.(string(speakers(speakerIdx))); adsTestSubset = subset(adsTest,adsTest.Labels~=speakers(speakerIdx)); llrPerSpeaker = zeros(numel(adsTestSubset.Files),1); for fileIdx = 1:numel(adsTestSubset.Files) audioData = read(adsTestSubset); [x,numFrames] = helperFeatureExtraction(audioData,afe,normFactors); logLikelihood = helperGMMLogLikelihood(x,localGMM); Lspeaker = helperLogSumExp(logLikelihood); logLikelihood = helperGMMLogLikelihood(x,ubm); Lubm = helperLogSumExp(logLikelihood); llrPerSpeaker(fileIdx) = mean(movmedian(Lspeaker - Lubm,3)); end llr{speakerIdx} = llrPerSpeaker; end fprintf('FAR computed in %0.2f seconds.\n',toc)
FAR computed in 22.64 seconds.
Постройте график FAR как функции порога.
llr = cat(1,llr{:});
FAR = mean(llr>thresholds);
plot(thresholds,FAR*100)
title('False Acceptance Rate (FAR)')
xlabel('Threshold')
ylabel('Incorrectly Rejected (%)')
grid on
При перемещении порога в системе проверки динамика происходит компромисс между FAR и FRR. Это упоминается как компромисс ошибок обнаружения (DET) и обычно сообщается для проблем двоичной классификации.
x1 = FAR*100; y1 = FRR*100; plot(x1,y1) grid on xlabel('False Acceptance Rate (%)') ylabel('False Rejection Rate (%)') title('Detection Error Tradeoff (DET) Curve')

Для сравнения нескольких систем необходима единая метрика, объединяющая характеристики FAR и FRR. Для этого определяется одинаковая частота ошибок (EER), которая является порогом, где встречаются кривые FAR и FRR. На практике порог EER может быть не лучшим выбором. Например, если верификация говорящего используется как часть подхода множественной аутентификации для телеграфных переводов, FAR, скорее всего, будет взвешиваться более сильно, чем FRR.
[~,EERThresholdIdx] = min(abs(FAR - FRR)); EERThreshold = thresholds(EERThresholdIdx); EER = mean([FAR(EERThresholdIdx),FRR(EERThresholdIdx)]); plot(thresholds,FAR,'k', ... thresholds,FRR,'b', ... EERThreshold,EER,'ro','MarkerFaceColor','r') title(sprintf('Equal Error Rate = %0.2f, Threshold = %0.2f',EER,EERThreshold)) xlabel('Threshold') ylabel('Error Rate') legend('False Acceptance Rate (FAR)','False Rejection Rate (FRR)','Equal Error Rate (EER)') grid on

Если вы изменили параметры обучения UBM, рассмотрите возможность повторного сохранения файла MAT с новой универсальной фоновой моделью, audioFeatureExtractorи нормальные факторы.
resave =false; if resave save('speakerVerificationExampleData.mat','ubm','afe','normFactors') end
function helperAddUser(fs,numToRecord,ID) % Create an audio device reader to read from your audio device deviceReader = audioDeviceReader('SampleRate',fs); % Initialize variables numRecordings = 1; audioIn = []; % Record the requested number while numRecordings <= numToRecord fprintf('Say "stop" once (recording %i of %i) ...',numRecordings,numToRecord) tic while toc<2 audioIn = [audioIn;deviceReader()]; end fprintf('complete.\n') idx = detectSpeech(audioIn,fs); if isempty(idx) fprintf('Speech not detected. Try again.\n') else audiowrite(sprintf('%s_%i.flac',ID,numRecordings),audioIn,fs) numRecordings = numRecordings+1; end pause(0.2) audioIn = []; end % Release the device release(deviceReader) end
function speakerGMM = helperEnroll(ubm,afe,normFactors,adsEnroll) % Initialization numComponents = numel(ubm.ComponentProportion); numFeatures = size(ubm.mu,1); N = zeros(1,numComponents); F = zeros(numFeatures,numComponents); S = zeros(numFeatures,numComponents); NumFrames = 0; while hasdata(adsEnroll) % Read from the enrollment datastore audioData = read(adsEnroll); % 1. Extract the features and apply feature normalization [features,numFrames] = helperFeatureExtraction(audioData,afe,normFactors); % 2. Calculate the a posteriori probability. Use it to determine the % sufficient statistics (the count, and the first and second moments) [n,f,s] = helperExpectation(features,ubm); % 3. Update the sufficient statistics N = N + n; F = F + f; S = S + s; NumFrames = NumFrames + numFrames; end % Create the Gaussian mixture model that maximizes the expectation speakerGMM = helperMaximization(N,F,S); % Adapt the UBM to create the speaker model. Use a relevance factor of 16, % as proposed in [2] relevanceFactor = 16; % Determine adaption coefficient alpha = N ./ (N + relevanceFactor); % Adapt the means speakerGMM.mu = alpha.*speakerGMM.mu + (1-alpha).*ubm.mu; % Adapt the variances speakerGMM.sigma = alpha.*(S./N) + (1-alpha).*(ubm.sigma + ubm.mu.^2) - speakerGMM.mu.^2; speakerGMM.sigma = max(speakerGMM.sigma,eps); % Adapt the weights speakerGMM.ComponentProportion = alpha.*(N/sum(N)) + (1-alpha).*ubm.ComponentProportion; speakerGMM.ComponentProportion = speakerGMM.ComponentProportion./sum(speakerGMM.ComponentProportion); end
function verificationStatus = helperVerify(audioData,afe,normFactors,speakerGMM,ubm,threshold) % Extract features x = helperFeatureExtraction(audioData,afe,normFactors); % Determine the log-likelihood the audio came from the GMM adapted to % the speaker post = helperGMMLogLikelihood(x,speakerGMM); Lspeaker = helperLogSumExp(post); % Determine the log-likelihood the audio came form the GMM fit to all % speakers post = helperGMMLogLikelihood(x,ubm); Lubm = helperLogSumExp(post); % Calculate the ratio for all frames. Apply a moving median filter % to remove outliers, and then take the mean across the frames llr = mean(movmedian(Lspeaker - Lubm,3)); if llr > threshold verificationStatus = true; else verificationStatus = false; end end
function [features,numFrames] = helperFeatureExtraction(audioData,afe,normFactors) % Normalize audioData = audioData/max(abs(audioData(:))); % Protect against NaNs audioData(isnan(audioData)) = 0; % Isolate speech segment % The dataset used in this example has one word per audioData, if more % than one is speech section is detected, just use the longest % detected. idx = detectSpeech(audioData,afe.SampleRate); if size(idx,1)>1 [~,seg] = max(idx(:,2) - idx(:,1)); else seg = 1; end audioData = audioData(idx(seg,1):idx(seg,2)); % Feature extraction features = extract(afe,audioData); % Feature normalization if ~isempty(normFactors) features = (features-normFactors.Mean')./normFactors.STD'; end features = features'; % Cepstral mean subtraction (for channel noise) if ~isempty(normFactors) features = features - mean(features,'all'); end numFrames = size(features,2); end
function y = helperLogSumExp(x) % Calculate the log-sum-exponent while avoiding overflow a = max(x,[],1); y = a + sum(exp(bsxfun(@minus,x,a)),1); end
function [N,F,S,L] = helperExpectation(features,gmm) post = helperGMMLogLikelihood(features,gmm); % Sum the likelihood over the frames L = helperLogSumExp(post); % Compute the sufficient statistics gamma = exp(post-L)'; N = sum(gamma,1); F = features * gamma; S = (features.*features) * gamma; L = sum(L); end
function gmm = helperMaximization(N,F,S) N = max(N,eps); gmm.ComponentProportion = max(N/sum(N),eps); gmm.mu = bsxfun(@rdivide,F,N); gmm.sigma = max(bsxfun(@rdivide,S,N) - gmm.mu.^2,eps); end
function L = helperGMMLogLikelihood(x,gmm) xMinusMu = repmat(x,1,1,numel(gmm.ComponentProportion)) - permute(gmm.mu,[1,3,2]); permuteSigma = permute(gmm.sigma,[1,3,2]); Lunweighted = -0.5*(sum(log(permuteSigma),1) + sum(bsxfun(@times,xMinusMu,(bsxfun(@rdivide,xMinusMu,permuteSigma))),1) + size(gmm.mu,1)*log(2*pi)); temp = squeeze(permute(Lunweighted,[1,3,2])); if size(temp,1)==1 % If there is only one frame, the trailing singleton dimension was % removed in the permute. This accounts for that edge case temp = temp'; end L = bsxfun(@plus,temp,log(gmm.ComponentProportion)'); end
[1] Уорден П. «Речевые команды: публичный набор данных для однословного распознавания речи», 2017. Доступно в https://storage.googleapis.com/download.tensorflow.org/data/speech_commands_v0.01.tar.gz. Авторское право Google 2017. Набор данных речевых команд лицензирован по лицензии Creative Commons Attribution 4.0, доступна здесь: https://creativecommons.org/licenses/by/4.0/legalcode.
[2] Рейнольдс, Дуглас А., Томас Ф. Кватьери и Роберт Б. Данн. «Проверка говорящего с использованием адаптированных моделей гауссовых смесей». Цифровая обработка сигналов 10, No 1-3 (2000): 19-41. https://doi.org/10.1006/dspr.1999.0361.