{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "3875d9e3-581d-4e7e-859b-b22d622a22f8",
   "metadata": {},
   "source": [
    "# Reconnaître des fleurs / réseau de neurones"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "6e653d6f-4a1a-492b-8d9f-32d826146fd8",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-04T20:57:15.593435Z",
     "iopub.status.busy": "2026-08-04T20:57:15.593078Z",
     "iopub.status.idle": "2026-08-04T20:57:15.937609Z",
     "shell.execute_reply": "2026-08-04T20:57:15.937113Z"
    }
   },
   "outputs": [],
   "source": [
    "import math\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3a4f25d1-5281-41bd-b8cd-f82e55614221",
   "metadata": {},
   "source": [
    "# Réseau de neurones\n",
    "\n",
    "## Généralités\n",
    "On va commencer par le tout début. Intuitivement pour reconnaître une fleur il faut la regarder. Si on a un doute on peut y regarder de plus près en mesurant les dimensions de ses composants. En réalité dans notre cas on va utiliser les pixels de l'image donnée par l'utilisateur pour deviner de quelle fleur il s'agit.\n",
    "\n",
    "L'ensemble des données qu'on \"regarde de plus près\" pour distinguer une fleur d'une autre va nous servir d'input. Ce sera $x$.\n",
    "Ensuite il faut savoir quelle importance on accorde à chaque valeur de $x$ dans la décision qu'on prendra. On appelle ça le poids associé à une valeur, $w$. Enfin il faut tenir compte de $b$ qui est notre biais.\n",
    "\n",
    "Au passage c'est amusant comme on en apprend plus sur \"comment prendre des décisions\" avec cette méthode de poids à donner à chaque élément qui entre en considération dans le choix à faire. J'avais vu quelques reels insta qui parlaient de \"la meilleure méthode pour faire un choix\" qui décrivaient une matrice de poids pour pondérer chaque élément pour prendre sa décision de la façon la plus optimale possible.\n",
    "\n",
    "## À quoi sert $b$ ?\n",
    "Si on considère une droite d'équation $y=ax$ on se prive de beaucoup d'autres \"droites\". L'idée de rajouter $b$ dans l'équation d'une droite affine est qu'on peut \"décaler\" la droite et ainsi considérer d'autres cas.\n",
    "\n",
    "Autrement dit, la seule façon de pouvoir représenter toutes les droites du plan et de n'en exclure aucune c'est de rajouter notre $b$ tout $b$-tement :)\n",
    "\n",
    "In fine, notre réseau de neurones va apprendre au fur et à mesure de l'entrainement les poids qui lui permettent de prédire le plus fidèlement possible l'espèce de fleur pour enfin prédire la fleur présentée. La fin de ce notebook sera dédiée à montrer un exemple d'entrainement avec le [dataset Iris de scikit](https://scikit-learn.org/stable/modules/generated/sklearn.datasets.load_iris.html)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "56807eb1-938a-431d-95be-d490a49e7c6c",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-04T20:57:15.939364Z",
     "iopub.status.busy": "2026-08-04T20:57:15.939190Z",
     "iopub.status.idle": "2026-08-04T20:57:16.039509Z",
     "shell.execute_reply": "2026-08-04T20:57:16.039009Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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a9fbvk5kZKQClLe3tzp9+nTa8a1btypADRkyJO3YqFGj1M3/lZOSkjI8Z5s2bdR9992X7lizZs1Us2bN0vafeOIJVbVq1dvWlpmsPK5r164qPDw8w/HM6geU0WhU//77b5Ze/+bvY86cOcpoNKo///wz3XnTpk1TgNq4ceMtn2vXrl0KUD///PMtzzl+/LgymUzqgw8+SHd83759ysPDI93xW/1731zztX/z2bNnpx3L7L25mc1mU8HBwapWrVrKarWmHZ8xY4YCXPa+XKsZUOPHj087ZrVaVa1atVRwcLCy2WxKKaXsdnu6WpRS6sqVKyokJER179497digQYNUQECAstvtt3zNkSNHKkAtWLAgw31Op1Mpdf33yI3//5RSau3atQpQa9euTTt288/hn3/+qQD1/fffp3vs8uXLMz0u8ga5LCXcwpQpU1i1alW627Jly+76+X7++WeaNm1K4cKFuXjxYtqtZcuWOBwONmzYcFfPu3TpUho0aED9+vXTjhUrVowXXnjhrmu9nSeffJLQ0NC0/fr16xMREcHSpUtv+7gbW5KutYo1a9aMY8eOZbi0cqNChQpx+vRp/v7772zVebePu51mzZpl2scqK37++WcqV65MpUqV0v37t2jRAiDTyyPXXGuZWbFiBUlJSZmes2DBApxOJx07dkz3/MWLF6dChQq3fX5X2759O9HR0fTp0yddH6pu3bqlfS/X5OR9ucbDw4PevXun7ZvNZnr37k10dDQ7duwAwGQypdXidDq5fPkydrudevXqsXPnzrTHFipUiMTERFatWnXL1/vll1+oWbMmTz31VIb7cjJM/pqff/6ZwMBAWrVqle49qVu3Ln5+fvf031K4jlyWEm6hfv36d+xQnB2HDx9m7969aX1qbhYdHX1Xz3vixAkiIiIyHK9YseJdPd+dVKhQIcOx+++/n3nz5t32cRs3bmTUqFFs3rw5wwd0bGxshg+9a4YNG8bq1aupX78+5cuXp3Xr1nTu3JnGjRvf9vXu9nG3k9nouaw6fPgwBw4cuKt//7JlyzJ06FA+/fRTvv/+e5o2bcrjjz/Oiy++mPa+HT58GKVUpv8+wD29jHHixAkg48+Kp6cn9913X7pjOXlfrilZsiS+vr7pjt1///2A1m+oQYMGAHzzzTeMHz+e//77j9TU1LRzb/x3ffXVV5k3bx5t27YlNDSU1q1b07Fjx3TTORw9epRnnnnmjnXdrcOHDxMbG0twcHCm99/t7wqhLwk3Il9yOp20atWKN998M9P7r/0y1oPD4cjV5z969CgPP/wwlSpV4tNPPyUsLAyz2czSpUuZMGFCpp2fr6lcuTIHDx7k999/Z/ny5fzyyy988cUXjBw5Mm3I/N0+7lZ/Zd/q/chJPyan00n16tX59NNPM73/xn4omRk/fjzdunXj119/ZeXKlQwcOJCxY8eyZcsWSpUqhdPpxGAwsGzZMkwmU4bH+/n5pW3f7vvO7LG5KafvS1Z99913dOvWjSeffJI33niD4OBgTCYTY8eO5ejRo2nnBQcHs3v3blasWMGyZctYtmwZs2fPpkuXLnzzzTdZfr3s/mzdyOl0EhwczPfff5/p/bcKgsK9SbgR+VK5cuVISEigZcuWtz0vu83a4eHhHD58OMPxgwcPZjhWuHBhYmJi0h2z2WycO3cuy6+X2WsdOnTotp1rf/vtN6xWK4sXL6Z06dJpx7PavO7r60unTp3o1KkTNpuNp59+mg8++IARI0bcdqjynR6X2fsB11seXKlcuXLs2bOHhx9++K4vXVSvXp3q1avz9ttvs2nTJho3bsy0adN4//33KVeuHEopypYte8egfLvv++aWlbsRHh4OaD8r1y4vAaSmphIZGUnNmjXTjrnifTl79iyJiYnpWm8OHToEkPZzOX/+fO677z4WLFiQ7nVunqMKtMta7du3p3379jidTl599VWmT5/OO++8Q/ny5SlXrlyGEYI3K1y4MECG9zkrP1vlypVj9erVNG7cONcGBoh7T/rciHypY8eObN68mRUrVmS4LyYmBrvdDoCPj0/asax49NFH2bJlC9u2bUs7duHChUz/6itXrlyGvj0zZszIVsvNokWLOHPmTNr+tm3b2Lp1K23btr3lY661Biil0o7FxsYye/bsO77epUuX0u2bzWaqVKmCUirdpYW7eVy5cuWIjY1l7969aeedO3eOhQsX3rGu7OrYsSNnzpxh5syZGe5LTk4mMTHxlo+Ni4tL+/m4pnr16hiNxrTh0k8//TQmk4nRo0ene59Be99vfD/KlSvHli1bsNlsacd+//33DEPG71a9evUoVqwY06ZNS/caX3/9dYaf65y8L9fY7XamT5+etm+z2Zg+fTrFihWjbt26QOY/g1u3bmXz5s3p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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def sigmoid(z):\n",
    "    return 1 / (1 + np.exp(-z))\n",
    "\n",
    "w = 1\n",
    "x = np.linspace(0, 6, 200)\n",
    "\n",
    "biais = [0, -1, -3]\n",
    "couleurs = [\"gold\", \"cornflowerblue\", \"orangered\"]\n",
    "\n",
    "for b, c in zip(biais, couleurs):\n",
    "    plt.plot(x, sigmoid(w * x + b), color=c, label=f\"b = {b}\")\n",
    "\n",
    "plt.xlabel(\"longueur du pétale (cm)\")\n",
    "plt.ylabel(\"sortie du neurone\")\n",
    "plt.title(\"Effet du biais sur le seuil de bascule\")\n",
    "plt.legend()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "69f5102f-8147-4445-bc78-829338199fef",
   "metadata": {},
   "source": [
    "On voit bien que la sortie de notre neurone est directement impactée par le biais choisi et que les valeurs que pourront prendre notre sortie en fonction de la longueur du pétale ne sont pas du tout semblables d'un biais $b$ à l'autre."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "16f3d422-6593-4878-8c09-e96ab82ce9bf",
   "metadata": {},
   "source": [
    "## Concrètement\n",
    "Un neurone artificiel va recevoir un vecteur d'entrée $x$ et calcule d'abord une somme pondérée : \n",
    "\\begin{equation}\n",
    "z = \\sum_{i=1}^{n} w_i x_i + b\n",
    "\\end{equation}\n",
    "\n",
    "Cette formule illustre simplement qu'on attribue un poids (de l'importance) à chaque valeur d'entrée pour notre réseau donc dans notre cas, des mesures caractéristiques d'une fleur.\n",
    "\n",
    "Ensuite on passe ce résultat dans une fonction d'activation. Sans cette activation, empiler des neurones ne servirait à rien : une composition de fonctions linéaires reste une fonction linéaire, donc un réseau à 100 couches sans activation équivaudrait à une seule couche. L'activation est ce qui permet au réseau d'apprendre des relations non linéaires.\n",
    "\n",
    "### Pourquoi une fonction d'activation ?\n",
    "Imaginons deux couches sans activation :\n",
    "\n",
    "\\begin{align} \n",
    "z_1 = W_1x+b_1 \\qquad \\qquad z_2 = W_2z_1+b_2 \n",
    "\\end{align}\n",
    "\n",
    "En substituant :\n",
    "$z_2 = W_2(W_1x+b_1) + b_2$\n",
    "\n",
    "On pose : $W'=W_2W_1$ et $b'=b_2+W_2b_1$\n",
    "\n",
    "On obtient : $z_2=W'x+b' $\n",
    "\n",
    "C'est mauvais, notre $z_2$ s'écrit en fonction de $x$ donc aucun intérêt... \n",
    "La fonction d'activation casse cette composition en introduisant une non-linéarité entre les couches, donc $z_2$ n'est plus une fonction affine de $x$. Le réseau peut alors représenter des frontières de décision courbes, pas seulement des hyperplans.\n",
    "\n",
    "### Deux fonctions d'activation\n",
    "\n",
    "- Sigmoïde : $\\sigma(z) = \\frac{1}{1+e^{-z}}$\n",
    "- ReLU : $ReLU(z)=max(0,z)$\n",
    "\n",
    "Ce serait super intéressant de voir quel impact a le choix de la fonction d'activation sur un réseau de neurones !!"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3527869b-e8b0-4302-9e4c-46d8de3816b2",
   "metadata": {},
   "source": [
    "# Le neurone"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "3c0f93a6-6029-431b-a3c7-2796ddd04e6a",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-04T20:57:16.041216Z",
     "iopub.status.busy": "2026-08-04T20:57:16.041096Z",
     "iopub.status.idle": "2026-08-04T20:57:16.043487Z",
     "shell.execute_reply": "2026-08-04T20:57:16.043031Z"
    }
   },
   "outputs": [],
   "source": [
    "def neurone(x, w, b):\n",
    "    z = b\n",
    "    for k in range(len(x)):\n",
    "        z += x[k] * w[k]\n",
    "    # fonction d'activation\n",
    "    a = 1 / (1 + np.exp(-z))    \n",
    "    return a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "43156024-a4ad-4f33-8dfa-c456ad819390",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-04T20:57:16.044889Z",
     "iopub.status.busy": "2026-08-04T20:57:16.044770Z",
     "iopub.status.idle": "2026-08-04T20:57:16.047533Z",
     "shell.execute_reply": "2026-08-04T20:57:16.047131Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(0.5)"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "neurone([1,2], [0.5,-0.3], 0.1)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a9240f7d-3537-4a80-b10b-4dfb4c11ed2f",
   "metadata": {},
   "source": [
    "On vient de définir notre premier neurone avec cette fonction `neurone` !\n",
    "Concrètement, un neurone prend en entrée :\n",
    "- $x$ correspond à des mesures (par exemple le diamètre de l'iris et le nombre de pétales) ;\n",
    "- $w$ correspond aux poids (à l'importance) qu'on donne  à chaque valeur de $x$ ;\n",
    "- $b$ notre biais, comme expliqué plus haut.\n",
    "\n",
    "Le neurone retourne en sortie une valeur qui servira à déterminer le choix de réponse que fera notre réponse."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b9a5498e-255b-4127-b08a-c7dd11e5a1ec",
   "metadata": {},
   "source": [
    "# La couche de neurones"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4426dbe2-e0f9-4091-bf75-adeda93348b5",
   "metadata": {},
   "source": [
    "À présent il faut définir une couche de neurones et pour cela on va passer à la dimension supérieure.\n",
    "Notre fonction qu'on appellera `couche` prend en entrée :\n",
    "- $x$ correspond toujours à nos mesures ;\n",
    "- $W$ correspond cette fois à une matrice de poids où $w_{ij}$ est le poids attribué à la valeur $j$ du neurone $i$ ;\n",
    "- $B$ notre biais qui est maintenant une matrice puisqu'il faut en attribuer un à chaque neurone. Ainsi $b_j$ est le biais du neurone $j$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "d509479d-c8ca-4afd-b1d3-6c51c4946902",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-04T20:57:16.048689Z",
     "iopub.status.busy": "2026-08-04T20:57:16.048587Z",
     "iopub.status.idle": "2026-08-04T20:57:16.050603Z",
     "shell.execute_reply": "2026-08-04T20:57:16.050223Z"
    }
   },
   "outputs": [],
   "source": [
    "def couche(x, W, B):\n",
    "    # np.dot pour le produit matriciel et éviter une boucle for -> ça marche aussi avec @\n",
    "    z = np.dot(W, x) + B\n",
    "    # toujours notre fonction d'activation\n",
    "    a = 1 / (1 + np.exp(-z))\n",
    "    return a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "5f8710e0-e38a-456d-aa6b-d22a2a5ab12a",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-04T20:57:16.052160Z",
     "iopub.status.busy": "2026-08-04T20:57:16.052011Z",
     "iopub.status.idle": "2026-08-04T20:57:16.055033Z",
     "shell.execute_reply": "2026-08-04T20:57:16.054576Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0.5        0.66818777 0.78583498]\n"
     ]
    }
   ],
   "source": [
    "x = [1, 2]\n",
    "W = [[0.5, -0.3], [0.1, 0.4], [-0.2, 0.6]]\n",
    "B = [0.1, -0.2, 0.3]\n",
    "print(couche(x, W, B))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ac7fbc29-1b7f-496e-aeda-3d2378750856",
   "metadata": {},
   "source": [
    "On utilisera $W$ en majuscule car il s'agit maintenant d'une matrice et plus simple d'un vecteur. En effet, pour une couche nous aurons plusieurs neurones et donc des poids propre à chaque neurone.\n",
    "\n",
    "Si on veut interpréter notre matrice $W$, on peut dire que :\n",
    "- le premier neurone de notre couche attribue un poids de $0.5$ à la première valeur de $x$ et un poids de $-0.3$ à la deuxième valeur de $x$ ;\n",
    "- le deuxième neurone de notre couche attribue un poids de $0.1$... ;\n",
    "- et ainsi de suite.\n",
    "\n",
    "Concernant la signification de la sortie de la fonction `couche`, chaque valeur de notre vecteur représente le niveau d'activation d'un neurone. On peut donc savoir quel neurone a joué quel rôle dans la décision au sein d'une couche ! \n",
    "\n",
    "Ça nous servira grandement dans la backpropagation pour modifier les poids et biais attribués dans l'entrainement."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b4164699-c16e-4632-aed2-89abdf5aa8cf",
   "metadata": {},
   "source": [
    "# La propagation"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4df05d81-44a1-4a57-80f0-410c8ea43a51",
   "metadata": {},
   "source": [
    "Maintenant on introduit la fonction `forward` pour aller de l'avant. J'ai pas trouvé mieux comme phrase d'accroche...\n",
    "\n",
    "On va maintenant pouvoir, grâce à notre fonction `forward`, passer d'une couche à l'autre en récupérant les niveaux d'activation des neurones détecteurs de la première couche pour nourrir la couche de décision, qui nous donnera un score par espèce de fleur candidate."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "0b0b60a3-1729-4cb4-8e7d-c1ff12cbc0e3",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-04T20:57:16.056299Z",
     "iopub.status.busy": "2026-08-04T20:57:16.056177Z",
     "iopub.status.idle": "2026-08-04T20:57:16.058356Z",
     "shell.execute_reply": "2026-08-04T20:57:16.057934Z"
    }
   },
   "outputs": [],
   "source": [
    "def forward(x, W1, B1, W2, B2):\n",
    "    a1 = couche(x, W1, B1)\n",
    "    a2 = couche(a1, W2, B2)\n",
    "    return a2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "3935f09f-2504-4500-8899-e13779bccac8",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-04T20:57:16.059421Z",
     "iopub.status.busy": "2026-08-04T20:57:16.059310Z",
     "iopub.status.idle": "2026-08-04T20:57:16.062362Z",
     "shell.execute_reply": "2026-08-04T20:57:16.062054Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0.99966465, 0.99999774, 0.99999998])"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "forward([1, 2, 3, 4], [[1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3], [4, 4, 4, 4], [5, 5, 5, 5]], [5, 5, 5, 5, 5], [[1, 1, 1, 1, 1], [2, 2, 2, 2, 2], [3, 3, 3, 3, 3]], [3, 3, 3])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d84f21cc-8246-4109-92e4-92d1a1dc0672",
   "metadata": {},
   "source": [
    "Ah oui et il faut mesurer si la prédiction est proche de la réalité !\n",
    "\n",
    "Pour cela, on introduit une fonction `cout` qui utilise l'erreur quadratique moyenne pour savoir à quel point notre prédiction est proche de la réalité ou non.\n",
    "La fonction `cout` prend en entrée la prédiction de notre réseau de neurones `pred` ainsi que ce qu'on attend `reel` et retourne l'erreur quadratique moyenne grâce à la formule suivante : \n",
    "\n",
    "\\begin{equation}\n",
    "Err = \\frac{1}{n} \\sum_{i=1}^{n} (pred_{i} - reel_{i})^2\n",
    "\\end{equation}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "092e1562-3f21-4b69-a405-d8062d36ae26",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-04T20:57:16.063678Z",
     "iopub.status.busy": "2026-08-04T20:57:16.063567Z",
     "iopub.status.idle": "2026-08-04T20:57:16.065605Z",
     "shell.execute_reply": "2026-08-04T20:57:16.065298Z"
    }
   },
   "outputs": [],
   "source": [
    "def cout(pred, reel):\n",
    "    n = len(reel)\n",
    "    err = (1 / n) * sum((pred[i] - reel[i])**2 for i in range(n)) \n",
    "    return err"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "77549e79-e4d3-4462-bdee-1e61cf999d86",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-04T20:57:16.066971Z",
     "iopub.status.busy": "2026-08-04T20:57:16.066857Z",
     "iopub.status.idle": "2026-08-04T20:57:16.069317Z",
     "shell.execute_reply": "2026-08-04T20:57:16.068971Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.4866666666666667"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pred = [0.1, 0.1, 0.8]\n",
    "reel = [1, 0, 0]\n",
    "\n",
    "cout(pred, reel)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6ad5b71c-0175-46cf-a994-0b7589b3fd09",
   "metadata": {},
   "source": [
    "# Le gradient\n",
    "\n",
    "Reprenons l'erreur quadratique moyenne introduite plus haut : $(1/n) \\sum (prédiction - vraie\\_valeur)^2$. Pour comprendre la descente de gradient sans se noyer dans les couches, on va en isoler un seul terme.\n",
    "\n",
    "Posons donc $C(w) = (w - 3)^2$. Ici, $w$ joue le rôle de la sortie prédite, et 3 celui de la vraie valeur attendue : on entraîne $w$ à se rapprocher d'une cible fictive fixée à 3. Le minimum théorique de cette fonction se situe donc en $w = 3$, exactement là où l'erreur s'annule.\n",
    "\n",
    "Le gradient n'est pas un outil de mesure indépendant. C'est la dérivée de la fonction de coût, calculée au point où $w$ se trouve actuellement. La fonction de coût dessine la courbe des erreurs possibles, et le gradient en donne la pente locale, exactement là où on se situe. Dans la boucle `w = w - n * f(w)`, `f(w)` désigne donc cette dérivée, pas le coût lui-même — c'est elle qui indique la direction et l'intensité de la correction à apporter à $w$.\n",
    "\n",
    "Près du minimum, l'écart $(w - 3)$ devient minuscule. Et comme la pente $2(w-3)$ en dépend directement, elle s'aplatit aussi, mécaniquement. Les pas rétrécissent donc naturellement à l'approche de la solution, ce qui explique pourquoi il faut davantage d'epochs pour finir de converger que pour s'en approcher grossièrement.\n",
    "\n",
    "Cet exemple à un seul poids n'est qu'un cas particulier : dès qu'on passera à un réseau à plusieurs couches, la même logique s'appliquera à chaque poids, seule la dimension change."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "c29ee342-fdc4-410d-91db-6caa04e2578c",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-04T20:57:16.070848Z",
     "iopub.status.busy": "2026-08-04T20:57:16.070732Z",
     "iopub.status.idle": "2026-08-04T20:57:16.072729Z",
     "shell.execute_reply": "2026-08-04T20:57:16.072376Z"
    }
   },
   "outputs": [],
   "source": [
    "def gradient(w, eta, f, epochs):    \n",
    "    for k in range(epochs):\n",
    "        w = w - eta * f(w)\n",
    "    return w"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "87a35706-6ab2-4db5-9ef7-1b724e25a0da",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-04T20:57:16.074069Z",
     "iopub.status.busy": "2026-08-04T20:57:16.073955Z",
     "iopub.status.idle": "2026-08-04T20:57:16.076452Z",
     "shell.execute_reply": "2026-08-04T20:57:16.076036Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2.9999999993888893"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "gradient(0, 0.1, lambda w : 2 * (w - 3), 100)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2a79ad65-8bc5-4159-85d1-11ac36778aed",
   "metadata": {},
   "source": [
    "Petite illustration pour comprendre comment on approche la valeur $3$ dans notre exemple avec une fonction $(w - 3)^2$ :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "6abcc70b-b155-4f92-a8ad-7ea956bad90d",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-04T20:57:16.077588Z",
     "iopub.status.busy": "2026-08-04T20:57:16.077482Z",
     "iopub.status.idle": "2026-08-04T20:57:16.177934Z",
     "shell.execute_reply": "2026-08-04T20:57:16.177463Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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fLeLFy+WyfkLKxwOHjzI888/XyYZyqONGzcSHx/Phg0byMzMZP369UaPd+zYkQkTJqgTTggTI519hTBz3bt3Z+nSpUbbPD09VUpTPs6vtu7du9O9e3cAfv75Z5XTCGHapEXmAW04cYORyw5y+MpttaMIcU82Njb4+PgY3bRaLQA7d+6kefPm2NjY4Ovry5QpU8jOzjY8t2PHjowbN47XXnsNNzc3fHx8mD59utHx4+PjeeGFF/D29sbW1pb69euzfv16duzYwYgRI0hISDC0BOU99+5LS1evXqVPnz44Ojri7OzMoEGDiImJMTw+ffp0GjVqxIoVKwgMDMTFxYWnnnqKpKSke772ZcuWUbVqVezt7enXrx+3bt3Kt89vv/1GkyZNsLW1pVq1asyYMcPoa1CQb775hnr16hm+bmPHji3yaxk+fDh9+/Y1Ot6ECRPo2LGj4fGdO3cyb948w9ctIiLinnmEUMtPB68y8adjqv4ulELmAW0+HcPWs7H8fixK7ShCJYqikJqZXeY3RVFKJP/169fp2bMnzZo1IywsjEWLFvH1118za9Yso/2+/fZbHBwc2L9/Px9++CEzZ85k8+bNQM78Oj169GDPnj189913nD59mvfffx+tVkvr1q2ZO3cuzs7O3Lhxgxs3bjB58uR8OfR6PX369OH27dvs3LmTzZs3c/nyZZ588kmj/S5dusTatWtZv34969evZ+fOnbz//vuFvr79+/czcuRIxo4dy7Fjx+jUqVO+17Zr1y6GDh3K+PHjOX36NIsXL2bZsmXMnj270OMuWrSIMWPG8Pzzz3PixAl+//13atSoUazXci/z5s2jVatWjB492vB18/f3L/LzhShLqw5d49ej1wmLTFAtg1xaekC9G/rx69Hr/Hkymrd710NrIZOjVTRpWTrqvr2pzM97emY37K2L/qO7fv16HB0dDfd79OjB6tWr+eKLL/D392fBggVoNBpq165NVFQUr7/+Om+//bZhCG2DBg145513AAgODmbBggVs3bqVRx55hC1btnDgwAHOnDlDzZo1AahWrZrhXC4uLmg0Gnx8fArNt3XrVk6cOEF4eLjhF/by5cupV68eBw8epFmzZkBOkbBs2TKcnJwAGDJkCFu3bi206Jg3bx7du3fntddeA6BmzZr8888/bNy40bDPjBkzmDJlCsOGDTNkf/fdd3nt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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def cout_exemple(w):\n",
    "    return (w - 3)**2\n",
    "\n",
    "def gradient_cout(w):\n",
    "    return 2 * (w - 3)\n",
    "\n",
    "w = -4.0\n",
    "eta = 0.1\n",
    "epochs = 15\n",
    "\n",
    "trajectoire = [w]\n",
    "for k in range(epochs):\n",
    "    w = w - eta * gradient_cout(w)\n",
    "    trajectoire.append(w)\n",
    "\n",
    "trajectoire = np.array(trajectoire)\n",
    "w_range = np.linspace(-5, 11, 200)\n",
    "\n",
    "plt.plot(w_range, cout_exemple(w_range), label=\"Fonction de coût\")\n",
    "\n",
    "plt.scatter(trajectoire, cout_exemple(trajectoire), color=\"crimson\", label=\"Étapes de la descente\") #j'adore king crimson donc j'utilise souvent le rouge crimson\n",
    "\n",
    "plt.xlabel(\"w (paramètre)\")\n",
    "plt.ylabel(\"Coût\")\n",
    "plt.title(\"Descente de gradient sur une fonction de coût\")\n",
    "plt.legend()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5b9d0d67-0116-4fd8-bb8b-849c1ce4db89",
   "metadata": {},
   "source": [
    "# La backpropagation\n",
    "\n",
    "La backpropagation, ou rétropropagation, c'est la technique qui permet de calculer comment chaque poids d'un réseau a contribué à l'erreur finale. Le principe : remonter la chaîne de calculs à l'envers, de la sortie vers l'entrée, en appliquant la règle de la chaîne à chaque étape.\n",
    "\n",
    "Ici, avec un seul neurone, cette chaîne est courte : $w, b \\to z \\to a \\to L$. Le mécanisme reste rigoureusement le même que dans un réseau à plusieurs couches, où l'erreur doit simplement traverser bien plus d'étapes avant d'atteindre les premiers poids.\n",
    "\n",
    "## Pourquoi cette fonction\n",
    "\n",
    "Notre neurone part avec des poids $w$ et $b$ tirés au hasard, donc ses prédictions initiales n'ont aucun sens. Le but de `entraine_neurone` est de corriger ces deux valeurs, petit à petit, jusqu'à ce que la sortie $a$ colle à la vraie valeur $y$.\n",
    "\n",
    "Chaque tour de boucle répète le même geste : regarder ce que prédit le neurone avec ses poids actuels, mesurer à quel point il se trompe, puis ajuster $w$ et $b$ dans la direction qui réduit cette erreur. Le paramètre `epochs` fixe simplement combien de fois on répète ce geste et comme on l'a vu avec la parabole, plus on s'approche de la bonne réponse, plus les ajustements deviennent fins, donc plus il en faut pour peaufiner le résultat.\n",
    "\n",
    "Reste à savoir comment calculer, à chaque tour, la direction et l'intensité de cet ajustement. C'est le rôle de `grad_w` et `grad_b`, détaillés ci-dessous qui sont les deux sorties concrètes de cette rétropropagation, appliquées à notre neurone unique.\n",
    "\n",
    "## Calcul de `grad_w` et `grad_b`\n",
    "\n",
    "Le coût $L$ ne dépend pas directement de $w$ et $b$ : il faut passer par $z$ puis par $a$.\n",
    "\n",
    "$z = wx + b \\qquad a = \\frac{1}{1+e^{-z}} \\qquad L = (a - y)^2$\n",
    "\n",
    "- Dérivées partielles de chaque maillon\n",
    "\n",
    "$$\n",
    "\\frac{\\partial L}{\\partial a} = 2(a - y)\n",
    "\\qquad\n",
    "\\frac{\\partial a}{\\partial z} = a(1-a)\n",
    "\\qquad\n",
    "\\frac{\\partial z}{\\partial w} = x\n",
    "\\qquad\n",
    "\\frac{\\partial z}{\\partial b} = 1\n",
    "$$\n",
    "\n",
    "- Application de la règle de la chaîne\n",
    "\n",
    "$$\n",
    "\\frac{\\partial L}{\\partial w} = \\frac{\\partial L}{\\partial a} * \\frac{\\partial a}{\\partial z} * \\frac{\\partial z}{\\partial w} = 2(a-y)\\,a(1-a)\\,x\n",
    "$$\n",
    "\n",
    "$$\n",
    "\\frac{\\partial L}{\\partial b} = \\frac{\\partial L}{\\partial a} * \\frac{\\partial a}{\\partial z} * \\frac{\\partial z}{\\partial b} = 2(a-y)\\,a(1-a)\n",
    "$$\n",
    "\n",
    "Ces deux expressions correspondent directement à `grad_w` et `grad_b` dans le code : seule la dernière étape de la chaîne diffère ($x$ contre $1$), puisque $z$ dépend de $w$ et de $b$ différemment."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "d78fa62d-0469-4ac9-8fc3-a23c78599064",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-04T20:57:16.179489Z",
     "iopub.status.busy": "2026-08-04T20:57:16.179375Z",
     "iopub.status.idle": "2026-08-04T20:57:16.182184Z",
     "shell.execute_reply": "2026-08-04T20:57:16.181756Z"
    }
   },
   "outputs": [],
   "source": [
    "def entraine_neurone(x, y, w, b, eta, epochs):\n",
    "    for k in range(epochs):\n",
    "        z = w * x + b\n",
    "        a = 1 / (1 + math.exp(-z))\n",
    "\n",
    "        grad_w = 2 * (a - y) * a * (1 - a) * x\n",
    "        grad_b = 2 * (a - y) * a * (1 - a)\n",
    "\n",
    "        w = w - eta * grad_w\n",
    "        b = b - eta * grad_b\n",
    "\n",
    "        L = (a - y) ** 2\n",
    "        \n",
    "        if k % 10 == 0:\n",
    "            print(f\"epoch {k}: L = {L}, a = {a}\")\n",
    "\n",
    "    return w, b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "1cbe2d23-02c5-43c2-885b-8dfe64fe9e28",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-04T20:57:16.183384Z",
     "iopub.status.busy": "2026-08-04T20:57:16.183276Z",
     "iopub.status.idle": "2026-08-04T20:57:16.186257Z",
     "shell.execute_reply": "2026-08-04T20:57:16.185825Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch 0: L = 0.2026494299756621, a = 0.549833997312478\n",
      "epoch 10: L = 0.012789758486928291, a = 0.8869081855883093\n",
      "epoch 20: L = 0.006117578641277499, a = 0.9217850484799901\n",
      "epoch 30: L = 0.003971275232485292, a = 0.9369819451864365\n",
      "epoch 40: L = 0.002925439919070996, a = 0.9459126639676995\n",
      "epoch 50: L = 0.0023097273937545183, a = 0.9519403766790197\n",
      "epoch 60: L = 0.0019052281965053553, a = 0.956351080236673\n",
      "epoch 70: L = 0.0016196856219379784, a = 0.9597546819873668\n",
      "epoch 80: L = 0.0014076068454612083, a = 0.9624819130890019\n",
      "epoch 90: L = 0.0012440118590713951, a = 0.9647294477067427\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "(1.3663695296410523, 0.6331847648205262)"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "entraine_neurone(2, 1, 0.1, 0, 0.5, 100)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "18b8cb92-4a66-4575-9b45-04956b17ecbc",
   "metadata": {},
   "source": [
    "# Neurone into couche\n",
    "\n",
    "La logique ne change pas : on cherche toujours à corriger des poids en suivant le gradient du coût. Ce qui change, c'est l'échelle. Au lieu d'un seul `w` et un seul `b`, on a maintenant une matrice `W` et un vecteur `b`, parce que la couche produit plusieurs sorties à la fois (une par neurone). Le calcul se vectorise, mais chaque neurone de la couche suit individuellement le même raisonnement que celui vu précédemment avec `entraine_neurone`.\n",
    "\n",
    "## Le rôle de `delta`\n",
    "\n",
    "`delta` généralise ce qu'on calculait avant en une seule valeur : c'est maintenant un vecteur, avec une composante par neurone de sortie. Pour un neurone $j$ donné, sa composante vaut :\n",
    "\n",
    "$\\delta_j = \\frac{\\partial L}{\\partial z_j} = \\frac{2}{n_{out}}(a_j - y_j)\\,a_j(1-a_j)$\n",
    "\n",
    "C'est exactement la formule de `grad_w` dans `entraine_neurone`, avant la multiplication par `x`, le facteur $\\frac{2}{n_{out}}$ vient simplement de la moyenne dans le coût $L = \\frac{1}{n_{out}}\\sum_j (a_j - y_j)^2$. Chaque $\\delta_j$ mesure donc à quel point le neurone $j$ s'est trompé, et dans quelle direction.\n",
    "\n",
    "## De `delta` aux gradients\n",
    "\n",
    "Pour un neurone $j$, le poids reliant l'entrée $k$ à ce neurone s'appelle $W_{jk}$. La règle de la chaîne donne :\n",
    "\n",
    "$$\n",
    "\\frac{\\partial L}{\\partial W_{jk}} = \\delta_j * x_k\n",
    "\\qquad\\qquad\n",
    "\\frac{\\partial L}{\\partial b_j} = \\delta_j\n",
    "$$\n",
    "\n",
    "Rien de neuf ici : $\\frac{\\partial z_j}{\\partial W_{jk}} = x_k$ et $\\frac{\\partial z_j}{\\partial b_j} = 1$, comme pour le neurone seul. La seule nouveauté, c'est qu'il faut répéter ce calcul pour chaque paire $(j, k)$ et c'est précisément ce que fait le produit extérieur :\n",
    "\n",
    "$$\n",
    "\\text{grad\\_W} = \\delta \\otimes x\n",
    "\\quad\\Leftrightarrow\\quad\n",
    "\\text{grad\\_W}_{jk} = \\delta_j \\, x_k\n",
    "$$\n",
    "\n",
    "`np.outer(delta, x)` construit exactement cette matrice, de forme $(n_{out}, n_{in})$, la même que `W`. Quant à `grad_b`, il vaut directement `delta` : aucune transformation nécessaire, puisque $\\frac{\\partial z_j}{\\partial b_j} = 1$ pour chaque neurone.\n",
    "\n",
    "## En résumé\n",
    "\n",
    "`entraine_couche` empile donc, en une seule opération matricielle, ce que `entraine_neurone` faisait pour un seul neurone. `delta` porte l'erreur de chaque neurone ; l'outer product la distribue vers chaque poids concerné. La mécanique de descente reste identique. On soustrait toujours `eta * grad_W` et `eta * grad_b`, seule la dimension du problème a changé."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4f250569-4994-46a2-9410-16bf815bafc2",
   "metadata": {},
   "source": [
    "**Remarque.** Pourquoi $\\otimes$ et pas $*$ ?\n",
    "\n",
    "`*` désigne une multiplication élément par élément entre deux objets de même taille. Or `delta` (taille $n_{out}$) et `x` (taille $n_{in}$) n'ont pas la même dimension : `delta * x` n'a donc aucun sens ici.\n",
    "\n",
    "$\\otimes$ (que j'ai découvert exactement avant hier) note le produit extérieur (*outer product*) : il prend deux vecteurs de tailles différentes et produit une matrice, où chaque case $(j,k)$ contient $\\delta_j \\, x_k$. C'est un objet différent : deux vecteurs entrent, une matrice sort, d'où une notation distincte. D'ailleurs `np.outer(delta, x)` calcule exactement cette matrice."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "2576eae4-cb43-4489-8570-8ab71b621a1f",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-04T20:57:16.187469Z",
     "iopub.status.busy": "2026-08-04T20:57:16.187354Z",
     "iopub.status.idle": "2026-08-04T20:57:16.190016Z",
     "shell.execute_reply": "2026-08-04T20:57:16.189672Z"
    }
   },
   "outputs": [],
   "source": [
    "def entraine_couche(x, y, W, b, eta, epochs):\n",
    "    for k in range(epochs):\n",
    "        z = np.dot(W, x) + b\n",
    "        a = 1 / (1 + np.exp(-z))\n",
    "\n",
    "        n_out = len(y)\n",
    "        delta = (2 / n_out) * (a - y) * a * (1 - a)\n",
    "\n",
    "        grad_W = np.outer(delta, x)\n",
    "        grad_b = delta\n",
    "\n",
    "        W = W - eta * grad_W\n",
    "        b = b - eta * grad_b\n",
    "\n",
    "        L = np.mean((a - y) ** 2)\n",
    "        \n",
    "        if k % 10 == 0:\n",
    "            print(f\"epoch {k}: L = {L}\")\n",
    "\n",
    "    return W, b"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4386744b-6fb8-48c2-b5dd-77dfd2d3bee1",
   "metadata": {},
   "source": [
    "# Empiler deux couches\n",
    "\n",
    "`entraine_couche` corrigeait une seule couche, isolée. `entraine_reseau` en enchaîne deux : une couche cachée, puis une couche de sortie. La vraie nouveauté n'est pas dans les gradients de la couche 2 : `grad_W2` et `grad_b2` se calculent exactement comme avant, à partir de `delta2`. Elle se trouve dans le calcul de `delta1`, là où la chaîne s'allonge d'un maillon.\n",
    "\n",
    "## Pourquoi `delta1` ne se calcule pas comme `delta2`\n",
    "\n",
    "Pour la couche de sortie, l'erreur $\\delta_2$ se lit directement depuis $(a_2 - y)$ : le coût compare $a_2$ à $y$ sans intermédiaire. Mais $a_1$ n'apparaît dans aucune cible connue, sa seule influence sur $L$ passe *par* $a_2$. Il faut donc remonter la chaîne :\n",
    "\n",
    "$w_1, b_1 \\to z_1 \\to a_1 \\to z_2 \\to a_2 \\to L$\n",
    "\n",
    "Chaque neurone caché $i$ contribue à TOUS les neurones de sortie $j$ à la fois, via $W_2$. Sa part de responsabilité dans l'erreur finale est donc une somme, sur tous les $j$, du produit entre $\\delta_j$ (l'erreur du neurone $j$) et $W_{2,ji}$ (le poids qui relie le neurone caché $i$ au neurone de sortie $j$) :\n",
    "\n",
    "$\\frac{\\partial L}{\\partial a_{1,i}} = \\sum_j \\delta_{2,j} \\, W_{2,ji}$\n",
    "\n",
    "En notation vectorielle, cette somme sur tous les $j$ est exactement un produit matrice-vecteur, celui que fait `np.dot(W2.T, delta2)`. La transposée est nécessaire ici : $W_2$ va de $a_1$ vers $a_2$, donc $W_2^T$ fait le chemin inverse, de $\\delta_2$ vers $a_1$.\n",
    "\n",
    "Reste à multiplier par la dérivée locale de la sigmoïde, $a_1(1-a_1)$, pour obtenir $\\delta_1$ :\n",
    "\n",
    "$\\delta_1 = (W_2^T \\, \\delta_2) \\odot a_1 \\odot (1-a_1)$\n",
    "\n",
    "C'est cette étape, précisément, qui porte le nom de rétropropagation : l'erreur mesurée en sortie est renvoyée vers l'arrière, couche par couche, pondérée par les poids qu'elle traverse en chemin.\n",
    "\n",
    "## Et enfin\n",
    "\n",
    "`grad_W1 = np.outer(delta1, x)` et `grad_b1 = delta1` suivent la même logique que pour n'importe quelle couche isolée, seul l'input change : `x` plutôt que `a1`. Un réseau à trois couches ajouterait simplement un maillon de plus : $\\delta_1$ se propagerait à son tour vers un $\\delta_0$, via $W_1^T$. Le motif se répète, quel que soit le nombre de couches ; seule la longueur de la chaîne remontée change."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "bb146006-396c-422d-80dd-05b8e4e1de35",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-04T20:57:16.191279Z",
     "iopub.status.busy": "2026-08-04T20:57:16.191115Z",
     "iopub.status.idle": "2026-08-04T20:57:16.194111Z",
     "shell.execute_reply": "2026-08-04T20:57:16.193699Z"
    }
   },
   "outputs": [],
   "source": [
    "def entraine_reseau(x, y, W1, b1, W2, b2, eta, epochs):\n",
    "    n_out = len(y)\n",
    "\n",
    "    for k in range(epochs):\n",
    "        a1 = couche(x, W1, b1) \n",
    "        a2 = couche(a1, W2, b2)\n",
    "\n",
    "        delta2 = (2 / n_out) * (a2 - y) * a2 * (1 - a2) #delta de la sortie\n",
    "        delta1 = np.dot(W2.T, delta2) * a1 * (1 - a1) #delta de la couche cachée\n",
    "\n",
    "        grad_W2 = np.outer(delta2, a1) #forme (n_out, n_hidden)\n",
    "        grad_b2 = delta2\n",
    "\n",
    "        grad_W1 = np.outer(delta1, x) # forme (n_hidden, n_in)\n",
    "        grad_b1 = delta1\n",
    "\n",
    "        W2 = W2 - eta * grad_W2\n",
    "        b2 = b2 - eta * grad_b2\n",
    "        W1 = W1 - eta * grad_W1\n",
    "        b1 = b1 - eta * grad_b1\n",
    "\n",
    "        L = np.mean((a2 - y) ** 2)\n",
    "        \n",
    "        if k % 100 == 0:\n",
    "            print(f\"epoch {k}: L = {L}\")\n",
    "\n",
    "    return W1, b1, W2, b2, L / epochs"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7566800c-a305-4b12-887b-02042202fc8a",
   "metadata": {},
   "source": [
    "# Chargement et préparation des données\n",
    "\n",
    "Cette cellule charge le dataset Iris et prépare tout ce qu'il faut pour entraîner le réseau à deux couches construit précédemment.\n",
    "\n",
    "- Les données : `load_iris()` fournit 150 fleurs, chacune décrite par 4 mesures (longueur et largeur des pétales et des sépales) stockées dans `X`, et son espèce réelle (0, 1 ou 2) stockée dans `Y`.\n",
    "\n",
    "- Après petit souci : le réseau a 3 neurones de sortie, un par espèce possible. Il faut donc transformer chaque étiquette en vecteur : l'espèce `1` devient `[0, 1, 0]`, par exemple. C'est le rôle de la fonction `classe_vers_vecteur`.\n",
    "\n",
    "- L'initialisation des poids : `W1`, `b1`, `W2`, `b2` sont tirés aléatoirement, avec `np.random.seed(0)` pour que le tirage reste identique à chaque exécution. La couche cachée compte 5 neurones et reçoit les 4 mesures en entrée ; la couche de sortie compte 3 neurones, un par espèce.\n",
    "\n",
    "- L'entraînement, en deux temps : on entraîne d'abord sur une seule fleur, `X[0]`, pendant 1000 epochs pour vérifier que la mécanique de gradient fonctionne avant de généraliser. Puis on tente d'entraîner sur les 150 fleurs, une par une, dans une boucle."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "747a73ad-36d9-4741-825d-8047cd3e5823",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-04T20:57:16.195197Z",
     "iopub.status.busy": "2026-08-04T20:57:16.195035Z",
     "iopub.status.idle": "2026-08-04T20:57:16.197056Z",
     "shell.execute_reply": "2026-08-04T20:57:16.196714Z"
    }
   },
   "outputs": [],
   "source": [
    "def classe_vers_vecteur(Y, n_classes):\n",
    "    resultat = np.zeros((len(Y), n_classes))\n",
    "    for i, classe in enumerate(Y):\n",
    "        resultat[i, classe] = 1\n",
    "    return resultat"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "a1cb3d32-2c30-4f46-b181-b193f2b3d567",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-04T20:57:16.198262Z",
     "iopub.status.busy": "2026-08-04T20:57:16.198145Z",
     "iopub.status.idle": "2026-08-04T20:57:17.766726Z",
     "shell.execute_reply": "2026-08-04T20:57:17.766075Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch 0: L moyen = 0.18795428791240798, accuracy = 0.3333333333333333\n",
      "epoch 20: L moyen = 0.1997968367086164, accuracy = 0.3333333333333333\n",
      "epoch 40: L moyen = 0.044666104967845274, accuracy = 0.6666666666666666\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch 60: L moyen = 0.01892031592201796, accuracy = 0.76\n",
      "epoch 80: L moyen = 0.012569368365134037, accuracy = 0.84\n",
      "epoch 100: L moyen = 0.009951993299900885, accuracy = 0.8733333333333333\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch 120: L moyen = 0.00865765683854657, accuracy = 0.9133333333333333\n",
      "epoch 140: L moyen = 0.007924637724344194, accuracy = 0.9133333333333333\n",
      "epoch 160: L moyen = 0.0074569032202176895, accuracy = 0.9266666666666666\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch 180: L moyen = 0.007142779899563775, accuracy = 0.94\n",
      "Accuracy finale : 0.9466666666666667\n"
     ]
    }
   ],
   "source": [
    "from sklearn.datasets import load_iris\n",
    "\n",
    "def entraine_epoch(X, Y_onehot, W1, b1, W2, b2, eta):\n",
    "    total_L = 0\n",
    "    n = len(X)\n",
    "    for k in range(n):\n",
    "        x = X[k]\n",
    "        y = Y_onehot[k]\n",
    "\n",
    "        a1 = couche(x, W1, b1)\n",
    "        a2 = couche(a1, W2, b2)\n",
    "\n",
    "        n_out = len(y)\n",
    "        delta2 = (2 / n_out) * (a2 - y) * a2 * (1 - a2)\n",
    "        delta1 = np.dot(W2.T, delta2) * a1 * (1 - a1)\n",
    "\n",
    "        grad_W2 = np.outer(delta2, a1)\n",
    "        grad_b2 = delta2\n",
    "        grad_W1 = np.outer(delta1, x)\n",
    "        grad_b1 = delta1\n",
    "\n",
    "        W2 = W2 - eta * grad_W2\n",
    "        b2 = b2 - eta * grad_b2\n",
    "        W1 = W1 - eta * grad_W1\n",
    "        b1 = b1 - eta * grad_b1\n",
    "\n",
    "        total_L += np.mean((a2 - y) ** 2)\n",
    "\n",
    "    return W1, b1, W2, b2, total_L / n\n",
    "\n",
    "\n",
    "def accuracy(X, Y, W1, b1, W2, b2):\n",
    "    correct = 0\n",
    "    for k in range(len(X)):\n",
    "        a1 = couche(X[k], W1, b1)\n",
    "        a2 = couche(a1, W2, b2)\n",
    "        pred = np.argmax(a2) #ça c'était **** parce que c'est pas une liste donc max() ça fonctionne pas et je sais pas pourquoi j'ai mis un temps fouuuu à trouver cette fonction numpy\n",
    "        if pred == Y[k]:\n",
    "            correct += 1\n",
    "    return correct / len(X)\n",
    "\n",
    "data = load_iris()\n",
    "X = data.data #150 exemples, 4 features\n",
    "Y = data.target #0, 1 ou 2\n",
    "Y_onehot = classe_vers_vecteur(Y, 3)\n",
    "\n",
    "\n",
    "np.random.seed(0)\n",
    "W1 = np.random.randn(5, 4) * 0.5\n",
    "b1 = np.zeros(5)\n",
    "W2 = np.random.randn(3, 5) * 0.5\n",
    "b2 = np.zeros(3)\n",
    "\n",
    "n_epochs = 200\n",
    "for epoch in range(n_epochs):\n",
    "    W1, b1, W2, b2, L_moyen = entraine_epoch(X, Y_onehot, W1, b1, W2, b2, eta=0.1)\n",
    "    if epoch % 20 == 0:\n",
    "        acc = accuracy(X, Y, W1, b1, W2, b2)\n",
    "        print(f\"epoch {epoch}: L moyen = {L_moyen}, accuracy = {acc}\")\n",
    "\n",
    "print(\"Accuracy finale :\", accuracy(X, Y, W1, b1, W2, b2))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4f7008ca-f741-4d8a-886b-c3dde3a7b605",
   "metadata": {},
   "source": [
    "## Lecture des résultats affichés\n",
    "\n",
    "L'entraînement affiche une ligne toutes les 20 epochs, de la forme :\n",
    "\n",
    "```\n",
    "epoch 0: L moyen = 0.18795428791240798, accuracy = 0.3333333333333333\n",
    "epoch 20: L moyen = 0.1997968367086164, accuracy = 0.3333333333333333\n",
    "...\n",
    "```\n",
    "\n",
    "- `L moyen` est le coût moyen calculé sur les 150 fleurs, à la fin de l'epoch en cours. Cette valeur doit décroître au fil des epochs parce que c'est le signe que les poids `W1`, `b1`, `W2`, `b2` s'ajustent bien dans la bonne direction. Une valeur qui stagne ou remonte signalerait un problème, par exemple un `eta` trop élevé.\n",
    "\n",
    "- `accuracy` mesure la proportion de fleurs correctement classées, à ce même instant. Contrairement à `L moyen`, cette valeur ne baisse jamais de façon strictement monotone : elle peut légèrement fluctuer d'une epoch à l'autre, même quand le coût continue de décroître, parce que passer un score de `0.49` à `0.51` change une classification sans que le coût associé varie beaucoup.\n",
    "\n",
    "La dernière ligne, `Accuracy finale`, donne le taux de réussite du modèle après les 200 epochs sur les 150 fleurs utilisées pour l'entraînement. \n",
    "\n",
    "Une nuance importante à garder en tête : ce chiffre mesure à quel point le réseau a bien appris ces fleurs précises, pas sa capacité à généraliser sur des fleurs jamais vues."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e050bd55-b133-42f1-a45c-8ad6236d5e73",
   "metadata": {},
   "source": [
    "Ça signifie une chose : un prochain notebook arrivera pour pousser ce modèle sur des fleurs jamais vues et avec du computer vision pour donner directement les mesures au réseau et pouvoir faire un VRAI détecteur de fleurs !!!! Ce serait trop génial."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.14.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
