494 lines
34 KiB
Plaintext
494 lines
34 KiB
Plaintext
{
|
||
"cells": [
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"# Генеративне мреже\n",
|
||
"\n",
|
||
"Рекурентне неуронске мреже (RNNs) и њихове варијанте са контролисаним ћелијама, као што су Long Short Term Memory ћелије (LSTMs) и Gated Recurrent Units (GRUs), пружају механизам за моделирање језика, односно могу да науче редослед речи и дају предвиђања за следећу реч у низу. Ово нам омогућава да користимо RNNs за **генеративне задатке**, као што су обично генерисање текста, машински превод, па чак и генерисање описа слика.\n",
|
||
"\n",
|
||
"У RNN архитектури коју смо разматрали у претходној јединици, свака RNN јединица је производила следеће скривено стање као излаз. Међутим, можемо додати још један излаз свакој рекурентној јединици, што би нам омогућило да добијемо **низ** (који је једнак по дужини оригиналном низу). Штавише, можемо користити RNN јединице које не прихватају улаз на сваком кораку, већ само узимају неки почетни вектор стања и затим производе низ излаза.\n",
|
||
"\n",
|
||
"У овом нотебуку, фокусираћемо се на једноставне генеративне моделе који нам помажу да генеришемо текст. Ради једноставности, направимо **мрежу на нивоу карактера**, која генерише текст слово по слово. Током тренинга, потребно је узети неки корпус текста и поделити га на низове слова.\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": [
|
||
"## Изградња речника карактера\n",
|
||
"\n",
|
||
"Да бисмо изградили генеративну мрежу на нивоу карактера, потребно је да текст поделимо на појединачне карактере уместо на речи. `TextVectorization` слој који смо раније користили не може то да уради, па имамо две опције:\n",
|
||
"\n",
|
||
"* Ручно учитавање текста и ручна токенизација, као у [овом званичном примеру из Keras-а](https://keras.io/examples/generative/lstm_character_level_text_generation/)\n",
|
||
"* Коришћење `Tokenizer` класе за токенизацију на нивоу карактера.\n",
|
||
"\n",
|
||
"Одлучићемо се за другу опцију. `Tokenizer` се такође може користити за токенизацију на нивоу речи, па би требало да буде лако прећи са токенизације на нивоу карактера на токенизацију на нивоу речи.\n",
|
||
"\n",
|
||
"Да бисмо извршили токенизацију на нивоу карактера, потребно је да проследимо параметар `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": [
|
||
"Такође желимо да користимо један посебан токен за означавање **краја секвенце**, који ћемо назвати `<eos>`. Хајде да га ручно додамо у вокабулар:\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": [
|
||
"Сада, да бисмо кодирали текст у низове бројева, можемо користити:\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": [
|
||
"## Тренирање генеративне RNN за генерисање наслова\n",
|
||
"\n",
|
||
"Начин на који ћемо тренирати RNN да генерише наслове вести је следећи. У сваком кораку, узимамо један наслов, који ће бити унет у RNN, и за сваки улазни карактер тражимо од мреже да генерише следећи излазни карактер:\n",
|
||
"\n",
|
||
"\n",
|
||
"\n",
|
||
"За последњи карактер у нашој секвенци, тражићемо од мреже да генерише `<eos>` токен.\n",
|
||
"\n",
|
||
"Главна разлика између генеративне RNN коју овде користимо је у томе што ћемо узимати излаз из сваког корака RNN-а, а не само из последње ћелије. Ово се може постићи постављањем параметра `return_sequences` за RNN ћелију.\n",
|
||
"\n",
|
||
"Дакле, током тренирања, улаз у мрежу биће секвенца кодираних карактера одређене дужине, а излаз ће бити секвенца исте дужине, али померена за један елемент и завршена са `<eos>`. Минибатч ће се састојати од неколико таквих секвенци, и биће потребно користити **попуњавање** (padding) да би се све секвенце ускладиле.\n",
|
||
"\n",
|
||
"Хајде да направимо функције које ће трансформисати скуп података за нас. Пошто желимо да попуњавамо секвенце на нивоу минибатча, прво ћемо груписати скуп података позивом `.batch()`, а затим га `map`-овати како бисмо извршили трансформацију. Дакле, функција за трансформацију ће узимати читав минибатч као параметар:\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",
|
||
"* Прво извлачимо стварни текст из стринг тензора\n",
|
||
"* `text_to_sequences` претвара листу стрингова у листу целобројних тензора\n",
|
||
"* `pad_sequences` допуњава те тензоре до њихове максималне дужине\n",
|
||
"* На крају вршимо one-hot енкодирање свих карактера, као и померање и додавање `<eos>`. Ускоро ћемо видети зашто су нам потребни one-hot енкодирани карактери\n",
|
||
"\n",
|
||
"Међутим, ова функција је **Pythonic**, тј. не може се аутоматски превести у Tensorflow рачунски граф. Добићемо грешке ако покушамо да користимо ову функцију директно у `Dataset.map` функцији. Потребно је да ову Pythonic функцију обухватимо коришћењем `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**: Разликовање између Pythonic и Tensorflow функција трансформације може изгледати превише сложено, и можда се питате зашто не трансформишемо скуп података користећи стандардне Python функције пре него што га проследимо функцији `fit`. Иако је то дефинитивно могуће, коришћење `Dataset.map` има огромну предност, јер се процес трансформације података извршава користећи Tensorflow рачунски граф, који користи предности GPU обраде и минимизује потребу за преносом података између CPU/GPU.\n",
|
||
"\n",
|
||
"Сада можемо изградити нашу генераторску мрежу и започети тренинг. Она може бити заснована на било којој рекурентној ћелији коју смо разматрали у претходној јединици (једноставна, LSTM или GRU). У нашем примеру користићемо LSTM.\n",
|
||
"\n",
|
||
"Пошто мрежа узима карактере као улаз, а величина вокабулара је прилично мала, не треба нам слој за уграђивање (embedding layer); улаз кодирани у one-hot формату може директно ући у LSTM ћелију. Излазни слој биће `Dense` класификатор који ће претворити излаз LSTM-а у бројеве токена кодиране у one-hot формату.\n",
|
||
"\n",
|
||
"Поред тога, пошто радимо са секвенцама променљиве дужине, можемо користити слој `Masking` да креирамо маску која ће игнорисати попуњени (padded) део низа. Ово није строго неопходно, јер нас не занима превише све што иде изван `<eos>` токена, али ћемо га користити ради стицања искуства са овим типом слоја. `input_shape` биће `(None, vocab_size)`, где `None` означава секвенцу променљиве дужине, а излазни облик је такође `(None, vocab_size)`, као што можете видети из `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": [
|
||
"## Генерисање резултата\n",
|
||
"\n",
|
||
"Сада када смо обучили модел, желимо да га користимо за генерисање резултата. Пре свега, потребан нам је начин за декодирање текста представљеног низом бројева токена. За то бисмо могли да користимо функцију `tokenizer.sequences_to_texts`; међутим, она не ради добро са токенизацијом на нивоу карактера. Због тога ћемо узети речник токена из токенизатора (назван `word_index`), направити обрнуту мапу и написати сопствену функцију за декодирање:\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": [
|
||
"Сада, хајде да започнемо са генерисањем. Почећемо са неким низом `start`, кодирати га у секвенцу `inp`, а затим ћемо на сваком кораку позвати нашу мрежу да предвиди следећи карактер.\n",
|
||
"\n",
|
||
"Излаз мреже `out` је вектор са `vocab_size` елемената који представљају вероватноће за сваки токен, а највероватнији број токена можемо пронаћи коришћењем `argmax`. Затим додајемо овај карактер у генерисану листу токена и настављамо са генерисањем. Овај процес генерисања једног карактера понавља се `size` пута како бисмо генерисали потребан број карактера, а прекидамо раније ако се појави `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": [
|
||
"## Узимање узорка резултата током обуке\n",
|
||
"\n",
|
||
"Пошто немамо корисне метрике као што је *тачност*, једини начин да видимо да ли наш модел постаје бољи је **узимање узорка** генерисаног низа током обуке. Да бисмо то урадили, користићемо **повратне позиве**, односно функције које можемо проследити функцији `fit`, а које ће бити позиване периодично током обуке.\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": [
|
||
"Овај пример већ генерише прилично добар текст, али може се додатно побољшати на неколико начина:\n",
|
||
"* **Више текста**. Користили смо само наслове за наш задатак, али можда желите да експериментишете са пуним текстом. Запамтите да RNN-ови нису баш добри у обради дугих секвенци, па има смисла или их поделити на краће реченице, или увек тренирати на фиксној дужини секвенце од неке унапред дефинисане вредности `num_chars` (рецимо, 256). Можете покушати да промените горњи пример у такву архитектуру, користећи [званични Керас туторијал](https://keras.io/examples/generative/lstm_character_level_text_generation/) као инспирацију.\n",
|
||
"* **Вишеслојни LSTM**. Има смисла пробати 2 или 3 слоја LSTM ћелија. Као што смо поменули у претходној јединици, сваки слој LSTM-а извлачи одређене обрасце из текста, а у случају генератора на нивоу карактера можемо очекивати да ће нижи LSTM слој бити одговоран за извлачење слогова, а виши слојеви - за речи и комбинације речи. Ово се може једноставно имплементирати прослеђивањем параметра броја слојева конструктору LSTM-а.\n",
|
||
"* Можда ћете желети да експериментишете и са **GRU јединицама** и видите које боље функционишу, као и са **различитим величинама скривених слојева**. Превелики скривени слој може довести до пренатренираности (нпр. мрежа ће научити тачан текст), а мања величина можда неће дати добар резултат.\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Генерисање меког текста и температура\n",
|
||
"\n",
|
||
"У претходној дефиницији функције `generate`, увек смо узимали карактер са највећом вероватноћом као следећи карактер у генерисаном тексту. Ово је често доводило до тога да се текст \"врти\" између истих секвенци карактера изнова и изнова, као у овом примеру:\n",
|
||
"```\n",
|
||
"today of the second the company and a second the company ...\n",
|
||
"```\n",
|
||
"\n",
|
||
"Међутим, ако погледамо расподелу вероватноћа за следећи карактер, може се десити да разлика између неколико највећих вероватноћа није велика, на пример, један карактер може имати вероватноћу 0.2, а други 0.19, итд. На пример, када тражимо следећи карактер у секвенци '*play*', следећи карактер може једнако добро бити размак или **е** (као у речи *player*).\n",
|
||
"\n",
|
||
"Ово нас доводи до закључка да није увек \"праведно\" изабрати карактер са највећом вероватноћом, јер избор другог највећег може и даље довести до смисленог текста. Паметније је **узорковати** карактере из расподеле вероватноћа коју даје излаз мреже.\n",
|
||
"\n",
|
||
"Ово узорковање може се обавити помоћу функције `np.multinomial`, која имплементира такозвану **мултиномијалну расподелу**. Функција која имплементира ово **меко** генерисање текста дефинисана је испод:\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": [
|
||
"Увели смо још један параметар који се зове **температура**, који се користи да означи колико строго треба да се држимо највеће вероватноће. Ако је температура 1.0, радимо правично мултиномијално узорковање, а када температура иде ка бесконачности - све вероватноће постају једнаке, и насумично бирамо следећи карактер. У примеру испод можемо приметити да текст постаје бесмислен када превише повећамо температуру, и подсећа на \"циклично\" тешко генерисан текст када се приближи 0.\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"\n---\n\n**Одрицање од одговорности**: \nОвај документ је преведен коришћењем услуге за превођење помоћу вештачке интелигенције [Co-op Translator](https://github.com/Azure/co-op-translator). Иако се трудимо да превод буде тачан, молимо вас да имате у виду да аутоматски преводи могу садржати грешке или нетачности. Оригинални документ на његовом изворном језику треба сматрати ауторитативним извором. За критичне информације препоручује се професионални превод од стране људи. Не преузимамо одговорност за било каква погрешна тумачења или неспоразуме који могу настати услед коришћења овог превода.\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:36:14+00:00",
|
||
"source_file": "lessons/5-NLP/17-GenerativeNetworks/GenerativeTF.ipynb",
|
||
"language_code": "sr"
|
||
}
|
||
},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 4
|
||
} |