
Un modèle est un ensemble de fonctions \(\mathcal{F}\) de \(\mathbb{R}^p \rightarrow \mathbb{R}^q\)
Données
Fonction de coût/loss :
Exemple: coût quadratique:
\(loss(\theta) = \sum_{i=1}^n \|f(X_i) - Y_i\|^2\)
Minimiser cette fonction de coût sur nos données



Fonction de coût:
Gradient stochastique:
Pour calculer le gradient de la fonction de coût:
Solution:
Comment cela fonctionne:
(*) c’est une simplification: en réalité pytorch crée un arbre décrivant l’expression mathématique du modèle
Soit \(f_1:\mathbb{R}^n \rightarrow \mathbb{R}\), \(f_2:\mathbb{R}^n \rightarrow \mathbb{R}^n\) et \(f_3:\mathbb{R}^n \rightarrow \mathbb{R}^n\) posons \[f=f_1\circ f_2\circ f_3 \]
Pour calculer la différentielle de \(f\) en \(x\), posons: \[A_1=J_{f_1}(f_2of_3(x))\in M_{n,1}(\mathbb{R})\] \[A_2=J_{f_2}(f_3(x))\in M_{n,n}(\mathbb{R})\] \[A_3=J_{f_3}(x)\in M_{n,n}(\mathbb{R})\] Le calcul de la différentielle nous donne: \[J_f(x)=A_1 A_2 A_3\]
Il y a deux manières de faire ce produit matriciel, l’une est plus coûteuse que l’autre:
Forward: \(J_f(x)=A_1 (A_2 A_3)\)
Backward: \(J_f(x)=(A_1 A_2) A_3\)
\[A_1=J_{f_1}(f_2of_3(x))\in M_{n,1}(\mathbb{R})\] \[A_2=J_{f_2}(f_3(x))\in M_{n,n}(\mathbb{R})\] \[A_3=J_{f_3}(x)\in M_{n,n}(\mathbb{R})\]
Les bibliothèques de différentiation automatique :
Pour l’apprentissage:
import torch
# Define a tensor with requires_grad=True to track computations
x = torch.tensor(3.0, requires_grad=True)
y = x**2 + x
print("y =",y.item())
y.backward()
# The gradient of y with respect to x is stored in x.grad
print(f"dy/dx = {x.grad.item()} at x =",x.item())y = 12.0
dy/dx = 7.0 at x = 3.0
Résultat:
Pytorch distingue 2 concepts :
from torch.utils.data import TensorDataset
# Exemple de dataset simple
data = torch.tensor([[1.0], [2.0], [3.0], [4.0]])
labels = torch.tensor([[0.0], [0.0], [1.0], [1.0]])
# Création d'un TensorDataset
dataset = TensorDataset(data, labels)
print("length:", dataset.__len__())
print("elem 0:", dataset.__getitem__(0))length: 4
elem 0: (tensor([1.]), tensor([0.]))
Pour charger un dataset, il faut implémenter la classe dataset comme suit :
from torch.utils.data import Dataset
class CustomDataset(Dataset):
def __init__(self, some_args, transform=None, target_transform=None):
# initialize whatever you need here
def __len__(self):
#return the length of the dataset
def __getitem__(self, idx):
#load data at index = idx
data = ....
label = ....
return data, labelUsage:
Custom vs TensorDataset:
from torch.utils.data import DataLoader, TensorDataset
# Exemple de dataset simple
data = torch.tensor([[1.0], [2.0], [3.0], [4.0]])
labels = torch.tensor([[0.0], [0.0], [1.0], [1.0]])
# Création d'un TensorDataset
dataset = TensorDataset(data, labels)
# Initialisation du DataLoader
dataloader = DataLoader(dataset, batch_size=2, shuffle=True)
# Iteration sur le DataLoader
for batch in dataloader:
print("data:",batch[0],"labels:",batch[1])data: tensor([[2.],
[1.]]) labels: tensor([[0.],
[0.]])
data: tensor([[3.],
[4.]]) labels: tensor([[1.],
[1.]])
On reprend le modèle du cours précédent, ainsi que les données du cours précédent :
import torch
import torch.nn as nn
import torch.nn.functional as F
class SimpleNN(nn.Module):
def __init__(self):
super(SimpleNN, self).__init__()
self.flatten = nn.Flatten()
# Définir les poids et biais pour trois couches
self.w1 = nn.Parameter(torch.randn(28*28,512))
self.b1 = nn.Parameter(torch.randn(512))
self.w2 = nn.Parameter(torch.randn(512, 512))
self.b2 = nn.Parameter(torch.randn(512))
self.w3 = nn.Parameter(torch.randn(512, 10))
self.b3 = nn.Parameter(torch.randn(10))
def forward(self, x):
x = self.flatten(x)
# Appliquer les transformations et les fonctions d'activation
x = F.relu(x.matmul(self.w1) + self.b1)
x = F.relu(x.matmul(self.w2) + self.b2)
x = x.matmul(self.w3) + self.b3
return x
# Instancier le modèle
model = SimpleNN()Pour évaluer le coût sur un batch de données:
dataloader = DataLoader(training_data, batch_size=2, shuffle=True)
loss_function= torch.nn.CrossEntropyLoss()
# Calculer la perte pour un batch
for batch_data, batch_labels in dataloader:
outputs = model(batch_data)
loss = loss_function(outputs, batch_labels)
print(f'Loss: {loss.item()}')
break # Calcul de la perte pour un seul batchLoss: 8850.0703125
train_loader = DataLoader(dataset=training_data,
batch_size=len(training_data), shuffle=True)
full_batch_data, full_batch_labels = next(iter(train_loader))
learning_rate = 0.01
num_steps = 6
for i in range(num_steps):
# Zero the gradients
model.zero_grad()
# Forward pass
outputs = model(full_batch_data)
loss = loss_function(outputs, full_batch_labels)
# Backward pass
loss.backward()
# Update weights manually
with torch.no_grad():
for param in model.parameters():
param -= learning_rate * param.grad
print(f'step [{i+1}/{num_steps}], Loss: {loss.item():.4f}')step [1/6], Loss: 3760.8013
step [2/6], Loss: 15396.2969
step [3/6], Loss: 15643.5566
step [4/6], Loss: 8759.0859
step [5/6], Loss: 4254.5693
step [6/6], Loss: 2324.6482
Estimateur du gradient:
epoch :
learning_rate = 0.01
num_epochs = 3
batch_size = 10000
train_loader = DataLoader(dataset=training_data,
batch_size=batch_size, shuffle=True)
for epoch in range(num_epochs):
for batch_data, batch_labels in train_loader:
i=i+1
# Zero the gradients
model.zero_grad()
# Forward pass
outputs = model(batch_data)
loss = loss_function(outputs, batch_labels)
# Backward pass
loss.backward()
# Update weights manually
with torch.no_grad():
for param in model.parameters():
param -= learning_rate * param.grad
print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')Epoch [1/3], Loss: 1397.9691
Epoch [2/3], Loss: 273.5677
Epoch [3/3], Loss: 154.3725
num_epochs = 3
batch_size = 10000
train_loader = DataLoader(dataset=training_data,
batch_size=batch_size, shuffle=True)
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
i=0
for epoch in range(num_epochs):
for batch_data, batch_labels in train_loader:
i=i+1
# Zero the gradients
optimizer.zero_grad()
# Forward pass
outputs = model(batch_data)
loss = loss_function(outputs, batch_labels)
# Backward pass
loss.backward()
# Update weights
optimizer.step()
print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')Epoch [1/3], Loss: 894.4625
Epoch [2/3], Loss: 314.3895
Epoch [3/3], Loss: 178.6331
Le taux d’apprentissage est un hyperparamètre clé qui contrôle la vitesse à laquelle un modèle ajuste ses poids pendant l’entraînement.

2 grands types:



Arrête l’entraînement quand la performance sur le set de validation cesse de s’améliorer
Empêche le modèle de trop s’ajuster aux données d’entraînement
Critère de patience :
Early stopping at epoch 30

Ajoute une pénalité à la fonction de coût pour des poids trop élevés
Réduit la complexité du modèle et favorise la généralisation
Types de régularisation :
Avantages :

“Understanding deep learning requires rethinking generalization”