Верификация динамика или аутентификация, является задачей проверки, что данный речевой сегмент принадлежит данному динамику. В системах верификации динамика существует неизвестный набор всех других динамиков, таким образом, вероятность, что произнесение принадлежит цели верификации, сравнивается с вероятностью, что это не делает. Это контрастирует с идентификационными задачами динамика, где вероятность каждого динамика вычисляется, и те вероятности сравнены. И верификация динамика и идентификация динамика могут быть текстовым зависимым или независимым текстом. В этом примере вы создаете зависимую текстом систему верификации динамика с помощью смешанной гауссовской модели / универсальная фоновая модель (GMM-UBM).
Эскиз системы 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. Установите метки datastore на соответствующий ID динамика.
[~,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.1; сбросьте (adsTest) while hasdata (adsTest) fprintf'Identity to confirm: %s\n', enrollLabel) [аудиоданные, adsInfo] = читают (adsTest); fprintf' | Speaker identity: %s\n', строка (adsInfo. Метка, verificationStatus = helperVerify (аудиоданные, 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} Маркировка Count: 2}> =3);
forEnroll = forEnrollAndTestSet (randi ([1, numel (forEnrollAndTestSet)], numSpeakersToEnroll, 1));
tf = ismember (объявления. Метки, forEnroll);
adsEnrollAndValidate = подмножество (объявления, tf);
adsEnroll = splitEachLabel (adsEnrollAndValidate, 2);
adsTest = подмножество (объявления, ismember (объявления. Метки, forEnrollAndTestSet));
adsTest = подмножество (adsTest, ~ismember (adsTest. Файлы, adsEnroll. Файлы));
forUBMTraining = ~ (ismember (объявления. Файлы, adsTest. Файлы) | ismember (объявления. Файлы, adsEnroll. Файлы));
adsTrainUBM = подмножество (объявления, forUBMTraining);
Читайте из учебного datastore и слушайте файл. Сбросьте datastore.
[audioData,audioInfo] = read(adsTrainUBM); fs = audioInfo.SampleRate; sound(audioData,fs) reset(adsTrainUBM)
В извлечении признаков конвейерно обрабатывают для этого примера, вас:
Нормируйте аудио
Используйте detectSpeech
удалить неречевые области из аудио
Извлеките функции из аудио
Нормируйте функции
Примените среднюю нормализацию cepstral
Во-первых, создайте 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;
Примените локальную среднюю нормализацию cepstral.
features = features - mean(features,'all');
Конвейер извлечения признаков инкапсулируется в функции помощника, helperFeatureExtraction.
Извлеките все функции из набора данных. Если вы имеете Parallel Computing Toolbox™, определяете оптимальное количество разделов для набора данных и распространяете расчет через доступных рабочих. Если у вас нет Parallel Computing Toolbox™, используйте один раздел.
featuresAll = {}; if ~isempty(ver('parallel')) pool = gcp; numPar = numpartitions(ads,pool); 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 allFeatures = cat(2,featuresAll{:});
Вычислите среднее значение и отклонение каждой функции.
normFactors.Mean = mean(allFeatures,2,'omitnan'); normFactors.STD = std(allFeatures,[],2,'omitnan');
Универсальная фоновая модель является смешанной гауссовской моделью. Задайте количество компонентов в смеси. [2] предлагает больше чем 512 для независимых от текста систем. Веса компонента начинаются равномерно распределенный.
numComponents =32;
альфа = единицы (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.005;
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; for 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 = -831.395 Iteration 2, Log-likelihood = -526.217 Iteration 3, Log-likelihood = -489.717 Iteration 4, Log-likelihood = -478.680 Iteration 5, Log-likelihood = -472.411 Iteration 6, Log-likelihood = -468.099 Iteration 7, Log-likelihood = -465.051 Iteration 8, Log-likelihood = -462.790 Iteration 9, Log-likelihood = -460.845 Iteration 10, Log-likelihood = -459.270 Iteration 11, Log-likelihood = -458.023 Iteration 12, Log-likelihood = -457.047 Iteration 13, Log-likelihood = -456.238 Iteration 14, Log-likelihood = -455.571 Iteration 15, Log-likelihood = -455.037 Iteration 16, Log-likelihood = -454.579 Iteration 17, Log-likelihood = -454.206 Iteration 18, Log-likelihood = -453.876 Iteration 19, Log-likelihood = -453.562 Iteration 20, Log-likelihood = -453.229
fprintf('UBM training completed in %0.2f seconds.\n',toc)
UBM training completed in 187.69 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.18 seconds.
В бухгалтерских целях преобразуйте массив ячеек GMMs к 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.17 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 19.66 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] Начальник П. "Речевые Команды: общедоступный набор данных для распознавания речи однословного", 2017. Доступный от https://storage.googleapis.com/download.tensorflow.org/data/speech_commands_v0.01.tar.gz. Авторское право Google 2017. Речевой Набор данных Команд лицензируется при Приписывании Creative Commons 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.