diff --git a/web/content/am/TP_AEAnimation.md b/web/content/am/TP_AEAnimation.md
index 1fa72e229a9cc6187a6972f32b0dbc33cc0f38e5..996b7de1b68fbcc080a868af6ca49c50909524be 100644
--- a/web/content/am/TP_AEAnimation.md
+++ b/web/content/am/TP_AEAnimation.md
@@ -1,4 +1,4 @@
-==== Partie (IV) Animation et DL ====
+## Partie (IV) Animation et DL
 
 Une vidéo courte expliquant quelques principes pour le TP :
 
@@ -13,7 +13,7 @@ Le papier qui propose une approche équivalente pour transférer le style d'une
 
   
 
-## Le code  
+### Le code  
  * [Le code de départ est à télécharger ici.](https://perso.liris.cnrs.fr/alexandre.meyer/teaching/master_charanim/download/StyleTransfer.zip)
 
 
@@ -74,7 +74,7 @@ Remarque : l'autoencoder de ce code est très basique. Il introduit des tremblem
   
   
 
-#### Tester l'auto-encodeur
+### Tester l'auto-encodeur
 
 Ajouter une action liée à la touche 'r' qui "casse" une animation pour une ou deux articulations (par exemple figer épaule+coude). Puis vous pourrez tester le passage dans l'auto-encoder avec la touche 'e' (e=encodeur). Testez également l'optimisation sur les longueurs de membres. Regardez dans le fichier "HPAAnimation.py" pour une description des articulations.
 ```
@@ -86,7 +86,7 @@ Vous pouvez également ajouter de l'aléatoire sur certaines articulations. Pas
   
   
 
-#### Interpolation dans l'espace caché (espace latent)
+### Interpolation dans l'espace caché (espace latent)
 
 * Faites l'interpolation entre l'animation 1 et l'animation 2 dans l'espace 3D, ranger le résultat dans l'animation 3.
 * Faites l'interpolation entre l'animation 1 et l'animation 2 dans l'espace latent (l'espace de l'ato-encodeur), ranger le résultat dans l'animation 4.
@@ -94,7 +94,7 @@ Vous pouvez également ajouter de l'aléatoire sur certaines articulations. Pas
 
   
 
-##### Transfert de style
+### Transfert de style
 
 Comme pour les images, l'objectif est de produire une nouvelle animation par optimisation de toutes les positions pour toutes les frames. Donc d'optimiser les 240x73 valeurs. Le code à trou réalisant l'optimisation pour transférer le style est dans **pydeepan/chara/AOStyleTransfer.py**. Vous devez compléter les fonctions 'optimize', 'loss' et 'gram'.
 
diff --git a/web/content/am/TP_Classification.md b/web/content/am/TP_Classification.md
index a2cc45e40019ccc5ac1b53719de006d956ef2a95..ee6be12a0e6fb2c835d2f6e506ddd1a2aac64b92 100644
--- a/web/content/am/TP_Classification.md
+++ b/web/content/am/TP_Classification.md
@@ -1,7 +1,7 @@
 
 __
 
-# Partie (I.a) Classification de points 2D
+## Partie (I.a) Classification de points 2D
 
 Un réseau de neurones est un très bon 'classifier'. Dans un exemple simple, nous voudrions reconnaitre la classe d'un point à partir de ses coordonnées 2D notées (x_1, x_2). Un point peut appartenir à 2 classes : classe 1 par exemple en bleu ou classe 2 par exemple en vert. Le réseau prend en entrée 2 valeurs (x_1, x_2) et sort 2 valeurs (suis-je_bleu?, suis-je_vert?). "suis-je_bleu?" sera représenté par un nombre réel entre 0 et 1 : proche de 0 indiquant que le point n’appartient pas à la classe, proche de 1 indiquant que le point appartient à la classe. Par exemple, une sortie \[0.3, 0.7\] sera tranché en "c'est un point de la classe 2".
 
@@ -10,7 +10,7 @@ L'entrainement du réseau consistera à lui montrer toute une série de coordonn
 
   
 
-## Un neurone
+### Un neurone
 
 Un neurone artificiel (ou un perceptron) reçoit des valeurs d’entrées, il les multiplie une à une par un poids, puis en fait la somme. Cette
 somme est passée à une fonction d'activation. Par exemple une fonction d'activation très simple peut-être de comparer la somme à un seuil. Si
@@ -20,7 +20,7 @@ elle est inférieure, la valeur de sortie sera 0, 1 sinon. L’objectif de l’a
 
   
 
-## Un réseau
+### Un réseau
 
 Le principe du réseau de neurones est d’assembler entre-eux des neurones, pour leur faire apprendre des tâches complexes. Les neurones
 vont être regroupés en couches, une couche réalisant une tâche donnant un niveau d’abstraction supplémentaire pour la couche suivante. Par
@@ -152,7 +152,7 @@ Pour rendre le problème un peu plus dur vous pouvez augmenter la plage de gén
 
 __
 __
-# Partie (I.b) Classification d'images
+## Partie (I.b) Classification d'images
 
 Pour ce 2e problème un peu plus concret, nous disposons d'images et nous voudrions reconnaitre la classe à laquelle elles appartiennent. Par
 exemple, pour reconnaitre le nombre à partir de l'image du nombre écrit ou reconnaitre la figure géométrique à partir d'un dessin, ou plus largement reconnaitre une famille d'objets (chat, voiture, avion, fourchette, etc.).
@@ -166,7 +166,7 @@ Pour du code avec pytorch, [regardez ici](https://pytorch.org/tutorials/beginner
 ![Image alt](../images/convnet.png)
 
   
-## Les données
+### Les données
 Pour ce TP, nous vous invitons à utiliser [une base de données d'images issue d'un projet de L3 qui cherche à reconnaitre 5 formes dessinés](https://github.com/ucacaxm/DeepLearning_Vision_SimpleExamples/blob/master/data/shapes5_preprocessed.zip) : carré, cercle, triangle, sablier, étoile. Il y a que quelques centaines d'images par forme, c'est un bon challenge de voir ce que la reconnaissance donne avec finalement assez peu d'images. Il est également intéressant d'augmenter les données. Dans le cas d'images comme ici, vous pouvez faire de petites rotations aléatoires aux images pour en augmenter le nombre.
 
   
@@ -223,34 +223,76 @@ Un exemple de code qui charge une base d'images, voir également la doc de [Data
 * [Un très bon tutoriel sur le chargement de données avec PyTorch](https://github.com/ncullen93/torchsample/blob/master/examples/Transforms%20with%20Pytorch%20and%20Torchsample.ipynb)
 
   
-## Le réseau 
+### Le réseau 
 
-Le code d'un réseau ressemble à ceci 
+Le code d'un réseau ressemble à ceci. Il y a la partie qui extrait les descripteurs (features) et la partie qui classifie.
 ```
 class Classifier(nn.Module):
     def __init__(self):
         super(Discriminator, self).__init__()
-        nc = 3          # 3 channels RGB
-        self.model = nn.Sequential(
-            nn.Conv2d(nc, ndf, 4, 2, 1, bias=False),
-            nn.LeakyReLU(0.2, inplace=True),
-            nn.Conv2d(ndf, ndf * 2, 4, 2, 1, bias=False),
-            nn.BatchNorm2d(ndf * 2),
-            nn.LeakyReLU(0.2, inplace=True),
-            ... # a completer
-            nn.Conv2d(ndf * 8, 1, 4, 1, 0, bias=False),
-            nn.Sigmoid()
-        ).to( torch.float32)
-        print(self.model)
+        self.features = nn.Sequential(
+            # 3 input image channel, 6 output channels, 5x5 square convolution
+            nn.Conv2d(3, 6, 5)
+            nn.ReLU(),
+            nn.MaxPool2d(2, 2),            
+            nn.Conv2d(6, 16, 5)
+
+            # ... à compléter
+            # ... 
+
+        )
+
+        self.classifier = nn.Sequential(
+            nn.Linear(16 * 5 * 5, 120),
+            nn.ReLU(),
+            nn.Linear(120, 84),
+            nn.ReLU(),
+            nn.Linear(84, 10)
+        )
+        print(self.features)
+        print(self.classifier)
+
 
     def forward(self, input):
-        return self.model(input)
+        x = self.features(x)
+        x = x.view(x.size(0), -1)
+        x = self.classifier(x)
 ```
 
 
 ## L'entrainement
-De manière assez similaire au classifier de nuages de point plus haut, il faut entrainer le réseau en déclarant également le DataLoader.
-[regardez ici](https://pytorch.org/tutorials/beginner/blitz/cifar10_tutorial.html)
+De manière assez similaire au classifier de nuages de point plus haut, il faut entrainer le réseau en déclarant également le DataLoader,  l'optimiseur, la loss, etc. [Regardez le tutorial CIFAR10 de pytorch](https://github.com/pytorch/tutorials/blob/main/beginner_source/blitz/cifar10_tutorial.py)
+
+```
+net = Classifier()
+criterion = nn.CrossEntropyLoss()
+optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
+
+for epoch in range(2):  # loop over the dataset multiple times
+    running_loss = 0.0
+    for i, data in enumerate(trainloader, 0):
+        # get the inputs; data is a list of [inputs, labels]
+        inputs, labels = data
+
+        # zero the parameter gradients
+        optimizer.zero_grad()
+
+        # forward + backward + optimize
+        outputs = net(inputs)
+        loss = criterion(outputs, labels)
+        loss.backward()
+        optimizer.step()
+
+        # print statistics
+        running_loss += loss.item()
+        if i % 2000 == 1999:    # print every 2000 mini-batches
+            print(f'[{epoch + 1}, {i + 1:5d}] loss: {running_loss / 2000:.3f}')
+            running_loss = 0.0
+
+print('Finished Training')
+
+```
+
 
 
 ## Conclusion