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

495 lines
27 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Generative nettverk\n",
"\n",
"Rekurrente nevrale nettverk (RNNs) og deres gatede cellevarianter som Long Short Term Memory Cells (LSTMs) og Gated Recurrent Units (GRUs) har gitt en mekanisme for språkmodellering, dvs. de kan lære ordrekkefølge og gi prediksjoner for neste ord i en sekvens. Dette gjør det mulig å bruke RNNs til **generative oppgaver**, som vanlig tekstgenerering, maskinoversettelse og til og med bildetekstgenerering.\n",
"\n",
"I RNN-arkitekturen vi diskuterte i forrige enhet, produserte hver RNN-enhet neste skjulte tilstand som et output. Imidlertid kan vi også legge til et annet output til hver rekurrente enhet, som gjør det mulig for oss å generere en **sekvens** (som er like lang som den opprinnelige sekvensen). Videre kan vi bruke RNN-enheter som ikke tar imot en input på hvert steg, men kun tar en initial tilstandsvektor og deretter produserer en sekvens av outputs.\n",
"\n",
"I denne notatboken vil vi fokusere på enkle generative modeller som hjelper oss med å generere tekst. For enkelhets skyld skal vi bygge et **tegn-nivå nettverk**, som genererer tekst bokstav for bokstav. Under trening må vi ta et tekstkorpus og dele det opp i tegnsekvenser.\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": [
"## Bygge opp tegnordforråd\n",
"\n",
"For å bygge et tegnbasert generativt nettverk, må vi dele opp tekst i individuelle tegn i stedet for ord. `TextVectorization`-laget vi har brukt tidligere kan ikke gjøre dette, så vi har to alternativer:\n",
"\n",
"* Laste inn tekst manuelt og gjøre tokenisering 'for hånd', som vist i [dette offisielle Keras-eksempelet](https://keras.io/examples/generative/lstm_character_level_text_generation/)\n",
"* Bruke `Tokenizer`-klassen for tegnbasert tokenisering.\n",
"\n",
"Vi velger det andre alternativet. `Tokenizer` kan også brukes til å tokenisere til ord, så det skal være ganske enkelt å bytte fra tegnbasert til ordnivå-tokenisering.\n",
"\n",
"For å gjøre tegnbasert tokenisering, må vi sende inn parameteren `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 ønsker også å bruke en spesiell token for å markere **slutt på sekvens**, som vi vil kalle `<eos>`. La oss legge den til manuelt i vokabularet:\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": [
"## Trene en generativ RNN til å lage titler\n",
"\n",
"Måten vi skal trene RNN til å generere nyhetstitler på er som følger. For hvert steg tar vi én tittel, som mates inn i en RNN, og for hvert inndata-tegn ber vi nettverket om å generere neste utdata-tegn:\n",
"\n",
"![Bilde som viser et eksempel på RNN-generering av ordet 'HELLO'.](../../../../../translated_images/no/rnn-generate.56c54afb52f9781d.webp)\n",
"\n",
"For det siste tegnet i sekvensen vår ber vi nettverket om å generere `<eos>`-token.\n",
"\n",
"Den største forskjellen med den generative RNN-en vi bruker her er at vi tar utdata fra hvert steg i RNN-en, og ikke bare fra den siste cellen. Dette kan oppnås ved å spesifisere `return_sequences`-parameteren til RNN-cellen.\n",
"\n",
"Dermed, under treningen, vil inndata til nettverket være en sekvens av kodede tegn av en viss lengde, og utdata vil være en sekvens av samme lengde, men forskjøvet med ett element og avsluttet med `<eos>`. Minibatch vil bestå av flere slike sekvenser, og vi må bruke **padding** for å justere alle sekvensene.\n",
"\n",
"La oss lage funksjoner som vil transformere datasettet for oss. Fordi vi ønsker å padde sekvenser på minibatch-nivå, vil vi først batch'e datasettet ved å kalle `.batch()`, og deretter `map` det for å utføre transformasjonen. Så transformasjonsfunksjonen vil 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": [
"Noen viktige ting vi gjør her:\n",
"* Vi starter med å hente ut selve teksten fra streng-tensoren\n",
"* `text_to_sequences` konverterer listen av strenger til en liste av heltallstensorer\n",
"* `pad_sequences` fyller ut disse tensorene til deres maksimale lengde\n",
"* Til slutt one-hot-koder vi alle tegnene, og utfører også forskyvning og legger til `<eos>`. Vi skal snart se hvorfor vi trenger one-hot-kodede tegn\n",
"\n",
"Denne funksjonen er imidlertid **Pythonisk**, dvs. den kan ikke automatisk oversettes til Tensorflow sin beregningsgraf. Vi vil få feil hvis vi prøver å bruke denne funksjonen direkte i `Dataset.map`-funksjonen. Vi må omslutte dette Pythoniske kallet ved å bruke `py_function`-innpakningen:\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": [
"> **Merk**: Å skille mellom Pythonic- og Tensorflow-transformasjonsfunksjoner kan virke litt for komplisert, og du lurer kanskje på hvorfor vi ikke transformerer datasettet ved hjelp av standard Python-funksjoner før vi sender det til `fit`. Selv om dette absolutt kan gjøres, har det en stor fordel å bruke `Dataset.map`, fordi datatransformasjonsrørledningen utføres ved hjelp av Tensorflows beregningsgraf, som drar nytte av GPU-beregninger og minimerer behovet for å overføre data mellom CPU/GPU.\n",
"\n",
"Nå kan vi bygge vårt generatornettverk og starte treningen. Det kan baseres på hvilken som helst rekurrent celle som vi diskuterte i forrige enhet (simple, LSTM eller GRU). I vårt eksempel vil vi bruke LSTM.\n",
"\n",
"Siden nettverket tar tegn som input, og vokabularstørrelsen er ganske liten, trenger vi ikke en embedding-lag; én-hot-kodet input kan sendes direkte inn i LSTM-cellen. Utgangslaget vil være en `Dense`-klassifiserer som konverterer LSTM-utgangen til én-hot-kodede token-numre.\n",
"\n",
"I tillegg, siden vi jobber med sekvenser av variabel lengde, kan vi bruke `Masking`-laget for å lage en maske som ignorerer den utfylte delen av strengen. Dette er ikke strengt nødvendig, fordi vi ikke er veldig interessert i alt som går utover `<eos>`-tokenet, men vi vil bruke det for å få litt erfaring med denne lagtypen. `input_shape` vil være `(None, vocab_size)`, hvor `None` indikerer sekvensen med variabel lengde, og utgangsformen er også `(None, vocab_size)`, som du kan se fra `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": [
"## Generere output\n",
"\n",
"Nå som vi har trent modellen, ønsker vi å bruke den til å generere noe output. Først og fremst trenger vi en måte å dekode tekst representert av en sekvens av token-numre. For å gjøre dette, kunne vi bruke funksjonen `tokenizer.sequences_to_texts`; men den fungerer ikke godt med tokenisering på tegnnivå. Derfor vil vi ta en ordbok med tokens fra tokenizer (kalt `word_index`), bygge et reversert kart, og skrive vår egen dekodingsfunksjon:\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": [
"Nå skal vi generere. Vi starter med en streng `start`, koder den til en sekvens `inp`, og deretter kaller vi nettverket vårt på hvert steg for å finne neste tegn.\n",
"\n",
"Utdataene fra nettverket `out` er en vektor med `vocab_size` elementer som representerer sannsynlighetene for hver token, og vi kan finne nummeret på den mest sannsynlige tokenen ved å bruke `argmax`. Deretter legger vi til dette tegnet i den genererte listen av tokens og fortsetter genereringen. Denne prosessen med å generere ett tegn gjentas `size` ganger for å generere ønsket antall tegn, og vi avslutter tidligere hvis `eos_token` oppdages.\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": [
"## Eksempel på output under trening\n",
"\n",
"Siden vi ikke har noen nyttige målinger som *nøyaktighet*, er den eneste måten vi kan se at modellen vår blir bedre på, ved å **eksemplifisere** genererte strenger under trening. For å gjøre dette, vil vi bruke **callbacks**, altså funksjoner som vi kan sende til `fit`-funksjonen, og som vil bli kalt med jevne mellomrom under trening.\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": [
"Dette eksempelet genererer allerede ganske god tekst, men det kan forbedres på flere måter:\n",
"\n",
"* **Mer tekst**. Vi har kun brukt titler for oppgaven vår, men du kan eksperimentere med fullstendig tekst. Husk at RNN-er ikke er så gode til å håndtere lange sekvenser, så det gir mening enten å dele dem opp i kortere setninger, eller alltid trene på en fast sekvenslengde med en forhåndsdefinert verdi `num_chars` (for eksempel 256). Du kan prøve å endre eksempelet ovenfor til en slik arkitektur, ved å bruke [offisiell Keras-veiledning](https://keras.io/examples/generative/lstm_character_level_text_generation/) som inspirasjon.\n",
"\n",
"* **Flerlags LSTM**. Det kan være fornuftig å prøve 2 eller 3 lag med LSTM-celler. Som nevnt i forrige enhet, trekker hvert lag av LSTM ut visse mønstre fra tekst, og i tilfelle av en generator på tegnnivå kan vi forvente at det laveste LSTM-laget er ansvarlig for å trekke ut stavelser, og de høyere lagene - for ord og ordkombinasjoner. Dette kan enkelt implementeres ved å sende parameteren for antall lag til LSTM-konstruktøren.\n",
"\n",
"* Du kan også eksperimentere med **GRU-enheter** og se hvilke som gir bedre resultater, samt med **forskjellige størrelser på skjulte lag**. For store skjulte lag kan føre til overtilpasning (f.eks. at nettverket lærer nøyaktig tekst), mens mindre størrelser kanskje ikke gir gode resultater.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Myk tekstgenerering og temperatur\n",
"\n",
"I den tidligere definisjonen av `generate` valgte vi alltid tegnet med høyest sannsynlighet som neste tegn i den genererte teksten. Dette førte ofte til at teksten \"gikk i sirkel\" og gjentok de samme tegnsekvensene igjen og igjen, som i dette eksempelet:\n",
"```\n",
"today of the second the company and a second the company ...\n",
"```\n",
"\n",
"Men hvis vi ser på sannsynlighetsfordelingen for neste tegn, kan det hende at forskjellen mellom de høyeste sannsynlighetene ikke er så stor, for eksempel kan ett tegn ha sannsynlighet 0,2, mens et annet har 0,19, osv. For eksempel, når vi ser etter neste tegn i sekvensen '*play*', kan neste tegn like gjerne være et mellomrom eller **e** (som i ordet *player*).\n",
"\n",
"Dette fører oss til konklusjonen at det ikke alltid er \"rettferdig\" å velge tegnet med høyest sannsynlighet, fordi det å velge det nest høyeste fortsatt kan føre til meningsfull tekst. Det er klokere å **samle** tegn fra sannsynlighetsfordelingen som er gitt av nettverksutgangen.\n",
"\n",
"Denne sampling-prosessen kan gjøres ved hjelp av funksjonen `np.multinomial`, som implementerer den såkalte **multinomiale fordelingen**. En funksjon som implementerer denne **myke** tekstgenereringen er definert nedenfor:\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 introdusert en ekstra parameter kalt **temperatur**, som brukes til å indikere hvor strengt vi skal holde oss til den høyeste sannsynligheten. Hvis temperaturen er 1.0, gjør vi rettferdig multinomial sampling, og når temperaturen går mot uendelig - blir alle sannsynligheter like, og vi velger neste tegn tilfeldig. I eksempelet nedenfor kan vi observere at teksten blir meningsløs når vi øker temperaturen for mye, og den ligner \"syklisk\" hard-generert tekst når den nærmer seg 0.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Ansvarsfraskrivelse**: \nDette dokumentet er oversatt ved hjelp av AI-oversettelsestjenesten [Co-op Translator](https://github.com/Azure/co-op-translator). Selv om vi streber etter nøyaktighet, vær oppmerksom på at automatiske oversettelser kan inneholde feil eller unøyaktigheter. Det originale dokumentet på sitt opprinnelige språk bør anses som den autoritative kilden. For kritisk informasjon anbefales profesjonell menneskelig oversettelse. Vi er ikke ansvarlige for misforståelser eller feiltolkninger som oppstår ved bruk av denne oversettelsen.\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:26:23+00:00",
"source_file": "lessons/5-NLP/17-GenerativeNetworks/GenerativeTF.ipynb",
"language_code": "no"
}
},
"nbformat": 4,
"nbformat_minor": 4
}