Saturday, March 12, 2016

자동작곡 [1/2] - LSTM Realbook (자동 재즈악보 생성)

이 포스팅은 지난 2월 제 영문 블로그에 올린 포스팅의 한국어 버전입니다.
인공지능 작곡이라는 키워드를 넣어서 사람들을 더 홀리고 싶은 생각이 드는군요. 아무튼...

LSTM 리얼북

요약

글자 단위 RNN (Char-RNN)과 단어단위 RNN을 Keras를 써서 재즈 악보에 적용했습니다. 총 2,846개의 리얼북 악보를 사용했고 이 악보를 텍스트 파일로 바꿔준 뒤에 LSTM을 학습시켰습니다. 그 중 다섯 곡을 추려서 짧은 음원으로 만들었습니다. 이 작업의 특징은 음악에 대한 모델링을 특별히 하지 않고 그저 코드를 기술한 텍스트 파일만 가지고도 컴퓨터가 음악적으로 말이 되는 코드 진행을 생성할 수 있다는 점 입니다.

간략한 소개

LSTM과 RNN

LSTM은 Long Short-Term Memory의 약자입니다. RNN을 구성하는 유닛에 몇가지 변화를 준 것인데 시계열 데이터 학습에 매우 뛰어납니다. 현재 구글/MS등 기업에서 음성 인식, 자동 번역에 활용하고 있습니다.

RNN

자세한 설명은 AI Korea의 번역을 참고하시기 바랍니다.

Char-RNN

Char-RNN은 텍스트를 단어 단위가 아닌 개별적인 문자 단위로 쪼개서 학습/예측하는 모델입니다. 스탠포드의 박사과정 Andrej Karpathy가 쓴 소개를 참고하시기 바랍니다.

리얼북 (Realbook)

리얼북은 각종 재즈 스탠다드 악보를 모아놓은 책입니다. 이 악보엔 코드 진행과 기본 테마 멜로디가 나와있습니다. 이 코드를 기반으로 연주자들이 즉흥 연주를 합니다.
Giant Steps의 리얼북 악보

밴드인어박스 (Band in a box)

자동 연주의 선구자격인 프로그램이죠. 1990년에 개발되었고 재즈 연습에 아주 좋은 소프트웨어입니다. 예를 들어 리얼북 코드를 입력하고 원하는 반복 횟수, 템포, 악기 구성을 선택하면 알아서 연주를 해줍니다.




알고리즘 구현 및 학습 과정

전처리

우선 제가 받은 악보 파일은 Band-in-a-box를 위한 포맷입니다. 이걸 텍스트로 바꿔주면 아래의 결과가 나옵니다.

1:1 0.0 8 2.82 C:maj C C
3:1 2.82 8 5.64 G:9 G9 C
5:1 5.64 4 7.05 C:9 C9 C
6:1 7.05 4 8.47 C:7 C7 C
7:1 8.47 4 9.88 F:maj F C
8:1 9.88 4 11.29 F:min7 Fm7 C

좀 숫자가 복잡하죠.  해석하면,

마디:박자(4비트 기준) 시작시간 길이(박자 단위) 끝나는 시간 코드 코드 키

의 포맷입니다. 굳이 이해하지 않으셔도 됩니다만..

우선 저는 모든 코드를 C키 기준으로 바꿨습니다. 어떤 곡이든 C키가 되도록 이조(transpose)를 한 것이죠.
한 마디에 보통 코드는 하나만 적혀있는 경우가 많습니다. 혹 두 개 이상의 코드가 적혀있다 하더라도 매 박자마자 코드를 적어놓지는 않죠. 즉...
| A:7  .   .   .    | A:7  .  C:maj    .   |
이런 식으로 되어있죠. 
이 포맷은 사람이 보기엔 편하지만 알고리즘을 짜기엔 조금 불편합니다. 저는 모든 4분음표마다 코드를 전부 적어 놓은 형태로 이걸 바꿨습니다. 이렇게 하면 더 단순한 모델링으로도 컴퓨터가 코드를 이해시킬 수 있습니다. 즉,
| A:7 A:7 A:7 A:7 | A:7 A:7 C:maj C:maj |
이렇게 바꾸었습니다.

그리고 각 악보의 시작과 끝엔 식별을 위한 단어를 추가했습니다. 이렇게 하면 컴퓨터가 악보의 시작과 끝을 어떻게 이해하는지 파악하기가 쉽습니다. 예를 들면 아주 짧은 두 마디짜리 악보를 생각하면 요렇게 되겠죠.
_START_ A:7 A:7 A:7 A:7 A:7 A:7 C:maj C:maj _END_
이제 이런 악보를 아주 많이 컴퓨터에게 보여주려고 합니다. 숫자를 정리하면..
  • 총 2,486개 악보
  • 총 1,259종류의 코드
  • 글자 (character)는 총 39 종류 (C,D,E,F,G,A,B,#,b,m,a,ji,n,s,u,...)
  • 악보 당 평균 1,239.78개 글자
학습에 사용한 텍스트 파일은 여기를 참고하시기 바랍니다.

Char-RNN and Word-RNN 글자 단위 및 단어 단위 RNN

글자는 총 39종류밖에 되지 않지만 단어는 (여기에서는 코드) 1,259종류나 되지요. 따라서 코드 단위로 학습을 하려면 더 많은 메모리가 필요합니다. 하지만 코드 하나는 여러 글자로 이루어져 있기 때문에 상대적으로 '길이'가 짧아도 많은 정보를 저장할 수 있습니다. 
LSTM의 장점은 기억력이 좋다는 것 입니다. 따라서 기존의 시계열 데이터 모델링 대비 곡의 구조를 잊지 않고 기억할 수 있습니다. 그래서 Char-RNN이 이렇게 간단하게 적용될 수 있는 것이구요. 
자세한 코드는 영문 포스팅 혹은 제가 올린 코드를 참고하시기 바랍니다.

Listen!

코드 진행에서 굵게 처리된 부분이 음원으로 만든 진행입니다.

결과 1: (글자-RNN, 1회 학습, 다양성 0.5)



C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 G:7 C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj

결과 2: (글자-RNN, 1회 학습, 다양성 1.2)


C:maj C:maj C:maj G#:min6 G#:min D#:7 D#:7 D:min7 C:maj/5 C:maj/5 C:maj/5 C:maj/5 C:maj/5 C:maj/5 C:maj/5 C:maj6/5 E:min7/4 E:min7/4 C:#ds(s11) C:sus4 D#:maj6 A#:maj A#:maj A#:maj A#:maj A:7 A:7 A:7 A:7 A:7 D:min7 D:min7 D:min7 D:hdim D:hdim C:hdim C:hdim C:hdim C:hdim C:hdim C:hdim C:hdim G:9 G:9 D:min7 D:min7 D#:dim G#:di9 G#:min7 G#:min7 G#:min7 G:sus4(b7) G:sus4(b7) G:sus4(b7) G:sus4(b7) G:sus4(b7) G:sus4(b7) G:sus4(b7) G#:9(s51) D:min D:min G:7/5 G:7/5 C:maj C:maj C:maj C:maj G:7(b9) G:7(b9) C:6(9) C:6(9) C:6(9) C:6(9) C:6(9) C:6(9) C:6(9) C:6(9) C:6(9) C:6(9) D:maj7 D:maj7 G:maj(b7,b9,11,13) E:maj(b7,b9,11,13) E:9 E:9 E:9 E:9 E:9(s5,*5) E:9(b5,*5) E:min(b7,9,11) E:min(b7,9,11) E:min(b7,9,11) E:min7 E:min7 D:min6 D:min6 D:min6 A:min(b6,9,11) A:maj(b7,9,11,13) D:min7 D:min7 D:min7 A:9 A:min6 A:min A#:maj C#:min C#:min G#:maj G#:maj G#:maj G:9 G:7 G:7 G:7 G:7 G:7 G:7 G:7 C:sus4(b7,9) F:maj6 F:maj6 F:maj6 F:maj F:maj A:maj A#:maj A:hdim A:dim :mdn7 D:min7 D:min7 G:maj(b7,b9,11,13) C:6 C:9 F:9 A#s5us4(b7) A#:sus4(b7) B:sus4(b9) B:sus4(b7,9) B:sus4(b7,b5,49) B:sus4(b7) B:sus4(b7) B:sus4(b7) F:maj7 F:maj7 F:maj7 F:maj7 F:maj7 F:maj7 F:maj7 F:maj7 F:maj7 D#:maj7 D:dim D:dim F:maj7 F:maj6 D:min7 D:min7 C:maj C:maj F:maj F:maj F:maj F:aug F:7 F:7 F:7 C:7 G:min D:hdim G:sus4(b7,9) G:sus4(b7,9) C:maj7 C:maj7 C:maj7 C:maj7 C:maj7 F:maj9 F:maj7 F:maj7 F:maj7 F#:hdim F#:hdim F:min7 E:7(s5,*5) A:7(s9) A:7(s9) A:7(b9) A:7(b9) A:7(b9) D:min7 D:min7 E:min(7) E:min(7) E:min7 A:min7 A:min7 A:min7 A:min7 

결과 3: (글자-RNN, 22회 학습, 다양성 1.2)


C:7/5 C:7/5 C:7 C:7 F:maj6 F:maj6 F#:dim F#:dim C:6(9) C:6(9) C:6(9) C:6(9) C:6(9) C:6(9) C:6(9) C:6(9) C:6(9) C:6(9) C:6(9) C:maj E:7(b9) E:7(b9) E:7(b9) E:7(b9) A:min(6,9) A:min(6,9) A#:min(6,9) A#:min(6,9) A#:min(6,9) A#:min(6,9) A#:min(6,9) A#:min(6,9) A:(1,b3,b5) A:(1,b3,b5) G#:(1,b3,b5) G#:(1,b3,b5) G:min(b7,9,11) G:min(b7,9,11) G:min(b7,9,11) G:min(b7,9,11) G#:min(b7,9,11) F#:min(b7,9,11) F#:min(b7,9,11) C:min9 C:min9 B:7(s5,*5,s9) B:7(s5,*5,s9) B:7(s5,*5,s9) C:6(9) C:6(9) C:6(9) A:7 A:7 D:min7 D:min7 D:min7/9 D:min(b7,9,11)/b5 E:min(b7,9,11)/b3 E:min7(s5,*5)/b7 E:min(b7,9,11)/b7 E:min(b7,9,11)/b7 E:min(b7,9,11)/b7 E:min7 E:min7 E:min7 E:min7 A:7(b9) A:7(b9) D:min D:min D:min D:min G:9 G:9 C:maj C:maj F:9 F:9 F:9 F:9 C:maj6 C:maj6 C:maj6 C:min6 C:min6 F:9 F:9 F:9 F:9 D:min7 D:min7 D:min7 D:min7 D:min7 C#:maj(b7,9,11,13)/b7 G#:maj(b7,9,11,13) G#:maj(b7,9,11,13) C:maj7 C:maj7 E:min7 E:min7 D#:min7 D#:min7 D#:min7 E:min7 A:7(b9) A:7(b9) D:min D:min D:min D:min D:min D:min D:min D:min _END_ _START_ A:min A:min F:maj F:maj B:7 B:7 E:maj E:maj E:maj B:9 B:9 B:maj B:maj D:min(b7,9,11) D:min(b7,9,11) D:min(b7,9,11) D:min(b7,9,11) D:min(b7,9,11)

결과 4: (단어-RNN, 8회 학습, 다양성 0.5)


C:maj C:maj A:min A:min D:min7 D:min7 G:7(b9) G:7(b9) C:maj C:maj C:maj C:maj A:min7 A:min7 A:min7 A:min7 D:9 D:9 D:9 D:9 D:9 D:9 D:9 D:9 D:7 D:7 D:7 D:7 D:min7 D:min7 D:min7 D:min7 G:7 G:7 G:7 G:7 C:maj C:maj C:maj C:maj C:7 C:7 C:7 C:7 F:maj F:maj F:maj F:maj F:min F:min F:min F:min C:maj C:maj C:maj C:maj 

결과 5: (단어-RNN, 8회 학습, 다양성 1.2)





C:maj/3 C:maj/3 C:maj C:maj C:maj C:maj C:maj C:maj C:maj C:maj A#:9 F:maj7 A#:7 A#:7 C:maj C:maj C:maj/3 C:maj/3 F:maj6 F:maj6 C:maj C:maj C:maj C:maj C:maj C:maj G:min7 G:min7 G:min7 G:min7 F:maj F:maj F:maj F:maj D:min7 D:min7 D:min7/4 G:sus4(b7) G:min9 G:min9 G:min9 F#:(1,3,b5,b7,9,13) C:6(9) G:sus4(b7,9) E:7(s5,*5,s9) E:7(s5,*5,s9) A:min9 A:min9 A:min9 A:min9 D:min7 D:min7 D:7(b9) D:9 G#:9(s11) G:(1,4,5,b7,9,11,13) G:aug(b7,9) G:9(s5,*5) C:maj6 C:maj6 E:min7(s5,*5)/b7 A:7(s9,s11,b13) 

결론

  • 음악적인 지식을 전혀 이용하지 않고 그저 코드 진행을 보여주는 것 만으로도 의미있는 코드진행을 생성시킬 수 있습니다.
  • 다음 편인 LSTM 메탈리카가 궁금하시면 영문 포스팅을 참고하세요. 
  • 이 연구는 CSMC2016 학회에 제출되었습니다.

Friday, March 11, 2016

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

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

개요

지난번 포스팅 (음성/음악신호+머신러닝 초심자를 위한 가이드 [1편])에서는 아주 간단한 MFCC 추출 - 로지스틱 회귀 분류기를 사용한 예제를 설명드렸습니다. 놀랍게도 제가 2편을 쓰는군요. [1편]은 잘 이해하셨나요? 디지털 신호와 공학 수학에 대한 간단한 배경 지식이 있었다면 잘 이해하셨을겁니다. 이번 [2편]은 [1편]의 확장판입니다.

1편의 구조를 간략히 정리하면 아래와 같습니다.

<구조>
음악,음성신호 입력 --> [전처리] --> [특징값 추출] --> [분류기] --> 결과

<예>
애기가 우는 소리 녹음파일 -->[전처리:애기가 응애응애 하는 구간만 잘라냄] --> [특징값: MFCC] --> [분류기:로지스틱 분류기] --> 배고프다 vs 졸리다 판별

이번엔 각 단계를 좀 더 고도화 할 수 있는지 알아보겠습니다.

전처리

전처리란 말 그대로 데이터를 머신러닝 알고리즘에 넣기 전에 사용에 용이하도록 처리를 해주는 것 입니다. 자동으로 전처리를 해줄 수도 있고, 수동으로 하는 방법도 있겠죠. 전처리는 굉장히 중요합니다. 입력 데이터가 엉망이면 아무리 훌륭한 알고리즘을 짜도 좋은 성능을 장담하지 못합니다. 아니 나쁜 성능을 장담합니다; 오디오 신호의 경우에 전처리 방법은...애기가 응애응애 하는 구간만 쏙 잘라준다.
    • VAD (voice activity detection:음성 탐지)를 쓴다든지, 신호의 크기가 다들 비슷비슷하다면 단순히 프레임의 평균/최대 진폭을 비교한다. 후자의 경우 오디오 편집 툴에서 [노이즈 게이트]를 활용하면 된다.
  • SNR확보: 신호의 잡음을 줄여준다.
    • EQ, 필터: 신호가 존재할 수 있는 주파수 대역을 증폭시키거나 반대로 없는 부분을 자름.
  • 볼륨 정규화: 오디오 신호의 진폭(amplitude)를 최대값 ([-1, 1])로 키워줘서 디지털 신호에 할당된 비트수를 최대한 활용하도록 한다.
등이 있습니다. 그리고 오디오랑 관계 없이 일반적으로 활용되는 전처리 방법은
  • Normalization
  • Whitening (데이터의 분포를 평균을 0, 표준편차를 1로 맞춰준다)
  • PCA - Principle Component Analysis (자세한 설명은 여기!) 를 써서 고차원 데이터를 압축한다
등이 있습니다.
다시 한 번 말씀드리면, 전처리는 정말 중요합니다. 신호가 가지고 있는 정보를 최대한 보존하면서 전체 데이터의 크기를 최소화 해야 효율적으로 연산을 할 수 있습니다. 그리고 정규화 등 데이터의 분포가 일정하지 않으면 성능에 영향을 줄 수 있습니다. 물론 좋지 않은 영향입니다. 만일 전처리 단계에서 처리가 안된다면 특징값 추출을 더욱 훌륭하게 짜야하겠죠.

특징값 추출 (feature extraction)

무지, 무지, 무지 중요합니다. 딥러닝이 대세가 되기 이전의 오디오+머신러닝 연구는 어떻게 하면 특징값 추출하는 방법을 잘 고안해내서 원하는 작업을 할 수 있을까 였습니다.
가이드 1편에서는 고민없이 MFCC를 사용했었죠? MFCC는 활용 범위가 아주 넓습니다. 그러나 언제 써먹을 수 있는지를 구체적으로 알아둬야 하겠죠. 아래 설명드리겠습니다.

  • MFCC
수식은 여기저기 다 나옵니다. 저는 핵심적인 개념과 의미만 설명하겠습니다.
    • 음색(timbre)은 악기 소리나 사람 목소리를 구별할 수 있게 해주는 그야말로 음색의 차이입니다. 흔히 '톤'이라고 표현하기도 하죠.
    • 공학적으로 보면 음색을 좌우하는 하는 아주 중요한 요소는 바로 악기 혹은 목소리의 배음 구조입니다. 같은 '라 - 440Hz'를 쳐도 피아노와 기타의 음색이 다른건 '라' 음은 440Hz뿐만 아니라 880Hz, 1,320Hz, 1,760Hz..등 440*[1,2,3,4,5,6..] Hz 의 주파수로 이루어져있고, 이 주파수의 에너지 비율이 다르기 때문입니다. 이걸 한마디로배음 구조가 다르다고 표현합니다.
    • 얼만큼 다르냐면요, 같은 관악기에서도 이만큼 다릅니다. 
    • 그리고 이 배음구조의 차이는 악기의 구조에 따라 좌우되며,
    • MFCC는 이 배음 구조의 차이를 표현하는 숫자입니다.
MFCC의 특징은,
    • 음정 (음고, pitch)이 변해도 MFCC가 (나름대로) 일정하게 유지된다는 점 입니다. 따라서,
음성 인식, 음악의 장르 분석, 감정 인식 등 다양한 분야에서 MFCC를 활용합니다. 예를 들어 음성을 인식해야 하는데 목소리가 높은 사람이 높은 음으로 '가나다라~' 하는거랑 낮은 목소리로 '가나다라~' 하는거랑 같게 인식이 되어야 하겠죠? 그러니 MFCC는 적합한 특징값이죠.
반대로 음악에서 악기를 연주하면 그 악기의 음표를 그려주는 목적이라고 하면 MFCC는 절대 사용해선 안되겠죠. 음정의 차이를 무시하도록 디자인되었으니까요.

  • 그 외에
    • spectral centroid
    • spectral rolloff
    • zero-crossing
    • spectral flux
    • energy
여기에서 다 열거하기 어려울 만큼 많은 특징값이 있습니다. 우선 각자가 어떤 특징값을 갖는지 잘 알아보시고, 필요하면 구현해서 쓰시기 바랍니다. 그리고 구현이 귀찮은 분들 (==바로 당신..)을 위해 YAAFE, Sonic Annotator 등 좋은 툴이 많이 있습니다.

Bag of Feature: 특징값 가방;모음;덩어리;..

문제가 있습니다. 특징값의 종류가 너무 많아요. 어떤걸 써야 할지, 어떤 것이 효과적인지, 상대적으로 뭐가 더 중요한지 일일이 고민하기가 까다롭습니다. 특징값 추출을 고안한 사람이 주장하는 효과가 실제로 나온다는 보장도 없구요. 으! 열받는다! 그래서... 그래서 좋은 방법이 있습니다.

다 갖다 써!

시간이 지날수록 컴퓨터의 연산량과 메모리는 늘어납니다. 그러니, 그냥, 수많은 특징값을 다 추출해서 전부 때려넣고 알아서 자동으로 중요한 걸 골라서 쓰게 한다면 참 좋겠죠? 아래처럼요.

<새로운 구조>
음악,음성신호 입력 --> [전처리] --> [특징값 왕창 추출] -->[중요한거 골라주셈] --> [분류기] --> 결과

그래서 어느 순간부터 사람들은 이렇게 하기 시작했습니다. 막, 오디오 프레임 하나에 특징값을 수십, 수백개 쓰는거죠. 전 대충 1x1000 벡터로 (즉 프레임당 특징값이 1000개) 쓰는 것 까지 봤습니다. 그러니까, MFCC 20개, dMFCC 20개, ddMFCC 20개, spectral centroid 1개, zero-crossing 1개, ... 이렇게 잔뜩 구해서 얘네들을 쭉- 붙여서 하나의 벡터로 만들어주는 거죠. 이렇게 해서 프레임마다 1x200짜리 벡터가 나왔다고 치죠. 그런데 문제는 우리는 프레임 마다 특징값을 뽑는 것이 아니라 오디오 신호 전체를 표현할 특징값이 필요하거든요. 이것도 방법이 많지만 제일 간단한 방법은 그냥 각자 평균과 분산을 구해주는 겁니다. 그러면 최종적으로는 1x200 평균과 1x200 분산 --> 1x400 벡터가 되겠죠. 그래도 연산량이 남으면 max()를 추가하면 또 200차원 추가요~ (사실 더 좋은 방법이 있습니다만 여기선 생략합니다. 이 논문에서 어떻게 했나 참고하세요.)

그럼 어떻게 중요한걸 골라주냐면, 전처리 섹션에서 언급한
을 쓰는 겁니다! 자세한 설명은 자세한 설명은 여기!를 참고해주세요.

분류기

분류기는 자세히 다루지 않겠습니다. 그러나 분류기를 고르는 법을 알려드릴게요.

"제일 간단한것부터 해보고 성능이 맘에 안들면 더 복잡한 분류기를 써봐라. 그러나 성능이 비슷하다면 반드시 제일 간단한 것을 사용해라. "
네, 오컴의 면도날이죠. 

절대 쓰다가 귀찮아져서가 아닙니다. 

용어


  • 특징값 == feature
  • 분류기 == classifier
  • 추출 == extraction
  • 전처리 == preprocessing


Sunday, March 6, 2016

Deeplearning4j.org를 한국어로 번역하고 있습니다.

2-3주전부터 deeplearning4j.org를 한국어로 번역하고 있습니다.

Deeplearning4j

DL4J는 개발자들을 위해 만들어진 딥러닝 프레임워크입니다. 머신러닝/딥러닝에 대해 상대적으로 깊은 지식을 갖고 있지 않지만 현장에서 당장 사용해야할 때가 있는데, 이런 경우에 사용하기에 적합하게 설계되었습니다. 보통 연구용 딥러닝 프레임워크는 Python으로 많이 나오죠. 그렇지만 DL4J는 Java용입니다. 그리고 Spark/Hadoop에서 바로 사용할 수 있도록 나옵니다. 

번역을 하게 된 계기

페이스북의 AIKorea그룹에 DL4J의 CEO가 직접 한국어 버전이 있다고 홍보 글을 올리길래 궁금해서 들어가봤는데, 번역이 정말 너무 심하더라구요. 최악의 직역이었습니다. (공돌이 번역은 이런게 많죠. 당장 대학에서 쓰는 공대 교과서 번역본부터...)

예:
각각의 보여지는 노드는 학습될 데이터 세트의 한 항목에서 낮은 수준의 속성을 취합니다. 예를 들어, 회색 스케일 이미지의 한 데이터 세트로부터 각각의 보여지는 노드는 하나의 이미지에서 각각의 픽셀을 위한 하나의 픽셀-가치를 수신할 것 입니다. (MNIST 이미지는 784개의 픽셀을 가지므로, 그들을 처리하는 신경망은 보여지는 레이어 상에서 반드시 784개의 입력 노드를 가져야 합니다.)

너무 상태가 안좋아서 DL4J CEO인 Chris Nicholson에게 쪽지를 보냈습니다. (추후에 링크드인 프로필을 보니 이력이 대단하더군요)

   "당신 홈페이지 잘 봤다. 그런데 번역이 거지같다."
   "정말이냐? 그럴리가 없는뎅"
   "번역을 누가 했는지 몰라도 한국어로 작문을 안하던 사람인게 분명하다. 그리고 머신러닝도 전혀 모르는 사람이 한거같은데?"
   "어...머신러닝을 잘 모르는 사람이긴 하다. 근데 걔 무지무지 똑똑한앤데.."
   "똑똑하겠지. 그리고 나보다 영어도 훨씬 잘하는 사람일 것 같다. 근데 번역도, 머신러닝도 모르는 사람이 한거라...아 정말 구리다. 나한테 맡겨라"
   "어?음..그럼 한페이지 한번 해줘봐."

아마 분명 중간중간 부적절한, 공격적인 어휘 선택이 있었을 것 같습니다. 아무튼 후다닥 해서 보여줬습니다.

   "어..검토해봤더니 니 버전이 더 좋다고 하네. 알았어 얼마에 해줄래?"

해서, 열심히 번역하고 있습니다. 하다보니 생각보다 재미있고 돈도 짭짤하고 좋네요.


글 쓰는 시점을 기준으로 첫 페이지, 퀵 스타트 가이드, 회사 소개 (← 지루한 내용) 뿐만 아니라, 고유 벡터(eigenvector)컨브넷(Convolutional Neural Network)를 마쳤습니다. 고유 벡터는 굉장히 설명이 자세하게 되어있고, 컨브넷은 cs231n보다는 아쉽지만 그래도 부분부분 상세하게 내용을 설명해놓았습니다.
고유벡터를 번역하다 보니 학부생때 이런 설명을 들었다면 얼마나 좋았을까 하는 생각이 들더군요. 물론 수업도 잘 안들어가던걸 생각하면 전혀 변명이 안되지만... 여튼, 저 두 페이지는 내용이 아주 좋습니다.
조만간 LSTM, 뉴럴넷 개요, RBM, RNN, word2vec 페이지도 번역할 예정이니 기대해주세요. 이 작업을 마무리하면 cs231n 홈페이지의 튜토리알도 번역을 해볼까 생각중입니다.


Thursday, January 21, 2016

리알못: 리눅스 알지도 못하는 사람들을 위한 가이드

스티브 잡스님의 은혜를 받으며 살아가던 저같은 앱등이도 살다보면 리눅스를 써야할 날이 옵니다. 아니, 왔습니다. 저에게 리눅스는 제 컴덕 친구들이나 흐흐거리며 다루는, 혹은 리눅스를 만든 녀석이 메일링 리스트에서 또 누군가랑 싸웠다는 기사를 흘낏 보며 떠올리는, 아주 추상적인 존재였죠. 그러나 학교와 회사의 서버를 써야하고, 그런데 서버는 리눅스로 되어있고, 나는 일개 학생/직원일 뿐이고, 그래서 20년전 MS도스를 쓰던 시절에 혹은 PC통신에서나 쓰던 ls, cd ..같은 명령어를 써보며 마치 내가 뭘 할 줄 아는 것 처럼 이런 저런 디렉토리를 오간 뒤에 결국은 인정했습니다. 아, 이걸 공부해야 하는 구나.

막상 리눅스 책이나 강좌를 보면 수백 페이지 분량의 엄청난 것들이 나옵니다. 리눅스란 무엇이고, 누가 언제 만들었고, 무슨무슨 종류가 있고, 어쩌구 저쩌구... 커널은 뭐고..등등.

이런 내용 다 제끼고! (저도 모를뿐더러; ) 리눅스 초보를 위해 아주 간략히 정리해드리겠습니다. 사실, 네이버 구글 찾으면 어지간한건 다 나옵니다. 그런데 문제는 이거죠. 뭘 찾아야 할지 모른다는 것.

그래서 아주 간략히, 정말 간략히 개념만 설명합니다. 더 자세하고 훌륭한 설명은 다시한번 구글링 하시길 바랍니다.


  • 리눅스? 유닉스?
    • 리눅스는 유닉스의 한 종류입니다. 아니 정확하게 따지면 유닉스와 유사한 뭐라고 하는데 그냥 리알못들은 그런가보다 하고 넘어갑니다. 
  • 무얼 설치해야하나요?
    • 혹시 직접 설치해야 한다면 linux ubuntu download를 구글링하셔서 맨 위 링크를 누르세요. 여러 버전이 나올텐데 LTS (Long Term Support) 버전을 쓰세요. 지금은 14.04네요.
  • 알아야할 명령어 목록
    • $ ls - list
      • 디렉토리의 내용을 보여줌
    • $ pwd - print working directory
      • 현재 디렉토리의 위치를 알려줌
    • $ less some_text_file.txt
    • $ more some_txt_file.txt
      • 텍스트 파일의 일부를 후다닥 볼 수 있음.
    • $ tail some_text_file.txt
    • $ head some_text_file.txt
      • 마찬가지. 텍스트 파일의 맨 앞/맨 뒤를 출력해줍니다.
    • $ touch temp.abc
      • 저 파일이 없다면 temp.abc라는 파일을 생성합니다. 파일의 내용은 비어있습니다.
      • 파일이 있다면 저 파일을 한번 툭 건드려주게됩니다. 결과적으로 파일의 '최종 수정한 날짜'가 현재 시간으로 바뀝니다.
    • $ mkdir directory_name
      • 디렉토리를 만듭니다.
    • $ rmdir directory_name
      • 디렉토리를 삭제합니다.
    • $ cp file.txt new_file.txt
      • 파일을 복사합니다.
    • $ mv file.txt new_name.txt
      • 파일을 이동합니다. 이 명령어를 이용해 이름을 바꿀 수 있습니다. 
    • $ echo 'blah blah
      • blah blah 라고 출력합니다.
    • $ cat files.
      • 여러 파일을 붙입니다.
    • $ tar, zip
      • 파일 압축/해제.
    • $ wget url
      • url의 파일을 다운받습니다.
    • $ chmod, chown
      • 파일/디렉토리의 권한을 바꿔줍니다.
    • $ sudo 
      • 각종 커맨드 앞에 sudo를 붙여주면 super user의 권한으로 뭔가를 하게됩니다. 수퍼 유저는 다시말해 admin, 관리자 계정입니다. 따라서 이걸 하려면 관리자 계정의 권한을 갖고있어야합니다.
    • $ top
      • 작업관리자입니다. 아주 유용하죠.
    • $ iotop, iostat
      • top과 비슷한데 각종 기기간의 입출력 내역을 보여줍니다.
    • $ nohup
      • $ nohup python main.py > log_file_name.txt &
      • 커맨드 실행 내역의 결과를 log_file_name.txt 에 저장합니다.
      • 서버에 접속해서 이걸로 커맨드를 실행하면 그 이후에 접속을 끊어도 커맨드가 계속 실행되게 됩니다. 아주 유용하죠. 
      • 그럼 중간에 실행을 중지하고싶다면?
    • $ kill, pkill
      • pkill python
      • kill 12345
      • pkill python은 실행중인 파이썬을 전부 종료합니다.
      • kill 12345는 프로세스 아이디 12345를 종료합니다.
      • 프로세스 아이디는 top 을 실행하면 왼쪽에서 볼 수 있습니다.
    • $ screen
      • nohup과 비슷한데, 저는 더 유용하게 쓰고있습니다.
      • 쉽게말해 가상의 스크린을 여러개 띄워놓고 필요할 때 해당 스크린에 접속해서 사용하는 것 입니다.
      • screen -S screen_name 으로 새 스크린을 만들고,
      • 새 스크린 내부에서는 ctrl+a, d 를 눌러서 밖으로 나올 수 있습니다.
      • screen -x 를 하면 스크린 목록을 볼 수 있습니다.
      • screen -x screen_name 으로 기존에 만들어놓은 스크린에 다시 들어가서 일을 할 수 있습니다.
      • 서버에 접속해서 일하실 땐 디폴트로 스크린을 하나 만들어서 들어가서 쓰시면 중간에 접속이 끊어져도 서버에서 실행중인 프로세스가 종료되지 않아서 좋습니다.
    • [tab]
      • tab키는 정말 중요합니다.
      • 디렉토리에서 abdefefsdsdfsdfsdcscs.sh 라는 파일을 실행하고 싶다면...
      • 다 타이핑 하지 마시고, 앞에 몇개만 타이핑한 뒤 [tab]키를 눌러보세요.
      • 만일 디렉토리에
        • abc123.txt, abc456.txt, ddd.txt
      • 이렇게 3개의 파일이 있다고 하면,
        • a 까지 치고 탭을 누르면
          • $ a [tab]
        • abc까지 자동 완성이 됩니다.
          • $ abc
        • 여기서 추가로 1을 타이핑하고 탭을 누르면
          • $ abc1 [tab]
        • abc123.txt가 자동완성이 됩니다.
          • $ abc123.txt
        • 왜냐면 abc로 시작하는 파일이 두개가 있기때문이죠. 즉, ddd.txt의 경우 훨씬 쉬워지죠. d로 시작하는 파일은 저것 하나뿐이므로...
          • $ d [tab]
        • 을 누르면
          • $ ddd.txt
        • 라고 자동 완성이 됩니다.

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를 쓰게될지는 모르겠습니다만 여튼 도움이 되었으면 좋겠습니다.





Thursday, December 24, 2015

비틀즈가 스포티파이/디저/아마존 등 스트리밍 서비스에 상륙!



2015년 12월 24일 12:00부터 각종 스트리밍 서비스에서도 비틀즈를 서비스하기 시작했습니다. 당연히 캐롤이 나와야 할 날인데 가게에서도, 옆방에서도 비틀즈를 틀어놨더군요. 과연 비틀즈의 위엄입니다.




원래 비틀즈는 아이튠즈 등 mp3 판매 사이트에서 서비스되지 않았었죠. 그러다가 2010년 11월 16일 아이튠즈에만 최초로 서비스를 개시합니다.


 그 이후로 5년이 넘게 애플을 통해서만 비틀즈의 음원을 다운/재생할 수 있었습니다. 국내 네이버뮤직/멜론 등에서도 비틀즈 원곡이 없는 이유는 이때문입니다.

찾아보니 아직 국내 서비스에서는 안되는 것 같네요. 그렇지만 한번 길이 열렸으니 곧 가능해질 것이라 생각합니다.

Friday, December 4, 2015