xbe.at

NLP and transformers / NLP core

Zero-Shot Classification with Python

8 min read, 15 sections

Contents
  1. Introduction to Zero-Shot Classification
  2. How Zero-Shot Classification Works
  3. Advantages of Zero-Shot Classification
  4. Real-Life Example: Content Categorization
  5. Real-Life Example: Multilingual Sentiment Analysis
  6. Preparing Input for Zero-Shot Classification
  7. Handling Multiple Labels in Zero-Shot Classification
  8. Improving Zero-Shot Classification with Prompt Engineering
  9. Handling Ambiguity in Zero-Shot Classification
  10. Zero-Shot Classification for Text Similarity
  11. Combining Zero-Shot Classification with Other NLP Tasks
  12. Evaluating Zero-Shot Classification Performance
  13. Limitations and Considerations
  14. Future Directions and Research
  15. Additional Resources

Introduction to Zero-Shot Classification

Zero-shot classification is a machine learning technique that allows models to classify objects or concepts they haven't been explicitly trained on. This approach leverages the semantic relationships between known and unknown classes, enabling the model to make predictions on new, unseen categories.

from transformers import pipeline

classifier = pipeline("zero-shot-classification")
sequence = "I love playing guitar and composing music."
candidate_labels = ["music", "sports", "cooking"]

result = classifier(sequence, candidate_labels)
print(result)

How Zero-Shot Classification Works

Zero-shot classification utilizes pre-trained language models and their understanding of semantic relationships. The model compares the input text with given candidate labels, assessing the likelihood of each label based on the contextual understanding it has gained during pre-training.

import numpy as np
import torch
from transformers import AutoModelForSequenceClassification, AutoTokenizer

model = AutoModelForSequenceClassification.from_pretrained("facebook/bart-large-mnli")
tokenizer = AutoTokenizer.from_pretrained("facebook/bart-large-mnli")

def zero_shot_classify(text, labels):
    hypothesis = [f"This text is about {label}." for label in labels]
    premise = [text] * len(labels)
    
    inputs = tokenizer(premise, hypothesis, return_tensors="pt", padding=True, truncation=True)
    outputs = model(**inputs)
    probs = torch.nn.functional.softmax(outputs.logits, dim=1)
    
    return dict(zip(labels, probs[:, 1].tolist()))

text = "The new smartphone has a powerful processor and high-resolution camera."
labels = ["technology", "food", "sports"]

results = zero_shot_classify(text, labels)
print(results)

Advantages of Zero-Shot Classification

Zero-shot classification offers flexibility in handling new classes without retraining the model. It's particularly useful when dealing with evolving datasets or when training data for certain classes is scarce. This approach can significantly reduce the time and resources required for model updates.

from transformers import pipeline

classifier = pipeline("zero-shot-classification")

# Existing classes
texts = ["I enjoy playing basketball", "The cat is sleeping on the couch"]
labels = ["sports", "animals"]

# New, unseen class
new_text = "The rocket launched successfully into orbit"
new_label = "space"

# Classify with existing and new labels
all_labels = labels + [new_label]
for text in texts + [new_text]:
    result = classifier(text, all_labels)
    print(f"Text: {text}")
    print(f"Classification: {result['labels'][0]}")
    print(f"Confidence: {result['scores'][0]:.2f}\n")

Real-Life Example: Content Categorization

Zero-shot classification can be applied to automatically categorize content in content management systems or news aggregators. This allows for dynamic categorization without predefined categories.

from transformers import pipeline

classifier = pipeline("zero-shot-classification")

articles = [
    "SpaceX successfully launches Starship rocket for orbital test flight",
    "New study reveals potential breakthrough in Alzheimer's treatment",
    "Global stock markets react to recent economic policy changes"
]

categories = ["Space Exploration", "Medical Research", "Finance", "Technology", "Politics"]

for article in articles:
    result = classifier(article, categories)
    print(f"Article: {article}")
    print(f"Category: {result['labels'][0]}")
    print(f"Confidence: {result['scores'][0]:.2f}\n")

Real-Life Example: Multilingual Sentiment Analysis

Zero-shot classification can perform sentiment analysis across multiple languages without language-specific training data.

from transformers import pipeline

classifier = pipeline("zero-shot-classification", model="facebook/bart-large-mnli")

texts = [
    "I love this product! It's amazing.",
    "Ce film était terrible, je ne le recommande pas.",
    "Diese Erfahrung war weder gut noch schlecht."
]

labels = ["positive", "negative", "neutral"]

for text in texts:
    result = classifier(text, labels)
    print(f"Text: {text}")
    print(f"Sentiment: {result['labels'][0]}")
    print(f"Confidence: {result['scores'][0]:.2f}\n")

Preparing Input for Zero-Shot Classification

To effectively use zero-shot classification, it's crucial to prepare your input data and candidate labels appropriately. The input text should be clear and concise, while the candidate labels should be relevant and diverse.

from transformers import pipeline

classifier = pipeline("zero-shot-classification")

# Poor example
poor_text = "It was good."
poor_labels = ["positive", "very positive", "extremely positive"]

# Better example
better_text = "The restaurant's atmosphere was cozy, the food was delicious, and the service was prompt."
better_labels = ["positive dining experience", "negative dining experience", "average dining experience"]

for text, labels in [(poor_text, poor_labels), (better_text, better_labels)]:
    result = classifier(text, labels)
    print(f"Text: {text}")
    print(f"Best label: {result['labels'][0]}")
    print(f"Confidence: {result['scores'][0]:.2f}\n")

Handling Multiple Labels in Zero-Shot Classification

Zero-shot classification can handle scenarios where multiple labels apply to a single input. By adjusting the classification threshold, we can allow for multi-label classification.

from transformers import pipeline

classifier = pipeline("zero-shot-classification")

text = "The new smartphone features a high-resolution camera, 5G connectivity, and a powerful AI chip."
labels = ["camera quality", "network technology", "processing power", "battery life"]

result = classifier(text, labels, multi_label=True)

print("Text:", text)
print("\nMulti-label classification results:")
for label, score in zip(result['labels'], result['scores']):
    if score > 0.5:  # Adjust this threshold as needed
        print(f"{label}: {score:.2f}")

Improving Zero-Shot Classification with Prompt Engineering

Prompt engineering can significantly enhance the performance of zero-shot classification. By carefully crafting the input prompt and candidate labels, we can guide the model towards more accurate predictions.

from transformers import pipeline

classifier = pipeline("zero-shot-classification")

text = "The stock market experienced a sharp decline following the announcement of new economic policies."

# Basic approach
basic_labels = ["finance", "politics", "technology"]

# Improved approach with prompt engineering
improved_labels = [
    "This text is about financial markets and economic news.",
    "This text is about government policies and political decisions.",
    "This text is about technological advancements and innovations."
]

print("Basic approach:")
basic_result = classifier(text, basic_labels)
print(basic_result)

print("\nImproved approach with prompt engineering:")
improved_result = classifier(text, improved_labels)
print(improved_result)

Handling Ambiguity in Zero-Shot Classification

Zero-shot classification may encounter ambiguous cases where multiple labels seem equally plausible. In such scenarios, it's important to analyze the confidence scores and consider the context.

from transformers import pipeline

classifier = pipeline("zero-shot-classification")

ambiguous_text = "The bank by the river was crowded."
labels = ["financial institution", "river bank", "crowded place"]

result = classifier(ambiguous_text, labels)

print("Text:", ambiguous_text)
print("\nClassification results:")
for label, score in zip(result['labels'], result['scores']):
    print(f"{label}: {score:.2f}")

print("\nAnalysis:")
if max(result['scores']) - min(result['scores']) < 0.1:
    print("This case is ambiguous. Consider providing more context or refining the labels.")
else:
    print(f"The most likely interpretation is: {result['labels'][0]}")

Zero-Shot Classification for Text Similarity

Zero-shot classification can be adapted for text similarity tasks, such as finding the most similar sentence in a group.

from transformers import pipeline

classifier = pipeline("zero-shot-classification")

reference = "I enjoy reading science fiction novels."
candidates = [
    "I love watching sci-fi movies.",
    "Gardening is my favorite hobby.",
    "I prefer non-fiction books about history."
]

results = []
for candidate in candidates:
    result = classifier(candidate, [reference], hypothesis_template="This text is similar to: {}")
    results.append((candidate, result['scores'][0]))

results.sort(key=lambda x: x[1], reverse=True)

print(f"Reference: {reference}\n")
print("Candidates sorted by similarity:")
for candidate, score in results:
    print(f"{candidate} (Similarity: {score:.2f})")

Combining Zero-Shot Classification with Other NLP Tasks

Zero-shot classification can be combined with other NLP tasks to create more sophisticated text analysis pipelines. Here's an example that combines named entity recognition with zero-shot classification.

from transformers import pipeline

ner = pipeline("ner", grouped_entities=True)
classifier = pipeline("zero-shot-classification")

text = "Apple Inc. announced a new iPhone model with advanced AI capabilities."

# Step 1: Named Entity Recognition
entities = ner(text)

# Step 2: Zero-shot classification for each entity
for entity in entities:
    entity_text = entity['word']
    entity_type = entity['entity_group']
    
    if entity_type == "ORG":
        labels = ["Technology Company", "Food Company", "Financial Institution"]
    elif entity_type == "PRODUCT":
        labels = ["Smartphone", "Computer", "Software"]
    else:
        continue
    
    result = classifier(entity_text, labels)
    
    print(f"Entity: {entity_text}")
    print(f"Type: {entity_type}")
    print(f"Classification: {result['labels'][0]} (Confidence: {result['scores'][0]:.2f})")
    print()

Evaluating Zero-Shot Classification Performance

Assessing the performance of zero-shot classification models is crucial. Here's a simple evaluation script that calculates accuracy on a test set.

from transformers import pipeline
from sklearn.metrics import accuracy_score

classifier = pipeline("zero-shot-classification")

# Test data
test_data = [
    ("The cat is sleeping on the couch", "pets"),
    ("The stock market crashed yesterday", "finance"),
    ("Scientists discovered a new exoplanet", "astronomy"),
    ("The recipe calls for flour and sugar", "cooking")
]

all_labels = ["pets", "finance", "astronomy", "cooking", "sports"]

true_labels = []
predicted_labels = []

for text, true_label in test_data:
    result = classifier(text, all_labels)
    predicted_label = result['labels'][0]
    
    true_labels.append(true_label)
    predicted_labels.append(predicted_label)
    
    print(f"Text: {text}")
    print(f"True label: {true_label}")
    print(f"Predicted label: {predicted_label}")
    print(f"Confidence: {result['scores'][0]:.2f}\n")

accuracy = accuracy_score(true_labels, predicted_labels)
print(f"Overall accuracy: {accuracy:.2f}")

Limitations and Considerations

While zero-shot classification is powerful, it has limitations. The model's performance depends on the quality of pre-training and the semantic relationship between input and labels. It may struggle with highly specialized domains or concepts far from its training data. Always validate results and consider fine-tuning for specific use cases.

from transformers import pipeline

classifier = pipeline("zero-shot-classification")

# Example of a limitation: highly specialized domain
specialized_text = "The patient exhibits signs of keratoconus in the left eye."
general_labels = ["health", "sports", "technology"]
specialized_labels = ["ophthalmology", "cardiology", "neurology"]

print("General labels:")
print(classifier(specialized_text, general_labels))

print("\nSpecialized labels:")
print(classifier(specialized_text, specialized_labels))

# Example of a concept far from training data
unusual_text = "The zorblax fluttered its tentacles in the crimson sky of Xargon-7."
labels = ["science fiction", "historical fiction", "romance", "mystery"]

print("\nUnusual concept:")
print(classifier(unusual_text, labels))

Future Directions and Research

Zero-shot classification is an active area of research with promising future directions. These include improving model generalization, reducing biases, and extending to more complex tasks like multi-label and hierarchical classification. Researchers are also exploring ways to combine zero-shot learning with few-shot learning for enhanced performance.

import matplotlib.pyplot as plt
import numpy as np

# Simulating improvement in zero-shot classification performance over time
years = np.arange(2020, 2026)
performance = [0.65, 0.72, 0.78, 0.83, 0.87, 0.90]  # Hypothetical values

plt.figure(figsize=(10, 6))
plt.plot(years, performance, marker='o')
plt.title("Hypothetical Zero-Shot Classification Performance Improvement")
plt.xlabel("Year")
plt.ylabel("Accuracy")
plt.ylim(0.6, 1.0)
plt.grid(True)
plt.show()

Additional Resources

For those interested in diving deeper into zero-shot classification, here are some valuable resources:

  1. "Zero-shot Learning - A Comprehensive Evaluation of the Good, the Bad and the Ugly" (ArXiv:1707.00600) URL: https://arxiv.org/abs/1707.00600
  2. "Zero-shot Text Classification With Generative Language Models" (ArXiv:1912.10165) URL: https://arxiv.org/abs/1912.10165
  3. "Learning to Compose Domain-Specific Transformations for Data Augmentation" (ArXiv:1709.01643) URL: https://arxiv.org/abs/1709.01643

These papers provide in-depth discussions on various aspects of zero-shot learning and its applications in natural language processing.

More in NLP core

  1. Using Regular Expressions for Natural Language Processing in Python6 min

    Regular expressions (regex) are powerful tools for pattern matching and text manipulation in Natural Language Processing (NLP). They provide a concise and...

  2. Unleashing Word2Vec for NLP in Python10 min

    Word2Vec is a powerful technique in Natural Language Processing (NLP) that transforms words into dense vector representations. These vectors capture semantic...

  3. Understanding Word Embeddings in Machine Learning12 min

    Word embeddings begin with one-hot encoding, a fundamental technique where each word is represented as a binary vector. This implementation demonstrates how...

  4. Understanding TF-IDF! A Key Text Analysis Technique in Python10 min

    TF-IDF (Term Frequency-Inverse Document Frequency) is a numerical statistic used to reflect the importance of a word in a document within a collection or...

  5. Understanding TF-IDF Vectorizer with Python7 min

    TF-IDF (Term Frequency-Inverse Document Frequency) is a numerical statistic used to reflect the importance of words in a document within a collection or...

  6. The Importance of Tokenization in NLP17 min

    Text tokenization forms the foundation of NLP by splitting raw text into individual tokens. This process transforms unstructured text data into a sequence of...