Viterbi Algorithm › The Viterbi Recursion

Michael BrenndoerferUpdated April 28, 20258 min read
Language AI HandbookAll chapters
Part 6 of 67Sequence Labeling
Chapter 41Viterbi Algorithm › The Viterbi Recursion
Reading section 3 of 12 · The Viterbi Recursion · 8 minSection 3 of 12 · 8 min

Book contents

Section 3 of 12 · 8 min read

Viterbi Algorithm › The Viterbi RecursionOne section · Sections in this chapter3 / 12 ↓
Reading tools Definitions & inline links

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

We've established that greedy decoding fails because local choices can force globally suboptimal sequences, and that exhaustive search is computationally impossible. How can we find the optimal path without examining every possibility? The answer lies in a beautiful insight from dynamic programming: we can build the optimal solution incrementally from smaller optimal solutions.

The Key Insight: Optimal Substructure

Imagine you're at position 3 in a sequence, and you want to know the best path that ends at the tag NOUN. The recurrence relies on this observation: regardless of how that path reached position 2, the best continuation to NOUN at position 3 depends only on:

  1. What state we're in at position 2 (not how we got there)
  2. The transition probability to NOUN
  3. The emission probability of the observed word from NOUN

This property is called optimal substructure. If the best path through the entire sequence passes through state s′s' at position 2 and then reaches NOUN at position 3, then the portion of that path from the start to s′s' must itself be optimal. Why? If there were a better path to s′s', we could substitute it and get a better overall path, contradicting our assumption that we had the best path.

Viterbi Principle (Bellman's Optimality)

The best path ending at state ss at position ii consists of the best path to some state s′s' at position i−1i-1, followed by a transition from s′s' to ss. We can find the globally optimal path by computing locally optimal subpaths.

This principle transforms our approach entirely. Instead of tracking complete paths (exponentially many), we only need to track the best score for reaching each state at each position. At any position, we have just kk values to maintain, one per possible state, rather than an exponentially growing set of paths.

Building the Recurrence: From Intuition to Formula

Let's formalize this insight. We define Vi(s)V_i(s) as the probability of the most likely path that:

  • Ends at state ss at position ii
  • Generates the observations w1,…,wiw_1, \ldots, w_i seen so far

How do we compute Vi(s)V_i(s)? Consider any path ending at state ss at position ii. That path must have come from some predecessor state s′s' at position i−1i-1. The probability of this path factors into three terms:

  1. The probability of the best path to s′s': This is Vi−1(s′)V_{i-1}(s'), which we've already computed
  2. The transition probability from s′s' to ss: This is P(s∣s′)P(s | s')
  3. The probability of emitting the current observation from ss: This is P(wi∣s)P(w_i | s)

Since we want the best path to ss, we take the maximum over all possible predecessor states. This gives us the Viterbi recurrence:

Vi(s)=max⁡s′[Vi−1(s′)⋅P(s∣s′)⋅P(wi∣s)]V_i(s) = \max_{s'} \left[ V_{i-1}(s') \cdot P(s | s') \cdot P(w_i | s) \right]

where:

  • Vi(s)V_i(s): the probability of the best path ending at state ss at position ii
  • max⁡s′\max_{s'}: takes the maximum over all possible predecessor states s′s'
  • Vi−1(s′)V_{i-1}(s'): the best score for reaching state s′s' at the previous position (already computed)
  • P(s∣s′)P(s | s'): the transition probability from predecessor state s′s' to current state ss
  • P(wi∣s)P(w_i | s): the emission probability of observing word wiw_i from state ss

Notice that P(wi∣s)P(w_i | s) appears inside the maximization but doesn't depend on the predecessor s′s'. This is because once we decide to be in state ss at position ii, the emission probability is fixed regardless of how we arrived. We could factor it out:

Vi(s)=P(wi∣s)⋅max⁡s′[Vi−1(s′)⋅P(s∣s′)]V_i(s) = P(w_i | s) \cdot \max_{s'} \left[ V_{i-1}(s') \cdot P(s | s') \right]

This form is computationally equivalent but makes clear that we're choosing the best predecessor based solely on the accumulated path score and transition, then multiplying by the emission.

The Base Case: Starting the Sequence

The recurrence needs a starting point. At position 1, there is no predecessor to consider. The probability of the best path ending at state ss after seeing just the first observation is simply:

V1(s)=P(s)⋅P(w1∣s)V_1(s) = P(s) \cdot P(w_1 | s)

where:

  • P(s)P(s): the initial state probability (how likely the sequence starts in state ss)
  • P(w1∣s)P(w_1 | s): the emission probability of the first observation from state ss

This captures both how likely we are to start in state ss and how well state ss explains the first observed word.

Complexity: Why This Works

Let's count the operations. At each of the nn positions (after the first), we compute Vi(s)V_i(s) for each of the kk states. Computing each Vi(s)V_i(s) requires examining kk predecessors. Total: O(n⋅k2)O(n \cdot k^2) operations.

Compare this to the knk^n paths we would examine exhaustively:

Complexity comparison between exhaustive search and Viterbi.
ApproachComplexity45 tags, 20 words
ExhaustiveO(kn)O(k^n)~103310^{33}
ViterbiO(n⋅k2)O(n \cdot k^2)40,500

The exponential has become polynomial. This is the power of dynamic programming: by recognizing that we can solve the problem incrementally and that we only need to remember the best score per state (not every path), we collapse an intractable problem into an efficient algorithm.

Visualizing the Trellis

It helps to visualize the Viterbi computation as filling a grid called a trellis. The horizontal axis represents positions in the sequence (1 through nn), and the vertical axis represents possible states (the kk tags or labels). Each cell (i,s)(i, s) holds the score Vi(s)V_i(s), the probability of the best path ending at state ss at position ii.

Arrows connect cells at adjacent positions. Each arrow from (i−1,s′)(i-1, s') to (i,s)(i, s) represents one term in the maximization: "if I came from state s′s', what would my score be?" The algorithm fills this grid column by column, left to right, computing each cell from the cells in the previous column.

Out[7]:
Visualization
Grid diagram showing positions 1-4 horizontally and three possible tags vertically, with arrows connecting adjacent columns representing transition probabilities.
A Viterbi trellis for part-of-speech tagging. Each column represents a position in the sequence, and each row represents a possible tag. Blue nodes show states, and arrows show transitions weighted by transition and emission probabilities. The algorithm finds the highest-scoring path from left to right through this lattice.

In the figure above, gray arrows show all possible transitions between adjacent positions. The red path highlights the optimal sequence discovered by Viterbi: DT → NN → VB → NN for the sentence "The can hold water." Notice that:

  • At position 1, DT (determiner) wins because "The" is overwhelmingly a determiner
  • At position 2, NN (noun) wins, not because "can" is most often a noun, but because this choice enables better continuations
  • The algorithm found this globally optimal path without explicitly enumerating all 81 possible sequences (3 states × 4 positions)

Now we understand how Viterbi computes scores efficiently. But there's a missing piece: at the end of the algorithm, we know the score of the best path, but we haven't recorded the path itself. How do we reconstruct the sequence of states along that path?