ドキュメンテーション

最新のリリースでは、このページがまだ翻訳されていません。 このページの最新版は英語でご覧になれます。

深層学習ネットワークを使用した音声のノイズ除去

この例では、深層学習ネットワークを使用して音声信号をノイズ除去する方法を説明します。例は、同じタスクに適用された 2 つのタイプのネットワーク (全結合と畳み込み) を比較します。

はじめに

音声のノイズ除去の目的は、音声の品質と明瞭度を強調しながら、音声信号からノイズを削除することです。この例は、深層学習のネットワークを使用した音声信号からの洗浄機ノイズの削除について紹介します。例は、同じタスクに適用された 2 つのタイプのネットワーク (全結合と畳み込み) を比較します。

問題の概要

8 kHz でサンプリングされた以下の音声信号について考えます。

[cleanAudio,fs] = audioread("SpeechDFT-16-8-mono-5secs.wav");
sound(cleanAudio,fs)

洗浄機のノイズを音声信号に付加します。S/N 比 (SNR) が 0 dB となるようにノイズ パワーを設定します。

noise        = audioread("WashingMachine-16-8-mono-1000secs.wav");

% Extract a noise segment from a random location in the noise file
ind          = randi(numel(noise) - numel(cleanAudio) + 1, 1, 1);
noiseSegment = noise(ind:ind + numel(cleanAudio) - 1);

speechPower  = sum(cleanAudio.^2);
noisePower   = sum(noiseSegment.^2);
noisyAudio   = cleanAudio + sqrt(speechPower/noisePower) * noiseSegment;

ノイズ音声信号を再生します。

sound(noisyAudio,fs)

元の信号とノイズ信号を可視化します。

t = (1/fs) * (0:numel(cleanAudio)-1);
subplot(2,1,1)
plot(t,cleanAudio)
title("Clean Audio")
grid on
subplot(2,1,2)
plot(t,noisyAudio)
title("Noisy Audio")
xlabel("Time (s)")
grid on

音声のノイズ除去の目的は、出力音声で望ましくないアーティファクトを最小化しながら、音声信号から洗浄機のノイズを削除することです。

データセットの確認

この例では、Mozilla Common Voice データセット [1] を使用して、深層学習ネットワークを学習してテストします。データセットには、短い文章を話す被験者の 48 kHz の録音が含まれます。データセットをダウンロードして、ダウンロードしたファイルを解凍します。datafolder をデータの場所に設定します。

datafolder = PathToDatabase;

audioDatastore を使用して、cv-valid-train フォルダーにファイルのデータストアを作成します。

ads = audioDatastore(fullfile(datafolder,"cv-valid-train"));

shuffle を使用して、データストアのファイルの順番をランダム化します。

ads = shuffle(ads);

ファイルのサブセット上で深層学習ネットワークを学習します。データストアの最初の 1000 ファイルを含むデータストア サブセットを作成します。

ads = subset(ads,1:1000);

read を使用し、データストア内の最初のファイルの内容を取得します。

[audio,info] = read(ads);

音声信号を再生します。

sound(audio,info.SampleRate)

音声信号をプロットします。

figure
t = (1/info.SampleRate) * (0:numel(audio)-1);
plot(t,audio)
title("Example Speech Signal")
xlabel("Time (s)")
grid on

深層学習システムの概要

標準の深層学習の学習スキームを以下に示します。音声が通常 4 kHz 未満になるため、ネットワークの計算負荷を減らすために、最初にクリーンなオーディオ信号とノイズを含むオーディオ信号を 8 kHz までダウンサンプリングすることに注意してください。予測子とターゲットのネットワーク信号は、それぞれノイズを含む信号とクリーンなオーディオ信号の振幅スペクトルです。ネットワークの出力はノイズ除去後の信号の振幅スペクトルです。回帰ネットワークは、予測子入力を使用して、出力と入力のターゲット間の平均二乗誤差を最小化します。ノイズ除去後のオーディオは、出力振幅スペクトルとノイズを含む信号の位相を使用して時間領域に戻されます [2]。

短時間フーリエ変換 (STFT) を使用して、ウィンドウの長さが 256 サンプル、オーバーラップが 75%、ハミング ウィンドウをもつ周波数領域にオーディオを変換します。負の周波数に対応する周波数サンプルを落として、スペクトル ベクトルのサイズを 129 まで縮小します (時間領域の音声信号が実数のため、これは情報の損失にはつながりません)。各 STFT 出力の推定が現在のノイズを含む STFT と 7 つの以前のノイズを含む STFT ベクトルを基にして計算されるように、予測子入力は 8 つの連続するノイズを含む STFT ベクトルで構成されます。

STFT のターゲットと予測子

この節では、1 つの学習ファイルからターゲット信号と予測子信号を生成する方法を説明します。

最初に、次のシステム パラメーターを定義します。

windowLength = 256;
win          = hamming(windowLength,"periodic");
overlap      = round(0.75 * windowLength);
ffTLength    = windowLength;
inputFs      = 48e3;
fs           = 8e3;
numFeatures  = ffTLength/2 + 1;
numSegments  = 8;

48 kHz オーディオを 8 kHz に変換するために使用されるサンプルレート変換を定義します。

src = dsp.SampleRateConverter("InputSampleRate",inputFs, ...
                              "OutputSampleRate",fs, ...
                              "Bandwidth",7920);

read を使用して、データストアからオーディオ ファイルの内容を取得します。

audio = read(ads);

オーディオの長さがサンプルレート変換の間引き係数の倍数であることを確認してください。

decimationFactor = inputFs/fs;
L = floor(numel(audio)/decimationFactor);
audio = audio(1:decimationFactor*L);

オーディオ信号を 8 kHz に変換します。

audio = src(audio);
reset(src)

洗浄機のノイズ ベクトルからランダムなノイズのセグメントを作成します。

randind      = randi(numel(noise) - numel(audio),[1 1]);
noiseSegment = noise(randind : randind + numel(audio) - 1);

SNR が 0 dB となるように音声信号にノイズを付加します。

noisePower   = sum(noiseSegment.^2);
cleanPower   = sum(audio.^2);
noiseSegment = noiseSegment .* sqrt(cleanPower/noisePower);
noisyAudio   = audio + noiseSegment;

stft を使用して、元のオーディオ信号とノイズを含むオーディオ信号から振幅 STFT ベクトルを生成します。

cleanSTFT = stft(audio,'Window',win,'OverlapLength',overlap,'FFTLength',ffTLength);
cleanSTFT = abs(cleanSTFT(numFeatures-1:end,:));
noisySTFT = stft(noisyAudio,'Window',win,'OverlapLength',overlap,'FFTLength',ffTLength);
noisySTFT = abs(noisySTFT(numFeatures-1:end,:));

ノイズを含む STFT から 8 つのセグメントの学習予測子信号を生成します。連続する予測子間のオーバーラップは、7 セグメントです。

noisySTFT    = [noisySTFT(:,1:numSegments - 1), noisySTFT];
stftSegments = zeros(numFeatures, numSegments , size(noisySTFT,2) - numSegments + 1);
for index = 1:size(noisySTFT,2) - numSegments + 1
    stftSegments(:,:,index) = (noisySTFT(:,index:index + numSegments - 1));
end

ターゲットと予測子を設定します。両方の変数の最後の次元は、オーディオ ファイルによって生成された個別の予測子/ターゲットのペアの数に対応します。各予測子は、129 x 8 で、各ターゲットは 129 x 1 です。

targets = cleanSTFT;
size(targets)
predictors = stftSegments;
size(predictors)
ans =

   129   457


ans =

   129     8   457

tall 配列を使用した特徴の抽出

プロセスの速度を上げるには、tall 配列を使用してデータストアのオーディオ ファイルすべての音声セグメントから特徴シーケンスを抽出します。インメモリ配列とは異なり、tall 配列は、通常、関数 gather を呼び出すまで未評価のままになります。この延期された評価によって、大容量のデータセットを高速で処理することができます。gather を使用して出力を最終的に要求するときに、MATLAB は、可能であればキューに入っている計算を結合して、データからパスの最小数を取ります。Parallel Computing Toolbox™ がある場合、ローカルの MATLAB セッションまたはローカルの並列プールで tall 配列を使用することができます。MATLAB® Parallel Server™ をインストールしている場合は、クラスター上で tall 配列の計算を実行することもできます。

最初に、データストアを tall 配列に変換します。

reset(ads)
T = tall(ads)
Starting parallel pool (parpool) using the 'local' profile ...
Connected to the parallel pool (number of workers: 12).

T =

  M×1 tall cell array

    {294384×1 double}
    {176880×1 double}
    {188400×1 double}
    {246000×1 double}
    {240240×1 double}
    {231024×1 double}
    {156144×1 double}
    {248304×1 double}
        :        :
        :        :

表示は、(データストアのファイル数に対応する) 行数、M はまだわからないことを示します。計算が完了するまで M はプレースホルダーです。

tall table からターゲットと予測子の振幅 STFT を抽出します。このアクションは、新しい tall 配列変数を作成して、後続の計算で使用します。関数 HelperGenerateSpeechDenoisingFeatures は、STFT Targets and Predictors セクションで既に強調表示された手順を実行します。cellfun コマンドは HelperGenerateSpeechDenoisingFeatures をデータストアの各オーディオ ファイルの内容に適用します。

[targets,predictors] = cellfun(@(x)HelperGenerateSpeechDenoisingFeatures(x,noise,src),T,"UniformOutput",false);

gather を使用して、ターゲットと予測子を評価します。

[targets,predictors] = gather(targets,predictors);
Evaluating tall expression using the Parallel Pool 'local':
- Pass 1 of 1: Completed in 1 min 4 sec
Evaluation completed in 2 min 16 sec

すべての特徴をゼロ平均および標準偏差 1 に正規化することをお勧めします。

予測子とターゲットの平均値と標準偏差をそれぞれ計算して、データを正規化するのに使用します。

predictors    = cat(3,predictors{:});
targets       = cat(2,targets{:});
noisyMean     = mean(predictors(:));
noisyStd      = std(predictors(:));
predictors(:) = (predictors(:) - noisyMean)/noisyStd;
cleanMean     = mean(targets(:));
cleanStd      = std(targets(:));
targets(:)    = (targets(:) - cleanMean)/cleanStd;

予測子とターゲットを深層学習ネットワークによって予測される次元に形状変更します。

predictors = reshape(predictors,size(predictors,1),size(predictors,2),1,size(predictors,3));
targets    = reshape(targets,1,1,size(targets,1),size(targets,2));

学習中の検証にデータの 1% を使用します。検証は、ネットワークが学習データを過適合しているシナリオを検出するのに役立ちます。

学習セットと検証セットにデータをランダムに分割します。

inds               = randperm(size(predictors,4));
L                  = round(0.99 * size(predictors,4));
trainPredictors    = predictors(:,:,:,inds(1:L));
trainTargets       = targets(:,:,:,inds(1:L));
validatePredictors = predictors(:,:,:,inds(L+1:end));
validateTargets    = targets(:,:,:,inds(L+1:end));

全結合層での音声ノイズ除去

最初に全結合層で構成されたノイズ除去ネットワークについて考えます。全結合層の各ニューロンは、前の層からのすべての活性化に接続されます。全結合層は、入力に重み行列を乗算し、バイアス ベクトルを加算します。重み行列とバイアス ベクトルの次元は、層のニューロン数と前の層からの活性化の数によって決定されます。

ネットワークの層を定義します。サイズ NumFeatures x NumSegments (このサンプルでは 129 x 8) のイメージになるように入力サイズを指定します。2 つの隠れ全結合層を、それぞれ 1024 ニューロンで定義します。純粋な線形システムであるため、正規化線形ユニット (ReLU) 層がある各隠れ全結合層に従います。バッチ正規化層は、出力の平均と標準偏差を正規化します。129 ニューロンをもつ全結合層を追加し、その後回帰層を追加します。

layers = [
    imageInputLayer([numFeatures,numSegments])
    fullyConnectedLayer(1024)
    batchNormalizationLayer
    reluLayer
    fullyConnectedLayer(1024)
    batchNormalizationLayer
    reluLayer
    fullyConnectedLayer(numFeatures)
    regressionLayer
    ];

次に、ネットワークの学習オプションを指定します。ネットワークが学習データから 3 個のパスを作るよう MaxEpochs3 に設定します。ネットワークが一度に 128 の学習信号を確認するよう 128MiniBatchSize を設定します。Plots"training-progress" として指定し、反復回数の増大に応じた学習の進行状況を示すプロットを生成します。Verbosefalse に設定し、プロットで示されるデータに対応する表出力のコマンド ライン ウィンドウへの表示を無効にします。Shuffle"every-epoch" として指定して、各エポックの最初に学習シーケンスをシャッフルします。LearnRateSchedule"piecewise" に指定して、特定のエポック数 (1) が経過するたびに、指定された係数 (0.9) によって学習率を減らします。ValidationData を検証予測子とターゲットに設定します。検証の平均二乗誤差がエポックごとに 1 回計算されるように ValidationFrequency を設定します。この例では、適応モーメント推定 (Adam) ソルバーを使用します。

miniBatchSize = 128;
options = trainingOptions("adam", ...
    "MaxEpochs",3, ...
    "InitialLearnRate",1e-5,...
    "MiniBatchSize",miniBatchSize, ...
    "Shuffle","every-epoch", ...
    "Plots","training-progress", ...
    "Verbose",false, ...
    "ValidationFrequency",floor(size(trainPredictors,4)/miniBatchSize),...
    "LearnRateSchedule","piecewise",...
    "LearnRateDropFactor",0.9,...
    "LearnRateDropPeriod",1,...
    "ValidationData",{validatePredictors,validateTargets});

trainNetwork を使用し、指定した学習オプションと層のアーキテクチャでネットワークに学習させます。学習セットが大きいため、学習プロセスには数分かかる場合があります。ネットワークにゼロから学習させる代わりに、事前学習済みのネットワークを読み込む場合は、doTrainingfalse に設定します。

doTraining = true;
if doTraining
    denoiseNetFullyConnected = trainNetwork(trainPredictors,trainTargets,layers,options);
else
    s = load("denoisenet.mat");
    denoiseNetFullyConnected = s.denoiseNetFullyConnected;
    cleanMean = s.cleanMean;
    cleanStd  = s.cleanStd;
    noisyMean = s.noisyMean;
    noisyStd  = s.noisyStd;
end

ネットワークの全結合層の重みの数をカウントします。

numWeights = 0;
for index = 1:numel(denoiseNetFullyConnected.Layers)
    if isa(denoiseNetFullyConnected.Layers(index),"nnet.cnn.layer.FullyConnectedLayer")
        numWeights = numWeights + numel(denoiseNetFullyConnected.Layers(index).Weights);
    end
end
fprintf("The number of weights is %d.\n",numWeights);
The number of weights is 2237440.

畳み込み層での音声ノイズ除去

全結合層の代わりに畳み込み層を使用するネットワークについて考えます [3]。2 次元畳み込み層は、入力にスライディング フィルターを適用します。この層では、入力に沿って垂直方向および水平方向にフィルターを移動させ、重みと入力のドット積を計算し、バイアス項を加算することによって、入力を畳み込みます。畳み込み層は、通常、全結合層より少ないパラメーターで構成されます。

16 の畳み込み層で構成される、[3] で説明されている完全畳み込みネットワークの層を定義します。最初の 15 の畳み込み層は、3 つの層のグループで 5 回繰り返されます。それぞれ、フィルター幅が 9、5、9、フィルター数が 18、30、8 です。最後の畳み込み層は、フィルター幅が 129、フィルターが 1 です。このネットワークには、畳み込みは一方向のみで (周波数次元に沿って) 実行され、時間次元に沿ってフィルター幅は最初の 1 つを除いてすべての層で 1 に設定されます。全結合ネットワークと同様、畳み込み層の後に ReLu 層とバッチ正規化層が続きます。

layers = [imageInputLayer([numFeatures,numSegments])
          convolution2dLayer([9 8],18,"Stride",[1 100],"Padding","same")
          batchNormalizationLayer
          reluLayer

          repmat(...
          [convolution2dLayer([5 1],30,"Stride",[1 100],"Padding","same")
          batchNormalizationLayer
          reluLayer
          convolution2dLayer([9 1],8,"Stride",[1 100],"Padding","same")
          batchNormalizationLayer
          reluLayer
          convolution2dLayer([9 1],18,"Stride",[1 100],"Padding","same")
          batchNormalizationLayer
          reluLayer], 4,1)

          convolution2dLayer([5 1],30,"Stride",[1 100],"Padding","same")
          batchNormalizationLayer
          reluLayer
          convolution2dLayer([9 1],8,"Stride",[1 100],"Padding","same")
          batchNormalizationLayer
          reluLayer

          convolution2dLayer([129 1],1,"Stride",[1 100],"Padding","same")

          regressionLayer
          ];

学習オプションは、全結合ネットワークのオプションと同じになります。ただし、検証ターゲット信号の次元が回帰層で必要な次元と一致するように並べ替えられる点が異なります。

options = trainingOptions("adam", ...
    "MaxEpochs",3, ...
    "InitialLearnRate",1e-5,...
    "MiniBatchSize",miniBatchSize, ...
    "Shuffle","every-epoch", ...
    "Plots","training-progress", ...
    "Verbose",false, ...
    "ValidationFrequency",floor(size(trainPredictors,4)/miniBatchSize),...
    "LearnRateSchedule","piecewise",...
    "LearnRateDropFactor",0.9,...
    "LearnRateDropPeriod",1,...
    "ValidationData",{validatePredictors,permute(validateTargets,[3 1 2 4])});

trainNetwork を使用し、指定した学習オプションと層のアーキテクチャでネットワークに学習させます。学習セットが大きいため、学習プロセスには数分かかる場合があります。ネットワークにゼロから学習させる代わりに、事前学習済みのネットワークを読み込む場合は、doTrainingfalse に設定します。

doTraining = true;
if doTraining
    denoiseNetFullyConvolutional = trainNetwork(trainPredictors,permute(trainTargets,[3 1 2 4]),layers,options);
else
    s = load("denoisenet.mat");
    denoiseNetFullyConvolutional = s.denoiseNetFullyConvolutional;
    cleanMean = s.cleanMean;
    cleanStd  = s.cleanStd;
    noisyMean = s.noisyMean;
    noisyStd  = s.noisyStd;
end
IdleTimeout has been reached.
Parallel pool using the 'local' profile is shutting down.

ネットワークの全結合層の重みの数をカウントします。

numWeights = 0;
for index = 1:numel(denoiseNetFullyConvolutional.Layers)
    if isa(denoiseNetFullyConvolutional.Layers(index),"nnet.cnn.layer.Convolution2DLayer")
        numWeights = numWeights + numel(denoiseNetFullyConvolutional.Layers(index).Weights);
    end
end
fprintf("The number of weights in convolutional layers is %d\n",numWeights);
The number of weights in convolutional layers is 31812

ノイズ除去ネットワークのテスト

"cv-valid-test" フォルダーからの音声信号を使用して、学習済みネットワークの性能をテストします。audioDatastore を使用して、"cv-valid-test" フォルダーにファイルのデータストアを作成します。

ads = audioDatastore(fullfile(datafolder,"cv-valid-test"));

データストアのファイルをシャッフルします。

ads = shuffle(ads);

データストアからファイルの内容を読み取ります。

[cleanAudio,info] = read(ads);

オーディオの長さがサンプルレート変換の間引き係数の倍数であることを確認してください。

L            = floor( numel(cleanAudio)/decimationFactor);
cleanAudio   = cleanAudio(1:decimationFactor*L);

オーディオ信号を 8 kHz に変換します。

cleanAudio = src(cleanAudio);
reset(src)

このテスト段階で、学習段階で使用されなかった洗浄機のノイズで音声を破損させます。

noise = audioread("WashingMachine-16-8-mono-200secs.wav");

洗浄機のノイズ ベクトルからランダムなノイズのセグメントを作成します。

randind      = randi(numel(noise) - numel(cleanAudio) , [1 1]);
noiseSegment = noise(randind : randind + numel(cleanAudio) - 1);

SNR が 0 dB となるように音声信号にノイズを付加します。

noisePower   = sum(noiseSegment.^2);
cleanPower   = sum(cleanAudio.^2);
noiseSegment = noiseSegment .* sqrt(cleanPower/noisePower);
noisyAudio   = cleanAudio + noiseSegment;

stft を使用して、ノイズを含むオーディオ信号から振幅 STFT ベクトルを生成します。

noisySTFT  = stft(noisyAudio,'Window',win,'OverlapLength',overlap,'FFTLength',ffTLength);
noisyPhase = angle(noisySTFT(numFeatures-1:end,:));
noisySTFT  = abs(noisySTFT(numFeatures-1:end,:));

ノイズを含む STFT から 8 つのセグメントの学習予測子信号を生成します。連続する予測子間のオーバーラップは、7 セグメントです。

noisySTFT  = [noisySTFT(:,1:numSegments-1) noisySTFT];
predictors = zeros( numFeatures, numSegments , size(noisySTFT,2) - numSegments + 1);
for index = 1 : size(noisySTFT,2) - numSegments + 1
    predictors(:,:,index) = noisySTFT(:,index:index + numSegments - 1);
end

学習段階で計算された平均値と標準偏差によって予測子を正規化します。

predictors(:) = (predictors(:) - noisyMean) / noisyStd;

2 つの学習済みネットワークで predict を使用してノイズ除去された振幅 STFT を計算します。

predictors = reshape(predictors, [numFeatures,numSegments,1,size(predictors,3)]);
STFTFullyConnected = predict(denoiseNetFullyConnected, predictors);
STFTFullyConvolutional = predict(denoiseNetFullyConvolutional, predictors);

学習段階で使用された平均値と標準偏差によって出力をスケーリングします。

STFTFullyConnected(:)     = cleanStd * STFTFullyConnected(:)     +  cleanMean;
STFTFullyConvolutional(:) = cleanStd * STFTFullyConvolutional(:) +  cleanMean;

片側 STFT を中央揃え STFT に変換します。

STFTFullyConnected     = STFTFullyConnected.' .* exp(1j*noisyPhase);
STFTFullyConnected     = [conj(STFTFullyConnected(end-1:-1:2,:)) ; STFTFullyConnected];
STFTFullyConvolutional = squeeze(STFTFullyConvolutional) .* exp(1j*noisyPhase);
STFTFullyConvolutional = [conj(STFTFullyConvolutional(end-1:-1:2,:)) ; STFTFullyConvolutional];

ノイズ除去後の音声信号を計算します。istft は逆 STFT を実行します。ノイズを含む STFT ベクトルの位相を使用して、時間領域信号を再構成します。

denoisedAudioFullyConnected     = istft(STFTFullyConnected,  ...
                                        'Window',win,'OverlapLength',overlap, ...
                                        'FFTLength',ffTLength,'ConjugateSymmetric',true);
denoisedAudioFullyConvolutional = istft(STFTFullyConvolutional,  ...
                                        'Window',win,'OverlapLength',overlap, ...
                                        'FFTLength',ffTLength,'ConjugateSymmetric',true);

クリーンなオーディオ信号、ノイズを含むオーディオ信号、およびノイズ除去後のオーディオ信号をプロットします。

figure
subplot(4,1,1)
t = (1/fs) * (0:numel(denoisedAudioFullyConnected)-1);
plot(t,cleanAudio(1:numel(denoisedAudioFullyConnected)))
title("Clean Speech")
grid on
subplot(4,1,2)
plot(t,noisyAudio(1:numel(denoisedAudioFullyConnected)))
title("Noisy Speech")
grid on
subplot(4,1,3)
plot(t,denoisedAudioFullyConnected)
title("Denoised Speech (Fully Connected Layers)")
grid on
subplot(4,1,4)
plot(t,denoisedAudioFullyConvolutional)
title("Denoised Speech (Convolutional Layers)")
grid on
xlabel("Time (s)")

クリーンなスペクトログラム、ノイズを含むスペクトログラム、およびノイズ除去後のスペクトログラムをプロットします。

h = figure;
subplot(4,1,1)
spectrogram(cleanAudio,win,overlap,ffTLength,fs);
title("Clean Speech")
grid on
subplot(4,1,2)
spectrogram(noisyAudio,win,overlap,ffTLength,fs);
title("Noisy Speech")
grid on
subplot(4,1,3)
spectrogram(denoisedAudioFullyConnected,win,overlap,ffTLength,fs);
title("Denoised Speech (Fully Connected Layers)")
grid on
subplot(4,1,4)
spectrogram(denoisedAudioFullyConvolutional,win,overlap,ffTLength,fs);
title("Denoised Speech (Convolutional Layers)")
grid on
p = get(h,'Position');
set(h,'Position',[p(1) 65 p(3) 800]);

ノイズを含む音声を再生します。

sound(noisyAudio,fs)

全結合層をもつネットワークからノイズ除去後の音声を再生します。

sound(denoisedAudioFullyConnected,fs)

畳み込み層をもつネットワークからノイズ除去後の音声を再生します。

sound(denoisedAudioFullyConvolutional,fs)

クリーンな音声を再生します。

sound(cleanAudio,fs)

testDenoisingNets を呼び出すことによってデータストアのファイルをさらにテストできます。時間領域と周波数領域を作成する関数は、上記で強調表示したものをプロットします。さらに、クリーンなオーディオ信号、ノイズを含むオーディオ信号、およびノイズ除去後のオーディオ信号を返します。

[cleanAudio,noisyAudio,denoisedAudioFullyConnected,denoisedAudioFullyConvolutional] = testDenoisingNets(ads,denoiseNetFullyConnected,denoiseNetFullyConvolutional,noisyMean,noisyStd,cleanMean,cleanStd);

リアルタイム アプリケーション

前の節の手順は、predict にノイズを含む信号の全体のスペクトルを渡します。これは、低レイテンシが要件であるリアルタイム アプリケーションには適していません。

ストリーミング用リアルタイム バージョンのノイズ除去ネットワークをシミュレートする方法の例については、speechDenoisingRealtimeApp を実行します。アプリは全結合層をもつネットワークを使用します。オーディオ フレームの長さは、STFT ホップ サイズ (0.25 * 256 = 64 サンプル) と同じです。

speechDenoisingRealtimeApp はシミュレーションを対話的に実行するように設計された UI (ユーザー インターフェイス) を起動します。UI ではパラメーターを調整でき、結果はシミュレーションにすぐに反映されます。さらに、ノイズ除去された出力で操作するノイズ ゲートを有効または無効にして、ノイズをさらに減らしたり、ノイズ ゲートのアタック時間、リリース時間、しきい値の微調整を行うことができます。ノイズを含むオーディオ、クリーンなオーディオまたはノイズ除去後のオーディオを UI によって再生することができます。

スコープは、クリーンな信号、ノイズを含む信号およびノイズ除去後の信号とノイズ ゲートの増幅率をプロットします。

参考文献

[1] https://voice.mozilla.org/

[2] "Experiments on Deep Learning for Speech Denoising", Ding Liu, Paris Smaragdis, Minje Kim, INTERSPEECH, 2014.

[3] "A Fully Convolutional Neural Network for Speech Enhancement", Se Rim Park, Jin Won Lee, INTERSPEECH, 2017.