ML2021Spring-hw2 : Phoneme Classification

FOCK
11 min readMar 24, 2022

--

感謝李宏毅老師所提供的ML2021 Spring OCW

Result

雙過Strong Baseline(0.76118)

(1) Understanding

此次任務是要將MFCC(Mel Frequency Cepstral Coefficients)透過神經網路分類成Phoneme。

https://speech.ee.ntu.edu.tw/~tlkagk/courses/DLHLP20/ASR%20(v12).pdf

Phoneme : 分辨語意下的最小發音單位
In phonology and linguistics, a phoneme is a unit of sound that can distinguish one word from another in a particular language.
通常單字會由一個或以上的phoneme組合,因此我們能將每段聲音訊號拆解成phoeme,以辨識不同文字。

MFCC
參考這篇文章 语音信号处理之(四)梅尔频率倒谱系数(MFCC) :
給一段聲音訊號,以25ms當作窗口大小進行採樣,每個窗口經過一系列頻域轉換、倒譜分析、濾波後變成一組特徵向量,如此便得到MFCC。
(作業已將wav包成MFCC,不須再做轉換)

下圖為MFCC的Heatmap圖,橫軸為時間、縱軸為頻率。
值得注意的是,Mel-scale下的頻譜經過filter bank使低頻較高頻明顯,更接近人耳識別的效果

https://ithelp.ithome.com.tw/articles/10195970

(2) Pre-processing

https://speech.ee.ntu.edu.tw/~hylee/ml/ml2021-course-data/hw/HW02/HW02.pdf

input資料是由一萬多筆(1,429)的MFCC及phoneme label組成。

作業給了以下提示 :
Usually, a phoneme will span several frames

假設每10ms取一次frame,則10組frames為100ms。
英文語速大約每秒2.33個單字,以最常見的兩音節單字rich為例,其包含3個phonemes,故可得每秒約有3~5個phonemes。

由於原先的11組MFCC不夠表示phomene的長度,我做了資料擴增,使得每筆訓練資料更有機會涵蓋到整個 phoneme。

  1. 拆開並取中間的frame。
  2. 選定取多少範圍,concatenate範圍內相鄰的MFCC。

實際測試之後,發現前後各取10個MFCC的效果最好(DNN)。

為什麼frame不是取越多組越好?
如果離中心太遠可能會參雜到與label phoneme不相關的資訊,變相給data加了雜訊,使模型沒有學到原來phoneme該有的pattern。
至於取樣個數需透過模型決定,CNN和DNN的最優frames個數有所差異,這點在下面會討論。

(3) Model Selecting

1. DNN

範例給四層Fully-Connected Network,我慢慢疊加層數,發現在七層時的表現最好(分數為0.735)。
並且在layer間補上Batch Normalization和dropout(效果提升不少),另外activation function用的是ReLU。

2. CNN

CNN能針對圖像進行特徵化處理,而MFCC是照時間順序取樣的,故相鄰MFCC間對應頻譜位置有所關聯。

MFCC classification model 中回答提到 :

A standard approach for classification is a Deep Neural Network, that consists of Convolutional and adjacent Pooling layer since MFCCs are like images locally connected/correlated and Convolutional layers take care of that.

將input data看成(N, number of MFCC, 39)的三維向量,在放入CNN前轉為4D的(N, channel, number of MFCC, 39),channel數為1。如此一來,就能將MFCC當作2D image處理。

建立架構之前,先參考了深度學習:CNN原理,我基於此篇的架構去建立layer,需要注意的在convolution layer間不要放drop out,因為捲積層權值共享的特性,如果隨機廢掉部分神經元會無法學習到該掌握的特徵。

最後線性層的輸出補上softmax,變成加總為1的機率向量。

CNN和DNN誰好?
先定義stride : 以第i筆資料為中心,往左往右各取k組MFCC做Concatenation (i-k, i+k)。
CNN最優stride為25,DNN最優stride為10。

CNN只試過stride = 5, 10, 15, 20, 25,分數依序上升。我推測可以再吃更多筆MFCC,只是因為RAM不太夠,繼續往上加容易造成執行中斷,這代表CNN的表現可以再更好。
DNN我一樣試過上面幾組,最後會在10的情況分數最高,雖然具體原因有待釐清,但可以粗淺判斷,當MFCC拉長成1-dim vector時,他們像是被縱向concatenate在一起的,相鄰兩MFCC並非頭接頭、尾接尾,模型難以掌握到其連續性。
這算是trade-off,
DNN雖然對於intput每筆總量有所限制,卻能以更短的時間達到差不多的準確率

(4) Training

這次著重在模型的架構與選擇,超參數我只稍微修改了 :
learning rate = 1e-4 , batch_size = 1024 (縮短訓練時間)

我也用了 Improving Generalization Performance by Switching from Adam to SGD 提到的技巧,利用Adam前期快速收斂的特性,等到穩定時再換到SGD來跑,更容易在long-run training下得到更好的最優解,也算是應用了作業一提到的進階方法。

此外,CNN訓練時間比DNN多了大概4.5倍,兩者表現差異卻不大,說明DNN就足夠解決這項任務。只是都得跑400~500個epoch才能確保過strong baseline,如果沒有colab pro+會有點辛苦…

為何CNN訓練需要耗時這麼久?
先來比較一下兩者模型的神經元運算數量 :
CNN :
input (51,39)
Conv2d(1, 32, 3, 1, 1) = 1 * 32 * 51 * 39 * 3 * 3 = ~0.6M
Conv2d(32, 32, 5, 1, 1) = 32 * 32 * 47 * 35 * 5 * 5 = ~42M
Conv2d(64, 64, 5, 1, 1) = 64 * 64 * 43 * 31 * 5 * 5 = ~136.5M
MLP層先省略不計
Total : ~180M
DNN :
input(21*11*39)
Linear(21*11, 1024) = 1 * 21 * 11 * 39 * 1024 = ~10M
Linear(1024, 2048) = 1024 * 2048 = ~2M
Linear(2048, 2048) = 2048 * 2048 = ~4M
Linear(2048, 1024) = 2048 * 1024 = ~2M
Linear(1024, 512) = 1024 * 512 = ~ 0.5M
Linear(512, 128) = 512 * 128 = ~0.06M
Linear(128, 39) = ~0
Total : ~18.5M
光運算次數就差一個數量級,訓練時間理所當然地差異懸殊。
因此,兩種模型各有好壞,CNN雖然可塑性更高(能一次吃更多筆MFCC),但所需時間和其回報不成正比,可能因為資料真正可用的信息太過稀疏,每增加一筆MFCC得花上更多時間去處理特徵。

(5) Post-processing

Discontinuous Prediction

我參考pai4451的code :

從predict.csv可看出有些地方不連續,當出現[1,1,0,1,1]時,將其填補為[1,1,1,1,1],分數提高不少,這方法適合用於input資料前後有特定關係的情況(如時間序列)。

原本只檢查data[i-1]及data[i+1]前後各一個值。我將其再補上data[i-2],data[i+2]相同也更新data[i],實測後發現分數會再高一些。可以推測,持續不到5個frames長度的phoneme是不合法的(因此需要修正)。

為什麼這樣做有幫助?
其實,光是判斷相鄰phoneme之間關係是不夠的。
語言中也有「狀態機率」存在,某些字母常出現在頭、某些則常出現在尾,又或是某些字母常接在特定字母後面。
對於一段有意義的文字序列,通常會使用HMM(
Hidden Markov Model)建立一組狀態機率集合,如此一來,我們便能透過觀察HMM來得到誰最有可能成為下一個phoneme。

http://www.inf.ed.ac.uk/teaching/courses/asr/2018-19/asr07-nnintro.pdf

如何建立HMM?
下圖給定一組phoneme序列,我們目標是得到一組Observation Probability Set,並與Transition Probability set越接近越好。
而Transition Prob是從training data的label統計而來,具體實現可參考
演算法筆記。而Observation Prob則是由DNN訓練狀態分類,再透過Softmax得到狀態機率分布。
此外,在無法知道先前狀態序列的情況下,要求所有可能路徑(條件機率)的總和相當費時,因此要用到
Viterbi algorithm,透過動態刪減路徑的技巧,更快得到最大機率。

Phoneme橫跨多個Frames
HMM通常應用在文字序列中,其單字是由多個不同phoneme所組成的,因此相鄰的labels較不會有重複出現的情形。
回到原先問題,由於訓練資料是一段連續的聲音訊號,而好幾個frames才組成一個phomene,所以
下一個出現的最大可能phoneme往往是自己
而將HMM technique應用到此次任務,所預測的結果剛好與將過短的phoneme視作異常,用相鄰值來補的效果類似。

http://www.inf.ed.ac.uk/teaching/courses/asr/2018-19/asr08-hybrid_hmm_nn.pdf

Unbalanced Labels

另外,B站作業講解中觀察到phoneme labels有極度不均衡的問題 :

但在試過weightedRamdomSampler(按佔比調整採樣機率)後,會發現模型準確率大幅降低,因為這破壞了phoneme相對出現頻率的規律,從Relative Frequencies of English Phonemes中可看出,某些phoneme的出現次數就是比較高,如果忽略這項特性反而會使預測失準。

Conclusion

我將code公開在github上,有任何需要修改的還請指正!

這次作業在資料處理、模型選擇上特別要注意,不同的模型適合的資料類型也有所差異,反而在一些參數微調上並沒有太大的影響(但也是過baseline的關鍵因素)。

此外,我也學到了音訊轉換為MFCC的原理,以及HMM-DNN對於單字組成關係的基本概念(實作方面仍有待加強),NLP非常要求domain knowledge,光只是feature selection, balancing data, 或加上noise是行不通的,或許等修了DLHLP 後能更理解整個流程。

--

--