본문 바로가기
딥러닝으로 하루하루 씹어먹기

딥러닝 STT 모델 - ESPNet (5 - 음성처리 도메인)

by Yoo Sung Hyun 2021. 10. 25.
728x90

지난 시간에는, 거의 딥러닝에 대한, ESPNet의 모델 아키텍쳐와 구조 흐름이 어떻게 흘러가고, 실제로 소스로 논문과 비슷하게 작성되어있는지 확인하는 작업까지 마쳤다.

글을 읽는 것 만으로는, 길기도 길어서 보기 어렵고 난해할 수 있는데, 언제든지 질문은 환영이다!

2021.10.22 - [논문으로 현업 씹어먹기] - 딥러닝 STT 모델 - ESPNet (4 - Training 시작!)

 

딥러닝 STT 모델 - ESPNet (4 - Training 시작!)

BERT 관련 프로젝트를 진행하면서 쓰려니, 왔다갔다 정신이 없다...ㅋㅋ 그래도 시간이 좀 되는거 같아 바로 이어서 가보도록 하자. 2021.10.21 - [논문으로 현업 씹어먹기] - 딥러닝 STT 모델 - ESPNet (3

shyu0522.tistory.com

다만 이제 이전 설명에서 부족하게 넘어간 부분이 있다면, Data Set Pre-Processing 부분은 후다닥 넘어간 면이 없지않아 있다.

 

서론

그래서 이번 시간엔, 딥러닝이라기보단, 음향처리에 대한 도메인 지식들을 다뤄보고자 한다.

필자도 컴퓨터 공학도 인데다가, 과거에 TTS 프로젝트를 진행했을땐, 약간 도메인에 대해 깊게 고민해보진 않았었고, STT를 하게 되서야 집중하게 되는 것 같다.

2021.05.14 - [논문으로 현업 씹어먹기] - 딥러닝 STT 모델 - ESPNet (1)

더군다나 1장에서 진짜 초창기에 지식습득하기 시작하면서 적어놓은 귀여운 지식들은, 사실상 음향 전처리라기 보다는, ESPNet의 기술을 이해하기 위한 개요에 불과한 지식들이었다.

 

앞뒤가 조금 안맞을 수도 있고, 내용이 너무 구구절절일 수 있지만, 일단은 도메인 지식에 대해서 한큐에 정리를 하고 넘어가보고자 한다.

 

아마 AI 엔지니어가 이해한 수준의 음향처리 도메인이므로, 같은 직군의 친구들에게는 좀 더 공감가는 유용한 내용일 수도 있겠고, 아니면 잘못되거나 추가할만한 부분이 있다면, 댓글로 남겨준다면 고맙겠다.

 

음성 데이터란 무엇인가?

음성 데이터는, 공기 분자가 얼마나 크게 흔들렸는가? 이다.

그래서 그 흔들림은 진폭으로 표현 가능하며, 주파수는 1초에 그 주기가 몇번 발생하였는가를 의미한다.

따지고 보면 시간에 대한 세기(에너지)로 표현되어서, 내가 담당하던 수요예측 등과 비슷한 맥락으로 생각 해볼 수 있겠다.

 

ADC (Analog Digital Conversion)

아날로그 신호는 우리가 내는 자연상태에서의 신호라면, 디지털신호는 컴퓨터가 이해할 수 있는 신호로 어떤 특정 숫자값으로 치환 가능해야한다.

또한 우리는 딥러닝에서의 Input Data로 사용하기 위해서, 이산형 벡터 데이터로 치환하는 과정이 필요하다.

Sampling과 Quantization의 2 Step으로 주로 이루어져 있으며, 우리가 흔히 듣는 Sample Rate가 이와 같은 시도의 결과라고 볼 수 있다.

Sample Rate는 1초에 존재하는 sample의 개수로, 영상으로 생각하면 Frame 이라고도 생각해볼 수 있을 것 같다.

결국에는 Sampling과 Quantization의 방식으로, 마치 곡선으로 표현되어있는 원을, 직선으로 표현하려면, 몇개의 면을 가지는 다각형으로 표현할 수 있게 되는 것과 같은 이치이다. 

그러면 다각형으로 표현된 원을, 사람이 다시 듣기 위해서는 다시 곡선으로 바꿔야 할텐데, 어떻게 해야할까?

여기서 재미있는 원리중 하나인 Nyquist Law가 등장한다.

예시를 들어보자면, 내가 이해하기로는, 마치 바람개비에 한 날개에만 색을 칠한뒤, 빙글빙글 도는 것을 사진으로 증명해야한다. 우리는 어떻게 하겠는가?

사진을 찍어서 마치 만화를 넘기듯 빠르게 넘기고자 할 것이다.

 

그런데, 사진을 1장만 찍으면? -> 바람개비가 돌아가지 않는 것 처럼 보일 것이다.

사진을 2장 찍으면? -> 바람개비가 돌아가는 것 처럼 보일 수는 있겠다.

사진을 수백, 수천, 수만장 찍으면? -> 실제로 바람개비가 돌아가는 속도보다 더 빠르게, 혹은 더 느리게 돌아가는 것 처럼 표현되어, 사실이 왜곡될 수 있다.

 

Nyquist Law에서는 이런 현실에서의 아날로그 신호를 디지털 신호로 변경한뒤, 다시 이걸 아날로그 신호로 바꾸려고 할때, 가장 효과적인 사진의 개수를 결정지은 것인데, 그것은 주파수의 2배만큼을 Sampling 하면 된다는 이론이다.

그래서, 사람의 가청주파수인 20KHz의 2배값인 40KHz에, 오차범위 10%정도를 가미하고, 여러 방식들을 적용하면, Sample Rate는 44100Hz정도가 일반적인 형태가 되는 것이다.

물론 이 값이 작아지면, 표현할 수 있는 사진의 수가 적어지는 것이니, 음성에 유실이 생길 수 있겠고, 또 너무 많아지면 아까 위에서 다룬 것과 같이 사람이 인지하는 것과 다른 노이즈가 발생하는 Aliasing 문제가 발생하게 될 수도 있다.

http://www.alanjshan.com/sampling-01/

 

샘플링 이야기

(adsbygoogle = window.adsbygoogle || []).push({}); Vinyl 이나 Tape 을 최종 녹음 미디엄 (medium) 으로 사용하던 아날로그 시대를 거쳐 우리는 지금 디지털의 시대에 살고 있습니다.   소리는 공기 중의 떨림 입

www.alanjshan.com

Quantization은 좌표 평면에 존재하게되는 이산형 데이터를 어떻게 숫자로 표현할 것인가에 대한 문제이며, 16bit 라고하면 65536 Levels 값으로 양자화 시키게 된다.

 

자 그러면, 음성 데이터라는게 어떤 것이고, 컴퓨터에서 활용하기 위해서는 어떤 처리등이 필요한지 알아보았다.

그러면 실제로 학습용 데이터로 사용되기 위해서는 어떤 작업들이 수반되어야 할까?

 

Input Data로 쓰이기까지의 음성데이터의 여정

Window Frame

위에서 잠깐 다뤘지만, 음성데이터는 시간에 따른 에너지라고 볼 수 있으며, 우리는 해당 문제를 시계열 처럼 다뤄서 해결할 수 있다.

시계열하면? LSTM이고, LSTM하면? 가장 먼저 생각나는 것이 Window Frame일 것이다. (나만 그런가?)

음성 데이터는 결국 시계열에 의존하기때문에, 시간순에 대한 Frame으로 구성할 수 있으나, 우리가 말하는 소리는 아아안녀어어엉하아아아세에에에요오오오 라고 말하는 사람이 있는 반면, 안냐세요 라고 얘기하는 사람이 있어서, 어느 기준으로 잘라야 할지 애매하다. 잘못 자르면, 온전한 주파수가 완성되지 않고, 앞뒤로 주파수가 섞여있는 현상이 발생할 수도 있기 때문이다.(side lobe, leakage가 발생한다고 한다.)

그래서 강제로 온전한 1 진폭이 완성되기 위해서, Frame을 떼서, 신호의 시작과 끝을 강제로 0으로 수렴시켜버린다. Uniform과 비슷한 모양이 되도록 말이다. 이런걸 구형 윈도우라고 한다. 강제로 0으로 수렴시켜버리면, 값이 날라가서 손해일 것 같지만, 그런 문제들을 해결하기 위해서는 오버랩을 사용하여, 데이터를 겹쳐서 Frame이동을 시키는 것으로, 손실을 최소화한다. (물론 많이 오버랩할 수록 속도는 떨어진다.)

 위와 같은 작업들을 해주는 여러가지 삼각함수를 이용한 방법들이 Hamming, Hanning, Blackman, Kaiser 윈도우 등등이 있다. 이렇게 되면, 일단 시간의 흐름대로 처리할 수 있는 최소의 분해는 완료되었다고 할 수 있겠다.

 

FFT (Fast Fourier Transform)

사실 Window Frame 이동을 시키는 것은, (F)FT((Fast) Fourier Transform) 를 하기 위함이라고 볼 수 있다.

우리가 가지고있는 Frame으로 쪼개어진 음성들은, 사실 그 안에 여러 주기적 파동들이 섞여서 비주기성처럼 보인다는 것이다. (예를들면, 새의 소리도 여러개의 주기적 진폭들이 모여 각각 새의 목소리를 만들어내는 것이다.)

우리는 시계열 분석에서 활용하기 위해서 최대한 Stational한 데이터를 원한다. 그래야 패턴들이 잘 학습되고, 예측력이 좋아지기 때문이다. (Arima 등을 할때 ACF PACF p-value 돌려가면서, 1차 2차 차분 하고 난리 부르스 치던거 잘 생각해보자...ㅋㅋ)

그래서 한 Frame안에 있는 Not Stational한 진동을 여러개 종류의 Stational한 진동으로 분해하고자 한다. (여기서 사용되는 바는 차분이랑은 다르긴하지만.)

마치 햄버거가 무슨 햄버거인지 맞추고 싶다. 그러면 단순히 먹어서 판단하는게 가장 정확한 방법일까?

맛이 합쳐지는 복잡한 방법보다는, 햄버거의 층을 전부 분해해서, 각각의 요소가 뭐가 다른지를 판단하는 것이 가장 정확한 방법이겠다. (아 2층이 양상추면 빅맥인데, 새우인거보니까 쉬림프 버거구나....!!!)

섞인 맛은 Not Stational 하지만, 직접 분해한 재료는 Stational 할 수밖에 없지 않겠는가....!?

푸리에 변환은 한마디로 비정상적인 합쳐진 Frequency를 일정 기준으로 분해된 고정적인 Frequency 조합으로 바꾸어준다.

그러면 우리는 최종적으로 얻는 값의 형태가, 한 시간 흐름에 들어있는 음성 데이터에 대한 2개 3개의 Feature Value를 뽑아낼 수 있는 것이다. (한 주문의 햄버거에 고기가 무엇인지, 새우는 들었는지를 Feature로 가져갈 수 있게 되는 형태가 되는 것이다.!)

시간의 흐름에 따라 분해된 3개의 Feature를 가지는 진동

근데 이제 Frame이 어떤 일정 순간의 한 스크린 샷이라는건 알지만, 거기서 Feature를 분해해버리면, 다시 해당 진폭에 시간값을 가지게 하는데 어려움이 생긴다. (수백개의 햄버거에서 재료를 다 헤집어놨는데, 다시 온전한 햄버거를 만들라는 미션과 같다.)

뭐 이미 LSTM을 위한 데이터셋을 다뤄본 친구들이라면, 그깟거야 진작에 3차원으로 시간축 하나 놓으면 끝날거 아냐? 라고 생각할 수 있다. 물론 맞고, 이 방법으로 해결하는데 그 방법이 Short Time Fourier Transform이라는 방식이다.

쉽게 Frame마다 순서대로 FFT를 진행해서, 각각의 데이터를 차곡차곡 쌓아 시간축 1개를 추가하는 방식이다.

이러면 이제 우리가 흔히 아는, 3차원의 LSTM 용 Input Data와 상당히 흡사해진다.

 

Mel Filter Bank

아까 위에서 잠시 나왔지만 사람의 가청주파수라는 것이 존재한다.

이제 이만큼 데이터를 전처리했다면, 사실 그대로 학습을 시켜도 되긴 하나, 최대한 빠르고 효과적으로 학습시키기 위해서라면, 사람이 들을 수 있고, 이해할 수 있는 데이터들에 좀 더 집중해서 학습시키는 것이 좋을 것이다.

그래서 우리는 Mel Filter Bank라는 작업을 거치게 된다.

Mel Filter Bank는 사람의 청각은 1000Hz가 넘어가면 덜 민감하게 되기 때문에, 이를 기준으로 Log Scale등으로 Scaling 해버리는 방식이다. 어떻게보면 필터링을 하나 거치는 것과 다름 없으니 그렇게 부르는 것도 있다. 그리고 그냥 전체데이터를 전부다 Scaling 해버리면, 사람이 잘 듣지 못하는 주파수 대역과, 잘 듣는 주파수 대역이 동일한 조건에서 Scaling 되어버리므로, 데이터 측면에서 불합리하다고 생각할 수도 있겠다.

필터 뱅크로는 26 ~ 40개의 값을 사용하는게 일반적이라고 하며, 공식은 이러하다.

Hertz -> Mel 공식 : M(f) = 1125 ln(1 + f/700)
Mel -> Hertz 공식 : M^(-1)(m) = 700( exp(m/1125) - 1)

https://gibles-deepmind.tistory.com/50

 

왜 로그 스케일을 사용하는가?

목차 1. 지진 강도(로그 스케일 예시) 2. 왜 그래프를 그리는가? 3. 우리가 거리를 지각하는 방식 4. 지도에서 거리를 지각하는 방식 5. 로그 스케일이 더 멀리 볼 수 있는 이유 1. 지진 강도(로그 스

gibles-deepmind.tistory.com

 

그렇다면, 사실 생각해보면, 높은 주파수 대역은 굳이 볼 필요가 있을까? Scaling해서 굳이 낮춰서 동일선상에서 보는게 이득이 있을까? 이런 고민들이 생길 수 있다.

어떻게보면 Attention을 사용하면, 어짜피 낮은 주파수 대역대에 Attention Weight가 가중될 것이라고 생각할 수도 있고, 그렇다면 Filter Bank값 까지만 사용해도 충분할것 같은데....!!

하지만, 많은 음성처리에서는 MFCC를 이용하여, 높은 주파수는 그냥 날려버리고, 낮은 주파수 대역들만 상세하게 Feature로 사용하는 시도들도 많이 하고 있다.

 

MFCC (Mel Frequency Cepstral Coefficient)

https://m.blog.naver.com/mylogic/220988857132

 

Mel Frequency Cepstral Coefficient (MFCC) 란 무엇인가? - 음성 인식 알고리즘

MFCC !! 음성 인식에서 가장 널리 사용되는 알고리즘!! 음성 인식을 위하여 가장 먼저 해야할 것은 입...

blog.naver.com

MFCC는 DCT 함수를 이용하여 얻어낼 수 있는데, Cosine 함수의 합을 사용하는 방식으로, 이렇게 하면 자동으로 에너지가 시작 부분에 집중되는 현상을 만들어낼 수 있다고 한다.

그래서, 

    비교적 앞쪽인 12개의 값 + DCT 계산이 된 1개의 값

    + 그 데이터들의 1차 차분값 13개

    + 차분된 값의 2차 차분값 13개

    =  39개의 Feature

를 사용하게 된다. (참고로 차분은 Delta라고 불리며, 소스에서 비슷한 내용이 보인다면, 차분값으로 이해하면 된다.)

차분을 구하는 이유는 아무리 오버랩을 하고 했지만은, Frame 각각으로 데이터를 다루고 있기 때문Frame 안에서는 정상성을 찾으려고 노력했지만, 각각 Frame간의 시간 관계성이 뚜렷하지 않게 될 수 있다. 그래서 이런 Frame간의 정상성을 잘 고려할 수 있게 하기 위해서, 차분 데이터를 사용한다. (따지고보면, Arima에서 차분을 이용하는 이유도, 각 시간순에 대한 변화량의 정상성을 찾기 위함이 아니었던가? 나름 일리가 있다.)

 단, 차분을 사용하기 때문에, 만약 낮은 주파수 대역에 Noise가 존재한다면, 그 값이 39개의 Feature에 전부 차분되어 들어가게 되므로, 학습이 잘 안될 수도 있다는 점을 명심해야한다.

 

CMVN (Cepstral Mean Variance Normalization)

하지만, 이런 Noise를 강인하게 하려면 우리는 통상 무엇을 하는가? Scaling을 하지 않는가!

음성 데이터에서도 Scaling하는 방식들이 여러가지 제안되는데, 그 중 하나인 CMVN에 대해서 알아보겠다.

Cepstral Mean Variance Normalization으로, 한마디로 평균-분산 정규화다. 그냥 Standard Scaler와 거의 똑같다. 실제로 소스를 까봐도 그렇다.

뭐 외에도 CMN, CMSN, HE 등등 존재한데, 엥간한 통계적 정규화 방식은 전부 채용 가능하지 않을까 싶다.

다만 거의 대부분의 스케일링이 그런게, 평균이나 분산을 사용한다면, 데이터의 양이 너무 적은경우, 제대로 평균과 분산이 계산되지 못해서, 정규화로 손실이 더 커질 수도 있으니, 사용할때 잘 고려해서 써야하겠다.

 

우리는 지금까지 달려온 과정을 통해, 음성데이터를 시계열로 쪼개고, 시계열 속에서 정상성을 찾고, Feature로 사용하기 위한 Set를 구성하는 과정을 거쳤다. 마치 Stage처럼, 한단계 한단계 진행되면서, 최종적으론 Scaling까지 진행하게 되는데, 사실 Feature 데이터는 학습 Layer를 어떻게 구성할거냐에 따라서, 꼭 MFCC를 쓰란 법도 없으며, CMVN도 선택이고, Filter Bank 이전의 값을 쓰는것도 상황에 따라 고려해볼 수 있다. (물론 잘되리란 보장은 없겠지만.)

이 때문에, Kaldi에서 여러가지 C 라이브러리를 제공해주지만, Shell Script는 생각해보고 본인들의 상황에 맞는 스크립트를 작성해야한다고 한 점이 그렇다. 선택과 분기점이 많기 때문이었다.

 

개인적인 생각으로는 MFCC를 사용한다면, 저주파 대역만을 사용하니까, 어조라거나, 악센트라거나 하는 것들이 학습이 잘 안될 것 같다. 하지만, 데이터를 꼭 봐야할 부분만 보기 때문에, 표준어 기준으로는 정확도는 좀 더 높아지지 않을까 싶기도 하다.

그 이전 값들을 쓴다면(Filter Bank 등), 상황에 따라 다르겠지만, Deep Learning Layer에 학습에 맡겨놓은채로, 전체 데이터를 골고루 볼테니, 오히려 성별이나 어조 악센트에 따라서도 학습이 되는 모델이 되지 않을까 생각한다. (마치 여자가 얘기하는 발음과 애기가 얘기하는 발음과 남자가 얘기하는 발음이 각각 특색있게 학습되지 싶다.) (실험해보지는 않았다.)

 

아 그리고, 이전시간에 specaug에 대한 이야기도 했었는데, 논문을 정독해보진 않았지만, 마치 CNN에서 노이즈가 조금 들어가도 학습이 잘 되는 것을 이용하여, 데이터를 증강하듯이, 음성데이터에서도 시계열에 따른 노이즈나, 특정 주파수 대역에서의 노이즈를 주어서 증강해도, 학습이 잘 된다는 것을 이야기하는 바였다. https://arxiv.org/pdf/1904.08779.pdf

 

그리고 진행하면서 알게되었는데 Kaldi말고도 HTK라는 툴킷도 존재한다는 것 같다.(이미 우리나라에서는 Kaldi가 대세인것 같지만.ㅋㅋ)

 

이쯤하면, 어느정도 음성처리에 대한 도메인 정리도 다 된 것 같다.

시계열 데이터와 비슷한 맥락으로 흘러간다는 점에서, LSTM을 사용해볼 수도 있지만, 마치 OCR을 진행하듯 CNN+LSTM을 사용하려는 시도도 보인 것 같고, 실제로 이전시간 소스를 확인해보면 유의미했으니 만들어서 넣어두지 않았을까 싶다.

또한 자연어와 같은 제한된 벡터에서의 연관관계로 찾는 부분들도 있다보니 Attention이 한 몫 했겠지, 그래서 이런 다양한 Layer들도 선택가능한 것 같으며, 그 때때에 맞춰서 데이터도 어느 수준까지 전처리하고 정규화하여 활용할지 고민해볼 가치가 충분한 부분인 것 같다.

 

아 그리고 또한, 아까 Frame 얘기할때 나왔던 말이지만, 음성데이터를 어느 수준으로 잘라서, 음성인식에 활용하고 학습할거냐도 분명히 고민해봐야할 문제다. (Frame 말고 실제로)

 

레퍼런스를 찾아보니, 오히려 음성을 인식하는 것보다, 어느정도 길이를 효과적으로 잘라내는가에 대한 레퍼런스가 더 없고, 실제로 고민도 많이 되는 것 같다. 실제로 음성에 사용되는 특정 조건부만큼을 잘라내는 모델이라도 만들어야 하는 것일까? (무조건 한마디로 자른다던가, 질문과 답변 세트로 자른다던가, 화자에 대한 고민들, 다양한 자르는 방법들이 선택 수반되어야 할 것인데....)

 

이런 고민들을 이어서 다음시간에는 Inference 부분을 같이 들여다보도록 하겠다. 오히려 STT를 보다가, 다른 음향처리 모델 레퍼런스를 더 고민해보게 된 시간이 되어가게 된다....

728x90

댓글