# -*- coding: utf-8 -*-
"""getting-started-with-transformers.ipynb

Automatically generated by Colab.

Original file is located at
    https://colab.research.google.com/drive/1cPmyGnjQ_dvJPl6mEtvQUomAGt72gNKm

# ⚡ **Transformers: Revolutionizing Deep Learning**  

Transformers have redefined the landscape of deep learning, establishing themselves as the cornerstone of cutting-edge advancements in **Natural Language Processing (NLP) 📖**, **Computer Vision 🖼️**, and beyond. 🌍✨  

Introduced in the seminal paper *["Attention Is All You Need"](https://arxiv.org/abs/1706.03762)*, the **transformer architecture** leverages **self-attention mechanisms 🤖🧠** to efficiently model complex dependencies in data, enabling unprecedented breakthroughs in artificial intelligence. 🚀  

---

## 🎯 **About This Notebook**  

This course/notebook is designed to provide a **comprehensive understanding** of how to get stared with Transformers library🏆🚀  

### Also I will only be using Pytorch, i mean like it's obv why...

# **> Using the `pipeline()` Function for Inference in `transformers` Library**

The `pipeline()` function from Hugging Face’s `transformers` library provides an easy-to-use interface for leveraging pretrained models across various natural language processing (NLP), computer vision, and speech-related tasks. It abstracts away the complexities of model selection, tokenization, feature extraction, and inference, allowing users to perform state-of-the-art AI tasks with minimal setup.

---

## **1. Purpose of `pipeline()`**
The `pipeline()` function serves as a high-level API for running inference on various machine learning tasks using pretrained models. It simplifies the process of loading models from the Hugging Face Model Hub and executing them efficiently. Instead of manually handling the model, tokenizer, and preprocessing steps, `pipeline()` takes care of everything in the background.

The function is particularly useful for:
- Rapid prototyping and experimentation.
- Users who want to leverage deep learning models without diving into complex implementation details.
- Applications where inference speed and ease of use are prioritized over customization.

---

## **2. Key Components and Workflow**
When calling `pipeline()`, the function automatically:
1. **Loads the model**: If no specific model is provided, it selects a default pretrained model suitable for the task.
2. **Handles preprocessing**: Applies tokenization for text models or feature extraction for images and audio.
3. **Performs inference**: Passes the processed input through the model for prediction.
4. **Post-processes outputs**: Converts model outputs into a human-readable format.

The function supports various deep learning frameworks, including PyTorch and TensorFlow, and can be executed on CPUs or GPUs for faster performance.

---

## **3. Supported Tasks**
The `pipeline()` function supports a broad range of tasks across different modalities:

### **a) Natural Language Processing (NLP) Tasks**
- **Text Classification** – Categorizes text into predefined labels (e.g., sentiment analysis, spam detection).
- **Named Entity Recognition (NER)** – Identifies entities such as names, locations, and organizations in text.
- **Summarization** – Generates a concise summary from a longer text passage.
- **Question Answering** – Answers questions based on a given context (e.g., extractive QA).
- **Text Generation** – Produces new text based on a given prompt using models like GPT.
- **Translation** – Translates text from one language to another.
- **Text-to-Text Generation** – Converts one form of text into another (e.g., paraphrasing).

### **b) Computer Vision Tasks**
- **Image Classification** – Assigns labels to images based on their content.
- **Object Detection** – Detects and localizes objects within an image.
- **Image Segmentation** – Identifies pixels belonging to specific objects.
- **Image-to-Text** – Generates captions for images.

### **c) Speech and Audio Tasks**
- **Speech Recognition (ASR)** – Converts spoken language into text.
- **Text-to-Speech (TTS)** – Synthesizes speech from text.
- **Audio Classification** – Categorizes audio clips into predefined classes.

### **d) Multimodal Tasks**
- **Image Captioning** – Generates descriptive text for images.
- **Document Question Answering** – Answers questions based on scanned documents.

---

## **4. Advantages of Using `pipeline()`**
- **Ease of Use**: Requires minimal setup and eliminates the need for manual preprocessing and model loading.
- **Efficiency**: Automatically selects optimal configurations for inference.
- **Framework Agnostic**: Works with both PyTorch and TensorFlow models.
- **Supports Multiple Modalities**: Can be used for text, images, and audio-based tasks.
- **Scalability**: Can run on CPUs or GPUs for better performance.

# **> Let's install some important libraries**
"""

!pip install transformers datasets evaluate accelerate

pip install torch

"""# **> Understanding the pipeline for Inference**
## **Using the `pipeline()` for Inference**
The `pipeline()` function is the easiest way to use pretrained models for various tasks, such as:
- **Text classification**
- **Summarization**
- **Object detection**
- **Speech recognition**
- **Image captioning**
- **And more!**

# **> Now we can easily get started with performing some basic sentiment analysis using the pipeline function**
"""

# Commented out IPython magic to ensure Python compatibility.
# %%capture
# from transformers import pipeline
# 
# # Load a sentiment analysis pipeline
# classifier = pipeline("sentiment-analysis")
#

# Run inference
result = classifier("I am happy to see you guys here")
print(result)

"""**As you can see the drop in positive score percentage as the sentiment of the input was a bit changed and make a bit less positive**"""

result = classifier("I am happy to see you guys here, but also sad because of a few personal event in my life")
print(result)

"""**Now let's try with some harsh and negative tone**"""

result = classifier("I feel like i should hurt more people")
print(result)

"""**As we can see that the sentiment appears to be quite negative as the input seems quite harsh**"""

result = classifier("I like to abuse people in my spare time")
print(result)

"""## **> We can also also multiple input's at once to get their sentiment analysis score, Better known as "Batch Inference"**"""

results = classifier([
    "We're thrilled to introduce this new feature! 🎉",
    "I sincerely hope you find it useful",
    "We are genuinely proud of this update",
    "Not sure if you’ll like it, but here it is",
    "You might want to try it before deciding",
    "This is probably our best release yet!",
    "We hope you don’t mind the changes",
    "It’s a big step forward, and we're excited!",
    "We understand it might not be for everyone",
    "Feel free to ignore it if it doesn’t interest you"
])

for result in results:
    print(f"label: {result['label']}, with score: {round(result['score'], 4)}")

"""# **> Uptil now we not using any model or any tokenizer, we were just using general pipeline without any defined model and tokenizer just for the sake of learning, now let's use some...**"""

from transformers import AutoTokenizer, AutoModelForSequenceClassification, pipeline

# Load a custom model and tokenizer
model_name = "nlptown/bert-base-multilingual-uncased-sentiment"
model = AutoModelForSequenceClassification.from_pretrained(model_name)
tokenizer = AutoTokenizer.from_pretrained(model_name)

# Create a pipeline with the custom model
classifier = pipeline("sentiment-analysis", model=model, tokenizer=tokenizer)

# Function to map the star ratings to sentiment labels
def map_to_sentiment(star_rating):
    if star_rating in [1, 2]:
        return "Negative"
    elif star_rating == 3:
        return "Neutral"
    else:
        return "Positive"

# Classify French text
result = classifier("I am glad that i made it to the first place in this competition")

# Extract the star rating and convert it to a sentiment label
star_rating = int(result[0]['label'].split()[0])  # Extract number of stars
sentiment_label = map_to_sentiment(star_rating)

# Output the mapped sentiment label
print({"sentiment": sentiment_label, "score": result[0]['score']})

"""# **> Now Let's have a look at AutoClasses**
**AutoClasses (AutoModel, AutoTokenizer) provide an easy way to load a model from the Hugging Face Model Hub without specifying its architecture manually.**

**Let's look at some of the Classes that comes under AutoClasses**

## **1- AutoTokenizer**
**AutoTokenizer is used to load the appropriate tokenizer for a given model.**
"""

from transformers import AutoTokenizer

# Load the tokenizer for a model
tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")

# Tokenize a sample sentence
input_text = "Hello, how are you?"
encoded_input = tokenizer(input_text, return_tensors="pt")
print(encoded_input)

"""## **2- AutoModel**
**AutoModel loads the appropriate model for a given task (without specifying the task type directly).**
"""

from transformers import AutoModel

# Load the base model for BERT
model = AutoModel.from_pretrained("bert-base-uncased")

# Sample input
input_text = "Hello, how are you?"
encoded_input = tokenizer(input_text, return_tensors="pt")

# Forward pass through the model
output = model(**encoded_input)
print(output)

"""## 1. **3- AutoModelForSequenceClassification**
**AutoModelForSequenceClassification loads a pre-trained model for sequence classification tasks (like sentiment analysis).**
"""

from transformers import AutoModelForSequenceClassification, AutoTokenizer
import torch

# Load the pre-trained model for sentiment analysis
model_name = "distilbert-base-uncased-finetuned-sst-2-english"
model = AutoModelForSequenceClassification.from_pretrained(model_name)
tokenizer = AutoTokenizer.from_pretrained(model_name)

# Input text
text = "I am so happy with the results!"

# Tokenize the input text
inputs = tokenizer(text, return_tensors="pt", padding=True, truncation=True)

# Perform forward pass (get logits)
outputs = model(**inputs)

# Get the logits (raw model predictions)
logits = outputs.logits
print("Logits:", logits)

# Convert logits to probabilities using softmax
probabilities = torch.nn.functional.softmax(logits, dim=-1)
print("Probabilities:", probabilities)

# Get the predicted class (0 = negative, 1 = positive)
predicted_class = torch.argmax(probabilities, dim=-1).item()
print("Predicted class:", predicted_class)

# Map the predicted class to a label
labels = ["negative", "positive"]
predicted_label = labels[predicted_class]
print("Predicted sentiment:", predicted_label)

"""## **AutoModelForTokenClassification**
**AutoModelForTokenClassification is used for tasks like named entity recognition (NER).**
"""

# Commented out IPython magic to ensure Python compatibility.
# %%capture
# from transformers import AutoModelForTokenClassification
# 
# # Load the BERT model for token classification
# model = AutoModelForTokenClassification.from_pretrained("dbmdz/bert-large-cased-finetuned-conll03-english")
#

# Forward pass
output = model(**encoded_input)
print(output)

"""## **5- AutoModelForQuestionAnswering**
**AutoModelForQuestionAnswering is used for question-answering tasks.**
"""

# Commented out IPython magic to ensure Python compatibility.
# %%capture
# from transformers import AutoModelForQuestionAnswering
# 
# # Load the BERT model for question answering
# model = AutoModelForQuestionAnswering.from_pretrained("bert-large-uncased-whole-word-masking-finetuned-squad")
# 
# # Example question-answering input
# context = "Transformers are a type of machine learning model used in NLP."
# question = "What are transformers used for?"
# 
# encoded_input = tokenizer(question, context, return_tensors="pt")

# Forward pass through the model
output = model(**encoded_input)
print(output)

"""## **6- AutoModelForCausalLM**
**AutoModelForCausalLM is for causal language modeling tasks, such as autoregressive generation (e.g., GPT-2).**
"""

# Commented out IPython magic to ensure Python compatibility.
# %%capture
# from transformers import AutoModelForCausalLM
# 
# # Load GPT-2 for causal language modeling
# model = AutoModelForCausalLM.from_pretrained("gpt2")
# 
# # Example text to generate continuation
# input_text = "Once upon a time"
# encoded_input = tokenizer(input_text, return_tensors="pt")

# Forward pass and generation
output = model.generate(encoded_input['input_ids'], max_length=50)
print(tokenizer.decode(output[0], skip_special_tokens=True))

"""## **7- AutoModelForMaskedLM**
**AutoModelForMaskedLM is for masked language modeling tasks like BERT’s fill-mask.**
"""

# Commented out IPython magic to ensure Python compatibility.
# %%capture
# from transformers import AutoModelForMaskedLM
# 
# # Load BERT for masked language modeling
# model = AutoModelForMaskedLM.from_pretrained("bert-base-uncased")
# 
# # Example masked input
# input_text = "I am a [MASK] model."
# encoded_input = tokenizer(input_text, return_tensors="pt")

# Forward pass
output = model(**encoded_input)
print(output)

"""## **8- AutoModelForMultipleChoice**
**AutoModelForMultipleChoice is used for multiple-choice tasks, often used for tasks like SWAG.**
"""

# Commented out IPython magic to ensure Python compatibility.
# %%capture
# import torch
# from transformers import AutoModelForMultipleChoice, AutoTokenizer
# 
# # ✅ Use a model fine-tuned for multiple-choice tasks
# model_name = "LIAMF-USP/roberta-large-finetuned-race"  # Best for multiple-choice QA
# model = AutoModelForMultipleChoice.from_pretrained(model_name)
# tokenizer = AutoTokenizer.from_pretrained(model_name)
# 
# # ✅ Define the question and choices
# question = "What is the capital of France?"
# choices = ["Berlin", "Madrid", "Paris", "Rome", "London", "Lisbon", "Amsterdam", "Brussels", "Stockholm", "Vienna", "Oslo"]
# 
# # ✅ Tokenize input properly (pair each choice with the question)
# encoding = tokenizer(
#     [[question, choice] for choice in choices],  # Format: (question, choice)
#     padding=True,
#     truncation=True,
#     return_tensors="pt"
# )
# 
# # ✅ Ensure input tensor dimensions match (batch_size=1, num_choices, sequence_length)
# input_ids = encoding["input_ids"].unsqueeze(0)  # Add batch dimension
# attention_mask = encoding["attention_mask"].unsqueeze(0)
# 
# # ✅ Forward pass through model
# outputs = model(input_ids=input_ids, attention_mask=attention_mask)
# 
# # ✅ Extract logits and find the highest-scoring choice
# logits = outputs.logits
# predicted_choice = torch.argmax(logits, dim=-1).item()
# predicted_answer = choices[predicted_choice]

print(f"✅ Predicted answer: {predicted_answer}")

"""## **AutoConfig**
**AutoConfig is used to load the configuration of a model. This is often used for fine-tuning or customizing models.**
"""

from transformers import AutoConfig

# Load the model configuration for BERT
config = AutoConfig.from_pretrained("bert-base-uncased")
print(config)

"""## **10- AutoFeatureExtractor**
**AutoFeatureExtractor is used for feature extraction tasks (typically for image models).**
"""

# Commented out IPython magic to ensure Python compatibility.
# %%capture
# from transformers import AutoFeatureExtractor
# from PIL import Image
# 
# # Load a feature extractor (e.g., for image models)
# extractor = AutoFeatureExtractor.from_pretrained("facebook/dino-vitb16")
# 
# # Process an image (requires a PIL image)
# image = Image.open("/kaggle/input/car-image/car.png")
# 
# # Ensure the image is in RGB format
# image = image.convert("RGB")
# 
# # Extract features
# features = extractor(images=image, return_tensors="pt")

# Print the extracted features
print(features)

"""## **11- AutoProcessor**
**AutoProcessor is used for multimodal tasks (such as vision-language models).**
"""

from transformers import AutoProcessor
from PIL import Image

# Use a publicly available model that doesn't require a token
processor = AutoProcessor.from_pretrained("openai/clip-vit-base-patch32")

# Load an image to process
image = Image.open("/kaggle/input/car-image/car.png")  # Replace with your image file

# Process the image
inputs = processor(images=image, return_tensors="pt")

# Display the processed inputs
print(inputs)

