asr學習系列(二:特征提?。?/h2>

背景:

報了深藍學院的語音識別課程,這里做學習記錄

第二課:語音信號處理-->特征提取

1.數(shù)字信號處理

  • 1)傅立葉變換

2.常用特征提取

  • 1)Fbank特征一般用于DNN訓練
  • 2)MFCC特征一般用于對角GMM訓練,各維度之間相關性小
Step1.預加重(pre-emphasis)

? 為什么需要預加重?

提高信號高頻部分的能量,高頻信號在傳遞過程中,衰減較快,
但是高頻部分又蘊含很多對語音識別有利的特征,
因此,在特征提取部分,需要提高高頻部分能量

預加重濾波器是一個一階高通濾波器,給定時域輸入信號??[??],預加重之后的信號為:
?? [??] = ??[??] ? ????[?? ? 1]

import librosa
import numpy as np
from scipy.fftpack import dct

#preemphasis config 
alpha = 0.97

# Enframe config
frame_len = 400      # 25ms, fs=16kHz
frame_shift = 160    # 10ms, fs=15kHz
fft_len = 512

# Mel filter config
num_filter = 23
num_mfcc = 12

# Read wav file
wav, fs = librosa.load('./test.wav', sr=None)

def preemphasis(signal, coeff=alpha):
    """perform preemphasis on the input signal.

        :param signal: The signal to filter.
        :param coeff: The preemphasis coefficient. 0 is no filter, default is 0.97.
        :returns: the filtered signal.
    """
    return np.append(signal[0], signal[1:] - coeff * signal[:-1])
Step2.加窗(windowing)分幀
  • 為什么需要分幀?

語音信號為非平穩(wěn)信號,其統(tǒng)計屬性是隨著時間變化的,以漢語為例,一句話中包含很多聲母和韻母,不同的拼音,發(fā)音的特點很明顯是不一樣的;

  • 但是!語音信號又具有短時平穩(wěn)的屬性,比如漢語里一個聲母或者韻母,往往只會持續(xù)幾十到幾百毫秒,在這一個發(fā)音單元里,語音信號表現(xiàn)出明顯的穩(wěn)定性,規(guī)律性(可以自己使用Audition觀察一段語音)
    ?在進行語音識別的時候,對于一句話,識別的過程也是以較小的發(fā)音單元(音素、字、字節(jié))為單位進行識別,因此用滑動窗來提取短時片段,

? 幀長、幀移、窗函數(shù)的概念,對于采樣率為16kHz的信號,幀長、幀移一般為25ms、10ms,即400和160個采樣點

def enframe(signal, frame_len=frame_len, frame_shift=frame_shift, win=np.hamming(frame_len)):
    """Enframe with Hamming widow function.

        :param signal: The signal be enframed
        :param win: window function, default Hamming
        :returns: the enframed signal, num_frames by frame_len array
    """
    
    num_samples = signal.size
    num_frames = np.floor((num_samples - frame_len) / frame_shift)+1
    frames = np.zeros((int(num_frames),frame_len))
    for i in range(int(num_frames)):
        frames[i,:] = signal[i*frame_shift:i*frame_shift + frame_len] 
        frames[i,:] = frames[i,:] * win

    return frames
Step3.傅里葉變換
  • 將上一步分幀之后的語音幀,由時域變換到頻域,取DFT系數(shù)的模,得到譜特征
def get_spectrum(frames, fft_len=fft_len):
    """Get spectrum using fft
        :param frames: the enframed signal, num_frames by frame_len array
        :param fft_len: FFT length, default 512
        :returns: spectrum, a num_frames by fft_len/2+1 array (real)
    """
    cFFT = np.fft.fft(frames, n=fft_len)
    valid_len = int(fft_len / 2 ) + 1
    spectrum = np.abs(cFFT[:,0:valid_len])
    return spectrum
Step4.梅爾濾波器組和對數(shù)操作

? DFT得到了每個頻帶上信號的能量,但是人耳對頻率的感知不是等間隔的,近似于對數(shù)函數(shù)
? 將線性頻率轉換為梅爾頻率,梅爾頻率和線性頻率轉換關系

mel(f) = 2595 * log(1 + f /700)

? 梅爾三角濾波器組:根據(jù)起始頻率、中間頻率和截止頻率,確定各濾波器系數(shù)


三角濾波圖示(采樣率為16k,對應的fbank的濾波外形)

filter_bank_m(k) = [ k - f(m-1) ] / [ f(m) - f(m-1)] , f(m-1) < k < f(m)
filter_bank_m(k) = [ f(m+1) - k] / [ f(m) - f(m-1)] , f(m) < k < f(m+1)


def fbank(spectrum, num_filter = num_filter):
    """Get mel filter bank feature from spectrum
        :param spectrum: a num_frames by fft_len/2+1 array(real)
        :param num_filter: mel filters number, default 23
        :returns: fbank feature, a num_frames by num_filter array 
        DON'T FORGET LOG OPRETION AFTER MEL FILTER!
    """

    feats=np.zeros((spectrum.shape[0], num_filter))
    freq_h = fs // 2 # 最大截止頻率
    mel_h = f_mel(freq_h) # 最大梅爾刻度
    mel_lst = np.linspace(0, mel_h, num_filter+2) # mel刻度等間隔
    freq_lst = mel_f(mel_lst) # mel對應的頻率
    fft_mel = np.floor((fft_len + 1) * freq_lst / fs) # mel對應fft的位置
    
    bank = np.zeros((num_filter, int(fft_len//2)+1))
    for i in range(1, num_filter+1):
        left = int(fft_mel[i-1]) # 三角波左側
        center = int(fft_mel[i]) # 三角波頂點
        right = int(fft_mel[i+1]) # 三角波右側
        for j in range(left, center):
            bank[i-1, j] = (j - left) / (center -left)
        for j in range(center, right):
            bank[i-1, j] = (right - j) / (right - center)

    feats = np.dot(spectrum, bank.T) # 頻譜與濾波器點乘
    feats = np.where(feats == 0, np.finfo(float).eps, feats) # 避免log(0)
    return np.log(feats)
Step5.動態(tài)特征計算
  • 一階差分(Delta,Δ),類比速度,最簡單的一階差分計算方法
    Δ t = [c(t + 1) ? c(t ? 1)]/2
def mfcc(fbank, num_mfcc = num_mfcc):
    """Get mfcc feature from fbank feature
        :param fbank: a num_frames by  num_filter array(real)
        :param num_mfcc: mfcc number, default 12
        :returns: mfcc feature, a num_frames by num_mfcc array 
    """

    feats = dct(fbank, type=2, axis=1, norm="ortho")[:, 1 : (num_mfcc + 1)] 

    return feats
  • 二階差分(Delta delta, ΔΔ),類比加速度,簡單計算方法
    ΔΔ t = [Δ(t + 1) ? Δ(t ? 1)]/2

3. 代碼實踐

主要代碼在上面有詳細實現(xiàn),以下是一些實現(xiàn)的感想:

  • 1)主要是寫fbank的濾波器,mfcc就是在fbank的基礎上做了一個離散余弦變換,可以直接調(diào)用scipy;

  • 2)對于fbank,核心是三角濾波器, 直接按照公式,循環(huán)計算就可以了

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容