본문 바로가기

Study/class note

딥러닝 / 개와 고양이 음성 분류 신경망 코드

1 개와 고양이 음성 분류 신경망 코드 설명

 

=> 코드 진행은 구글 코랩에서 진행합니다.

 

1. 구글 드라이브를 마운트 합니다.

from google.colab import drive
drive.mount('/content/drive')

2. 구글 드라이브에 데이터 업로드 후 압축해제합니다.

!unzip -qq /content/drive/MyDrive/ColabNotebooks/cats_dogs.zip  -d /content/drive/MyDrive/ColabNotebooks/cats_dogs

3. 필요한 패키지를 로드하고 seed값을 설정합니다.

import pandas as pd
import numpy as np
import glob #glob 모듈의 glob 함수는 사용자가 제시한 조건에 맞는 파일명을 리스트 형식으로 반환한다. 
# glob을 이용하면 편하게 데이터를 로드할 수 있음
import tensorflow as tf 
tf.random.set_seed(777)

4. 데이터를 로드해서 X_path에 담습니다.

Test_root = glob.glob('/content/drive/MyDrive/ColabNotebooks/cats_dogs/test')[0]
Train_root = glob.glob('/content/drive/MyDrive/ColabNotebooks/cats_dogs/train')[0]
X_path = glob.glob(Test_root + "/dogs/*")
X_path = X_path + glob.glob(Test_root + "/cats/*")
X_path = X_path + glob.glob(Train_root + "/dog/*")
X_path = X_path + glob.glob(Train_root + "/cat/*")
print(X_path)

5. 정답 데이터 라벨링을 진행합니다.

#정답 데이터 만드는 코드(고양이 0, 강아지 1)
import ntpath # 특정 경로에서 파일들을 가져오는 라이브러리
y = np.empty((0, 1, )) # 비어있는 리스트를 만듭니다. 
for f in X_path:
    if 'cat' in ntpath.basename(f): #  음성 데이터가 있는 디렉토리의 데이터가 고양이 음성 데이터라면 
        resp = np.array([0])  #   [0]
        resp = resp.reshape(1, 1, ) # [[0]] 2차원 데이터로 생성
        y = np.vstack((y, resp))  # 배열을 세로로 결합
    elif 'dog' in ntpath.basename(f): # 음성 데이터가 있는 디렉토리의 데이터가 개 음성 데이터라면
        resp = np.array([1])  # [1] 
        resp = resp.reshape(1, 1, ) #[[1]]
        y = np.vstack((y, resp)) # 
print (len(y))

6. 훈련데이터와 테스트 데이터를 분리합니다.

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X_path, y, test_size=0.25, random_state=42)

7. 파이썬으로 음원 파일이 잘 들어왔는지 확인해봅니다.

import IPython.display as ipd  # 음원 파일의 소리를 들을 수 있도록 오디오 플레이 화면을 디스플레이
ipd.Audio(X_train[1])

8. 개와 고양이 음성에서 진폭을 담는 함수를 생성합니다.

# 개와 고양이 음성에서 진폭을 담는 함수 생성
import librosa #음원 데이터를 분석해주는 아주 고마운 라이브러리

# https://hyongdoc.tistory.com/401 음성 파일 로드하는 부분 설명 잘한 블러그

def librosa_read_wav_files(wav_files):
    if not isinstance(wav_files, list): # https://brownbears.tistory.com/155  isinstance(1, int) # 1이 int형인지 알아봅니다. 결과는 True 입니다. 
        wav_files = [wav_files]  # wav_files에 있는 데이터가 리스트가 아니라면 리스트시켜라
    return [librosa.load(f)[0] for f in wav_files]

9. 첫번째 동물의 sample rate값을 wave_rate에 담고 훈련데이터와 테스트 데이터를 진폭데이터로 변환합니다.

wav_rate = librosa.load(X_train[0])[1]  # 훈련데이터 첫번째 동물의 sample rate값을 wave_rate에 담음

X_train = librosa_read_wav_files(X_train) #훈련데이터 207개의 진폭 데이터를 X_train에 담음
X_test  = librosa_read_wav_files(X_test) #테스트 데이터 70개의 진폭 데이터를 X_test에 담음
print(len(X_train))
print(len(X_test))
print(X_train[0])

wav_rate = librosa.load(X_train[0])[1] 

첫번째 동물을 기준으로 wav_rate를 담은 이유는 개와 고양이 음성에 대한 wav_rate는 비행기 소리, 사람 목소리와는 다른 범위에 있습니다. 그래서 신경망에 입력될 학습 데이터를 만들 때 개와 고양이 중 한마리의 sample_rate만 wav_rate에 담고 이 값을 대표값으로 사용하기 위해서 입니다.

 

+) 참고 사이트
1. 그림:  https://yeji1214.tistory.com/43
2. 그림: https://github.com/p2yeong/Audio-Study/blob/main/Audio_Processing.ipynb
3. 이산 신호 그림 : https://ko.wikipedia.org/wiki/%EC%9D%B4%EC%82%B0_%EC%8B%A0%ED%98%B8

 

# y, sr = librosa.load(audio_path)
# y: 파형의 amplitude 값(소리의 세기), 파동을 특징지을 수 있는 중요량 .  최고점의 수직 높이, 골의 깊이
# sr : 샘플링 레이트 또는 샘플링 주파수는 이산적인 신호를 만들기 위해 연속적 신호에서 얻어진 단위시간당 샘플링 횟수를 정의한다


# sample rate ? 1초당 들리는 sample 의 개수를 단위로 나타낸것. 오디오 데이터의 표본비율. Hz단위, 1초당 샘플의 빈도수
# 예: 44.1 KHz : 1초에 sample 의 수가 44100개 들어있다.

#sample 이란 ? 아날로그 신호의 소리 신호를 디지털로 표현하기 위해 잘게 쪼개는데 이 잘게 쪼갠 정보를 디지털 정보로 표현한게 sample이다.

 

 

10. 음성 진폭 데이터를 시각화해서 파형을 확인합니다.

# 동물들의 음성 진폭 데이터 4개로 각각 plot그래프로 시각화 함
import matplotlib.pyplot as plt
fig, axs = plt.subplots(2, 2, figsize=(16,7))  # 2행 2열로 그래프 4개
axs[0][0].plot(X_train[0]) #개
axs[0][1].plot(X_train[1]) #개
axs[1][0].plot(X_train[2]) #고양이
axs[1][1].plot(X_train[3]) #개
plt.show()

11. 음성의 특징을 추출하는 함수를 생성합니다.

def extract_features(audio_samples, sample_rate):  #음성의 특징을 추출하는 함수
    extracted_features = np.empty((0, 41, )) # (1,41) 은 아니고 그냥 41개의 값을 받을 메모리를 할당하겠다는 뜻
    if not isinstance(audio_samples, list):
        audio_samples = [audio_samples]
        
    for sample in audio_samples:  #진폭데이터 하나씩 돌리기
        zero_cross_feat = librosa.feature.zero_crossing_rate(sample).mean()  # 음성신호 파형이 중심축을 통과하는 횟수의 평균을 냄
        mfccs = librosa.feature.mfcc(y=sample, sr=sample_rate, n_mfcc=40) # https://youdaeng-com.tistory.com/5
        mfccsscaled = np.mean(mfccs.T,axis=0)  # 각 주파수별 평균값을 구합니다. #https://stackoverflow.com/questions/36182697/why-does-librosa-librosa-feature-mfcc-spit-out-a-2d-array
        mfccsscaled = np.append(mfccsscaled, zero_cross_feat)  #주파수 40개에 대한 평균값 40개와 zero_cross_feat값을 가지고
        mfccsscaled = mfccsscaled.reshape(1, 41, )  # 총 41개의 값을 학습 데이터로 구성.
        extracted_features = np.vstack((extracted_features, mfccsscaled))
    return extracted_features

 신경망에 입력할 학습 데이터를 만드는 함수입니다.

학습 데이터가 크게 2가지입니다.
1. zero_crossing_rate 값
2. mfcc 값

# zero_cossing_rate 란 ?  음성 신호 파형이 중심축(0) 을 통과하는 횟수이자, 신호의 부호가 바뀌는 비율

 

12. 훈련데이터와 테스트데이터의 음성 특징을 추출합니다.

# wave_rate 에 개과 고양이에 속하는 주파수 영역을 주어야 합니다. 
# 사람의 목소리는 대부분 16000Hz 안에 포함된다고 합니다

#librosa_read_wav_files 함수로 wav파일에서 진폭 리스트를 추출한 X_train, X_test와
#첫번째 동물의 sample_rate를 담은 wav_rate 값을 extract_features함수에 넣어서
#입력된 소리의 mel값과 zero_cross_feat

X_train_features = extract_features(X_train, wav_rate) 
X_test_features  = extract_features(X_test, wav_rate)
print(len(X_train_features))
print(len(X_test_features))

 

13. 모델 구성을 위한 패키지 임포트 합니다.

# 모델을 구성하기 위한 패키지들을 임포트
from keras import layers
from keras import models
from keras import optimizers
from keras import losses
from keras.callbacks import ModelCheckpoint,EarlyStopping  
from tensorflow.keras.utils import to_categorical

14. 정답데이터를 one hot encoding 합니다.

# 위에서 만들었던 정답 데이터를 one hot encoding
train_labels = to_categorical(y_train)
test_labels = to_categorical(y_test)
print(test_labels)

 

15. 완전연결계층 3층 신경망을 구성합니다.

# 완전연결계층으로 3층 신경망 구성

model = models.Sequential()
model.add(layers.Dense(100, activation = 'relu', input_shape = (41, )))  # 41개의 입력뉴런으로 flatten 시킨 것을 입력 받음
model.add(layers.Dense(50, activation = 'relu'))
model.add(layers.Dense(2, activation = 'softmax'))  # 출력층 2개
model.summary()  #모델의 설계도 보기

 

16. earlystopping과 checkpoint을 설정하여 모델을 생성합니다.

best_model_weights = '/content/drive/MyDrive/ColabNotebooks/base_model.h5'

# https://deep-deep-deep.tistory.com/53  

#학습 시킨 모델을 저장할 때 가장 좋은 모델을 알아서 자동으로 생성
checkpoint = ModelCheckpoint(
    best_model_weights,
    monitor='val_acc',   #테스트 데이터에 대한 정확도가 가장 좋은것으로 
    verbose=1,  #모델이 저장되었으면 저장되었다고 표시
    save_best_only=True,
    mode='max', # monitor를 val_acc로 했으면 정확도는 클수록 좋으니까 max로 해야하고 val_loss로 했으면 오차는 작을수록 좋으니까 min
    save_weights_only=False  #가중치 뿐만 아니라 모델도 저장되어야 하므로 False
)

estop = EarlyStopping(monitor = 'val_accuracy', patience = 20, verbose = -1) # 얼리스탑

callbacks = [checkpoint, estop]

model.compile(optimizer='adam',
              loss=losses.categorical_crossentropy,
              metrics=['accuracy'])

 

17. 모델을 훈련시킵니다.

history = model.fit(
    X_train_features,  # 훈련데이터 (40개의 mel값 + 1개의 zero_crossing_rate의 평균값)
    train_labels,  #원핫 인코딩한 값
    validation_data=(X_test_features,test_labels),
    epochs = 200, 
    verbose = 1,
    callbacks=callbacks
)

 

18. 훈련데이터와 테스트데이터의 정확도를 시각화 합니다.

print(history.history.keys())
acc = history.history['accuracy']
val_acc = history.history['val_accuracy']
epochs = range(1, len(acc)+1)
plt.plot(epochs, acc, 'b', label = "training accuracy")
plt.plot(epochs, val_acc, 'r', label = "validation accuracy")
plt.title('Training and validation accuracy')
plt.legend()
plt.show()

 

19. 모델을 저장합니다.

model.save_weights('model_wieghts.h5')
model.save('model_keras.h5')

 

20. 저장한 모델을 가지고 데이터를 넣어 분류예측을 진행해봅니다.

import IPython.display as ipd
nr_to_predict = 6
pred = model.predict(X_test_features[nr_to_predict].reshape(1, 41,))
print("Cat: {} Dog: {}".format(pred[0][0], pred[0][1]))
if (y_test[nr_to_predict] == 0):
    print ("This is a cat meowing")
else:
    print ("This is a dog barking")
    
plt.plot(X_test_features[nr_to_predict])
ipd.Audio(X_test[nr_to_predict],  rate=wav_rate)
nr_to_predict = 22
pred = model.predict(X_test_features[nr_to_predict].reshape(1, 41,))
print("Cat: {} Dog: {}".format(pred[0][0], pred[0][1]))
if (y_test[nr_to_predict] == 0):
    print ("This is a cat meowing")
else:
    print ("This is a dog barking")
    
plt.plot(X_test_features[nr_to_predict])
ipd.Audio(X_test[nr_to_predict],  rate=wav_rate)

 

반응형