Urban Sound Classification

뉴욕 대학교 MARL(Music and Audio Research Lab)에서 2014 년에 공개한 UrbanSound8K 데이터를 이용하여 텐서플로우를 사용해 사운드를 분류 모델을 만들어 보았습니다. 텐서플로우 코드는 아퀴브 사이드(Aaqib Saeed)의 블로그를 참고하였습니다.

UrbanSound8K 데이터는 모두 10 가지 종류의 소리를 4 초 가량 녹음한 것으로 8 천개가 넘는 wav 파일들 입니다. 소리의 종류는 ‘air_conditioner’, ‘car_horn’, ‘children_playing’, ‘dog_bark’, ‘drilling’, ‘engine_idling’, ‘gun_shot’, ‘jackhammer’, ‘siren’, ‘street_music’ 입니다. 압축을 풀기 전의 데이터 사이즈가 5 GB 가 넘습니다. 이 데이터를 받기 위해서는 깃허브에서 다운로드 주소를 이용해 다운받을 수 있지만 사용 목적에 대해 알려달라고 합니다.

먼저 wav 파일을 이용해서 피처를 뽑아 내야합니다. 아퀴브 사이드가 사용한 방법은 사운드 분석 파이썬 라이브러리인 librosa 를 이용해서 특성을 추출하였습니다. 사용된 특성은 mfcc(Mel-frequency cepstral coefficients), chroma_stft(chromagram from a waveform or power spectrogram), melspectrogram(Mel-scaled power spectrogram), spectral_contrast(spectral contrast), tonnetz(tonal centroid features) 입니다. 이 데이터를 모두 행으로 늘여 놓으면 총 193 개의 입력 데이터가 만들어 집니다.

오디오 파일이 많다보니 이 데이터를 주피터 노트북에서 생성하고 모델을 만들기가 부담스러운 작업입니다. 별도의 파이썬 스크립트로 입력 데이터를 미리 가공하여 하나의 파일로 합쳐 놓은 urban_sound.npz 파일을 제 깃허브에 올려 놓았습니다. 이 파일은 입력 데이터로 만들어진 넘파이 배열을 파일로 저장해 놓은 것입니다. 특성을 추출하여 npz 데이터를 생성한 코드는 깃허브의 feature_extraction.py 와 feature_merge.py 파일을 참고하세요.

npz 파일을 사용하면 모델을 만들고 테스트할 때 오디오 파일을 매번 가공할 필요 없이 npz 파일로 부터 바로 입력 특성을 로드할 수 있습니다.

sound_data = np.load('urban_sound.npz')

모델 훈련은 20% 를 테스트 데이터로 떼어내고 20% 를 다시 밸리데이션 데이터로 분리하였습니다. 노트북에서 돌리다 보니 속도가 느려 크로스 밸리데이션은 사용하지 않았습니다. 밸리데이션 데이터로 하이퍼파라메타를 적절히 고르고 훈련 데이터와 밸리데이션 데이터를 합쳐서 최종 모델을 훈련시키고 테스트 데이터로 모델을 평가하였습니다.

사용한 뉴럴 네트워크는 완전 연결 뉴럴 네트워크로 3 개의 히든 레이어에 각각 뉴런을 300 개, 200 개, 100 개를 설정하였습니다.

n_hidden_units_one = 300
n_hidden_units_two = 200
n_hidden_units_three = 100

파라메타 초기 값은 입력 데이터의 크기인 193 의 제곱근의 역수를 사용했는데 각 레이어의 히든 유닛 수나 활성화 함수에 맞게 다르게 했으면 더 좋았을 것 같았습니다. 3개의 히든 레이어와 출력 레이어에 대한 텐서플로우 그래프를 아래와 같이 생성하였습니다. 첫번째 세번째의 활성화 함수는 시그모이드를 사용하였고 두번째 활성화 함수는 하이퍼볼릭 탄젠트 함수를 사용했습니다.

X = tf.placeholder(tf.float32,[None,n_dim])
Y = tf.placeholder(tf.float32,[None,n_classes])

W_1 = tf.Variable(tf.random_normal([n_dim, n_hidden_units_one], mean=0, stddev=sd), name="w1")
b_1 = tf.Variable(tf.random_normal([n_hidden_units_one], mean=0, stddev=sd), name="b1")
h_1 = tf.nn.sigmoid(tf.matmul(X, W_1) + b_1)

W_2 = tf.Variable(tf.random_normal([n_hidden_units_one, n_hidden_units_two], mean=0, stddev=sd), name="w2")
b_2 = tf.Variable(tf.random_normal([n_hidden_units_two], mean=0, stddev=sd), name="b2")
h_2 = tf.nn.tanh(tf.matmul(h_1, W_2) + b_2)

W_3 = tf.Variable(tf.random_normal([n_hidden_units_two, n_hidden_units_three], mean=0, stddev=sd), name="w3")
b_3 = tf.Variable(tf.random_normal([n_hidden_units_three], mean=0, stddev=sd), name="b3")
h_3 = tf.nn.sigmoid(tf.matmul(h_2, W_3) + b_3)

W = tf.Variable(tf.random_normal([n_hidden_units_three, n_classes], mean=0, stddev=sd), name="w")
b = tf.Variable(tf.random_normal([n_classes], mean = 0, stddev=sd), name="b")
y_ = tf.nn.softmax(tf.matmul(h_3, W) + b)

비용 함수는 크로스 엔트로피를 사용하고 그래디언트 디센트 옵티마이저를 사용하였습니다. 모델의 반복은 총 6000 회를 진행했습니다. 최종 테스트 결과는 대략 86.7% 의 정확도를 내었습니다.(아래 코드에 Validation accuracy 라고 되어 있는데 최종 테스트 정확도를 계산하면서 수정하지 못했습니다. Test accuracy 라고 이해해 주세요.)

cost_history = np.empty(shape=[1],dtype=float)
with tf.Session() as sess:
    sess.run(init)
    for epoch in range(training_epochs):
        _,cost = sess.run([optimizer, cost_function], feed_dict={X: X_sub, Y: y_sub})
        cost_history = np.append(cost_history,cost)
 
    print('Validation accuracy: ',round(sess.run(accuracy, feed_dict={X: X_test, Y: y_test}) , 3))
    saver.save(sess, "model_321.ckpt")
Validation accuracy:  0.867

비용 값의 감소 그래프를 그려 보면 비교적 요동이 심한 것으로 보입니다. 이 요동의 원인을 잡아낼 수 있다면 좀 더 정확도를 높일 수 있지 않을까 생각됩니다.

urban-sound-learning

다른 곳에서 구한 사운드 데이터로 테스트해 보니 강아지 소리는 잘 구분해 냈는데 드릴 소리는 절반 정도를 구분하지 못했습니다. 드릴 소리를 스트리트 뮤직이라고 판단하는 경우가 많았습니다.

만들어진 모델 파라메타는 model_321.ckpt 파일에 저장하여 깃허브에 올려 놓았습니다. 필요하신 분이 있다면 자유롭게 사용하시고 혹 더 좋은 팁이 있다면 피드백 부탁 드립니다.

 

Urban Sound Classification”에 대한 5개의 생각

  1. 호찬이

    안녕하십니까 선생님. 선생님이 번역하신 텐서플로 첫걸음과 본 블로그를 통해 텐서플로를 공부중인 박찬호라고 합니다. 위 포스팅과 아퀴브 사이드 씨의 블로그를 참고하며 Sound classification 공부를 하는 와중 좀 헷갈리는부분이 몇 있어 도움을 얻고자 글 남깁니다.

    우선 첫째로는 사운드 feature 추출파일인 npz 파일을 선생님께서 만드신 것을 이용해 모델파라미터 파일을 생성하고, 이를이용해 다른곳에서 구해온 사운드파일을이용해 분류를 하였을때 올바른 category를 찾지못한다면, 이를 정정하기 위해 어떻게 해야할까요. 구글링을 통해 얻어온 dog bark wav파일을 car horn으로 분류하는 경우가 좀 잦던데 해당 파일을 추가하여 npz파일을 추가해야 하는것인가요? 추가한다해도 이소리가 car horn이 아닌 dog bark임을 어떻게 훈련시켜야하는지 부분이.. 난해합니다 ..ㅠㅠ urban sound 데이터를 분석해보니 category별로 폴더를 나눈것이 아니더라고요..

    두번째로는 아퀴브씨는 2개의 히든레이어를 사용하였고, 선생님께서는 3개의 히든레이어를 사용하셨는데, 이 아키텍쳐를 뭐라고 분류한다고 알고있어야 하는지가 햇갈립니다. 단순히 Multilayer Neural Network라고 알고있으면되는지요? NN, CNN, RNN처럼 통상적으로 쓰이는 아키텍처 중 정확히 어디에 속하는 것인지요??

    마지막으로는 제가 지금 하고있는게 정확히 머신러닝인 것인지 딥러닝인 것인지.. 모르겠습니다 막무가내로 책과 포스팅을 보며 하고있습니다..

    부디.. 답을 부탁드리겠습니다 ㅠㅠ

    좋아하기

    응답
    1. 로드홈 글의 글쓴이

      안녕하세요. 블로그에 들려 주셔서 감사합니다. ^^
      실전에서 dog 소리를 car horn으로 분류하는 경우가 많다면 모델이 그 만큼 잘 일반화되지 못했다고 볼 수 있습니다. 여러가지 이유가 있겠지만 기본적으로 다양하고 충분한 데이터를 공급했을 때 좋은 모델을 만들 수 있습니다. 하지만 한두개의 데이터를 추가해서는 효과를 보기가 어렵습니다. 원하시는 음원 데이터가 충분히 있다면 feature_extraction.py 에 있는 extract_feature 함수를 사용하여 특성을 뽑아내면 제가 만든 입력 데이터(X_data)과 합칠 수 있습니다. 카테고리는 UrbanSound8K_README.txt 파일에 들어있습니다. dog_bark 는 3 이네요.
      여기서 사용한 뉴럴 네트워크는 일반적인 피드 포워드 뉴럴 네트워크입니다. 혹은 완전 연결 뉴럴 네트워크, 멀티 레이어 퍼셉트론, 그냥 뉴럴 네트워크라고도 부릅니다. 굳이 약자를 사용하자면 히든 레이어를 사용했으니 DNN이라고 할 수 있습니다.
      지금 하고 계시는 것은 딥러닝이기도 하고 머신 러닝이기도 합니다. 딥러닝은 뉴럴 네트워크를 사용하는 경우를 말하고 머신 러닝은 딥러닝을 포함하고 있습니다. ^^

      좋아하기

      응답
    1. 호찬이

      선생님.. 추가 질문사항이있는데.. 코드부를 추가하여 댓글을 다려니 어떤이유인지 달리지가 않습니다.. 혹시 이메일등 따로 질문을 드릴 루트가 있을까요? ㅠ 선생님 댓글에 대한 댓글, 새로운 댓글 제댓글에 대한 댓글 모두 시도 하여도 추가가 되질않습니다.. ㅠㅠㅠㅠ

      좋아하기

      응답
      1. 로드홈 글의 글쓴이

        아 네 워드프레스가 코드를 넣으면 자동으로 스팸처리하더리구요. 블로그 메뉴 about 에 들어가시면 저에게 멜 보내실 수 있습니다.

        좋아하기

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

%s에 연결하는 중