Пример #1
0
/** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * **
*   Routine for Viterbi backtrace.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
double viterbi_backtrace(const Graph& graph, matrix<VitCell>& chart,
    vector<int>& outLabelList, bool doAlign)
    {
    int frmCnt = chart.size1() - 1;
    int stateCnt = chart.size2();

    //  Find best final state.
    vector<int> finalStates;
    int finalCnt = graph.get_final_state_list(finalStates);
    double bestLogProb = g_zeroLogProb;
    int bestFinalState = -1;
    for (int finalIdx = 0; finalIdx < finalCnt; ++finalIdx)
        {
        int stateIdx = finalStates[finalIdx];
        if (chart(frmCnt, stateIdx).get_log_prob() == g_zeroLogProb)
            continue;
        double curLogProb = chart(frmCnt, stateIdx).get_log_prob() +
            graph.get_final_log_prob(stateIdx);
        if (curLogProb > bestLogProb)
            bestLogProb = curLogProb, bestFinalState = stateIdx;
        }
    if (bestFinalState < 0)
        throw runtime_error("No complete paths found.");

    //  Do backtrace, collect appropriate labels.
    outLabelList.clear();
    int stateIdx = bestFinalState;
    for (int frmIdx = frmCnt; --frmIdx >= 0; )
        {
        assert((stateIdx >= 0) && (stateIdx < stateCnt));
        int arcId = chart(frmIdx + 1, stateIdx).get_arc_id();
        Arc arc;
        graph.get_arc(arcId, arc);
        assert((int) arc.get_dst_state() == stateIdx);
        if (doAlign)
            {
            if (arc.get_gmm() < 0)
                throw runtime_error("Expect all arcs to have GMM.");
            outLabelList.push_back(arc.get_gmm());
            }
        else if (arc.get_word() > 0)
            outLabelList.push_back(arc.get_word());
        stateIdx = graph.get_src_state(arcId);
        }
    if (stateIdx != graph.get_start_state())
        throw runtime_error("Backtrace does not end at start state.");
    reverse(outLabelList.begin(), outLabelList.end());
    return bestLogProb;
    }
Пример #2
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);
    }