{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "Z7cDc2dVX2D1" }, "source": [ "# Séance 4 - Réseau récurrent\n", "\n", "Dans cette séance nous allons entraîner un modèle à copier le style de poésie de Beaudelaire, spécifiquement l'oeuvre *Les fleurs du mal*. Ce TP est largement inspiré du cours du [CNAM](https://cedric.cnam.fr/~thomen/cours/US330X/tpRNNs.html) que l'on a adapté ici.\n", "\n", "Pour cela, nous utiliserons le projet [Gutenberg](https://www.gutenberg.org) qui permet l'accès l'ensemble des oeuvres littéraires classique gratuitement. C'est sur ce dataset, entre autres, que les LLM s'entraînent.\n", "\n", "Commençons par importer les packages dont nous aurons besoin." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "Pe1mrRDtYaBM" }, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "import numpy as np\n", "import pandas as pd\n", "import seaborn as sns\n", "\n", "sns.set(style=\"whitegrid\")\n", "\n", "from tensorflow import keras" ] }, { "cell_type": "markdown", "metadata": { "id": "InTQRzhkY6My" }, "source": [ "Après avoir chargé dans l'environnement le fichier .txt de poésie, nous devons le travailler un peu pour l'exploiter. Quand on regarde le détail du fichier, on voit qu'il y a du texte qui n'est pas de la poésie. Nous décidons de n'exploiter que les poèmes." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "hkSTixun__Xw" }, "outputs": [], "source": [ "start = False\n", "book = open(\"Beaudelaire.txt\", encoding=\"utf8\") # noqa: SIM115\n", "lines = book.readlines()\n", "verses = []\n", "\n", "for line in lines:\n", " line_stripped = line.strip().lower()\n", " if \"AU LECTEUR\".lower() in line_stripped and not start:\n", " start = True\n", " if (\n", " \"End of the Project Gutenberg EBook of Les Fleurs du Mal, by Charles Baudelaire\".lower()\n", " in line_stripped\n", " ):\n", " break\n", " if not start or len(line_stripped) == 0:\n", " continue\n", " verses.append(line_stripped)\n", "\n", "book.close()\n", "text = \" \".join(verses)\n", "characters = sorted(set(text))\n", "n_characters = len(characters)" ] }, { "cell_type": "markdown", "metadata": { "id": "7626TUDbZHVf" }, "source": [ "On décide ici de le découper en séquence de 32 caractères et de se décaler d'un caractère à chaque fois. Nous allons donc prédire le caractère suivant à partir des 32 caractères précédents.\n", "Construisons deux listes qui, une fois transformée, deviendront $X$ et $y$.\n", "\n", "**Consigne** : Compléter la cellule suivante avec les informations précédentes." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "uO403MyQAzim" }, "outputs": [], "source": [ "sequence_length = 32\n", "stride = 1\n", "sequences = []\n", "y_character = []\n", "for index in range(0, len(text) - sequence_length, stride):\n", " sequences.append(text[index : index + sequence_length])\n", " y_character.append(text[index + sequence_length])" ] }, { "cell_type": "markdown", "metadata": { "id": "12vayeAWZaAo" }, "source": [ "Un réseau de neurone ne comprend pas le texte, donc nous devrons jongler entre nombre et caractères. Pour cela, nous créons deux dictionnaires pour traduire ces deux visions." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "rGkZx3JQB3gn" }, "outputs": [], "source": [ "character_to_index = {character: index for index, character in enumerate(characters)}\n", "index_to_character = dict(enumerate(characters))" ] }, { "cell_type": "markdown", "metadata": { "id": "4er_XSvHZljl" }, "source": [ "Nous sommes maintenant prêt pour renseigner $X$ et $y$. La matrice $X$ sera de taille $n \\times N \\times C$ avec:\n", "* $n$ : le nombre de séquence exemples\n", "* $N$ : la longueur de la séquence que l'on considère, ici 32\n", "* $C$ : le nombre de caractères différents, ici stocké dans la variable *n_characters*\n", "\n", "La matrice $y$ sera de taille $n\\times C$. Les deux matrices seront de types booléens avec la valeur *True* à l'index du caractères représenté.\n", "\n", "**Consigne** : Remplir la cellule suivante avec les informations précédentes. On utilisera le dictionnaire *character_to_index*." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "3b5vdYJ_DO8y" }, "outputs": [], "source": [ "X = np.zeros((len(sequences), sequence_length, n_characters), dtype=bool)\n", "y = np.zeros((len(sequences), n_characters), dtype=bool)\n", "\n", "for row, sequence in enumerate(sequences):\n", " for position, character in enumerate(sequence):\n", " X[row, position, character_to_index[character]] = 1\n", " y[row, character_to_index[y_character[row]]] = 1" ] }, { "cell_type": "markdown", "metadata": { "id": "GhrZsGulZs6U" }, "source": [ "Découpons à présent $X$ et $y$ en un jeu de test et un jeu d'entraînement. Aussi, nous allons sauvegarder ces matrices au cas où nous souhaiterions ne pas avoir à relancer ce preprocessing." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "b37hlbPmFUd6" }, "outputs": [], "source": [ "import _pickle as pickle\n", "\n", "train_size = 0.8\n", "train_index = round(len(sequences) * train_size)\n", "X_train = X[:train_index, :, :]\n", "y_train = y[:train_index, :]\n", "\n", "X_test = X[train_index:, :, :]\n", "y_test = y[train_index:, :]\n", "\n", "\n", "outfile = f\"Baudelaire_len_{sequence_length}.p\"\n", "\n", "with open(outfile, \"wb\") as pickle_f:\n", " pickle.dump([index_to_character, X_train, y_train, X_test, y_test], pickle_f)" ] }, { "cell_type": "markdown", "metadata": { "id": "K-zzNAhSZ7pA" }, "source": [ "## Modélisation\n", "\n", "Dans cet exemple, nous allons définir un réseau récurrent avec les neurones de bases : pas de LSTM ou GRU.\n", "\n", "Un neurone [`SimpleRNN`](https://keras.io/api/layers/recurrent_layers/simple_rnn/) possède les mêmes attributs qu'un neurones classique en plus de deux paramètres majeurs:\n", "* **return_sequences**: si l'on doit renvoyer la totalité de la séquence ou seulement la dernière valeur\n", "* **unroll**: permet d'accélérer l'entraînement du réseau de neurone au prix de plus de mémoire impliquée\n", "\n", "**Consigne** : Compléter la cellule suivante pour définir le réseau de neurones avec les informations précédentes." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "muGo3GElW-6l" }, "outputs": [ { "data": { "text/html": [ "
Model: \"sequential_1\"\n",
       "
\n" ], "text/plain": [ "\u001b[1mModel: \"sequential_1\"\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n",
       "┃ Layer (type)                     Output Shape                  Param # ┃\n",
       "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n",
       "│ simple_rnn_2 (SimpleRNN)        │ (None, 32, 128)        │        23,424 │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ layer_normalization_1           │ (None, 32, 128)        │           256 │\n",
       "│ (LayerNormalization)            │                        │               │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ simple_rnn_3 (SimpleRNN)        │ (None, 128)            │        32,896 │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ dense_1 (Dense)                 │ (None, 54)             │         6,966 │\n",
       "└─────────────────────────────────┴────────────────────────┴───────────────┘\n",
       "
\n" ], "text/plain": [ "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n", "┃\u001b[1m \u001b[0m\u001b[1mLayer (type) \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mOutput Shape \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1m Param #\u001b[0m\u001b[1m \u001b[0m┃\n", "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n", "│ simple_rnn_2 (\u001b[38;5;33mSimpleRNN\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m32\u001b[0m, \u001b[38;5;34m128\u001b[0m) │ \u001b[38;5;34m23,424\u001b[0m │\n", "├─────────────────────────────────┼────────────────────────┼───────────────┤\n", "│ layer_normalization_1 │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m32\u001b[0m, \u001b[38;5;34m128\u001b[0m) │ \u001b[38;5;34m256\u001b[0m │\n", "│ (\u001b[38;5;33mLayerNormalization\u001b[0m) │ │ │\n", "├─────────────────────────────────┼────────────────────────┼───────────────┤\n", "│ simple_rnn_3 (\u001b[38;5;33mSimpleRNN\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m128\u001b[0m) │ \u001b[38;5;34m32,896\u001b[0m │\n", "├─────────────────────────────────┼────────────────────────┼───────────────┤\n", "│ dense_1 (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m54\u001b[0m) │ \u001b[38;5;34m6,966\u001b[0m │\n", "└─────────────────────────────────┴────────────────────────┴───────────────┘\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
 Total params: 63,542 (248.21 KB)\n",
       "
\n" ], "text/plain": [ "\u001b[1m Total params: \u001b[0m\u001b[38;5;34m63,542\u001b[0m (248.21 KB)\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
 Trainable params: 63,542 (248.21 KB)\n",
       "
\n" ], "text/plain": [ "\u001b[1m Trainable params: \u001b[0m\u001b[38;5;34m63,542\u001b[0m (248.21 KB)\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
 Non-trainable params: 0 (0.00 B)\n",
       "
\n" ], "text/plain": [ "\u001b[1m Non-trainable params: \u001b[0m\u001b[38;5;34m0\u001b[0m (0.00 B)\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "model = keras.models.Sequential(\n", " [\n", " keras.layers.InputLayer(shape=(sequence_length, n_characters)),\n", " # Ajouter une couche SimpleRNN\n", " keras.layers.SimpleRNN(128, return_sequences=True),\n", " # Ajouter une couche de LayerNormalization\n", " keras.layers.LayerNormalization(),\n", " # Ajouter une couche SimpleRNN\n", " keras.layers.SimpleRNN(128, return_sequences=False),\n", " # Ajouter une couche Dense\n", " keras.layers.Dense(n_characters, activation=\"softmax\"),\n", " ],\n", ")\n", "\n", "model.summary()" ] }, { "cell_type": "markdown", "metadata": { "id": "bLfT59Q3adf9" }, "source": [ "Pour éviter l'overfitting, on se propose d'exploiter la mécanique d'[EarlyStopping](https://keras.io/api/callbacks/early_stopping/).\n", "\n", "**Consigne** : Compléter la cellule suivante pour compiler le réseau de neurones et l'entraîner avec la mécanique d'EarlyStopping à paramétrer." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "Jk1g8higXtED" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Epoch 1/50\n", "\u001b[1m1529/1529\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m28s\u001b[0m 17ms/step - accuracy: 0.5332 - loss: 1.4744 - val_accuracy: 0.4982 - val_loss: 1.6537\n", "Epoch 2/50\n", "\u001b[1m1529/1529\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m26s\u001b[0m 17ms/step - accuracy: 0.5345 - loss: 1.4680 - val_accuracy: 0.4965 - val_loss: 1.6555\n", "Epoch 3/50\n", "\u001b[1m1529/1529\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m26s\u001b[0m 17ms/step - accuracy: 0.5357 - loss: 1.4609 - val_accuracy: 0.4932 - val_loss: 1.6608\n", "Epoch 4/50\n", "\u001b[1m1529/1529\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m26s\u001b[0m 17ms/step - accuracy: 0.5365 - loss: 1.4585 - val_accuracy: 0.4951 - val_loss: 1.6449\n", "Epoch 5/50\n", "\u001b[1m1529/1529\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m26s\u001b[0m 17ms/step - accuracy: 0.5386 - loss: 1.4508 - val_accuracy: 0.4953 - val_loss: 1.6524\n", "Epoch 6/50\n", "\u001b[1m1529/1529\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m27s\u001b[0m 17ms/step - accuracy: 0.5399 - loss: 1.4484 - val_accuracy: 0.4934 - val_loss: 1.6657\n", "Epoch 7/50\n", "\u001b[1m1529/1529\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m31s\u001b[0m 20ms/step - accuracy: 0.5397 - loss: 1.4452 - val_accuracy: 0.4943 - val_loss: 1.6644\n", "Epoch 8/50\n", "\u001b[1m1529/1529\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m30s\u001b[0m 20ms/step - accuracy: 0.5412 - loss: 1.4389 - val_accuracy: 0.4921 - val_loss: 1.6641\n", "Epoch 9/50\n", "\u001b[1m1529/1529\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m26s\u001b[0m 17ms/step - accuracy: 0.5420 - loss: 1.4336 - val_accuracy: 0.4946 - val_loss: 1.6630\n" ] } ], "source": [ "n_epochs = 50\n", "batch_size = 64\n", "validation_split = 0.1\n", "\n", "callback = keras.callbacks.EarlyStopping(patience=5, restore_best_weights=True)\n", "model.compile(\n", " loss=\"categorical_crossentropy\",\n", " optimizer=keras.optimizers.Adam(),\n", " metrics=[\"accuracy\"],\n", ")\n", "history = model.fit(\n", " X_train,\n", " y_train,\n", " epochs=n_epochs,\n", " batch_size=batch_size,\n", " validation_split=validation_split,\n", " callbacks=[callback],\n", ")" ] }, { "cell_type": "markdown", "metadata": { "id": "wnYgg07XaxtI" }, "source": [ "L'entraînement étant terminé, visualisons sa courbe d'entraînement." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "qsPvn4t6XuuK" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "50 9\n" ] }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAABN4AAAJNCAYAAADu07jxAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjEsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvc2/+5QAAAAlwSFlzAAAPYQAAD2EBqD+naQAAlEFJREFUeJzs3Qd4FNX6x/E3vZCEEFoCoXeQ3kQBERX9W7FXLPeKXdSr2K8FG9cuKnb0WrD3K/YOShUVIXSCoQZI7/X/vGczm900Qsiwm8n38zzz7O7s2dk5m3bym1MCysvLywUAAAAAAABAowps3MMBAAAAAAAAUARvAAAAAAAAgA0I3gAAAAAAAAAbELwBAAAAAAAANiB4AwAAAAAAAGxA8AYAAAAAAADYgOANAAAAAAAAsAHBGwAAAAAAAGADgjcAAAAAAADABgRvAACgWfrggw+kT58+NW4DBw6UcePGyZVXXim///57tdda5RYuXFjr8e+77z5TZtGiRe59N998s9l300031fq6pKQkU0bL1mbLli21nntNm+c57C893kknnbRfn/krr7zSaOcDAADgz4J9fQIAAAC+NGrUKLN5ysrKkj///FO++eYb+eGHH+S///2vjBgxotpr77zzTvnkk08kLCxsn97zo48+MuHVIYcc0qBzjomJkauuuqpaYPftt9/WWJ+OHTtKY9H3bdOmTYNe269fP/P6IUOGNNr5AAAA+DOCNwAA0KxpSHX11VfX+NwTTzwhs2fPlocffljeeuutas8nJyfL008/Lf/617/2+X01tPv0008lPDy8QcFb1XPW3mRW8FZbfRrD/hxbgzfdAAAAmguGmgIAANTi8ssvl5CQEFm+fLnk5+d7PdehQweJjY2Vl156SVavXr1Px+3fv7/8/fff8uSTTzbyGQMAAMCfELwBAADUIjQ0VKKiosz94uLiar3OdB62kpIS+fe//y1lZWX1Pu706dOlVatWZq4zHSJ6IEycOFGmTJki77//vhniOnToUJk5c6a7bjqc9owzzpDhw4fLQQcdJIcffrjccccdkpaWVuccbxoe6r4NGzbIo48+KhMmTDCvP+644+TNN9/c6xxv1nnp6y+77DLz/npuU6dOrTHQXLlypVx66aWmZ5+Wve6662Tnzp0mzKxrXjwAAABfIHgDAACoxV9//SXp6emmd5sGbVWdfPLJJsTS+eBee+21eh9XQ7dbbrnFhHa33367lJaWyoGwbt06mTFjhhx55JFyzDHHuOdau/766+X++++X4OBgE76deeaZJnR8++23TQBW3zDxnXfekfHjx5tjaBh21113mX17s337djnrrLNkz5495rWjR4+Wn376yQRynsGf9jw899xz5ZdffjHvc9ppp8lvv/0mZ599tpSXl+/HJwMAAGAP5ngDAADwoAFOdna2CXnuvfdes09XN63N3XffLSeccII8/vjjctRRR5mQrj6015guzDB//nx59dVX5aKLLhK7aYioQZ8GWhZdtfXLL780ddC57CwaCmqwqOHjpk2bpFu3bnUeOyMjQ+bNmydxcXHm8fHHH28Csffee8+EaXVJSUkxgZr2HAwICDD79L6GdnpuehylPfC0d94bb7zhDg2vuOIKc/x96XEIAABwoNDjDQAANGtPPfWUGf5obX379pWRI0fKJZdcYoIqHb6oPatq07lzZ7NSZ15enunhtS+0fEREhMyaNUu2bNkiB8KkSZO8HsfHx5shp9dcc43Xfu39pkM5lfZE25tTTz3VHbqpYcOGmV6CW7durdd5ac86K3RThx12mLm1Xq9DTNeuXWuGsHquitqyZctqK7wCAAD4C3q8AQCAZk3nCtNN5eTkyBdffCE7duyQE088Ue655556rTqqvdU+++wz+fHHH82thkP10alTJ5k2bZr85z//MSHciy++KHbShSLat29fLXjTnm3aw03DLe3dpgs/6NxzOqRT1ac3WU094nR+PP1M9yYsLEwSEhKqvVYVFRWZ2xUrVpjbQYMGVXu9hnwAAAD+iOANAAA0axq6XX311e7H2vNLe7vpMNDo6GgzvHFvtHeYhnQ6N9p9990nhx56aL3f/4ILLpD//e9/8vPPP5v37NWrl9ilthDxrbfekqefflpSU1PNY+2pNnjwYOnRo4f88ccf9Zo/TeeEq0p7sO3Pa5X1eu19qNq0aVOtbLt27fb6HgAAAL7AUFMAAAAPkZGRZr42DXh0LjENpepj4MCBcv7555thmdqDrb6CgoLMXHJ6+8ADD5i50g6kzz//XO68806z4IOGbz/88IMsWbLE9L7r16+f+AurB1xNPejq06sOAADAFwjeAAAAqtDQzZqvTec/q+/8azpstGPHjvLBBx/I0qVL6/1+/fv3lwsvvNCs4Pnggw/KgaS97dQjjzxiVjv1HPK5ceNGc+sPK4YOGDDA3OoKslXVtA8AAMAfELwBAADUQFco1YUI8vPz671ogvaWs8quWrVqn95Ph7vqnG/7+rr9pfOrqd27d3vt/+ijj2Tx4sXmvs7/5mtDhw6V7t27m+G4OhedJSsrS5544gmfnhsAAEBtCN4AAABqcfvtt5shjjr/mtUzbG/Gjx8vJ5xwwj6/l65uevfdd8uBpotIKF0ZVOez0x53U6ZMkZtuuklat25tnjvQw19ronO+zZgxw4SA55xzjkyfPt08Pumkk2Tbtm2mTGAgTVsAAOBfaJ0AAADUQlcAve6668z9+++/XzIzM+v1ultvvVViY2P3+f10UYbJkyfLgTRhwgR57LHHpHPnzvLpp5/Khx9+KIWFhSaEs1ZZ1dVa/cHIkSPl1VdflSFDhsg333wjH3/8sQwfPtzd403DSwAAAH8SUO4Pk3YAAAAAddAwcNeuXWYOOl2IwtPChQvN6rA33HCDTJ061WfnCAAAUBU93gAAAOD3cnNz5YgjjpCLLrrIa7GH0tJSeeWVV8z90aNH+/AMAQAAqguuYR8AAADgV+Li4uToo4+WL7/8Uk499VQTsmno9ssvv8i6devkzDPPlEGDBvn6NAEAALww1BQAAABNQlFRkbzxxhtmxdWUlBSzT1c6Pf300+WMM84wCzAAAAD4E4I3AAAAAAAAwAbM8QYAAAAAAADYgOANAAAAAAAAsAHBGwAAAAAAAGADgjcAAAAAAADABgRvAAAAAAAAgA0I3gAAAAAAAAAbELwBAAAAAAAANiB4AwAAAAAAAGxA8AYAAAAAAADYgOANAAAAAAAAsAHBGwAAAAAAAGADgjcAAAAAAADABgRvAAAAAAAAgA0I3gAAAAAAAAAbELwBAAAAAAAANiB4AwAAAAAAAGxA8AYAAAAAAADYgOANAAAAAAAAsAHBGwAAAAAAAGADgjcATU55ebk0N82xzgAAAPuqObaZmmOdgaaE4A2AlylTppjNHxUVFcn9998vn376qXvfzTffLBMnTpSmoE+fPvLkk0/u8+tmz54tL730UqOcQ0M+r6b0GQMA0Fxcf/31pm0xZ84cX5+K3/j222/lpptucj9etGiR+Yz01t81tL21bNkyueSSSxrlHBryeTWlzxjwFYI3AE1Gamqq/Pe//5WSkhJpTp544gnJz89vlGNdccUV8tRTT9n+GgAAYJ/s7Gz55ptvpHfv3vL222/T46nCK6+8Itu3b5fm5N1335UNGzY0yrEGDBhgvp/01s7XAM0NwRsANCOdO3eW/v372/4aAABgn//973/m9rbbbpPk5GRZuHChr08JDhAVFSVDhgwxt3a+BmhuCN4ANMiCBQvknHPOkeHDh8vo0aPNcAfPK4xlZWXy2GOPmS7zBx10kLl95JFHpLi42KvReOKJJ8qgQYPk4IMPlhtuuEF27txZ4/tt2bJFjjjiCHP/lltuqdYV/4MPPpCjjz5aBg4caI75448/ej2nwZFeETz00ENl1KhRsn79evPcvHnz5JRTTpGhQ4ea5+644w7JzMyss9u/not2qdfjWvRK49SpU2XYsGFyyCGHmLrreVYdtpuTk2MayXoO+p7Tpk2T3bt31/o56/so7XFm3dfhqkcddZTZp8cZO3asOeeCggLzGU+aNMl85nouF110kSQlJdVaH70/a9Ys+c9//mPOW78W//znP00jfn9eoz788EM59thj3V+TX3/91XwdPD83AACw795//30ZM2aMaT916dJF3nrrrWplPvroIzn55JNl8ODBMmHCBNNG0Gk7LL///rv84x//MO0FPc6//vUvdztM/1Zru0PbPJ60DaDtAouW0faItqW0PWD1kF+yZIlpG4wcOdLdDtT2i7YPPdtE99xzj4wbN84EN6eeeqr88MMP5jltY+jxtGdf1ek3tO1Z00gAbXMtXrzYbFWHPm7cuNGcj34W2t57+OGHvUZQ1FYPbdtoW01fo+eo76FDO/c2zLLq1C3a/tX3HD9+vLvdpF+fmj7jutq0VenXQttbW7dudbdNrXbqyy+/LMccc4yps36/KO0lqe13bYPq10Wff+ONN2qtj9Xm1K/LCSecYF6j56bnvj+v2Ze2M+AEBG8A9pn+4dSGWkJCgjz66KPmj+Ty5cvlzDPPlD179pgyL7zwgrz55pty5ZVXmrlHzj77bDNP2TPPPGOe10bLjTfeaEIiLavH0Ku1GuDVpF27du5G0OWXX+419FEDv+eff16uueYa88c+ICDANJKsc1GlpaXmPO677z7zXj169DCNN21kakNKgyQ91y+//NL8wdcQq77S0tLkvPPOM+fxwAMPyO233y5ffPGF+2q0p1dffdU0vnT4qNb1u+++kxkzZtR6bO26r047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AAAAADYgeAMAAAAAAABsQPAGAAAAAAAA2IDgDQAAAAAAALABwRsAAAAAAABgA4I3AAAAAAAAwAYEbwAAAAAAAIANCN4AAAAAAAAAGxC8AQAAAAAAADYgeAMAAAAAAABsQPAGAAAAAAAA2IDgDQAAAAAAALABwRsAAAAAAABgA4I3AAAAAAAAwAYEbwAAAAAAAIANCN4AAAAAAAAAGxC8AQAAAAAAADYgeAMAAIDPlJWVyaxZs2TcuHEyZMgQmTp1qqSkpNRafs+ePXL99dfLwQcfLKNHj5brrrtOdu7ceUDPGQAAoL4I3gAAAOAzs2fPlrlz58o999wjb731lgniLr74YikqKqqx/LXXXivbtm2Tl19+2Wx6/8orrzzg5w0AAFAfBG8AAADwCQ3X5syZI9OmTZMJEyZI37595bHHHpMdO3bIV199Va18VlaWLF682PSK69evn/Tv318uueQSWbFihWRkZPikDgAAAHUheAMAAIBPrF69WnJzc2XMmDHufTExMSZQW7JkSbXy4eHh0qJFC/noo48kJyfHbB9//LF069bNvA4AAMDfBPv6BAAAANA8ac82lZCQ4LW/Xbt27uc8hYaGysyZM+WOO+6QESNGSEBAgCn7+uuvS2Bgw68nl5eXS15entghPz/f69bpqK+zUV9no77ORn0bl7YdtB1SHwRvAAAA8AmrMayBmqewsDDJzMyssZGblJQkQ4cONfPAlZaWmqGpV1xxhbz55psSFRXVoPMoLi42x7VTcnKyNCfU19mor7NRX2ejvo2navulNgRvAAAA8AkdOmrN9WbdV4WFhRIREVGt/Oeff256t33//ffukO3ZZ5+Vww8/XN577z258MILG3QeISEh0rNnT7ErXNRGf9euXWusk9NQX2ejvs5GfZ2N+jau9evX17sswRsAAAB8whpimpqaKp07d3bv18d9+vSpVn7p0qVmPjfPnm0tW7Y0+zZv3tzg89ChIpGRkWInbfTb/R7+hPo6G/V1NurrbNS3cdR3mKlicQUAAAD4hK5iqiHaokWLvFYuXbVqlYwcObJa+fj4eBOwaY84i87NtmXLFnNFGwAAwN8QvAEAAMAndG6U8847Tx5++GH59ttvzSqn1113nQnYJk2aZOZw27VrlxQUFJjykydPNrfXXnutKavbv/71LzMn3CmnnOLj2gAAAFRH8AYAAACf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ilC1YRwWFiaZmZk1lq+pEa3lCwsLG3QOtPMAAICdmOMNAAAAPhEeHm5uqy6koCFaREREjeVrWnRBy0dGRtp4pgAAAA1D8AYAAACfsIaNpqameu3Xx+3bt69WPj4+vlpZDeIyMjLM8FQAAAB/Q/AGAAAAn9BVTKOiomTRokXufVlZWbJq1SoZOXJktfK6T+d+27x5s3ufrnKqhg8ffoDOGgAAoP6Y4w0AAAA+ofO1nXfeefLwww9LXFycdOzYUR566CHTs23SpElSWloqaWlpEh0dbYaZDh48WIYNGybXXXed3HXXXZKXlyd33HGHTJ48ucYecgAAAL4WUG6tsQoAAAAcYBquPfroo/LBBx9IQUGB6dWmYVpiYqJs2bJFjjjiCHnggQfklFNOMeX37Nkjd999t/z8889mUYVjjjlGbrnlFnMfAADA3xC8AQAAAAAAADZgjjcAAAAAAADABgRvAAAAAAAAgA0I3gAAAAAAAAAbELwBAAAAAAAANiB4AwAAAAAAAGxA8AYAAAAAAADYgODNTzz33HMyZcoUcbKMjAy54447ZPz48TJs2DA5++yzZenSpeJUe/bskenTp8vBBx8sQ4cOlUsuuUQ2bNggzcGmTZtMnT/44ANxqp07d0qfPn2qbU6u80cffSTHHnusDBw4UI477jj5/PPPxYkWLVpU49dWtyOOOEKcqKSkRJ544gk5/PDDzc/uueeeK7///rs4VU5Ojtx5550yduxYGTVqlNxwww3mdzZgF9p5zkM7j3ae09DOo53nJDl+1tYjePMDb7zxhjz++OPidP/6179k+fLl8uijj8r7778v/fr1k3/+85+yceNGcaIrr7xSNm/eLM8//7y89957Eh4eLhdeeKHk5+eLkxUXF5tfbHl5eeJkq1evlrCwMPn5559l/vz57k0bLE708ccfy2233Wb+UH/22Wdy/PHHu3+mnUYbJJ5fU92eeuopCQgIkCuuuEKc6JlnnpF3331X7rnnHtPw7tatm1x88cWSmpoqTnTNNdfIjz/+KPfdd5/5G6y/l88//3wpKiry9anBgWjn0c5zEtp5tPOaOtp5zm/n+WNbj+DNx1dSLrvsMnn44Yela9eu4mTaMFmwYIHcddddMmLECPPD/u9//1vatWsnn376qThNZmamdOzYUe69914ZNGiQ9OjRw/wi119u69atEyd78skn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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "historic = pd.DataFrame(history.history)\n", "figure, (axis_1, axis_2) = plt.subplots(1, 2, figsize=(15, 6))\n", "epochs = range(1, n_epochs + 1)\n", "\n", "print(len(epochs), len(historic[\"loss\"]))\n", "\n", "for index, (metric_name, axis) in enumerate(\n", " zip([\"loss\", \"accuracy\"], [axis_1, axis_2], strict=False),\n", "):\n", " color = sns.color_palette()[index]\n", " axis.plot(\n", " epochs[: len(historic[metric_name])],\n", " historic[metric_name],\n", " lw=2,\n", " color=color,\n", " )\n", " axis.plot(\n", " epochs[: len(historic[\"val_\" + metric_name])],\n", " historic[\"val_\" + metric_name],\n", " ls=\"--\",\n", " color=color,\n", " )\n", "\n", " if metric_name == \"accuracy\":\n", " axis.set_ylim(0, 1)\n", " axis.set_ylabel(metric_name.capitalize())\n", " axis.set_xlabel(\"Epochs\")\n", " axis.set_title(f\"{metric_name.capitalize()} through training\")\n", "\n", "\n", "plt.suptitle(\"RNN Training\")\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": { "id": "56NMPwxOa8I9" }, "source": [ "Sauvegardons le modèle pour pouvoir l'utiliser plus tard, ou sur un autre notebook par exemple." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "sS2kjywjGx8_" }, "outputs": [], "source": [ "def save_model(model, name) -> None:\n", " \"\"\"Save a Keras model to JSON and H5 files.\"\"\"\n", " model_json = model.to_json()\n", " with open(name + \".json\", \"w\") as json_file:\n", " json_file.write(model_json)\n", " model.save_weights(name + \".h5\")\n", "\n", "\n", "save_model(model, \"SimpleRNN.weights\")" ] }, { "cell_type": "markdown", "metadata": { "id": "UqMSdzSbX06B" }, "source": [ "Importons le modèle que l'on vient de sauvegarder sous un autre alias." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "FRVCXsVOHQx-" }, "outputs": [], "source": [ "from keras.models import model_from_json\n", "\n", "\n", "def load_model(name):\n", " \"\"\"Load a Keras model from JSON and H5 files.\"\"\"\n", " with open(name + \".json\") as json_file:\n", " model = model_from_json(json_file.read())\n", " model.load_weights(name + \".h5\")\n", " return model\n", "\n", "\n", "model_SimpleRNN = load_model(\"SimpleRNN.weights\")" ] }, { "cell_type": "markdown", "metadata": { "id": "1UKNXx4lbD4g" }, "source": [ "**Consignes** : Compléter la cellule suivante pour vérifier que les performances sont bien celles que nous connaissons." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "AhFyJkrbX-bn" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[1m850/850\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m3s\u001b[0m 3ms/step - accuracy: 0.4930 - loss: 1.6966\n", "Test accuracy: 49.30%\n" ] } ], "source": [ "model_SimpleRNN.compile(\n", " loss=\"categorical_crossentropy\",\n", " optimizer=keras.optimizers.Adam(),\n", " metrics=[\"accuracy\"],\n", ")\n", "score = model_SimpleRNN.evaluate(X_test, y_test)\n", "print(\"Test accuracy: %.02f%%\" % (score[1] * 100))" ] }, { "cell_type": "markdown", "metadata": { "id": "DzMrZFmKbVfL" }, "source": [ "## Génération de texte\n", "\n", "On souhaite exploiter le modèle pour générer de la poésie dans le style de Beaudelaire.\n", "On se propose de commencer par un bout d'un poème au hasard." ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Start sequence: mère épouvantée et pleine de bla\n" ] } ], "source": [ "seed = 2025\n", "sequence = \"\"\n", "for index in range(sequence_length):\n", " character = index_to_character[np.argmax(X_train[seed, index, :])]\n", " sequence += character\n", "\n", "print(\"Start sequence: \" + sequence)" ] }, { "cell_type": "markdown", "metadata": { "id": "NeGrigxYa9lj" }, "source": [ "Pour choisir le prochain caractère, nous pouvons simplement sélectionner le caractère le plus probable prédit par le modèle. Cette approche peut amener le modèle à dégénérer.\n", "\n", "Nous allons essayer de sélectionner aléatoirement l'index du prochain caractère en s'appuyant sur le vecteur de probabilité produit par le réseau de neurone définit plus tôt.\n", "\n", "**Consigne** : A l'aide de la fonction [np.random.multinomial](https://numpy.org/doc/stable/reference/random/generated/numpy.random.multinomial.html), sélectionner un index aléatoirement selon un vecteur de probabilité à construire aléatoirement." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "OkE9Dd9Ua9W3" }, "outputs": [], "source": [ "random_index = np.random.multinomial(\n", " 1,\n", " y_test[np.random.randint(0, len(X_test) - 1)].ravel(),\n", ").argmax()" ] }, { "cell_type": "markdown", "metadata": { "id": "eu6NDVX6bpLn" }, "source": [ "Nous allons en pratique exploiter le *temperature sampling* pour sélectionner le prochain caractère.\n", "\n", "### Température\n", "\n", "On considère un vecteur $u = (u_1, u_2, \\ldots, u_d)$ et un paramètre $\\tau > 0$ que l'on appelle la température. On peut construire le vecteur $v = (v_1, v_2, \\ldots, v_d)$ à partir de $u$ et de $\\tau$ comme:\n", "\n", "$$\\forall i \\leqslant d, \\quad v_i = \\frac{\\displaystyle \\exp\\left(\\frac{u_i}{\\tau}\\right)}{\\displaystyle \\sum_{j=1}^d \\exp\\left(\\frac{u_j}{\\tau}\\right)}$$\n", "\n", "Cela ressemble à la fonction softmax mais paramétrer par la température $\\tau$.\n", "\n", "**Consigne** : Ecrire une fonction nommé `sampling` qui prend en paramètre un vecteur de probabilité et la température. Cette fonction doit renvoyer un index sélectionné selon le vecteur de probabilité définit par la température. On s'appuiera sur le travail de la cellule précédente." ] }, { "cell_type": "code", "execution_count": 29, "metadata": { "id": "Jeglw8biH6E8" }, "outputs": [], "source": [ "def sampling(probabilities: np.ndarray, temperature: float = 1.0) -> int:\n", " \"\"\"Sample an index from a probability array reweighted by temperature.\n", "\n", " Args:\n", " probabilities (np.ndarray): Array of probabilities.\n", " temperature (float, optional): Temperature parameter. Defaults to 1.0.\n", "\n", " Returns:\n", " int: Sampled index.\n", "\n", " \"\"\"\n", " probabilities = np.asarray(probabilities).astype(\"float64\")\n", " log_probabilities = np.log(probabilities + 1e-10) / temperature\n", " exp_probabilities = np.exp(log_probabilities)\n", " probabilities = exp_probabilities / np.sum(exp_probabilities)\n", " return np.random.multinomial(1, probabilities, 1).argmax()" ] }, { "cell_type": "markdown", "metadata": { "id": "9i1JrHL-cCAq" }, "source": [ "Maintenant que nous sommes capables de sélectionner le prochain caractère avec plus de justesse, il ne nous restes plus qu'à générer la suite de la phrase !" ] }, { "cell_type": "code", "execution_count": 30, "metadata": { "id": "faT74GT7PkJt" }, "outputs": [], "source": [ "def generate_sequence(start: str, length: int, model, temperature: float = 1) -> str:\n", " \"\"\"Generate a sequence of characters given a starting string.\n", "\n", " Args:\n", " start (str): The starting string to seed the generation.\n", " length (int): The length of the sequence to generate.\n", " model: The trained Keras model for character prediction.\n", " temperature (float): The temperature parameter for sampling.\n", "\n", " Returns:\n", " str: The generated sequence of characters.\n", "\n", " \"\"\"\n", " sequence = np.zeros((1, sequence_length, n_characters), dtype=bool)\n", " for position, character in enumerate(start):\n", " sequence[0][position][character_to_index[character]] = True\n", "\n", " generated_sequence = start\n", "\n", " for _ in range(length):\n", " probabilities = model.predict(sequence, verbose=0)[0]\n", " next_index = sampling(probabilities, temperature=temperature)\n", " character = index_to_character[next_index]\n", " generated_sequence += character\n", "\n", " for index in range(sequence_length - 1):\n", " sequence[0, index, :] = sequence[0, index + 1, :]\n", "\n", " sequence[0, sequence_length - 1, :] = 0\n", " sequence[0, sequence_length - 1, next_index] = 1\n", "\n", " return generated_sequence" ] }, { "cell_type": "markdown", "metadata": { "id": "v4Rm2tKib-md" }, "source": [ "Avec l'ensemble du travail, on a :" ] }, { "cell_type": "code", "execution_count": 31, "metadata": { "id": "qvHtwn9ZcC-t" }, "outputs": [ { "data": { "text/plain": [ "'mère épouvantée et pleine de blasphères, où les profonds des flamois ses monstres '" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "generate_sequence(start=sequence, length=50, model=model_SimpleRNN, temperature=0.5)" ] }, { "cell_type": "markdown", "metadata": { "id": "BYX-wJDHcazG" }, "source": [ "**Consignes** : Définir et comparer d'autres architectures de réseau de neurones pour répondre à ce problème. On conseille d'observer les performances avec les courbes d'apprentissage mais aussi avec plusieurs génération de texte.\n", "\n", "## Pour continuer\n", "\n", "Choisir une ou plusieurs pistes de recherche parmi les suivantes. Il est possible de choisir une autre direction, mais elle doit être validé auparavant.\n", "\n", "1. Nous avons défini une seule architecture. On peut en essayer d'autres et les comparer à la fois avec les courbes d'apprentissages mais également avec la génération de texte.\n", "2. Il existe une couche [`Embedding`](https://keras.io/api/layers/core_layers/embedding/). On se propose de l'exploiter et de mesurer ses performances.\n" ] } ], "metadata": { "colab": { "provenance": [] }, "kernelspec": { "display_name": "studies", "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.13.9" } }, "nbformat": 4, "nbformat_minor": 1 }