👁️ ViT (Vision Transformer) – Le Guide Ultime
Deep Dive : La fin des CNNs ? "An Image is Worth 16x16 Words", Patches, 🚀 Self-Attention & [CLS] Token.
1. C'est quoi ViT ?
Vision Transformer (Google, 2020). La 1ère architecture qui a battu les CNNs (ResNet).
ViT Transformer2. Philosophie : "Une image = Mots"
Le "plugin" clé. Traiter une image non pas comme des pixels (CNN), mais comme une *séquence de patchs* (NLP).
NLP Patches3. 📈 Architecture (Patches)
Image -> Patches (16x16) -> Projection Linéaire -> + Positional Embedding.
Patch Embedding Positional Embedding4. Le "Plugin" [CLS] Token
Un "token" (plugin) *apprenable* ajouté à la séquence. L'état final de ce token est la prédiction.
[CLS] Token BERT5. Le Bloc : Transformer Encoder
L'architecture de "Attention Is All You Need". Multi-Head Self-Attention (MHSA) + MLP.
Encoder Self-Attention6. 🚀 Self-Attention (Q, K, V)
La "magie". Query, Key, Value. Permet à chaque patch de "regarder" *tous* les autres patches.
Q K V Attention7. 📊 CNN vs ViT (Le Choc)
Inductive Bias (CNN) vs Scaling (ViT). ViT est "data-hungry" (affamé de données).
CNN vs ViT Inductive Bias8. Le "Plugin": Pré-training Massif
ViT ne bat ResNet que s'il est pré-entraîné sur >100M images (JFT-300M).
JFT-300M Data-Hungry9. Code (PyTorch / timm)
pip install timm. timm.create_model('vit_base_patch16_224'). L'addon (plugin) n°1.
10. Code (Keras / TF)
tf.keras.applications.ViT() n'existe PAS (officiellement). KerasCV ou Hugging Face.
11. Addons & Dérivés
DeiT (Data-efficient), Swin (Windows/Hiérarchie), MAE (Self-Supervised).
DeiT Swin MAE12. Projets & Liens
Projets (Vision, Médical). Liens (Papier, HF, timm).
ViT (Vision Transformer) est une architecture de modèle de vision (IA) publiée par Google Brain en 2020 (papier : "An Image is Worth 16x16 Words").
C'est le *deuxième* "Big Bang" de la Computer Vision (après AlexNet en 2012).
AlexNet (2012) a prouvé que les CNNs (Réseaux Convolutifs) étaient l'avenir.
ViT (2020) a prouvé que les CNNs n'étaient *pas* nécessaires, et que l'architecture Transformer (venue du NLP/Langage, ex: BERT, GPT) pouvait *battre* les CNNs (comme ResNet) sur les tâches de vision.
ViT a lancé la "guerre" CNN vs Transformers en Computer Vision, et les Transformers sont en train de gagner (ex: Swin, ViT v2).
Le "plugin" (l'idée) de ViT est radical : et si on arrêtait de traiter une image comme une grille 2D de pixels (CNN) et qu'on la traitait comme une séquence 1D de "mots" (NLP) ?
1. Approche CNN (ResNet, VGG)
"Localité". Un filtre 3x3 "glisse" sur l'image. Le réseau "voit" d'abord les bords, puis les formes, puis les objets.
(Image 224x224)
|
▼
[Conv 3x3] -> [Pool]
|
▼
[Conv 3x3] -> [Pool]
|
▼
(Output: "Chat")
2. Approche ViT (Transformer)
"Global". On découpe l'image en "patchs" (des "mots"), et on les traite comme une *phrase*.
(Image 224x224)
|
▼
[Découpe en 196 "Patches" de 16x16]
|
▼
[Transformer (Self-Attention)]
(Chaque patch "regarde" TOUS les autres)
|
▼
(Output: "Chat")
Un Transformer (NLP) attend une "séquence de tokens" (des vecteurs 1D). Comment transformer une image (3D : H, W, C) en séquence 1D ?
C'est le "plugin" (l'astuce) Patch Embedding.
Diagramme (Patch Embedding)
# Input: Image (1, 3, 224, 224) # (Batch, Canaux, Hauteur, Largeur) # 1. Découpage en "Patches" (16x16) # (224 / 16 = 14) -> On obtient 14x14 = 196 patchs # Chaque patch = (3, 16, 16) # 2. "Aplatir" (Flatten) chaque patch # (3 * 16 * 16) = 768 # -> (196, 768) # 3. "Plugin": Projection Linéaire (une couche Conv2D "hackée") # (On projette 768 -> 768 (ou "D", la dimension du modèle)) # (C'est l'équivalent du "Token Embedding" en NLP) # -> (Séquence: 196, 768) # 4. Ajout du Positional Embedding # (Problème: "Patches" n'a pas d'ordre. On *ajoute* un vecteur "apprenable" # qui dit "Tu es le patch N°1", "Tu es le patch N°2"...) # -> (Séquence: 196, 768) # 5. Ajout du [CLS] Token (voir 1.4) # (On ajoute un token "fictif" au début) # -> (Séquence: 197, 768)
C'est un "plugin" (concept) hérité de BERT (le grand modèle de langage de Google).
Le Problème
L'Encoder Transformer (voir 1.5) va "mélanger" l'information entre tous les 196 "patchs". À la fin, on se retrouve avec 196 vecteurs "riches" (196, 768).
*Lequel* utiliser pour la classification (dire "Chat") ?
- Faire la moyenne (Avg Pooling) ? (GoogleNet) - Prendre le premier ? Le dernier ?
La Solution : Le Token [CLS] (Classification)
ViT ajoute un "patch" (plugin) *fictif* et *apprenable* (un vecteur) au tout début de la séquence (avant les 196 patchs d'image).
Ce token [CLS] (position 0) n'a "pas d'image". Il est *conçu* (pendant l'entraînement) pour que le Transformer (via Self-Attention) y *agrège* toute l'information "globale" de l'image.
Diagramme (Tête de Classification)
(Input Séquence: 197, 768)
|
▼
[ N x Blocs Transformer Encoder ]
|
▼
(Output Séquence: 197, 768)
|
▼
[ EXTRAIRE LE PREMIER TOKEN (le [CLS]) ]
|
▼
(Vecteur: 1, 768)
|
▼
[ Tête MLP (Couche Dense) ]
|
▼
(Output: 1, 1000) (Classification)
Le "corps" de ViT n'est *pas* un CNN. C'est une pile (ex: 12x) du "plugin" Transformer Encoder (défini dans le papier "Attention Is All You Need" de 2017).
Diagramme (Bloc Encoder)
(Input Séquence: 197, 768)
|
+-------------(Skip Connection)-------------+
| |
▼ |
[ Layer Norm ] |
| |
▼ |
[ Multi-Head Self-Attention (MHSA) ] (voir 1.6) |
| |
▼ |
+-----------------[ ADD ] <-----------------+
|
+-------------(Skip Connection)-------------+
| |
▼ |
[ Layer Norm ] |
| |
▼ |
[ MLP (Feed-Forward) ] (2x Couches Dense) |
| |
▼ |
+-----------------[ ADD ] <-----------------+
|
▼
(Output Séquence: 197, 768)
Note : ViT utilise la "pré-normalisation" (Layer Norm *avant* l'attention), ce qui stabilise l'entraînement.
C'est la "magie" du Transformer. L'Auto-Attention (Self-Attention) est le "plugin" qui permet à ViT de *peser* l'importance de chaque "patch" (mot) par rapport à tous les autres.
L'Analogie (Recherche de Base de Données)
L'Attention est (basiquement) une recherche "soft" (floue) dans une base de données (clé/valeur).
| Matrice | Rôle (Analogie) |
|---|---|
Query (Q) (Requête) | "Ce que je suis" (ex: le patch "oreille de chat"). |
Key (K) (Clé) | "Ce que je possède" (ex: "Je suis un patch 'œil de chat'"). |
Value (V) (Valeur) | "Ce que je vaux" (l'information que je détiens). |
Le Flux (Simplifié)
- On prend notre séquence (197, 768).
- On la projette (via 3x
nn.Linear) en 3 matrices : Q, K, V. - (Attention) On calcule le "Score" :
MatMul(Q, K.Transpose). (Chaque "patch" (Q) est comparé à *tous* les autres "patchs" (K)). - (Softmax) On normalise les scores (pour que la somme = 1).
- (Output) On multiplie les scores (le "poids" d'attention) par les Values (V).
Résultat : Le "patch" de l'oreille de chat "regarde" tous les autres, voit que le "patch" de l'œil est très important (score élevé), et "absorbe" l'information de ce patch (sa "Value"). Il apprend le *contexte global*.
La plus grande différence entre CNN (ResNet) et ViT (Transformer) est l'Inductive Bias (Biais Inductif).
| Critère | CNN (ResNet, VGG) | ViT (Transformer) |
|---|---|---|
| Inductive Bias (Le "Plugin") | FORT. (Locality, Translation Equivariance). | FAIBLE. (Ne suppose *rien* sur l'image). |
| Explication | Un CNN est *conçu* pour la vision. Le filtre 3x3 (plugin) *sait* qu'il doit chercher des features locales (pixels voisins) et les partager (le même filtre partout). | Un ViT ne sait *rien*. Il traite l'image comme un "sac de patchs" (mots). Il doit *apprendre* la localité (que le patch 1 est à côté du 2) de zéro. |
| "Faim" (Data) | Faible. (Marche bien sur des *petits* datasets (ex: 10K images) grâce à son "plugin" (biais)). | Data-Hungry (Affamé). (Sur 10K images, ViT est *nul*. Il n'apprend rien). |
| Scaling | Plafonne (ResNet). | Ne plafonne pas. Si on lui donne plus de données (100M, 300M, 1B), il *continue* de s'améliorer (voir 2.2). |
Quand Google a testé ViT sur ImageNet (1.1M images), il était *moins bon* que ResNet (à cause du manque d'Inductive Bias).
Le "plugin" (l'astuce) de Google a été d'utiliser leur dataset *privé* (non-public) : JFT-300M.
| Dataset (Plugin) | Taille (Images) | Résultat (ViT vs ResNet) |
|---|---|---|
| ImageNet | 1.1 Million | ResNet (CNN) gagne. (ViT est "data-hungry"). |
| ImageNet-21k | 14 Millions | ViT rattrape ResNet. |
| JFT-300M | 300 Millions | ViT *pulvérise* ResNet. |
Conclusion : L'architecture Transformer (ViT) est *meilleure* (plus "scalable") que les CNNs, *à condition* d'avoir un "plugin" (un dataset) d'une taille absurde (100M+) pour lui apprendre la "vision" de zéro.
torchvision (le "plugin" officiel) a models.vit_b_16().
Mais le "vrai" addon (plugin) de la communauté PyTorch pour *tous* les modèles de vision (ViT, ResNet, EfficientNet...) est timm (PyTorch Image Models) par Ross Wightman.
Installation (Addon timm)
(venv) $ pip install timm
Exemple (Inférence timm)
import torch
import timm
from PIL import Image
# 1. Lister les "plugins" (modèles) ViT disponibles
print(timm.list_models('*vit*'))
# 2. Créer le modèle (Base, Patch 16x16, Input 224x224)
model = timm.create_model('vit_base_patch16_224', pretrained=True)
model.eval()
# 3. Obtenir la config (transforms) du modèle
data_config = timm.data.resolve_model_data_config(model)
transforms = timm.data.create_transform(**data_config, is_training=False)
# 4. Charger l'image
img = Image.open("image.jpg")
tensor = transforms(img).unsqueeze(0) # (Ajoute batch dim)
# 5. Inférence
with torch.no_grad():
output = model(tensor)
# (output est [1, 1000] (logits ImageNet))
Contrairement à ResNet/VGG, ViT n'est *pas* (encore) un "plugin" (application) standard dans tf.keras.applications.
Pour utiliser ViT (SOTA) avec Keras, il y a deux "plugins" (méthodes) :
1. KerasCV (L'écosystème "vision" moderne de Keras).
2. Hugging Face Transformers (l'addon n°1 pour TF/PyTorch).
Exemple (Plugin Hugging Face transformers)
# (Nécessite: pip install transformers tensorflow)
from transformers import ViTImageProcessor, TFViTForImageClassification
from PIL import Image
# 1. Charger le "processor" (plugin de transforms) et le Modèle
processor = ViTImageProcessor.from_pretrained('google/vit-base-patch16-224')
model = TFViTForImageClassification.from_pretrained('google/vit-base-patch16-224')
# 2. Charger l'image
img = Image.open("image.jpg")
# 3. Pré-processer
inputs = processor(images=img, return_tensors="tf")
# 4. Inférence
outputs = model(**inputs)
logits = outputs.logits
# 5. Interpréter
predicted_class_id = int(tf.math.argmax(logits, axis=-1)[0])
print(model.config.id2label[predicted_class_id])
ViT (2020) a créé une "explosion" de recherche (comme ResNet). Les "plugins" (dérivés) ont cherché à corriger son principal défaut : être "data-hungry" (voir 2.1).
| Modèle (Addon) | Auteur | Innovation (Le "Plugin") |
|---|---|---|
| DeiT (Data-efficient ViT) | Facebook (Meta) | "Distillation Token". Entraîne le ViT (l'"étudiant") à imiter un *CNN* (le "professeur", ex: ResNet) sur ImageNet. Résultat : Un ViT qui marche bien *sans* JFT-300M. |
| Swin Transformer | Microsoft | "Shifted Windows" (Fenêtres glissantes). Compromis CNN/ViT. Calcule l'Attention *localement* (dans une "fenêtre" 7x7), puis "décale" (shift) la fenêtre à la couche suivante. Résultat : Efficacité (linéaire, pas quadratique). SOTA pour la Détection/Segmentation. |
| MAE (Masked Autoencoders) | Facebook (Meta) | Self-Supervised Learning (SSL). Le "BERT" de la vision. Cache 75% des "patchs" (plugin) et entraîne le ViT à les *reconstruire*. Résultat : Apprend la "vision" sans *aucun* label. |
Exemples de Projets
- Transfer Learning (Standard) : Utiliser un
ViT-Base(pré-entraîné sur ImageNet-21k, via le "plugin"timm) pour du "fine-tuning" (voir ResNet 2.3) sur un dataset custom (ex: classification médicale, industrielle). - Backbone (Segmentation) : Utiliser un Swin Transformer (dérivé de ViT) comme "plugin" (backbone) pour un U-Net (voir U-Net 3.2) ou un Mask R-CNN (voir 1.5).
