Диаризация громкоговорителя - это процесс разделения аудиосигнала на сегменты в соответствии с идентичностью громкоговорителя. Он отвечает на вопрос «кто говорил, когда» без предварительного знания говорящих и, в зависимости от применения, без предварительного знания количества говорящих.
Диаризация говорящих имеет множество применений, в том числе: усиление транскрипции речи путём структурирования текста по активному говорящему, субтитры видео, извлечение контента (что сказала Джейн?) и подсчёт говорящих (сколько говорящих присутствовало на собрании?).
В этом примере выполняется диаризация динамиков с использованием предварительно обученной системы x-векторов [1] для характеристики областей аудио и агломеративной иерархической кластеризации (AHC) для группирования аналогичных областей аудио [2]. Сведения о том, как определялась и обучалась система x-vector, см. в разделе Распознавание говорящих с помощью 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-vector, см. в разделе Распознавание говорящих с помощью x-векторов.
Загрузите легкую предварительно обученную систему x-векторов. X-векторная система состоит из:
afe один audioFeatureExtractor изобретение позволяет получить частотные кепстральные коэффициенты (МФЦК).
factors - структура, содержащая среднее и стандартное отклонения МФКЦ, определенные из репрезентативного набора данных. Эти факторы используются для стандартизации MFCC.
extractor - структура, содержащая параметры и состояние нейронной сети, обученной извлекать х-векторы. xvecModel функция выполняет фактическое извлечение x-вектора. xvecModel при открытии этого примера функция помещается в текущую папку.
classifier - структура, содержащая обученную проекционную матрицу для уменьшения размерности 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(features,1) featuresSegmented = cat(3,featuresSegmented,features(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 (Статистика и инструментарий машинного обучения). [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,classifier),'linkage','average','maxclust',maxclusters); case 'agglomerative - CSS scoring' T = clusterdata(x','Criterion','distance','distance','cosine','linkage','average','maxclust',maxclusters); case 'kmeans - CSS scoring' T = kmeans(x',maxclusters,'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)); figure(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 sound(audioToPlay,fs) figure(11) tiledlayout(2,1) nexttile plot(t,audioIn) axis tight ylabel('Amplitude') nexttile plot(t,audioIn.*bmsk(:,speakerToInspect)) axis tight xlabel('Time (s)') ylabel('Amplitude') title("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] Снайдер, Дэвид, и др. Международная конференция IEEE 2018 по акустике, обработке речи и сигналов (ICASSP), IEEE, 2018, стр. 5329-33. DOI.org (Crossref), doi:10.1109/ICASSP.2018.8461375.
[2] Продавать, Г., Снайдер, Д., Маккри, А., Гарсия-Ромеро, Д., Вильяльба, Дж., Мацеевский, М., Манохар, В., Дехак, Н., Повей, Д., Ватанабе, С., Худанпур, С. ( Proc. Interspeech 2018, 2808-2812, DOI: 10.21437/Interspeech.2018-1893.