Esta página aún no se ha traducido para esta versión. Puede ver la versión más reciente de esta página en inglés.

Denoise Speech Using Deep Learning Networks

Este ejemplo muestra cómo eliminar el ruido de las señales de voz mediante redes de aprendizaje profundo. En el ejemplo se comparan dos tipos de redes aplicadas a la misma tarea: totalmente conectadas y convolucionales.

Introducción

El objetivo de la denoising del habla es eliminar el ruido de las señales de voz y, al mismo tiempo, mejorar la calidad y la inteligibilidad del habla. En este ejemplo se muestra la eliminación del ruido de la lavadora de las señales de voz mediante redes de aprendizaje profundo. En el ejemplo se comparan dos tipos de redes aplicadas a la misma tarea: totalmente conectadas y convolucionales.

Resumen del problema

Considere la siguiente señal de voz muestreada a 8 kHz.

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

Agregue el ruido de la lavadora a la señal de voz. Establezca la potencia de ruido de tal forma que la relación señal-ruido (SNR) sea cero 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;

Escucha la señal de voz ruidoso.

sound(noisyAudio,fs)

Visualice las señales originales y ruidosos.

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

El objetivo de la denoising de voz es eliminar el ruido de la lavadora de la señal de voz mientras se minimizan los artefactos no deseados en la voz de salida.

Examine el conjunto de datos

En este ejemplo se utiliza el conjunto de datos de voz común de Mozilla [ ] para entrenar y probar las redes de aprendizaje profundo.1 El conjunto de datos contiene grabaciones de 48 kHz de sujetos que hablan frases cortas. Descargue el conjunto de datos y descomprima el archivo descargado. Establézalo en la ubicación de los datos.datafolder

datafolder = PathToDatabase;

Se usa para crear un almacén de datos para todos los archivos del conjunto de datos.audioDatastore

ads0 = audioDatastore(fullfile(datafolder,"clips"));

Se utiliza para leer los metadatos asociados con los archivos de audio del conjunto de entrenamiento.readtable Los metadatos están contenidos en el archivo.train.tsv Inspeccione las primeras filas de los metadatos.

metadata = readtable(fullfile(datafolder,"train.tsv"),"FileType","text"); head(metadata)
ans=8×8 table
                                                                 client_id                                                                                                                                  path                                                                                                               sentence                                               up_votes    down_votes        age           gender        accent  
    ____________________________________________________________________________________________________________________________________    ____________________________________________________________________________________________________________________________________    ______________________________________________________________________________________________    ________    __________    ____________    __________    __________

    {'55451a804635a88160a09b9b8122e3dddba46c2e6df2d6d9ec9d3445c38180fd18516d76acc9035978f27ee1f798f480dcb55dcbd31a142374c3af566c9be3c4'}    {'f480b8a93bf84b7f74c141284a71c39ff47d264a75dc905dc918286fb67f0333595206ff953a27b8049c7ec09ea895aa66d1cd4f7547535167d3d7901d12feab'}    {'Unfortunately, nobody can warrant the sanctions that will have an effect on the community.'}       3            0         {'twenties'}    {'female'}    {'canada'}
    {'55451a804635a88160a09b9b8122e3dddba46c2e6df2d6d9ec9d3445c38180fd18516d76acc9035978f27ee1f798f480dcb55dcbd31a142374c3af566c9be3c4'}    {'7647873ce81cd81c90b9e0fe3cb6c85cc03df7c0c4fdf2a04c356d75063af4b9de296a24e3bef0ba7ef0b0105d166abf35597e9c9a4b3857fd09c57b79f65a99'}    {'Came down and picked it out himself.'                                                      }       2            0         {'twenties'}    {'female'}    {'canada'}
    {'55451a804635a88160a09b9b8122e3dddba46c2e6df2d6d9ec9d3445c38180fd18516d76acc9035978f27ee1f798f480dcb55dcbd31a142374c3af566c9be3c4'}    {'81a3dd920de6251cc878a940aff258e859ef13efb9a6446610ab907e08832fafdc463eda334ee74a24cc02e3652a09f5573c133e6f46886cb0ba463efc7a6b43'}    {'She crossed the finish line just in time.'                                                 }       2            0         {'twenties'}    {'female'}    {'canada'}
    {'5b8c0f566c1201a94e684a334cf8a2cbced8a009a5a346fc24f1d51446c6b8610fc7bd78f69e559b29d138ab92652a45408ef87c3ec0e426d2fc5f1b2b44935b'}    {'5e6fc96a7bc91ec2261a51e7713bb0ed8a9f4fa9e20a38060dc4544fb0c2600c192d6e849915acaf8ea0766a9e1d481557d674363e780dbb064586352e560f2c'}    {'Please find me the Home at Last trailer.'                                                  }       2            0         {0×0 char  }    {0×0 char}    {0×0 char}
    {'5b8c0f566c1201a94e684a334cf8a2cbced8a009a5a346fc24f1d51446c6b8610fc7bd78f69e559b29d138ab92652a45408ef87c3ec0e426d2fc5f1b2b44935b'}    {'3a0929094a9aac80b961d479a3ee54311cc0d60d51fe8f97071edc2999e7747444b261d2c0c2345f86fb8161f3b73a14dc19da911d19ca8d9db39574c6199a34'}    {'Play something by Louisiana Blues'                                                         }       2            0         {0×0 char  }    {0×0 char}    {0×0 char}
    {'5b8c0f566c1201a94e684a334cf8a2cbced8a009a5a346fc24f1d51446c6b8610fc7bd78f69e559b29d138ab92652a45408ef87c3ec0e426d2fc5f1b2b44935b'}    {'82b8edf3f1420295069b5bb4543b8f349faaca28f45a3279b0cd64c39d16afb590a4cc70ed805020161f8c1f94bc63d3b69756fbc5a0462ce12d2e17c4ebaeeb'}    {'When is The Devil with Hitler playing in Bow Tie Cinemas'                                  }       2            0         {0×0 char  }    {0×0 char}    {0×0 char}
    {'60013a707ac8cdd2b44427418064915f7810b2d58d52d8f81ad3c6406b8922d61c134259747f3c73d2e64c885fc6141761d29f7e6ada7d6007c48577123e4af0'}    {'8606bac841a08bcbf5ddb83c768103c467ffd1bf38b16052414210dc3ce3267561cb0368d227b6eb420dc147387cc1807032102b6248a13a40f83e5ac06d7122'}    {'Give me the list of animated movies playing at the closest movie house'                    }       3            0         {0×0 char  }    {0×0 char}    {0×0 char}
    {'60013a707ac8cdd2b44427418064915f7810b2d58d52d8f81ad3c6406b8922d61c134259747f3c73d2e64c885fc6141761d29f7e6ada7d6007c48577123e4af0'}    {'0f7e63d320cfbf6ea5d1cda674007131d804a06f5866d38f81da7def33a4ce8ee4f2cb7e47b45eee97903cad3160b3a10f715862227e8ecdc3fb3bafc6b4279d'}    {'The better part of valor is discretion'                                                    }       3            0         {0×0 char  }    {0×0 char}    {0×0 char}

Busque los archivos en el almacén de datos correspondientes al conjunto de entrenamiento.

csvFiles = metadata.path; adsFiles =  ads0.Files; adsFiles = cellfun(@HelperGetFilePart,adsFiles,'UniformOutput',false); [~,indA] = intersect(adsFiles,csvFiles);

Cree un conjunto de entrenamiento de subconjuntoa a partir del conjunto de datos grande.

ads = subset(ads0,indA);

Entrenará las redes de aprendizaje profundo en un subconjunto de los archivos. Cree un subconjunto de almacén de datos que contenga los primeros 1000 archivos del almacén de datos.

ads = subset(ads,1:1000);

Se utiliza para obtener el contenido del primer archivo en el almacén de datos.read

[audio,info] = read(ads);

Escucha la señal del habla.

sound(audio,info.SampleRate)

Trazar la señal de voz.

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

Descripción general del sistema de aprendizaje profundo

El esquema básico de entrenamiento de aprendizaje profundo se muestra a continuación. Tenga en cuenta que, dado que la voz generalmente cae por debajo de 4 kHz, primero reduce la muestra de las señales de audio limpias y ruidosos a 8 kHz para reducir la carga computacional de la red. Las señales de red predictor y de destino son los espectros de magnitud de las señales de audio ruidosos y limpios, respectivamente. La salida de la red es el espectro de magnitud de la señal despulsada. La red de regresión utiliza la entrada predictora para minimizar el error cuadrado medio entre su salida y el destino de entrada. El audio desruidoso se convierte de nuevo al dominio de tiempo utilizando el espectro de magnitud de salida y la fase de la señal ruidosa [ ].2

El audio se transforma en el dominio de frecuencia mediante la transformación Fourier de tiempo corto (STFT), con una longitud de ventana de 256 muestras, una superposición del 75% y una ventana Hamming. Reduce el tamaño del vector espectral a 129 dejando caer las muestras de frecuencia correspondientes a las frecuencias negativas (porque la señal de voz de dominio de tiempo es real, esto no conduce a ninguna pérdida de información). La entrada predictora consta de 8 vectores STFT ruidosos consecutivos, de modo que cada estimación de salida STFT se calcula sobre la base de los vectores STFT ruidosos actuales y los 7 vectores STFT ruidosos anteriores.

Objetivos y predictores STFT

Esta sección ilustra cómo generar las señales de destino y predictor a partir de un archivo de entrenamiento.

En primer lugar, defina los parámetros del sistema:

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

Defina el convertidor de frecuencia de muestreo utilizado para convertir el audio de 48 kHz a 8 kHz.

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

Se utiliza para obtener el contenido de un archivo de audio del almacén de datos.read

audio = read(ads);

Asegúrese de que la longitud del audio es un múltiplo del factor de diezma del convertidor de frecuencia de muestreo.

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

Convierta la señal de audio a 8 kHz.

audio = src(audio); reset(src)

Cree un segmento de ruido aleatorio a partir del vector de ruido de la lavadora.

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

Agregue el ruido a la señal de voz tal que el SNR sea 0 dB.

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

Se utiliza para generar vectores STFT de magnitud a partir de las señales de audio originales y ruidosos.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,:));

Genere las señales predictoras de entrenamiento de 8 segmentos del ruidoso STFT. La superposición entre predictores consecutivos es de 7 segmentos.

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

Establezca los objetivos y los predictores. La última dimensión de ambas variables corresponde al número de pares de predictor/destino distintos generados por el archivo de audio. Cada predictor es 129 por 8, y cada objetivo es 129 por 1.

targets = cleanSTFT; size(targets)
ans = 1×2

   129   457

predictors = stftSegments; size(predictors)
ans = 1×3

   129     8   457

Extraer operaciones mediante matrices altas

Para acelerar el procesamiento, extraiga secuencias de características de los segmentos de voz de todos los archivos de audio del almacén de datos mediante matrices altas. A diferencia de las matrices en memoria, las matrices altas suelen permanecer sin evaluar hasta que se llama a la función.gather Esta evaluación diferida le permite trabajar rápidamente con grandes conjuntos de datos. Cuando finalmente solicita la salida mediante , MATLAB combina los cálculos en cola siempre que sea posible y toma el número mínimo de pasadas a través de los datos.gather Si tiene Parallel Computing Toolbox™, puede utilizar matrices altas en la sesión local de MATLAB o en un grupo paralelo local. También puede ejecutar cálculos de matrices altas en un clúster si tiene MATLAB® Parallel Server™ instalado.

En primer lugar, convierta el almacén de datos en una matriz alta.

reset(ads) T = tall(ads)
Starting parallel pool (parpool) using the 'local' profile ... Connected to the parallel pool (number of workers: 8).  T =    M×1 tall cell array      {156144×1 double}     {176880×1 double}     {193008×1 double}     {144624×1 double}     {212592×1 double}     {219504×1 double}     {198768×1 double}     {247152×1 double}         :        :         :        : 

La pantalla indica que aún no se conoce el número de filas (correspondiente al número de archivos del almacén de datos), M. M es un marcador de posición hasta que se completa el cálculo.

Extraiga el objetivo y la magnitud del predictor STFT de la tabla alta. Esta acción crea nuevas variables de matriz alta para utilizar en cálculos posteriores. La función realiza los pasos ya resaltados en la sección.HelperGenerateSpeechDenoisingFeaturesObjetivos y predictores STFT El comando se aplica al contenido de cada archivo de audio en el almacén de datos.cellfunHelperGenerateSpeechDenoisingFeatures

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

Se utiliza para evaluar los destinos y los predictores.gather

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

Es una buena práctica normalizar todas las entidades a cero media y unidad desviación estándar.

Calcular la media y la desviación estándar de los predictores y objetivos, respectivamente, y utilizarlos para normalizar los datos.

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;

Reforme los predictores y los objetivos a las dimensiones esperadas por las redes de aprendizaje profundo.

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

Utilizará el 1% de los datos para la validación durante el entrenamiento. La validación es útil para detectar escenarios en los que la red está sobreajustando los datos de entrenamiento.

Divida aleatoriamente los datos en conjuntos de entrenamiento y validación.

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));

Denoising de voz con capas totalmente conectadas

En primer lugar, considere una red de denoising compuesta de capas totalmente conectadas. Cada neurona de una capa totalmente conectada está conectada a todas las activaciones de la capa anterior. Una capa totalmente conectada multiplica la entrada por una matriz de peso y, a continuación, agrega un vector de sesgo. Las dimensiones de la matriz de peso y el vector de sesgo están determinadas por el número de neuronas en la capa y el número de activaciones de la capa anterior.

Defina las capas de la red. Especifique el tamaño de entrada para que sean imágenes de tamaño NumFeatures-by-NumSegments (129-by-8 en este ejemplo). Defina dos capas ocultas totalmente conectadas, cada una con 1024 neuronas. Puesto que los sistemas puramente lineales, siga cada capa oculta totalmente conectada con una capa de unidad lineal rectificada (ReLU). Las capas de normalización por lotes normalizan las medias y las desviaciones estándar de las salidas. Añade una capa totalmente conectada con 129 neuronas, seguida de una capa de regresión.

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

A continuación, especifique las opciones de entrenamiento para la red. Establézalo para que la red realice 3 pasadas a través de los datos de entrenamiento.MaxEpochs3 Conjunto de modo que la red mire 128 señales de entrenamiento a la vez.MiniBatchSize128 Especifique como para generar trazados que muestren el progreso del entrenamiento a medida que aumenta el número de iteraciones.Plots"training-progress" Establézcalo para deshabilitar la impresión de la salida de tabla que corresponde a los datos mostrados en el trazado en la ventana de línea de comandos.Verbosefalse Especifique como para barajar las secuencias de entrenamiento al principio de cada época.Shuffle"every-epoch" Especifique para disminuir la tasa de aprendizaje en un factor especificado (0,9) cada vez que haya pasado un cierto número de épocas (1).LearnRateSchedule"piecewise" Establézalo en los predictores y destinos de validación.ValidationData Establezca de forma que el error cuadrado medio de validación se calcule una vez por época.ValidationFrequency En este ejemplo se utiliza el solucionador de estimación de momento adaptable (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});

Entrene la red con las opciones de entrenamiento y la arquitectura de capa especificadas utilizando .trainNetwork Debido a que el conjunto de entrenamiento es grande, el proceso de entrenamiento puede tardar varios minutos. Para cargar una red preentrenada en lugar de entrenar una red desde cero, establezca en .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

Cuente el número de pesos en las capas totalmente conectadas de la red.

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. 

Denoising de voz con capas convolucionales

Considere una red que utilice capas convolucionales en lugar de capas totalmente conectadas [3]. Una capa convolucional 2D aplica filtros deslizantes a la entrada. La capa convoluciona la entrada moviendo los filtros a lo largo de la entrada vertical y horizontalmente y calculando el producto de punto de los pesos y la entrada, y luego agregando un término de sesgo. Las capas convolucionales suelen constar de menos parámetros que las capas totalmente conectadas.

Defina las capas de la red totalmente convolucional descrita en [ ], que comprende 16 capas convolucionales.3 Las primeras 15 capas convolucionales son grupos de 3 capas, repetidas 5 veces, con anchos de filtro de 9, 5 y 9, y número de filtros de 18, 30 y 8, respectivamente. La última capa convolucional tiene un ancho de filtro de 129 y 1 filtro. En esta red, las convoluciones se realizan en una sola dirección (a lo largo de la dimensión de frecuencia) y el ancho del filtro a lo largo de la dimensión de tiempo se establece en 1 para todas las capas excepto la primera. Al igual que la red totalmente conectada, las capas convolucionales van seguidas de las capas de normalización relu y por lotes.

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           ];

Las opciones de entrenamiento son idénticas a las opciones de la red totalmente conectada, excepto que las dimensiones de las señales de destino de validación se procesan para que sean coherentes con las dimensiones esperadas por la capa de regresión.

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])});

Entrene la red con las opciones de entrenamiento y la arquitectura de capa especificadas utilizando .trainNetwork Debido a que el conjunto de entrenamiento es grande, el proceso de entrenamiento puede tardar varios minutos. Para cargar una red preentrenada en lugar de entrenar una red desde cero, establezca en .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

Cuente el número de pesos en las capas totalmente conectadas de la red.

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 

Prueba las redes de denoising

Creará un conjunto de datos de validación con el mismo enfoque que usó para el conjunto de datos de entrenamiento. Utilice la función para leer los metadatos asociados con los archivos de validación.readtable

metadata = readtable(fullfile(datafolder,"test.tsv"),"FileType","text");

Busque los archivos de validación en el almacén de datos.

csvFiles   = metadata.path; adsFiles =  ads0.Files; adsFiles = cellfun(@HelperGetFilePart,adsFiles,'UniformOutput',false); [~,indA] = intersect(adsFiles,csvFiles);

Cree un almacén de datos de validación desde el almacén de datos grande.

ads = subset(ads0,indA);  % Create a datastore subset containing the first 100 files of the % datastore. ads = subset(ads,1:100);

Baraja los archivos en el almacén de datos.

ads = shuffle(ads);

Lea el contenido de un archivo desde el almacén de datos.

[cleanAudio,info] = read(ads);

Asegúrese de que la longitud del audio es un múltiplo del factor de diezma del convertidor de frecuencia de muestreo.

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

Convierta la señal de audio a 8 kHz.

cleanAudio = src(cleanAudio); reset(src)

En esta etapa de prueba, se corrompe el habla con el ruido de la lavadora no utilizado en la etapa de entrenamiento.

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

Cree un segmento de ruido aleatorio a partir del vector de ruido de la lavadora.

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

Agregue el ruido a la señal de voz tal que el SNR sea 0 dB.

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

Se utiliza para generar vectores STFT de magnitud a partir de las señales de audio ruidosos.stft

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

Genere las señales predictoras de entrenamiento de 8 segmentos del ruidoso STFT. La superposición entre predictores consecutivos es de 7 segmentos.

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

Normalizar los predictores por la media y la desviación estándar calculadas en la etapa de entrenamiento.

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

Calcular la magnitud deruido STFT mediante el uso con las dos redes entrenadas.predict

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

Escale las salidas por la media y la desviación estándar utilizadas en la etapa de entrenamiento.

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

Convierta el STFT unilateral en un STFT centrado.

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];

Calcular las señales de voz despulsadas. realiza el STFT inverso.istft Utilice la fase de los vectores STFT ruidosos para reconstruir la señal de dominio de tiempo.

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

Trazar las señales de audio limpias, ruidosas y despulsadas.

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)")

Trazar los espectrogramas limpios, ruidosos y desruidos.

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]);

Escucha el ruidoso discurso.

sound(noisyAudio,fs)

Escuche el discurso desruido de la red con capas totalmente conectadas.

sound(denoisedAudioFullyConnected,fs)

Escuche el discurso desruido de la red con capas convolucionales.

sound(denoisedAudioFullyConvolutional,fs)

Escucha el discurso limpio.

sound(cleanAudio,fs)

Puede probar más archivos desde el almacén de datos llamando a .testDenoisingNets La función produce las gráficas de dominio de tiempo y dominio de frecuencia resaltadas anteriormente, y también devuelve las señales de audio limpias, ruidosas y deruidos.

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

Aplicación en tiempo real

El procedimiento de la sección anterior pasa todo el espectro de la señal ruidoso a .predict Esto no es adecuado para aplicaciones en tiempo real donde la latencia baja es un requisito.

Ejecute un ejemplo de cómo simular una versión en tiempo real y de streaming de la red de denoising.speechDenoisingRealtimeApp La aplicación utiliza la red con capas totalmente conectadas. La longitud de fotograma de audio es igual al tamaño del salto STFT, que es 0,25 * 256 x 64 muestras.

inicia una interfaz de usuario (UI) diseñada para interactuar con la simulación.speechDenoisingRealtimeApp La interfaz de usuario le permite ajustar los parámetros y los resultados se reflejan en la simulación al instante. También puede activar/desactivar una puerta de ruido que funcione en la salida denoised para reducir aún más el ruido, así como ajustar el tiempo de ataque, el tiempo de liberación y el umbral de la puerta de ruido. Puede escuchar el audio ruidoso, limpio o deruido desde la interfaz de usuario.

El alcance traza las señales limpias, ruidosas y deruidos, así como la ganancia de la puerta de ruido.

Referencias

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

[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.