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

497 lines
27 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Generativne mreže\n",
"\n",
"Rekurentne neuronske mreže (RNN-ovi) i njihove varijante s kontroliranim ćelijama, poput ćelija dugog kratkoročnog pamćenja (LSTM-ova) i kontroliranih rekurentnih jedinica (GRU-ova), omogućile su modeliranje jezika, tj. mogu naučiti redoslijed riječi i pružiti predviđanja za sljedeću riječ u nizu. To nam omogućuje korištenje RNN-ova za **generativne zadatke**, poput običnog generiranja teksta, strojnog prevođenja, pa čak i opisivanja slika.\n",
"\n",
"U RNN arhitekturi koju smo raspravili u prethodnoj jedinici, svaka RNN jedinica proizvodila je sljedeće skriveno stanje kao izlaz. Međutim, možemo dodati i drugi izlaz svakoj rekurentnoj jedinici, što bi nam omogućilo da dobijemo **niz** (koji je jednake duljine kao i izvorni niz). Štoviše, možemo koristiti RNN jedinice koje ne primaju ulaz na svakom koraku, već samo uzimaju neki početni vektor stanja i zatim proizvode niz izlaza.\n",
"\n",
"U ovom ćemo se bilježniku usredotočiti na jednostavne generativne modele koji nam pomažu generirati tekst. Radi jednostavnosti, izgradimo **mrežu na razini znakova**, koja generira tekst slovo po slovo. Tijekom treniranja, trebamo uzeti neki korpus teksta i podijeliti ga na nizove slova.\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": [
"## Izgradnja vokabulara znakova\n",
"\n",
"Za izgradnju generativne mreže na razini znakova, potrebno je tekst podijeliti na pojedinačne znakove umjesto na riječi. `TextVectorization` sloj koji smo koristili ranije ne može to učiniti, pa imamo dvije opcije:\n",
"\n",
"* Ručno učitati tekst i izvršiti tokenizaciju 'ručno', kao u [ovom službenom Keras primjeru](https://keras.io/examples/generative/lstm_character_level_text_generation/)\n",
"* Koristiti `Tokenizer` klasu za tokenizaciju na razini znakova.\n",
"\n",
"Odlučit ćemo se za drugu opciju. `Tokenizer` se također može koristiti za tokenizaciju na razini riječi, pa bi trebalo biti jednostavno prebaciti se s tokenizacije na razini znakova na tokenizaciju na razini riječi.\n",
"\n",
"Za tokenizaciju na razini znakova, potrebno je proslijediti parametar `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": [
"Također želimo koristiti jedan poseban token za označavanje **kraja niza**, koji ćemo nazvati `<eos>`. Dodajmo ga ručno u vokabular:\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": [
"Sada, za kodiranje teksta u nizove brojeva, možemo koristiti:\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": [
"## Treniranje generativne RNN za generiranje naslova\n",
"\n",
"Način na koji ćemo trenirati RNN za generiranje naslova vijesti je sljedeći. U svakom koraku uzet ćemo jedan naslov, koji će se proslijediti u RNN, i za svaki ulazni znak tražit ćemo od mreže da generira sljedeći izlazni znak:\n",
"\n",
"![Slika koja prikazuje primjer generiranja riječi 'HELLO' pomoću RNN-a.](../../../../../translated_images/hr/rnn-generate.56c54afb52f9781d.webp)\n",
"\n",
"Za posljednji znak našeg niza tražit ćemo od mreže da generira `<eos>` token.\n",
"\n",
"Glavna razlika generativne RNN koju ovdje koristimo je ta što ćemo uzimati izlaz iz svakog koraka RNN-a, a ne samo iz završne ćelije. To se može postići postavljanjem parametra `return_sequences` za RNN ćeliju.\n",
"\n",
"Dakle, tijekom treniranja, ulaz u mrežu bit će niz kodiranih znakova određene duljine, a izlaz će biti niz iste duljine, ali pomaknut za jedan element i završen s `<eos>`. Minibatch će se sastojati od nekoliko takvih nizova, a za poravnanje svih nizova trebat ćemo koristiti **padding**.\n",
"\n",
"Napravimo funkcije koje će transformirati skup podataka za nas. Budući da želimo dodati padding na razini minibatcha, prvo ćemo grupirati skup podataka pozivom `.batch()`, a zatim ga `map`-irati kako bismo izvršili transformaciju. Dakle, funkcija transformacije uzimat će cijeli minibatch kao parametar:\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": [
"Nekoliko važnih stvari koje ovdje radimo:\n",
"* Prvo izdvajamo stvarni tekst iz string tenzora\n",
"* `text_to_sequences` pretvara popis stringova u popis tenzora s cijelim brojevima\n",
"* `pad_sequences` dopunjava te tenzore do njihove maksimalne duljine\n",
"* Na kraju vršimo one-hot enkodiranje svih znakova, kao i pomicanje i dodavanje `<eos>`. Uskoro ćemo vidjeti zašto su nam potrebni one-hot enkodirani znakovi\n",
"\n",
"Međutim, ova funkcija je **Pythonic**, tj. ne može se automatski prevesti u Tensorflow računalni graf. Dobit ćemo pogreške ako pokušamo koristiti ovu funkciju izravno u funkciji `Dataset.map`. Moramo ovu Pythonic funkciju obuhvatiti koristeći `py_function` omotač:\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": [
"> **Napomena**: Razlikovanje između Pythonovih i Tensorflow funkcija za transformaciju podataka može se činiti prilično složenim, i možda se pitate zašto ne transformiramo skup podataka koristeći standardne Python funkcije prije nego ga proslijedimo u `fit`. Iako se to definitivno može učiniti, korištenje `Dataset.map` ima veliku prednost, jer se pipeline za transformaciju podataka izvršava koristeći Tensorflow-ov računalni graf, što omogućuje korištenje GPU-a za izračune i minimizira potrebu za prijenosom podataka između CPU-a i GPU-a.\n",
"\n",
"Sada možemo izgraditi naš generator mreže i započeti treniranje. Može se temeljiti na bilo kojoj rekurentnoj ćeliji koju smo raspravili u prethodnoj jedinici (jednostavna, LSTM ili GRU). U našem primjeru koristit ćemo LSTM.\n",
"\n",
"Budući da mreža prima znakove kao ulaz, a veličina vokabulara je prilično mala, ne trebamo sloj za ugrađivanje; ulaz kodiran u one-hot formatu može direktno ući u LSTM ćeliju. Izlazni sloj bit će `Dense` klasifikator koji će pretvoriti LSTM izlaz u brojeve tokena kodirane u one-hot formatu.\n",
"\n",
"Osim toga, budući da radimo s nizovima promjenjive duljine, možemo koristiti sloj `Masking` za stvaranje maske koja će ignorirati popunjeni dio niza. Ovo nije strogo potrebno, jer nas ne zanima previše sve što dolazi nakon `<eos>` tokena, ali ćemo ga koristiti radi stjecanja iskustva s ovom vrstom sloja. `input_shape` će biti `(None, vocab_size)`, gdje `None` označava niz promjenjive duljine, a izlazni oblik također je `(None, vocab_size)`, kao što možete vidjeti iz `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": [
"## Generiranje izlaza\n",
"\n",
"Sada kada smo model istrenirali, želimo ga koristiti za generiranje izlaza. Prije svega, trebamo način za dekodiranje teksta predstavljenog nizom brojeva tokena. Za to bismo mogli koristiti funkciju `tokenizer.sequences_to_texts`; međutim, ona ne funkcionira dobro s tokenizacijom na razini znakova. Stoga ćemo uzeti rječnik tokena iz tokenizatora (nazvan `word_index`), izgraditi obrnuti mapiranje i napisati vlastitu funkciju za dekodiranje:\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": [
"Sada ćemo započeti generiranje. Počet ćemo s nekim nizom `start`, kodirati ga u sekvencu `inp`, a zatim ćemo u svakom koraku pozvati našu mrežu kako bismo odredili sljedeći znak.\n",
"\n",
"Izlaz mreže `out` je vektor s `vocab_size` elemenata koji predstavljaju vjerojatnosti svakog tokena, a najvjerojatniji broj tokena možemo pronaći koristeći `argmax`. Zatim dodajemo ovaj znak generiranom popisu tokena i nastavljamo s generiranjem. Ovaj proces generiranja jednog znaka ponavlja se `size` puta kako bismo generirali potreban broj znakova, a završavamo ranije ako se naiđe na `eos_token`.\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": [
"## Uzorkovanje rezultata tijekom treniranja\n",
"\n",
"Budući da nemamo korisne metrike poput *točnosti*, jedini način na koji možemo vidjeti da naš model postaje bolji jest **uzorkovanjem** generiranog niza tijekom treniranja. Da bismo to učinili, koristit ćemo **povratne pozive** (callbacks), tj. funkcije koje možemo proslijediti funkciji `fit`, a koje će se periodično pozivati tijekom treniranja.\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": [
"Ovaj primjer već generira prilično dobar tekst, ali može se dodatno poboljšati na nekoliko načina:\n",
"\n",
"* **Više teksta**. Koristili smo samo naslove za naš zadatak, ali možda biste htjeli eksperimentirati s punim tekstom. Imajte na umu da RNN-ovi nisu previše dobri u rukovanju dugim sekvencama, pa ima smisla ili ih podijeliti na kraće rečenice, ili uvijek trenirati na fiksnoj duljini sekvence neke unaprijed definirane vrijednosti `num_chars` (recimo, 256). Možete pokušati promijeniti gornji primjer u takvu arhitekturu, koristeći [službeni Keras vodič](https://keras.io/examples/generative/lstm_character_level_text_generation/) kao inspiraciju.\n",
"\n",
"* **Višeslojni LSTM**. Ima smisla isprobati 2 ili 3 sloja LSTM ćelija. Kao što smo spomenuli u prethodnoj jedinici, svaki sloj LSTM-a izdvaja određene uzorke iz teksta, a u slučaju generatora na razini znakova možemo očekivati da će niži LSTM sloj biti odgovoran za izdvajanje slogova, a viši slojevi - za riječi i kombinacije riječi. Ovo se jednostavno može implementirati prosljeđivanjem parametra broja slojeva konstruktoru LSTM-a.\n",
"\n",
"* Također biste mogli eksperimentirati s **GRU jedinicama** i vidjeti koje bolje funkcioniraju, kao i s **različitim veličinama skrivenih slojeva**. Prevelik skriveni sloj može rezultirati prekomjernim učenjem (npr. mreža će naučiti točan tekst), dok manja veličina možda neće dati dobar rezultat.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Generiranje mekog teksta i temperatura\n",
"\n",
"U prethodnoj definiciji funkcije `generate`, uvijek smo birali znak s najvećom vjerojatnošću kao sljedeći znak u generiranom tekstu. To je često rezultiralo time da se tekst \"vrtio\" između istih sekvenci znakova iznova i iznova, kao u ovom primjeru:\n",
"```\n",
"today of the second the company and a second the company ...\n",
"```\n",
"\n",
"Međutim, ako pogledamo raspodjelu vjerojatnosti za sljedeći znak, može se dogoditi da razlika između nekoliko najvećih vjerojatnosti nije velika, npr. jedan znak može imati vjerojatnost 0.2, dok drugi ima 0.19, itd. Na primjer, kada tražimo sljedeći znak u sekvenci '*play*', sljedeći znak može jednako dobro biti razmak ili **e** (kao u riječi *player*).\n",
"\n",
"To nas dovodi do zaključka da nije uvijek \"pravedno\" odabrati znak s većom vjerojatnošću, jer odabir drugog po redu također može dovesti do smislenog teksta. Mudrije je **uzorkovati** znakove iz raspodjele vjerojatnosti koju daje izlaz mreže.\n",
"\n",
"Ovo uzorkovanje može se provesti pomoću funkcije `np.multinomial`, koja implementira tzv. **multinomialnu raspodjelu**. Funkcija koja implementira ovo **meko** generiranje teksta definirana je u nastavku:\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": [
"Uveli smo još jedan parametar nazvan **temperature** koji se koristi za označavanje koliko strogo trebamo slijediti najveću vjerojatnost. Ako je temperatura 1.0, provodimo pošteno multinomijalno uzorkovanje, a kada temperatura ide prema beskonačnosti - sve vjerojatnosti postaju jednake i nasumično biramo sljedeći znak. U primjeru ispod možemo primijetiti da tekst postaje besmislen kada previše povećamo temperaturu, a nalikuje \"cikliranom\" strogo generiranom tekstu kada se približi 0.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Odricanje od odgovornosti**: \nOvaj dokument je preveden korištenjem AI usluge za prevođenje [Co-op Translator](https://github.com/Azure/co-op-translator). Iako nastojimo osigurati točnost, imajte na umu da automatski prijevodi mogu sadržavati pogreške ili netočnosti. Izvorni dokument na izvornom jeziku treba smatrati mjerodavnim izvorom. Za ključne informacije preporučuje se profesionalni prijevod od strane stručnjaka. Ne preuzimamo odgovornost za bilo kakva nesporazuma ili pogrešna tumačenja koja mogu proizaći iz korištenja ovog prijevoda.\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-30T07:58:46+00:00",
"source_file": "lessons/5-NLP/17-GenerativeNetworks/GenerativeTF.ipynb",
"language_code": "hr"
}
},
"nbformat": 4,
"nbformat_minor": 4
}