495 lines
28 KiB
Plaintext
495 lines
28 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Rețele generative\n",
|
|
"\n",
|
|
"Rețelele Neuronale Recurente (RNN) și variantele lor cu celule cu porți, cum ar fi Celulele cu Memorie pe Termen Lung (LSTM) și Unitățile Recurente cu Porți (GRU), au oferit un mecanism pentru modelarea limbajului, adică pot învăța ordonarea cuvintelor și pot oferi predicții pentru următorul cuvânt dintr-o secvență. Acest lucru ne permite să folosim RNN-urile pentru **sarcini generative**, cum ar fi generarea obișnuită de text, traducerea automată și chiar generarea de descrieri pentru imagini.\n",
|
|
"\n",
|
|
"În arhitectura RNN discutată în unitatea anterioară, fiecare unitate RNN producea următoarea stare ascunsă ca ieșire. Totuși, putem adăuga și o altă ieșire fiecărei unități recurente, ceea ce ne-ar permite să generăm o **secvență** (care este egală ca lungime cu secvența originală). Mai mult, putem folosi unități RNN care nu acceptă o intrare la fiecare pas, ci doar primesc un vector de stare inițială și apoi produc o secvență de ieșiri.\n",
|
|
"\n",
|
|
"În acest notebook, ne vom concentra pe modele generative simple care ne ajută să generăm text. Pentru simplitate, să construim o **rețea la nivel de caractere**, care generează text literă cu literă. În timpul antrenării, trebuie să luăm un corpus de text și să-l împărțim în secvențe de litere.\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": [
|
|
"## Construirea vocabularului de caractere\n",
|
|
"\n",
|
|
"Pentru a construi o rețea generativă la nivel de caractere, trebuie să împărțim textul în caractere individuale, în loc de cuvinte. Stratul `TextVectorization` pe care l-am folosit anterior nu poate face acest lucru, așa că avem două opțiuni:\n",
|
|
"\n",
|
|
"* Încărcarea manuală a textului și realizarea tokenizării „manual”, așa cum se arată în [acest exemplu oficial Keras](https://keras.io/examples/generative/lstm_character_level_text_generation/)\n",
|
|
"* Utilizarea clasei `Tokenizer` pentru tokenizarea la nivel de caractere.\n",
|
|
"\n",
|
|
"Vom alege a doua opțiune. `Tokenizer` poate fi folosit și pentru tokenizarea în cuvinte, astfel încât să fie ușor de trecut de la tokenizarea la nivel de caractere la cea la nivel de cuvinte.\n",
|
|
"\n",
|
|
"Pentru a realiza tokenizarea la nivel de caractere, trebuie să transmitem parametrul `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": [
|
|
"Vrem să folosim și un token special pentru a indica **sfârșitul secvenței**, pe care îl vom numi `<eos>`. Să-l adăugăm manual la vocabular:\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": [
|
|
"## Antrenarea unui RNN generativ pentru a genera titluri\n",
|
|
"\n",
|
|
"Modul în care vom antrena RNN pentru a genera titluri de știri este următorul. La fiecare pas, vom lua un titlu, care va fi introdus într-un RNN, iar pentru fiecare caracter de intrare vom cere rețelei să genereze următorul caracter de ieșire:\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"Pentru ultimul caracter al secvenței noastre, vom cere rețelei să genereze token-ul `<eos>`.\n",
|
|
"\n",
|
|
"Principala diferență între RNN-ul generativ pe care îl folosim aici este că vom lua o ieșire de la fiecare pas al RNN-ului, și nu doar de la celula finală. Acest lucru poate fi realizat prin specificarea parametrului `return_sequences` pentru celula RNN.\n",
|
|
"\n",
|
|
"Astfel, în timpul antrenamentului, o intrare în rețea ar fi o secvență de caractere codificate de o anumită lungime, iar o ieșire ar fi o secvență de aceeași lungime, dar deplasată cu un element și terminată cu `<eos>`. Un minibatch va consta din mai multe astfel de secvențe, iar noi va trebui să folosim **padding** pentru a alinia toate secvențele.\n",
|
|
"\n",
|
|
"Să creăm funcții care vor transforma setul de date pentru noi. Deoarece dorim să completăm secvențele la nivel de minibatch, mai întâi vom grupa setul de date apelând `.batch()`, iar apoi îl vom `map`-a pentru a face transformarea. Așadar, funcția de transformare va lua un întreg minibatch ca parametru:\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": [
|
|
"Câteva lucruri importante pe care le facem aici:\n",
|
|
"* Mai întâi extragem textul efectiv din tensorul de tip string\n",
|
|
"* `text_to_sequences` convertește lista de șiruri de caractere într-o listă de tensori de tip întreg\n",
|
|
"* `pad_sequences` completează acești tensori la lungimea lor maximă\n",
|
|
"* În final, codificăm one-hot toți caracterii, realizăm și deplasarea, precum și adăugarea `<eos>`. Vom vedea în curând de ce avem nevoie de caractere codificate one-hot.\n",
|
|
"\n",
|
|
"Totuși, această funcție este **Pythonică**, adică nu poate fi tradusă automat într-un grafic computațional Tensorflow. Vom primi erori dacă încercăm să folosim această funcție direct în funcția `Dataset.map`. Trebuie să închidem acest apel Pythonic utilizând wrapper-ul `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**: Diferențierea între funcțiile de transformare Pythonic și cele Tensorflow poate părea puțin prea complicată, și poate te întrebi de ce nu transformăm setul de date folosind funcții standard Python înainte de a-l transmite către `fit`. Deși acest lucru se poate face cu siguranță, utilizarea `Dataset.map` are un mare avantaj, deoarece pipeline-ul de transformare a datelor este executat folosind graful computațional Tensorflow, care profită de calculele GPU și minimizează necesitatea de a transfera date între CPU/GPU.\n",
|
|
"\n",
|
|
"Acum putem construi rețeaua noastră generator și începe antrenarea. Aceasta poate fi bazată pe orice celulă recurentă pe care am discutat-o în unitatea anterioară (simplă, LSTM sau GRU). În exemplul nostru vom folosi LSTM.\n",
|
|
"\n",
|
|
"Deoarece rețeaua primește caractere ca input, iar dimensiunea vocabularului este destul de mică, nu avem nevoie de un strat de embedding; input-ul codificat one-hot poate fi transmis direct în celula LSTM. Stratul de ieșire va fi un clasificator `Dense` care va converti ieșirea LSTM în numere de token-uri codificate one-hot.\n",
|
|
"\n",
|
|
"În plus, deoarece lucrăm cu secvențe de lungime variabilă, putem folosi stratul `Masking` pentru a crea o mască care va ignora partea umplută a șirului. Acest lucru nu este strict necesar, deoarece nu suntem foarte interesați de tot ceea ce depășește token-ul `<eos>`, dar îl vom folosi pentru a câștiga ceva experiență cu acest tip de strat. `input_shape` va fi `(None, vocab_size)`, unde `None` indică secvența de lungime variabilă, iar forma de ieșire este `(None, vocab_size)` de asemenea, așa cum poți vedea din `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": [
|
|
"## Generarea rezultatului\n",
|
|
"\n",
|
|
"Acum că am antrenat modelul, vrem să-l folosim pentru a genera un rezultat. În primul rând, avem nevoie de o modalitate de a decoda textul reprezentat de o secvență de numere de tokeni. Pentru aceasta, am putea folosi funcția `tokenizer.sequences_to_texts`; totuși, aceasta nu funcționează bine cu tokenizarea la nivel de caracter. Prin urmare, vom lua un dicționar de tokeni din tokenizer (numit `word_index`), vom construi o hartă inversă și vom scrie propria noastră funcție de decodare:\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": [
|
|
"Acum, să începem generarea. Vom începe cu un șir `start`, îl vom codifica într-o secvență `inp`, iar apoi, la fiecare pas, vom apela rețeaua noastră pentru a deduce următorul caracter.\n",
|
|
"\n",
|
|
"Rezultatul rețelei `out` este un vector cu `vocab_size` elemente care reprezintă probabilitățile fiecărui token, iar noi putem găsi numărul tokenului cel mai probabil folosind `argmax`. Apoi, adăugăm acest caracter la lista generată de tokeni și continuăm procesul de generare. Acest proces de generare a unui caracter se repetă de `size` ori pentru a genera numărul necesar de caractere, și ne oprim mai devreme dacă întâlnim `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": [
|
|
"## Eșantionarea rezultatelor în timpul antrenamentului\n",
|
|
"\n",
|
|
"Deoarece nu avem metrici utile precum *acuratețea*, singura modalitate prin care putem observa că modelul nostru se îmbunătățește este prin **eșantionarea** șirurilor generate în timpul antrenamentului. Pentru a face acest lucru, vom folosi **callback-uri**, adică funcții pe care le putem transmite funcției `fit` și care vor fi apelate periodic în timpul antrenamentului.\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": [
|
|
"Acest exemplu generează deja un text destul de bun, dar poate fi îmbunătățit în mai multe moduri:\n",
|
|
"\n",
|
|
"* **Mai mult text**. Am folosit doar titluri pentru sarcina noastră, dar poate doriți să experimentați cu text complet. Rețineți că RNN-urile nu sunt foarte bune la gestionarea secvențelor lungi, așa că are sens fie să le împărțiți în propoziții mai scurte, fie să antrenați întotdeauna pe o lungime fixă de secvență cu o valoare predefinită `num_chars` (de exemplu, 256). Puteți încerca să modificați exemplul de mai sus într-o astfel de arhitectură, folosind [tutorialul oficial Keras](https://keras.io/examples/generative/lstm_character_level_text_generation/) ca inspirație.\n",
|
|
"\n",
|
|
"* **LSTM cu mai multe straturi**. Este logic să încercați 2 sau 3 straturi de celule LSTM. Așa cum am menționat în unitatea anterioară, fiecare strat de LSTM extrage anumite modele din text, iar în cazul generatorului la nivel de caractere, ne putem aștepta ca nivelul inferior al LSTM să fie responsabil pentru extragerea silabelor, iar nivelurile superioare - pentru cuvinte și combinații de cuvinte. Acest lucru poate fi implementat simplu prin transmiterea unui parametru pentru numărul de straturi către constructorul LSTM.\n",
|
|
"\n",
|
|
"* De asemenea, puteți experimenta cu **unități GRU** și să vedeți care performează mai bine, precum și cu **dimensiuni diferite ale straturilor ascunse**. O dimensiune prea mare a stratului ascuns poate duce la supraînvățare (de exemplu, rețeaua va învăța textul exact), iar o dimensiune mai mică s-ar putea să nu producă rezultate bune.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Generarea textului soft și temperatura\n",
|
|
"\n",
|
|
"În definiția anterioară a funcției `generate`, alegeam întotdeauna caracterul cu cea mai mare probabilitate ca următor caracter în textul generat. Acest lucru ducea adesea la faptul că textul \"cicla\" între aceleași secvențe de caractere, din nou și din nou, ca în acest exemplu:\n",
|
|
"```\n",
|
|
"today of the second the company and a second the company ...\n",
|
|
"```\n",
|
|
"\n",
|
|
"Totuși, dacă analizăm distribuția probabilităților pentru următorul caracter, este posibil ca diferența dintre câteva dintre cele mai mari probabilități să nu fie semnificativă, de exemplu, un caracter poate avea probabilitatea 0.2, iar altul - 0.19, etc. De exemplu, când căutăm următorul caracter în secvența '*play*', următorul caracter poate fi la fel de bine fie un spațiu, fie **e** (ca în cuvântul *player*).\n",
|
|
"\n",
|
|
"Acest lucru ne conduce la concluzia că nu este întotdeauna \"corect\" să selectăm caracterul cu probabilitatea cea mai mare, deoarece alegerea celui de-al doilea cel mai probabil caracter poate duce tot la un text semnificativ. Este mai înțelept să **eșantionăm** caracterele din distribuția de probabilitate oferită de rezultatul rețelei.\n",
|
|
"\n",
|
|
"Această eșantionare poate fi realizată folosind funcția `np.multinomial`, care implementează așa-numita **distribuție multinomială**. O funcție care implementează această generare de text **soft** este definită mai jos:\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": [
|
|
"Am introdus încă un parametru numit **temperatură**, care este utilizat pentru a indica cât de strict ar trebui să ne bazăm pe cea mai mare probabilitate. Dacă temperatura este 1.0, facem o eșantionare multinomială corectă, iar când temperatura merge spre infinit - toate probabilitățile devin egale și selectăm aleator următorul caracter. În exemplul de mai jos putem observa că textul devine lipsit de sens atunci când creștem temperatura prea mult și seamănă cu un text \"ciclic\" generat rigid atunci când se apropie de 0.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"\n---\n\n**Declinare de responsabilitate**: \nAcest document a fost tradus folosind serviciul de traducere AI [Co-op Translator](https://github.com/Azure/co-op-translator). Deși ne străduim să asigurăm acuratețea, vă rugăm să fiți conștienți că traducerile automate pot conține erori sau inexactități. Documentul original în limba sa natală ar trebui considerat sursa autoritară. Pentru informații critice, se recomandă traducerea profesională realizată de un specialist uman. Nu ne asumăm responsabilitatea pentru eventualele neînțelegeri sau interpretări greșite care pot apărea din utilizarea acestei traduceri.\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-30T00:34:26+00:00",
|
|
"source_file": "lessons/5-NLP/17-GenerativeNetworks/GenerativeTF.ipynb",
|
|
"language_code": "ro"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 4
|
|
} |