Paraphrase Detection
Same meaning, different words
Paraphrase detection determines whether two pieces of text express the same meaning despite differing surface wording — 'How do I reset my password?' and 'I forgot my password, what do I do?' are paraphrases; 'How do I reset my password?' and 'How do I delete my account?' are not. This underlies deduplicating FAQ entries, detecting plagiarism, consolidating duplicate support tickets, and identifying redundant questions in community Q&A platforms (its original benchmark use case, Quora Question Pairs).
Framing it as a classification or regression problem
Paraphrase detection is typically framed either as binary classification (paraphrase / not paraphrase, as in the Quora Question Pairs and MRPC benchmarks) or as semantic textual similarity (STS) regression, predicting a continuous similarity score (e.g., 0-5 on the STS Benchmark) rather than a hard binary label — useful when 'somewhat similar but not identical' is a meaningful distinction the downstream application cares about (e.g., ranking near-duplicates by degree rather than a flat yes/no). The modeling architectures are the same two families used for document similarity generally: bi-encoders for scalable retrieval of candidate paraphrases, cross-encoders for high-precision pairwise verification.
from sentence_transformers import CrossEncoder
# Cross-encoders are the standard choice for paraphrase detection when you
# already have a candidate pair and need an accurate yes/no or score —
# they jointly attend over both sentences rather than encoding separately.
model = CrossEncoder("cross-encoder/quora-distilroberta-base")
pairs = [
("How do I reset my password?", "I forgot my password, what do I do?"),
("How do I reset my password?", "How do I delete my account?"),
]
scores = model.predict(pairs) # probability of being a paraphrase pair
for (q1, q2), score in zip(pairs, scores):
label = "PARAPHRASE" if score > 0.5 else "NOT PARAPHRASE"
print(f"{score:.3f} {label} | {q1!r} <-> {q2!r}")
# For scaling to large candidate sets: first retrieve top-k similar
# questions with a fast bi-encoder, THEN apply the cross-encoder to
# verify/rank only those candidates.Why paraphrase detection is harder than general semantic similarity
Paraphrase pairs require more than topical relatedness — 'What's the best programming language for beginners?' and 'What's the hardest programming language to learn?' are topically close (both about programming languages) but not paraphrases, because they're asking fundamentally different questions. This distinction between topical similarity and paraphrase equivalence is a frequent source of false positives in naive embedding-cosine-similarity approaches, which tend to conflate 'about the same subject' with 'asking the same thing.' Cross-encoders fine-tuned specifically on paraphrase-labeled data (rather than general STS data) tend to handle this distinction more reliably because the training signal explicitly penalizes exactly this kind of near-miss.
| Confounding case | Naive embedding similarity | Fine-tuned paraphrase model |
|---|---|---|
| True paraphrase, different wording | High (correctly flagged) | High (correctly flagged) |
| Topically related, different question | Often falsely high | Usually correctly low |
| Negation flip ('is X good' vs 'is X bad') | Can be falsely high (shares most words) | Usually correctly low, if trained on such cases |
| Same question, very different length/phrasing | Can be falsely low | Usually correctly high |
Negation and antonym substitution are the classic failure mode
Deduplication thresholds need domain-specific calibration
What's Next?
A closely related but more surgical problem — not detecting whether two full texts mean the same thing, but identifying and fixing small grammatical errors within a single text — uses an entirely different modeling approach worth examining on its own.
I build these systems professionally.
Whether it's a RAG pipeline, analytics migration, or AI workflow — let's talk.