# Extraction de caractéristiques d'image

L’extraction de caractéristiques d’images consiste à extraire des caractéristiques sémantiquement significatives à partir d’une image. Cette tâche présente de nombreuses applications, notamment la similarité d’images et la récupération d’images. De plus, la plupart des modèles de vision par ordinateur peuvent être utilisés pour l’extraction de caractéristiques d’images : il suffit de retirer la tête spécifique à la tâche (classification d’images, détection d’objets, etc.) pour obtenir les caractéristiques. Ces caractéristiques sont très utiles à un niveau supérieur : détection de contours, détection de coins, etc. Elles peuvent également contenir des informations sur le monde réel (par exemple, à quoi ressemble un chat), selon la profondeur du modèle. Par conséquent, ces sorties peuvent être utilisées pour entraîner de nouveaux classifieurs sur un jeu de données spécifique.

Dans ce guide, vous allez :

- Apprenez à construire un système simple de similarité d’images à partir du pipeline `image-feature-extraction`.
- Accomplir la même tâche avec une inférence sur le modèle brut.

## Similarité d'images à l'aide du pipeline `image-feature-extraction`

Nous disposons de deux images de chats assis sur des filets de pêche, dont une est générée.

```python
from PIL import Image
import requests

img_urls = ["https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/cats.png", "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/cats.jpeg"]
image_real = Image.open(requests.get(img_urls[0], stream=True).raw).convert("RGB")
image_gen = Image.open(requests.get(img_urls[1], stream=True).raw).convert("RGB")
```

Passons le pipeline en action. Tout d'abord, initialisez le pipeline. Si vous ne lui transmettez aucun modèle, le pipeline sera automatiquement initialisé avec [google/vit-base-patch16-224](https://huggingface.co/google/vit-base-patch16-224). Si vous souhaitez calculer la similarité, définissez `pool` sur True.

```python
import torch
from transformers import pipeline
from accelerate import Accelerator
# automatically detects the underlying device type (CUDA, CPU, XPU, MPS, etc.)
device = Accelerator().device
pipe = pipeline(task="image-feature-extraction", model="google/vit-base-patch16-384", device=device, pool=True)
```

Pour effectuer une inférence avec `pipe`, passez-lui les deux images.

```python
outputs = pipe([image_real, image_gen])
```

La sortie contient les embeddings agrégés de ces deux images.

```python
# get the length of a single output
print(len(outputs[0][0]))
# show outputs
print(outputs)

# 768
# [[[-0.03909236937761307, 0.43381670117378235, -0.06913255900144577,
```

Pour obtenir le score de similarité, nous devons les transmettre à une fonction de similarité.

```python
from torch.nn.functional import cosine_similarity

similarity_score = cosine_similarity(torch.Tensor(outputs[0]),
                                     torch.Tensor(outputs[1]), dim=1)

print(similarity_score)

# tensor([0.6043])
```

Si vous souhaitez obtenir les derniers états cachés avant le pooling, évitez de passer une valeur au paramètre `pool`, car il est défini sur `False` par défaut. Ces états cachés sont utiles pour entraîner de nouveaux classifieurs ou modèles basés sur les caractéristiques issues du modèle.

```python
pipe = pipeline(task="image-feature-extraction", model="google/vit-base-patch16-224", device=device)
outputs = pipe(image_real)
```

Comme les sorties ne sont pas agrégées, nous obtenons les derniers états cachés, dont la première dimension correspond à la taille du lot et les deux dernières à la forme de l'embedding.

```python
import numpy as np
print(np.array(outputs).shape)
# (1, 197, 768)
```

## Obtenir les fonctionnalités et les similarités à l'aide de `AutoModel`

Nous pouvons également utiliser la classe `AutoModel` de transformers pour obtenir les caractéristiques. `AutoModel` charge n’importe quel modèle de transformers sans tête spécifique à une tâche, et nous pouvons l’utiliser pour extraire les caractéristiques.

```python
from transformers import AutoImageProcessor, AutoModel

processor = AutoImageProcessor.from_pretrained("google/vit-base-patch16-224")
model = AutoModel.from_pretrained("google/vit-base-patch16-224").to(device)
```

Écrivons une fonction simple pour l'inférence. Nous transmettrons d'abord les entrées au `processor`, puis ses sorties au `model`.

```python
def infer(image):
  inputs = processor(image, return_tensors="pt").to(device)
  outputs = model(**inputs)
  return outputs.pooler_output
```

Nous pouvons passer directement les images à cette fonction pour obtenir les embeddings.

```python
embed_real = infer(image_real)
embed_gen = infer(image_gen)
```

Nous pouvons à nouveau obtenir la similarité sur les embeddings.

```python
from torch.nn.functional import cosine_similarity

similarity_score = cosine_similarity(embed_real, embed_gen, dim=1)
print(similarity_score)

# tensor([0.6061], device='cuda:0', grad_fn=<SumBackward1>)
```

