Tuesday, July 9, 2019

책 - 타인에게 말걸기 (단편집), 은희경

<타인에게 말걸기> 은희경 단편소설집 (리디북스 링크)


소설가 은희경이 신춘 문예로 등단하고 <새의 선물>을 낸 것이 1995년입니다. 이 책은 그 뒤에 나온 첫번째 작품으로 총 8개의 작품이 수록되어있습니다.

- 그녀의 세번째 남자
- 특별하고도 위대한 연인
- 연미와 유미
- 짐작과는 다른 일들
- 빈처
- 열쇠
- 타인에게 말 걸기
- 먼지 속의 나비

은희경 작가님의 장점은 굳이 제가 열거할 필요 없을것 같습니다. 옥의 티를 꼽자면 여러 작품에 나오는 인물의 사고방식이나 어투에 다양성이 조금 떨어진다는 점입니다.

총 8개 중 앞에 나오는 6개를 읽었습니다. 가장 기억에 남는 작품은 <연미와 유미>입니다. 소설에 나오는 언니의 노트를 읽는 부분에선 끝없이 휘몰아치는 색소폰 솔로를 듣고있는 기분이 들었습니다.







Sunday, June 9, 2019

딥러닝과 오디오 데이터 전처리

이번 글에서는 딥러닝과 오디오 데이터 전처리 전반을 살펴보겠습니다. 제가 몇몇 발표 (2017-11-03 판교 혁신센터, "음악과 딥러닝의 사랑과 전쟁" (발표자료))에서 다룬적이 있는데, 이미지랑은 달리 오디오 데이터는 몇가지 특징이 있습니다.

  • 데이터 사이즈가 크다 - 상황에따라 천차만별이지만 오디오는 기본 16비트고 (이미지는 8비트 x 3, 4채널) 1초당 int16짜리 데이터가 44,100개가 있습니다.
  • 디코딩이 느리다 - 데이터가 크기 때문에 음성/음악 코덱 기술이 많이 발달했습니다. 그런데 오디오 코덱은 신호를 시작부터 끝까지 순차적으로 디코딩합니다. 그리고 연산량이 적어서 디코딩 속도가 빠를수록 좋긴 하지만, 한편으론 재생 속도보다 빠르기만 하면 일반적인 오디오 재생에는 별 문제가 없겠죠. 그러다보니 딥러닝 학습과정에선 문제가 될 수 있습니다. 즉, 디코딩 속도가 데이터 로딩의 병목이 될 수 있습니다.
  • 별도의 전처리가 필요할 수 있다 - STFT, Melspectrogram 등의 연산이 여기에 해당합니다.

그 외에, 일반적인 딥러닝 학습을 하다보면 누구나 겪게되는 상황이 있습니다.

  • 데이터가 커서 메모리에 다 안들어간다.
    • HDF? memmap?
  • 데이터를 추가하거나 데이터 전처리 파라미터를 편리하게 변경할 수 있어야한다.

이런 상황을 고려하면 해결책은 아래와 같습니다.

  • 저장 포맷
    • 디코딩이 끝난 오디오 데이터를 그대로, 파일마다 .wav (int16)나 .npy (numpy array, int16/float32/etc)로 저장
    • 예: audio_1.wav, audio_2.wav, ... audio_10000.wav
    • 장점: 로딩이 빠르다
    • 단점: mp3등 압축 코덱 대비 하드디스크 공간을 많이 차지한다. 그러나 대부분의 경우에 현실적으로 큰 문제가 아님. 하드디스크는 별로 안비싸고, 오디오 데이터셋이 보통 그렇게까지 크지 않음. 
  • 로딩 방식
    • 파이토치와 텐서플로 모두 데이터 로딩 모듈이 잘 짜여져있습니다. 각 모듈에서 데이터 인덱스(예: idx=10)를 받아서 파일을 하나 로딩하는걸 구현합니다.
    • 사용할때는 인덱스 ([1, 2, 3,.. ,10000])을 shuffle한 뒤에 순서대로 불러오면 됩니다.
    • 파이토치의 경우엔 예를들면 저는 이렇게 합니다 (소스).
    • 장점: 
      • 데이터를 쉽게 추가할 수 있음. 마찬가지로 shuffle도 다양하게 할 수 있음. (만일 hdf를 쓰면 연속된 메모리에서 불러와야 유리하므로 미리 셔플을하고 저장해야하는데 이 모든 데이터 준비 과정이 시간을 많이 잡아먹음)
      • 배치 사이즈만큼의 데이터를 불러오는 과정은 텐서플로/파이토치의 데이터 로딩이 알아서 멀티프로세싱으로 잘 수행하므로 편리하고 안정적임. 
  • 전처리
    • 가급적 대부분의 전처리를 gpu에서 수행 (stft 등)
      • 장점: 파라미터 변경이 쉬움. 나중에 모델을 배포하고 사용할때도 오디오 파일을 그대로 불러와서 진폭을 바꿔주고 (int16 --> float, [-1.0, 1.0]) 샘플링 레잇만 맞춰주면 바로 모델에 넣을 수 있어서 편리함. Dependency가 적어짐 (librosa같은 외부 라이브러리를 쓰지 않아도 되므로). 
      • 단점: gpu의 연산과 메모리를 조금 더 사용함.


Thursday, May 9, 2019

오디오 노멀라이즈(정규화) 방법 정리


오디오 신호를 입력받는 머신러닝이나 신호처리 시스템을 사용할 때는 입력받은 신호가 사용하기 적합하도록 다양한 처리를 해주곤 합니다. 가장 단순한 방법으로 오디오 신호의 레벨을 조정하는 노멀라이즈가 있습니다. 이번 포스트에서는 다양한 노멀라이즈 기법이 어떤 특징을 가지고 언제 적용할 수 있는지 알아보겠습니다.

용어

노멀라이즈(Normalize)는 정규화라고 번역하는경우가 많은데, 노멀라이즈에는 결과가 특정 기준에서 '1'이 된다는 의미를 함축하고있습니다. 좀 고민이 되는데 그냥 노멀라이즈라고 해버리겠습니다.

레벨 변경

우선 디지털 오디오 신호를 $x[n]$ 혹은 간단히 $x$라고 하겠습니다. 보통 노멀라이즈는 $x_{normalized} = K \times x$ 의 과정이 됩니다. $K>1$ 이면 소리가 더 커지는 증폭(amplification)이 되고 $K<1$이면 소리가 더 작아지는 감쇠(reduction)가 됩니다. 즉, 특별히 주파수별로 처리를 해주지 않는다면 소리의 특성은 그대로 남아있고 레벨만 변합니다. 청취자가 이 소리를 듣는 맥락이라면 이를 흔히 볼륨을 높이거나 낮춘다고 이야기합니다.

이제 노멀라이즈 기법에 대해 알아봅시다.

1. 진폭(Amplitude) 노멀라이즈 

디지털 도메인에서는 신호 $x$의 최댓값, 최솟값이 존재하죠. 정수로 표현하면 비트레잇에 따라 다르겠지만 Float으로 표현하면 $[-1, 1]$의 범위를 갖는것이 일반적입니다. 만일 $\text{max}(|x|)>1$인 신호가 있더라도 이를 오디오 '데이터'로 사용하는데는 별 문제가 없습니다. 즉, 이런 오디오 신호도 머신러닝 시스템의 입력값으로 사용할 수 있다는 말입니다. 물론 i) 시스템이 입력값의 크기와 무관한 성능을 보여야 하는지, ii) 실제로 원하는대로 작동하는지는 따로 점검을 해야겠지만요. 하지만 이를 그대로 재생한다면 진폭이 1이 넘는 구간은 제대로 소리가 나지 않습니다. 재생과정에서 이는 강제로 $[-1, 1]$구간이 되도록 짤리게되는데 이를 클리핑이라고 합니다. 클리핑이 난다, 클리핑이 뜬다, 등의 상황입니다.

정리하면, 재생하려는 오디오 신호는 진폭 노멀라이즈가 필요합니다.

2. 에너지(Energy) 노멀라이즈

에너지 노멀라이즈는 다소 상대적인 개념입니다. 신호 $x$와 $y$가 있을 때, 두 신호의 제곱의 합(의 평균)이 같아지도록 하는 과정입니다. 데이터셋에 신호가 많이 있다면 전체 신호의 제곱의 합(의 평균)이 전부 같아지도록 해야겠죠. 즉.. $\sum_n{x[n] ^ 2} / n $과 $\sum_n{y[n] ^ 2} / n $가 같아지도록 두 신호의 레벨을 조정하는 것입니다. RMS 에너지/볼륨 노멀라이즈라고도 이야기합니다.

진폭과 차이점은, 진폭보다는 에너지가 '실제로 사람이 들었을 때 느껴지는 두 신호의 크기'(=라우드니스)를 더 잘 나타내주기 때문에 에너지 노멀라이즈를 함으로써 두 신호의 '볼륨'이 같아지는 것(을 근사하는 것)이라고 볼 수 있습니다.

에너지 노멀라이즈는 머신러닝에서도 흔히 사용하는 방법입니다. 다만, 위에서도 이야기했듯이 에너지 노멀라이즈를 해주는게 학습하는 시스템의 특성과 잘 맞는지 고민해보고 사용해야합니다.

3. 라우드니스(Loudness) 노멀라이즈

우선 라우드니스의 개념을 알아보겠습니다. 위에서 제가 라우드니스를 '실제로 사람이 들었을 때 느껴지는 두 신호의 크기'라고 이야기했는데, 이 정의를 꼼꼼히 살펴볼 필요가 있습니다.

주관성

우선 소리의 크기 인지는 사람마다 다르므로 근본적으로 라우드니스는 주관적인 개념입니다. 그래도 뭔가 하긴 해야하니 '평균'적인 인지를 가정하겠습니다.

라우드니스는 주파수의 함수

에너지가 소리의 크기를 대략적으로 나타내주긴하지만 정확하진 않습니다. 에너지가 같은 신호라도 주파수가 다르면 라우드니스, 즉 체감상 느끼는 소리의 크기가 달라집니다. 예를 들어 사람은 3-5 kHz 대역의 소리에 예민하고, 주파수가 아주 낮아지거나 아주 높아지면 잘 듣지 못합니다. 그러므로 에너지가 같은 신호라도 $x$의 주 성분이 100 Hz에,  $y$의 주 성분이 3,000 Hz에 있다면 $y$의 라우드니스가 훨씬 큽니다. (물론 이것도 주파수 특성이 평탄한, 즉 100 Hz와 3,000 Hz의 소리를 둘 다 균일하게 재생하는 스피커나 이어폰을 사용하는 경우에 해당합니다.)

따라서 라우드니스를 맞춰주려면 주파수 분석을 해야합니다.

라우드니스는 레벨의 함수

그런데 그게 다가 아니고, 라우드니스는 레벨에 따라 달라집니다. 이걸 한번에 나타내주는 그림이 아래의 등청감곡선인데, i) 값이 주파수에 따라 달라서 선이 구불구불하고, ii) 구불구불한 패턴이 소리의 크기에 따라 다르다는 점을 이해하면 됩니다. 



따라서 정확한 라우드니스를 구하려면 주파수 분석뿐만 아니라 이 신호(signal)가 어떤 크기의 소리(sound)로 재생될지 알아야합니다.

..그런데 당연히 이걸 알 수가 없겠죠?
도대체 이 신호를 청취자가 들을 때 볼륨을 어떻게 설정하고 들을지 알 수가 없으니까요. 
애당초 디지털 도메인에 있는 신호에는 '라우드니스'라는 개념이 정의되지 않습니다. 

그렇지만 근사적으로 맞춰주고자할때는 위의 등청감곡선의 평균적인 분포를 이용하거나, 이를 더욱 더 근사한 A-weighting같은것을 사용합니다. 조금 신경을 쓴다면 예를들어 0 dBFS를 100 dB SPL과 같다고 가정하고 이를 기준으로 처리하는 방법도 있습니다.

마지막으로, 여러 신호를 균일하게 전처리하려는 목적은 아니지만 음성 신호 처리에서 사용하는 pre-emphasis도 라우드니스가 주파수의 함수이기 때문에 (구체적으로는 사람이 저주파수 성분을 잘 못듣기 때문에) 적용된다고 볼 수 있습니다.

4. Mu-law

Mu-law는 낮은 비트레잇(예: 8비트)으로도 최대한 좋은 음질을 얻기 위해 사용하는 방법입니다. 보통 16비트에서는 잘 사용하지 않습니다. 이 방법은 앞에서 소개한 노멀라이즈랑은 조금 다르지만 같이 소개하겠습니다. 

Mu-law는 웨이브넷에서 사용하면서 유명해졌죠. 웨이브넷은 오디오의 샘플을 직접 생성하는 뉴럴넷입니다. 그런데 최종 레이어에서 Softmax를 사용하고, 진폭 출력을 회귀(Regression)가 아니라 분류(Classification)문제로 보고 값을 예측합니다. 따라서 8비트 오디오를 생성하는 문제는 총 $2^8=256$개의 카테고리 중 정답을 고르는 문제인데, 이걸 16비트 오디오로 비트레잇을 올리면 $2^{16}=65536$개의 카테고리가 되어서 문제가 많이 어려워집니다. 이를 효율적으로 해결하기 위해 8비트 오디오를 사용하지만 mu-law를 활용했습니다. 다시말해, 진폭을 8비트로 양자화하는 방법중에서 결과가 듣기 좋도록(잡음이 덜 들리도록) 최적화하는 방법입니다.

Mu-law는 오디오를 더 높은 비트레잇의 오디오를 (예: 16비트) 더 낮은 비트레잇으로 저장하는 과정에서(예: 8비트) mu-law따라 저장하는것으로 미리 설정해줘야(=mu-law 인코딩을 수행한 뒤 저장)합니다. 다시말해 일반적인 8비트 오디오 신호를 다시 mu-law를 이용해 더 고음질로 저장하는것은 불가능합니다. 

5. 주파수 도메인 (STFT) 노멀라이즈

이건 오디오 신호처리보다 머신러닝에 국한된 이야기입니다. 상당수 연구에서 log STFT Magnitude $\log(M)=\log(|X|)=\log(|\text{stft}(x)|)$의 크기를 특정 구간으로 노멀라이즈합니다. 상황에 따라 $[0, 80]$, $[0, 120]$, $[-120, 0]$, $[-1, 1]$ 등.. 제각각입니다. 이쯤되면 오디오 신호라기보다는 입력 데이터의 값을 컨디셔닝해주는 것으로 보는게 더 알맞겠죠.

진폭에도 해당되는 이야기인데, 특히 오디오 신호나 STFT Magnitude를 생성하는 머신러닝 시스템이라면 출력값의 범위와 최종 레이어의 액티베이션 함수 등을 적절하게 선택해야겠죠. 예컨대 GANSynth에서는 마지막 레이어에 $Tanh$ 함수를 사용하지만, 가급적 함수의 선형 구간에 값이 해당되도록 하기 위해 STFT의 크기와 위상을 $[-1, 1]$로 노멀라이즈했습니다. 



이번 포스트는 여기까지입니다.




Sunday, May 5, 2019

블로그 통계

약 4년간 블로그를 운영했네요. 제 블로그의 방문 현황과 게시물 조회수등을 간략히 공유합니다. 

게시물 누적 조회수

45334
29945
14951
13888
May 31, 2016, 9 comments
5076
4490
4016
3169
3106
3008


최근 일주일간 게시물 조회수

201
103
82
82
76
May 31, 2016, 9 comments
75
37
23
22
18


누적 방문 경로 


파편화가 긴했는데 구글과 페이스북이 압도적이군요. 

국가별 페이지뷰

South Korea
210146
United States
17518
Russia
12321
United Kingdom
3143
Japan
2900
Germany
1256
Ukraine
1189
France
915
Canada
786
Unknown Region
610

대략한국 유학생의 분포가 아닐까합니다. 우크라이나가 순위권에 있는것은 조금 의외군요.