494 lines
27 KiB
Plaintext
494 lines
27 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Generativní sítě\n",
|
|
"\n",
|
|
"Rekurentní neuronové sítě (RNNs) a jejich varianty s bráněnými buňkami, jako jsou buňky Long Short Term Memory (LSTMs) a Gated Recurrent Units (GRUs), poskytují mechanismus pro modelování jazyka, tj. dokážou se naučit pořadí slov a poskytovat předpovědi pro další slovo v sekvenci. To nám umožňuje používat RNNs pro **generativní úlohy**, jako je běžná generace textu, strojový překlad nebo dokonce popisování obrázků.\n",
|
|
"\n",
|
|
"V architektuře RNN, kterou jsme probírali v předchozí kapitole, každá jednotka RNN produkovala jako výstup další skrytý stav. Můžeme však také přidat další výstup ke každé rekurentní jednotce, což nám umožní generovat **sekvenci** (která má stejnou délku jako původní sekvence). Navíc můžeme použít jednotky RNN, které nepřijímají vstup na každém kroku, ale pouze berou nějaký počáteční stavový vektor a poté generují sekvenci výstupů.\n",
|
|
"\n",
|
|
"V tomto notebooku se zaměříme na jednoduché generativní modely, které nám pomáhají generovat text. Pro zjednodušení vytvoříme **síť na úrovni znaků**, která generuje text písmeno po písmenu. Během trénování potřebujeme vzít nějaký textový korpus a rozdělit jej na sekvence znaků.\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": [
|
|
"## Vytváření slovníku znaků\n",
|
|
"\n",
|
|
"Pro vytvoření generativní sítě na úrovni znaků je potřeba rozdělit text na jednotlivé znaky místo slov. Vrstva `TextVectorization`, kterou jsme používali dříve, to neumí, takže máme dvě možnosti:\n",
|
|
"\n",
|
|
"* Ručně načíst text a provést tokenizaci \"ručně\", jak je uvedeno v [tomto oficiálním příkladu Keras](https://keras.io/examples/generative/lstm_character_level_text_generation/)\n",
|
|
"* Použít třídu `Tokenizer` pro tokenizaci na úrovni znaků.\n",
|
|
"\n",
|
|
"Zvolíme druhou možnost. `Tokenizer` lze také použít k tokenizaci na úrovni slov, takže by mělo být snadné přepnout z tokenizace na úrovni znaků na tokenizaci na úrovni slov.\n",
|
|
"\n",
|
|
"Pro tokenizaci na úrovni znaků je potřeba předat parametr `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": [
|
|
"Chceme také použít jeden speciální token k označení **konce sekvence**, který nazveme `<eos>`. Přidejme ho ručně do slovníku:\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": [
|
|
"Nyní, abychom zakódovali text do sekvencí čísel, můžeme použít:\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énování generativní RNN pro vytváření nadpisů\n",
|
|
"\n",
|
|
"Způsob, jakým budeme trénovat RNN na generování nadpisů zpráv, je následující. V každém kroku vezmeme jeden nadpis, který bude předán do RNN, a pro každý vstupní znak požádáme síť, aby vygenerovala následující výstupní znak:\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"Pro poslední znak naší sekvence požádáme síť, aby vygenerovala token `<eos>`.\n",
|
|
"\n",
|
|
"Hlavní rozdíl mezi generativní RNN, kterou zde používáme, je ten, že budeme brát výstup z každého kroku RNN, a nejen z poslední buňky. Toho lze dosáhnout nastavením parametru `return_sequences` u buňky RNN.\n",
|
|
"\n",
|
|
"Během trénování tedy bude vstupem do sítě sekvence zakódovaných znaků určité délky a výstupem bude sekvence stejné délky, ale posunutá o jeden prvek a ukončená tokenem `<eos>`. Minibatch bude obsahovat několik takových sekvencí, a bude nutné použít **padding**, aby se všechny sekvence zarovnaly.\n",
|
|
"\n",
|
|
"Vytvořme funkce, které pro nás dataset transformují. Protože chceme sekvence zarovnávat na úrovni minibatch, nejprve dataset seskupíme pomocí `.batch()`, a poté použijeme `map` k provedení transformace. Transformační funkce tedy bude přijímat celý minibatch jako parametr:\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ěkolik důležitých věcí, které zde děláme:\n",
|
|
"* Nejprve extrahujeme skutečný text z tensoru řetězců\n",
|
|
"* `text_to_sequences` převádí seznam řetězců na seznam tensorů s celými čísly\n",
|
|
"* `pad_sequences` doplňuje tyto tensory na jejich maximální délku\n",
|
|
"* Nakonec provedeme one-hot kódování všech znaků, a také posun a přidání `<eos>`. Brzy uvidíme, proč potřebujeme znaky kódované pomocí one-hot.\n",
|
|
"\n",
|
|
"Nicméně, tato funkce je **Pythonická**, tj. nemůže být automaticky přeložena do výpočetního grafu Tensorflow. Pokud se pokusíme použít tuto funkci přímo ve funkci `Dataset.map`, dostaneme chyby. Musíme tento Pythonický volání uzavřít pomocí obálky `py_function`:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 6,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def title_batch_fn(x):\n",
|
|
" x = x['title']\n",
|
|
" a,b = tf.py_function(title_batch,inp=[x],Tout=(tf.float32,tf.float32))\n",
|
|
" return a,b"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"> **Note**: Rozlišování mezi Pythonovými a Tensorflow transformačními funkcemi může působit příliš složitě a možná se ptáte, proč dataset nepřetransformujeme pomocí standardních Python funkcí před jeho předáním do `fit`. I když to určitě lze udělat, použití `Dataset.map` má obrovskou výhodu, protože datová transformační pipeline je vykonávána pomocí Tensorflow výpočetního grafu, který využívá výpočty na GPU a minimalizuje potřebu přenosu dat mezi CPU/GPU.\n",
|
|
"\n",
|
|
"Nyní můžeme vytvořit naši generátorovou síť a začít s trénováním. Může být založena na jakékoliv rekurentní buňce, kterou jsme probírali v předchozí jednotce (jednoduchá, LSTM nebo GRU). V našem příkladu použijeme LSTM.\n",
|
|
"\n",
|
|
"Protože síť přijímá znaky jako vstup a velikost slovníku je poměrně malá, nepotřebujeme vrstvu pro vkládání (embedding layer), jednorázově zakódovaný vstup může přímo vstoupit do LSTM buňky. Výstupní vrstva bude `Dense` klasifikátor, který převede výstup LSTM na jednorázově zakódovaná čísla tokenů.\n",
|
|
"\n",
|
|
"Navíc, protože pracujeme s sekvencemi proměnné délky, můžeme použít vrstvu `Masking`, která vytvoří masku ignorující vyplněné části řetězce. To není striktně nutné, protože nás příliš nezajímá vše, co přesahuje token `<eos>`, ale použijeme ji kvůli získání zkušeností s tímto typem vrstvy. `input_shape` bude `(None, vocab_size)`, kde `None` označuje sekvenci proměnné délky, a výstupní tvar je také `(None, vocab_size)`, jak můžete vidět z `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": [
|
|
"## Generování výstupu\n",
|
|
"\n",
|
|
"Nyní, když jsme model natrénovali, chceme jej použít k vytvoření nějakého výstupu. Nejprve potřebujeme způsob, jak dekódovat text reprezentovaný sekvencí čísel tokenů. K tomu bychom mohli použít funkci `tokenizer.sequences_to_texts`; nicméně tato funkce nefunguje dobře s tokenizací na úrovni znaků. Proto vezmeme slovník tokenů z tokenizeru (nazvaný `word_index`), vytvoříme reverzní mapu a napíšeme vlastní dekódovací funkci:\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": [
|
|
"Nyní začneme s generováním. Začneme s nějakým řetězcem `start`, zakódujeme jej do sekvence `inp`, a poté při každém kroku zavoláme naši síť, aby určila další znak.\n",
|
|
"\n",
|
|
"Výstup sítě `out` je vektor o `vocab_size` prvcích, který reprezentuje pravděpodobnosti jednotlivých tokenů. Nejpravděpodobnější číslo tokenu můžeme najít pomocí `argmax`. Tento znak pak připojíme k seznamu vygenerovaných tokenů a pokračujeme v generování. Tento proces generování jednoho znaku opakujeme `size` krát, abychom vygenerovali požadovaný počet znaků, a ukončíme jej předčasně, pokud narazíme 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": [
|
|
"## Ukázka výstupu během trénování\n",
|
|
"\n",
|
|
"Protože nemáme žádné užitečné metriky, jako je *přesnost*, jediný způsob, jak můžeme zjistit, že se náš model zlepšuje, je **ukázka** generovaného řetězce během trénování. K tomu použijeme **callbacky**, tj. funkce, které můžeme předat funkci `fit` a které budou pravidelně volány během trénování.\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": [
|
|
"Tento příklad již generuje poměrně dobrý text, ale lze jej dále vylepšit několika způsoby:\n",
|
|
"* **Více textu**. Použili jsme pouze nadpisy pro náš úkol, ale můžete experimentovat s plným textem. Pamatujte, že RNN nejsou příliš dobré při práci s dlouhými sekvencemi, takže má smysl buď je rozdělit na kratší věty, nebo vždy trénovat na pevné délce sekvence s nějakou předem definovanou hodnotou `num_chars` (například 256). Můžete zkusit upravit výše uvedený příklad na takovou architekturu, přičemž se inspirujete [oficiálním tutoriálem Keras](https://keras.io/examples/generative/lstm_character_level_text_generation/).\n",
|
|
"* **Vícevrstvé LSTM**. Má smysl vyzkoušet 2 nebo 3 vrstvy LSTM buněk. Jak jsme zmínili v předchozí části, každá vrstva LSTM extrahuje určité vzory z textu, a v případě generátoru na úrovni znaků můžeme očekávat, že nižší úroveň LSTM bude zodpovědná za extrakci slabik, zatímco vyšší úrovně - za slova a kombinace slov. To lze jednoduše implementovat předáním parametru počtu vrstev konstruktoru LSTM.\n",
|
|
"* Můžete také experimentovat s **GRU jednotkami** a zjistit, které fungují lépe, a s **různými velikostmi skrytých vrstev**. Příliš velká skrytá vrstva může vést k přeučení (např. síť se naučí přesný text), zatímco menší velikost nemusí produkovat dobré výsledky.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Generování měkkého textu a teplota\n",
|
|
"\n",
|
|
"V předchozí definici `generate` jsme vždy vybírali znak s nejvyšší pravděpodobností jako další znak v generovaném textu. To vedlo k tomu, že se text často \"cyklil\" mezi stejnými sekvencemi znaků znovu a znovu, jako v tomto příkladu:\n",
|
|
"```\n",
|
|
"today of the second the company and a second the company ...\n",
|
|
"```\n",
|
|
"\n",
|
|
"Pokud se však podíváme na rozložení pravděpodobností pro další znak, může se stát, že rozdíl mezi několika nejvyššími pravděpodobnostmi není velký, např. jeden znak může mít pravděpodobnost 0,2, jiný 0,19 atd. Například při hledání dalšího znaku v sekvenci '*play*' může být další znak stejně dobře mezera nebo **e** (jako ve slově *player*).\n",
|
|
"\n",
|
|
"To nás vede k závěru, že není vždy \"spravedlivé\" vybírat znak s vyšší pravděpodobností, protože výběr druhého nejvyššího může stále vést k smysluplnému textu. Je rozumnější **vzorkovat** znaky z rozložení pravděpodobností, které poskytuje výstup sítě.\n",
|
|
"\n",
|
|
"Toto vzorkování lze provést pomocí funkce `np.multinomial`, která implementuje tzv. **multinomické rozložení**. Funkce, která implementuje toto **měkké** generování textu, je definována níže:\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 <b>...</b>\n",
|
|
"Little red riding hood ficed to the spam countered in European <b>...</b>\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 <b>...</b>\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": [
|
|
"Zavedli jsme další parametr nazvaný **teplota**, který slouží k určení, jak striktně bychom se měli držet nejvyšší pravděpodobnosti. Pokud je teplota 1.0, provádíme spravedlivé multinomiální vzorkování, a když teplota dosáhne nekonečna - všechny pravděpodobnosti se stanou rovnými a náhodně vybíráme další znak. Na níže uvedeném příkladu můžeme pozorovat, že text se stává nesmyslným, když příliš zvýšíme teplotu, a připomíná „cyklický“ tvrdě generovaný text, když se blíží k 0.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"\n---\n\n**Prohlášení**: \nTento dokument byl přeložen pomocí služby pro automatický překlad [Co-op Translator](https://github.com/Azure/co-op-translator). I když se snažíme o přesnost, mějte prosím na paměti, že automatické překlady mohou obsahovat chyby nebo nepřesnosti. Původní dokument v jeho původním jazyce by měl být považován za autoritativní zdroj. Pro důležité informace doporučujeme profesionální lidský překlad. Neodpovídáme za žádná nedorozumění nebo nesprávné interpretace vyplývající z použití tohoto překladu.\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-29T15:43:30+00:00",
|
|
"source_file": "lessons/5-NLP/17-GenerativeNetworks/GenerativeTF.ipynb",
|
|
"language_code": "cs"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 4
|
|
} |