Python

[Python/파이썬] 목소리와 음악을 구분하자 - 2편(with Resnet)

F12:) 2023. 8. 1. 20:23

안녕하세요. 오늘은 이전 글인 목소리와 음악을 구분하자 1편에 이어 2편을 시작하겠습니다. 이전 글을 보고 오시지 않으셨으면, 아래의 글을 통해 읽고 오시면 되겠습니다.

 

2023.07.25 - [Python] - [Python/파이썬] 목소리와 음악을 구분하자 - 1편(with Spleeter)

 

[Python/파이썬] 목소리와 음악을 구분하자 - 1편(with Spleeter)

오늘은 음성데이터에서 존재하는 음악과 목소리를 분류하는 작업을 진행하려 합니다. 이를 위해서 저는 두 가지 방법을 거쳐 진행하였습니다. Spleeter를 통해서 음성 데이터의 mr을 진행했습니다

studyblog4244.tistory.com


1. 목소리 출현 구간 탐색

멘트인 구간을 찾기 위해서 우리는 먼저 멘트가 아닌 컨텐츠의 구간을 확실하게 할 필요가 있습니다. 이 말은, 멘트가 출현하는 구간을 확실하게 하는 말과 같으니 말이죠.

 

따라서 저희는, MR을 제거한 음성을 가지고 목소리가 출현하는 구간만을 판단합니다. 이렇게 되면 실제로 목소리가 들려지는 시점을 찾게 됩니다. 또한 목소리가 사라지는 시점마다 구간을 나눠서 음성 컨텐츠(멘트, 노래, 광고)가 혼합되지 않도록 해줍니다.

 

그래서 우리는 음성 데이터 전체의 MR을 제거해줍니다. 제거하는 방법은 1편에서 소개한 spleeter 라이브러리를 이용합니다.

 

 

2. 멘트 구간 파악

우리는 목소리 출현 구간을 찾았습니다. 이제 우리가 해야할 것은 그 목소리 구간에서 노래와 광고를 not_ment 즉, 멘트가 아닌 것으로 분류하고 멘트는 멘트라고 분류하는 작업을 해야합니다.

 

여기서 우리는 CNN 모델을 적용하려고 합니다. 음성 데이터를 주파수 영역으로 바꿔주는 STFT(Short-Time Fourier Transformation)을 통해 노래와 멘트일 때를 비교해보겠습니다.

 

stft 기법에 대한 설명은 생략하겠습니다.

 

멘트를 stft한 결과

 

노래를 stft한 결과

 

차이점이 보이시나요?? 이러한 이유는 노래의 특성 때문입니다. 노래는 일반적인 발화할 때의 주파수보다 훨씬 고역대를 갖습니다.(이는 높은 음의 단위시간당 진동 횟수가 더 높기 때문입니다.) 스펙트로그램을 통해서 확인해봐도 확실히 알 수 있습니다.

 

멘트의 Mel-Spectrum
노래의 Mel-Spectrum

 

보이시는 것처럼 노래의 데이터는 낮은 음역대의 빈도가 낮습니다. 이러한 차이를 이용해서 우리는 멘트와 멘트가 아닌 것을 분류하려고 시도했습니다.

 

초기에 모델을 직접 구축하였지만, CNN의 pretrain모델 중 하나인 resNet을 사용해보기로 했습니다.

어느 논문에서는 resnet이 음성데이터의 이미지를 구분하는데 효과적이라고 쓴 것을 본 적이 있었습니다.

 

 

저는 resNet18을 사용했고, 이 모델은 (244, 244, 3)의 이미지 사이르를 요구하므로, stft의 결과를 그대로 복제하여 3개로 만들고, Image 라이브러리의 zoom 함수를 사용하여 이미지를 resize 해주었습니다.

 

훈련데이터는 임의로 생성한 데이터를 통해서 batch_size = 32, epoch은 30으로 진행했습니다. (epoch은 20만으로도 충분해보였습니다.)

 

저는 Apple Silicon M2를 사용하므로 cpu로 돌리느라 8시간정도 소요됐던 것 같습니다. 이 점 참고하셔서, gpu를 사용하시는 것을 권장드립니다.. 특히 sota 모델이라면 꼭...


3. 결론

결과는 나름 좋았습니다. 많은 데이터들 사이에서 노래와 멘트를 훌륭히 구분하였습니다. 다만 아쉬운 점은, 너무나도 완벽한 구분 탓에 광고에서 멘트로만 광고하는 부분을 멘트라고 인식하는 것이 아쉬웠습니다.

 

이 부분은 추후, 앞뒤를 고려하거나 stt를 통한 테스트로 분류하는 기법을 선정하여 강화할 계획입니다.

 


4. 마치며

이 기능을 구현하면서 찝찝했던 부분은, resnet의 채널 2개를 단순히 복사하여 훈련하였다는 것입니다. 이러한 행위가 쓸데없다고 느낀 저는 음성의 특징을 추출하는 많은 기법 중 세가지를 추출하여 다른 채널들을 넣어주어, 조금 더 멘트를 잘 분류할 수 있도록 하려고 합니다.

 

정리하자면, 채널 3개에서 1개의 값을 복사하여주는 것이 아닌, 의미있는 3개의 채널을 input으로 넣어보려고 합니다.

 

 

이상입니다.

코드 및 위 글에 대해 궁금한 사항은 언제든지 질문해주시면 감사하겠습니다!