이 페이지의 최신 내용은 아직 번역되지 않았습니다. 최신 내용은 영문으로 볼 수 있습니다.

심층 학습을 사용해 음성 명령 인식하기

이 예제에서는 오디오에서 음성 명령의 존재 여부를 감지하는 간단한 심층 학습 모델을 훈련시키는 방법을 보여줍니다. 이 예제에서는 Speech Commands Dataset을 사용하여 컨벌루션 신경망이 주어진 명령 세트를 인식하도록 훈련시킵니다[1].

이 예제를 실행하려면 먼저 데이터 세트를 다운로드해야 합니다. 데이터 세트를 다운로드하거나 네트워크를 훈련시키기를 원치 않는 경우에는 이 예제를 MATLAB®에서 열고 명령줄에 load('commandNet.mat')를 입력하여 사전 훈련된 네트워크를 불러올 수 있습니다. 네트워크를 불러왔으면 이 예제의 마지막 섹션인 마이크의 스트리밍 오디오를 사용하여 명령 감지하기로 이동하십시오.

음성 명령 데이터 세트 불러오기

http://download.tensorflow.org/data/speech_commands_v0.01.tar.gz에서 데이터 세트를 다운로드하고 다운로드한 파일의 압축을 풉니다. datafolder를 데이터의 위치로 설정합니다. audioDatastore를 사용하여 파일 이름과 여기에 대응하는 레이블이 포함된 데이터저장소를 만듭니다. 폴더 이름을 레이블 소스로 사용합니다. 전체 오디오 파일을 읽도록 읽기 메서드를 지정합니다. 나중에 사용할 수 있도록 데이터저장소의 복사본을 만듭니다.

datafolder = fullfile(tempdir,'speech_commands_v0.01');
ads = audioDatastore(datafolder, ...
    'IncludeSubfolders',true, ...
    'FileExtensions','.wav', ...
    'LabelSource','foldernames')
ads0 = copy(ads);
ads = 

  audioDatastore with properties:

                       Files: {
                              ' ...\Temp\speech_commands_v0.01\_background_noise_\doing_the_dishes.wav';
                              ' ...\Local\Temp\speech_commands_v0.01\_background_noise_\dude_miaowing.wav';
                              ' ...\Local\Temp\speech_commands_v0.01\_background_noise_\exercise_bike.wav'
                               ... and 64724 more
                              }
                      Labels: [_background_noise_; _background_noise_; _background_noise_ ... and 64724 more categorical]
    AlternateFileSystemRoots: {}
              OutputDataType: 'double'

인식할 단어 선택하기

모델이 명령으로 인식해야 할 단어를 사용자가 지정해 줍니다. 명령이 아닌 단어는 모두 unknown으로 지정합니다. 명령이 아닌 단어를 unknown으로 지정하면 명령을 제외한 모든 단어의 분포에 근접한 단어 그룹이 만들어집니다. 네트워크는 이 그룹을 사용하여 명령과 명령이 아닌 단어의 차이를 학습합니다.

알려진 단어와 알려지지 않은 단어 사이의 클래스 불균형을 줄이고 처리 속도를 높이려면 알려지지 않은 단어들의 일부인 includeFraction만 훈련 세트에 포함하십시오. 배경 잡음이 있는 긴 파일은 아직 훈련 세트에 포함하지 마십시오. 배경 잡음은 나중에 별도의 단계에서 추가하게 됩니다.

subset(ads,indices)를 사용하여 indices로 참조되는 파일과 레이블만 포함하는 데이터저장소를 만듭니다. 알려지지 않은 단어의 서브셋과 명령만 포함하도록 데이터저장소 ads를 줄입니다. 각 클래스에 속하는 표본의 개수를 셉니다.

commands = categorical(["yes","no","up","down","left","right","on","off","stop","go"]);

isCommand = ismember(ads.Labels,commands);
isUnknown = ~ismember(ads.Labels,[commands,"_background_noise_"]);

includeFraction = 0.2;
mask = rand(numel(ads.Labels),1) < includeFraction;
isUnknown = isUnknown & mask;
ads.Labels(isUnknown) = categorical("unknown");

ads = subset(ads,isCommand|isUnknown);
countEachLabel(ads)
ans =

  11×2 table

     Label     Count
    _______    _____

    down       2359 
    go         2372 
    left       2353 
    no         2375 
    off        2357 
    on         2367 
    right      2367 
    stop       2380 
    unknown    8250 
    up         2375 
    yes        2377 

데이터를 훈련 세트, 검증 세트와 테스트 세트로 분할하기

데이터 세트 폴더에는 검증 세트와 테스트 세트로 사용할 오디오 파일이 나열된 텍스트 파일이 포함되어 있습니다. 이러한 미리 정의된 검증 세트와 테스트 세트에는 동일한 사람이 발화한 동일한 단어가 포함되어 있지 않으므로, 전체 데이터 세트에서 서브셋을 임의로 선택하는 것보다 이러한 미리 정의된 세트를 사용하는 것이 좋습니다. 지원 함수 splitData를 사용하여 데이터 세트 폴더에 있는 검증 파일 및 테스트 파일 목록을 기준으로 데이터저장소를 훈련 세트, 검증 세트, 테스트 세트로 분할합니다.

이 예제에서는 단일 네트워크를 훈련시키기 때문에 테스트 세트가 아닌 검증 세트만 사용하여 훈련된 모델을 평가합니다. 여러 네트워크를 훈련시킨 후 검증 정확도가 가장 높은 네트워크를 최종 네트워크로 선택하는 경우 테스트 세트를 사용하여 최종 네트워크를 평가할 수 있습니다.

[adsTrain,adsValidation,adsTest] = splitData(ads,datafolder);

음성 스펙트로그램 계산하기

컨벌루션 신경망의 효율적인 훈련을 위해 데이터를 준비하려면 음성 파형을 로그-멜(log-mel) 스펙트로그램으로 변환하십시오.

스펙트로그램 계산의 파라미터를 정의합니다. segmentDuration은 각 음성 클립의 길이(단위: 초)입니다. frameDuration은 스펙트로그램 계산에서 각 프레임의 재생 시간입니다. hopDuration은 스펙트로그램의 각 열 사이의 시간 스텝입니다. numBands는 로그-멜 필터의 개수로, 각 스펙트로그램의 높이와 같습니다.

segmentDuration = 1;
frameDuration = 0.025;
hopDuration = 0.010;
numBands = 40;

지원 함수 speechSpectrograms를 사용하여 훈련 세트, 검증 세트, 테스트 세트에 대한 스펙트로그램을 계산합니다. speechSpectrograms 함수는 로그-멜 스펙트로그램 계산에 melSpectrogram을 사용합니다. 보다 매끄러운 분포를 갖는 데이터를 얻으려면 작은 오프셋 epsil을 사용하여 스펙트로그램의 로그를 구하십시오.

epsil = 1e-6;

XTrain = speechSpectrograms(adsTrain,segmentDuration,frameDuration,hopDuration,numBands);
XTrain = log10(XTrain + epsil);

XValidation = speechSpectrograms(adsValidation,segmentDuration,frameDuration,hopDuration,numBands);
XValidation = log10(XValidation + epsil);

XTest = speechSpectrograms(adsTest,segmentDuration,frameDuration,hopDuration,numBands);
XTest = log10(XTest + epsil);

YTrain = adsTrain.Labels;
YValidation = adsValidation.Labels;
YTest = adsTest.Labels;
Computing speech spectrograms...
Processed 1000 files out of 24982
Processed 2000 files out of 24982
Processed 3000 files out of 24982
Processed 4000 files out of 24982
Processed 5000 files out of 24982
Processed 6000 files out of 24982
Processed 7000 files out of 24982
Processed 8000 files out of 24982
Processed 9000 files out of 24982
Processed 10000 files out of 24982
Processed 11000 files out of 24982
Processed 12000 files out of 24982
Processed 13000 files out of 24982
Processed 14000 files out of 24982
Processed 15000 files out of 24982
Processed 16000 files out of 24982
Processed 17000 files out of 24982
Processed 18000 files out of 24982
Processed 19000 files out of 24982
Processed 20000 files out of 24982
Processed 21000 files out of 24982
Processed 22000 files out of 24982
Processed 23000 files out of 24982
Processed 24000 files out of 24982
...done
Computing speech spectrograms...
Processed 1000 files out of 3477
Processed 2000 files out of 3477
Processed 3000 files out of 3477
...done
Computing speech spectrograms...
Processed 1000 files out of 3473
Processed 2000 files out of 3473
Processed 3000 files out of 3473
...done

데이터 시각화하기

몇몇 훈련 표본의 파형과 스펙트로그램을 플로팅합니다. 대응하는 오디오 클립을 재생합니다.

specMin = min(XTrain(:));
specMax = max(XTrain(:));
idx = randperm(size(XTrain,4),3);
figure('Units','normalized','Position',[0.2 0.2 0.6 0.6]);
for i = 1:3
    [x,fs] = audioread(adsTrain.Files{idx(i)});
    subplot(2,3,i)
    plot(x)
    axis tight
    title(string(adsTrain.Labels(idx(i))))

    subplot(2,3,i+3)
    spect = XTrain(:,:,1,idx(i));
    pcolor(spect)
    caxis([specMin+2 specMax])
    shading flat

    sound(x,fs)
    pause(2)
end

신경망에 대한 입력값이 적절히 매끄러운 분포를 가지며 정규화되어 있을 때 가장 쉽게 신경망을 훈련시킬 수 있습니다. 데이터가 매끄러운 분포를 갖는지 확인하려면 훈련 데이터의 픽셀 값의 히스토그램을 플로팅하십시오.

figure
histogram(XTrain,'EdgeColor','none','Normalization','pdf')
axis tight
ax = gca;
ax.YScale = 'log';
xlabel("Input Pixel Value")
ylabel("Probability Density")

배경 잡음 데이터 추가하기

네트워크는 발화된 다양한 단어를 인식할 수 있어야 할 뿐 아니라 입력값에 무음이 포함되어 있는지 배경 잡음이 포함되어 있는지 감지할 수도 있어야 합니다.

_background_noise_ 폴더에 있는 오디오 파일을 사용하여 1초 길이의 배경 잡음 샘플 클립을 만듭니다. 각 배경 잡음 파일로부터 동일한 개수의 배경 클립을 만듭니다. 배경 잡음을 직접 녹음한 다음 _background_noise_ 폴더에 추가해도 됩니다. adsBkg 데이터저장소의 오디오 파일에서 가져온 배경 클립의 numBkgClips개 스펙트로그램을 계산하려면 지원 함수 backgroundSpectrograms를 사용하십시오. 이 함수는 스펙트로그램을 계산하기 전에 먼저 volumeRange로 지정된 범위에 있는 로그 균등 분포에서 샘플링한 인자로 각 오디오 클립을 다시 스케일링합니다.

배경 클립 4,000개를 만들고 각 클립을 1e-41 사이에 있는 수로 다시 스케일링합니다. XBkg에는 실질적 무음과 소음 사이의 음량을 갖는 배경 잡음의 스펙트로그램이 포함되어 있습니다.

adsBkg = subset(ads0,ads0.Labels=="_background_noise_");
numBkgClips = 4000;
volumeRange = [1e-4,1];

XBkg = backgroundSpectrograms(adsBkg,numBkgClips,volumeRange,segmentDuration,frameDuration,hopDuration,numBands);
XBkg = log10(XBkg + epsil);
Computing background spectrograms...
Processed 1000 background clips out of 4000
Processed 2000 background clips out of 4000
Processed 3000 background clips out of 4000
Processed 4000 background clips out of 4000
...done

배경 잡음의 스펙트로그램을 훈련 세트, 검증 세트, 테스트 세트로 분할합니다. _background_noise_ 폴더에는 약 5분 30초 분량의 배경 잡음만 포함되어 있으므로 서로 다른 데이터 세트의 배경 샘플은 밀접한 상관관계를 갖습니다. 배경 잡음의 변형을 늘리기 위해 직접 배경 파일을 만들어 폴더에 추가할 수 있습니다. 잡음에 대한 네트워크의 견고성을 높이기 위해 음성 파일에 배경 잡음을 섞어볼 수도 있습니다.

numTrainBkg = floor(0.8*numBkgClips);
numValidationBkg = floor(0.1*numBkgClips);
numTestBkg = floor(0.1*numBkgClips);

XTrain(:,:,:,end+1:end+numTrainBkg) = XBkg(:,:,:,1:numTrainBkg);
XBkg(:,:,:,1:numTrainBkg) = [];
YTrain(end+1:end+numTrainBkg) = "background";

XValidation(:,:,:,end+1:end+numValidationBkg) = XBkg(:,:,:,1:numValidationBkg);
XBkg(:,:,:,1:numValidationBkg) = [];
YValidation(end+1:end+numValidationBkg) = "background";

XTest(:,:,:,end+1:end+numTestBkg) = XBkg(:,:,:,1: numTestBkg);
clear XBkg;
YTest(end+1:end+numTestBkg) = "background";

YTrain = removecats(YTrain);
YValidation = removecats(YValidation);
YTest = removecats(YTest);

훈련 세트와 검증 세트에서 다양한 클래스 레이블의 분포를 플로팅합니다. 테스트 세트의 분포가 검증 세트의 분포와 매우 유사합니다.

figure('Units','normalized','Position',[0.2 0.2 0.5 0.5]);
subplot(2,1,1)
histogram(YTrain)
title("Training Label Distribution")
subplot(2,1,2)
histogram(YValidation)
title("Validation Label Distribution")

데이터 증대 추가하기

스펙트로그램의 자동 증대와 크기 변경을 위해 증대 이미지 데이터저장소를 만듭니다. 스펙트로그램을 최대 10프레임(100ms) 앞으로 또는 뒤로 무작위로 평행 이동하고, 스펙트로그램을 시간 축을 따라 20% 많게 또는 적게 스케일링합니다. 데이터를 증대하면 훈련 데이터의 유효 크기가 늘어나고 네트워크가 과적합되지 않도록 하는 데 도움이 됩니다. 증대 이미지 데이터저장소는 훈련 중에 실시간으로 증대된 이미지를 만들어 네트워크에 입력합니다. 증대된 스펙트로그램은 메모리에 저장되지 않습니다.

sz = size(XTrain);
specSize = sz(1:2);
imageSize = [specSize 1];
augmenter = imageDataAugmenter( ...
    'RandXTranslation',[-10 10], ...
    'RandXScale',[0.8 1.2], ...
    'FillValue',log10(epsil));
augimdsTrain = augmentedImageDatastore(imageSize,XTrain,YTrain, ...
    'DataAugmentation',augmenter);

신경망 아키텍처 정의하기

간단한 네트워크 아키텍처를 계층 배열로 만듭니다. 컨벌루션 계층과 배치 정규화 계층을 사용하고, 최댓값 풀링 계층을 사용하여 특징 맵을 "공간적으로"(즉, 시간과 주파수에서) 다운샘플링합니다. 시간의 흐름에 따라 입력 특징 맵을 전역적으로 풀링하는 마지막 최댓값 풀링 계층을 추가합니다. 이렇게 하면 입력 스펙트로그램에서 (근사적인) 시간 이동 불변성이 적용되어 음성의 정확한 시간적 위치에 상관없이 네트워크가 동일한 분류를 수행할 수 있게 됩니다. 전역적 풀링은 마지막 완전 연결 계층에서 파라미터의 개수를 대폭 줄여 주기도 합니다. 네트워크가 훈련 데이터의 구체적인 특징을 기억할 가능성을 줄이려면 입력값의 마지막 완전 연결 계층에 소량의 드롭아웃을 추가하십시오.

네트워크는 몇 개의 필터만 있는 컨벌루션 계층 5개만 포함하므로 크기가 작습니다. numF는 컨벌루션 계층의 필터 개수를 제어합니다. 네트워크의 정확도를 높이려면 컨벌루션 계층, 배치 정규화 계층, ReLU 계층으로 구성된 동일한 블록들을 추가하여 네트워크의 심도를 높여보십시오. numF를 높여 컨벌루션 필터의 개수를 늘려볼 수도 있습니다.

가중 교차 엔트로피 분류 손실을 사용합니다. weightedClassificationLayer(classWeights)classWeights에 의해 가중치가 적용된 관측값으로 교차 엔트로피 손실을 계산하는 사용자 지정 분류 계층을 만듭니다. categories(YTrain)에 나타나는 클래스 순서대로 클래스 가중치를 지정합니다. 각 클래스에 손실의 총 가중치를 동일하게 주려면 각 클래스의 훈련 표본의 개수에 반비례하는 클래스 가중치를 사용하십시오. Adam 최적화 함수를 사용하여 네트워크를 훈련시키는 경우에는 훈련 알고리즘이 클래스 가중치의 전체 정규화에 대해 독립적입니다.

classWeights = 1./countcats(YTrain);
classWeights = classWeights'/mean(classWeights);
numClasses = numel(categories(YTrain));

timePoolSize = ceil(imageSize(2)/8);
dropoutProb = 0.2;
numF = 12;
layers = [
    imageInputLayer(imageSize)

    convolution2dLayer(3,numF,'Padding','same')
    batchNormalizationLayer
    reluLayer

    maxPooling2dLayer(3,'Stride',2,'Padding','same')

    convolution2dLayer(3,2*numF,'Padding','same')
    batchNormalizationLayer
    reluLayer

    maxPooling2dLayer(3,'Stride',2,'Padding','same')

    convolution2dLayer(3,4*numF,'Padding','same')
    batchNormalizationLayer
    reluLayer

    maxPooling2dLayer(3,'Stride',2,'Padding','same')

    convolution2dLayer(3,4*numF,'Padding','same')
    batchNormalizationLayer
    reluLayer
    convolution2dLayer(3,4*numF,'Padding','same')
    batchNormalizationLayer
    reluLayer

    maxPooling2dLayer([1 timePoolSize])

    dropoutLayer(dropoutProb)
    fullyConnectedLayer(numClasses)
    softmaxLayer
    weightedClassificationLayer(classWeights)];

네트워크 훈련시키기

훈련 옵션을 지정합니다. 미니 배치 크기가 128인 Adam 최적화 함수를 사용합니다. Epoch 25회에 대해 훈련시키고, Epoch 20회가 지나면 학습률을 10배만큼 줄입니다.

miniBatchSize = 128;
validationFrequency = floor(numel(YTrain)/miniBatchSize);
options = trainingOptions('adam', ...
    'InitialLearnRate',3e-4, ...
    'MaxEpochs',25, ...
    'MiniBatchSize',miniBatchSize, ...
    'Shuffle','every-epoch', ...
    'Plots','training-progress', ...
    'Verbose',false, ...
    'ValidationData',{XValidation,YValidation}, ...
    'ValidationFrequency',validationFrequency, ...
    'LearnRateSchedule','piecewise', ...
    'LearnRateDropFactor',0.1, ...
    'LearnRateDropPeriod',20);

네트워크를 훈련시킵니다. GPU가 없으면, 네트워크 훈련에 시간이 걸릴 수 있습니다. 네트워크를 처음부터 훈련시키는 대신 사전 훈련된 네트워크를 불러오려면 doTrainingfalse로 설정하십시오.

doTraining = true;
if doTraining
    trainedNet = trainNetwork(augimdsTrain,layers,options);
else
    load('commandNet.mat','trainedNet');
end

훈련된 네트워크 평가하기

(데이터 증대가 적용되지 않은) 훈련 세트와 검증 세트에 대해 네트워크의 최종 정확도를 계산합니다. 네트워크는 이 데이터 세트에서 매우 정확한 결과를 나타냅니다. 그러나 훈련 데이터, 검증 데이터, 테스트 데이터는 모두 실제 환경을 그대로 반영한다고 보기 어려운 비슷한 분포를 갖고 있습니다. 이러한 한계는 특히 적은 개수의 발화된 단어를 포함하는 unknown 범주에서 두드러지게 나타납니다.

YValPred = classify(trainedNet,XValidation);
validationError = mean(YValPred ~= YValidation);
YTrainPred = classify(trainedNet,XTrain);
trainError = mean(YTrainPred ~= YTrain);
disp("Training error: " + trainError*100 + "%")
disp("Validation error: " + validationError*100 + "%")
Training error: 1.7103%
Validation error: 4.5912%

정오분류표를 플로팅합니다. 열 및 행 요약을 사용하여 각 클래스의 정밀도를 표시하고 다시 호출합니다. 정오분류표의 클래스를 정렬합니다. 알려지지 않은 단어와 명령인 upoff, downno, gono 사이에서 가장 큰 오분류가 발생합니다.

figure('Units','normalized','Position',[0.2 0.2 0.5 0.5]);
cm = confusionchart(YValidation,YValPred);
cm.Title = 'Confusion Matrix for Validation Data';
cm.ColumnSummary = 'column-normalized';
cm.RowSummary = 'row-normalized';
sortClasses(cm, [commands,"unknown","background"])

모바일 응용 프로그램과 같이 하드웨어 리소스 제약이 있는 응용 프로그램에서 작업할 때는 가용 메모리와 연산 리소스에 대한 제한을 고려해야 합니다. 네트워크의 총 크기를 kB 단위로 계산하고, CPU를 사용할 때의 예측 속도를 테스트합니다. 예측 시간은 단일 입력 이미지를 분류하는 시간입니다. 네트워크에 여러 개의 이미지를 입력하는 경우, 복수의 이미지가 동시에 분류될 수 있고, 그 결과 이미지당 예측 시간이 단축됩니다. 그러나 스트리밍 오디오를 분류할 때는 단일 이미지 예측 시간이 가장 중요합니다.

info = whos('trainedNet');
disp("Network size: " + info.bytes/1024 + " kB")

for i=1:100
    x = randn(imageSize);
    tic
    [YPredicted,probs] = classify(trainedNet,x,"ExecutionEnvironment",'cpu');
    time(i) = toc;
end
disp("Single-image prediction time on CPU: " + mean(time(11:end))*1000 + " ms")
Network size: 295.9141 kB
Single-image prediction time on CPU: 3.1274 ms

마이크의 스트리밍 오디오를 사용하여 명령 감지하기

새로 훈련시킨 명령 감지 네트워크를 마이크의 스트리밍 오디오에 대해 테스트합니다. 네트워크를 훈련시키지 않았다면 명령줄에 load('commandNet.mat')를 입력하여 사전 훈련된 네트워크와 라이브 스트리밍 오디오 분류에 필요한 파라미터를 불러옵니다. yes, no, stop과 같은 명령을 말해 봅니다. 그런 다음 Marvin, Sheila, bed, house, cat, bird 또는 0과 9 사이의 임의의 숫자와 같은 알려지지 않은 단어를 말해 봅니다.

오디오 샘플링 레이트와 분류 속도를 Hz 단위로 지정하고 마이크의 오디오를 읽을 수 있는 오디오 장치 리더를 만듭니다.

fs = 16e3;
classificationRate = 20;
audioIn = audioDeviceReader('SampleRate',fs, ...
    'SamplesPerFrame',floor(fs/classificationRate));

스트리밍 스펙트로그램 계산의 파라미터를 지정하고 오디오를 위한 버퍼를 초기화합니다. 네트워크의 분류 레이블을 추출합니다. 스트리밍 오디오의 레이블 및 분류 확률을 위해 0.5초 분량의 버퍼를 초기화합니다. 초기화한 버퍼를 사용하여 보다 긴 시간에 걸쳐 분류 결과를 비교하고, 이를 사용하여 명령이 감지된 때를 대상으로 '일치하는' 부분을 구축합니다.

frameLength = floor(frameDuration*fs);
hopLength = floor(hopDuration*fs);
waveBuffer = zeros([fs,1]);

labels = trainedNet.Layers(end).Classes;
YBuffer(1:classificationRate/2) = categorical("background");
probBuffer = zeros([numel(labels),classificationRate/2]);

Figure를 만들고, 이 Figure가 존재하는 한 계속해서 명령을 감지합니다. 라이브 감지를 중단하려면 Figure를 닫으십시오.

h = figure('Units','normalized','Position',[0.2 0.1 0.6 0.8]);

while ishandle(h)

    % Extract audio samples from the audio device and add the samples to
    % the buffer.
    x = audioIn();
    waveBuffer(1:end-numel(x)) = waveBuffer(numel(x)+1:end);
    waveBuffer(end-numel(x)+1:end) = x;

    % Compute the spectrogram of the latest audio samples.
    spec = melSpectrogram(waveBuffer,fs, ...
        'WindowLength',frameLength, ...
        'OverlapLength',frameLength - hopLength, ...
        'FFTLength',512, ...
        'NumBands',numBands, ...
        'FrequencyRange',[50,7000]);
    spec = log10(spec + epsil);

    % Classify the current spectrogram, save the label to the label buffer,
    % and save the predicted probabilities to the probability buffer.
    [YPredicted,probs] = classify(trainedNet,spec,'ExecutionEnvironment','cpu');
    YBuffer(1:end-1)= YBuffer(2:end);
    YBuffer(end) = YPredicted;
    probBuffer(:,1:end-1) = probBuffer(:,2:end);
    probBuffer(:,end) = probs';

    % Plot the current waveform and spectrogram.
    subplot(2,1,1);
    plot(waveBuffer)
    axis tight
    ylim([-0.2,0.2])

    subplot(2,1,2)
    pcolor(spec)
    caxis([specMin+2 specMax])
    shading flat

    % Now do the actual command detection by performing a very simple
    % thresholding operation. Declare a detection and display it in the
    % figure title if all of the following hold:
    % 1) The most common label is not |background|.
    % 2) At least |countThreshold| of the latest frame labels agree.
    % 3) The maximum predicted probability of the predicted label is at
    % least |probThreshold|. Otherwise, do not declare a detection.
    [YMode,count] = mode(YBuffer);
    countThreshold = ceil(classificationRate*0.2);
    maxProb = max(probBuffer(labels == YMode,:));
    probThreshold = 0.7;
    subplot(2,1,1);
    if YMode == "background" || count<countThreshold || maxProb < probThreshold
        title(" ")
    else
        title(string(YMode),'FontSize',20)
    end

    drawnow

end

참고 문헌

[1] Warden P. "Speech Commands: A public dataset for single-word speech recognition", 2017. Available from http://download.tensorflow.org/data/speech_commands_v0.01.tar.gz. Copyright Google 2017. The Speech Commands Dataset is licensed under the Creative Commons Attribution 4.0 license, available here: https://creativecommons.org/licenses/by/4.0/legalcode.

참고 항목

| |

관련 항목