n4nAI

How BLEU, ROUGE, and perplexity differ as metrics

A practical comparison of BLEU, ROUGE, and perplexity for LLM evaluation — when each metric works, where they fail, and how to pick the right one for your task.

n4n Team5 min read1,182 words

Audio narration

Coming soon — every post will get a voice note here.

BLEU, ROUGE, and perplexity are the three metrics you’ll encounter most often when evaluating LLM outputs, but they measure fundamentally different things. BLEU and ROUGE compare generated text against reference answers, making them suitable for translation, summarization, and any task with ground truth. Perplexity measures how surprised a model is by a sequence, which makes it a training-time diagnostic and a proxy for fluency — not correctness. Understanding these differences prevents you from optimizing the wrong signal.

What each metric actually measures

BLEU: precision-oriented n-gram overlap

BLEU (Bilingual Evaluation Understudy) computes the geometric mean of n-gram precisions (typically 1-gram through 4-gram) between candidate and reference texts, multiplied by a brevity penalty that discourages short outputs. It was designed for machine translation where multiple valid translations exist, and it correlates reasonably with human judgment when you have multiple references.

from nltk.translate.bleu_score import sentence_bleu, SmoothingFunction

reference = [["the", "cat", "sat", "on", "the", "mat"]]
candidate = ["the", "cat", "is", "on", "the", "mat"]

# Smoothing prevents zero scores when higher-order n-grams don't match
chencherry = SmoothingFunction()
score = sentence_bleu(reference, candidate, smoothing_function=chencherry.method1)
print(f"BLEU: {score:.4f}")  # ~0.58

BLEU’s precision focus means it rewards conservative outputs that repeat high-confidence n-grams. It penalizes hallucination indirectly — if you generate tokens not in the reference, precision drops — but it doesn’t directly measure factuality.

ROUGE: recall-oriented n-gram and sequence overlap

ROUGE (Recall-Oriented Understudy for Gisting Evaluation) comes in several variants. ROUGE-N measures n-gram recall (like BLEU but recall instead of precision). ROUGE-L uses longest common subsequence (LCS) to capture sentence-level structure. ROUGE-S adds skip-bigram co-occurrence statistics. For summarization, ROUGE-L and ROUGE-1/2 are standard.

from rouge_score import rouge_scorer

scorer = rouge_scorer.RougeScorer(['rouge1', 'rouge2', 'rougeL'], use_stemmer=True)
reference = "The cat sat on the mat and looked around."
candidate = "The cat is on the mat looking around."

scores = scorer.score(reference, candidate)
for metric, score in scores.items():
    print(f"{metric}: P={score.precision:.3f} R={score.recall:.3f} F1={score.fmeasure:.3f}")

ROUGE’s recall orientation means it rewards coverage of reference content. A verbose summary that includes everything in the reference (plus fluff) scores well on ROUGE but poorly on BLEU. This asymmetry matters: if your task penalizes missing key facts more than verbosity, ROUGE aligns better.

Perplexity: model uncertainty, not output quality

Perplexity is the exponentiated average negative log-likelihood of a sequence under a model: PPL = exp(-1/N Σ log P(token_i | context)). Lower perplexity means the model assigns higher probability to the observed tokens. It’s a property of the model on a dataset, not a direct comparison between candidate and reference.

import torch
import torch.nn.functional as F

def perplexity(logits, targets, ignore_index=-100):
    """
    logits: (batch, seq_len, vocab_size)
    targets: (batch, seq_len)
    """
    log_probs = F.log_softmax(logits, dim=-1)
    # Gather log probs of target tokens
    target_log_probs = log_probs.gather(-1, targets.unsqueeze(-1)).squeeze(-1)
    mask = (targets != ignore_index).float()
    nll = -(target_log_probs * mask).sum() / mask.sum()
    return torch.exp(nll).item()

# During evaluation, you compute perplexity on a held-out dataset
# Lower = model is less "surprised" by the data

Perplexity correlates with fluency and grammaticality, but a low-perplexity model can still hallucinate confidently. It’s primarily a training diagnostic — tracking validation perplexity tells you if the model is learning — and a model selection signal. It does not measure task performance.

Head-to-head comparison

Dimension BLEU ROUGE Perplexity
Primary signal N-gram precision vs reference(s) N-gram/LCS recall vs reference(s) Model probability of held-out tokens
Reference required Yes (1+, more is better) Yes (1+, more is better) No (evaluates model on corpus)
Task fit Translation, constrained generation Summarization, QA with ground truth Model selection, training monitoring
Correlates with Human adequacy judgments (with multi-ref) Human informativeness judgments Fluency, not factuality
Sensitive to Length (brevity penalty), n-gram order Coverage, verbosity Token distribution, vocabulary
Gameable Yes — short, safe outputs Yes — verbose outputs covering refs Yes — memorization, overfitting
Compute cost Negligible Negligible Requires forward pass on eval set
Interpretability 0-1 scale, higher better 0-1 scale (F1), higher better Positive real, lower better (typ. 10-100)
Multi-reference support Native (geometric mean) Native (max over refs) N/A

Where each metric fails

BLEU’s blind spots

BLEU correlates poorly with human judgment on open-ended generation. A fluent, factually correct answer that uses different phrasing than the reference scores near zero. The brevity penalty helps but doesn’t fix semantic equivalence. BLEU also ignores word order beyond 4-grams — “cat the mat on sat the” and “the cat sat on the mat” share many 4-grams.

For code generation, BLEU is particularly misleading. Two functionally equivalent programs with different variable names or formatting score poorly. Use CodeBLEU or execution-based evaluation instead.

ROUGE’s blind spots

ROUGE rewards extraction over abstraction. An extractive summary that copies sentences verbatim from the source often beats a well-written abstractive summary that paraphrases. ROUGE-L’s LCS component partially addresses this but still favors surface overlap.

ROUGE also can’t detect hallucination that happens to use words from the reference. If the reference says “revenue increased 5%” and your summary says “revenue decreased 5%”, ROUGE-1/2/L all score highly because the n-grams overlap.

Perplexity’s blind spots

Perplexity is the most dangerous metric to optimize directly. A model that memorizes the training set achieves near-zero perplexity but generalizes poorly. A model that outputs “I don’t know” for everything gets low perplexity on uncertain tokens but provides zero utility.

Perplexity also depends heavily on tokenization. A model with a larger vocabulary typically shows lower perplexity on the same text because each token carries more information. Comparing perplexity across different tokenizers is meaningless without normalization (bits per character or bits per byte).

Practical evaluation workflows

For translation: BLEU + chrF + human

# sacreBLEU provides standardized, reproducible BLEU with tokenization
pip install sacrebleu

# Evaluate with standard tokenization (intl for non-English)
sacrebleu -t wmt19 -l de-en --echo "model_output.txt" > results.json

Always report chrF++ alongside BLEU — it’s character-level F-score that correlates better with human judgment on morphologically rich languages. And budget for human evaluation on a 100-200 sample subset; automatic metrics are proxies, not ground truth.

For summarization: ROUGE + factuality + human

# Combine ROUGE with a factuality checker
from rouge_score import rouge_scorer
# Factuality: use a separate NLI model or LLM-as-judge
# e.g., entailment score between summary and source

scorer = rouge_scorer.RougeScorer(['rouge1', 'rouge2', 'rougeL'], use_stemmer=True)
rouge_scores = scorer.score(source_doc, generated_summary)

# Factuality check (pseudo-code)
# factuality = nli_model.entailment_score(source_doc, generated_summary)

ROUGE tells you coverage. You need a separate factuality metric — either an NLI model checking entailment from source to summary, or an LLM judge prompted to verify claims. n4n.ai’s routing can direct factuality checks to a specialized model while keeping the primary generation on a cost-efficient one.

For open-ended generation: perplexity (training) + LLM-as-judge (inference)

During training, track validation perplexity with early stopping:

# Training loop snippet
best_ppl = float('inf')
patience = 3
patience_counter = 0

for epoch in range(max_epochs):
    train_epoch(model, train_loader)
    val_ppl = evaluate_perplexity(model, val_loader)
    
    if val_ppl < best_ppl:
        best_ppl = val_ppl
        save_checkpoint(model)
        patience_counter = 0
    else:
        patience_counter += 1
        if patience_counter >= patience:
            break

At inference time, perplexity is useless for comparing outputs. Use LLM-as-judge with a rubric:

JUDGE_PROMPT = """Rate the response on a 1-5 scale for:
1. Instruction following
2. Factual accuracy
3. Reasoning quality
4. Clarity

Response: {response}
Reference: {reference}

Output JSON: {{"instruction_following": int, "factual_accuracy": int, ...}}"""

This correlates far better with human preference than any n-gram metric.

Which to choose

Choose BLEU when:

  • You have multiple reference translations for the same source
  • The task is translation or similarly constrained generation
  • You need a fast, deterministic, reproducible metric for regression testing
  • You’re comparing systems on standard benchmarks (WMT, IWSLT) where BLEU is established

Choose ROUGE when:

  • The task is summarization, headline generation, or any compression task
  • Recall (coverage of key information) matters more than precision (conciseness)
  • You have reference summaries written by humans
  • You need ROUGE-L for structural similarity or ROUGE-S for skip-gram flexibility

Choose perplexity when:

  • Monitoring training dynamics — validation perplexity should decrease smoothly
  • Selecting between model checkpoints or architectures pre-deployment
  • Comparing tokenization schemes (normalize to bits-per-byte)
  • Diagnosing distribution shift: test perplexity >> train perplexity indicates OOD data

Choose none of the above when:

  • Evaluating open-ended chat, creative writing, or reasoning — use LLM-as-judge with a rubric
  • Evaluating code — use execution accuracy (pass@k) or CodeBLEU
  • Evaluating factual QA — use exact match / F1 on answer spans, or LLM judge for free-form
  • Evaluating RAG — use retrieval metrics (recall@k, MRR) + generation faithfulness (NLI)

Combining metrics in practice

No single metric suffices. A production evaluation pipeline typically layers:

  1. Automatic metrics (BLEU/ROUGE/perplexity) for CI/CD regression gates — fast, deterministic, catch catastrophic regressions
  2. Model-based metrics (NLI for factuality, embedding similarity for semantic equivalence) for nightly evaluation on larger samples
  3. Human evaluation (side-by-side or absolute rating) on a small but representative sample weekly or per release
# Example: gated deployment check
def should_deploy(new_model, baseline_model, eval_set, thresholds):
    results = {}
    
    # Fast automatic metrics
    results['bleu'] = compute_bleu(new_model, eval_set)
    results['rouge_l'] = compute_rouge_l(new_model, eval_set)
    
    # Model-based factuality (sample 200)
    results['factuality'] = compute_factuality(new_model, eval_set.sample(200))
    
    # Regression gates
    if results['bleu'] < thresholds['bleu'] * 0.98:
        return False, "BLEU regression"
    if results['factuality'] < thresholds['factuality'] * 0.95:
        return False, "Factuality regression"
    
    # Human eval triggered automatically on borderline cases
    if results['bleu'] < thresholds['bleu'] * 1.02:
        queue_human_eval(new_model, baseline_model, eval_set.sample(50))
    
    return True, "Passed automatic gates"

The metrics you optimize determine the behavior you get. BLEU gives you conservative translations. ROUGE gives you extractive summaries. Perplexity gives you fluent but potentially hollow text. Choose the metric that aligns with your actual quality criteria, and always validate the correlation on your specific domain.

Tagsbleurougeperplexityevaluation-metrics

Written by

n4n Team

The team building n4n — a single OpenAI-compatible API in front of 240+ models, with automatic fallback, load balancing and pay-per-token metering.

More from n4n Team →

All perplexity & language model evaluation metrics posts →