conditional random fields crf structured prediction

# Conditional Random Fields: CRF & Structured Prediction

## Introduction & Motivation

Conditional Random Fields: discriminative graphical model. Model P(Y|X) directly. Undirected graphs; no independence assumptions on input. Applications: sequence labeling, named entity recognition, structured prediction.

Motivation: Discriminative model avoids modeling input distribution.

Applications: Tagging, structured prediction.

---

## Core Concepts & Theory

### Potential Functions

Unnormalized factor scores.

### Clique Potentials

Local compatibility functions.

### Partition Function

Normalizing constant Z(x).

---

## Mathematical Formulation

CRF probability:
$$P(y|x) = \frac{1}{Z(x)} \exp\left(\sum_c \psi_c(y_c, x) ight)$$

Linear-chain CRF:
$$P(y|x) = \frac{1}{Z(x)} \exp\left(\sum_t (\mathbf{w} \cdot \mathbf{f}(y_t, y_{t-1}, x_t)) ight)$$

Loss (negative log-likelihood):
$$L = -\log P(y|x)$$

---

## Advanced Theory & Extensions

### Structured Perceptron

Online discriminative learning.

### Skip-Chain CRF

Long-range dependencies.

### Semi-CRF

Segmental structure.

---

## Computational Considerations

Inference: O(T·|Y|²) Viterbi.

Learning: O(T·|Y|²) per gradient computation.

Decoding: O(T·|Y|) with dynamic programming.

---

## Practical Implementation Strategies

### Feature Engineering

Hand-crafted features for domain.

### Regularization

L2 penalty on weights.

### Beam Search

Approximate inference for speedup.

---

## Benchmark Datasets & Evaluation

CoNLL 2003: NER benchmark.

POS Tagging: Sequence labeling task.

BIO Tagging: Entity boundaries.

---

## Key Challenges & Limitations

### Feature Sparsity

Manual feature engineering needed.

### Computational Cost

Normalizing constant expensive.

### Label Imbalance

Common in tagging tasks.

---

## Hyperparameter Tuning

Regularization: L2 penalty 0.01-1.0.

Learning rate: 0.001-0.1.

Beam size: 1-10; speed-accuracy tradeoff.

---

## Real-World Applications & Case Studies

Named Entity Recognition: CoNLL benchmark.

Part-of-Speech Tagging: Syntax annotation.

Slot Filling: Dialogue systems.

---

## Integration with Other Methods

CRF + Neural Network → neural CRF.

CRF + Attention → attended structure.

---

## Summary & Key Takeaways

Conditional Random Fields via structured prediction enable sequence labeling through discriminative potential functions and graph-based inference.

Principles:
1. Discriminative: P(Y|X) directly.
2. Potentials: local compatibility.
3. Partition function: normalization.
4. Viterbi: optimal path decoding.
5. Feature engineering: domain knowledge.

---

---

## Appendix: Practical Labs

### Lab 1: Linear-Chain CRF Scoring

import numpy as np

def crf_score(sequence, transitions, emissions, weights):
 """Compute CRF score for sequence"""
 score = 0.0
 
 for t in range(len(sequence) - 1):
 # Transition score
 prev_state = sequence[t]
 curr_state = sequence[t+1]
 score += transitions[prev_state, curr_state]
 
 # Emission scores
 for t in range(len(sequence)):
 state = sequence[t]
 score += emissions[t, state]
 
 return score

# Test
np.random.seed(42)
sequence = [0, 1, 0, 1]
transitions = np.random.randn(2, 2)
emissions = np.random.randn(4, 2)

score = crf_score(sequence, transitions, emissions, None)

assert np.isfinite(score), "Score finite"
print("✓ CRF scoring working")

if __name__ == "__main__":
 print("Lab 1: CRFScoring - PASSED")

### Lab 2: Partition Function (Forward Algorithm)

import numpy as np

def partition_function(transitions, emissions, num_states):
 """Compute partition function Z(x)"""
 T = emissions.shape[0]
 
 # Forward table
 alpha = np.zeros((T, num_states))
 
 # Initialize
 alpha[0] = emissions[0]
 
 # Forward pass
 for t in range(1, T):
 for j in range(num_states):
 alpha[t, j] = np.sum(alpha[t-1] * np.exp(transitions[:, j])) * np.exp(emissions[t, j])
 
 # Partition function
 Z = np.sum(alpha[-1])
 
 return Z

# Test
np.random.seed(42)
transitions = np.random.randn(2, 2)
emissions = np.random.randn(4, 2)

Z = partition_function(transitions, emissions, 2)

assert Z > 0, "Partition function positive"
assert np.isfinite(Z), "Partition function finite"
print("✓ Partition function working")

if __name__ == "__main__":
 print("Lab 2: PartitionFunction - PASSED")

### Lab 3: CRF Inference (Viterbi)

import numpy as np

def crf_viterbi(emissions, transitions, num_states):
 """Viterbi inference for CRF"""
 T = emissions.shape[0]
 
 # Viterbi table
 viterbi = np.zeros((T, num_states))
 backpointer = np.zeros((T, num_states), dtype=int)
 
 # Initialize
 viterbi[0] = emissions[0]
 
 # Forward pass
 for t in range(1, T):
 for j in range(num_states):
 # Find best previous state
 temp = viterbi[t-1] + transitions[:, j]
 backpointer[t, j] = np.argmax(temp)
 viterbi[t, j] = np.max(temp) + emissions[t, j]
 
 # Backtrack
 path = [np.argmax(viterbi[-1])]
 for t in range(T-1, 0, -1):
 path.append(backpointer[t, path[-1]])
 
 return list(reversed(path))

# Test
np.random.seed(42)
emissions = np.random.randn(4, 2)
transitions = np.random.randn(2, 2)

path = crf_viterbi(emissions, transitions, 2)

assert len(path) == 4, "Path length"
assert all(0 <= s < 2 for s in path), "Valid states"
print("✓ CRF Viterbi working")

if __name__ == "__main__":
 print("Lab 3: CRFViterbi - PASSED")

### Lab 4: Marginal Probabilities

import numpy as np

def crf_marginals(emissions, transitions, num_states):
 """Compute marginal probabilities at each position"""
 T = emissions.shape[0]
 
 # Forward pass
 alpha = np.zeros((T, num_states))
 alpha[0] = np.exp(emissions[0])
 
 for t in range(1, T):
 for j in range(num_states):
 alpha[t, j] = np.sum(alpha[t-1] * np.exp(transitions[:, j])) * np.exp(emissions[t, j])
 
 # Backward pass
 beta = np.zeros((T, num_states))
 beta[-1] = 1.0
 
 for t in range(T-2, -1, -1):
 for i in range(num_states):
 beta[t, i] = np.sum(np.exp(transitions[i]) * np.exp(emissions[t+1]) * beta[t+1])
 
 # Marginals
 Z = np.sum(alpha[-1])
 marginals = (alpha * beta) / Z
 
 return marginals

# Test
np.random.seed(42)
emissions = np.random.randn(4, 2)
transitions = np.random.randn(2, 2)

marginals = crf_marginals(emissions, transitions, 2)

assert marginals.shape == (4, 2), "Marginals shape"
assert np.allclose(marginals.sum(axis=1), 1.0), "Marginals sum to 1"
print("✓ CRF marginals working")

if __name__ == "__main__":
 print("Lab 4: CRFMarginals - PASSED")

Go deeper with CFSGPT

Get AI-powered deep-dives, save terms, and run advanced simulations — free account.

Create Free Account