An introduction to deep learning
Jeremy Fix
November 13, 2024
Slides made with slidemakerCependant, l’apprentissage est généralement (sauf pour les CNNs) difficile. Et les SVMs arrivent dans les années 1990… : deuxième hiver
Pour une revue historique : (Schmidhuber, 2015)
Voir aussi l’apprentissage profond par renforcement : Atari / AlphaGO / AlphaStar / AlphaChem; réseaux de neurones de graphes, etc.
Quelques raisons du succès actuel :
De très bons frameworks facilitent grandement l’entraînement et le déploiement des réseaux de neurones :
Quelques grands contributeurs au domaine :
Quelques conférences majeures en apprentissage machine : NIPS/NeurIPS, ICLR, CVPR, (ICML, ICASSP, ..)
Ressources en ligne :
TPs : sur le DCE/clusters GPU (1080, 2080 Ti, pytorch).
warning On utilise dcejs. Vous devez l’installer et le tester avant les TPs. Si vous avez des soucis, contactez moi
Note de contrôle continu sur les TPs, en particulier “Segmentation sémantique” : rendu expérimental. Date limite ? avant les vacances de Noel ?
Examen final mutualisé avec AS + DL (modalités bientôt précisées)
Un réseau de neurones est un graphe orienté :
Il existe deux catégories de graphes :
Mais pourquoi s’intéresser aux réseaux de neurones convolutionnels avec une sortie softmax, des activations cachées ReLu, une perte cross entropy, des couches de batch normalization, entraînés avec RMSprop avec le momentum de Nesterov, régularisés avec dropout ?
Problème : Étant donné \((x_i, y_i)\), \(x_i\in\mathbb{R}^{n+1}, y_i \in \mathbb{R}\)
Proposé par (Widrow & Hoff, 1962) : AdaLine
La régression linéaire est convexe.
D’autres choix peuvent également être envisagés (perte de Huber, MAE, …).
Possiblement régularisée (mais plus de détails sur la régularisation plus tard).
Problème : Étant donné \((x_i, y_i)\), \(x_i\in\mathbb{R}^{n+1}, y_i \in \{0, 1\}\)
Modèle logit linéaire : \(o(x) = w^Tx\) (nous supposons toujours \(x[0] = 1\) pour le biais)
Fonction de transfert sigmoïde : \(\hat{y}(x) = p(x; w) = \sigma(o(x)) = \sigma(w^T x)\)
La régression logistique est convexe.
Problème : Étant donné \((x_i, y_i)\), \(x_i\in\mathbb{R}^{n+1}, y_i \in [|0, K-1|]\)
Supposons un \(P(y=y_i | x_i) = f_\theta(x_i, y_i)\) paramétrique. La vraisemblance conditionnelle des étiquettes se lit :
\[ \mathcal{L}(w) = \prod_i P(y=y_i | x_i) \]
Avec l’estimation du maximum de vraisemblance, nous minimisons plutôt la log-vraisemblance négative moyenne :
\[ J(w) = -\frac{1}{N} \log(\mathcal{L}(w)) = -\frac{1}{N} \sum_i \log(P(y=y_i | x_i)) \]
Avec un encodage one-hot de la classe cible (c’est-à-dire \(y_i = [0, ..., 0, 1, 0, .. ]\)), cela peut s’écrire :
\[ J(w) = -\frac{1}{N} \log(\mathcal{L}(w)) = -\frac{1}{N} \sum_i \sum_c y_c \log(P(y=c | x_i)) \]
Problème : Étant donné \((x_i, y_i)\), \(x_i\in\mathbb{R}^{n+1}, y_i \in [|0, K-1|]\)
La régression Softmax est convexe.
Éviter les grands exponentiels
Si vous calculez naïvement le softmax, vous obtiendrez \(\exp(..)\) qui devient rapidement grand.
Heureusement :
\[ softmax(o_1, o_2, o_3, ..) = softmax(o_1 - o^\star, o_2 - o^\star, o_3-o^\star) = \frac{\exp(o_i - o^\star)}{\sum_j \exp(o_j - o^\star)} \]
Vous calculez toujours \(\exp(z)\) avec \(z \leq 0\).
Éviter certains exponentiels avec le truc log-sum-exp \(\log(\sum_j \exp(o_j)) = o^\star + \log(\sum_j \exp(o_j-o^\star))\)
Vous n’avez pas vraiment besoin de calculer le \(\log(\hat{y}_j) = \log(softmax_j(x)))\) puisque :
\[ \log(\hat{y}_i) = \log(\frac{\exp(o_i-o^\star)}{\sum_j \exp(o_j - o^\star)}) = o_i - o^\star - \log(\sum_j \exp(o_j - o^\star)) \]
En pratique, cela explique pourquoi nous utilisons la perte d’entropie croisée avec des sorties logits plutôt que Softmax + log-vraisemblance négative ou même LogSoftMax + NLLLoss (ce qui n’a pas le log… ouais, confus…)
Notre objectif est de minimiser le risque réel de la fonction de perte par rapport aux paramètres du réseau de neurones :
\[ argmin_\theta E_{X,Y \sim P_{X,Y}}[L(f_\theta(x), y)] \]
En général, nous avons un ensemble fini d’échantillons \((x_i, y_i)\), pas la densité \(P_{X,Y}\). Par conséquent, nous procédons par :
\[\frac{1}{N}\sum_{x_i,y_i} L(f_\theta(x_i), y_i)\]
Nous effectuons cette optimisation par descente de gradient.
\[J(w,x,y) = \frac{1}{N} \sum_{i=1}^N L(w,x_i,y_i)\] par exemple \(L(w,x_i,y_i) = ||y_i - w^T x_i||^2\)
Mini-lot
\[ w_{t+1} = w_t - \epsilon_t \textcolor{red}{\frac{1}{M} \sum_{j \in \mathcal{J}} \nabla_w L(w,x_j,y_j)} \]
Calculer le gradient dans un réseau de neurones implique :
différenciation par mode inverse (règle de la chaîne) \(\frac{\partial y_n}{\partial y_1} = \frac{\partial y_n}{\partial y_{n-1}}\frac{\partial y_{n-1}}{\partial y_{n-2}}\cdots\frac{\partial y_2}{\partial y_1}\)
appliqué sur un graphe computationnel warning
Le graphe computationnel est une notion centrale dans les réseaux de neurones modernes/apprentissage profond. Élargissez le champ avec la programmation différentiable.
Ces dernières années, des blocs différentiables plus “sophistiqués” autres que \(f(W f(W..))\), et qui sont construits dynamiquement (mode eager vs graphe statique).
Réseaux de transformateurs spatiaux
(Jaderberg, Simonyan,
& Zisserman, 2015)
Adressage basé sur le contenu/la localisation
Machine de Turing Neurale / Ordinateur Neuronal Différentiable (Graves et al.,
2016)
Le Problème Fondamental de l’Apprentissage Profond a été observé pour la première fois par (Josef Hochreiter, 1991) pour les RNN. Le gradient peut soit disparaître, soit exploser, surtout dans les réseaux profonds (les RNN sont très profonds).
Algorithme canonique
Rationnel (développement de Taylor) : \(L(\theta_{t+1}) \approx L(\theta_{t}) + (\theta_{t+1} - \theta_{t})^T \nabla_{\theta} L(\theta_{t})\)
Variantes
Étapes générales :
Entraînement
0- Imports
1- Chargement des données
2- Définir le réseau
3- Définir la perte, l’optimiseur, les callbacks, …
4- Itérer et surveiller
Test
0- Imports
1- Chargement des données
2- Définir le réseau et charger les paramètres entraînés
3- Définir la perte
4- Itérer
0- Imports
import torch
import torch.nn as nn
import torch.optim as optim
import sklearn
import sklearn.datasets
import tqdm
import matplotlib.pyplot as plt
1- Chargement des données
# Chargement des données
data = sklearn.datasets.fetch_california_housing()
# X is (20640, 8), y is (20640, )
X, y = data.data, data.target
# La normalization facilite la descente de gradient
mean, std = X.mean(axis=0), X.std(axis=0)
X = (X - mean)/std
X_train = torch.tensor(X).float()
y_train = torch.tensor(y).float()
# Un dataset est un objet indexable (__getitem__) et
# dont on peut demander la taille (__len__)
train_dataset = torch.utils.data.TensorDataset(X_train, y_train)
# A dataloader will create the minibatches
train_dataloader = torch.utils.data.DataLoader(train_dataset,
batch_size=64,
shuffle=True,
pin_memory=True)
Doc: Dataset, DataLoader. Pin memory
Itérer sur le train_dataloader fourni des paires de tenseur de taille \((64, 8)\) et \((64, )\)
2- Définition du réseau
if torch.cuda.is_available():
device = torch.device('gpu')
else:
device = torch.device('cpu')
# Construction du modèle
Nh = 64
model = nn.Linear(8, 1)
model.to(device)
Doc: Linear, Sequential
3- Définition de la perte, optimiseur, callbacks
4- Itération et monitoring
for e in range(num_epochs):
# On passe le réseau en mode "entrainement"
model.train()
print(f"Epoch {e}")
for X, y in tqdm.tqdm(train_dataloader):
# Send the data to the GPU if necessary
X, y = X.to(device), y.to(device)
# Reset the gradient accumulator
optimizer.zero_grad()
# Forward pass
y_pred = model(X).squeeze()
loss_value = loss(y_pred, y)
# Backward pass
loss_value.backward()
# Weight update
optimizer.step()
print(f"MSELoss on the training set : {mseloss(train_dataloader)}")
# Adaptation du taux d'apprentissage
scheduler.step()
Évaluation
def mseloss(loader):
# Estimation du risque réel après
# chaque epoch
cum_loss = 0.0
n_samples = 0
# Passage du modèle en mode évaluation
model.eval()
with torch.no_grad():
for X, y in tqdm.tqdm(loader):
X, y = X.to(device), y.to(device)
# Passe forward
y_pred = model(X).squeeze()
loss_value = loss(y_pred, y)
# La perte est moyennée, donc on la dénormalise
# avant de l'intégrer
cum_loss += loss_value * y_pred.size()[0]
n_samples += y_pred.size()[0]
return cum_loss/n_samples
Les prédicteurs linéaires vus précédemment réalisent leurs prédictions sur un espace d’attributs (feature space) prédéfinis, fixés.
Peux t’on apprendre cet espace d’attributs \(\phi_j(x)\) ?
\[ \begin{eqnarray*} \phi(x) = \begin{pmatrix} 1 \\ \exp{\frac{-||x-\mu_0||^2}{2\sigma_0^2}} \\ \vdots\\ \exp{\frac{-||x-\mu_{N_a-1}||^2}{2\sigma_{N_a-1}^2}} \\ \end{pmatrix} \end{eqnarray*} \]
Régression
Classification binaire
Classification mutli-classes
On sait apprendre les poids \(w\) : descente de gradient minibatch
Comment fixer les centres et variances ? (Schwenker, Kestler, & Palm, 2001)
On les réparti uniformément ou aléatoirement, ou par quantification vectorielle (K-means++(Arthur & Vassilvitskii, 2007), GNG (Fritzke, 1994))
on fixe les centre/variances, on apprends les poids, on apprends tout ! (\(\nabla_{\mu} L, \nabla_{\sigma} L, \nabla_w L\))
Théorème : Approximateur universel (Park & Sandberg, 1991)
Notons \(\mathcal{S}\) la famille de
fonctions basées sur des RBF \(\mathbb{R}^d\): \[\mathcal{S} = \{g \in \mathbb{R}^d \to
\mathbb{R}, g(x) = \sum_i w_i K(\frac{x-\mu_i}{\sigma}), w \in
\mathbb{R}^N\}\] avec \(K :
\mathbb{R}^d \rightarrow \mathbb{R}\) continue presque partout et
\(\int_{\mathbb{R}^d}K(x)dx \neq
0\),
Alors \(\mathcal{S}\) est dense dans
\(L^p(\mathbb{R})\) pour tout \(p \in [1, \infty)\)
En particulier, cela s’applique aux RBFs à noyau gaussien \(K(x) = exp(-\frac{1}{2}x^2)\)
Vocabulaire
Un réseau FFNs avec \(1\) couche cachée est un approximant universel.
Les ReLu sont plus favorables au flux de gradient que les fonctions saturantes (plus de détails à ce sujet plus tard, lors de la discussion des graphes computationnels et du calcul du gradient).
Exactement comme lorsque nous avons discuté des RBF, cela dépend de la tâche.
Régression
Classification binaire
Classification multi-classes
En effet :
\[ \begin{align*} & \begin{bmatrix} \\ x \\ \phantom{} \end{bmatrix}\\ \begin{bmatrix} & & \\ & W_1 & \\ & & \phantom{} \end{bmatrix} & \begin{bmatrix} \\ y_1 \\ \phantom{} \end{bmatrix} \end{align*} \]
\[ \begin{align*} & \begin{bmatrix} \\ f(y_1) \\ \phantom{} \end{bmatrix}\\ \begin{bmatrix} & & \\ & W_2 & \\ & & \phantom{} \end{bmatrix} & \begin{bmatrix} \\ y_2 \\ \phantom{} \end{bmatrix} \end{align*} \]
Mais empiriquement, la plupart des minimums locaux sont proches (en performance) du minimum global, surtout avec des réseaux larges/profonds. Voir (Dauphin et al., 2014), (Pascanu, Dauphin, Ganguli, & Bengio, 2014), (Choromanska, Henaff, Mathieu, Arous, & LeCun, 2015). Les points selles semblent être plus critiques.
Algorithme
Rationnel (développement de Taylor) : \(L(\theta_{t+1}) \approx L(\theta_{t}) + (\theta_{t+1} - \theta_{t})^T \nabla_{\theta} L(\theta_{t})\)
Le choix de la taille du batch :
L’optimisation peut converger lentement ou même diverger si le taux d’apprentissage \(\epsilon\) n’est pas approprié.
Bengio : “Le taux d’apprentissage optimal est
généralement proche du plus grand taux d’apprentissage qui ne provoque
pas la divergence du critère d’entraînement” (Bengio, 2012)
Karpathy “\(0.0003\) est le meilleur taux d’apprentissage pour Adam, sans hésitation.” (Twitter, 2016)
(Note : Adam sera discuté dans quelques diapositives)
Voir aussi :
- Recommandations pratiques pour l’entraînement basé sur le gradient des
architectures profondes (Bengio, 2012)
- Backpropagation efficace (Y. A. LeCun et al., 1998)
Configuration
Paramètres : \(\epsilon=0.005\), \(\theta_0 = \begin{bmatrix} 10 \\ 5\end{bmatrix}\)
Converge vers \(\theta_{\infty} = \begin{bmatrix} 1.9882 \\ 2.9975\end{bmatrix}\)
Algorithme : Atténuons les oscillations avec un filtrage passe-bas sur \(\nabla_{\theta}\)
En général, \(\mu \approx 0.9\) ou \(0.99\).
Voir aussi distill.pub. Notez que les frameworks peuvent implémenter des variations subtiles.
Paramètres : \(\epsilon=0.005\), \(\mu=0.6\), \(\theta_0 = \begin{bmatrix} 10 \\ 5\end{bmatrix}\)
Converge vers \(\theta_{\infty} = \begin{bmatrix} 1.9837 \\ 2.9933\end{bmatrix}\)
Idée Anticiper pour potentiellement corriger la mise à jour. Basé sur le gradient accéléré de Nesterov. Formulation de (Sutskever, Martens, Dahl, & Hinton, 2013)
Algorithme
Paramètres : \(\epsilon=0.005\), \(\mu=0.8\), \(\theta_0 = \begin{bmatrix} 10 \\ 5\end{bmatrix}\)
Converge vers \(\theta_{\infty} = \begin{bmatrix} 1.9738 \\ 2.9914\end{bmatrix}\)
Sur notre simple problème de régression
Vous devriez toujours adapter votre taux d’apprentissage avec un planificateur de taux d’apprentissage
Certaines approches récentes changent l’idée de “diminution du taux d’apprentissage” (“conditions de Robbins-Monro”)
Voir (Smith, 2018), The 1cycle policy - S. Gugger
Descente de Gradient Stochastique avec Redémarrage (Loshchilov & Hutter, 2017)
Les meilleures performances peuvent être liées à l’atteinte de minimums plus plats (c’est-à-dire avec des prédictions moins sensibles que des minimums plus aigus). Les modèles atteints avant les redémarrages peuvent être moyennés (voir Snapshot ensemble).
Il semble également que des taux d’apprentissage initiaux élevés conduisent à de meilleurs modèles à long terme (Y. Li, Wei, & Ma, 2019).
Adagrad Gradient adaptatif (Duchi, Hazan, & Singer, 2011)
Le \(\sqrt{.}\) est expérimentalement critique ; \(\delta \approx [1e-8, 1e-4]\) pour la stabilité numérique.
Petits gradients \(\rightarrow\)
plus grand taux d’apprentissage pour avancer rapidement dans les
directions plates
Grands gradients \(\rightarrow\) plus
petit taux d’apprentissage pour calmer la descente dans les directions à
forte courbure.
Mais l’accumulation depuis le début est trop agressive. Les taux d’apprentissage diminuent trop rapidement.
RMSprop Hinton (non publié, Coursera)
Idée : nous devrions utiliser une moyenne mobile exponentielle lors de l’accumulation du gradient.
Moments adaptatifs (ADAM) (Kingma & Ba, 2015)
\[ \theta(t+1) = \theta(t) - \frac{\epsilon}{\delta + \sqrt{\hat{v}(t+1)}} \hat{m}(t+1) \]
et d’autres méthodes : Adadelta (Zeiler, 2012), …, YellowFin (Zhang & Mitliagkas, 2018).
Voir le billet de blog de Sebastian Ruder, ou le billet de blog de John Chen
(Goodfellow, Bengio, & Courville, 2016) Il n’y a actuellement pas de consensus […] aucun algorithme unique n’a émergé comme le meilleur […] les plus populaires et couramment utilisés incluent SGD, SGD avec momentum, RMSprop, RMSprop avec momentum, Adadelta et Adam.
Voir aussi Chap. 8 de (Goodfellow et al., 2016)
XOR est facile, non ?
Mais cela échoue lamentablement (6/20 échecs). Tmax=1000
XOR est facile, non ?
Maintenant, c’est mieux (0/20 échecs). Tmax=1000
La descente de gradient converge plus rapidement si vos données sont normalisées et décorrélées. Notez \(x_i \in \mathbb{R}^d\) comme étant vos données d’entrée, \(\hat{x}_i\) leurs données normalisées.
Mise à l’échelle Min-Max \[ \forall i,j \hat{x}_{i,j} = \frac{x_{i,j} - \min_k x_{k,j}}{\max_k x_{k,j} - \min_k x_{k,j} + \epsilon} \]
Normalisation Z-score (objectif : \(\hat{\mu}_j = 0, \hat{\sigma}_j = 1\)) \[ \forall i,j, \hat{x}_{i,j} = \frac{x_{i,j} - \mu_j}{\sigma_j + \epsilon} \]
Blanchiment ZCA (objectif : \(\hat{\mu}_j = 0, \hat{\sigma}_j = 1\), \(\frac{1}{n-1} \hat{X} \hat{X}^T = I\))
\[ \hat{X} = W X, W = \frac{1}{\sqrt{n-1}} (XX^T)^{-1/2} \]
Souvenez-vous de notre régression linéaire : \(y = 3x+2+\mathcal{U}(-0.1, 0.1)\), perte L2, 30 échantillons 1D
Une bonne initialisation doit briser la symétrie : les schémas d’initialisation constants font que toutes les unités apprennent la même chose
Une bonne initialisation doit commencer l’optimisation dans une région de faible capacité : réseau de neurones linéaire
Un bon schéma d’initialisation doit préserver la distribution des activations et des gradients : gradients explosifs/vanissants
Initialisation Xavier (Glorot)
\(\mathcal{U}(-\frac{\sqrt{6}}{\sqrt{fan_{in}+fan_{out}}}, \frac{\sqrt{6}}{\sqrt{fan_{in}+fan_{out}}})\), b=0
\(\mathcal{N}(0, \frac{\sqrt{2}}{\sqrt{fan_{in}+fan_{out}}})\), b=0
Initialisation He (Kaiming) pour ReLU
\(\mathcal{U}(-\frac{\sqrt{6}}{\sqrt{fan_{in}}}, \frac{\sqrt{6}}{\sqrt{fan_{in}}})\), b=0
\(\mathcal{N}(0, \frac{\sqrt{2}}{\sqrt{fan_{in}}})\), b=0
Par défaut, les paramètres sont initialisés de manière aléatoire. Par exemple, dans torch.nn.Linear :
class Linear(torch.nn.Module):
def __init__(self):
...
self.reset_parameters()
def reset_parameters(self) -> None:
# Setting a=sqrt(5) in kaiming_uniform is the same as initializing with
# uniform(-1/sqrt(in_features), 1/sqrt(in_features)). For details, see
# https://github.com/pytorch/pytorch/issues/57109
torch.nn.init.kaiming_uniform_(self.weight, a=math.sqrt(5))
fan_in, _ = torch.init.calculate_fan_in_and_fan_out(self.weight)
bound = 1/math.sqrt(fan_in)
init.uniform_(self.bias, -bound, bound)
Oh, mais ce n’est pas ce que nous devrions utiliser pour ReLu ?!? En effet, vous avez raison, voir cet issue. Cela évite de casser la manière dont torch(lua) initialisait les poids.
import torch.nn.init as init
class MyModel(torch.nn.Module):
def __init__(self):
super(MyModel, self).__init__()
self.classifier = nn.Sequential(
*linear_relu(input_size, 256),
*linear_relu(256, 256),
nn.Linear(256, num_classes)
)
self.init()
def init(self):
@torch.no_grad()
def finit(m):
if type(m) == nn.Linear:
init.kaiming_uniform_(m.weight,
a=0,
mode='fan_in',
nonlinearity='relu')
m.bias.fill_(0.0)
self.apply(finit)
(Ioffe & Szegedy, 2015) a observé un changement dans la distribution des activations du réseau dû aux modifications des paramètres du réseau pendant l’entraînement.
Expérience : 3 couches entièrement connectées (100 unités), sigmoïde, sortie softmax, ensemble de données MNIST
Idée : standardiser les activations de chaque couche pour maintenir les mêmes distributions pendant l’entraînement (Ioffe & Szegedy, 2015)
Le gradient doit être conscient de cette normalisation, sinon, il pourrait y avoir une explosion des paramètres (voir (Ioffe & Szegedy, 2015)) \(\rightarrow\) nous avons besoin d’une couche de normalisation différentiable.
introduit une couche de normalisation par batch différentiable :
\[ z = g(W x + b) \rightarrow z = g(BN(W x)) \]
BN fonctionne élément par élément : \[ \begin{align*} y_i &= BN_{\gamma,\beta} (x_i) = \gamma \hat{x}_i + \beta\\ \hat{x}_i &= \frac{x_i - \mu_{\mathcal{B}, i} }{\sqrt{\sigma^2_{\mathcal{B}, i} + \epsilon}} \end{align*} \]
avec \(\mu_{\mathcal{B},i}\) et \(\sigma_{\mathcal{B},i}\) des statistiques calculées sur le mini batch pendant l’entraînement.
Permet d’apprendre plus rapidement, avec une meilleure généralisation.
Pendant l’entraînement
Pendant l’inférence (test) :
warningNe pas oublier de passer le modèle en mode évaluation :
Certains travaux récents remettent en question l’idée du shift covariant (Santurkar, Tsipras, Ilyas, & Ma, 2018), (Bjorck, Gomes, Selman, & Weinberger, 2018). La perte semble plus lisse, permettant des taux d’apprentissage plus élevés, une meilleure généralisation, et une robustesse face aux hyperparamètres.
Pénalité L2 (décroissance du poids, Tikhonov)
\[ \begin{align*} J(\theta) &= L(\theta) + \frac{\alpha}{2} \|\theta\|^2_2 \\ &= L(\theta) + \frac{\alpha}{2}\theta^T \theta\\ \nabla_\theta J &= \nabla_\theta L + \alpha \theta\\ \theta &\leftarrow \theta - \epsilon \nabla_\theta J = (1 - \alpha \epsilon) \theta - \epsilon \nabla_\theta L \end{align*} \]
Pénalité L1 (favorise la parcimonie) \[ \begin{align*} J(\theta) &= L(\theta) + \alpha \|\theta\|_1 \\ &= L(\theta) + \alpha \sum_i |\theta_i|\\ \nabla_\theta J &= \nabla_\theta L + \alpha \mbox{sign}(\theta) \end{align*} \]
Introduites dans (Srivastava, Hinton, Krizhevsky, Sutskever, & Salakhutdinov, 2014):
Idée 1 : prévenir la co-adaptation. Un motif est robuste par
lui-même, non pas grâce aux autres qui font partie du travail.
Idée 2 : moyenne de tous les sous-réseaux (apprentissage par
ensemble)
Comment :
Pour chaque mini-lot, annuler les activations cachées et d’entrée avec une probabilité \(p\) (\(p=0.5\) pour caché, \(p=0.2\) pour l’entrée). Au moment du test, multiplier chaque activation par \(p\)
Dropout “inversé” : multiplier les activations conservées par \(p\) au moment de l’entraînement. Au moment du test, il suffit de faire un passage avant normal.
L1/L2
Dropout
Principe appliquer des perturbations aléatoires à l’entrée pour lesquelles vous pouvez calculer les conséquences sur la cible.
Vous pouvez utiliser des librairies dédiées, e.g. albumentations.ai
Par exemple, en utilisant le module torchvision.transforms.v2
import torchvision
from torchvision.transforms import v2
base_dataset = torchvision.datasets.Caltech101(
root=root_dir,
download=True,
transform=None,
)
preprocess_transforms = [
v2.ToImage(),
GrayToRGB(),
v2.Resize(128), # Keeps the aspect ratio
v2.RandomCrop(128), # Crops the variable size to a fixed 128 x 128
v2.ToDtype(torch.float32, scale=True),
v2.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
]
augmentation_transforms = [
v2.RandomHorizontalFlip(),
v2.RandomRotation(10),
v2.RandomResizedCrop(128, scale=(0.8, 1.0)),
v2.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.2),
]
train_transforms = v2.Compose(preprocess_transforms + augmentation_transforms)
train_dataset = WrappedDataset(train_dataset, train_transforms)
class WrappedDataset(torch.utils.data.dataset.Dataset):
def __init__(self, dataset, transform):
super().__init__()
self.dataset = dataset
self.transform = transform
def __getitem__(self, idx):
xi, yi = self.dataset[idx]
t_xi = self.transform(xi)
return t_xi, yi
def __repr__(self):
return f"{self.__class__.__name__}(dataset={self.dataset}, transform={self.transform})"
def __len__(self):
return len(self.dataset)
Principe :
Voir
Dans le TP2, sur la ségmentation sémantique, nous utiliserons un modèle pré-entrainé comme encodeur.
Récemment, il y a une tendance à l’apprentissage auto-supervisé. Pré-entrainement sans labels utilisant des tâches prétextes.
Par exemple, en utilisant timm
import timm
class TimmEncoder(nn.Module):
def __init__(self, cin):
super().__init__()
self.model = timm.create_model(
model_name="resnet18", in_chans=cin, pretrained=True
)
def forward(self, x):
x = self.model.conv1(x)
x = self.model.bn1(x)
x = self.model.act1(x)
x = self.model.maxpool(x)
f1 = self.model.layer1(x)
f2 = self.model.layer2(f1)
f3 = self.model.layer3(f2)
f4 = self.model.layer4(f3)
return f4, [f1, f2, f3]
voir aussi la documentation
Voir plutôt le document en ligne references.pdf