728x90

음성 인식 테스크에서 pcm 파일을 direct로 읽어야 할 때가 있는데, 이 때 두 가지의 코드를 주로 사용한다.

 

오늘은 이에 대해 생각 정리 겸 실험 내용을 저장하기 위해 작성한다.

 

1. numpy memmap으로 읽을 경우

 

이 때에는, 읽은 pcm 파일을 그대로 저장하게 되면 음성의 magnitude가 굉장히 크기 때문에 max value인 32767로 나눠주어야 한다.

 

signal = np.memmap(sample_data, dtype='h', mode='r').astype('float32')

signal = signal / 32767

 

2. numpy frombuffer + librosa로 읽을 경우

 

1번과는 다르게 따로 나눠줄 필요는 없다.

 

with open(sample_data, 'rb') as opened_pcm_file:
    buf = opened_pcm_file.read()
    pcm_data = np.frombuffer(buf, dtype = 'int16')
    wav_data = librosa.util.buf_to_float(pcm_data, 2)

 

3. 음질 결과 비교 

 

1번:

method1_16000.wav
0.07MB

 

2번: 

method2_16000.wav
0.07MB

 

 

1번의 32767로 normalized 한 파일과 2번 방식으로 읽은 파일은 서로 데이터의 크기가 같다.

 

4. 변환 속도 비교

1번과 2번의 시간 비교는 아래와 같다.

2번이 약 2배 이상 빠른것을 알 수 있다.

 

 

5. 결론

두 방법 모두 가능하지만, 대규모 데이터셋을 처리하기 위해서는 2번 방법을 사용하는 것이 좋을 것 같다.

 

예를 들어 KoSpeech 같은 경우 각 음성 파일의 길이 비교 없이 training set 62만개에 대해서 10에폭을 돌린다고 하면

 

1번 방법: 620,000 * 10 * 0.00054 = 3,348 = 0.93시간

2번 방법: 620,000 * 10 * 0.00026 = 1,612 = 0.44시간

 

의 차이가 data loading 할 때 발생한다.

 

 

전체 코드

 

import soundfile as sf
import os
import numpy as np
import time

sample_data = './45.pcm'
data_dir = './check_pcm/'

start = time.time()
signal = np.memmap(sample_data, dtype='h', mode='r').astype('float32')
print(signal.shape)

signal = signal / 32767
print('method1 takes {}'.format(time.time() - start))


sf.write(os.path.join(data_dir, 'method1_16000.wav'), signal, 16000, format='WAV', endian='LITTLE', subtype='PCM_16')

import librosa
start = time.time()
with open(sample_data, 'rb') as opened_pcm_file:
    buf = opened_pcm_file.read()
    pcm_data = np.frombuffer(buf, dtype = 'int16')
    wav_data = librosa.util.buf_to_float(pcm_data, 2)
print('method2 takes {}'.format(time.time() - start))    

sf.write(os.path.join(data_dir, 'method2_16000.wav'), wav_data, 16000, format='WAV', endian='LITTLE', subtype='PCM_16')

 

 

pcm 파일의 sampling rate는 어떻게 구할 수 있을까? 다음번에는 이 문제와 관련된 issue 정리해보기

728x90

+ Recent posts