Диаризация динамика - это процесс разбиения аудиосигнала на сегменты в соответствии с тождествами динамика. В нем дается ответ на вопрос «кто говорил, когда» без предварительного знания ораторов и, в зависимости от заявки, без предварительного знания числа ораторов.
Диаризация динамика имеет много приложений, в том числе: улучшение транскрипции речи путем структурирования текста в соответствии с активным динамиком, подписывание видео, поиск содержимого (что сказала Джейн?) и подсчет диктора (сколько спикеров присутствовало на заседании?).
В этом примере вы выполняете диаризацию динамика с помощью предварительно обученной системы x-векторов [1], чтобы охарактеризовать области аудио и агломеративной иерархической кластеризации (AHC) для группировки аналогичных областей аудио [2]. Чтобы увидеть, как была определена и обучена система x-векторов, смотрите Распознавание динамика с использованием векторов x.
Загрузите аудиосигнал и таблицу, содержащую аннотации основной истины. Сигнал состоит из пяти динамиков. Прослушайте аудиосигнал и постройте график его волны во временной области.
[audioIn,fs] = audioread('exampleconversation.flac'); load('exampleconversationlabels.mat') audioIn = audioIn./max(abs(audioIn)); sound(audioIn,fs) t = (0:size(audioIn,1)-1)/fs; figure(1) plot(t,audioIn) xlabel('Time (s)') ylabel('Amplitude') axis tight
В этом примере вы использовали предварительно обученную систему x-векторов. Система x-векторов является облегченной версией исходной системы x-векторов, описанной в [1]. Чтобы увидеть, как была определена и обучена система x-векторов, смотрите Распознавание динамика с использованием векторов x.
Загрузите легкую предварительно обученную систему x-векторов. Система x-векторов состоит из:
afe
- an audioFeatureExtractor
объект для извлечения коэффициентов mel frequency cepstral (MFCC).
factors
- struct, содержащая среднее и стандартное отклонение MFCC, определяемое из репрезентативного набора данных. Эти факторы используются для стандартизации MFCC.
extractor
- struct, содержащая параметры и состояние нейронной сети, обученной извлекать x-векторы. The xvecModel
функция выполняет фактическое выделение x-вектора. The xvecModel
функция помещается в текущую папку, когда вы открываете этот пример.
classifier
- struct, содержащая обученную проекционную матрицу для уменьшения размерности x-векторов и обученную модель PLDA для оценки x-векторов.
load('xvectorSystem.mat')
Извлеките стандартизированные функции MFCC из аудио данных. Просмотрите распределения функции, чтобы подтвердить, что факторы стандартизации, полученные из отдельного набора данных, приблизительно стандартизируют функции, выведенные в этом примере. Стандартное распределение имеет среднее значение нуля и стандартное отклонение 1.
features = single((extract(afe,audioIn)-factors.Mean)./factors.STD);
figure(2)
histogram(features)
xlabel('Standardized MFCC')
Каждый вектор акустической функции представляет приблизительно 0,01 секунды аудио данных. Сгруппировать функции примерно в 2 вторых сегментов с 0,1 секундным хмелем между сегментами.
featureVectorHopDur = (numel(afe.Window) - afe.OverlapLength)/afe.SampleRate; segmentDur = 2; segmentHopDur = 0.1; segmentLength = round (segmentDur/featureVectorHopDur); segmentHop = round (segmentHopDur/featureVectorHopDur); idx = 1:segmentLength; featuresSegmented = []; while idx (end) < size (функции, 1) featuresSegmented = cat функций (idx,:)); idx = idx + segmentHop; end
Извлеките x-векторы из каждого сегмента. x-векторы соответствуют выходу из 7-го слоя в модели x-вектора, обученной в Распознавании Динамика с Использованием x-векторов. 7-й слой является первым слоем уровня сегмента после вычисления статистики для расширенных во времени слоев уровня кадра. Визуализируйте векторы X с течением времени.
outputLayer = 7; xvecs = zeros(numel(extractor.Parameters.("fc"+outputLayer).Bias),size(featuresSegmented,3)); for sample = 1:size(featuresSegmented,3) dlX = dlarray(featuresSegmented(:,:,sample),'SCB'); xvecs(:,sample) = extractdata(xvecModel(dlX,extractor.Parameters,extractor.State,'DoTraining',false,'OutputLayer',outputLayer)); end figure(3) surf(xvecs','EdgeColor','none') view([90,-90]) axis([1 size(xvecs,1) 1 size(xvecs,2)]) xlabel('Features') ylabel('Segment')
Примените предварительно обученную проекционную матрицу линейного дискриминантного анализа (LDA), чтобы уменьшить размерность x-векторов и затем визуализировать x-векторы с течением времени.
x = classifier.projMat*xvecs; figure(4) surf(x','EdgeColor','none') view([90,-90]) axis([1 size(x,1) 1 size(x,2)]) xlabel('Features') ylabel('Segment')
X-векторная система учится извлекать компактные представления (x-векторы) дикторов. Кластеризуйте векторы X, чтобы сгруппировать подобные области аудио с помощью агломеративной иерархической кластеризации (clusterdata
(Statistics and Machine Learning Toolbox)) или k-означает кластеризацию (kmeans
(Statistics and Machine Learning Toolbox). [2] предлагает использовать агломеративную наследственную кластеризацию с оценкой PLDA в качестве измерения расстояния. K-средних значений кластеризация с использованием косинусоидального счета подобия также обычно используется. Предположим, что ранее было известно количество динамиков в аудио. Установите максимальное количество кластеров в количестве известных динамиков + 1, чтобы фон был кластеризован независимо.
knownNumberOfSpeakers = numel(unique(groundTruth.Label)); maxclusters = knownNumberOfSpeakers + 1; clusterMethod = 'agglomerative - PLDA scoring'; switch clusterMethod case 'agglomerative - PLDA scoring' T = clusterdata (x ','Criterion','distance','distance', @ (a, b) helperPLDAScorer (a, b, классификатор),'linkage','average','maxclust', максимальные кластеры); case 'agglomerative - CSS scoring' T = clusterdata (x ','Criterion','distance','distance','cosine','linkage','average','maxclust', максимальные кластеры); case 'kmeans - CSS scoring' T = kmeans (x ', максимальные кластеры,'Distance','cosine'); end
Постройте график кластерных решений с течением времени.
figure(5) tiledlayout(2,1) nexttile plot(t,audioIn) axis tight ylabel('Amplitude') xlabel('Time (s)') nexttile plot(T) axis tight ylabel('Cluster Index') xlabel('Segment')
Чтобы изолировать сегменты речи, соответствующие кластерам, сопоставьте сегменты с аудио выборок. Постройте график результатов.
mask = zeros(size(audioIn,1),1); start = round((segmentDur/2)*fs); segmentHopSamples = round(segmentHopDur*fs); mask(1:start) = T(1); start = start + 1; for ii = 1:numel(T) finish = start + segmentHopSamples; mask(start:start + segmentHopSamples) = T(ii); start = finish + 1; end mask(finish:end) = T(end); figure(6) tiledlayout(2,1) nexttile plot(t,audioIn) axis tight nexttile plot(t,mask) ylabel('Cluster Index') axis tight xlabel('Time (s)')
Использование detectSpeech
для определения речевых областей. Использование sigroi2binmask
для преобразования речевых областей в маску обнаружения двоичной голосовой активности (VAD). Функции detectSpeech
второй раз без каких-либо аргументов для построения графика обнаруженных речевых областей.
mergeDuration = 0.5; VADidx = detectSpeech (audioIn, fs,'MergeDistance', fs * mergeDuration); VADmask = sigroi2binmask (VADidx, numel (audioIn)); рисунок (7) detectSpeech (audioIn, fs,'MergeDistance', fs * mergeDuration)
Примените маску VAD к маске динамика и постройте график результатов. Индекс кластера 0 указывает на область отсутствия речи.
mask = mask.*VADmask; figure(8) tiledlayout(2,1) nexttile plot(t,audioIn) axis tight nexttile plot(t,mask) ylabel('Cluster Index') axis tight xlabel('Time (s)')
В этом примере вы предполагаете, что каждая обнаруженная речевая область принадлежит одному динамику. Если в области речи присутствует более двух меток, объедините их с наиболее часто встречающейся меткой.
maskLabels = zeros(size(VADidx,1),1); for ii = 1:size(VADidx,1) maskLabels(ii) = mode(mask(VADidx(ii,1):VADidx(ii,2)),'all'); mask(VADidx(ii,1):VADidx(ii,2)) = maskLabels(ii); end figure(9) tiledlayout(2,1) nexttile plot(t,audioIn) axis tight nexttile plot(t,mask) ylabel('Cluster Index') axis tight xlabel('Time (s)')
Подсчитайте количество остальных кластеров динамиков.
uniqueSpeakerClusters = unique(maskLabels); numSpeakers = numel(uniqueSpeakerClusters)
numSpeakers = 5
Создайте signalMask
объект, а затем постройте график кластеров динамиков. Пометьте график метками основной истины. Метки кластера закодированы клавишей справа от графика. Истинные метки напечатаны над графиком.
msk = signalMask(table(VADidx,categorical(maskLabels))); figure(10) plotsigroi(msk,audioIn,true) axis([0 numel(audioIn) -1 1]) trueLabel = groundTruth.Label; for ii = 1:numel(trueLabel) text(VADidx(ii,1),1.1,trueLabel(ii),'FontWeight','bold') end
Выберите кластер для проверки и последующего использования binmask
для изоляции динамика. Постройте график изолированного речевого сигнала и прослушайте кластер динамиков.
speakerToInspect = 2; cutOutSilenceFromAudio = true; bmsk = binmask (msk, numel (audioIn)); audioToPlay = audioIn; if cutOutSilenceFromAudio audioToPlay (~ bmsk (:, speakerToInspect)) = []; end звук (audioToPlay, fs) рисунок (11) tiledlayout (2,1) nexttile график (t, audioIn) ось tight ylabel ('Amplitude') nexttile график (t, audioIn. * bmsk (:, speakerToInspect)) ось tight xlabel ('Time (s)') ylabel ('Amplitude') заголовок ("Speaker Group "+ speakerToInspect)
Общей метрикой для систем диаризации динамика является вероятность ошибки диаризации (DER). DER является суммой частоты пропусков (классифицируя речь как неречевую), частоты ложных предупреждений (классифицируя неречевую речь как речь) и частоты ошибок говорящего (запутывая речь одного говорящего для другого).
В этом простом примере частота пропусков и частота ложных предупреждений являются тривиальными проблемами. Вы оцениваете только частоту ошибок диктора.
Сопоставьте каждый истинный динамик с соответствующим наиболее подходящим кластером динамиков. Чтобы определить вероятность ошибки динамика, подсчитайте количество несоответствий между истинными динамиками и наиболее подходящими кластерами динамиков, а затем разделите на количество истинных регионов динамика.
uniqueLabels = unique(trueLabel); guessLabels = maskLabels; uniqueGuessLabels = unique(guessLabels); totalNumErrors = 0; for ii = 1:numel(uniqueLabels) isSpeaker = uniqueLabels(ii)==trueLabel; minNumErrors = inf; for jj = 1:numel(uniqueGuessLabels) groupCandidate = uniqueGuessLabels(jj) == guessLabels; numErrors = nnz(isSpeaker-groupCandidate); if numErrors < minNumErrors minNumErrors = numErrors; bestCandidate = jj; end minNumErrors = min(minNumErrors,numErrors); end uniqueGuessLabels(bestCandidate) = []; totalNumErrors = totalNumErrors + minNumErrors; end SpeakerErrorRate = totalNumErrors/numel(trueLabel)
SpeakerErrorRate = 0
[1] Snyder, David, et al. «X-Vectors: Robust DNN Embeddings for Speaker Recognition». 2018 IEEE International Conference on Acoustics, Speech and Signal Processing (ICASSP), IEEE, 2018, pp. 5329-33. DOI.org (Crossref), doi:10.1109/ICASSP.2018.8461375.
[2] Sell, G., Snyder, D., McCree, A., Garcia-Romero, D., Villalba, J., Maciejewski, M., Manohar, V., Dehak, N., Povey, D., Watanabe, S. Proc. Interspeech 2018, 2808-2812, DOI: 10.21437/Interspeech.2018-1893.