Динамик diarization является процессом разделения звукового сигнала в сегменты согласно идентичности динамика. Это отвечает на вопрос, "кто говорил когда" без предварительных знаний динамиков и, в зависимости от приложения без предварительных знаний количества динамиков.
У динамика diarization есть много приложений, включая: улучшая речевую запись путем структурирования текста согласно активной акустической системе, видео вводу субтитров, извлечению содержимого (что говорила Джейн?) и динамик, рассчитывающий (сколько динамиков присутствовало на встрече?).
В этом примере вы выполняете динамик diarization использование предварительно обученной системы 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
- audioFeatureExtractor
возразите, чтобы извлечь mel частоту cepstral коэффициенты (MFCCs).
factors
- struct, содержащий среднее и стандартное отклонение MFCCs, определяется из представительного набора данных. Эти факторы используются, чтобы стандартизировать MFCCs.
extractor
- struct, содержащий параметры и состояние нейронной сети, обученной, чтобы извлечь x-векторы. xvecModel
функция выполняет фактическую экстракцию x-вектора. 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 = вокруг (segmentDur/featureVectorHopDur); segmentHop = вокруг (segmentHopDur/featureVectorHopDur); idx = 1:segmentLength; featuresSegmented = []; while idx (конец) <размер (функции, 1) featuresSegmented = кошка (3, featuresSegmented, функции (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', 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, фс,'MergeDistance', fs*mergeDuration); VADmask = sigroi2binmask (VADidx, numel (audioIn)); фигура (7) detectSpeech (audioIn, фс,'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, фс) фигура (11) tiledlayout (2,1) nexttile график (t, audioIn) ось tight yLabel 'Amplitude') nexttile график (t, audioIn. *bmsk (: speakerToInspect)) ось tight xlabel'Time (s)') yLabel 'Amplitude') заголовок"Speaker Group "+speakerToInspect)
Общая метрика для динамика diarization системы является коэффициентом ошибок diarization (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] Снайдер, Дэвид, и др. “X-векторы: Устойчивые Вложения DNN для Распознавания Динамика”. 2 018 Международных конференций IEEE по вопросам Акустики, Речи и Обработки сигналов (ICASSP), IEEE, 2018, стр 5329–33. DOI.org (Crossref), doi:10.1109/ICASSP.2018.8461375.
[2] Продайте, G., Снайдер, D., Маккри, A., Гарсия-Ромеро, D., Вильяльба, J., Мациейевский, M., Manohar, V., Dehak, N., Povey, D., Ватанабе, S., Khudanpur, S. (2018) Diarization Тверд: Некоторые События и Уроки, Извлеченные для Команды JHU во Вступительной проблеме DIHARD. Proc. Межречь 2018, 2808-2812, DOI: 10.21437/Interspeech.2018-1893.