別實(shí)戰(zhàn):特征提取與分類器全流程)
簡(jiǎn)介面向音頻處理與機(jī)器學(xué)習(xí)初學(xué)者的MATLAB男聲女聲識(shí)別項(xiàng)目基于GUI圖形界面完成性別分類。資源共五個(gè)文件包含三段分別用于訓(xùn)練和測(cè)試的男女聲音頻、一個(gè)GUI布局文件以及一份完整M源碼壓縮包僅1.42MB輕量易部署。項(xiàng)目從讀取音頻、預(yù)處理、傅里葉變換與頻譜分析到MFCC特征提取再到SVM或神經(jīng)網(wǎng)絡(luò)分類器構(gòu)建形成完整識(shí)別鏈路界面文件保存了布局源碼實(shí)現(xiàn)按鈕回調(diào)、特征計(jì)算與結(jié)果展示可直接運(yùn)行并替換自己的音頻進(jìn)行驗(yàn)證。已有3721人學(xué)習(xí)瀏覽既能作為MATLAB信號(hào)處理與模式識(shí)別課程的實(shí)戰(zhàn)練習(xí)也可作為語音性別識(shí)別競(jìng)賽或畢業(yè)設(shè)計(jì)的基礎(chǔ)模板。整個(gè)項(xiàng)目在純MATLAB環(huán)境下即可完成實(shí)驗(yàn)與驗(yàn)證適合初學(xué)者快速掌握語音特征分析與分類器訓(xùn)練流程。1. 男女聲音識(shí)別不是玄學(xué)MATLAB里的特征與分類兩條線把一段錄音交給計(jì)算機(jī)判斷說話人是男是女這件事在MATLAB里跑通全流程只需要幾十行代碼但很多人第一次做都會(huì)翻車。男聲和女聲的差異本質(zhì)上是生理結(jié)構(gòu)差異在聲學(xué)上的映射聲帶厚薄導(dǎo)致基頻不同聲道長(zhǎng)短導(dǎo)致共振峰位置不同。用MATLAB做男女聲音識(shí)別核心工作其實(shí)是兩條線——特征提取和分類器訓(xùn)練前者決定信息是否夠用后者決定信息怎么被利用。這個(gè)項(xiàng)目非常適合語音入門者驗(yàn)證信號(hào)處理流程也適合有數(shù)據(jù)但缺分類思路的從業(yè)者做快速原型驗(yàn)證。下面從特征參數(shù)講起逐層落到代碼和坑位。2. 特征提取基頻、MFCC與共振峰的參數(shù)怎么設(shè)2.1 基頻男聲85-180Hz、女聲165-255Hz分水嶺在這里基頻是男女聲音識(shí)別里最直觀、也最穩(wěn)定的特征。成年男性聲帶厚而長(zhǎng)振動(dòng)頻率大致落在85到180Hz女性聲帶薄而短基頻范圍大約在165到255Hz。兩個(gè)范圍有重疊區(qū)間單靠閾值切分會(huì)留下誤判但作為特征輸入分類器它貢獻(xiàn)的區(qū)分度非常高。MATLAB從R2019a開始內(nèi)置了pitch函數(shù)不用自己寫自相關(guān)或倒譜法輸入音頻和采樣率就能拿到逐幀基頻序列。[audioIn, fs] audioread(female_01.wav); if size(audioIn, 2) 1 audioIn mean(audioIn, 2); % 雙聲道混成單聲道避免兩個(gè)聲道數(shù)據(jù)不同步 end [f0, loc] pitch(audioIn, fs, ... WindowLength, round(fs * 0.05), ... % 幀長(zhǎng)50ms OverlapLength, round(fs * 0.025), ... % 幀移25ms Range, [70 300]); % 基頻搜索范圍 f0Median median(f0, omitnan); % 中位數(shù)比均值更抗個(gè)別幀的野值這里幾個(gè)參數(shù)值得解釋。WindowLength設(shè)50ms而不是語音識(shí)別常用的25ms是因?yàn)榛l提取需要足夠長(zhǎng)的周期數(shù)才能穩(wěn)定估計(jì)幀移25ms保證相鄰幀有50%重疊讓基頻軌跡平滑。Range建議鎖在[70 300]而不是默認(rèn)的[60 300]能過濾掉部分低頻噪聲和咳嗽聲。最后用median而不是mean做匯總統(tǒng)計(jì)是因?yàn)殇浺衾锝?jīng)常會(huì)有個(gè)別幀pitch估計(jì)失敗返回NaN或極端值中位數(shù)不會(huì)被這些離群點(diǎn)帶偏。實(shí)際項(xiàng)目里我一般還會(huì)把f0Median和std(f0, omitnan)一起作為兩個(gè)特征后者反映說話人語調(diào)起伏程度對(duì)區(qū)分朗讀和口語也有幫助。2.2 MFCC提取幀長(zhǎng)25ms、13個(gè)系數(shù)的默認(rèn)值是哪里來的基頻只描述了聲帶的振動(dòng)快慢沒有描述聲音在頻域上的形狀。男女聲除了基頻不同聲道傳遞特性也不同——女性聲道短頻譜共振峰整體往高頻偏移。MFCC梅爾頻率倒譜系數(shù)就是用來捕捉這個(gè)頻譜包絡(luò)形狀的。MATLAB的mfcc函數(shù)把每幀音頻變換到梅爾域再做離散余弦變換輸出一組系數(shù)。第一維代表幀能量其余各維描述頻譜形狀。[coeffs, ~] mfcc(audioIn, fs, ... WindowLength, round(fs * 0.025), ... % 25ms語音識(shí)別事實(shí)標(biāo)準(zhǔn) OverlapLength, round(fs * 0.0125), ... % 12.5ms幀移 NumCoeffs, 13); % 13維前13維保留絕大多數(shù)頻譜形狀信息 mfccMean mean(coeffs(:, 2:end), 1); % 丟掉第1維能量只留MFCC25ms幀長(zhǎng)、10ms左右?guī)剖钦Z音領(lǐng)域的經(jīng)驗(yàn)參數(shù)理論上窗越短時(shí)間分辨率越高但頻率分辨率越差25ms是兩者平衡點(diǎn)。NumCoeffs用13是HTK時(shí)代的習(xí)慣低維系數(shù)描述頻譜包絡(luò)的整體走向高維系數(shù)描述細(xì)節(jié)對(duì)性別分類來說細(xì)節(jié)部分反而容易帶進(jìn)說話人個(gè)性噪聲所以13夠用。MFCC在幀和幀之間是短時(shí)平穩(wěn)的但整個(gè)句子里不同位置的音素不同簡(jiǎn)單求平均會(huì)把音素差異抹掉。我的做法是把mfccMean和std(coeffs(:, 2:end), 0, 1)即每一維的標(biāo)準(zhǔn)差拼接起來這樣既保留平均頻譜形狀又記錄了頻譜隨時(shí)間的變化幅度。這一步對(duì)短音頻尤其重要后面避坑章節(jié)會(huì)細(xì)說。2.3 共振峰與短時(shí)能量補(bǔ)特征還是補(bǔ)噪聲共振峰是聲道諧振產(chǎn)生的頻譜峰值成年女性由于聲道短前三個(gè)共振峰F1-F3平均比男性高20%左右。MATLAB沒有現(xiàn)成的共振峰提取函數(shù)常見做法是用LPC線性預(yù)測(cè)系數(shù)求解多項(xiàng)式根來推算。做法不復(fù)雜但共振峰估計(jì)對(duì)噪聲極敏感真實(shí)錄音里一個(gè)電話信道就把高頻共振峰壓沒了所以我不建議把它當(dāng)作主力特征。[ar, ~] lpc(audioIn, 12); % 12階LPC覆蓋4個(gè)共振峰左右 rts roots(ar); % 多項(xiàng)式根 rts rts(imag(rts) 0); % 只保留復(fù)平面上半部分 angles atan2(imag(rts), real(rts)); formantHz sort(angles * fs / (2 * pi)); % 換算成頻率這個(gè)代碼塊在干凈錄音上能得到相對(duì)合理的F1-F3估計(jì)但也僅此而已。實(shí)戰(zhàn)中我會(huì)把共振峰特征作為可選項(xiàng)當(dāng)數(shù)據(jù)集是麥克風(fēng)近場(chǎng)錄音時(shí)加上前三個(gè)共振峰頻率能提升一到兩個(gè)百分點(diǎn)的準(zhǔn)確率當(dāng)數(shù)據(jù)來源混雜比如一部分是手機(jī)錄音、一部分是電話錄音時(shí)共振峰引入的噪聲遠(yuǎn)大于信息量不加。短時(shí)能量同理男聲通常比女聲略低但能量受錄音距離影響太大同一句話遠(yuǎn)近各錄一遍能量差異比性別差異還大。特征選取的邏輯是優(yōu)先選物理機(jī)制明確且對(duì)錄音條件不敏感的特征基頻和MFCC屬于前者共振峰和能量屬于后者。3. 分類器選型SVM、決策樹與kNN的實(shí)戰(zhàn)對(duì)比3.1 用fitcecoc包SVMRBF核與標(biāo)準(zhǔn)化是默認(rèn)動(dòng)作特征提取完后男女聲音識(shí)別就是一個(gè)典型的二分類問題。在樣本量幾百到幾千這個(gè)區(qū)間支持向量機(jī)是穩(wěn)定度最高的選擇。MATLAB里直接調(diào)fitcecoc就可以完成多分類封裝二分類時(shí)它等價(jià)于訓(xùn)練一個(gè)標(biāo)準(zhǔn)的SVM。選擇RBF核是因?yàn)樾詣e分類的特征邊界不是線性的——基頻和MFCC之間存在交互關(guān)系線性核在這個(gè)任務(wù)上表現(xiàn)明顯差一截。svmModel fitcecoc(features, labels, ... Learners, templateSVM(KernelFunction, rbf, ... KernelScale, auto), ... Standardize, true, ... Prior, empirical);KernelScale設(shè)成auto讓MATLAB根據(jù)訓(xùn)練數(shù)據(jù)自動(dòng)估計(jì)RBF核的尺度參數(shù)省去手動(dòng)調(diào)參。Standardize一定要設(shè)true因?yàn)镸FCC均值在幾十的量級(jí)基頻中位數(shù)只有一百多標(biāo)準(zhǔn)差不一致會(huì)導(dǎo)致RBF核的距離計(jì)算被大數(shù)值維度主導(dǎo)。Prior設(shè)empirical表示按訓(xùn)練集中男女樣本的比例自動(dòng)調(diào)整先驗(yàn)概率這一步對(duì)處理不平衡數(shù)據(jù)特別重要后面避坑章節(jié)會(huì)展開。這套配置在我的實(shí)測(cè)里對(duì)干凈語音數(shù)據(jù)集通常能拿90%以上的準(zhǔn)確率而且基本不需要調(diào)參。3.2 決策樹和kNN什么時(shí)候可以替代SVM決策樹的特點(diǎn)是訓(xùn)練極快、結(jié)果可解釋能直接看出模型用了哪些特征、閾值是多少。fitctree在特征維度不高時(shí)表現(xiàn)不錯(cuò)而且對(duì)數(shù)據(jù)分布沒有假設(shè)男女樣本重疊嚴(yán)重時(shí)也沒問題。但它對(duì)特征縮放不敏感不需要標(biāo)準(zhǔn)化代價(jià)是決策邊界是軸對(duì)齊的矩形在特征耦合較強(qiáng)的數(shù)據(jù)上精度上限不如SVM。kNN的思路更樸素——新樣本距離誰近就歸誰。treeModel fitctree(features, labels, ... MaxNumSplits, 20, ... % 限制樹的復(fù)雜度防止深樹過擬合 SplitCriterion, gdi); % 基尼不純度 knnModel fitcknn(features, labels, ... NumNeighbors, 5, ... Distance, cosine); % 余弦距離在高維特征上比歐氏距離更穩(wěn)定MaxNumSplits設(shè)20意味著允許最多20個(gè)分支節(jié)點(diǎn)對(duì)二分類問題通常夠用。限制深度是一種正則化——決策樹如果不限深會(huì)逐幀記住訓(xùn)練集里的噪聲訓(xùn)練準(zhǔn)確率接近100%測(cè)試集立刻掉回75%。kNN的NumNeighbors設(shè)奇數(shù)在二分類里可以避免平票5是默認(rèn)起點(diǎn)樣本少時(shí)可以降到3樣本多時(shí)提到7效果差別不大。kNN在推理時(shí)要計(jì)算新樣本與所有訓(xùn)練樣本的距離當(dāng)訓(xùn)練集超過幾千條時(shí)單次預(yù)測(cè)耗時(shí)明顯上升實(shí)時(shí)性要求高的場(chǎng)景不推薦。3.3 數(shù)據(jù)集劃分與交叉驗(yàn)證分層抽樣決定結(jié)果可信度分類器選完下一步就是驗(yàn)證它到底行不行。很多人在這一步犯的錯(cuò)誤是隨機(jī)劃分訓(xùn)練集和測(cè)試集導(dǎo)致某個(gè)人的語音片段同時(shí)出現(xiàn)在兩邊——雖然測(cè)試集和訓(xùn)練集來自同一個(gè)說話人模型記住了這個(gè)人的音色測(cè)試準(zhǔn)確率虛高到95%以上但換成一個(gè)陌生說話人立刻崩盤。正確的做法是分層抽樣并按說話人去切。cv cvpartition(labels, KFold, 5, Stratify, true); for i 1:cv.NumTestSets trainIdx cv.training(i); testIdx cv.test(i); model fitcecoc(features(trainIdx, :), labels(trainIdx), ... Learners, templateSVM(KernelFunction, rbf, KernelScale, auto), ... Standardize, true); pred predict(model, features(testIdx, :)); acc(i) sum(pred labels(testIdx)) / numel(testIdx); end meanAcc mean(acc);KFold設(shè)5代表五折交叉驗(yàn)證每次用4/5數(shù)據(jù)訓(xùn)練、1/5驗(yàn)證循環(huán)五次取平均。Stratify必須設(shè)true它保證每一折里男女比例和全量數(shù)據(jù)一致避免某一折全是女聲導(dǎo)致模型在這個(gè)fold上直接失分。如果你的數(shù)據(jù)集里有重復(fù)說話人記得先把同一個(gè)人的所有語音分到同一折里這需要你手動(dòng)構(gòu)造分組信息cvpartition本身不知道哪些文件屬于同一個(gè)人。SVM在特征經(jīng)過標(biāo)準(zhǔn)化后會(huì)有額外開銷但五折交叉驗(yàn)證的整體耗時(shí)通常在幾十秒量級(jí)完全可接受。4. 用MATLAB跑通“采集→特征→訓(xùn)練→預(yù)測(cè)”全流程4.1 audioDatastore按文件夾批量讀取標(biāo)簽從目錄名來寫完整流程的第一步是把散落的音頻文件組織成帶標(biāo)簽的數(shù)據(jù)集。常見做法是建兩個(gè)文件夾male目錄放男聲錄音female目錄放女聲錄音然后讓audioDatastore自動(dòng)掃描子目錄用子目錄名生成標(biāo)簽。這個(gè)方案的好處是后續(xù)只有新增數(shù)據(jù)不用改代碼往文件夾里丟文件就行。ads audioDatastore(data, ... IncludeSubfolders, true, ... LabelSource, foldernames);data目錄下面直接放male和female兩個(gè)子文件夾。IncludeSubfolders設(shè)true才會(huì)遞歸掃描子目錄。LabelSource設(shè)foldernames告訴MATLAB把文件所在子目錄的名字作為該文件的標(biāo)簽生成的結(jié)果是categorical類型方便后面直接喂給分類器。錄音格式不限制wav、mp3、m4a都能讀但建議盡量統(tǒng)一成wavMP3經(jīng)過有損壓縮會(huì)抹平一部分高頻細(xì)節(jié)這些細(xì)節(jié)對(duì)MFCC的前幾維影響不大但會(huì)污染共振峰相關(guān)特征。4.2 批量特征提取與拼接把音頻變成特征矩陣音頻數(shù)據(jù)按batch讀入后要對(duì)每條錄音做相同流程的預(yù)處理和特征提取。這里有幾個(gè)隱藏細(xì)節(jié)每條錄音的長(zhǎng)度不同所以MFCC幀數(shù)不同直接用全部幀拼特征會(huì)有對(duì)齊問題。我的做法是逐條提取特征后在時(shí)間維上做聚合統(tǒng)計(jì)把每條音頻壓縮成一個(gè)固定長(zhǎng)度的行向量最后拼成一個(gè)大矩陣。allFeatures []; allLabels []; while hasdata(ads) [audioIn, info] read(ads); fs info.SampleRate; if size(audioIn, 2) 1 audioIn mean(audioIn, 2); end audioIn audioIn / max(abs(audioIn)); % 峰值歸一化消除錄音音量差異 f0 pitch(audioIn, fs, ... WindowLength, round(fs * 0.05), ... OverlapLength, round(fs * 0.025), ... Range, [70 300]); f0Vec [median(f0, omitnan), std(f0, omitnan), mean(f0, omitnan)]; [coeffs, ~] mfcc(audioIn, fs, ... WindowLength, round(fs * 0.025), ... OverlapLength, round(fs * 0.0125), ... NumCoeffs, 13); mfccFeat [mean(coeffs(:, 2:end), 1), std(coeffs(:, 2:end), 0, 1)]; featVec [f0Vec, mfccFeat]; % 3 24 27維特征 allFeatures [allFeatures; featVec]; %#okAGROW allLabels [allLabels; info.Label]; %#okAGROW endaudioIn / max(abs(audioIn))這一步很容易被跳過但對(duì)真實(shí)錄音影響很大——不同設(shè)備錄音的音量差異能到10倍以上不做歸一化的話能量相關(guān)的分量會(huì)把分類器帶偏。特征向量一共27維基頻中位數(shù)、基頻標(biāo)準(zhǔn)差、基頻均值再加12維MFCC均值和12維MFCC標(biāo)準(zhǔn)差。std在MFCC上用的是0權(quán)重即除以N-1這也是MATLAB默認(rèn)。4.3 訓(xùn)練與五折交叉驗(yàn)證一張混淆矩陣看透結(jié)果特征矩陣和標(biāo)簽都準(zhǔn)備好了接下來進(jìn)入訓(xùn)練階段。我習(xí)慣先跑一遍五折交叉驗(yàn)證確認(rèn)模型穩(wěn)定再在全部數(shù)據(jù)上重新訓(xùn)練最終模型。features allFeatures; labels allLabels; featuresNorm zscore(features); % 全局標(biāo)準(zhǔn)化保存均值和標(biāo)準(zhǔn)差供預(yù)測(cè)復(fù)用 rng(42); % 固定隨機(jī)種子結(jié)果可復(fù)現(xiàn) cv cvpartition(labels, KFold, 5, Stratify, true); acc zeros(cv.NumTestSets, 1); confMat zeros(2, 2); for i 1:cv.NumTestSets trainIdx cv.training(i); testIdx cv.test(i); model fitcecoc(featuresNorm(trainIdx, :), labels(trainIdx), ... Learners, templateSVM(KernelFunction, rbf, KernelScale, auto), ... Standardize, false); % 已用zscore標(biāo)準(zhǔn)化這里關(guān)掉避免雙重標(biāo)準(zhǔn)化 pred predict(model, featuresNorm(testIdx, :)); acc(i) mean(pred labels(testIdx)); confMat confMat confusionmat(labels(testIdx), pred); end fprintf(平均準(zhǔn)確率: %.2f%%\n, mean(acc) * 100);rng(42)固定隨機(jī)種子讓交叉驗(yàn)證的結(jié)果可以復(fù)現(xiàn)這在調(diào)參時(shí)很重要——不固定種子的話每次跑結(jié)果都在波動(dòng)你沒法判斷一個(gè)參數(shù)改動(dòng)是真實(shí)提升還是隨機(jī)波動(dòng)。zscore要放在交叉驗(yàn)證之前做還是放在每折內(nèi)部做其實(shí)有講究。嚴(yán)格來說應(yīng)該在訓(xùn)練折上計(jì)算均值和標(biāo)準(zhǔn)差再應(yīng)用到測(cè)試折上避免測(cè)試集信息泄漏到標(biāo)準(zhǔn)化里但樣本量大時(shí)兩者結(jié)果幾乎無差別這里為了簡(jiǎn)化代碼用了全局標(biāo)準(zhǔn)化。如果追求嚴(yán)謹(jǐn)把標(biāo)準(zhǔn)化放進(jìn)循環(huán)內(nèi)部即可。最后的混淆矩陣對(duì)角線元素之和除以總樣本數(shù)和平均準(zhǔn)確率應(yīng)該一致兩者互為校驗(yàn)。4.4 單條錄音的預(yù)測(cè)上線前的最后一步模型訓(xùn)練完成后實(shí)際使用場(chǎng)景是給一條新的錄音輸出一個(gè)性別標(biāo)簽。這中間要做的不是直接調(diào)用predict而是把訓(xùn)練階段那套預(yù)處理和特征提取邏輯原封不動(dòng)地搬過來否則特征對(duì)不上模型預(yù)測(cè)毫無意義。function label predictGender(audioPath, model, normMean, normStd) [audioIn, fs] audioread(audioPath); if size(audioIn, 2) 1 audioIn mean(audioIn, 2); end audioIn audioIn / max(abs(audioIn)); f0 pitch(audioIn, fs, ... WindowLength, round(fs * 0.05), ... OverlapLength, round(fs * 0.025), ... Range, [70 300]); f0Vec [median(f0, omitnan), std(f0, omitnan), mean(f0, omitnan)]; [coeffs, ~] mfcc(audioIn, fs, ... WindowLength, round(fs * 0.025), ... OverlapLength, round(fs * 0.0125), ... NumCoeffs, 13); mfccFeat [mean(coeffs(:, 2:end), 1), std(coeffs(:, 2:end), 0, 1)]; featVec [f0Vec, mfccFeat]; featVecNorm (featVec - normMean) ./ normStd; % 用訓(xùn)練集的統(tǒng)計(jì)量標(biāo)準(zhǔn)化 label predict(model, featVecNorm); end這個(gè)函數(shù)把流程封裝成了一個(gè)可復(fù)用的入口。normMean和normStd是訓(xùn)練時(shí)zscore返回的均值和標(biāo)準(zhǔn)差必須在訓(xùn)練階段保存下來。要注意這里處理的是單條短音頻如果音頻超過10秒建議切段后逐段預(yù)測(cè)再投票因?yàn)檎吻蟪鼍禃?huì)把前半段說話、后半段沉默的情況抹平導(dǎo)致特征被拉向中間值。這個(gè)細(xì)節(jié)在真實(shí)場(chǎng)景出現(xiàn)頻率很高下一章詳細(xì)展開。5. 避坑五個(gè)讓識(shí)別模型翻車的常見問題5.1 訓(xùn)練集準(zhǔn)確率99%、測(cè)試集70%特征里混進(jìn)了錄音環(huán)境交叉驗(yàn)證結(jié)果遠(yuǎn)低于訓(xùn)練集這是最常見的翻車現(xiàn)場(chǎng)。男女聲音識(shí)別里訓(xùn)練集和測(cè)試集如果來自不同設(shè)備MFCC特征會(huì)把麥克風(fēng)的頻響特性一起學(xué)進(jìn)去。我遇到過用一套錄音設(shè)備的數(shù)據(jù)訓(xùn)練到另一套設(shè)備上測(cè)試準(zhǔn)確率直接從92%掉到71%的情況。原因在于MFCC描述的是頻譜包絡(luò)而頻譜包絡(luò)里既有聲道形狀生理特征也有錄音設(shè)備的濾波特性環(huán)境特征SVM無法自動(dòng)區(qū)分這兩者。解決思路有兩個(gè)方向。第一個(gè)是數(shù)據(jù)層面訓(xùn)練數(shù)據(jù)盡可能覆蓋多設(shè)備、多場(chǎng)景讓分類器學(xué)到的是聲帶差異而不是麥克風(fēng)差異。第二個(gè)是特征層面把MFCC做倒譜均值歸一化CMN減去整段音頻MFCC的均值。MATLAB里手動(dòng)實(shí)現(xiàn)就是coeffs coeffs - mean(coeffs)這能去掉大部分線性信道畸變。兩個(gè)做法都做效果最好。5.2 pitch返回一堆NaN搜索范圍和采樣率沒對(duì)齊pitch函數(shù)返回的f0里如果出現(xiàn)大量NaN說明你的音頻可能根本不是預(yù)期采樣率或者搜索范圍設(shè)得太窄。我踩過一次某批wav文件標(biāo)注是44.1kHz實(shí)際是16kHz的mp3轉(zhuǎn)碼來的audioread返回的實(shí)際Fs就是16kHz代碼里寫的幀長(zhǎng)參數(shù)是按44.1kHz算的等效窗長(zhǎng)從50ms變成了138ms基頻軌跡亂七八糟。解決方法是每次audioread之后直接用返回的fs計(jì)算窗口參數(shù)不要寫死。另外檢查Range——如果錄音里有壓著嗓子的氣聲基頻可能跌到70Hz以下被過濾掉。我的習(xí)慣是先用[50 400]跑一遍看統(tǒng)計(jì)分布再?zèng)Q定要不要收窄到[70 300]。調(diào)試時(shí)打印sum(isnan(f0)) / numel(f0)如果超過20%就要回頭查數(shù)據(jù)了。5.3 所有測(cè)試樣本都判成男聲數(shù)據(jù)不平衡與先驗(yàn)糾纏模型把測(cè)試集里的女聲也判成男聲說明訓(xùn)練集里男聲樣本遠(yuǎn)多于女聲SVM的決策邊界被先驗(yàn)概率推向了女聲一側(cè)。fitcecoc默認(rèn)假設(shè)類別先驗(yàn)均勻當(dāng)實(shí)際比例是8:2時(shí)模型會(huì)在置信度上偏向多數(shù)類。解決方法是顯式設(shè)置Prior參數(shù)。除了empirical讓MATLAB按訓(xùn)練集比例自動(dòng)估計(jì)更穩(wěn)妥的方案是做類別加權(quán)給少數(shù)類更高的權(quán)重讓決策邊界重新居中。數(shù)據(jù)擴(kuò)充是另一個(gè)方向——把女聲樣本做變速和加噪在特征空間里等價(jià)于女聲樣本周圍多了合法鄰居SVM的支撐向量會(huì)把這部分空間重新劃分。兩者可以疊加使用效果比單方面調(diào)整閾值要好。5.4 mfcc矩陣形狀對(duì)不上幀長(zhǎng)與音頻時(shí)長(zhǎng)不匹配當(dāng)音頻短于一個(gè)窗長(zhǎng)時(shí)mfcc返回空矩陣或行數(shù)極少的矩陣后續(xù)mean(coeffs)直接報(bào)錯(cuò)。這個(gè)問題在真實(shí)場(chǎng)景比想象中更常見——我用手機(jī)錄過長(zhǎng)按語音消息生成的文件只有0.3秒整個(gè)音頻還不夠一幀MFCC使用。解決思路是設(shè)置最小音頻時(shí)長(zhǎng)門檻處理前先判斷numel(audioIn) fs * 0.5就跳過該條數(shù)據(jù)或補(bǔ)零到0.5秒。補(bǔ)零會(huì)引入假的頻譜形狀所以我傾向直接過濾。另外幀移參數(shù)如果設(shè)成round(fs * 0.0125)短音頻產(chǎn)生的幀數(shù)很少幀與幀之間的統(tǒng)計(jì)量方差會(huì)非常大這也是短音頻判別結(jié)果不穩(wěn)定的根源。建議少于2秒的錄音不要直接進(jìn)模型而是先按0.5秒一段切片取多數(shù)投票。5.5 程序跑到一半內(nèi)存爆炸循環(huán)里數(shù)組不斷變長(zhǎng)批量特征提取的循環(huán)里用allFeatures [allFeatures; featVec]是可以跑的但樣本量超過幾千以后MATLAB每次拼接都要重新分配整塊內(nèi)存運(yùn)行速度會(huì)以指數(shù)級(jí)下降最后直接內(nèi)存溢出。這在純技術(shù)層面是個(gè)性能問題在工程層面是數(shù)據(jù)規(guī)模增長(zhǎng)必然遇到的瓶頸。兩個(gè)常見的優(yōu)化方向。一是預(yù)分配先統(tǒng)計(jì)ads里的文件總數(shù)numel(ads.Files)按這個(gè)數(shù)預(yù)分配一個(gè)大矩陣再用索引填入。二是改用tall數(shù)組或直接寫parfor并行處理每個(gè)文件獨(dú)立提取特征再合并天然適合并行。我一般會(huì)先用預(yù)分配解決90%的場(chǎng)景數(shù)據(jù)量到幾萬條再考慮并行。內(nèi)存問題看起來不起眼但處理一整夜數(shù)據(jù)跑到一半崩潰的體驗(yàn)真的很痛。6. 進(jìn)階說話人歸一化與數(shù)據(jù)增強(qiáng)把準(zhǔn)確率再往上推一檔6.1 說話人歸一化去掉個(gè)性留性別共性基線模型能到90%左右以后再往上提就進(jìn)入精調(diào)階段。男女聲音識(shí)別有一個(gè)獨(dú)特優(yōu)勢(shì)基頻的絕對(duì)值其實(shí)混合了“性別信息”和“個(gè)人音色”兩個(gè)因素。一個(gè)嗓門粗的女低音和一個(gè)聲線高的男聲單看基頻中位數(shù)可能完全重疊。說話人歸一化的思路是把每條音頻的基頻軌跡除以該條音頻的基頻中位數(shù)把絕對(duì)頻率變成相對(duì)變化模式。f0Norm f0 / median(f0, omitnan); f0StatNorm [std(f0Norm, omitnan), iqr(f0Norm), mean(f0Norm)];歸一化后保留了語調(diào)起伏的相對(duì)模式抹掉了說話人本身的絕對(duì)音高這在跨說話人場(chǎng)景下能顯著提升泛化能力。代價(jià)是如果測(cè)試時(shí)輸入只有一句話、音高變化范圍太小歸一化后的特征會(huì)變得不穩(wěn)定所以這種方法在長(zhǎng)音頻上效果好于短音頻。前后對(duì)比可以用五折交叉驗(yàn)證正確率來評(píng)判提升通常在1到3個(gè)百分點(diǎn)之間。6.2 數(shù)據(jù)增強(qiáng)三件套變速、加噪、音量抖動(dòng)數(shù)據(jù)集只有幾十條語音時(shí)模型再調(diào)也就那樣。擴(kuò)大訓(xùn)練集最便宜的方式不是去網(wǎng)上找數(shù)據(jù)而是對(duì)已有數(shù)據(jù)做增強(qiáng)。語音領(lǐng)域最常用的三件套是變速、加噪和音量抖動(dòng)。變速保持基頻不變、時(shí)長(zhǎng)變化模擬說話快慢差異加噪讓模型見過不干凈的環(huán)境音量抖動(dòng)模擬不同錄音距離。MATLAB里變速用shiftPitch或者audioread后重采樣再插值都可以最簡(jiǎn)單的實(shí)現(xiàn)是把音頻用resample插值后播放長(zhǎng)度變化但音高也變了其實(shí)這已經(jīng)足夠破壞掉一部分設(shè)備特征達(dá)到增強(qiáng)目的。對(duì)MFCC類特征來說只要增強(qiáng)了頻譜形狀和基頻的多樣性模型的魯棒性就會(huì)提升具體增強(qiáng)倍數(shù)建議每類數(shù)據(jù)翻三倍左右再多容易過擬合到噪聲模式上。6.3 驗(yàn)證方法留一個(gè)陌生說話人出來交叉驗(yàn)證能防止隨機(jī)波動(dòng)但它測(cè)不出模型的真實(shí)泛化能力。我最后都會(huì)做一個(gè)留出性驗(yàn)證把所有訓(xùn)練文件按說話人分組隨機(jī)挑出兩個(gè)陌生說話人的所有音頻不參與訓(xùn)練只做測(cè)試。這個(gè)測(cè)試模擬的是真實(shí)使用場(chǎng)景——來的永遠(yuǎn)是沒見過的新說話人。這里有一個(gè)很容易被忽略的點(diǎn)同一個(gè)人的不同音頻在交叉驗(yàn)證里會(huì)被分到不同折模型實(shí)際上已經(jīng)“見過”這個(gè)人了準(zhǔn)確率偏樂觀。按說話人做分組交叉驗(yàn)證才接近真實(shí)水平。如果這個(gè)準(zhǔn)確率能穩(wěn)定在85%以上這個(gè)模型才算真正可以落地。我最早做這個(gè)項(xiàng)目時(shí)沒有按說話人分組模型在見過的人上表現(xiàn)優(yōu)秀一換陌生人立刻掉到75%。后來把說話人信息顯式編碼到交叉驗(yàn)證分組里才看到真實(shí)水平。希望這個(gè)驗(yàn)證方法能幫你少走一段彎路。本文還有配套的精品資源點(diǎn)擊獲取