[Dacon] 음성 분류 경진대회
데이콘의 “음성 분류 경진대회”에 참여하여 작성한 글이며, 음성 데이터에 대한 데이터 증강(Data Augmentation)과 음성 특성 추출(Feature Extraction) 구현 방법을 서술합니다.
코드실행은 Google Colab의 CPU, Standard RAM 환경에서 진행했습니다.
➔ 데이콘에서 읽기
0. Import Packages
- 주요 라이브러리 불러오기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import numpy as np
import pandas as pd
import random as rn
import os
from scipy.io import wavfile
import librosa
import matplotlib.pyplot as plt
import seaborn as sns
import IPython.display as ipd
import librosa.display
import warnings
warnings.filterwarnings("ignore")
%matplotlib inline
1. Load and explore dataset
- 데이터 불러오기
1
2
train = pd.read_csv('/content/drive/MyDrive/Speech_classification/train.csv')
test = pd.read_csv('/content/drive/MyDrive/Speech_classification/test.csv')
- 한 음성의 Waveplot을 확인해보겠습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
a_filename = '/content/drive/MyDrive/Speech_classification/dataset/train/001.wav'
samples, sample_rate = librosa.load(a_filename)
plt.figure(figsize=(10, 7))
# plt.plot(np.linspace(0, sample_rate/len(samples), len(samples)), samples)
librosa.display.waveplot(samples, sr=40000)
plt.xlabel('time', fontsize = 14)
plt.ylabel('amplitude', fontsize = 14)
plt.title('001.wav | Length : ' + str(len(samples)))
plt.show()
1
2
print(sample_rate)
print(samples)
22050 [0.00013066 0.00016804 0.00014106 ... 0.00017342 0.00017514 0. ]
- 한 음성 샘플에 대한 Spectrogram을 생성하겠습니다.
↪ Short term Fourier transform (STFT)의 Magnitude를 DB-스케일로 변환하여 Spectrogram을 생성합니다.
1
2
3
4
5
6
7
8
9
samples, sample_rate = librosa.load(a_filename)
X = librosa.stft(samples) # data -> short term FT
Xdb = librosa.amplitude_to_db(abs(X))
plt.figure(figsize=(12, 3))
plt.title('001.wav spectrogram | Length : ' + str(len(samples)))
librosa.display.specshow(Xdb, sr = sample_rate, x_axis='time', y_axis='hz')
plt.colorbar()
plt.show()
train.csv
에는train
폴더에 위치한 음성 파일들의 이름과 라벨 컬럼이 포함되어 있습니다.label
컬럼은 0과 9사이의 정수로 구성됩니다.
1
train.head()
file_name label 0 001.wav 9 1 002.wav 0 2 004.wav 1 3 005.wav 8 4 006.wav 0
1
print(train['label'].unique())
[9 0 1 8 7 4 5 2 6 3]
- 데이터가 클래스 균형을 이루고 있습니다.
1
2
3
4
5
6
7
plt.figure(figsize=(12, 8))
sns.countplot(train['label'])
plt.title("The number of recordings for each label")
plt.ylabel("Count", fontsize = 14)
plt.xlabel("Label", fontsize = 14)
plt.show()
1
2
file_name = train['file_name']
train_path = '/content/drive/MyDrive/Speech_classification/dataset/train/'
- 데이터들의 길이가 모두 다릅니다.
1
2
3
4
5
6
7
8
all_shape = []
for f in file_name:
data, sample_rate = librosa.load(train_path + f, sr = 20000)
all_shape.append(data.shape)
print(all_shape[:5])
print("Max :", np.max(all_shape, axis = 0))
print("Min :", np.min(all_shape, axis = 0))
[(12740,), (13126,), (12910,), (9753,), (17572,)] Max : [19466] Min : [7139]
2. Data Augmentation
- 모델의 일반화 능력 향상을 위해, 기존의 음성데이터에 Perturbation을 추가하여 새 음성데이터를 생성합니다.
↪ Noise 추가, Time Stretching, Pitch 변환
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# noise 추가
def noise(sample):
noise_amp = 0.01*np.random.uniform()*np.amax(sample)
sample = sample + noise_amp*np.random.normal(size = sample.shape[0])
return sample
# time stretching
def stretch(sample, rate = 0.8):
stretch_sample = librosa.effects.time_stretch(sample, rate)
return stretch_sample
# pitch 변환
def pitch(sample, sampling_rate, pitch_factor = 0.8):
pitch_sample = librosa.effects.pitch_shift(sample, sampling_rate, pitch_factor)
return pitch_sample
3. Feature Extraction
- 모델링에 사용할 만한 몇가지 Feature Extraction 방법을 소개하겠습니다.
(1) ZCR Zero Crossing Rate
↪ 특정 프레임에서 신호의 부호(Sign)가 변경되는 빈도입니다. (i.e., 신호의 부호 변화율)
(2) Chroma Shift
↪ 파형(Waveform) 또는 Power Spectrogram으로 생성한 크로마그램(Chromagram) 입니다.
(3) Mel spectrum
↪ 오디오 신호(Time Domain)에 Fast Fourier Transform(FFT)를 적용하여 얻은 주파수 영역(Frequency Domain)의 스펙트럼(Spectrum) 입니다.
↪ Mel Filter Bank를 사용한 필터링 과정을 거쳐 Mel 스펙트럼을 생성합니다.
(4) MFCC Mel-Frequency Cepstral Coefficient
↪ Mel 스펙트럼에서 Cepstral 분석을 통해 고유한 음향 특성을 추출한 지표입니다.
(5) RMS Root Mean Square
↪ 오디오 평균 음량을 측정하는 데 사용되는 값입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def extract_features(sample):
# ZCR
result = np.array([])
zcr = np.mean(librosa.feature.zero_crossing_rate(y = sample).T, axis=0)
result=np.hstack((result, zcr))
# Chroma_stft
stft = np.abs(librosa.stft(sample))
chroma_stft = np.mean(librosa.feature.chroma_stft(S = stft, sr = sample_rate).T, axis=0)
result = np.hstack((result, chroma_stft))
# MelSpectogram
mel = np.mean(librosa.feature.melspectrogram(y = sample, sr = sample_rate).T, axis=0)
result = np.hstack((result, mel))
# MFCC
mfcc = np.mean(librosa.feature.mfcc(y = sample, sr = sample_rate).T, axis=0)
result = np.hstack((result, mfcc))
# Root Mean Square Value
rms = np.mean(librosa.feature.rms(y = sample).T, axis=0)
result = np.hstack((result, rms))
return result
- Noise 추가, Time Stretching, Pitching 방법들을 통해 한 음성데이터 샘플 당 (1, 162) 크기의 Feature를 (3, 162) 로 증강(Augmentation) 합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def get_features(path):
sample, sample_rate = librosa.load(path)
# without augmentation
res1 = extract_features(sample)
result = np.array(res1)
# sample with noise
noise_sample = noise(sample)
res2 = extract_features(noise_sample)
result = np.vstack((result, res2))
# sample with stretching and pitching
str_sample = stretch(sample)
sample_stretch_pitch = pitch(str_sample, sample_rate)
res3 = extract_features(sample_stretch_pitch)
result = np.vstack((result, res3))
return result
1
2
3
4
5
6
7
8
9
10
11
12
13
labels = train['label']
x, y = [], []
for f, label in zip(file_name, labels):
feature = get_features(train_path + f)
for fe in feature:
x.append(fe)
y.append(label)
X = np.array(x)
Y = np.array(y)
print("Shape of X:", np.shape(X))
print("Shape of Y:", np.shape(Y))
Shape of X: (1200, 162) Shape of Y: (1200,)
Reference
This post is licensed under CC BY 4.0 by the author.