Monday, January 4, 2016

음성/음악신호+머신러닝 초심자를 위한 가이드 [1편]

음성/음악신호+머신러닝 초심자를 위한 가이드 전체 게시물은 여기를 클릭하세요.

소개

음성, 음악신호를 이용해 이러쿵저러쿵~~처리를 하고 머신러닝으로 뚝딱~ 하는 프로그램을 짜고싶다 (짜야한다..)! 그런데,

i) 오디오 신호 처리는 알지만 머신러닝을 몰라요.
OR
ii) 머신러닝은 알지만 오디오 신호 처리는 몰라요.

에 해당하시는 분들을 위해 간단한 포스팅을 씁니다. 예를 들면 아이 울음 소리를 번역하는 어플, 음악에서 자동 기타 코드 인식 등의 경우가 있겠죠.


가정:

- 문제: 아이 울음 소리를 번역하자! 이 아이가 a.배고파서 우는지 b.졸려서 우는지 이 두 가지만 고려.
- 사용 언어: 파이썬.
- 데이타: 아이 울음소리가 녹음된 파일 100개 (1.wav, 2.wav, ..., 100.wav)
- 라벨링: 되어있음. (파일명이 짝수면 배고픔, 홀수면 졸림)

가장 전통적인, 전형적인, 그리고 어지간한 성능을 보여주는 방법인 Feature extraction (특징값 추출) + classifier (분류기)의 조합을 시도해봅시다.
[방법 1] MFCC를 특징값으로 사용 + Logistic regression classifier를 써서 분류 - 가장 간단한 방법입니다.


[방법 1 - 단계a. 특징값 추출 Feature extraction]


* 준비물: 파이썬 패키지: librosa (documentation), 컴퓨터, 두뇌, 시간, 손가락, 공기, 지구 등.

- - 설치방법 생략.

* librosa.core.load

를 써서 오디오 파일을 읽어온다.
> y, sr = librosa.load('data/baby_cry.wav')

- - arguments 설명
- - - sr=22050 : input 샘플링 주파수입니다. 아마도 갖고있는 오디오 파일의 샘플링 주파수는 22050이 아닐 확률이 큽니다. 이렇게 값을 설정해주는 것은 11025 Hz 까지의 값만 써도 된다는 가정을 한 것이죠. 잘 모르시면 그냥 두세요.
- - - mono=True : 스테레오 음원일경우 모노로 바꿔준다는 말입니다. 역시 그냥 두시면 됩니다. 대부분의 경우 모노면 충분합니다. 이 글의 타겟이시면 스테레오 음원이 필요한 경우가 아닐거에요.
- - - offset, duration: 오디오 파일의 특정 구간만 쓰실경우 설정하시면 됩니다. 그러나, 초심자라면 이걸 쓰지 마시구요, 갖고있는 오디오 파일에서 의미있는 구간만 미리 잘라놓으세요. 예를들어 음원이 60초인데 아기 우는 소리가 20~35초에 있다면 그 부분만 남기고 나머지는 버려서 15초로 만들어놓고 쓰시면 됩니다.

* librosa.feature.mfcc

를 써서 오디오 신호를 mfcc로 바꾼다.
> mfcc = librosa.feature.mfcc(y=y, sr=sr)

- - arguments 설명
- - - n_mfcc=20 : mfcc 계수의 개수입니다. mfcc가 가장 활발하게 쓰이는 음성 인식에서는 대략 이 값을 수십개 (20~50)로 설정하고 씁니다. 즉 그정도면 충분하다고 알려져있습니다. 다만 주어진 상황과 목표에 따라 그 값은 다를 수 있습니다. 우선 20으로 두시면 됩니다.
- - mfcc란?
- - mfcc는 음성/음악 인식에서 가장 널리 쓰이는 특징값입니다. 자세한 설명은 위키를 참조.
mfcc 프레임 기반 특징값입니다. 즉, 각 프레임 (대체로 수 십 ms)마다 하나의 mfcc vector가 나오게 됩니다.
위의 코드를 실행하면 mfcc는 2차원 어레이가 할당됩니다. 즉

> print mfcc.shape 

를 하시면 (20, number_of_frames)이 나오게 됩니다.

이제 이 특징값을 써서 분류기를 활용해봅시다.


[방법 1 - 단계b. 분류기 Classifier]


* 분류기 Classifier

분류기란, 말그대로 분류를 해주는 기..;;입니다. 예를 들어, 20차원의 mfcc 벡터를 입력으로 하면 요 애기가 배고파서 우는지, 졸려서 우는지를 알려주는 녀석이죠. 즉 y = f(mfcc) 으로 표현해보면 f( )가 분류기에 해당하고, y는 그 결과입니다. y는 [0, 1] 중에 하나를 고르는걸로 우리가 설정해놓을 수 있죠. 즉 0=배고프다, 1=졸리다. 이렇게 설정해놓고 그에 맞춰서 트레이닝을(기계를, 혹은 알고리즘을 학습시키는 것을) 해 주는 것이죠. 좀 더 일반적으로는

판단 = f(특징값)

으로 쓸 수 있겠죠?
Logistic regression, SVM, decision tree, random forest, neural networks 등 분류기의 종류는 아주아주 많습니다.

* Logistic regression

(거의) 제일! 간단한! 분류기입니다.

*준비물: 파이썬 패키지: scikit-learn

열심히 설치하시면 됩니다.
$ pip install sklearn

* scikit-learn의 linear model의 LogisticRegression

를 쓰겠습니다.  (예제 참고)

1 > from sklearn import linear_model 
2 > logreg = linear_model.LogisticRegression()
3 > logreg.fit(X_train, y_train)
4 > y_test_estimated = logreg.predict(X_test)

요 네 줄의 코드가 핵심입니다. 그러나! 그 전에!

* X_train, y_train, x_test, y_test

머신 러닝 알고리즘의 트레이닝에선 반드시! 교차 검증 (Cross-validation)을 해야합니다.
쉽게말해, 100개의 음악 파일중 짝수는 배고픈, 홀수는 졸린 울음소리였죠? 그렇다면 2,4,6,8,..., 60 까지, 총 30개의 배고픈 울음 소리와 1,3,5,7,...,59까지, 총 30개의 졸린 울음 소리를 모아서 총 60개를 트레이닝 셋으로 두고, 나머지 40개를 테스트 셋으로 두죠. 그게 뭐냐구요? 쉽게 말하면 우리의 알고리즘 학생에게 기계학습을 열심히 시키는데, 1~60까지로 공부를 시키고 (트레이닝), 잘 이해 했는지를 61~100번으로 시험을 보는겁니다 (테스트). 왜 이렇게 하냐면, 이렇게 안하면 다들 시험에 나오는 것만 공부하고, 그래서 시험은 잘 보지만 막상 써먹을 수가 없게 되기 때문입니다.  즉, 이렇게 학습시킨 알고리즘으로 어플을 만들면 진짜로 사용자의 아기가 울었을때는 왜 우는지 전혀 맞출 수 없는거죠. (이걸 과적합/오버피팅/Overfitting이라고 합니다.)
그래서 우린 어떻게 하냐면요,

- 1~100의 wav 파일의 MFCC를 전부 구합니다.
- - 원래는 파일 하나당 여러 프레임이 존재하고, 따라서 파일 하나당 여러 개의 MFCC 벡터가 존재합니다.
- - - 귀찮으니 이걸 평균내서, 파일 하나당 하나의 MFCC 벡터를 만들었다고 합시다. 그러면 우린 총 100개의 MFCC 벡터를 갖고있지요. (n_mfcc=20, 즉 벡터는 20차원이라고 하죠.)
- 또, 아까 말했듯이 짝수는 배고픈 (=0), 홀수는 졸린(=1) 울음 소리에요.
자 이제,

- - - X_train은 60-by-20이 되도록 만드세요. 즉, 각 row는 각각의 mfcc가 되는거죠. 1번파일부터 60번 파일까지 순서대로~
- - - Y_train은 60-by-1 numpy 어레이로 하구요. 즉, 길이가 60인 [1,0,1,0,.....1,0] 이 되겠죠?
- - - X_test는 40-by-20이 됩니다. 여기엔 61번파일부터 100번 파일까지의 mfcc값을 넣습니다.
- - - Y_test는 40-by-1이구, 역시 [1,0,...1,0]인데 길이가 40이죠.
그리고 나서, 위의 코드를 돌리면! 그리고 나서,

5 > print y_test_estimated

를 통해 값을 보셔도 되고, 아무튼 열심히 y_test와 y_test_estimated를 비교하시면 됩니다.

*정리

"MFCC를 특징값으로 사용했고, 60:40으로 train set/test set을 나누었고, logistic regression을 이용해 분류(classification)를 했습니다."
- (MFCC,) training set, test set, logistic regression, classification 이 무엇인지 간략한 개념을 이해하셨으면 성공!
- 과연 방법 2를 쓰게될지는 모르겠습니다만 여튼 도움이 되었으면 좋겠습니다.





8 comments:

  1. 안녕하세요
    청각장애인들을 위한 아기울음 알림 장치를 DIY로 만들어보려 하는 중
    최근우님의 블로그를 보게 되었습니다.

    이 글의 안내에 따라
    MFCC 피쳐들을 뽑아서 평균, 분산, max값을 이용해
    간단한 Neural Network로 아기울음소리를 분류해 보았습니다.
    그러나 테스트 결과, 학습데이터에 없는 몇몇 소리들이
    아기울음으로 잘못 분류되는 경우가 발생했습니다.
    ex)여성 보컬 노래, 여자 흐느끼는 소리 등

    이러한 오작동(?)을 막기위해(혹은 줄이기위해)
    어떤 방법이 있을지 여쭙고 싶습니다.

    ReplyDelete
    Replies
    1. 분류기 선택 등 머신러닝 일반은 http://keunwoochoi.blogspot.co.uk/2016/08/blog-post.html 을 참고하시구요,
      false negative와 false positive중 어떤걸 줄일지 생각해보시구요.
      https://librosa.github.io/librosa/generated/librosa.feature.delta.html 를 참고하셔서 dMFCC, ddMFCC를 추가해보는것도 방법입니다.

      Delete
    2. 정말 감사합니다! 여러가지로 또 테스트를 해봐야겠습니다.

      Delete
  2. 친절히 설명해주셔서 감사합니다!

    ReplyDelete
  3. 1탄, 2탄, 3탄까지 읽게 되었는데요.
    깊이 공부해야할 부분은 요점요점 잘 정리해주셔서 감사합니다.
    잘 참고해서 사용하도록 하겠습니다.
    혹시 GANs를 사용한 tutorial이 있으면 알려주실 수 있을까요?
    영어가 워낙 약해서요 ㅠ.ㅠ

    ReplyDelete
    Replies
    1. 안녕하세요, GAN은 http://jaejunyoo.blogspot.com 유재준님 블로그에 많이 나와있습니다.

      Delete
  4. 안녕하세요. 1탄, 2탄, 3탄 읽으면서 공부하고 있는 학생입니다.
    우선 너무 유익한 블로그를 찾게되어 너무 감사합니다.

    1탄 내용을 보면서 공부하고 있는데요.

    위에
    데이타: 아이 울음소리가 녹음된 파일 100개 (1.wav, 2.wav, ..., 100.wav)
    이 파일을 참고하면서 따라가보려고 여기저기 찾다가 결국 글을 남기게 됬습니다..
    혹시 위 데이터파일은 어디서 찾을수 있을까요ㅠ??

    ReplyDelete
    Replies
    1. 안녕하세요, 반갑습니다. 4탄을 새로 작성했습니다. 일단 애기 우는 소리는 baby crying sound dataset이라고 구글하시면 맨 위에 나오는게 있구요, 4탄은 좀 더 일반적인 경우에 대한 이야기입니다. 참고하세요.

      Delete