Пример #1
0
/** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * **
*   Routine for Viterbi decoding.
*
*   @param graph HMM/graph to operate on.
*   @param gmmProbs Matrix of log prob for each GMM for each frame.
*   @param chart Dynamic programming chart to fill in; already
*       allocated to be of correct size and initialized with default values.
*   @param outLabelList Indices of decoded output tokens are placed here.
*   @param acousWgt Acoustic weight.
*   @param doAlign If true, return GMM indices rather than word indices
*       in @p outLabelList.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
double viterbi(const Graph& graph, const matrix<double>& gmmProbs,
    matrix<VitCell>& chart, vector<int>& outLabelList, double acousWgt,
    bool doAlign)
    {
    int frmCnt = chart.size1() - 1;
    int stateCnt = chart.size2();

    //  BEGIN_LAB
    //
    //  Input:
    //      An HMM stored in the object "graph" of type "Graph".
    //      A matrix of doubles "gmmProbs"
    //
    //      gmmProbs(0 .. (frmCnt - 1), 0 .. (#GMM's - 1))
    //
    //      that stores the log prob of each GMM in "gmmSet"
    //      for each frame.
    //
    //  Output:
    //      A matrix "chart" of "VitCell" objects (declaration of
    //      "VitCell" class above):
    //
    //      chart(0 .. frmCnt, 0 .. stateCnt - 1)
    //
    //      On exit, chart(frmIdx, stateIdx).get_log_prob()
    //      should be set to the logarithm of the probability
    //      of the best path from the start state to
    //      state "stateIdx" given the
    //      first "frmIdx" frames of observations;
    //      and chart(frmIdx, stateIdx).get_arc_id() should be set
    //      to the arc ID for the last arc of this best path (or -1
    //      if the best path is of length 0).
    //      If a cell is unreachable from the start state,
    //      these values should be set to "g_zeroLogProb"
    //      and -1, respectively, which are what these values
    //      are initialized to on entry.
    //      The matrix "chart" has already been initialized to be
    //      of the correct size.
    //
    //      Notes: "g_zeroLogProb" is a large negative number we use
    //      to represent "ln 0" instead of the actual
    //      value negative infinity.
    //      You can assume there are no skip arcs, i.e.,
    //      arc.get_gmm() >= 0 for all arcs "arc" in the graph.
    //      Log probabilities should be base e, i.e., natural
    //      logarithms.
    //
    //      Here is an example of the syntax for accessing a chart
    //      cell log prob:
    //
    //      logProb = chart(frmIdx, stateIdx).get_log_prob();
    //
    //      Here is an example of setting the contents of a chart cell:
    //
    //      chart(frmIdx, stateIdx).assign(logProb, arcId);
    //
    //  Fill in Viterbi algorithm here.
    //
    //  The code for calculating the final probability and
    //  the best path is provided for you below.




    // Start Viterbi algorithm
    
    // Allocate a matrix for storing the log probability for the each current state giving the previous state
    // G(cur_state,pre_state) = chart(frmIdx-1,pre_state)*transformpro*gmmProb
    matrix<double> G;
    G.resize(stateCnt,stateCnt);
    for(int rowIndex=0; rowIndex<stateCnt; ++rowIndex)
	for(int colIndex=0; colIndex<stateCnt; ++colIndex)
		G(rowIndex,colIndex) = g_zeroLogProb;
    vector<double> maxProb(stateCnt); // store the max value for each row of the G matrix
    vector<int> maxIndex(stateCnt); // store the Index of the max element for each row of the G matrix


    // Initialize start state i.e. chart(0,(0 .. stateCnt - 1))
    for(int stateIdx=0; stateIdx<stateCnt; ++stateIdx)
	if(stateIdx==graph.get_start_state())
		chart(0,stateIdx).assign(0,-1);
        else
		chart(0,stateIdx).assign(g_zeroLogProb,-1);
    // End


    for(int frmIdx=0; frmIdx<frmCnt; ++frmIdx){
	for(int stateIdx=0; stateIdx<stateCnt; ++stateIdx){
		int arcCnt = graph.get_arc_count(stateIdx); // Get number of outgoing arcs for the stateIdx
		int arcId = graph.get_first_arc_id(stateIdx); // Get arc ID of the first outgoing arc

		for(int arcIdx=0; arcIdx<arcCnt;++arcIdx)
		{
			Arc arc;
			arcId = graph.get_arc(arcId,arc);
			int dstState = arc.get_dst_state(); // get the destination state of the stateIdx
			double transProb = arc.get_log_prob();
			int gmmId = arc.get_gmm();
			double gmmProb = gmmProbs(frmIdx,gmmId);
			G(dstState,stateIdx) = chart(frmIdx, stateIdx).get_log_prob() + transProb + gmmProb;
		}
	}
	for(int curStaIdx=0; curStaIdx<stateCnt; ++curStaIdx){
		maxProb[curStaIdx] = g_zeroLogProb;
		maxIndex[curStaIdx] = -1;
		for(int preStaIdx=0; preStaIdx<stateCnt; ++preStaIdx)
			{
				if(G(curStaIdx,preStaIdx) > maxProb[curStaIdx]){
					maxProb[curStaIdx] = G(curStaIdx,preStaIdx);
					int arcCnt = graph.get_arc_count(preStaIdx); // Get number of outgoing arcs for the stateIdx
					int arcId = graph.get_first_arc_id(preStaIdx); // Get arc ID of the first outgoing arc
					for(int arcIdx=0; arcIdx<arcCnt;++arcIdx)
						{
							Arc arc;
							arcId = graph.get_arc(arcId,arc);
							int dstState = arc.get_dst_state(); // get the destination state of the stateIdx
							if(dstState==curStaIdx)
								maxIndex[curStaIdx] = arcId-1;
						}
				}
			}
		
        }


	// assign the chart(frmIdx+1,0 .. stateCnt - 1)
	for(int stateIdx=0; stateIdx<stateCnt; ++stateIdx){
		chart(frmIdx+1,stateIdx).assign(maxProb[stateIdx],maxIndex[stateIdx]);
	}
	// clear the matrix G and the vectors
	for(int rowIndex=0; rowIndex<stateCnt; ++rowIndex)
		for(int colIndex=0; colIndex<stateCnt; ++colIndex)
			G(rowIndex,colIndex) = g_zeroLogProb;
	for(int i=0; i<stateCnt; ++i){
		maxProb[i] = g_zeroLogProb;
		maxIndex[i] = -1;
	}

    }
    //  END_LAB
    //  The code for calculating the final probability and  
    //  the best path is provided for you.
    return viterbi_backtrace(graph, chart, outLabelList, doAlign);
    }