Распознавание динамика Используя x-векторы

Распознавание динамика отвечает на вопрос, "Кто говорит?". Распознавание динамика обычно делится на две задачи: идентификация динамика и верификация динамика. В идентификации динамика динамик распознан путем сравнения их речи в замкнутом множестве шаблонов. В верификации динамика динамик распознан путем сравнения вероятности, что речь принадлежит конкретному динамику против предопределенного порога. Традиционные методы машинного обучения выполняют хорошо в этих задачах в идеальных условиях. Для примеров идентификации динамика с помощью традиционных методов машинного обучения смотрите, что Идентификация Динамика Использует Тангаж и MFCC и Верификацию Динамика Используя i-векторы. Audio Toolbox™ обеспечивает ivectorSystem который инкапсулирует способность обучить систему i-вектора, зарегистрировать докладчиков или другие аудио метки, оценить систему для порога решения, и идентифицировать или проверить динамики или другие аудио метки.

В неблагоприятных условиях подход глубокого обучения x-векторов, как показывали, достиг современных результатов для многих сценариев и приложений [1]. Система x-вектора является эволюцией i-векторов, первоначально разработанных для задачи верификации динамика.

В этом примере вы разрабатываете систему x-вектора. Во-первых, вы обучаете нейронную сеть с временной задержкой (TDNN) выполнять идентификацию динамика. Затем вы обучаете традиционные бэкэнды x-vector-based системе верификации динамика: матрица проекции LDA и модель PLDA. Вы затем выполняете верификацию динамика с помощью TDNN и сокращения размерности бэкэнда и выигрыша. Системный бэкэнд x-вектора или классификатор, эквивалентен разработанный для систем i-вектора. Для получения дополнительной информации на бэкэнде, смотрите, что Верификация Динамика Использует i-векторы и ivectorSystem.

В Докладчике Диэризэйшне Используя x-векторы вы используете систему x-вектора, обученную в этом примере выполнять динамик diarization. Динамик diarization отвечает на вопрос, "Кто говорил когда?".

В этом примере вы найдете живые средства управления на настраиваемых параметрах. Изменение средств управления не повторно выполняет пример. Если вы изменяете управление, необходимо повторно выполнить пример.

Управление набором данных

Этот пример использует Базу данных Отслеживания Тангажа из Технологического университета Граца (PTDB-TUG) [2]. Набор данных состоит из 20 английских носителей языка, читающих 2 342 фонетически богатых предложения из корпуса TIMIT. Загрузите и извлеките набор данных. В зависимости от вашей системы, загружая и извлекая набор данных может занять приблизительно 1,5 часа.

url = 'https://www2.spsc.tugraz.at/databases/PTDB-TUG/SPEECH_DATA_ZIPPED.zip';
downloadFolder = tempdir;
datasetFolder = fullfile(downloadFolder,'PTDB-TUG');
if ~exist(datasetFolder,'dir')
    disp('Downloading PTDB-TUG (3.9 G) ...')
    unzip(url,datasetFolder)
end

Создайте audioDatastore возразите что точки против набора данных. Набор данных был первоначально предназначен для использования в отслеживающем тангаж обучении и оценке, и включает показания ларингографика и базовые решения тангажа. Используйте только исходные аудиозаписи.

ads = audioDatastore([fullfile(datasetFolder,"SPEECH DATA","FEMALE","MIC"),fullfile(datasetFolder,"SPEECH DATA","MALE","MIC")], ...
                     'IncludeSubfolders',true, ...
                     'FileExtensions','.wav');
fileNames = ads.Files;

Считайте звуковой файл из обучающего набора данных, слушайте его, и затем постройте его.

[audioIn,audioInfo] = read(ads);
fs = audioInfo.SampleRate;
t = (0:size(audioIn,1)-1)/fs;
sound(audioIn,fs)
plot(t,audioIn)
xlabel('Time (s)')
ylabel('Amplitude')
axis([0 t(end) -1 1])
title('Sample Utterance from Training Set')

Имена файлов содержат идентификаторы динамика. Декодируйте имена файлов, чтобы установить метки на audioDatastore объект.

speakerIDs = extractBetween(fileNames,'mic_','_');
ads.Labels = categorical(speakerIDs);

Разделите audioDatastore объект в пять наборов:

  • adsTrain - Содержит набор обучающих данных для классификатора бэкэнда и TDNN.

  • adsValidation - Содержит набор валидации, чтобы оценить процесс обучения TDNN.

  • adsTest - Содержит набор тестов, чтобы оценить эффективность TDNN для идентификации динамика.

  • adsEnroll - Содержит набор приема, чтобы оценить ошибочный компромисс обнаружения системы x-вектора для верификации динамика.

  • adsDET - Содержит набор оценки, используемый, чтобы определить ошибочный компромисс обнаружения системы x-вектора для верификации динамика.

developmentLabels = categorical(["M01","M02","M03","M04","M06","M07","M08","M09","F01","F02","F03","F04","F06","F07","F08","F09"]);
evaluationLabels = categorical(["M05","M010","F05","F010"]);
adsTrain = subset(ads,ismember(ads.Labels,developmentLabels));
[adsTrain,adsValidation,adsTest] = splitEachLabel(adsTrain,0.8,0.1,0.1);
adsEvaluate = subset(ads,ismember(ads.Labels,evaluationLabels));
[adsEnroll,adsDET] = splitEachLabel(adsEvaluate,3);

Отобразите распределения метки получившегося audioDatastore объекты.

countEachLabel(adsTrain)
ans=16×2 table
    Label    Count
    _____    _____

     F01      189 
     F02      189 
     F03      189 
     F04      189 
     F06      189 
     F07      189 
     F08      187 
     F09      189 
     M01      189 
     M02      189 
     M03      189 
     M04      189 
     M06      189 
     M07      189 
     M08      189 
     M09      189 

countEachLabel(adsValidation)
ans=16×2 table
    Label    Count
    _____    _____

     F01      23  
     F02      23  
     F03      23  
     F04      23  
     F06      23  
     F07      23  
     F08      24  
     F09      23  
     M01      23  
     M02      23  
     M03      23  
     M04      23  
     M06      23  
     M07      23  
     M08      23  
     M09      23  

countEachLabel(adsTest)
ans=16×2 table
    Label    Count
    _____    _____

     F01      24  
     F02      24  
     F03      24  
     F04      24  
     F06      24  
     F07      24  
     F08      23  
     F09      24  
     M01      24  
     M02      24  
     M03      24  
     M04      24  
     M06      24  
     M07      24  
     M08      24  
     M09      24  

countEachLabel(adsEnroll)
ans=2×2 table
    Label    Count
    _____    _____

     F05       3  
     M05       3  

countEachLabel(adsDET)
ans=2×2 table
    Label    Count
    _____    _____

     F05      233 
     M05      233 

Можно уменьшать ошибочные наборы данных компромисса обучения и обнаружения, используемые в этом примере, чтобы ускорить время выполнения за счет эффективности. В общем случае сокращение набора данных является хорошей практикой для разработки и отладки.

speedUpExample = false;
if speedUpExample
    adsTrain = splitEachLabel (adsTrain, 20);
    adsDET = splitEachLabel (adsDET, 20);
end

Извлечение признаков

Создайте audioFeatureExtractor возразите, чтобы извлечь 30 MFCCs из окон Hann на 30 мс с транзитным участком на 10 мс. Частота дискретизации набора данных составляет 48 кГц, но вы проредите набор данных к 16 кГц. Спроектируйте audioFeatureExtractor принимая желаемую частоту дискретизации, 16 кГц.

desiredFs = 16e3;

windowDuration = 0.03;
hopDuration = 0.005;
windowSamples = вокруг (windowDuration*desiredFs);
hopSamples = вокруг (hopDuration*desiredFs);
overlapSamples = windowSamples - hopSamples;
numCoeffs = 30;
afe = audioFeatureExtractor ( ...
    'SampleRate', desiredFs, ...
    'Window', hann (windowSamples,'periodic'), ...
    'OverlapLength', overlapSamples, ...
    ...
    'mfcc'TRUE, ...
    'pitch'ложь, ...
    'spectralEntropy'ложь, ...
    'spectralFlux'ложь;
setExtractorParams (afe,'mfcc','NumCoeffs', numCoeffs)

Downsample аудиоданные к 16 кГц и извлечение показывает от наборов данных обучения и валидации. Используйте обучающий набор данных, чтобы определить среднее и стандартное отклонение функций, чтобы выполнить стандартизацию функции. Функция поддержки, xVectorPreprocessBatch, использует ваш параллельный пул по умолчанию, если у вас есть Parallel Computing Toolbox™.

adsTrain = transform(adsTrain,@(x)resample(x,desiredFs,fs));
[features,YTrain] = xVectorPreprocessBatch(adsTrain,afe);
Starting parallel pool (parpool) using the 'local' profile ...
Connected to the parallel pool (number of workers: 6).
featuresMAT = cat(1,features{:});
numFeatures = size(featuresMAT,2);
factors = struct('Mean',mean(featuresMAT,1),'STD',std(featuresMAT,1));

XTrain = cellfun(@(x)(x-factors.Mean)./factors.STD,features,'UniformOutput',false);
XTrain = cellfun(@(x)x-mean(x(:)),XTrain,'UniformOutput',false);

adsValidation = transform(adsValidation,@(x)resample(x,desiredFs,fs));
[XValidation,YValidation] = xVectorPreprocessBatch(adsTrain,afe,'Factors',factors);

classes = unique(YTrain);
numClasses = numel(classes);

Модель Извлечения признаков x-вектора

В этом примере вы реализуете модель [1] экстрактора функции x-вектора с помощью парадигмы функционального программирования, обеспеченной Deep Learning Toolbox™. Эта парадигма включает полный контроль над проектом вашей модели глубокого обучения. Для примера на функциональном программировании в Deep Learning Toolbox смотрите Функцию Градиентов Модели Define для Пользовательского Учебного Цикла (Deep Learning Toolbox). Функция поддержки, xvecModel, помещается в вашу текущую папку, когда вы открываете этот пример. Отобразите содержимое xvecModel функция.

type('xvecModel')
function [Y,state] = xvecModel(X,parameters,state,nvargs)
% This function is only for use in this example. It may be changed or
% removed in a future release.
arguments
    X
    parameters
    state
    nvargs.DoTraining = false
    nvargs.OutputLayer = 'final'
    nvargs.Dropout = 0.2;
end


% LAYER 1 ----------------------------------------------------------------
Y = dlconv(X,parameters.conv1.Weights,parameters.conv1.Bias,'DilationFactor',1);
if nvargs.DoTraining
    [Y,state.batchnorm1.TrainedMean,state.batchnorm1.TrainedVariance] = ...
        batchnorm(Y, ...
        parameters.batchnorm1.Offset, ...
        parameters.batchnorm1.Scale, ...
        state.batchnorm1.TrainedMean, ...
        state.batchnorm1.TrainedVariance);
    Y(rand(size(Y))<nvargs.Dropout) = 0;
else
    Y = batchnorm(Y, ...
        parameters.batchnorm1.Offset, ...
        parameters.batchnorm1.Scale, ...
        state.batchnorm1.TrainedMean, ...
        state.batchnorm1.TrainedVariance);
end
if nvargs.OutputLayer==1
    return
end
Y = relu(Y);
% -------------------------------------------------------------------------


% LAYER 2 -----------------------------------------------------------------
Y = dlconv(Y,parameters.conv2.Weights,parameters.conv2.Bias,'DilationFactor',2);
if nvargs.DoTraining
    [Y,state.batchnorm2.TrainedMean,state.batchnorm2.TrainedVariance] = ...
        batchnorm(Y, ...
        parameters.batchnorm2.Offset, ...
        parameters.batchnorm2.Scale, ...
        state.batchnorm2.TrainedMean, ...
        state.batchnorm2.TrainedVariance);
    Y(rand(size(Y))<nvargs.Dropout) = 0;
else
    Y = batchnorm(Y, ...
        parameters.batchnorm2.Offset, ...
        parameters.batchnorm2.Scale, ...
        state.batchnorm2.TrainedMean, ...
        state.batchnorm2.TrainedVariance);
end
if nvargs.OutputLayer==2
    return
end
Y = relu(Y);
% -------------------------------------------------------------------------


% LAYER 3 -----------------------------------------------------------------
Y = dlconv(Y,parameters.conv3.Weights,parameters.conv3.Bias,'DilationFactor',3);
if nvargs.DoTraining
    [Y,state.batchnorm3.TrainedMean,state.batchnorm3.TrainedVariance] = ...
        batchnorm(Y, ...
        parameters.batchnorm3.Offset, ...
        parameters.batchnorm3.Scale, ...
        state.batchnorm3.TrainedMean, ...
        state.batchnorm3.TrainedVariance);
    Y(rand(size(Y))<nvargs.Dropout) = 0;
else
    Y = batchnorm(Y, ...
        parameters.batchnorm3.Offset, ...
        parameters.batchnorm3.Scale, ...
        state.batchnorm3.TrainedMean, ...
        state.batchnorm3.TrainedVariance);
end
if nvargs.OutputLayer==3
    return
end
Y = relu(Y);
% -------------------------------------------------------------------------


% LAYER 4 -----------------------------------------------------------------
Y = dlconv(Y,parameters.conv4.Weights,parameters.conv4.Bias,'DilationFactor',1);
if nvargs.DoTraining
    [Y,state.batchnorm4.TrainedMean,state.batchnorm4.TrainedVariance] = ...
        batchnorm(Y, ...
        parameters.batchnorm4.Offset, ...
        parameters.batchnorm4.Scale, ...
        state.batchnorm4.TrainedMean, ...
        state.batchnorm4.TrainedVariance);
    Y(rand(size(Y))<nvargs.Dropout) = 0;
else
    Y = batchnorm(Y, ...
        parameters.batchnorm4.Offset, ...
        parameters.batchnorm4.Scale, ...
        state.batchnorm4.TrainedMean, ...
        state.batchnorm4.TrainedVariance);
end
if nvargs.OutputLayer==4
    return
end
Y = relu(Y);
% -------------------------------------------------------------------------


% LAYER 5 -----------------------------------------------------------------
Y = dlconv(Y,parameters.conv5.Weights,parameters.conv5.Bias,'DilationFactor',1);
if nvargs.DoTraining
    [Y,state.batchnorm5.TrainedMean,state.batchnorm5.TrainedVariance] = ...
        batchnorm(Y, ...
        parameters.batchnorm5.Offset, ...
        parameters.batchnorm5.Scale, ...
        state.batchnorm5.TrainedMean, ...
        state.batchnorm5.TrainedVariance);
    Y(rand(size(Y))<nvargs.Dropout) = 0;
else
    Y = batchnorm(Y, ...
        parameters.batchnorm5.Offset, ...
        parameters.batchnorm5.Scale, ...
        state.batchnorm5.TrainedMean, ...
        state.batchnorm5.TrainedVariance);
end
if nvargs.OutputLayer==5
    return
end
Y = relu(Y);
% -------------------------------------------------------------------------


% Layer 6: Statistical pooling --------------------------------------------
if nvargs.DoTraining
    Y = Y + 0.0001*rand(size(Y));
end
Y = cat(2,mean(Y,1),std(Y,[],1));
if nvargs.OutputLayer==6
    return
end
% -------------------------------------------------------------------------

% LAYER 7 -----------------------------------------------------------------
Y = fullyconnect(Y,parameters.fc7.Weights,parameters.fc7.Bias);
if nvargs.DoTraining
    [Y,state.batchnorm7.TrainedMean,state.batchnorm6.TrainedVariance] = ...
        batchnorm(Y, ...
        parameters.batchnorm7.Offset, ...
        parameters.batchnorm7.Scale, ...
        state.batchnorm7.TrainedMean, ...
        state.batchnorm7.TrainedVariance);
     Y(rand(size(Y))<nvargs.Dropout) = 0;
else
        Y = batchnorm(Y, ...
            parameters.batchnorm7.Offset, ...
            parameters.batchnorm7.Scale, ...
            state.batchnorm7.TrainedMean, ...
            state.batchnorm7.TrainedVariance);
end
if nvargs.OutputLayer==7
    return
end
Y = relu(Y);
% -------------------------------------------------------------------------

% LAYER 8 -----------------------------------------------------------------
Y = fullyconnect(Y,parameters.fc8.Weights,parameters.fc8.Bias);
if nvargs.DoTraining
    [Y,state.batchnorm8.TrainedMean,state.batchnorm8.TrainedVariance] = ...
        batchnorm(Y, ...
        parameters.batchnorm8.Offset, ...
        parameters.batchnorm8.Scale, ...
        state.batchnorm8.TrainedMean, ...
        state.batchnorm8.TrainedVariance);
    Y(rand(size(Y))<nvargs.Dropout) = 0;
else
        Y = batchnorm(Y, ...
            parameters.batchnorm8.Offset, ...
            parameters.batchnorm8.Scale, ...
            state.batchnorm8.TrainedMean, ...
            state.batchnorm8.TrainedVariance);
end
if nvargs.OutputLayer==8
    return
end
Y = relu(Y);
% -------------------------------------------------------------------------

% LAYER 9 (softmax)--------------------------------------------------------
Y = fullyconnect(Y,parameters.fc9.Weights,parameters.fc9.Bias);
if nvargs.OutputLayer==9
    return
end
Y = softmax(Y);
% -------------------------------------------------------------------------
end

Инициализируйте структуры, которые содержат параметры и состояние модели TDNN с помощью функции поддержки, initializexVecModelLayers. [1] задает количество фильтров между большинством слоев, включая слой встраивания, как 512. Поскольку набор обучающих данных в этом примере мал, используйте размер представления 128.

numFilters = 128;
[параметры, состояние] = initializexVecModelLayers (numFeatures, numFilters, numClasses)
parameters = struct with fields:
         conv1: [1×1 struct]
    batchnorm1: [1×1 struct]
         conv2: [1×1 struct]
    batchnorm2: [1×1 struct]
         conv3: [1×1 struct]
    batchnorm3: [1×1 struct]
         conv4: [1×1 struct]
    batchnorm4: [1×1 struct]
         conv5: [1×1 struct]
    batchnorm5: [1×1 struct]
           fc7: [1×1 struct]
    batchnorm7: [1×1 struct]
           fc8: [1×1 struct]
    batchnorm8: [1×1 struct]
           fc9: [1×1 struct]

state = struct with fields:
    batchnorm1: [1×1 struct]
    batchnorm2: [1×1 struct]
    batchnorm3: [1×1 struct]
    batchnorm4: [1×1 struct]
    batchnorm5: [1×1 struct]
    batchnorm7: [1×1 struct]
    batchnorm8: [1×1 struct]

Таблица суммирует архитектуру сети, описанной в [1] и реализованный в этом примере. T является общим количеством систем координат (характеристические векторы в зависимости от времени) в звуковом сигнале. N является количеством классов (динамики) в наборе обучающих данных.

Обучите модель

Используйте arrayDatastore и minibatchqueue (Deep Learning Toolbox), чтобы создать мини-пакетную очередь для обучающих данных. Если вы имеете доступ к вычислить графическому процессору, устанавливаете ExecutionEnvironment к gpu. В противном случае установите ExecutionEnvironment к cpu.

ExecutionEnvironment = 'gpu';

dsXTrain = arrayDatastore (XTrain,'OutputType','same');
dsYTrain = arrayDatastore (YTrain','OutputType','cell');

dsTrain = объединение (dsXTrain, dsYTrain);

miniBatchSize = 128;
numOutputs = 2;
mbq = minibatchqueue (dsTrain, numOutputs, ...
    'MiniBatchSize', miniBatchSize, ...
    'MiniBatchFormat',{'SCB','CB'}, ...
    'MiniBatchFcn',@preprocessMiniBatch, ...
    'OutputEnvironment'Среда выполнения;

Установите количество циклов обучения, начальная буква изучают уровень, изучить период отбрасывания уровня, изучить фактор отбрасывания уровня и валидации в эпоху.

numEpochs = 6;

learnRate = 0.001;
gradDecay = 0.5;
sqGradDecay = 0.999;
trailingAvg = [];
trailingAvgSq = [];

LearnRateDropPeriod = 2;
LearnRateDropFactor = 0.1;

ValidationsPerEpoch = 2;

iterationsPerEpoch = пол (numel (XTrain)/miniBatchSize);
iterationsPerValidation = вокруг (iterationsPerEpoch/ValidationsPerEpoch);

При выполнении валидации, в то время как обучение, предварительно обработайте набор валидации для более быстрой эффективности в цикле.

if ValidationsPerEpoch ~= 0
    [XValidation,YValidation] = preprocessMiniBatch(XValidation,{YValidation});
    XValidation = dlarray(XValidation,'SCB');
    if strcmp(ExecutionEnvironment,'gpu')
        XValidation = gpuArray(XValidation);
    end
end

Чтобы отобразить прогресс обучения, инициализируйте объект progressPlotter поддержки. Объект поддержки, progressPlotter, помещается в вашу текущую папку, когда вы открываете этот пример.

Запустите учебный цикл.

pp = progressPlotter(categories(classes));

iteration = 0;
for epoch = 1:numEpochs
    
    % Shuffle mini-batch queue
    shuffle(mbq)
    
    while hasdata(mbq)
        
        % Update iteration counter
        iteration = iteration + 1;
        
        % Get mini-batch from mini-batch queue
        [dlX,Y] = next(mbq);

        % Evaluate the model gradients, state, and loss using dlfeval and the modelGradients function
        [gradients,state,loss,predictions] = dlfeval(@modelGradients,dlX,Y,parameters,state);

        % Update the network parameters using the Adam optimizer
        [parameters,trailingAvg,trailingAvgSq] = adamupdate(parameters,gradients, ...
            trailingAvg,trailingAvgSq,iteration,learnRate,gradDecay,sqGradDecay,eps('single'));

        % Update the training progress plot
        updateTrainingProgress(pp,'Epoch',epoch,'Iteration',iteration,'LearnRate',learnRate,'Predictions',predictions,'Targets',Y,'Loss',loss)

        % Update the validation plot
        if ~rem(iteration,iterationsPerValidation)
            
            % Pass validation data through x-vector model
            predictions = xvecModel(XValidation,parameters,state,'DoTraining',false);

            % Update plot
            updateValidation(pp,'Iteration',iteration,'Predictions',predictions,'Targets',YValidation)
        end
    end
    
    % Update learn rate
    if rem(epoch,LearnRateDropPeriod)==0
        learnRate = learnRate*LearnRateDropFactor;
    end
    
end

Оцените модель TDNN

Оцените точность распознавания динамика TDNN с помощью протянутого набора тестов. Для каждого файла в наборе тестов:

  1. Передискретизируйте аудио к 16 кГц

  2. Извлеките функции с помощью xVectorPreprocess поддерживание функции. Функции возвращены в массивах ячеек, где число элементов в массиве ячеек равно количеству отдельных речевых сегментов.

  3. Чтобы получить предсказанную марку докладчика, передайте каждый сегмент через модель.

  4. Если больше чем один речевой сегмент присутствовал в звуковом сигнале, насчитайте предсказания.

  5. Используйте onehotdecode (Deep Learning Toolbox), чтобы преобразовать предсказание в метку.

Используйте confusionchart (Deep Learning Toolbox), чтобы оценить производительность системы.

predictedLabels = classes;
predictedLabels(:) = [];

for sample = 1:numel(adsTest.Files)
    [audioIn,xInfo] = read(adsTest);
    audioIn = resample(audioIn,desiredFs,fs);
    f = xVectorPreprocess(audioIn,afe,'Factors',factors,'MinimumDuration',0);
    predictions = zeros(numel(classes),numel(f));
    for segment = 1:numel(f)
        dlX = dlarray(f{segment},'SCB');
        predictions(:,segment) = extractdata(xvecModel(dlX,parameters,state,'DoTraining',false));
    end 
    predictedLabels(sample) = onehotdecode(mean(predictions,2),categories(classes),1);
end
trueLabels = adsTest.Labels;
accuracy = mean(trueLabels==predictedLabels');

figure('Units','normalized','Position',[0.2 0.2 0.6 0.6]);
confusionchart(trueLabels,predictedLabels', ...
    'ColumnSummary','column-normalized', ...
    'RowSummary','row-normalized', ...
    'Title',sprintf('x-vector Speaker Recognition\nAccuracy = %0.2f%%',accuracy*100))

Обучите Системный Бэкэнд x-вектора

В системе x-вектора для верификации динамика TDNN, который вы только обучили, используется, чтобы вывести слой встраивания. Выход от слоя встраивания (слой 7 в этом примере, после нормализации партии. и перед активацией) является 'x-векторами' в системе x-вектора.

Бэкэнд (или классификатор) системы x-вектора совпадает с бэкэндом системы i-вектора. Для получения дополнительной информации на алгоритмах, смотрите ivectorSystem и Верификация Динамика Используя i-векторы.

Извлеките x-векторы из состава. Функция поддержки, xvecModel, имеет дополнительную пару "имя-значение" 'OutputLayer'. Установите 'OutputLayer' к 7 возвращать выходной параметр седьмого слоя. В [1], выход или от слоя 7 или от слоя 8 предлагается в качестве возможных слоев встраивания.

xvecs = zeros(numFilters,numel(YTrain));
for sample = 1:size(YTrain,2)
    dlX = dlarray(XTrain{sample},'SCB');
    
    embedding = xvecModel(dlX,parameters,state,'DoTraining',false,'OutputLayer',7);
    xvecs(:,sample) = extractdata(embedding);
end

Создайте матрицу проекции линейного дискриминантного анализа (LDA), чтобы уменьшать размерность x-векторов к 32. LDA пытается минимизировать отклонение внутрикласса и максимизировать отклонение между динамиками.

numEigenvectors = 32;
projMat = helperTrainProjectionMatrix (xvecs, YTrain, numEigenvectors);

Примените матрицу проекции LDA к x-векторам.

xvecs = projMat*xvecs;

Обучите модель G-PLDA выполнять выигрыш.

numIterations = 3;
numDimensions = 32;
plda = helperTrainPLDA (xvecs, YTrain, numIterations, numDimensions);

Оцените Систему x-вектора

Системы верификации динамика проверяют, что динамик - то, кем они подразумевают быть. Прежде чем динамик может быть проверен, они должны быть зарегистрированы в системе. Прием в систему означает, что система имеет представление x-вектора шаблона динамика.

Зарегистрируйте докладчиков

Извлеките x-векторы из протянутого набора данных, adsEnroll. Установите минимальную длительность аудио сегмента к эквиваленту 15 транзитных участков функций (минимальный номер, требуемый вычислить x-векторы).

minDur = (numel(afe.Window)+14*(numel(afe.Window)-afe.OverlapLength)+1)/desiredFs;

xvecs = zeros(numEigenvectors,numel(adsEnroll.Files));
reset(adsEnroll)
for sample = 1:numel(adsEnroll.Files)
    [audioIn,xInfo] = read(adsEnroll);
    audioIn = resample(audioIn,desiredFs,fs);
    f = xVectorPreprocess(audioIn,afe,'Factors',factors,'MinimumDuration',minDur);
    embeddings = zeros(numFilters,numel(f));
    for segment = 1:numel(f)
        dlX = dlarray(f{segment},'SCB');

        embeddings(:,segment) = extractdata(xvecModel(dlX,parameters,state,'DoTraining',false,'OutputLayer',7));
    end 
    xvecs(:,sample) = mean(projMat*embeddings,2);
end

Создайте x-векторы шаблона для каждого динамика путем усреднения x-векторов из отдельных динамиков через файлы приема.

labels = adsEnroll.Labels;
uniqueLabels = unique(labels);
atable = cell2table(cell(0,2),'VariableNames',{'xvector','NumSamples'});
for ii = 1:numel(uniqueLabels)
    idx = uniqueLabels(ii)==labels;
    wLocalMean = mean(xvecs(:,idx),2);
    localTable = table({wLocalMean},(sum(idx)), ...
        'VariableNames',{'xvector','NumSamples'}, ...
        'RowNames',string(uniqueLabels(ii)));
    atable = [atable;localTable]; %#ok<AGROW>
end
enrolledLabels = atable
enrolledLabels=2×2 table
              xvector       NumSamples
           _____________    __________

    F05    {32×1 double}        3     
    M05    {32×1 double}        3     

Системы верификации динамика требуют, чтобы вы установили порог, который балансирует вероятность ложного принятия (FA) и вероятность ложного отклонения (FR), согласно требованиям вашего приложения. Чтобы определить порог, который удовлетворяет ваши требования FA/FR, оцените ошибочный компромисс обнаружения системы.

xvecs = zeros(numEigenvectors,numel(adsDET.Files));
reset(adsDET)
for sample = 1:numel(adsDET.Files)
    [audioIn,xInfo] = read(adsDET);
    audioIn = resample(audioIn,desiredFs,fs);
    f = xVectorPreprocess(audioIn,afe,'Factors',factors,'MinimumDuration',minDur);
    embeddings = zeros(numFilters,numel(f));
    for segment = 1:numel(f)
        dlX = dlarray(f{segment},'SCB');
        embeddings(:,segment) = extractdata(xvecModel(dlX,parameters,state,'DoTraining',false,'OutputLayer',7));
    end 
    xvecs(:,sample) = mean(projMat*embeddings,2);
end
labels = adsDET.Labels;
detTable = helperDetectionErrorTradeoff(xvecs,labels,enrolledLabels,plda);

Постройте результаты ошибочной оценки компромисса обнаружения и для выигрыша PLDA и для выигрыша подобия косинуса (CSS).

plot(detTable.PLDA.Threshold,detTable.PLDA.FAR, ...
    detTable.PLDA.Threshold,detTable.PLDA.FRR)
eer = helperEqualErrorRate(detTable.PLDA);
title(sprintf('Speaker Verification\nDetection Error Tradeoff\nPLDA Scoring\nEqual Error Rate = %0.2f',eer));
xlabel('Threshold')
ylabel('Error Rate')
legend({'FAR','FRR'})

plot(detTable.CSS.Threshold,detTable.CSS.FAR, ...
    detTable.CSS.Threshold,detTable.CSS.FRR)
eer = helperEqualErrorRate(detTable.CSS);
title(sprintf('Speaker Verification\nDetection Error Tradeoff\nCosine Similarity Scoring\nEqual Error Rate = %0.2f',eer));
xlabel('Threshold')
ylabel('Error Rate')
legend({'FAR','FRR'})

Ссылки

[1] Снайдер, Дэвид, и др. “x-векторы: Устойчивые Вложения DNN для Распознавания Динамика”. 2 018 Международных конференций IEEE по вопросам Акустики, Речи и Обработки сигналов (ICASSP), IEEE, 2018, стр 5329–33. DOI.org (Crossref), doi:10.1109/ICASSP.2018.8461375.

[2] Обработка сигналов и Речевая Коммуникационная Лаборатория. Полученный доступ 12 декабря 2019. https://www.spsc.tugraz.at/databases-and-tools/ptdb-tug-pitch-tracking-database-from-graz-university-of-technology.html.

Вспомогательные Функции

Инициализируйте параметры слоев TDNN

function [parameters,state] = initializexVecModelLayers(numFeatures,numFilters,numClasses)
% This function is only for use in this example. It may be changed or
% removed in a future release.

% Initialize Layer 1 (1-D Convolutional)
filterSize1                      = 5;
numChannels1                     = numFeatures;
numFilters1                      = numFilters;

numIn1                           = filterSize1*numFilters1;
numOut1                          = filterSize1*numFilters1;

parameters.conv1.Weights         = initializeGlorot([filterSize1,numChannels1,numFilters1],numOut1,numIn1);
parameters.conv1.Bias            = dlarray(zeros([numFilters1,1],'single'));
parameters.batchnorm1.Offset     = dlarray(zeros([numFilters1,1],'single'));
parameters.batchnorm1.Scale      = dlarray(ones([numFilters1,1],'single'));
state.batchnorm1.TrainedMean     = zeros(numFilters1,1,'single');
state.batchnorm1.TrainedVariance = ones(numFilters1,1,'single');


% Initialize Layer 2 (1-D Convolutional)
filterSize2                      = 3;
numChannels2                     = numFilters1;
numFilters2                      = numFilters;

numIn2                           = filterSize2*numFilters2;
numOut2                          = filterSize2*numFilters2;

parameters.conv2.Weights         = initializeGlorot([filterSize2,numChannels2,numFilters2],numOut2,numIn2);
parameters.conv2.Bias            = dlarray(zeros([numFilters2,1],'single'));
parameters.batchnorm2.Offset     = dlarray(zeros([numFilters2,1],'single'));
parameters.batchnorm2.Scale      = dlarray(ones([numFilters2,1],'single'));
state.batchnorm2.TrainedMean     = zeros(numFilters2,1,'single');
state.batchnorm2.TrainedVariance = ones(numFilters2,1,'single');


% Initialize Layer 3 (1-D Convolutional)
filterSize3                      = 3;
numChannels3                     = numFilters2;
numFilters3                      = numFilters;

numIn3                           = filterSize3*numFilters3;
numOut3                          = filterSize3*numFilters3;

parameters.conv3.Weights         = initializeGlorot([filterSize3,numChannels3,numFilters3],numOut3,numIn3);
parameters.conv3.Bias            = dlarray(zeros([numFilters3,1],'single'));
parameters.batchnorm3.Offset     = dlarray(zeros([numFilters3,1],'single'));
parameters.batchnorm3.Scale      = dlarray(ones([numFilters3,1],'single'));
state.batchnorm3.TrainedMean     = zeros(numFilters3,1,'single');
state.batchnorm3.TrainedVariance = ones(numFilters3,1,'single');


% Initialize Layer 4 (1-D Convolutional)
filterSize4                      = 1;
numChannels4                     = numFilters3;
numFilters4                      = numFilters;

numIn4                           = filterSize4*numFilters4;
numOut4                          = filterSize4*numFilters4;

parameters.conv4.Weights         = initializeGlorot([filterSize4,numChannels4,numFilters4],numOut4,numIn4);
parameters.conv4.Bias            = dlarray(zeros([numFilters4,1],'single'));
parameters.batchnorm4.Offset     = dlarray(zeros([numFilters4,1],'single'));
parameters.batchnorm4.Scale      = dlarray(ones([numFilters4,1],'single'));
state.batchnorm4.TrainedMean     = zeros(numFilters4,1,'single');
state.batchnorm4.TrainedVariance = ones(numFilters4,1,'single');


% Initialize Layer 5 (1-D Convolutional)
filterSize5                      = 1;
numChannels5                     = numFilters4;
numFilters5                      = 1500;

numOut5                          = filterSize5*numFilters5;
numIn5                           = filterSize5*numFilters5;

parameters.conv5.Weights         = initializeGlorot([filterSize5,numChannels5,numFilters5],numOut5,numIn5);
parameters.conv5.Bias            = dlarray(zeros([numFilters5,1],'single'));
parameters.batchnorm5.Offset     = dlarray(zeros([numFilters5,1],'single'));
parameters.batchnorm5.Scale      = dlarray(ones([numFilters5,1],'single'));
state.batchnorm5.TrainedMean     = zeros(numFilters5,1,'single');
state.batchnorm5.TrainedVariance = ones(numFilters5,1,'single');


% Initialize Layer 6 (Statistical Pooling)
numIn6                           = numOut5;
numOut6                          = 2*numIn6;


% Initialize Layer 7 (Fully Connected)
numIn7                           = numOut6;
numOut7                          = numFilters;

parameters.fc7.Weights           = initializeGlorot([numFilters,numIn7],numOut7,numIn7);
parameters.fc7.Bias              = dlarray(zeros([numOut7,1],'single'));
parameters.batchnorm7.Offset     = dlarray(zeros([numOut7,1],'single'));
parameters.batchnorm7.Scale      = dlarray(ones([numOut7,1],'single'));
state.batchnorm7.TrainedMean     = zeros(numOut7,1,'single');
state.batchnorm7.TrainedVariance = ones(numOut7,1,'single');


% Initialize Layer 8 (Fully Connected)
numIn8                           = numOut7;
numOut8                          = numFilters;

parameters.fc8.Weights           = initializeGlorot([numOut8,numIn8],numOut8,numIn8);
parameters.fc8.Bias              = dlarray(zeros([numOut8,1],'single'));
parameters.batchnorm8.Offset     = dlarray(zeros([numOut8,1],'single'));
parameters.batchnorm8.Scale      = dlarray(ones([numOut8,1],'single'));
state.batchnorm8.TrainedMean     = zeros(numOut8,1,'single');
state.batchnorm8.TrainedVariance = ones(numOut8,1,'single');


% Initialize Layer 9 (Fully Connected)
numIn9                           = numOut8;
numOut9                          = numClasses;

parameters.fc9.Weights           = initializeGlorot([numOut9,numIn9],numOut9,numIn9);
parameters.fc9.Bias              = dlarray(zeros([numOut9,1],'single'));
end

Инициализируйте веса Используя инициализацию Glorot

function weights = initializeGlorot(sz,numOut,numIn)
% This function is only for use in this example. It may be changed or
% removed in a future release.
Z = 2*rand(sz,'single') - 1;
bound = sqrt(6 / (numIn + numOut));
weights = bound*Z;
weights = dlarray(weights);
end

Вычислите градиенты модели и обновленное состояние

function [gradients,state,loss,Y] = modelGradients(X,target,parameters,state)
% This function is only for use in this example. It may be changed or
% removed in a future release.
[Y,state] = xvecModel(X,parameters,state,'DoTraining',true);
loss = crossentropy(Y,target);
gradients = dlgradient(loss,parameters);
end

Предварительно обработайте мини-пакет

function [sequences,labels] = preprocessMiniBatch(sequences,labels)
% This function is only for use in this example. It may be changed or
% removed in a future release.
lengths = cellfun(@(x)size(x,1),sequences);
minLength = min(lengths);
sequences = cellfun(@(x)randomTruncate(x,1,minLength),sequences,'UniformOutput',false);
sequences = cat(3,sequences{:});
        
labels = cat(2,labels{:});
labels = onehotencode(labels,1);
labels(isnan(labels)) = 0;
end

Случайным образом Усеченные звуковые сигналы к заданной длине

function y = randomTruncate(x,dim,minLength)
% This function is only for use in this example. It may be changed or
% removed in a future release.
N = size(x,dim);
if N > minLength
    start = randperm(N-minLength,1);
    if dim==1
        y = x(start:start+minLength-1,:);
    elseif dim ==2
        y = x(:,start:start+minLength-1);
    end
else
    y = x;
end
end

Извлечение признаков и нормализация - Datastore

function [features,labels] = xVectorPreprocessBatch(ads,afe,nvargs)
% This function is only for use in this example. It may be changed or
% removed in a future release.
    arguments
        ads
        afe
        nvargs.Factors = []
        nvargs.Segment = true;
    end
    if ~isempty(ver('parallel'))
        pool = gcp;
        numpar = numpartitions(ads,pool);
    else
        numpar = 1;
    end
    labels = [];
    features = [];
    parfor ii = 1:numpar
        adsPart = partition(ads,numpar,ii);
        numFiles = numel(adsPart.UnderlyingDatastores{1}.Files);
        localFeatures = cell(numFiles,1);
        localLabels = [];
        for jj = 1:numFiles
            [audioIn,xInfo] = read(adsPart);
            label = xInfo.Label;
            [f,ns] = xVectorPreprocess(audioIn,afe,'Factors',nvargs.Factors,'Segment',nvargs.Segment); %#ok<PFBNS> 
            localFeatures{jj} = f;
            localLabels = [localLabels,repelem(label,ns)];
        end
        features = [features;localFeatures];
        labels = [labels,localLabels];
    end
    features = cat(1,features{:});
    labels = removecats(labels);
end

Извлечение признаков и нормализация

function [features,numSegments] = xVectorPreprocess(audioData,afe,nvargs)
% This function is only for use in this example. It may be changed or
% removed in a future release.
arguments
    audioData
    afe
    nvargs.Factors = []
    nvargs.Segment = true;
    nvargs.MinimumDuration = 1;
end
% Scale
audioData = audioData/max(abs(audioData(:)));

% Protect against NaNs
audioData(isnan(audioData)) = 0;

% Determine regions of speech
mergeDur = 0.5; % seconds
idx = detectSpeech(audioData,afe.SampleRate,'MergeDistance',afe.SampleRate*mergeDur);

% If a region is less than MinimumDuration seconds, drop it.
if nvargs.Segment
    idxToRemove = (idx(:,2)-idx(:,1))<afe.SampleRate*nvargs.MinimumDuration;
    idx(idxToRemove,:) = [];
end

% Extract features
numSegments = size(idx,1);
features = cell(numSegments,1);
for ii = 1:numSegments
    features{ii} = single(extract(afe,audioData(idx(ii,1):idx(ii,2))));
end

% Standardize features
if ~isempty(nvargs.Factors)
    features = cellfun(@(x)(x-nvargs.Factors.Mean)./nvargs.Factors.STD,features,'UniformOutput',false);
end

% Cepstral mean subtraction (for channel noise)
if ~isempty(nvargs.Factors)
    fileMean = mean(cat(1,features{:}),'all');
    features = cellfun(@(x)x - fileMean,features,'UniformOutput',false);
end

if ~nvargs.Segment
    features = cat(1,features{:});
end
end