Zero-shot classification
Why this matters
You often face classification problems where you can't collect labeled training data: detecting complaint categories, content moderation labels, or custom business taxonomies. Zero-shot classification solves this by reframing classification as entailment, letting you ship classifiers on day one without any annotation work.
Explanation
What it is: Zero-shot classification uses a pre-trained language model to assign text to categories you define at inference time, without ever training on those categories. The model never saw those exact labels during training, yet it can classify into them using only your class descriptions.
How it works mechanically: Internally, the model treats classification as a natural language inference (NLI) problem. For each candidate label, it computes the probability that the input text entails the hypothesis "This text is about [label]." The label with the highest entailment score wins. This works because transformer models pre-trained on massive text corpora learn semantic relationships between concepts, so they can reason about unseen labels by understanding their descriptions.
When to use it: Use zero-shot when you're prototyping, when labels change frequently, or when you need a quick baseline. It trades some accuracy for zero annotation overhead. You can always add fine-tuning later once you have labeled data and know the approach works.
Analogy
Think of a teacher who never studied a specific exam question but understands the subject deeply enough to reason through the answer. Zero-shot classification is the model doing exactly that: it never saw your specific labels during training, but it understands language well enough to infer which label fits based on descriptions alone.
Code
import torch
from transformers import pipeline
from transformers import AutoTokenizer, AutoModelForSequenceClassification
text_input = "I absolutely love this product! Best purchase ever."
candidate_labels = ["positive sentiment", "negative sentiment", "neutral", "product complaint"]
classifier = pipeline(
"zero-shot-classification",
model="facebook/bart-large-mnli",
device=0 if torch.cuda.is_available() else -1
)
result = classifier(text_input, candidate_labels, multi_class=False)
print(f"Input: {text_input}")
print(f"\nTop prediction:")
print(f" Label: {result['labels'][0]}")
print(f" Score: {result['scores'][0]:.4f}")
print(f"\nAll predictions (ranked):")
for label, score in zip(result['labels'], result['scores']):
print(f" {label}: {score:.4f}") Input: I absolutely love this product! Best purchase ever. Top prediction: Label: positive sentiment Score: 0.9895 All predictions (ranked): positive sentiment: 0.9895 neutral: 0.0085 product complaint: 0.0015 negative sentiment: 0.0005
What just happened?
The pipeline loaded a pre-trained BART model fine-tuned on the MNLI (entailment) task. It then reformulated the classification problem: for each of the 4 candidate labels, the model computed the probability that the input text entails the statement "This text is about [label]." It returned all 4 scores sorted by confidence. The positive sentiment label scored 0.9895 because the model understood that loving a product entails positive sentiment.
Common gotcha
The scores from zero-shot classification are relative entailment confidences, not calibrated probabilities. A score of 0.95 doesn't mean 95% confidence in production terms: it means this label had the highest entailment score relative to others. If you need absolute thresholds (e.g., "only return a label if confidence > 0.9"), collect a validation set and threshold on the training distribution, not on raw scores. Also, longer, more descriptive labels ("customer expressing strong satisfaction with a purchased item") often score higher than short labels ("positive") due to more matching surface area with the input text.
Error recovery
IndexError: list index out of rangeRuntimeError: CUDA out of memoryValueError: Input length > 1024 tokensModuleNotFoundError: No module named 'transformers'Experienced dev note
In transformers 5.5.x, the pipeline() function requires you to explicitly pin the model name, unlike earlier versions where a generic "zero-shot-classification" would load a default. This is good: it forces you to choose the right model upfront (BART vs. RoBERTa vs. DeBERTa for accuracy vs. speed tradeoffs). Also, avoid passing 20+ candidate labels: performance degrades quadratically. If you have many categories, cluster them hierarchically or run zero-shot twice (coarse, then fine-grained). Finally, if you need production-grade confidence, always validate on a holdout set: zero-shot scores don't generalize across domains the way fine-tuned models do.
Check your understanding
Your model returns these scores for three candidate labels: [0.92, 0.05, 0.03]. If you lower the input text's semantic similarity to the top label (by paraphrasing it more abstractly), what happens to these three scores? Why?
Show answer hint
The top label's score will drop because entailment is weaker when the input diverges semantically from the hypothesis. The other two scores may shift upward (relatively), but the change in relative ranking depends on how much the input moved. The key insight: all three scores are re-normalized via softmax over the same forward pass: they always sum to 1.0, so if one drops, mass redistributes to others.