AI-For-Beginners/translations/fr/lessons/5-NLP/17-GenerativeNetworks/GenerativeTF.ipynb

495 lines
29 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Réseaux génératifs\n",
"\n",
"Les réseaux neuronaux récurrents (RNNs) et leurs variantes à cellules à portes, comme les cellules Long Short Term Memory (LSTMs) et les Gated Recurrent Units (GRUs), ont introduit un mécanisme pour la modélisation du langage, c'est-à-dire qu'ils peuvent apprendre l'ordre des mots et fournir des prédictions pour le mot suivant dans une séquence. Cela nous permet d'utiliser les RNNs pour des **tâches génératives**, telles que la génération de texte ordinaire, la traduction automatique et même la génération de légendes pour des images.\n",
"\n",
"Dans l'architecture RNN que nous avons abordée dans l'unité précédente, chaque unité RNN produisait le prochain état caché comme sortie. Cependant, nous pouvons également ajouter une autre sortie à chaque unité récurrente, ce qui nous permettrait de produire une **séquence** (de même longueur que la séquence d'origine). De plus, nous pouvons utiliser des unités RNN qui n'acceptent pas d'entrée à chaque étape, mais qui prennent simplement un vecteur d'état initial, puis produisent une séquence de sorties.\n",
"\n",
"Dans ce notebook, nous allons nous concentrer sur des modèles génératifs simples qui nous aident à générer du texte. Pour simplifier, construisons un **réseau au niveau des caractères**, qui génère du texte lettre par lettre. Pendant l'entraînement, nous devons prendre un corpus de texte et le diviser en séquences de lettres.\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import tensorflow as tf\n",
"from tensorflow import keras\n",
"import tensorflow_datasets as tfds\n",
"import numpy as np\n",
"\n",
"ds_train, ds_test = tfds.load('ag_news_subset').values()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Construire un vocabulaire de caractères\n",
"\n",
"Pour créer un réseau génératif au niveau des caractères, nous devons diviser le texte en caractères individuels plutôt qu'en mots. La couche `TextVectorization` que nous avons utilisée auparavant ne peut pas le faire, donc nous avons deux options :\n",
"\n",
"* Charger manuellement le texte et effectuer la tokenisation \"à la main\", comme dans [cet exemple officiel de Keras](https://keras.io/examples/generative/lstm_character_level_text_generation/)\n",
"* Utiliser la classe `Tokenizer` pour la tokenisation au niveau des caractères.\n",
"\n",
"Nous allons opter pour la deuxième option. `Tokenizer` peut également être utilisé pour la tokenisation en mots, ce qui permet de passer facilement de la tokenisation au niveau des caractères à celle au niveau des mots.\n",
"\n",
"Pour effectuer une tokenisation au niveau des caractères, nous devons passer le paramètre `char_level=True` :\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"def extract_text(x):\n",
" return x['title']+' '+x['description']\n",
"\n",
"def tupelize(x):\n",
" return (extract_text(x),x['label'])\n",
"\n",
"tokenizer = keras.preprocessing.text.Tokenizer(char_level=True,lower=False)\n",
"tokenizer.fit_on_texts([x['title'].numpy().decode('utf-8') for x in ds_train])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Nous voulons également utiliser un jeton spécial pour indiquer **fin de séquence**, que nous appellerons `<eos>`. Ajoutons-le manuellement au vocabulaire :\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"eos_token = len(tokenizer.word_index)+1\n",
"tokenizer.word_index['<eos>'] = eos_token\n",
"\n",
"vocab_size = eos_token + 1"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": []
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[[48, 2, 10, 10, 5, 44, 1, 25, 5, 8, 10, 13, 78]]"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"tokenizer.texts_to_sequences(['Hello, world!'])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Entraîner un RNN génératif à créer des titres\n",
"\n",
"La manière dont nous allons entraîner un RNN à générer des titres d'actualités est la suivante. À chaque étape, nous prendrons un titre, qui sera introduit dans un RNN, et pour chaque caractère d'entrée, nous demanderons au réseau de générer le caractère de sortie suivant :\n",
"\n",
"![Image montrant un exemple de génération RNN du mot 'HELLO'.](../../../../../lessons/5-NLP/17-GenerativeNetworks/images/rnn-generate.png)\n",
"\n",
"Pour le dernier caractère de notre séquence, nous demanderons au réseau de générer le token `<eos>`.\n",
"\n",
"La principale différence avec le RNN génératif que nous utilisons ici est que nous prendrons une sortie à chaque étape du RNN, et pas seulement à partir de la cellule finale. Cela peut être réalisé en spécifiant le paramètre `return_sequences` à la cellule RNN.\n",
"\n",
"Ainsi, pendant l'entraînement, une entrée pour le réseau sera une séquence de caractères encodés d'une certaine longueur, et une sortie sera une séquence de la même longueur, mais décalée d'un élément et terminée par `<eos>`. Un minibatch sera constitué de plusieurs de ces séquences, et nous devrons utiliser **padding** pour aligner toutes les séquences.\n",
"\n",
"Créons des fonctions qui transformeront le jeu de données pour nous. Comme nous voulons ajouter du padding aux séquences au niveau du minibatch, nous commencerons par regrouper le jeu de données en appelant `.batch()`, puis nous utiliserons `map` pour effectuer la transformation. Ainsi, la fonction de transformation prendra un minibatch entier comme paramètre :\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"def title_batch(x):\n",
" x = [t.numpy().decode('utf-8') for t in x]\n",
" z = tokenizer.texts_to_sequences(x)\n",
" z = tf.keras.preprocessing.sequence.pad_sequences(z)\n",
" return tf.one_hot(z,vocab_size), tf.one_hot(tf.concat([z[:,1:],tf.constant(eos_token,shape=(len(z),1))],axis=1),vocab_size)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Quelques points importants que nous faisons ici :\n",
"* Nous commençons par extraire le texte réel du tenseur de chaînes\n",
"* `text_to_sequences` convertit la liste de chaînes en une liste de tenseurs d'entiers\n",
"* `pad_sequences` remplit ces tenseurs jusqu'à leur longueur maximale\n",
"* Enfin, nous encodons tous les caractères en one-hot, tout en effectuant le décalage et en ajoutant `<eos>`. Nous verrons bientôt pourquoi nous avons besoin de caractères encodés en one-hot.\n",
"\n",
"Cependant, cette fonction est **Pythonique**, c'est-à-dire qu'elle ne peut pas être automatiquement traduite en graphe computationnel Tensorflow. Nous obtiendrons des erreurs si nous essayons d'utiliser cette fonction directement dans la fonction `Dataset.map`. Nous devons encapsuler cet appel Pythonique en utilisant le wrapper `py_function` :\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"def title_batch_fn(x):\n",
" x = x['title']\n",
" a,b = tf.py_function(title_batch,inp=[x],Tout=(tf.float32,tf.float32))\n",
" return a,b"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **Note** : Différencier entre les fonctions de transformation Pythonic et Tensorflow peut sembler un peu trop complexe, et vous pourriez vous demander pourquoi nous ne transformons pas le dataset en utilisant des fonctions Python standard avant de le passer à `fit`. Bien que cela soit tout à fait possible, utiliser `Dataset.map` présente un énorme avantage, car le pipeline de transformation des données est exécuté via le graphe computationnel de Tensorflow, ce qui permet de tirer parti des calculs sur GPU et de minimiser le besoin de transférer les données entre le CPU et le GPU.\n",
"\n",
"Nous pouvons maintenant construire notre réseau générateur et commencer l'entraînement. Il peut être basé sur n'importe quelle cellule récurrente que nous avons abordée dans l'unité précédente (simple, LSTM ou GRU). Dans notre exemple, nous utiliserons LSTM.\n",
"\n",
"Étant donné que le réseau prend des caractères en entrée et que la taille du vocabulaire est assez petite, nous n'avons pas besoin de couche d'embedding ; une entrée encodée en one-hot peut directement être transmise à la cellule LSTM. La couche de sortie sera un classificateur `Dense` qui convertira la sortie du LSTM en numéros de tokens encodés en one-hot.\n",
"\n",
"De plus, comme nous travaillons avec des séquences de longueur variable, nous pouvons utiliser une couche `Masking` pour créer un masque qui ignorera la partie remplie de la chaîne. Ce n'est pas strictement nécessaire, car nous ne sommes pas particulièrement intéressés par tout ce qui dépasse le token `<eos>`, mais nous l'utiliserons dans le but d'acquérir de l'expérience avec ce type de couche. `input_shape` serait `(None, vocab_size)`, où `None` indique une séquence de longueur variable, et la forme de sortie est également `(None, vocab_size)`, comme vous pouvez le voir dans le `summary` :\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model: \"sequential\"\n",
"_________________________________________________________________\n",
"Layer (type) Output Shape Param # \n",
"=================================================================\n",
"masking (Masking) (None, None, 84) 0 \n",
"_________________________________________________________________\n",
"lstm (LSTM) (None, None, 128) 109056 \n",
"_________________________________________________________________\n",
"dense (Dense) (None, None, 84) 10836 \n",
"=================================================================\n",
"Total params: 119,892\n",
"Trainable params: 119,892\n",
"Non-trainable params: 0\n",
"_________________________________________________________________\n",
"15000/15000 [==============================] - 229s 15ms/step - loss: 1.5385\n"
]
},
{
"data": {
"text/plain": [
"<tensorflow.python.keras.callbacks.History at 0x7fa40c1245e0>"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model = keras.models.Sequential([\n",
" keras.layers.Masking(input_shape=(None,vocab_size)),\n",
" keras.layers.LSTM(128,return_sequences=True),\n",
" keras.layers.Dense(vocab_size,activation='softmax')\n",
"])\n",
"\n",
"model.summary()\n",
"model.compile(loss='categorical_crossentropy')\n",
"\n",
"model.fit(ds_train.batch(8).map(title_batch_fn))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Génération de sortie\n",
"\n",
"Maintenant que nous avons entraîné le modèle, nous souhaitons l'utiliser pour générer une sortie. Tout d'abord, nous avons besoin d'une méthode pour décoder le texte représenté par une séquence de numéros de tokens. Pour cela, nous pourrions utiliser la fonction `tokenizer.sequences_to_texts` ; cependant, elle ne fonctionne pas bien avec une tokenisation au niveau des caractères. Par conséquent, nous allons prendre un dictionnaire de tokens provenant du tokenizer (appelé `word_index`), construire une correspondance inversée, et écrire notre propre fonction de décodage :\n"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"reverse_map = {val:key for key, val in tokenizer.word_index.items()}\n",
"\n",
"def decode(x):\n",
" return ''.join([reverse_map[t] for t in x])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Commençons par une chaîne `start`, que nous encodons en une séquence `inp`, puis à chaque étape, nous appelons notre réseau pour déduire le caractère suivant.\n",
"\n",
"La sortie du réseau `out` est un vecteur de `vocab_size` éléments représentant les probabilités de chaque jeton, et nous pouvons trouver le numéro du jeton le plus probable en utilisant `argmax`. Nous ajoutons ensuite ce caractère à la liste des jetons générés et poursuivons la génération. Ce processus de génération d'un caractère est répété `size` fois pour produire le nombre requis de caractères, et nous terminons plus tôt si le `eos_token` est rencontré.\n"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'Today #39;s lead to strike for the strike for the strike for the strike (AFP)'"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def generate(model,size=100,start='Today '):\n",
" inp = tokenizer.texts_to_sequences([start])[0]\n",
" chars = inp\n",
" for i in range(size):\n",
" out = model(tf.expand_dims(tf.one_hot(inp,vocab_size),0))[0][-1]\n",
" nc = tf.argmax(out)\n",
" if nc==eos_token:\n",
" break\n",
" chars.append(nc.numpy())\n",
" inp = inp+[nc]\n",
" return decode(chars)\n",
" \n",
"generate(model)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Échantillonnage des résultats pendant l'entraînement\n",
"\n",
"Étant donné que nous ne disposons d'aucune métrique utile comme *l'exactitude*, la seule manière de vérifier que notre modèle s'améliore est de **prélever des exemples** de chaînes générées pendant l'entraînement. Pour ce faire, nous utiliserons des **callbacks**, c'est-à-dire des fonctions que nous pouvons passer à la fonction `fit`, et qui seront appelées périodiquement pendant l'entraînement.\n"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch 1/3\n",
"15000/15000 [==============================] - 226s 15ms/step - loss: 1.2703\n",
"Today #39;s a lead in the company for the strike\n",
"Epoch 2/3\n",
"15000/15000 [==============================] - 227s 15ms/step - loss: 1.2057\n",
"Today #39;s the Market Service on Security Start (AP)\n",
"Epoch 3/3\n",
"15000/15000 [==============================] - 226s 15ms/step - loss: 1.1752\n",
"Today #39;s a line on the strike to start for the start\n"
]
},
{
"data": {
"text/plain": [
"<tensorflow.python.keras.callbacks.History at 0x7fa40c74e3d0>"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"sampling_callback = keras.callbacks.LambdaCallback(\n",
" on_epoch_end = lambda batch, logs: print(generate(model))\n",
")\n",
"\n",
"model.fit(ds_train.batch(8).map(title_batch_fn),callbacks=[sampling_callback],epochs=3)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Cet exemple génère déjà un texte assez bon, mais il peut être amélioré de plusieurs façons :\n",
"\n",
"* **Plus de texte**. Nous avons uniquement utilisé des titres pour notre tâche, mais vous pourriez vouloir expérimenter avec du texte complet. Gardez à l'esprit que les RNN ne sont pas très performants pour gérer de longues séquences, il est donc judicieux soit de les diviser en phrases plus courtes, soit de toujours entraîner sur une longueur de séquence fixe d'une valeur prédéfinie `num_chars` (par exemple, 256). Vous pourriez essayer de modifier l'exemple ci-dessus pour adopter une telle architecture, en vous inspirant du [tutoriel officiel de Keras](https://keras.io/examples/generative/lstm_character_level_text_generation/).\n",
"\n",
"* **LSTM multicouche**. Il est pertinent d'essayer 2 ou 3 couches de cellules LSTM. Comme mentionné dans l'unité précédente, chaque couche de LSTM extrait certains motifs du texte, et dans le cas d'un générateur au niveau des caractères, on peut s'attendre à ce que le niveau inférieur du LSTM soit responsable de l'extraction des syllabes, et les niveaux supérieurs - des mots et des combinaisons de mots. Cela peut être simplement implémenté en passant un paramètre de nombre de couches au constructeur LSTM.\n",
"\n",
"* Vous pourriez également vouloir expérimenter avec **les unités GRU** pour voir lesquelles donnent de meilleurs résultats, ainsi qu'avec **différentes tailles de couches cachées**. Une couche cachée trop grande peut entraîner un surapprentissage (par exemple, le réseau apprendra le texte exact), tandis qu'une taille trop petite pourrait ne pas produire de bons résultats.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Génération de texte souple et température\n",
"\n",
"Dans la définition précédente de `generate`, nous choisissions toujours le caractère avec la probabilité la plus élevée comme prochain caractère dans le texte généré. Cela avait pour conséquence que le texte \"cyclait\" souvent entre les mêmes séquences de caractères encore et encore, comme dans cet exemple : \n",
"```\n",
"today of the second the company and a second the company ...\n",
"```\n",
"\n",
"Cependant, si nous examinons la distribution de probabilité pour le prochain caractère, il se peut que la différence entre quelques probabilités les plus élevées ne soit pas énorme, par exemple, un caractère peut avoir une probabilité de 0,2, un autre de 0,19, etc. Par exemple, en cherchant le prochain caractère dans la séquence '*play*', le caractère suivant pourrait tout aussi bien être un espace ou un **e** (comme dans le mot *player*).\n",
"\n",
"Cela nous amène à la conclusion qu'il n'est pas toujours \"juste\" de sélectionner le caractère avec la probabilité la plus élevée, car choisir le deuxième plus probable pourrait également conduire à un texte cohérent. Il est plus judicieux de **prélever un échantillon** parmi les caractères en fonction de la distribution de probabilité donnée par la sortie du réseau.\n",
"\n",
"Ce prélèvement peut être effectué à l'aide de la fonction `np.multinomial`, qui implémente ce que l'on appelle la **distribution multinomiale**. Une fonction qui implémente cette génération de texte **souple** est définie ci-dessous :\n"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"--- Temperature = 0.3\n",
"Today #39;s strike #39; to start at the store return\n",
"On Sunday PO to Be Data Profit Up (Reuters)\n",
"Moscow, SP wins straight to the Microsoft #39;s control of the space start\n",
"President olding of the blast start for the strike to pay &lt;b&gt;...&lt;/b&gt;\n",
"Little red riding hood ficed to the spam countered in European &lt;b&gt;...&lt;/b&gt;\n",
"\n",
"--- Temperature = 0.8\n",
"Today countie strikes ryder missile faces food market blut\n",
"On Sunday collores lose-toppy of sale of Bullment in &lt;b&gt;...&lt;/b&gt;\n",
"Moscow, IBM Diffeiting in Afghan Software Hotels (Reuters)\n",
"President Ol Luster for Profit Peaced Raised (AP)\n",
"Little red riding hood dace on depart talks #39; bank up\n",
"\n",
"--- Temperature = 1.0\n",
"Today wits House buiting debate fixes #39; supervice stake again\n",
"On Sunday arling digital poaching In for level\n",
"Moscow, DS Up 7, Top Proble Protest Caprey Mamarian Strike\n",
"President teps help of roubler stepted lessabul-Dhalitics (AFP)\n",
"Little red riding hood signs on cash in Carter-youb\n",
"\n",
"--- Temperature = 1.3\n",
"Today wits flawer ro, pSIA figat's co DroftwavesIs Talo up\n",
"On Sunday hround elitwing wint EU Powerburlinetien\n",
"Moscow, Bazz #39;s sentries olymen winnelds' next for Olympite Huc?\n",
"President lost securitys from power Elections in Smiltrials\n",
"Little red riding hood vides profit, exponituity, profitmainalist-at said listers\n",
"\n",
"--- Temperature = 1.8\n",
"Today #39;It: He deat: N.KA Asside\n",
"On Sunday i arry Par aldeup patient Wo stele1\n"
]
},
{
"ename": "KeyError",
"evalue": "0",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-33-db32367a0feb>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mf\"\\n--- Temperature = {i}\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mj\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m5\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 20\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgenerate_soft\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmodel\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0msize\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m300\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mstart\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mwords\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mj\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mtemperature\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;32m<ipython-input-33-db32367a0feb>\u001b[0m in \u001b[0;36mgenerate_soft\u001b[0;34m(model, size, start, temperature)\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0mchars\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnc\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 12\u001b[0m \u001b[0minp\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0minp\u001b[0m\u001b[0;34m+\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mnc\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 13\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mdecode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mchars\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 14\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[0mwords\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m'Today '\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'On Sunday '\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'Moscow, '\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'President '\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'Little red riding hood '\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m<ipython-input-10-3f5fa6130b1d>\u001b[0m in \u001b[0;36mdecode\u001b[0;34m(x)\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mdecode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0;34m''\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mreverse_map\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mt\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mt\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;32m<ipython-input-10-3f5fa6130b1d>\u001b[0m in \u001b[0;36m<listcomp>\u001b[0;34m(.0)\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mdecode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0;34m''\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mreverse_map\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mt\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mt\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mKeyError\u001b[0m: 0"
]
}
],
"source": [
"def generate_soft(model,size=100,start='Today ',temperature=1.0):\n",
" inp = tokenizer.texts_to_sequences([start])[0]\n",
" chars = inp\n",
" for i in range(size):\n",
" out = model(tf.expand_dims(tf.one_hot(inp,vocab_size),0))[0][-1]\n",
" probs = tf.exp(tf.math.log(out)/temperature).numpy().astype(np.float64)\n",
" probs = probs/np.sum(probs)\n",
" nc = np.argmax(np.random.multinomial(1,probs,1))\n",
" if nc==eos_token:\n",
" break\n",
" chars.append(nc)\n",
" inp = inp+[nc]\n",
" return decode(chars)\n",
"\n",
"words = ['Today ','On Sunday ','Moscow, ','President ','Little red riding hood ']\n",
" \n",
"for i in [0.3,0.8,1.0,1.3,1.8]:\n",
" print(f\"\\n--- Temperature = {i}\")\n",
" for j in range(5):\n",
" print(generate_soft(model,size=300,start=words[j],temperature=i))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Nous avons introduit un paramètre supplémentaire appelé **température**, qui est utilisé pour indiquer à quel point nous devons nous en tenir à la probabilité la plus élevée. Si la température est de 1,0, nous effectuons un échantillonnage multinomial équitable, et lorsque la température tend vers l'infini - toutes les probabilités deviennent égales, et nous sélectionnons aléatoirement le prochain caractère. Dans l'exemple ci-dessous, nous pouvons observer que le texte devient dénué de sens lorsque nous augmentons trop la température, et il ressemble à un texte \"cyclé\" généré de manière rigide lorsqu'il se rapproche de 0.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Avertissement** : \nCe document a été traduit à l'aide du service de traduction automatique [Co-op Translator](https://github.com/Azure/co-op-translator). Bien que nous nous efforcions d'assurer l'exactitude, veuillez noter que les traductions automatisées peuvent contenir des erreurs ou des inexactitudes. Le document original dans sa langue d'origine doit être considéré comme la source faisant autorité. Pour des informations critiques, il est recommandé de recourir à une traduction professionnelle effectuée par un humain. Nous déclinons toute responsabilité en cas de malentendus ou d'interprétations erronées résultant de l'utilisation de cette traduction.\n"
]
}
],
"metadata": {
"interpreter": {
"hash": "16af2a8bbb083ea23e5e41c7f5787656b2ce26968575d8763f2c4b17f9cd711f"
},
"kernelspec": {
"display_name": "Python 3.8.12 ('py38')",
"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.8.12"
},
"coopTranslator": {
"original_hash": "9fbb7d5fda708537649f71f5f646fcde",
"translation_date": "2025-08-31T15:11:26+00:00",
"source_file": "lessons/5-NLP/17-GenerativeNetworks/GenerativeTF.ipynb",
"language_code": "fr"
}
},
"nbformat": 4,
"nbformat_minor": 4
}