HMM原理簡述和使用說明


1、原理簡述   

      為了對GMM-HMM在語音識別上的應用有個宏觀認識,花了些時間讀了下HTK(用htk完成簡單的孤立詞識別)的部分源碼,對該算法總算有了點大概認識,達到了預期我想要的。不得不說,網絡上關於語音識別的通俗易懂教程太少,都是各種公式滿天飛,很少有說具體細節的,當然了,那需要有實戰經驗才行。下面總結以下幾點,對其有個宏觀印象即可(以孤立詞識別為例)。

  一、每個單詞的讀音都對應一個HMM模型,大家都知道HMM模型中有個狀態集S,那么每個狀態用什么來表示呢,數字?向量?矩陣?其實這個狀態集中的狀態沒有具體的數學要求,只是一個名稱而已,你可以用’1’, ’2’, ‘3’…表示,也可以用’a’, ‘b’, ’c ’表示。另外每個HMM模型中到底該用多少個狀態,是通過先驗知識人為設定的。

  二、HMM的每一個狀態都對應有一個觀察值,這個觀察值可以是一個實數,也可以是個向量,且每個狀態對應的觀察值的維度應該相同。假設現在有一個單詞的音頻文件,首先需要將其進行采樣得到數字信息(A/D轉換),然后分幀進行MFCC特征提取,假設每一幀音頻對應的MFCC特征長度為39,則每個音頻文件就轉換成了N個MFCC向量(不同音頻文件對應的N可能不同),這就成了一個序列,而在訓練HMM模型的參數時(比如用Baum-Welch算法),每次輸入到HMM中的數據要求就是一個觀測值序列。這時,每個狀態對應的觀測值為39維的向量,因為向量中元素的取值是連續的,需要用多維密度函數來模擬,通常情況下用的是多維高斯函數。在GMM-HMM體系中,這個擬合函數是用K個多維高斯混合得到的。假設知道了每個狀態對應的K個多維高斯的所有參數,則該GMM生成該狀態上某一個觀察向量(一幀音頻的MFCC系數)的概率就可以求出來了。

  三、對每個單詞建立一個HMM模型,需要用到該單詞的訓練樣本,這些訓練樣本是提前標注好的,即每個樣本對應一段音頻,該音頻只包含這個單詞的讀音。當有了該單詞的多個訓練樣本后,就用這些樣本結合Baum-Welch算法和EM算法來訓練出GMM-HMM的所有參數,這些參數包括初始狀態的概率向量,狀態之間的轉移矩陣,每個狀態對應的觀察矩陣(這里對應的是GMM,即每個狀態對應的K個高斯的權值,每個高斯的均值向量和方差矩陣)。

  四、在識別階段,輸入一段音頻,如果該音頻含有多個單詞,則可以手動先將其分割開(考慮的是最簡單的方法),然后提取每個單詞的音頻MFCC特征序列,將該序列輸入到每個HMM模型(已提前訓練好的)中,采用前向算法求出每個HMM模型生成該序列的概率,最后取最大概率對應的那個模型,而那個模型所表示的單詞就是我們識別的結果。

  五、在建立聲學模型時,可以用Deep Learning的方法來代替GMM-HMM中的GMM,因為GMM模擬任意函數的功能取決於混合高斯函數的個數,所以具有一定的局限性,屬於淺層模型。而Deep Network可以模擬任意的函數,因而表達能力更強。注意,這里用來代替GMM的Deep Nets模型要求是產生式模型,比如DBN,DBM等,因為在訓練HMM-DL網絡時,需要用到HMM的某個狀態產生一個樣本的概率。

  六、GMM-HMM在具體實現起來還是相當復雜的。

  七、一般涉及到時間序列時才會使用HMM,比如這里音頻中的語音識別,視頻中的行為識別等。如果我們用GMM-HMM對靜態的圖片分類,因為這里沒涉及到時間信息,所以HMM的狀態數可設為1,那么此時的GMM-HMM算法就退化成GMM算法了。

 

 

2、使用說明

一、離散輸出的隱馬爾科夫模型(DHMM,HMM with discrete outputs)

最大似然參數估計EM(Baum Welch算法

The script dhmm_em_demo.m gives an example of how to learn an HMM with discrete outputs. Let there be Q=2 states and O=3 output symbols. We create random stochastic matrices as follows.

O = 3;

Q = 2;

prior0 = normalise(rand(Q,1));

transmat0 = mk_stochastic(rand(Q,Q));

obsmat0 = mk_stochastic(rand(Q,O)); 

Now we sample nex=20 sequences of length T=10 each from this model, to use as training data.

T=10;   %序列長度

nex=20;  %樣本序列數目

data = dhmm_sample(prior0, transmat0, obsmat0, nex, T);      

Here data is 20x10. Now we make a random guess as to what the parameters are,

prior1 = normalise(rand(Q,1)); %初始狀態概率

transmat1 = mk_stochastic(rand(Q,Q)); %初始狀態轉移矩陣

obsmat1 = mk_stochastic(rand(Q,O)); %初始觀測狀態到隱藏狀態間的概率轉移矩陣

and improve our guess using 5 iterations of EM...

[LL, prior2, transmat2, obsmat2] = dhmm_em(data, prior1, transmat1, obsmat1, 'max_iter', 5);

%prior2, transmat2, obsmat2 為訓練好后的初始概率,狀態轉移矩陣及混合狀態概率轉移矩陣

LL(t) is the log-likelihood after iteration t, so we can plot the learning curve.

序列分類

To evaluate the log-likelihood of a trained model given test data, proceed as follows:

loglik = dhmm_logprob(data, prior2, transmat2, obsmat2)  %HMM測試

Note: the discrete alphabet is assumed to be {1, 2, ..., O}, where O = size(obsmat, 2). Hence data cannot contain any 0s.

To classify a sequence into one of k classes, train up k HMMs, one per class, and then compute the log-likelihood that each model gives to the test sequence; if the i'th model is the most likely, then declare the class of the sequence to be class i.

Computing the most probable sequence (Viterbi)

First you need to evaluate B(i,t) = P(y_t | Q_t=i) for all t,i:

B = multinomial_prob(data, obsmat);

Then you can use

[path] = viterbi_path(prior, transmat, B) 

 

二、具有高斯混合輸出的隱馬爾科夫模型(GHMM,HMM with mixture of Gaussians outputs)

Maximum likelihood parameter estimation using EM (Baum Welch)

Let us generate nex=50 vector-valued sequences of length T=50; each vector has size O=2.

O = 2;

T = 50;

nex = 50;

data = randn(O,T,nex);

Now let use fit a mixture of M=2 Gaussians for each of the Q=2 states using K-means.

M = 2;

Q = 2;

left_right = 0;

 

prior0 = normalise(rand(Q,1));

transmat0 = mk_stochastic(rand(Q,Q));

 

[mu0, Sigma0] = mixgauss_init(Q*M, reshape(data, [O T*nex]), cov_type);

mu0 = reshape(mu0, [O Q M]);

Sigma0 = reshape(Sigma0, [O O Q M]);

mixmat0 = mk_stochastic(rand(Q,M));

 

Finally, let us improve these parameter estimates using EM.

[LL, prior1, transmat1, mu1, Sigma1, mixmat1] = ...

    mhmm_em(data, prior0, transmat0, mu0, Sigma0, mixmat0, 'max_iter', 2);

Since EM only finds a local optimum, good initialisation is crucial. The initialisation procedure illustrated above is very crude, and is probably not adequate for real applications... Click here for a real-world example of EM with mixtures of Gaussians using BNT.

What to do if the log-likelihood becomes positive?

It is possible for p(x) > 1 if p(x) is a probability density function, such as a Gaussian. (The requirements for a density are p(x)>0 for all x and int_x p(x) = 1.) In practice this usually means your covariance is shrinking to a point/delta function, so you should increase the width of the prior (see below), or constrain the matrix to be spherical or diagonal, or clamp it to a large fixed constant (not learn it at all). It is also very helpful to ensure the components of the data vectors have small and comparable magnitudes (use e.g., KPMstats/standardize).

This is a well-known pathology of maximum likelihood estimation for Gaussian mixtures: the global optimum may place one mixture component on a single data point, and give it 0 covariance, and hence infinite likelihood. One usually relies on the fact that EM cannot find the global optimum to avoid such pathologies.

What to do if the log-likelihood decreases during EM?

Since I implicitly add a prior to every covariance matrix (see below), what increases is loglik + log(prior), but what I print is just loglik, which may occasionally decrease. This suggests that one of your mixture components is not getting enough data. Try a better initialization or fewer clusters (states).

What to do if the covariance matrix becomes singular?

Estimates of the covariance matrix often become singular if you have too little data, or if too few points are assigned to a cluster center due to a bad initialization of the means. In this case, you should constrain the covariance to be spherical or diagonal, or adjust the prior (see below), or try a better initialization.

How do I add a prior to the covariance matrix?

Buried inside of KPMstats/mixgauss_Mstep you will see that cov_prior is initialized to 0.01*I. This is added to the maximum likelihood estimate after every M step. To change this, you will need to modify the mhmm_em function so it calls mixgauss_Mstep with a different value.

Sequence classification

To classify a sequence (e.g., of speech) into one of k classes (e.g., the digits 0-9), proceed as in the DHMM case above, but use the following procedure to compute likelihood:

loglik = mhmm_logprob(data, prior, transmat, mu, Sigma, mixmat);

Computing the most probable sequence (Viterbi)

First you need to evaluate B(t,i) = P(y_t | Q_t=i) for all t,i:

B = mixgauss_prob(data(:,:,ex), mu, Sigma, mixmat);

where data(:,:,ex) is OxT where O is the size of the observation vector. Finally, use

[path] = viterbi_path(prior, transmat, B);

三、具有高斯輸出的HMM

This is just like the mixture of Gaussians case, except we have M=1, and hence there is no mixing matrix.

Online EM for discrete HMMs/ POMDPs

For some applications (e.g., reinforcement learning/ adaptive control), it is necessary to learn a model online. The script dhmm_em_online_demo gives an example of how to do this.

 

 

 

  MFCC:

  MFCC的matlab實現教程可參考:張智星老師的網頁教程mfcc. 最基本的12維特征。

[ruby]  view plain  copy
 
  1. function mfcc=frame2mfcc(frame, fs, filterNum, mfccNum, plotOpt)  
  2. % frame2mfcc: Frame to MFCC conversion.  
  3. %    Usage: mfcc=frame2mfcc(frame, fs, filterNum, mfccNum, plotOpt)  
  4. %  
  5. %    For example:  
  6. %        waveFile='what_movies_have_you_seen_recently.wav';  
  7. %        [y, fs, nbits]=wavReadInt(waveFile);  
  8. %        startIndex=12000;  
  9. %        frameSize=512;  
  10. %        frame=y(startIndex:startIndex+frameSize-1);  
  11. %        frame2mfcc(frame, fs, 20, 12, 1);  
  12.   
  13. %    Roger Jang 20060417  
  14.   
  15. if nargin<1, selfdemo; return; end  
  16. if nargin<2, fs=16000; end  
  17. if nargin<3, filterNum=20; end  
  18. if nargin<4, mfccNum=12; end  
  19. if nargin<5, plotOpt=0; end  
  20.   
  21. frameSize=length(frame);  
  22. % ====== Preemphasis should be done at wave level  
  23. %a=0.95;  
  24. %frame2 = filter([1, -a], 1, frame);  
  25. frame2=frame;  
  26. % ====== Hamming windowing  
  27. frame3=frame2.*hamming(frameSize);  
  28. % ====== FFT  
  29. [fftMag, fftPhase, fftFreq, fftPowerDb]=fftOneSide(frame3, fs);  
  30. % ====== Triangular band-pass filter bank  
  31. triFilterBankPrm=getTriFilterBankPrm(fs, filterNum);    % Get parameters for triangular band-pass filter bank  
  32. % Triangular bandpass filter.  
  33. for i=1:filterNum  
  34.     tbfCoef(i)=dot(fftPowerDb, trimf(fftFreq, triFilterBankPrm(:,i)));%得到filterNum個濾波系數  
  35. end  
  36. % ====== DCT  
  37. mfcc=zeros(mfccNum, 1); %DCT變換的前后個數也沒有變  
  38. for i=1:mfccNum  
  39.     coef = cos((pi/filterNum)*i*((1:filterNum)-0.5))'; %mfcc中的前mfccNum個系數  
  40.     mfcc(i) = sum(coef.*tbfCoef');%直接按照DCT公式  
  41. end  
  42. % ====== Log energy  
  43. %logEnergy=10*log10(sum(frame.*frame));  
  44. %mfcc=[logEnergy; mfcc];  
  45.   
  46. if plotOpt  
  47.     subplot(2,1,1);  
  48.     plot(frame, '.-');  
  49.     set(gca, 'xlim', [-inf inf]);  
  50.     title('Input frame');  
  51.     subplot(2,1,2);  
  52.     plot(mfcc, '.-');  
  53.     set(gca, 'xlim', [-inf inf]);  
  54.     title('MFCC vector');  
  55. end  
  56.   
  57. % ====== trimf.m (from fuzzy toolbox)  
  58. function y = trimf(x, prm) %由頻率的橫坐標算出三角形內的縱坐標,0~1  
  59. a = prm(1); b = prm(2); c = prm(3);  
  60. y = zeros(size(x));  
  61. % Left and right shoulders (y = 0)  
  62. index = find(x <= a | c <= x);  
  63. y(index) = zeros(size(index)); %只考慮三角波內的量  
  64. % Left slope  
  65. if (a ~= b)  
  66.     index = find(a < x & x < b);  
  67.     y(index) = (x(index)-a)/(b-a);  
  68. end  
  69. % right slope  
  70. if (b ~= c)  
  71.     index = find(b < x & x < c);  
  72.     y(index) = (c-x(index))/(c-b);  
  73. end  
  74. % Center (y = 1)  
  75. index = find(x == b);  
  76. y(index) = ones(size(index));  
  77.   
  78. % ====== Self demo  
  79. function selfdemo  
  80. waveFile='what_movies_have_you_seen_recently.wav';  
  81. [y, fs, nbits]=wavReadInt(waveFile);  
  82. startIndex=12000;  
  83. frameSize=512;  
  84. frame=y(startIndex:startIndex+frameSize-1);  
  85. feval(mfilename, frame, fs, 20, 12, 1);  

 

ZCR:

  過0檢測,用於判斷每一幀中過零點的數量情況,最簡單的版本可參考:zeros cross rate. 

[ruby]  view plain  copy
 
  1. waveFile='csNthu.wav';  
  2. frameSize=256;  
  3. overlap=0;  
  4. [y, fs, nbits]=wavread(waveFile);  
  5. frameMat=enframe(y, frameSize, overlap);  
  6. frameNum=size(frameMat, 2);  
  7. for i=1:frameNum  
  8.     frameMat(:,i)=frameMat(:,i)-mean(frameMat(:,i));    % mean justification  
  9. end  
  10. zcr=sum(frameMat(1:end-1, :).*frameMat(2:end, :)<0);  
  11. sampleTime=(1:length(y))/fs;  
  12. frameTime=((0:frameNum-1)*(frameSize-overlap)+0.5*frameSize)/fs;  
  13. subplot(2,1,1); plot(sampleTime, y); ylabel('Amplitude'); title(waveFile);  
  14. subplot(2,1,2); plot(frameTime, zcr, '.-');  
  15. xlabel('Time (sec)'); ylabel('Count'); title('ZCR');  

 

EPD:

  端點檢測,檢測聲音的起始點和終止點,可參考:EPD in Time Domain,在時域中的最簡單檢測方法。

[ruby]  view plain  copy
 
  1. waveFile='sunday.wav';  
  2. [wave, fs, nbits] = wavread(waveFile);  
  3. frameSize = 256;  
  4. overlap = 128;  
  5.   
  6. wave=wave-mean(wave);                % zero-mean substraction  
  7. frameMat=buffer2(wave, frameSize, overlap);    % frame blocking,每一列代表一幀  
  8. frameNum=size(frameMat, 2);            % no. of frames  
  9. volume=frame2volume(frameMat);        % volume,求每一幀的能量,絕對值或者平方和,volume為行向量  
  10. volumeTh1=max(volume)*0.1;            % volume threshold 1  
  11. volumeTh2=median(volume)*0.1;            % volume threshold 2  
  12. volumeTh3=min(volume)*10;            % volume threshold 3  
  13. volumeTh4=volume(1)*5;                % volume threshold 4  
  14. index1 = find(volume>volumeTh1); %找出volume大於閾值的那些幀序號  
  15. index2 = find(volume>volumeTh2);  
  16. index3 = find(volume>volumeTh3);  
  17. index4 = find(volume>volumeTh4);  
  18. %frame2sampleIndex()為從幀序號找到樣本點的序號(即每一個采樣點的序號)  
  19. %endPointX長度為2,包含了起點和終點的樣本點序號  
  20. endPoint1=frame2sampleIndex([index1(1), index1(end)], frameSize, overlap);  
  21. endPoint2=frame2sampleIndex([index2(1), index2(end)], frameSize, overlap);  
  22. endPoint3=frame2sampleIndex([index3(1), index3(end)], frameSize, overlap);  
  23. endPoint4=frame2sampleIndex([index4(1), index4(end)], frameSize, overlap);  
  24.   
  25. subplot(2,1,1);  
  26. time=(1:length(wave))/fs;  
  27. plot(time, wave);  
  28. ylabel('Amplitude'); title('Waveform');  
  29. axis([-inf inf -1 1]);  
  30. line(time(endPoint1(  1))*[1 1], [-1, 1], 'color', 'm');%標起點終點線  
  31. line(time(endPoint2(  1))*[1 1], [-1, 1], 'color', 'g');  
  32. line(time(endPoint3(  1))*[1 1], [-1, 1], 'color', 'k');  
  33. line(time(endPoint4(  1))*[1 1], [-1, 1], 'color', 'r');  
  34. line(time(endPoint1(end))*[1 1], [-1, 1], 'color', 'm');  
  35. line(time(endPoint2(end))*[1 1], [-1, 1], 'color', 'g');  
  36. line(time(endPoint3(end))*[1 1], [-1, 1], 'color', 'k');  
  37. line(time(endPoint4(end))*[1 1], [-1, 1], 'color', 'r');  
  38. legend('Waveform', 'Boundaries by threshold 1', 'Boundaries by threshold 2', 'Boundaries by threshold 3', 'Boundaries by threshold 4');  
  39.   
  40. subplot(2,1,2);  
  41. frameTime=frame2sampleIndex(1:frameNum, frameSize, overlap);  
  42. plot(frameTime, volume, '.-');  
  43. ylabel('Sum of Abs.'); title('Volume');  
  44. axis tight;  
  45. line([min(frameTime), max(frameTime)], volumeTh1*[1 1], 'color', 'm');  
  46. line([min(frameTime), max(frameTime)], volumeTh2*[1 1], 'color', 'g');  
  47. line([min(frameTime), max(frameTime)], volumeTh3*[1 1], 'color', 'k');  
  48. line([min(frameTime), max(frameTime)], volumeTh4*[1 1], 'color', 'r');  
  49. legend('Volume', 'Threshold 1', 'Threshold 2', 'Threshold 3', 'Threshold 4');  

 

 GMM: 

   GMM用在擬合數據分布上,本質上是先假設樣本的概率分布為GMM,然后用多個樣本去學習這些GMM的參數。GMM建模在語音中可用於某個單詞的發音,某個人的音色等。其訓練過程可參考:speaker recognition.

[ruby]  view plain  copy
 
  1. function [M, V, W, logProb] = gmmTrain(data, gaussianNum, dispOpt)  
  2. % gmmTrain: Parameter training for gaussian mixture model (GMM)  
  3. %    Usage: function [M, V, W, logProb] = gmm(data, gaussianNum, dispOpt)  
  4. %        data: dim x dataNum matrix where each column is a data point  
  5. %        gaussianNum: No. of Gaussians or initial centers  
  6. %        dispOpt: Option for displaying info during training  
  7. %        M: dim x meanNum matrix where each column is a mean vector  
  8. %        V: 1 x gaussianNum vector where each element is a variance for a Gaussian  
  9. %        W: 1 x gaussianNum vector where each element is a weighting factor for a Gaussian  
  10.   
  11. % Roger Jang 20000610  
  12.   
  13. if nargin==0, selfdemo; return; end  
  14. if nargin<3, dispOpt=0; end  
  15.   
  16. maxLoopCount = 50;    % Max. iteration  
  17. minImprove = 1e-6;    % Min. improvement  
  18. minVariance = 1e-6;    % Min. variance  
  19. logProb = zeros(maxLoopCount, 1);   % Array for objective function  
  20. [dim, dataNum] = size(data);  
  21.   
  22. % Set initial parameters  
  23. % Set initial M  
  24. %M = data(1+floor(rand(gaussianNum,1)*dataNum),:);    % Randomly select several data points as the centers  
  25. if length(gaussianNum)==1,  
  26.     % Using vqKmeans to find initial centers  
  27.     fprintf('Start KMEANS to find the initial mu...\n');  
  28. %    M = vqKmeansMex(data, gaussianNum, 0);  
  29.     M = vqKmeans(data, gaussianNum, 0); %利用聚類的方法求均值,聚成gaussianNum類  
  30. %    M = vqLBG(data, gaussianNum, 0);  
  31.     fprintf('Start GMM training...\n');  
  32.     if any(any(~isfinite(M))); keyboard; end  
  33. else  
  34.     % gaussianNum is in fact the initial centers  
  35.     M = gaussianNum;  
  36.     gaussianNum = size(M, 2);  
  37. end  
  38. % Set initial V as the distance to the nearest center  
  39. if gaussianNum==1  
  40.     V=1;  
  41. else  
  42.     distance=pairwiseSqrDist(M);%pairwiseSqrDist是dll  
  43.    %distance=pairwiseSqrDist2(M);  
  44.      
  45.     distance(1:(gaussianNum+1):gaussianNum^2)=inf;    % Diagonal elements are inf  
  46.     [V, index]=min(distance);    % Initial variance for each Gaussian  
  47. end  
  48. % Set initial W  
  49. W = ones(1, gaussianNum)/gaussianNum;    % Weight for each Gaussian,初始化時是均分權值  
  50.   
  51. if dispOpt & dim==2, displayGmm(M, V, data); end  
  52. for i = 1:maxLoopCount  %開始迭代訓練參數,EM算法  
  53.     % Expectation step:  
  54.     % P(i,j) is the probability of data(:,j) to the i-th Gaussian  
  55.     % Prob為每個樣本在GMM下的概率  
  56.     [prob, P]=gmmEval(data, M, V, W);  
  57.     logProb(i)=sum(log(prob)); %所有樣本的聯合概率  
  58.     if dispOpt  
  59.         fprintf('i = %d, log prob. = %f\n',i-1, logProb(i));  
  60.     end  
  61.     PW = diag(W)*P;  
  62.     BETA=PW./(ones(gaussianNum,1)*sum(PW));    % BETA(i,j) is beta_i(x_j)  
  63.     sumBETA=sum(BETA,2);  
  64.   
  65.     % Maximization step:  eqns (2.96) to (2.98) from Bishop p.67:  
  66.     M = (data*BETA')./(ones(dim,1)*sumBETA');  
  67.   
  68.    DISTSQ = pairwiseSqrDist(M, data);                    % Distance of M to data  
  69.    %DISTSQ = pairwiseSqrDist2(M, data);                    % Distance of M to data  
  70.      
  71.     V = max((sum(BETA.*DISTSQ, 2)./sumBETA)/dim, minVariance);    % (2.97)  
  72.     W = (1/dataNum)*sumBETA;                    % (2.98)  
  73.   
  74.     if dispOpt & dim==2, displayGmm(M, V, data); end  
  75.     if i>1, if logProb(i)-logProb(i-1)<minImprove, break; end; end  
  76. end  
  77. [prob, P]=gmmEval(data, M, V, W);  
  78. logProb(i)=sum(log(prob));  
  79. fprintf('Iteration count = %d, log prob. = %f\n',i, logProb(i));  
  80. logProb(i+1:maxLoopCount) = [];  
  81.   
  82. % ====== Self Demo ======  
  83. function selfdemo  
  84. %[data, gaussianNum] = dcdata(2);  
  85. data = rand(1000,2);  
  86. gaussianNum = 8;  
  87. data=data';  
  88. plotOpt=1;  
  89. [M, V, W, lp] = feval(mfilename, data, gaussianNum, plotOpt);  
  90.   
  91. pointNum = 40;  
  92. x = linspace(min(data(1,:)), max(data(1,:)), pointNum);  
  93. y = linspace(min(data(2,:)), max(data(2,:)), pointNum);  
  94. [xx, yy] = meshgrid(x, y);  
  95. data = [xx(:) yy(:)]';  
  96. z = gmmEval(data, M, V, W);  
  97. zz = reshape(z, pointNum, pointNum);  
  98. figure; mesh(xx, yy, zz); axis tight; box on; rotate3d on  
  99. figure; contour(xx, yy, zz, 30); axis image  
  100.   
  101. % ====== Other subfunctions ======  
  102. function displayGmm(M, V, data)  
  103. % Display function for EM algorithm  
  104. figureH=findobj(0, 'tag', mfilename);  
  105. if isempty(figureH)  
  106.     figureH=figure;  
  107.     set(figureH, 'tag', mfilename);  
  108.     colordef black  
  109.     plot(data(1,:), data(2,:),'.r'); axis image  
  110.     theta=linspace(-pi, pi, 21);  
  111.     x=cos(theta); y=sin(theta);  
  112.     sigma=sqrt(V);  
  113.     for i=1:length(sigma)  
  114.         circleH(i)=line(x*sigma(i)+M(1,i), y*sigma(i)+M(2,i), 'color', 'y');  
  115.     end  
  116.     set(circleH, 'tag', 'circleH', 'erasemode', 'xor');  
  117. else  
  118.     circleH=findobj(figureH, 'tag', 'circleH');  
  119.     theta=linspace(-pi, pi, 21);  
  120.     x=cos(theta); y=sin(theta);  
  121.     sigma=sqrt(V);  
  122.     for i=1:length(sigma)  
  123.         set(circleH(i), 'xdata', x*sigma(i)+M(1,i), 'ydata', y*sigma(i)+M(2,i));  
  124.     end  
  125.     drawnow  
  126. end  

 

 Speaker identification:

   給N個人的語音資料,用GMM可以訓練這N個人的聲音模型,然后給定一段語音,判斷該語音與這N個人中哪個最相似。方法是求出該語音在N個GMM模型下的概率,選出概率最大的那個。可參考:speaker recognition.

[ruby]  view plain  copy
 
  1. function [recogRate, confusionMatrix, speakerData]=speakerIdentify(speakerData, speakerGmm, useIntGmm)  
  2. % speakerIdentify: speaker identification using GMM parameters  
  3. %    Usage: [recogRate, confusionMatrix, speakerData]=speakerIdentify(speakerData, speakerGmm, useIntGmm)  
  4. %        speakerData: structure array generated by speakerDataRead.m  
  5. %        speakerGmm: speakerGmm(i).gmmPrm is the GMM parameters for speaker i.  
  6. %        useIntGmm: use fixed-point GMM  
  7.   
  8. %    Roger Jang, 20070517, 20080726  
  9.   
  10. if nargin<3, useIntGmm=0; end  
  11.   
  12. % ====== Speaker identification using GMM parameters  
  13. speakerNum=length(speakerData);  
  14. for i=1:speakerNum  
  15. %    fprintf('%d/%d: Recognizing wave files by %s\n', i, speakerNum, speakerData(i).name);  
  16.     for j=1:length(speakerData(i).sentence)  
  17. %        fprintf('\tSentece %d...\n', j);  
  18.         frameNum=size(speakerData(i).sentence(j).fea, 2);  
  19.         logProb=zeros(speakerNum, frameNum); %logProb(i,m)表示第i個人第j個句子中第m幀在GMM模型下的log概率  
  20.         %找出一個句子,看它屬於哪個speaker  
  21.         for k=1:speakerNum,  
  22. %            fprintf('\t\tSpeaker %d...\n', k);  
  23.         %    logProb(k, :)=gmmEval(speakerData(i).sentence(j).fea, speakerGmm(k).gmmPrm);  
  24.             if ~useIntGmm  
  25.             %    logProb(k, :)=gmmEvalMex(speakerData(i).sentence(j).fea, gmm(k).mean, gmm(k).covariance, gmm(k).weight);  
  26.                 logProb(k, :)=gmmEval(speakerData(i).sentence(j).fea, speakerGmm(k).gmmPrm);  
  27.             else  
  28.             %    logProb(k, :)=gmmEvalIntMex(speakerData(i).sentence(j).fea, gmm(k).mean, gmm(k).covariance, gmm(k).weight);  
  29.                 logProb(k, :)=gmmEvalIntMex(speakerData(i).sentence(j).fea, speakerGmm(i).gmmPrm);  
  30.             end  
  31.         end  
  32.         cumLogProb=sum(logProb, 2);  
  33.         [maxProb, index]=max(cumLogProb);  
  34.         speakerData(i).sentence(j).predictedSpeaker=index; %找出身份  
  35.         speakerData(i).sentence(j).logProb=logProb;  
  36.     end  
  37. end  
  38.   
  39. % ====== Compute confusion matrix and recognition rate  
  40. confusionMatrix=zeros(speakerNum);  
  41. for i=1:speakerNum,  
  42.     predictedSpeaker=[speakerData(i).sentence.predictedSpeaker];  
  43.     [index, count]=elementCount(predictedSpeaker);  
  44.     confusionMatrix(i, index)=count;  
  45. end  
  46. recogRate=sum(diag(confusionMatrix))/sum(sum(confusionMatrix));  

 

GMM-HMM:

  訓練階段:給出HMM的k個狀態,每個狀態下的觀察樣本的生成可以用一個概率分布來擬合,這里是采用GMM擬合的。其實,可以把GMM-HMM整體看成是一個生成模型。給定該模型的5個初始參數(結合隨機和訓練樣本獲得),啟動EM算法的E步:獲得訓練樣本分布,即計算訓練樣本在各個狀態下的概率。M步:用這些訓練樣本重新評估那5個參數。

  測試階段:(以孤立詞識別為例)給定每個詞發音的frame矩陣,取出某一個GMM-HMM模型,算出該發音每一幀數據在取出的GMM-HMM模型各個state下的概率,結合模型的轉移概率和初始概率,獲得對應的clique tree,可用圖模型的方法inference出生成該語音的概率。比較多個GMM-HMM模型,取最大概率的模型對應的詞。

   參考資料:

     機器學習&數據挖掘筆記_13(用htk完成簡單的孤立詞識別)

     http://htk.eng.cam.ac.uk/extensions/

     張智星老師的網頁教程mfcc.

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM