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

495 lines
28 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Generatieve netwerken\n",
"\n",
"Recurrent Neural Networks (RNNs) en hun varianten met gated cellen, zoals Long Short Term Memory Cells (LSTMs) en Gated Recurrent Units (GRUs), bieden een mechanisme voor taalmodellering, oftewel ze kunnen de volgorde van woorden leren en voorspellingen doen voor het volgende woord in een reeks. Dit stelt ons in staat om RNNs te gebruiken voor **generatieve taken**, zoals gewone tekstgeneratie, machinevertaling en zelfs beeldbeschrijving.\n",
"\n",
"In de RNN-architectuur die we in de vorige eenheid hebben besproken, produceerde elke RNN-eenheid de volgende verborgen toestand als output. We kunnen echter ook een extra output toevoegen aan elke recurrente eenheid, waardoor we een **reeks** kunnen genereren (die even lang is als de oorspronkelijke reeks). Bovendien kunnen we RNN-eenheden gebruiken die bij elke stap geen invoer accepteren, maar alleen een initiële toestandsvector nemen en vervolgens een reeks outputs produceren.\n",
"\n",
"In dit notebook richten we ons op eenvoudige generatieve modellen die ons helpen tekst te genereren. Voor de eenvoud bouwen we een **karakter-niveau netwerk**, dat tekst letter voor letter genereert. Tijdens de training moeten we een tekstcorpus nemen en deze splitsen in letterreeksen.\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": [
"## Het opbouwen van een karaktervocabulaire\n",
"\n",
"Om een generatief netwerk op karakter-niveau te bouwen, moeten we tekst splitsen in individuele karakters in plaats van woorden. De `TextVectorization`-laag die we eerder hebben gebruikt, kan dit niet doen, dus we hebben twee opties:\n",
"\n",
"* Tekst handmatig laden en zelf tokeniseren, zoals in [dit officiële Keras-voorbeeld](https://keras.io/examples/generative/lstm_character_level_text_generation/)\n",
"* De `Tokenizer`-klasse gebruiken voor tokenisatie op karakter-niveau.\n",
"\n",
"We kiezen voor de tweede optie. Met `Tokenizer` kun je ook tokeniseren op woordniveau, dus het zou vrij eenvoudig moeten zijn om te schakelen tussen tokenisatie op karakter- en woordniveau.\n",
"\n",
"Voor tokenisatie op karakter-niveau moeten we de parameter `char_level=True` doorgeven:\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": [
"We willen ook een speciale token gebruiken om **einde van de reeks** aan te duiden, die we `<eos>` zullen noemen. Laten we deze handmatig toevoegen aan de 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": [
"## Een generatieve RNN trainen om titels te genereren\n",
"\n",
"De manier waarop we een RNN zullen trainen om nieuwstitels te genereren is als volgt. Bij elke stap nemen we één titel, die wordt ingevoerd in een RNN, en voor elk invoerkarakter vragen we het netwerk om het volgende uitvoerkarakter te genereren:\n",
"\n",
"![Afbeelding die een voorbeeld toont van RNN-generatie van het woord 'HELLO'.](../../../../../translated_images/nl/rnn-generate.56c54afb52f9781d.webp)\n",
"\n",
"Voor het laatste karakter van onze reeks vragen we het netwerk om een `<eos>`-token te genereren.\n",
"\n",
"Het belangrijkste verschil tussen de generatieve RNN die we hier gebruiken is dat we een uitvoer nemen van elke stap van de RNN, en niet alleen van de laatste cel. Dit kan worden bereikt door de parameter `return_sequences` op te geven aan de RNN-cel.\n",
"\n",
"Dus, tijdens de training zou een invoer voor het netwerk een reeks van gecodeerde karakters van een bepaalde lengte zijn, en een uitvoer zou een reeks van dezelfde lengte zijn, maar verschoven met één element en beëindigd met `<eos>`. Een minibatch zal bestaan uit meerdere van dergelijke reeksen, en we moeten **padding** gebruiken om alle reeksen uit te lijnen.\n",
"\n",
"Laten we functies maken die de dataset voor ons transformeren. Omdat we reeksen willen opvullen op minibatch-niveau, zullen we eerst de dataset groeperen door `.batch()` aan te roepen, en vervolgens `map` gebruiken om de transformatie uit te voeren. Dus, de transformatiefunctie zal een hele minibatch als parameter nemen:\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": [
"Een paar belangrijke dingen die we hier doen:\n",
"* We halen eerst de daadwerkelijke tekst uit de string-tensor\n",
"* `text_to_sequences` zet de lijst van strings om in een lijst van integer-tensors\n",
"* `pad_sequences` vult die tensors aan tot hun maximale lengte\n",
"* We coderen uiteindelijk alle karakters één-op-één, en doen ook de verschuiving en `<eos>` toevoeging. We zullen binnenkort zien waarom we één-op-één gecodeerde karakters nodig hebben\n",
"\n",
"Echter, deze functie is **Pythonic**, wat betekent dat deze niet automatisch kan worden vertaald naar een Tensorflow computationele grafiek. We krijgen fouten als we proberen deze functie direct in de `Dataset.map` functie te gebruiken. We moeten deze Pythonic aanroep insluiten door gebruik te maken van de `py_function` wrapper:\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**: Het onderscheiden van Pythonic en Tensorflow transformatiefuncties kan een beetje te complex lijken, en je vraagt je misschien af waarom we de dataset niet transformeren met standaard Python-functies voordat we deze doorgeven aan `fit`. Hoewel dit zeker mogelijk is, heeft het gebruik van `Dataset.map` een groot voordeel, omdat de datatransformatie-pijplijn wordt uitgevoerd met behulp van het Tensorflow computationele grafiek, wat gebruik maakt van GPU-berekeningen en de noodzaak om gegevens tussen CPU/GPU te verplaatsen minimaliseert.\n",
"\n",
"Nu kunnen we ons generatornetwerk bouwen en beginnen met trainen. Het kan gebaseerd zijn op elke recurrente cel die we in de vorige eenheid hebben besproken (simpel, LSTM of GRU). In ons voorbeeld zullen we LSTM gebruiken.\n",
"\n",
"Omdat het netwerk tekens als invoer neemt en de vocabulairegrootte vrij klein is, hebben we geen embeddinglaag nodig; een one-hot-gecodeerde invoer kan direct naar de LSTM-cel gaan. De uitvoerlaag zou een `Dense` classifier zijn die de LSTM-uitvoer omzet in one-hot-gecodeerde tokennummers.\n",
"\n",
"Daarnaast, omdat we werken met sequenties van variabele lengte, kunnen we een `Masking`-laag gebruiken om een masker te creëren dat het opgevulde deel van de string negeert. Dit is niet strikt noodzakelijk, omdat we niet erg geïnteresseerd zijn in alles wat voorbij het `<eos>`-token gaat, maar we zullen het gebruiken om wat ervaring op te doen met dit type laag. `input_shape` zou `(None, vocab_size)` zijn, waarbij `None` de sequentie van variabele lengte aangeeft, en de uitvoervorm is ook `(None, vocab_size)`, zoals je kunt zien in de `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": [
"## Output genereren\n",
"\n",
"Nu we het model hebben getraind, willen we het gebruiken om output te genereren. Allereerst hebben we een manier nodig om tekst te decoderen die wordt weergegeven door een reeks tokennummers. Hiervoor zouden we de functie `tokenizer.sequences_to_texts` kunnen gebruiken; echter, deze werkt niet goed met tokenisatie op het niveau van individuele tekens. Daarom nemen we een woordenboek van tokens uit de tokenizer (genaamd `word_index`), bouwen we een omgekeerde map en schrijven we onze eigen decodeerfunctie:\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": [
"Nu gaan we genereren. We beginnen met een string `start`, coderen deze in een reeks `inp`, en vervolgens roepen we bij elke stap ons netwerk aan om het volgende teken te voorspellen.\n",
"\n",
"De uitvoer van het netwerk `out` is een vector van `vocab_size` elementen die de waarschijnlijkheden van elk token vertegenwoordigen. We kunnen het meest waarschijnlijke tokennummer vinden door `argmax` te gebruiken. Vervolgens voegen we dit teken toe aan de gegenereerde lijst van tokens en gaan verder met genereren. Dit proces van het genereren van één teken wordt `size` keer herhaald om het gewenste aantal tekens te genereren, en we stoppen voortijdig wanneer `eos_token` wordt aangetroffen.\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": [
"## Output bemonsteren tijdens training\n",
"\n",
"Omdat we geen bruikbare metrics hebben zoals *nauwkeurigheid*, is de enige manier waarop we kunnen zien dat ons model beter wordt door **bemonstering** van gegenereerde strings tijdens de training. Om dit te doen, zullen we **callbacks** gebruiken, oftewel functies die we kunnen doorgeven aan de `fit`-functie en die periodiek tijdens de training worden aangeroepen.\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": [
"Dit voorbeeld genereert al behoorlijk goede tekst, maar er zijn verschillende manieren om het verder te verbeteren:\n",
"\n",
"* **Meer tekst**. We hebben alleen titels gebruikt voor onze taak, maar je kunt experimenteren met volledige tekst. Onthoud dat RNN's niet zo goed zijn in het verwerken van lange reeksen, dus het is logisch om ze op te splitsen in kortere zinnen, of altijd te trainen op een vaste sequentielengte van een vooraf gedefinieerde waarde `num_chars` (bijvoorbeeld 256). Je kunt proberen het bovenstaande voorbeeld aan te passen naar een dergelijke architectuur, met behulp van de [officiële Keras-tutorial](https://keras.io/examples/generative/lstm_character_level_text_generation/) als inspiratie.\n",
"\n",
"* **Meerdere lagen LSTM**. Het is zinvol om 2 of 3 lagen van LSTM-cellen te proberen. Zoals we in de vorige eenheid hebben besproken, haalt elke laag van een LSTM bepaalde patronen uit tekst, en in het geval van een generator op tekenniveau kunnen we verwachten dat de lagere LSTM-laag verantwoordelijk is voor het herkennen van lettergrepen, en de hogere lagen - voor woorden en woordcombinaties. Dit kan eenvoudig worden geïmplementeerd door een parameter voor het aantal lagen door te geven aan de LSTM-constructor.\n",
"\n",
"* Je kunt ook experimenteren met **GRU-eenheden** om te zien welke beter presteren, en met **verschillende groottes van verborgen lagen**. Een te grote verborgen laag kan resulteren in overfitting (bijvoorbeeld dat het netwerk exacte tekst leert), terwijl een kleinere grootte mogelijk geen goed resultaat oplevert.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Zachte tekstgeneratie en temperatuur\n",
"\n",
"In de vorige definitie van `generate` kozen we altijd het karakter met de hoogste waarschijnlijkheid als het volgende karakter in de gegenereerde tekst. Dit resulteerde er vaak in dat de tekst \"cyclisch\" werd en steeds dezelfde karakterreeksen herhaalde, zoals in dit voorbeeld:\n",
"```\n",
"today of the second the company and a second the company ...\n",
"```\n",
"\n",
"Als we echter naar de waarschijnlijkheidsverdeling voor het volgende karakter kijken, kan het zijn dat het verschil tussen een paar hoogste waarschijnlijkheden niet groot is, bijvoorbeeld: één karakter kan een waarschijnlijkheid van 0,2 hebben, en een ander 0,19, enzovoort. Bijvoorbeeld, bij het zoeken naar het volgende karakter in de reeks '*play*', kan het volgende karakter net zo goed een spatie zijn, of **e** (zoals in het woord *player*).\n",
"\n",
"Dit leidt ons tot de conclusie dat het niet altijd \"eerlijk\" is om het karakter met de hoogste waarschijnlijkheid te kiezen, omdat het kiezen van het op één na hoogste karakter ook tot betekenisvolle tekst kan leiden. Het is verstandiger om **karakters te bemonsteren** uit de waarschijnlijkheidsverdeling die door de netwerkoutput wordt gegeven.\n",
"\n",
"Dit bemonsteren kan worden gedaan met behulp van de functie `np.multinomial`, die de zogenaamde **multinomiale verdeling** implementeert. Een functie die deze **zachte** tekstgeneratie implementeert, is hieronder gedefinieerd:\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": [
"We hebben een extra parameter geïntroduceerd genaamd **temperatuur**, die wordt gebruikt om aan te geven hoe strikt we ons moeten houden aan de hoogste waarschijnlijkheid. Als de temperatuur 1,0 is, doen we eerlijke multinomiale sampling, en wanneer de temperatuur naar oneindig gaat - worden alle waarschijnlijkheden gelijk, en selecteren we willekeurig het volgende teken. In het onderstaande voorbeeld kunnen we zien dat de tekst betekenisloos wordt wanneer we de temperatuur te veel verhogen, en het lijkt op \"gecycled\" hard gegenereerde tekst wanneer het dichter bij 0 komt.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Disclaimer**: \nDit document is vertaald met behulp van de AI-vertalingsservice [Co-op Translator](https://github.com/Azure/co-op-translator). Hoewel we streven naar nauwkeurigheid, dient u zich ervan bewust te zijn dat geautomatiseerde vertalingen fouten of onnauwkeurigheden kunnen bevatten. Het originele document in zijn oorspronkelijke taal moet worden beschouwd als de gezaghebbende bron. Voor cruciale informatie wordt professionele menselijke vertaling aanbevolen. Wij zijn niet aansprakelijk voor eventuele misverstanden of verkeerde interpretaties die voortvloeien uit het gebruik van deze vertaling.\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-28T21:31:59+00:00",
"source_file": "lessons/5-NLP/17-GenerativeNetworks/GenerativeTF.ipynb",
"language_code": "nl"
}
},
"nbformat": 4,
"nbformat_minor": 4
}