diff --git a/TP6/TP6_ex2_correc.ipynb b/TP6/TP6_ex2_correc.ipynb
index ff406c7a82b90bc4228f95b023c8561595300a75..be42d0e94a7cd4d2afb3d0e0408100b6b503e0ed 100644
--- a/TP6/TP6_ex2_correc.ipynb
+++ b/TP6/TP6_ex2_correc.ipynb
@@ -46,7 +46,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 1,
+   "execution_count": null,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -57,7 +57,7 @@
     "\n",
     "%matplotlib inline\n",
     "\n",
-    "def display_test(X_image_test,Y_test,Y_test_pred,txt):\n",
+    "def display_test(X_image_test,Y_test,Y_test_pred,dict_classes,txt):\n",
     "    # affiche les résultats de classification pour 120 images aléatoires\n",
     "    # paramètres: \n",
     "    # X_image_test: tableau des images de test \n",
@@ -70,9 +70,9 @@
     "        plt.subplot(12,10,n+1,xticks=[],yticks=[])\n",
     "        plt.imshow(X_image_test[alea[n]],cmap='gray')\n",
     "        if Y_test_pred[alea[n]]==Y_test[alea[n]]:\n",
-    "            plt.text(0.1,0.1,str(Y_test_pred[alea[n]])+' / '+str(Y_test[alea[n]]),fontsize=8,bbox=dict(facecolor='white', alpha=1))\n",
+    "            plt.text(0.1,0.1,str(dict_classes[Y_test_pred[alea[n]]])+' / '+str(dict_classes[Y_test[alea[n]]]),fontsize=8,bbox=dict(facecolor='white', alpha=1))\n",
     "        else:\n",
-    "            plt.text(0.1,0.1,str(Y_test_pred[alea[n]])+' / '+str(Y_test[alea[n]]),fontsize=8,bbox=dict(facecolor='red', alpha=1))\n",
+    "            plt.text(0.1,0.1,str(dict_classes[Y_test_pred[alea[n]]])+' / '+str(dict_classes[Y_test[alea[n]]]),fontsize=8,bbox=dict(facecolor='red', alpha=1))\n",
     "    plt.suptitle('prediction '+txt+'  --  classe prédite / classe réelle')\n",
     "    plt.show()"
    ]
@@ -102,12 +102,14 @@
     "X_image=[]\n",
     "X_train=[]\n",
     "X_test=[]\n",
+    "dict_class_names={}  # dictionnaires associant labels et noms des classes\n",
     "\n",
     "y=0  # numéro de classe\n",
     "\n",
     "for directory in os.listdir(path):\n",
     "    count = 0 # indice de l'image traitée dans le répertoire courant\n",
     "    print(\"%s  - classe: %d\" % (directory,y))\n",
+    "    dict_class_names[y]=directory[4:]\n",
     "    for file in os.listdir(path+directory):\n",
     "        img = plt.imread(path+directory+\"/\"+file)\n",
     "        if (len(img.shape)==2):\n",
@@ -158,7 +160,7 @@
     "n_image=200  # essayez d'autres valeurs\n",
     "plt.figure()\n",
     "plt.imshow(X_image_train[n_image]);\n",
-    "plt.title(\"Un exemple d'image\");\n",
+    "plt.title(\"Un exemple d'image - classe: \"+str(dict_class_names[Y_train[n_image]]));\n",
     "plt.figure()\n",
     "plt.imshow(X_train[n_image].reshape(100,150,3))\n",
     "plt.title(\"Sa représentation dans la base d'apprentissage (150x100 pixels)\")\n",
@@ -226,7 +228,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 5,
+   "execution_count": null,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -242,7 +244,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 6,
+   "execution_count": null,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -266,7 +268,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "On voit que la sortie de la partie \"convolutive\" est un tenseur de dimension $12\\times 18\\times 64 = 13 824$, qui est représenté par un vecteur de dimension $10 880$ après \"aplattisement\" (_flattening_).\n",
+    "On voit que la sortie de la partie \"convolutive\" est un tenseur de dimension $12\\times 18\\times 64 = 13 824$, qui est représenté par un vecteur de dimension $13 824$ après \"aplattisement\" (_flattening_).\n",
     "\n",
     "Ce modèle nécessite l'apprentissage de 913 895 paramètres, qui sont dans la partie \"fully connected\" pour la très grande majorité. Par exemple, la seconde couche de convolution nécessite l'estimation de 9248 paramètres. En effet, elle effectue 32 convolutions de taille $3 \\times 3 \\times \\text{(épaisseur de la sortie de la couche précédente)}$, soit: $(9\\times 32+1)\\times 32 = 9248$ paramètres (la couche précédente effectue 32 convolutions, et +1 car il faut ajouter le terme de biais).\n",
     "\n",
@@ -330,7 +332,7 @@
     "print(\"matrice de confusion\")\n",
     "print(metrics.confusion_matrix(Y_test,Y_test_pred))\n",
     "\n",
-    "display_test(X_image_test,Y_test,Y_test_pred,'CNN')"
+    "display_test(X_image_test,Y_test,Y_test_pred,dict_class_names,'CNN')"
    ]
   },
   {
@@ -368,7 +370,7 @@
     "\n",
     "plt.figure(figsize=[12,8])\n",
     "plt.imshow(adv_example[0])\n",
-    "plt.title(\"classe prédite pour l'exemple de test considéré: %d\" % init_pred)\n",
+    "plt.title(\"classe prédite pour l'exemple de test considéré: %s\" % dict_class_names[init_pred])\n",
     "plt.show()\n",
     "\n",
     "M=10\n",
@@ -382,7 +384,7 @@
     "\n",
     "plt.figure(figsize=[12,8])\n",
     "plt.imshow(adv_example[0])\n",
-    "plt.title(\"classe prédite pour l'exemple de test considéré: %d - %d pixels modifiés\" % (adv_pred, count));\n",
+    "plt.title(\"classe prédite pour l'exemple de test considéré: %s - %d pixels modifiés\" % (dict_class_names[adv_pred], count));\n",
     "plt.show()           "
    ]
   },
@@ -394,11 +396,11 @@
     "\n",
     "L'objectif de cette expérience très simple est d'illustrer que la perception humaine n'a rien à voir avec la classification algorithmique.\n",
     "\n",
-    "Relancez plusieurs fois la cellule: vous voyez que la classe affectée à notre exemple adversarial peut changer, et que quelques pixels suffisent à tromper le modèle. A quelques pixels près, un avion est reconnu comme un cheval...\n",
+    "Relancez plusieurs fois la cellule: vous voyez que la classe affectée à notre exemple contradictoire peut changer, et que quelques pixels suffisent à tromper le modèle. A quelques pixels près, un avion est reconnu comme un cheval...\n",
     "\n",
     "En fait on triche un peu ici: on autorise des modifications des valeurs des pixels entre 0 et M=10, alors que les composantes RVB des \"vraies\" images varient entre 0 et 1.\n",
     "\n",
-    "Dans les exemples présentés en cours (issus d'articles de recherche récents), les perturbations adversariales ne sont pas générées aléatoirement, mais en fonction du modèle de classification, et de manière à atteindre une classe prédeterminée. Voir la section 5 à la fin du carnet.\n"
+    "Dans les exemples présentés en cours (issus d'articles de recherche récents), les \"perturbations contradictoires\" ne sont pas générées aléatoirement, mais en fonction du modèle de classification, et de manière à atteindre une classe prédeterminée. Voir la section 5 à la fin du carnet.\n"
    ]
   },
   {
@@ -569,7 +571,7 @@
     "print(\"matrice de confusion\")\n",
     "print(metrics.confusion_matrix(Y_test,Y_test_pred))\n",
     "\n",
-    "display_test(X_image_test,Y_test,Y_test_pred,'with pretrained network')"
+    "display_test(X_image_test,Y_test,Y_test_pred,dict_class_names,'with pretrained network')"
    ]
   },
   {
@@ -580,7 +582,7 @@
     "\n",
     "<br>\n",
     "\n",
-    "Au passage, notons que notre génération aléatoire d'exemples adversariaux fonctionne toujours, comme on peut le constater à l'aide de la cellule suivante. Il faut néanmoins modifier un plus grand nombre de pixels."
+    "Au passage, notons que notre génération aléatoire d'exemples contradictoires fonctionne toujours, comme on peut le constater à l'aide de la cellule suivante. Il faut néanmoins modifier un plus grand nombre de pixels."
    ]
   },
   {
@@ -595,7 +597,7 @@
     "\n",
     "plt.figure(figsize=[12,8])\n",
     "plt.imshow(adv_example[0])\n",
-    "plt.title(\"classe prédite pour l'exemple de test considéré: %d\" % init_pred)\n",
+    "plt.title(\"classe prédite pour l'exemple de test considéré: %s\" % dict_class_names[init_pred])\n",
     "\n",
     "M=10\n",
     "count=0\n",
@@ -608,7 +610,7 @@
     "\n",
     "plt.figure(figsize=[12,8])\n",
     "plt.imshow(adv_example[0])\n",
-    "plt.title(\"classe prédite pour l'exemple de test considéré: %d - %d pixels modifiés\" % (adv_pred, count))\n",
+    "plt.title(\"classe prédite pour l'exemple de test considéré: %s - %d pixels modifiés\" % (dict_class_names[adv_pred[0]], count))\n",
     "plt.show()"
    ]
   },
@@ -697,7 +699,7 @@
     "print(\"score SVM rbf : %.3f\" % SVM_r.score(X_test_svm, Y_test) )\n",
     "Y_test_pred=SVM_r.predict(X_test_svm)\n",
     "print(metrics.confusion_matrix(Y_test,Y_test_pred))\n",
-    "display_test(X_image_test,Y_test,Y_test_pred,\"SVM rbf\")"
+    "display_test(X_image_test,Y_test,Y_test_pred,dict_class_names,\"SVM rbf\")"
    ]
   },
   {
@@ -722,24 +724,24 @@
     "\n",
     "Il s'agit d'une méthode de génération d'exemples contradictoires présentée dans l'article suivant:\n",
     "\n",
-    "Ian J. Goodfellow, Jonathon Shlens, Christian Szegedy, _Explaining and Harnessing Adversarial Examples_. Proceedings of ICLR, 2015. [Sur Arxiv](https://arxiv.org/abs/1412.6572)\n",
+    "Ian J. Goodfellow, Jonathon Shlens, Christian Szegedy, _Explaining and Harnessing Adversarial Examples_. Proceedings of ICLR, 2015. [Voir sur Arxiv](https://arxiv.org/abs/1412.6572)\n",
     "\n",
-    "Nous allons faire des expériences sur le premier modèle du carnet.\n",
+    "Nous allons faire des expériences sur le premier modèle CNN de ce carnet.\n",
     "\n",
     "<br>\n",
     "\n",
-    "Avec les notations de cet article, soit $J(\\theta,x,y)$ la valeur de la fonction de perte estimée sur le réseau $f_\\theta$ de paramètres $\\theta$ (paramètres du réseau après apprentissage) avec comme entrée l'observation $x$ ($x$ est une image ici) d'étiquette $y$: $J(\\theta,x,y)$ mesure donc l'écart entre la prédiction $f_\\theta(x)$ et la \"vraie\" étiquette $y$. On suppose $f_\\theta(x)=y$: l'étiquette de $y$ est correctement prédite par $f_\\theta(x)$.\n",
+    "On utilise les notations de l'article précédent. Soit $J(\\theta,x,y)$ la valeur de la fonction de perte estimée sur le réseau $f_\\theta$ de paramètres $\\theta$ (paramètres du réseau après apprentissage) avec comme entrée l'observation $x$ ($x$ est une image ici) d'étiquette $y$: $J(\\theta,x,y)$ mesure donc l'écart entre la prédiction $f_\\theta(x)$ et la \"vraie\" étiquette $y$. On suppose $f_\\theta(x)=y$: l'étiquette de $y$ est correctement prédite par $f_\\theta(x)$.\n",
     "\n",
     "Considérons alors $J$ comme une fonction de l'image $x$. On cherche une image $x'$ pas trop éloignée de $x$ (de manière à ce que les deux images se ressemblent) mais telle que $J(\\theta,x',y)>J(\\theta,x,y)$ de manière à ce que la valeur de la perte $J(\\theta,x,y)$ soit suffisamment grande pour que $f_\\theta(x')$ ne soit pas une prédiction correcte de $y$.\n",
     "\n",
     "Un développement limité à l'ordre 1 permet d'écrire:\n",
     "$$ J(\\theta,x',y) = J(\\theta,x,y) + (x'-x) \\cdot \\nabla_x J(\\theta,x,y)$$\n",
     "\n",
-    "Dans cette équation, le gradient $\\nabla_x J(\\theta,x,y)$ désigne le vecteur des dérivées partielles de la fonction à valeurs réelles $J$ par rapport aux composantes de $x$ qui est le vecteur des valeurs de l'intensité de chaque canal (rouge, vert, ou bleu) en chaque pixel de l'image $x$. Le gradient a donc même dimension que $x$.\n",
+    "Dans cette équation, le gradient $\\nabla_x J(\\theta,x,y)$ désigne le vecteur des dérivées partielles de la fonction à valeurs réelles $J$ par rapport aux composantes du vecteur des valeurs de l'intensité de chaque canal (rouge, vert, ou bleu) en chaque pixel de l'image $x$. Le gradient a donc même dimension que $x$.\n",
     "\n",
-    "On cherche alors $x'$ maximisant $J(\\theta,x',y)$, soit $(x'-x) \\cdot \\nabla_x J(\\theta,x,y)$. Contraignons $x'$ à ne pas être trop éloigné de $x$ en imposant $||x'-x||\\leqslant \\epsilon$. Ici, cela signifie qu'en tout pixel, le niveau de gris de $x'$ diffère de celui de $x$ d'au plus $\\epsilon$. On utilise alors la proposition suivante:\n",
+    "On cherche alors $x'$ maximisant $J(\\theta,x',y)$, c'est-à-dire $(x'-x) \\cdot \\nabla_x J(\\theta,x,y)$. Contraignons $x'$ à ne pas être trop éloigné de $x$ en imposant $||x'-x||_\\infty\\leqslant \\epsilon$. Ici, cela signifie qu'en tout pixel, la valeur de chaque composante R, V, B de $x'$ diffère de celles de $x$ d'au plus $\\epsilon$. On utilise alors la proposition suivante:\n",
     "\n",
-    "__Proposition__: Soit $w\\in{\\mathbb R}^d$. Le maximum de $f(x)=x\\cdot w $ sous contrainte $||x||_{\\infty} \\leqslant 1$ est $x=\\text{sign}(w)$, le vecteur dont les composantes sont 1 ou -1, selon le signe des composantes correspondantes de $w$.\n",
+    "__Proposition__: Soit $w\\in{\\mathbb R}^d$. Le maximum de $f(x)=x\\cdot w $ sous contrainte $||x||_{\\infty} \\leqslant 1$ est $||w||_1$ et est atteint pour $x=\\text{sign}(w)$, le vecteur dont les composantes sont 1 ou -1, selon le signe des composantes correspondantes de $w$.\n",
     "\n",
     "En effet, d'un part $|f(x)|\\leqslant ||x||_{\\infty}||w||_1$, et d'autre part il s'agit d'un problème de programmation linéaire dont le maximum est atteint sur les sommets de l'hypercube défini par $||x||_{\\infty} \\leqslant 1$. Ces sommets ont pour composantes $(\\pm 1, \\pm 1, \\dots, \\pm 1)$. Le maximum du produit scalaire $x\\cdot w$ est donc $||w||_1$, atteint pour $x=\\text{sign}(w)$.\n",
     "\n",
@@ -748,15 +750,17 @@
     "\n",
     "Pour que $x'$ soit un exemple contradictoire, il faut que $\\epsilon$ soit suffisamment petit pour que l'image $x'$ ressemble visuellement à l'image $x$, mais aussi suffisamment grand pour que $J(\\theta,x',y)$ soit assez différent de $J(\\theta,x,y)$ de manière à ce que le réseau se trompe en prédisant l'étiquette de $y$. \n",
     "\n",
-    "Comme $|J(\\theta,x',y) - J(\\theta,x,y)| \\leqslant ||x'-x||_\\infty \\; ||\\nabla_x J(\\theta,x,y)||_1$, si $m$ est la valeur maximale des dérivées partielles qui composent le gradient $\\nabla_x J(\\theta,x,y)$, alors:\n",
+    "Comme $|J(\\theta,x',y) - J(\\theta,x,y)| \\leqslant ||x'-x||_\\infty \\; ||\\nabla_x J(\\theta,x,y)||_1$ lorsque $x'$ n'est pas trop éloigné de $x$, si $m$ est la valeur maximale des valeurs absolues des dérivées partielles qui composent le gradient $\\nabla_x J(\\theta,x,y)$, alors on a:\n",
     "$$|J(\\theta,x',y) - J(\\theta,x,y)| \\leqslant \\epsilon\\, m\\, d$$\n",
-    "Cette inégalité suggère que même pour $\\epsilon$ petit, l'écart $J(\\theta,x',y)-J(\\theta,x,y)$ peut être d'autant plus grand que la dimension (ici, le nombre de pixels dans chaque canal de l'image) est grande. \n"
+    "Cette inégalité suggère que même pour $\\epsilon$ petit, l'écart $J(\\theta,x',y)-J(\\theta,x,y)$ peut être d'autant plus grand que la dimension (ici, le nombre total de pixels dans chaque canal de l'image) est grande. \n"
    ]
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "metadata": {},
+   "metadata": {
+    "scrolled": false
+   },
    "outputs": [],
    "source": [
     "import tensorflow as tf   # le premier import peut prendre une minute\n",
@@ -771,10 +775,20 @@
     "x=np.zeros([1, 100, 150, 3])\n",
     "x[0,:,:,:]=X_test[indice_image_test]\n",
     "x=tf.Variable(x)\n",
+    "# en cas de message d'erreur \"...was expected to be a double tensor but is a float tensor\", \n",
+    "# commentez la ligne précédente et utilisez:\n",
+    "# x=tf.Variable(np.float32(x))\n",
     "\n",
     "# création de l'étiquette de x comme un tenseur Tensorflow\n",
     "y=tf.Variable([Y_test[indice_image_test]])\n",
     "\n",
+    "# image originale\n",
+    "pred_y = np.array(model(x))\n",
+    "plt.figure()\n",
+    "plt.imshow(X_test[indice_image_test].reshape(100,150,3))\n",
+    "plt.title(\"Image originale - Vraie classe: \"+dict_class_names[Y_test[indice_image_test]]+\"\\nClasse prédite: \"+dict_class_names[pred_y.argmax(axis=1)[0]]+\" - confiance: \"+str(pred_y.max(axis=1)[0]))\n",
+    "plt.show()\n",
+    "\n",
     "# calcul du gradient à l'aide de la différentiation automatique\n",
     "with tf.GradientTape() as tape:\n",
     "    tape.watch(x)\n",
@@ -788,7 +802,7 @@
     "# représentation graphique des perturbations (valeurs entre 0 et 1)\n",
     "pred_signgrad=model.predict(signgrad)\n",
     "plt.imshow(signgrad[0]*0.5+0.5)\n",
-    "plt.title(\"Perturbation - Reconnue comme classe: \"+str(pred_signgrad.argmax(axis=1))+\" - confiance: \"+str(pred_signgrad.max(axis=1)))\n",
+    "plt.title(\"Perturbation - Reconnue comme classe: \"+dict_class_names[pred_signgrad.argmax(axis=1)[0]]+\" - confiance: \"+str(pred_signgrad.max(axis=1)[0]))\n",
     "plt.show()\n",
     "\n",
     "# Exemple contradictoire et classe prédite:\n",
@@ -796,27 +810,20 @@
     "pred_adv_example = model.predict(adv_example)\n",
     "plt.figure()\n",
     "plt.imshow(np.array(adv_example).reshape(100,150,3))\n",
-    "plt.title(\"Exemple contradictoire. \\nClasse prédite: \"+str(pred_adv_example.argmax(axis=1))+\" - confiance: \"+str(pred_adv_example.max(axis=1)))\n",
-    "plt.show()\n",
-    "\n",
-    "# image originale\n",
-    "pred_y = model.predict(x)  \n",
-    "plt.figure()\n",
-    "plt.imshow(X_test[indice_image_test].reshape(100,150,3))\n",
-    "plt.title(\"Image originale - Classe: \"+str(Y_test[indice_image_test])+\"\\nClasse prédite: \"+str(pred_y.argmax(axis=1))+\" - confiance: \"+str(pred_y.max(axis=1)))\n",
-    "plt.show()"
+    "plt.title(\"Exemple contradictoire. \\nClasse prédite: \"+dict_class_names[pred_adv_example.argmax(axis=1)[0]]+\" - confiance: \"+str(pred_adv_example.max(axis=1)[0]))\n",
+    "plt.show()\n"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "L'inconvénient de l'approche précédente est que le choix du paramètre $\\epsilon$ peut être délicat: parfois $\\epsilon$ est trop petit pour trouver, en maximisant $J(\\theta,x,y)$, un exemple contradictoire ayant une classe différente de celle de $x$.\n",
+    "L'inconvénient de l'approche précédente est que le choix du paramètre $\\epsilon$ peut être délicat: parfois $\\epsilon$ est trop petit pour que $ x'=\\epsilon \\; \\text{sign}\\left( \\nabla_x J(\\theta,x,y) \\right)$ ait une classe prédite différente de celle de $x$.\n",
     "\n",
     "On peut procéder de manière itérative:\n",
     "- $x_0$ est l'image originale, d'étiquette $y_0$\n",
-    "- on cherche $x_1$ maximisant $J(\\theta,x_0,y_0)$ sous contrainte $||x_0-x_1||<\\epsilon$ (comme précédemment)\n",
-    "- on recommence en cherchant $x_2$ maximisant $J(\\theta,x_1,y_0)$ sous contrainte $||x_1-x_2||<\\epsilon$\n",
+    "- on cherche $x_1$ maximisant $J(\\theta,x_0,y_0)$ sous contrainte $||x_0-x_1||\\leqslant\\epsilon$ (comme précédemment)\n",
+    "- on recommence en cherchant $x_2$ maximisant $J(\\theta,x_1,y_0)$ sous contrainte $||x_1-x_2||\\leqslant\\epsilon$\n",
     "- etc. jusqu'à ce que la classe prédite pour $x_n$ soit différente de $y_0$\n",
     "\n",
     "Cet algorithme fournit généralement des exemples contradictoires davantage semblables visuellement à l'image de départ.\n",
@@ -834,6 +841,7 @@
     "    x=np.zeros([1, 100, 150, 3])\n",
     "    x[0,:,:,:]=x0\n",
     "    x=tf.Variable(x)\n",
+    "    # x=tf.Variable(np.float32(x))  # si problème de type, voir ci-dessus\n",
     "    y=tf.Variable([y0])  \n",
     "    for iter in range(1,20):\n",
     "        with tf.GradientTape() as tape:\n",
@@ -860,12 +868,12 @@
     "\n",
     "plt.figure()\n",
     "plt.imshow(X_test[indice_image_test].reshape(100,150,3))\n",
-    "plt.title(\"image initiale -  classe: \"+str(Y_test[indice_image_test]))\n",
+    "plt.title(\"image initiale -  classe: \"+dict_class_names[Y_test[indice_image_test]])\n",
     "plt.show()\n",
     "\n",
     "plt.figure()\n",
     "plt.imshow(np.array(adv_example).reshape(100,150,3))\n",
-    "plt.title(\"exemple contradictoire \\nClasse prédite: \"+str(y_adv_example)+\" Confiance: \"+str(conf_y_adv_example))\n",
+    "plt.title(\"exemple contradictoire \\nClasse prédite: \"+dict_class_names[y_adv_example]+\" Confiance: \"+str(conf_y_adv_example))\n",
     "plt.show()"
    ]
   },
@@ -877,9 +885,9 @@
     "\n",
     "On peut facilement transformer cet algorithme en _targeted fast gradient sign method_ qui, cette fois, permet d'atteindre un exemple contradictoire de classe $y_t$ choisie à l'avance en __diminuant__ $J(\\theta,x,y_t$). Lorsque $J(\\theta,x,y_t)$ est suffisamment petit, la classe prédite pour $x$ par le modèle est $y_t$.\n",
     "\n",
-    "On s'appuie sur la proposition suivante.\n",
+    "On s'appuie sur la proposition suivante, de démonstration similaire à la propositon précédente.\n",
     "\n",
-    "__Proposition__: Soit $w\\in{\\mathbb R}^d$. Le minimum de $f(x)=x\\cdot w $ sous contrainte $||x||_{\\infty} \\leqslant 1$ est: $x=-\\text{sign}(w)$.\n",
+    "__Proposition__: Soit $w\\in{\\mathbb R}^d$. Le minimum de $f(x)=x\\cdot w $ sous contrainte $||x||_{\\infty} \\leqslant 1$ est $-||w||_1$, atteint par $x=-\\text{sign}(w)$.\n",
     "\n",
     "Ainsi, on déduit tout simplement l'algorithme _targeted FGSM_ à partir de l'algorithme _untargeted FGSM_ en changeant le signe du gradient, et en remplaçant $y_0$ par $y_t$ dans la fonction de perte."
    ]
@@ -894,6 +902,7 @@
     "    x=np.zeros([1, 100, 150, 3])\n",
     "    x[0,:,:,:]=x0\n",
     "    x=tf.Variable(x)\n",
+    "    # x=tf.Variable(np.float32(x))  # si problème de type, voir ci-dessus\n",
     "    yt=tf.Variable([y_t])\n",
     "    for iter in range(1,20):\n",
     "        with tf.GradientTape() as tape:\n",
@@ -917,26 +926,33 @@
     "\n",
     "SCCE = tf.keras.losses.SparseCategoricalCrossentropy()  # la fonction de loss utilisée \n",
     "\n",
-    "plt.figure()\n",
-    "plt.imshow(X_test[indice_image_test].reshape(100,150,3))\n",
-    "plt.title(\"image initiale -  classe: \"+str(Y_test[indice_image_test]))\n",
-    "plt.show()\n",
-    "\n",
     "plt.figure(figsize=[18,10])\n",
-    "for y_target in range(7): # classe cible\n",
+    "plt.subplot(3,3,1,xticks=[],yticks=[])\n",
+    "plt.imshow(X_test[indice_image_test].reshape(100,150,3))\n",
+    "plt.text(-1,-5,\"Image originale -  classe: \"+dict_class_names[Y_test[indice_image_test]],fontweight='bold')\n",
+    "for y_target in range(7): # classe cible différent de la classe originale\n",
+    "    if y_target==Y_test[indice_image_test]:\n",
+    "        continue\n",
     "    print(\"Classe \"+str(y_target))\n",
     "    adv_example, y_adv_example, conf_y_adv_example = FGSM_targeted(X_test[indice_image_test],y_target,eps)\n",
-    "    plt.subplot(3,3,y_target+1,xticks=[],yticks=[])\n",
+    "    plt.subplot(3,3,y_target+3,xticks=[],yticks=[])\n",
     "    plt.imshow(np.array(adv_example).reshape(100,150,3))\n",
-    "    plt.text(-1,-5,\"Classe \"+str(y_adv_example)+\" - Confiance: \"+str(conf_y_adv_example))\n",
+    "    plt.text(-1,-5,\"Classe \"+dict_class_names[y_adv_example]+\" - Confiance: \"+str(conf_y_adv_example))\n",
     "plt.suptitle(\"exemples contradictoires pour chaque classe\")\n",
     "plt.show()"
    ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
   }
  ],
  "metadata": {
   "kernelspec": {
-   "display_name": "base",
+   "display_name": "Python 3 (ipykernel)",
    "language": "python",
    "name": "python3"
   },
@@ -950,7 +966,7 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.12.7"
+   "version": "3.7.13"
   }
  },
  "nbformat": 4,