Верификация динамика, или аутентификация, является задачей проверки того, что данный сегмент речи принадлежит данному динамику. В системах верификации дикторов существует неизвестный набор всех других дикторов, поэтому вероятность того, что высказывание принадлежит цели верификации, сравнивается с вероятностью того, что оно не делает. Это контрастирует с задачами идентификации диктора, где вычисляется вероятность каждого диктора, и эти вероятности сравниваются. И верификация динамика, и идентификация динамика могут быть зависящими от текста или независимыми от текста. В этом примере вы создаете зависящую от текста систему верификации динамика, используя Смешанную гауссовскую модель/универсальную фоновую модель (GMM-UBM).
Рисунок системы GMM-UBM показан:
Чтобы мотивировать этот пример, вы сначала выполните верификацию динамика с помощью предварительно обученной универсальной фоновой модели (UBM). Модель обучалась с использованием слова «stop» из набора данных 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);
Файлы, включенные в этот пример, состоят из слова «stop», на котором пять раз говорят три разных динамика: BFn
(1), BHm
(3) и RPalanim
(1). Имена файлов указаны в SpeakerID_RecordingNumber формате. Установите метки datastore на соответствующий идентификатор динамика.
[~,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);
Зарегистрируйте выбранный динамик, используя максимально апостериорную (MAP) адаптацию. Подробную информацию об алгоритме регистрации можно найти позже в примере.
speakerGMM = helperEnroll(ubm,afe,normFactors,adsEnroll);
Для каждого из файлов в тестовом наборе используйте тест коэффициента вероятности и порог, чтобы определить, является ли динамик зарегистрированным оратором или самозванцем.
threshold = 0.7; сброс (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, порог); 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
набор данных, включающий только слово «стоп».
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 (объявления);
forEnrollAndTestSet = labelCount {:, 1} (labelCount {:, 2} > = 3);
forEnroll = forEnrollAndTestSet (randi ([1, numel (forEnrollAndTestSet)], numSpeakersToEnroll, 1));
tf = ismember (ads.Labels, forEnroll);
adsEnrollAndValidate = подмножество (объявления, tf);
adsEnroll = splitEachLabel (adsEnrollAndValidate, 2);
adsTest = subset (ads, ismember (ads.Labels, forEnrollAndTestSet));
adsTest = subset (adsTest, ~ ismember (adsTest.Files, файлы));
forUBMTraining = ~ (ismember (ads.Files, файлы) | ismember (ads.Files, файлы));
adsTrainUBM = подмножество (объявления, forUBMTraining);
Прочтите из обучающего datastore и прослушайте файл. Сбросьте datastore.
[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
-by- 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.
Извлеките все функции из набора данных. Если у вас есть Parallel Computing Toolbox™, определите оптимальное количество разделов для набора данных и распределите расчеты между доступными работниками. Если у вас нет Parallel Computing Toolbox™, используйте один раздел.
featuresAll = {}; if ~isempty(ver('parallel')) numPar = 18; else numPar = 1; end
Используйте функцию helper, 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 = таковые (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 в struct с полями, которые являются идентификаторами динамика и значениями, являющимися структурами 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 повторно спасти сохранить'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] Warden P. «Speech Commands: A public dataset for single-word speech recognition», 2017. Доступно из https://storage.googleapis.com/download.tensorflow.org/data/speech_commands_v0.01.tar.gz. Копирайт Google 2017. Набор данных Speech Commands лицензирован по лицензии Creative Commons Attribution 4.0, доступной здесь: https://creativecommons.org/licenses/by/4.0/legalcode.
[2] Рейнольдс, Дуглас А., Томас Ф. Кватьери и Роберт Б. Данн. «Динамик Верификации использования адаптированных Смешанных гауссовских моделей». Цифровая обработка сигналов 10, № 1-3 (2000): 19-41. https://doi.org/10.1006/dspr.1999.0361.