librosa能量_语音MFCC提取:librosa amp;amp; python_speech_feature(2019.12)
最近在閱讀語(yǔ)音方向的論文,其中有個(gè)被提及很多的語(yǔ)音信號(hào)特征MFCC(Mel-Frequency Cepstral Coefficients),找到了基于python的語(yǔ)音庫(kù)librosa(version=0.7.1)和python_speech_features(version=0.6),下文對(duì)這兩個(gè)庫(kù)計(jì)算MFCC的流程細(xì)節(jié)稍作梳理。
LibROSA - librosa 0.7.1 documentation?librosa.github.iopython_speech_features?pypi.org一、librosa
1.源語(yǔ)音信號(hào),shape = wav.length
wav, sample_rate = librosa.load(path, sr=22050, mono=True, offset=0.0, duration=None,dtype=np.float32, res_type='kaiser_best') #加載語(yǔ)音文件得到原始數(shù)據(jù)2.填充及分幀(無(wú)預(yù)加重處理),分幀后所有幀的shape = n_ftt * n_frames
y = numpy.pad(array, pad_width, mode, **kwargs) # 原函數(shù)及參數(shù) y = numpy.pad(wav, int(n_fft // 2), mode='reflect') # 默認(rèn),n_fft 為傅里葉變換維度 y = numpy.pad(wav, (0,pad_need), mode='constant') # 自定義librosa調(diào)用numpy對(duì)源語(yǔ)音數(shù)據(jù)進(jìn)行填充,默認(rèn)模式是'reflect'進(jìn)行鏡像填充,舉個(gè)例子:
對(duì)序列[1,2,3,4,5]進(jìn)行左填充2個(gè)、右填充3個(gè),左邊以1作對(duì)稱軸填充[3,2],右邊以5作對(duì)稱軸填充[4,3,2],最后結(jié)果為[3,2,1,2,3,4,5,4,3,2]。
自定義模式是按照python_speech_features的方式設(shè)置參數(shù)的,pad_need是經(jīng)過(guò)計(jì)算得到的需要填充的數(shù)據(jù)數(shù)量,在下文說(shuō)明。
y_frames = util.frame(y, frame_length=n_fft, hop_length=hop_length) # hop_length為幀移,librosa中默認(rèn)取窗長(zhǎng)的四分之一一般來(lái)說(shuō) 幀長(zhǎng) = 窗長(zhǎng) = 傅里葉變換維度,否則要進(jìn)行填充或者截?cái)嗵幚?。通過(guò)閱讀源碼發(fā)現(xiàn),librosa調(diào)用的分幀方式和python_speech_features一樣,這和librosa.feature.melspectrogram()參數(shù)里的center描述有所沖突,我把兩者對(duì)同一語(yǔ)音文件的分幀結(jié)果輸出到excel文件進(jìn)行了對(duì)比,結(jié)果是一樣的,當(dāng)然分幀之前的填充方式也修改成了一致。
3.對(duì)所有幀進(jìn)行加窗,shape = n_ftt * n_frames。librosa中window.shape = n_ftt * 1
fft_window = librosa.filters.get_window(window, Nx, fftbins=True) # 原函數(shù)及參數(shù) fft_window = get_window('hann', win_length, fftbins=True) # 窗長(zhǎng)一般等于傅里葉變換維度,短則填充長(zhǎng)則截?cái)?p>librosa加的窗函數(shù)調(diào)用的scipy,如scipy.signal.windows.hann。python_speech_features加的窗函數(shù)調(diào)用的numpy,如numpy.hanning,漢寧窗公式為:給原信號(hào)加窗的實(shí)現(xiàn)方式為相乘:
frames *= 0.5 - 0.5 * numpy.cos((2 * numpy.pi * n) / (frame_length - 1)) # 原信號(hào)乘以漢寧窗函數(shù)4.STFT處理得到spectrum(頻譜,實(shí)際是多幀的),shape = (n_ftt // 2 +1) * n_frames
fft = librosa.core.fft.get_fftlib() stft_matrix = fft.rfft(fft_window * frames)librosa和python_speech_features都是調(diào)用的numpy進(jìn)行傅里葉變換,numpy.fft.rfft(frames,NFFT)。
5.取絕對(duì)值得到magnitude spectrum/spectrogram(聲譜,包含時(shí)間維度,即多幀),shape = (n_ftt // 2 +1) * n_frames
magnitude_spectrum = numpy.abs(stft_matrix) # 承接上一步的STFT magnitude_spectrum = numpy.abs(librosa.core.spectrum.stft(wav, n_fft=n_fft, hop_length=hop_length,win_length=win_length, center=center,window=window, pad_mode=pad_mode))**power # librosa封裝的計(jì)算magnitude spectrum函數(shù),power參數(shù)默認(rèn)為1.06.取平方得到power spectrum/spectrogram(聲譜,包含時(shí)間維度,即多幀),shape = (n_ftt // 2 +1) * n_frames
power_spectrum = numpy.square(magnitude_spectrum) # 承接上一步的magnitude_spectrum power_spectrum = numpy.abs(librosa.core.spectrum.stft(wav, n_fft=n_fft, hop_length=hop_length,win_length=win_length, center=center,window=window, pad_mode=pad_mode))**power # librosa封裝的計(jì)算power spectrum函數(shù),power參數(shù)設(shè)置為2.07.構(gòu)造梅爾濾波器組,shape = n_mels * (n_ftt // 2 +1)
mel_basis = librosa.filters.mel(sr, n_fft, n_mels=128, fmin=0.0, fmax=None, htk=False,norm=1, dtype=np.float32) # 原函數(shù)及參數(shù)librosa和python_speech_features構(gòu)造mel_filtersbank的方式不同,librosa構(gòu)造細(xì)節(jié)尚未掌握。
8.矩陣乘法得到mel_spectrogram,shape = n_mels * n_frames
mel_spectrogram = numpy.dot(mel_basis, power_spectrum)[ n_mels ,(n_ftt // 2 +1) ] * [ (n_ftt // 2 +1) ,n_frames ] = [ n_mels,n_frames]
9.對(duì)mel_spectrogram進(jìn)行l(wèi)og變換,shape = n_mels * n_frames
log_mel_spectrogram = librosa.core.spectrum.power_to_db(mel_spectrogram, ref=1.0, amin=1e-10, top_db=80.0)S_db ~= 10 * log10(S) - 10 * log10(ref)
librosa采用以上方式計(jì)算log映射,python_speech_features定義mfcc( )函數(shù)時(shí)直接取自然常數(shù)e為底的對(duì)數(shù)。
10.IFFT變換,實(shí)際采用DCT得到MFCC,shape = n_mels * n_frames
mfcc = scipy.fftpack.dct(log_mel_spectrogram, type=2, n=None, axis=0, norm=None, overwrite_x=False) # n表示計(jì)算維度,需與log_mel_spectrogram.shape[axis]相同,否則作填充或者截?cái)嗵幚怼xis=0表示沿著自上而下的方向,分別選取每一行所在同一列的元素進(jìn)行運(yùn)算。與python_speech_features相同,librosa也是調(diào)用scipy對(duì)log_mel_spectrogram進(jìn)行離散余弦變換:scipy.fftpack.dct()。
11.取MFCC矩陣的低維(低頻)部分,shape = n_mfcc * n_frames
mfcc = mfcc[ :n_mfcc] # 取低頻維度上的部分值輸出,語(yǔ)音能量大多集中在低頻域,數(shù)值一般取13。二、python_speech_features
1.源語(yǔ)音信號(hào),shape = wav.length
sample_rate,signal = scipy.io.wavfile.read(filename, mmap=False) # scipy加載語(yǔ)音文件 signal, sample_rate = librosa.load(path, sr=22050, mono=True, offset=0.0, duration=None,dtype=np.float32, res_type='kaiser_best') # librosa加載語(yǔ)音文件2.預(yù)加重,shape = wav.length
signal = numpy.append(signal[0],signal[1:] - coeff * signal[:-1])語(yǔ)音信號(hào)的預(yù)加重,目的是為了對(duì)語(yǔ)音的高頻部分進(jìn)行加重,去除口唇輻射的影響,增加語(yǔ)音的高頻部分的分辨率和信噪比,計(jì)算方式為:y(n))=x(n)-a*x(n-1),系數(shù)a一般取0.97。
3.分幀和加窗,shape = n_frames * n_ftt
frames = python_speech_features.sigproc.framesig(signal,frame_len,frame_step,winfunc=lambda x:numpy.ones((x,))) # 分幀及加窗函數(shù)python_speech_features中默認(rèn)幀長(zhǎng)取25ms、幀移10ms,對(duì)應(yīng)實(shí)際的采樣點(diǎn)為:
幀長(zhǎng)點(diǎn)數(shù) = 幀長(zhǎng)時(shí)間 * 采樣率 ,幀移點(diǎn)數(shù) = 幀移時(shí)間 * 采樣率
numframes = 1 + int(math.ceil((1.0*slen - frame_len)/frame_step)) # 計(jì)算總分幀數(shù)總分幀數(shù)量 = 1 + 向上取整( ( 原信號(hào)長(zhǎng)度 - 幀長(zhǎng)點(diǎn)數(shù) ) / 幀移點(diǎn)數(shù) )
padlen = int((numframes-1)*frame_step + frame_len) # 計(jì)算待填充點(diǎn)的數(shù)量 zeros = numpy.zeros((padlen - slen,)) # 在原數(shù)據(jù)末尾進(jìn)行零填充待填充點(diǎn)數(shù) = ( 總分幀數(shù)量 - 1 ) * 幀移點(diǎn)數(shù) + 幀長(zhǎng)點(diǎn)數(shù)
這種填充方式和上面librosa的自定義的那種填充方式( y = numpy.pad(wav, (0,pad_need), mode='constant') )效果是一樣的,可以看出librosa庫(kù)的功能還是更加多樣化的。
加窗的話,python_speech_features默認(rèn)不加窗,但提供了調(diào)用numpy中窗函數(shù)的參數(shù)接口,經(jīng)測(cè)試numpy.hanning窗函數(shù)和scipy.signal.windows.hann窗函數(shù)的數(shù)值是一致的,只不過(guò)前者為矩陣形式(元素相同的多個(gè)向量構(gòu)成),后者為向量形式。
mfcc = python_speech_features.base.mfcc(signal,samplerate=16000,winlen=0.025,winstep=0.01,numcep=13,nfilt=26,nfft=512,lowfreq=0,highfreq=None,preemph=0.97,ceplifter=22,appendEnergy=True,winfunc=lambda x:numpy.ones((x,))) # winfunc參數(shù)即為窗函數(shù)接口,例如 winfunc=numpy.hanning4.STFT處理得到spectrum(頻譜,實(shí)際是多幀的),shape = n_frames * (n_ftt // 2 +1)
complex_spec = numpy.fft.rfft(frames,n_fft) # 離散傅里葉變換得到頻譜圖和librosa一致,python_speech_features也是調(diào)用numpy下的函數(shù)做離散傅里葉變換。
5.取絕對(duì)值得到magnitude spectrum/spectrogram(聲譜,包含時(shí)間維度,即多幀),shape = n_frames * (n_ftt // 2 +1)
mag_spec = numpy.absolute(complex_spec) # 承接上一步取絕對(duì)值得到幅度譜6.取平方得到power spectrum/spectrogram(聲譜,包含時(shí)間維度,即多幀),shape = n_frames * (n_ftt // 2 +1)
power_spec = 1.0 / n_fft * numpy.square(mag_spec) # 承接上一步取平方得到功率譜python_speech_features計(jì)算功率譜的方式和libraosa不一致,這里額外除以了傅里葉變換的維度n_fft。
7.構(gòu)造梅爾濾波器組,shape = n_mels * (n_ftt // 2 +1)
fb = python_speech_features.base.get_filterbanks(nfilt=20,nfft=512,samplerate=16000,lowfreq=0,highfreq=None)關(guān)于梅爾濾波器的構(gòu)造細(xì)節(jié),參考了這篇文章的部分介紹。具體細(xì)節(jié)如下:
赫茲轉(zhuǎn)梅爾:mel = 2595 * log10( 1+ hz / 700. )
梅爾轉(zhuǎn)赫茲:hz = 700 * ( 10** ( mel / 2595.0 ) - 1 )
(1)假設(shè)構(gòu)造n_mels=10個(gè)梅爾濾波器,建立坐標(biāo)系縱坐標(biāo)表示mel刻度、橫坐標(biāo)表示Hz刻度
(2)橫坐標(biāo)(頻率)設(shè)置最低值300hz、最高值8000hz(采樣率的二分之一),對(duì)應(yīng)的縱坐標(biāo)的最低和最高值分別為401.97mel和2840.02mel。
(3)把縱坐標(biāo)從低到高劃分為12(10+2)個(gè)離散的點(diǎn)melpoints = [ 401.97, 623.61,845.25,1066.89,1288.54,1510.18, 1731.82,1953.46, 2175.10,2396.74,2618.38,2840.02] ,這些點(diǎn)映射回橫坐標(biāo)上分別為[ 300,517.34,781.91,1103.98,1496.06,
1973.34,2554.36,3261.65,4122.66,5170.80,6446.75, 8000. ]。
(4)上面橫坐標(biāo)這12(0-11)個(gè)點(diǎn)正好對(duì)應(yīng)10個(gè)三角濾波器的三個(gè)點(diǎn):例如0、1、2分別對(duì)應(yīng)第一個(gè)濾波器的左底點(diǎn)、頂點(diǎn)、右底點(diǎn),1、2、3對(duì)應(yīng)第二個(gè)濾波器,以此類推第十個(gè)濾波器對(duì)應(yīng)9、10、11。這十個(gè)三角濾波器的函數(shù)解析式如下:
(5)對(duì)信號(hào)的濾波處理本質(zhì)上是乘法運(yùn)算,由于待濾波的spectrogram實(shí)際是離散的數(shù)據(jù),所以要對(duì)連續(xù)的濾波器函數(shù)進(jìn)行離散的采樣,從源代碼來(lái)看python_speech_features和librosa的采樣方式是不同的,經(jīng)測(cè)試發(fā)現(xiàn)兩者所構(gòu)造的梅爾濾波器數(shù)據(jù)確實(shí)不一樣。
(6)拿第一個(gè)濾波器舉例來(lái)說(shuō),其橫坐標(biāo)的采樣點(diǎn)選擇是根據(jù)經(jīng)傅里葉變換后的spectrogram維度確定的:
bin = numpy.floor( ( n_fft + 1 ) * mel2hz( melpoints ) / samplerate ) # 例子中n_fft取值512,samplerate取值16000 # 構(gòu)造梅爾采樣容器,實(shí)際上就是把原橫坐標(biāo)"samplerate/2"上的12個(gè)離散點(diǎn)映射到新橫坐標(biāo)"(n_ftt+1)/2"上面,這樣做保證了后面的乘法運(yùn)算維度一致。 # bin = [ 9. 16. 25. 35. 47. 63. 81. 104. 132. 165. 206. 256.],例子中n_fft取值512經(jīng)過(guò)以上映射后,第一個(gè)濾波器的函數(shù)表達(dá)式就確定了:在[9,16)區(qū)間為y=(x-9)/(16-9),在[16,25]區(qū)間為y=(25-x)/(25-16),其余點(diǎn)y取值為0。在這個(gè)濾波器的257(0-256)個(gè)離散點(diǎn)中,沿著三角形左邊y值逐漸遞增,在頂點(diǎn)處達(dá)到最大值"1",然后順著右邊y值逐漸遞減到0,其余部分點(diǎn)對(duì)應(yīng)的縱坐標(biāo)取值都為0。
(7)例子中(n_mel=10,n_fft=512,samplerate=16000)構(gòu)造的梅爾濾波器矩陣具體數(shù)值如下(作了轉(zhuǎn)置處理):
8.矩陣乘法得到mel_spectrogram,shape = n_frames * n_mels
mel_spectrogram = numpy.dot(power_spec,fb.T)[ n_frames ,(n_ftt // 2 +1) ] * [ (n_ftt // 2 +1) ,n_mels ] = [ n_frames,n_mels]
mel_spectrogram矩陣中的每個(gè)元素其實(shí)就是每一幀spectrogram向量和每個(gè)濾波器向量的內(nèi)積。mel_spectrogram(0,1)即為第1幀的spectrogram同第2個(gè)三角濾波器內(nèi)積運(yùn)算的結(jié)果。
9.對(duì)mel_spectrogram進(jìn)行l(wèi)og變換,shape = n_frames * n_mels
log_mel_spectrogram = numpy.log(mel_spectrogram) log_mel_spectrogram = python_speech_features.sigproc.logpowspec(frames,n_ftt,norm=1)python_speech_features.base.mfcc( )函數(shù)默認(rèn)取以自然常數(shù)e為底的對(duì)數(shù),作者還提供了另一種取對(duì)數(shù)域的接口python_speech_features.sigproc.logpowspec( ),計(jì)算方式與librosa略有差異:log_S = 10 * log10(S)
10.IFFT變換,實(shí)際采用DCT得到MFCC,shape = n_frames * n_mels
mfcc = scipy.fftpack.dct(log_mel_spectrogram, type=2, n=None, axis=0, norm=None, overwrite_x=False) # n表示計(jì)算維度,需與log_mel_spectrogram.shape[axis]相同,否則作填充或者截?cái)嗵幚?。axis=0表示自上而下方向分別選取每一行所在同一列的元素進(jìn)行計(jì)算。11.取MFCC矩陣的低維(低頻)部分,shape = n_frames * n_mfcc
mfcc = mfcc[:,:n_mfcc] # 取低頻維度上的部分值輸出,語(yǔ)音能量大多集中在低頻域,數(shù)值一般取13。python_speech_features.base.mfcc(appendEnergy=True )函數(shù)中,appendEnergy參數(shù)控制是否把MFCC的第一個(gè)倒譜系數(shù)替換為每一幀總能量的對(duì)數(shù),每一幀總能量的計(jì)算方式為:
energy = numpy.sum(power_spec,axis=1) # axis=1表示沿著從左到右的方向,分別選取每一列所在同一行的元素進(jìn)行運(yùn)算。12.倒譜提升,shape = n_frames * n_mfcc
mfcc = python_speech_features.base.lifter(cepstra=mfcc, L=22)倒譜提升系數(shù)默認(rèn)設(shè)置為22,具體實(shí)現(xiàn)方式為:
nframes,ncoeff = numpy.shape(cepstra) # ncoeff=n_mfcc n = numpy.arange(ncoeff) # n=0,1,2...n_mfcc-1 lift = 1 + (L / 2.) * numpy.sin(numpy.pi * n / L) # lift.shape = n_mfcc * 1 return lift * cepstra # shape = n_frames * n_mfcc13.微分:mfcc的動(dòng)態(tài)特征提取,shape = n_frames * n_mfcc
mfcc_delta_1 = python_speech_features.base.delta(feat=mfcc, N=1) # 計(jì)算mfcc的一階微分 mfcc_delta_2 = python_speech_features.base.delta(feat=mfcc, N=2) # 計(jì)算mfcc的二階微分有時(shí)會(huì)把MFCC的基礎(chǔ)特征同其一階、二階微分?jǐn)?shù)據(jù)結(jié)合起來(lái)使用,以做到特征層面的動(dòng)靜結(jié)合。
總結(jié)
以上是生活随笔為你收集整理的librosa能量_语音MFCC提取:librosa amp;amp; python_speech_feature(2019.12)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 短视频不得未经授权剪辑影视剧!3分钟看完
- 下一篇: python二维列表写入excel_用P