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

497 lines
27 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Generativa nätverk\n",
"\n",
"Recurrent Neural Networks (RNNs) och deras varianter med grindade celler, såsom Long Short Term Memory Cells (LSTMs) och Gated Recurrent Units (GRUs), gav en mekanism för språkmodellering, det vill säga de kan lära sig ordordning och ge förutsägelser för nästa ord i en sekvens. Detta gör det möjligt att använda RNNs för **generativa uppgifter**, såsom vanlig textgenerering, maskinöversättning och till och med bildbeskrivning.\n",
"\n",
"I RNN-arkitekturen som vi diskuterade i föregående enhet, producerade varje RNN-enhet nästa dolda tillstånd som en utgång. Men vi kan också lägga till en annan utgång till varje återkommande enhet, vilket skulle göra det möjligt för oss att generera en **sekvens** (som är lika lång som den ursprungliga sekvensen). Dessutom kan vi använda RNN-enheter som inte tar emot en inmatning vid varje steg, utan bara tar en initial tillståndsvektor och sedan producerar en sekvens av utgångar.\n",
"\n",
"I denna notebook kommer vi att fokusera på enkla generativa modeller som hjälper oss att generera text. För enkelhetens skull ska vi bygga ett **teckennivånätverk**, som genererar text bokstav för bokstav. Under träningen behöver vi ta en textkorpus och dela upp den i teckensekvenser.\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": [
"## Bygga teckenordförråd\n",
"\n",
"För att bygga ett generativt nätverk på teckennivå behöver vi dela upp texten i enskilda tecken istället för ord. `TextVectorization`-lagret som vi har använt tidigare kan inte göra detta, så vi har två alternativ:\n",
"\n",
"* Ladda text manuellt och göra tokenisering \"för hand\", som i [detta officiella Keras-exempel](https://keras.io/examples/generative/lstm_character_level_text_generation/)\n",
"* Använda `Tokenizer`-klassen för tokenisering på teckennivå.\n",
"\n",
"Vi kommer att välja det andra alternativet. `Tokenizer` kan också användas för att tokenisera till ord, så det bör vara enkelt att växla mellan tokenisering på teckennivå och ordnivå.\n",
"\n",
"För att göra tokenisering på teckennivå behöver vi ange parametern `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": [
"Vi vill också använda en speciell token för att beteckna **slut på sekvens**, som vi kommer att kalla `<eos>`. Låt oss lägga till den manuellt i vokabulären:\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": [
"Nu, för att koda text till sekvenser av siffror, kan vi använda:\n"
]
},
{
"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": [
"## Träna ett generativt RNN för att skapa titlar\n",
"\n",
"Så här kommer vi att träna ett RNN för att generera nyhetstitlar. Vid varje steg tar vi en titel, som matas in i ett RNN, och för varje inmatad tecken ber vi nätverket att generera nästa utmatade tecken:\n",
"\n",
"![Bild som visar ett exempel på RNN-generering av ordet 'HELLO'.](../../../../../translated_images/sv/rnn-generate.56c54afb52f9781d.webp)\n",
"\n",
"För det sista tecknet i vår sekvens kommer vi att be nätverket att generera `<eos>`-token.\n",
"\n",
"Den största skillnaden med det generativa RNN som vi använder här är att vi kommer att ta en utmatning från varje steg i RNN, och inte bara från den sista cellen. Detta kan uppnås genom att specificera parametern `return_sequences` till RNN-cellen.\n",
"\n",
"Således, under träningen, skulle en inmatning till nätverket vara en sekvens av kodade tecken av en viss längd, och en utmatning skulle vara en sekvens av samma längd, men förskjuten med ett element och avslutad med `<eos>`. En minibatch kommer att bestå av flera sådana sekvenser, och vi behöver använda **padding** för att justera alla sekvenser.\n",
"\n",
"Låt oss skapa funktioner som kommer att transformera datasetet åt oss. Eftersom vi vill fylla ut sekvenser på minibatch-nivå, kommer vi först att batcha datasetet genom att anropa `.batch()`, och sedan `map` för att utföra transformationen. Så, transformationsfunktionen kommer att ta en hel minibatch som parameter:\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": [
"Några viktiga saker som vi gör här:\n",
"* Vi börjar med att extrahera den faktiska texten från sträng-tensorn\n",
"* `text_to_sequences` omvandlar listan av strängar till en lista av heltals-tensorer\n",
"* `pad_sequences` fyller ut dessa tensorer till deras maximala längd\n",
"* Slutligen one-hot-kodar vi alla tecken, och gör även förskjutningen och lägger till `<eos>`. Vi kommer snart att se varför vi behöver one-hot-kodade tecken\n",
"\n",
"Den här funktionen är dock **Pythonisk**, dvs. den kan inte automatiskt översättas till Tensorflow:s beräkningsgraf. Vi kommer att få fel om vi försöker använda den här funktionen direkt i `Dataset.map`-funktionen. Vi behöver kapsla in detta Pythoniska anrop genom att använda `py_function`-omslutaren:\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": [
"> **Observera**: Att skilja mellan Pythoniska och Tensorflow-transformationsfunktioner kan verka lite för komplext, och du kanske undrar varför vi inte transformerar datasetet med standardfunktioner i Python innan vi skickar det till `fit`. Även om detta definitivt är möjligt, har användningen av `Dataset.map` en stor fördel, eftersom datatransformationspipelinan körs med Tensorflows beräkningsgraf. Detta drar nytta av GPU-beräkningar och minimerar behovet av att överföra data mellan CPU och GPU.\n",
"\n",
"Nu kan vi bygga vårt generatornätverk och börja träna. Det kan baseras på vilken återkommande cell som helst som vi diskuterade i föregående enhet (enkel, LSTM eller GRU). I vårt exempel kommer vi att använda LSTM.\n",
"\n",
"Eftersom nätverket tar tecken som indata och vokabulärstorleken är ganska liten, behöver vi inget inbäddningslager; one-hot-kodad indata kan direkt skickas in i LSTM-cellen. Utgångslagret skulle vara en `Dense`-klassificerare som omvandlar LSTM-utgången till one-hot-kodade tokennummer.\n",
"\n",
"Dessutom, eftersom vi arbetar med sekvenser av varierande längd, kan vi använda ett `Masking`-lager för att skapa en mask som ignorerar den utfyllda delen av strängen. Detta är inte strikt nödvändigt, eftersom vi inte är särskilt intresserade av allt som går bortom `<eos>`-token, men vi kommer att använda det för att få lite erfarenhet av denna typ av lager. `input_shape` skulle vara `(None, vocab_size)`, där `None` indikerar sekvenser av varierande längd, och utgångsformen är också `(None, vocab_size)`, som du kan se från `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": [
"## Generera output\n",
"\n",
"Nu när vi har tränat modellen vill vi använda den för att generera output. Först och främst behöver vi ett sätt att avkoda text som representeras av en sekvens av tokennummer. För att göra detta kan vi använda funktionen `tokenizer.sequences_to_texts`; dock fungerar den inte särskilt bra med tokenisering på teckennivå. Därför kommer vi att ta en ordbok med tokens från tokenizer (kallad `word_index`), bygga en omvänd karta och skriva vår egen avkodningsfunktion:\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 börjar vi med en sträng `start`, kodar den till en sekvens `inp`, och sedan vid varje steg anropar vi vårt nätverk för att förutsäga nästa tecken.\n",
"\n",
"Utdata från nätverket `out` är en vektor med `vocab_size` element som representerar sannolikheten för varje token, och vi kan hitta det mest sannolika token-numret genom att använda `argmax`. Därefter lägger vi till detta tecken i den genererade listan av tokens och fortsätter med genereringen. Denna process att generera ett tecken upprepas `size` gånger för att generera önskat antal tecken, och vi avslutar tidigare om `eos_token` påträffas.\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": [
"## Sampla output under träning\n",
"\n",
"Eftersom vi inte har några användbara mått som *noggrannhet*, är det enda sättet att se att vår modell förbättras genom att **sampla** genererade strängar under träning. För att göra detta kommer vi att använda **callbacks**, dvs. funktioner som vi kan skicka till `fit`-funktionen, och som kommer att anropas periodiskt under träningen.\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": [
"Det här exemplet genererar redan ganska bra text, men det kan förbättras på flera sätt:\n",
"\n",
"* **Mer text**. Vi har bara använt titlar för vår uppgift, men du kanske vill experimentera med fullständig text. Kom ihåg att RNN:er inte är särskilt bra på att hantera långa sekvenser, så det är vettigt att antingen dela upp dem i kortare meningar eller alltid träna på en fast sekvenslängd av ett fördefinierat värde `num_chars` (till exempel 256). Du kan försöka ändra exemplet ovan till en sådan arkitektur, med hjälp av [officiell Keras-handledning](https://keras.io/examples/generative/lstm_character_level_text_generation/) som inspiration.\n",
"\n",
"* **Flerskikts-LSTM**. Det kan vara värt att prova 2 eller 3 lager av LSTM-celler. Som vi nämnde i den tidigare enheten, extraherar varje lager av LSTM vissa mönster från texten, och i fallet med en generator på teckennivå kan vi förvänta oss att det lägre LSTM-lagret ansvarar för att extrahera stavelser, och de högre lagren - för ord och ordkombinationer. Detta kan enkelt implementeras genom att skicka ett parameter för antal lager till LSTM-konstruktorn.\n",
"\n",
"* Du kanske också vill experimentera med **GRU-enheter** och se vilka som presterar bättre, samt med **olika storlekar på dolda lager**. Ett för stort dolt lager kan leda till överanpassning (t.ex. att nätverket lär sig exakt text), medan en mindre storlek kanske inte ger ett bra resultat.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Mjuk textgenerering och temperatur\n",
"\n",
"I den tidigare definitionen av `generate` valde vi alltid tecknet med högst sannolikhet som nästa tecken i den genererade texten. Detta resulterade ofta i att texten \"cirkulerade\" mellan samma teckensekvenser om och om igen, som i detta exempel:\n",
"```\n",
"today of the second the company and a second the company ...\n",
"```\n",
"\n",
"Men om vi tittar på sannolikhetsfördelningen för nästa tecken, kan det vara så att skillnaden mellan de högsta sannolikheterna inte är särskilt stor, t.ex. ett tecken kan ha sannolikheten 0,2, ett annat 0,19, etc. Till exempel, när vi letar efter nästa tecken i sekvensen '*play*', kan nästa tecken lika gärna vara ett mellanslag eller **e** (som i ordet *player*).\n",
"\n",
"Detta leder oss till slutsatsen att det inte alltid är \"rättvist\" att välja tecknet med högst sannolikhet, eftersom att välja det näst högsta fortfarande kan leda till meningsfull text. Det är klokare att **sampla** tecken från sannolikhetsfördelningen som ges av nätverkets output.\n",
"\n",
"Denna sampling kan göras med hjälp av funktionen `np.multinomial`, som implementerar den så kallade **multinomialfördelningen**. En funktion som implementerar denna **mjuka** textgenerering definieras nedan:\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": [
"Vi har introducerat en ytterligare parameter kallad **temperatur**, som används för att indikera hur strikt vi ska hålla oss till den högsta sannolikheten. Om temperaturen är 1,0 gör vi rättvis multinomial sampling, och när temperaturen går mot oändligheten - blir alla sannolikheter lika, och vi väljer nästa tecken slumpmässigt. I exemplet nedan kan vi observera att texten blir meningslös när vi ökar temperaturen för mycket, och den liknar \"cyklisk\" hårdgenererad text när den närmar sig 0.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Ansvarsfriskrivning**: \nDetta dokument har översatts med hjälp av AI-översättningstjänsten [Co-op Translator](https://github.com/Azure/co-op-translator). Även om vi strävar efter noggrannhet, bör du vara medveten om att automatiserade översättningar kan innehålla fel eller felaktigheter. Det ursprungliga dokumentet på dess ursprungliga språk bör betraktas som den auktoritativa källan. För kritisk information rekommenderas professionell mänsklig översättning. Vi ansvarar inte för eventuella missförstånd eller feltolkningar som uppstår vid användning av denna översättning.\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-28T17:24:46+00:00",
"source_file": "lessons/5-NLP/17-GenerativeNetworks/GenerativeTF.ipynb",
"language_code": "sv"
}
},
"nbformat": 4,
"nbformat_minor": 4
}