Abrir en Google Colab
|
Descargar notebook
|
CLIP (Contrastive Language-Image Pretraining)
El modelo CLIP (Contrastive Language-Image Pretraining) es un método de aprendizaje automático que combina la capacidad de procesamiento de lenguaje natural con la capacidad de comprender imágenes. Se trata de un enfoque innovador en el campo de la visión por computadora y el procesamiento de lenguaje natural, que utiliza una técnica de aprendizaje por comparación para entrenar un modelo que pueda entender la relación entre textos y imágenes. En otras palabras, CLIP aprende a asociar palabras y frases con las imágenes que las representan, lo que permite a los modelos desarrollados a partir de él realizar tareas como la clasificación de objetos, la detección de objetos y la generación de texto a partir de imágenes.
Preparación del ambiente
Instalemos las librerias necesarias:
[ ]:
%pip install -U transformers datasets evaluate --quiet
Recordar reiniciar la sessión si se encuentra trabajando en Google Colab.
Utilizando el modelo CLIP
Para comenzar, descargaremos el modelos preentrenado de CLIP desde HuggingFace.
[ ]:
from transformers import CLIPModel
model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32")
/usr/local/lib/python3.11/dist-packages/huggingface_hub/utils/_auth.py:94: UserWarning:
The secret `HF_TOKEN` does not exist in your Colab secrets.
To authenticate with the Hugging Face Hub, create a token in your settings tab (https://huggingface.co/settings/tokens), set it as secret in your Google Colab and restart your session.
You will be able to reuse this secret in all of your notebooks.
Please note that authentication is recommended but still optional to access public models or datasets.
warnings.warn(
Como vimos anteriormente, descargamos el modelo y el procesador de imagenes asociado al mismo. Recuerde que estos objetos en la libraría transformers nos permiten realizar el mismo procesamiento sobre las imagenes de entrada que se realizó sobre el modelo en cuestión.
[ ]:
from transformers import CLIPProcessor
processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32", use_fast=False)
Note aqui que le nombre del modelo, clip-vit-base-patch32, es un modelo base de CLIP con parches de 32x32 pixeles.
Aplicando CLIP sobre pares de imagenes y textos
Utilicemos una imagen de ejemplo:
[ ]:
from google.colab import files
from PIL import Image
from pprint import pprint
uploaded = files.upload()
for fn in uploaded.keys():
try:
img = Image.open(fn)
except Exception as e:
print(f'Error al cargar la imagen: {e}')
Saving 000000039769.jpg to 000000039769 (4).jpg
[ ]:
img
CLIP es un modelo capaz de computar la similaridad pares de textos e imagenes. Utilicemos el modelo para procesar pares de textos con una determinada imagen y ver cual de ellos se encuentra mas cercano:
[ ]:
inputs = processor(
text=["a photo of a cat", "a photo of a dog"],
images=img,
return_tensors="pt",
padding=True,
)
Donde:
text, son muestras de textos sobre los cuales computar la similaridad con la imagen. Note que podemos indicar multiples instancias como un arreglo.imagesson las muestras de imagenes sobre las cuales queremos comparar.return_tensors="pt"indica que queremos tensores para la libraria Torch.padding=Trueindica al procesador de imagenes que si es necesario, aplique padding a la imagen.
Una vez que preprocesamos nuestras entradas, podemos ejecutar el modelo:
[ ]:
outputs = model(**inputs)
outputs es un diccionario que contiene las salidas del modelo. Dentro de las mas interesantes tenemos logits_per_image, la cual contiene los coeficientes de similitud, expresados en logits (logaritmos de probabilidades).
[ ]:
logits_per_image = outputs.logits_per_image
[ ]:
logits_per_image.shape
torch.Size([1, 2])
Podemos ver que las dimensiones son tensores de 2 dimensiones, representando las [imagenes, textos]. Su computamos la función softmax sobre las entradas, podemos obtener las probabilidades asociadas a cada uno de los textos:
[ ]:
probs = logits_per_image.softmax(dim=1)
[ ]:
probs
tensor([[0.9949, 0.0051]], grad_fn=<SoftmaxBackward0>)
Esto quiere decir que hay una probabilidad mucho mayor de que la imagen este asociada con el texto en la primera posición, «a photo of a cat» vs el segundo texto, «an image of a dog».
Aplicando CLIP como un modelo de clasificación
El ejemplo anterior computó las probabilidades asociadas a cada uno de los pares de textos con una determada imagen. En este caso, nuestro modelo funciono como un «zero-shot classifier» donde las descripciones de las imagenes funcionan como etiquetas.
A pesar de la versatilidad de este modelo como «zero-shot classifier», es poco probable que su performance puede sobrepasar a un clasificador entrenado especificamente para la tarea en cuestión.
Otra forma de utilizar el modelo CLIP es utilizando sus representaciones internas correspondientes a las imagenes. De esta forma, CLIP funcionaria como un extractor de predictores sobre los cuales luego podemos entrenar una red neuronal de clasificación que resuelva el problema puntual que quremos resolver.
En HuggingFace, disponemos de la clase CLIPForImageClassification para esto:
[ ]:
from transformers import AutoImageProcessor, CLIPForImageClassification
processor = AutoImageProcessor.from_pretrained("openai/clip-vit-base-patch32", use_fast=False)
model = CLIPForImageClassification.from_pretrained("openai/clip-vit-base-patch32")
Some weights of CLIPForImageClassification were not initialized from the model checkpoint at openai/clip-vit-base-patch32 and are newly initialized: ['classifier.bias', 'classifier.weight']
You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.
Corremos nuestro preprocesamiento sobre la imagen de entrada solamente:
[ ]:
inputs = processor(img, return_tensors="pt")
Podemos utilizar el modelo directamente como un clasificador, el cual predice alguna de las clases predefinidas en ImageNext:
[ ]:
import torch
with torch.no_grad():
logits = model(**inputs).logits
[ ]:
predicted_label = logits.argmax(-1).item()
print(model.config.id2label[predicted_label])
LABEL_1
Sin embargo, podemos utilizar realizar fine tuning sobre este modelo de igual forma que hicimos sobre cualquier modelo basado en transformers. Este entrenamiento, ajustará solamente la capa lineal de clasificación sobre los estados internos (hidden layer) de la última etapa del modelo CLIP.
Por ejemplo, el siguiente codigo configuraría el modelo para clasificar solo gatos y perros:
[ ]:
id2label = { 0: "cat", 1: "dog" }
label2id = { "cat": 0, "dog": 1 }
[ ]:
cat_dog_classifier = CLIPForImageClassification.from_pretrained(
"openai/clip-vit-base-patch32", num_labels=2, id2label=id2label, label2id=label2id
)
Some weights of CLIPForImageClassification were not initialized from the model checkpoint at openai/clip-vit-base-patch32 and are newly initialized: ['classifier.bias', 'classifier.weight']
You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.
Veamos un conjunto de datos para resolver la tarea en particular:
[ ]:
from datasets import load_dataset
dataset = load_dataset("microsoft/cats_vs_dogs")
[ ]:
# Sample 10% of the dataset
dataset = dataset["train"].train_test_split(test_size=0.9)
dataset = dataset["train"]
[ ]:
dataset
Dataset({
features: ['image', 'labels'],
num_rows: 2341
})
Como es habitual, configuramos la rutina de preprocesamiento y la aplicamos sobre todo el conjunto de datos:
[ ]:
def process_example(example):
inputs = processor(example['image'], return_tensors='pt')
inputs['labels'] = example['labels']
return inputs
[ ]:
prepared_dataset = dataset.with_transform(process_example)
Luego configuramos nuestro proceso de entrenamiento:
[ ]:
from transformers import TrainingArguments, Trainer
training_args = TrainingArguments(
output_dir="./cat_dog_classifier_results",
per_device_train_batch_size=16,
num_train_epochs=3,
logging_dir="./cat_dog_classifier_logs",
logging_steps=10,
remove_unused_columns=False,
report_to="none"
)
trainer = Trainer(
model=cat_dog_classifier,
args=training_args,
train_dataset=prepared_dataset,
)
Comenzamos el proceso:
[ ]:
trainer.train()
Evaluemos la performance del modelo. Tomaremos un 5% del conjunto de datos para evaluar el modelo rapidamente.
Tip sobre como generar
test_dataset: Utilizamoe el conjunto de datos original, que tambien utilizamos para entrenamiento.shuffle()asegura que tomemos muestras aleatorias y de esta forma no tomar las mismas muestras que para entrenamiento. Luegotrain_test_split(test_size=0.95)toma un 5% de estas muestras aleatorias. El conjunto solo tiene un split, corresponiente atrain, por lo cual vemos en el codigo que siempre accedemos al split con este nombre (a pesar que lo utilicemos para validacion. Aqui el nonmbre es anecdótico).
[ ]:
test_dataset = load_dataset("microsoft/cats_vs_dogs")["train"].shuffle().train_test_split(test_size=0.95)["train"]
prepared_test_dataset = test_dataset.with_transform(process_example)
[ ]:
import evaluate
from tqdm.auto import tqdm
metric = evaluate.load("accuracy")
eval_dataloader = torch.utils.data.DataLoader(prepared_test_dataset, batch_size=16)
for batch in tqdm(eval_dataloader):
with torch.no_grad():
outputs = cat_dog_classifier(**batch)
logits = outputs.logits
predictions = torch.argmax(logits, dim=-1)
metric.add_batch(predictions=predictions, references=batch["labels"])
print(metric.compute())
{'accuracy': 0.9282051282051282}
Conclusiones
En conclusión, el modelo CLIP de OpenAI ha revolucionado el campo multimodal. Lo que distingue a CLIP es su dominio del aprendizaje de disparo cero, lo que le permite clasificar imágenes en categorías para las que no fue entrenado explícitamente. Esta notable capacidad de generalización se debe a su innovador método de entrenamiento, donde aprende a relacionar imágenes con subtítulos de texto.
Abrir en Google Colab
Descargar notebook