AI-For-Beginners/translations/sr/lessons/5-NLP/13-TextRep/TextRepresentationTF.ipynb

647 lines
32 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Задатак класификације текста\n",
"\n",
"У овом модулу ћемо започети са једноставним задатком класификације текста заснованим на скупу података **[AG_NEWS](http://www.di.unipi.it/~gulli/AG_corpus_of_news_articles.html)**: класификоваћемо наслове вести у једну од 4 категорије: Свет, Спорт, Бизнис и Наука/Технологија.\n",
"\n",
"## Скуп података\n",
"\n",
"За учитавање скупа података користићемо **[TensorFlow Datasets](https://www.tensorflow.org/datasets)** API.\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",
"\n",
"# In this tutorial, we will be training a lot of models. In order to use GPU memory cautiously,\n",
"# we will set tensorflow option to grow GPU memory allocation when required.\n",
"physical_devices = tf.config.list_physical_devices('GPU') \n",
"if len(physical_devices)>0:\n",
" tf.config.experimental.set_memory_growth(physical_devices[0], True)\n",
"\n",
"dataset = tfds.load('ag_news_subset')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Сада можемо приступити деловима скупа података за обуку и тестирање користећи `dataset['train']` и `dataset['test']` респективно:\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Length of train dataset = 120000\n",
"Length of test dataset = 7600\n"
]
}
],
"source": [
"ds_train = dataset['train']\n",
"ds_test = dataset['test']\n",
"\n",
"print(f\"Length of train dataset = {len(ds_train)}\")\n",
"print(f\"Length of test dataset = {len(ds_test)}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Хајде да одштампамо првих 10 нових наслова из нашег скупа података:\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3 (Sci/Tech) -> b'AMD Debuts Dual-Core Opteron Processor' b'AMD #39;s new dual-core Opteron chip is designed mainly for corporate computing applications, including databases, Web services, and financial transactions.'\n",
"1 (Sports) -> b\"Wood's Suspension Upheld (Reuters)\" b'Reuters - Major League Baseball\\\\Monday announced a decision on the appeal filed by Chicago Cubs\\\\pitcher Kerry Wood regarding a suspension stemming from an\\\\incident earlier this season.'\n",
"2 (Business) -> b'Bush reform may have blue states seeing red' b'President Bush #39;s quot;revenue-neutral quot; tax reform needs losers to balance its winners, and people claiming the federal deduction for state and local taxes may be in administration planners #39; sights, news reports say.'\n",
"3 (Sci/Tech) -> b\"'Halt science decline in schools'\" b'Britain will run out of leading scientists unless science education is improved, says Professor Colin Pillinger.'\n",
"1 (Sports) -> b'Gerrard leaves practice' b'London, England (Sports Network) - England midfielder Steven Gerrard injured his groin late in Thursday #39;s training session, but is hopeful he will be ready for Saturday #39;s World Cup qualifier against Austria.'\n"
]
}
],
"source": [
"classes = ['World', 'Sports', 'Business', 'Sci/Tech']\n",
"\n",
"for i,x in zip(range(5),ds_train):\n",
" print(f\"{x['label']} ({classes[x['label']]}) -> {x['title']} {x['description']}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Векторизација текста\n",
"\n",
"Сада треба да претворимо текст у **бројеве** који могу бити представљени као тензори. Ако желимо репрезентацију на нивоу речи, потребно је да урадимо две ствари:\n",
"\n",
"* Користимо **токенизатор** за раздвајање текста на **токене**.\n",
"* Направимо **речник** тих токена.\n",
"\n",
"### Ограничење величине речника\n",
"\n",
"У примеру са AG News скупом података, величина речника је прилично велика, више од 100 хиљада речи. Генерално гледано, не требају нам речи које се ретко појављују у тексту — само неколико реченица ће их садржати, а модел их неће научити. Због тога има смисла ограничити величину речника на мањи број тако што ћемо проследити аргумент конструктору векторизатора:\n",
"\n",
"Оба ова корака могу се обавити коришћењем слоја **TextVectorization**. Хајде да инстанцирамо објекат векторизатора, а затим позовемо метод `adapt` како бисмо прошли кроз цео текст и направили речник:\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"vocab_size = 50000\n",
"vectorizer = keras.layers.experimental.preprocessing.TextVectorization(max_tokens=vocab_size)\n",
"vectorizer.adapt(ds_train.take(500).map(lambda x: x['title']+' '+x['description']))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **Напомена** да користимо само подскуп целокупног скупа података за изградњу речника. То радимо како бисмо убрзали време извршења и не бисмо вас држали у ишчекивању. Међутим, преузимамо ризик да неке речи из целокупног скупа података не буду укључене у речник и да буду игнорисане током обуке. Стога, коришћење целокупне величине речника и пролазак кроз цео скуп података током `adapt` би требало да повећа коначну тачност, али не значајно.\n",
"\n",
"Сада можемо приступити стварном речнику:\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['', '[UNK]', 'the', 'to', 'a', 'in', 'of', 'and', 'on', 'for']\n",
"Length of vocabulary: 5335\n"
]
}
],
"source": [
"vocab = vectorizer.get_vocabulary()\n",
"vocab_size = len(vocab)\n",
"print(vocab[:10])\n",
"print(f\"Length of vocabulary: {vocab_size}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Користећи векторизатор, можемо лако кодирати било који текст у скуп бројева:\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<tf.Tensor: shape=(7,), dtype=int64, numpy=array([ 112, 3695, 3, 304, 11, 1041, 1], dtype=int64)>"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"vectorizer('I love to play with my words')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Представљање текста методом \"торба речи\"\n",
"\n",
"Пошто речи представљају значење, понекад можемо схватити значење неког текста само гледајући појединачне речи, без обзира на њихов редослед у реченици. На пример, приликом класификације вести, речи као што су *време* и *снег* вероватно указују на *временску прогнозу*, док би речи као што су *акције* и *долар* биле повезане са *финансијским вестима*.\n",
"\n",
"**Торба речи** (BoW) представљање вектора је најједноставније за разумевање међу традиционалним представљањима вектора. Свака реч је повезана са индексом вектора, а елемент вектора садржи број појављивања сваке речи у датом документу.\n",
"\n",
"![Слика која приказује како је представљање вектора методом \"торба речи\" приказано у меморији.](../../../../../translated_images/sr/bag-of-words-example.606fc1738f1d7ba9.webp) \n",
"\n",
"> **Note**: Можете такође размишљати о BoW као о збиру свих једноврсно-кодираних вектора за појединачне речи у тексту.\n",
"\n",
"Испод је пример како да генеришете представљање методом \"торба речи\" користећи Python библиотеку Scikit Learn:\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[1, 1, 0, 2, 0, 0, 0, 0, 0]], dtype=int64)"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from sklearn.feature_extraction.text import CountVectorizer\n",
"sc_vectorizer = CountVectorizer()\n",
"corpus = [\n",
" 'I like hot dogs.',\n",
" 'The dog ran fast.',\n",
" 'Its hot outside.',\n",
" ]\n",
"sc_vectorizer.fit_transform(corpus)\n",
"sc_vectorizer.transform(['My dog likes hot dogs on a hot day.']).toarray()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Можемо такође користити Керас векторизатор који смо дефинисали изнад, претварајући сваки број речи у one-hot кодирање и сабирајући све те векторе:\n"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([0., 5., 0., ..., 0., 0., 0.], dtype=float32)"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def to_bow(text):\n",
" return tf.reduce_sum(tf.one_hot(vectorizer(text),vocab_size),axis=0)\n",
"\n",
"to_bow('My dog likes hot dogs on a hot day.').numpy()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **Напомена**: Можда ћете бити изненађени што се резултат разликује од претходног примера. Разлог је тај што у примеру са Keras-ом дужина вектора одговара величини речника, који је направљен из целог AG News скупа података, док смо у примеру са Scikit Learn-ом речник изградили директно из узорка текста.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Тренирање BoW класификатора\n",
"\n",
"Сада када смо научили како да изградимо представу текста у облику \"вреће речи\" (bag-of-words), хајде да обучимо класификатор који је користи. Прво, потребно је да наш скуп података конвертујемо у представу \"вреће речи\". Ово можемо постићи коришћењем функције `map` на следећи начин:\n"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"batch_size = 128\n",
"\n",
"ds_train_bow = ds_train.map(lambda x: (to_bow(x['title']+x['description']),x['label'])).batch(batch_size)\n",
"ds_test_bow = ds_test.map(lambda x: (to_bow(x['title']+x['description']),x['label'])).batch(batch_size)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Сада хајде да дефинишемо једноставну класификаторску неуронску мрежу која садржи један линеарни слој. Улазна величина је `vocab_size`, а излазна величина одговара броју класа (4). Пошто решавамо задатак класификације, завршна активациона функција је **softmax**:\n"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"938/938 [==============================] - 66s 70ms/step - loss: 0.6144 - acc: 0.8427 - val_loss: 0.4416 - val_acc: 0.8697\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.History at 0x20c70a947f0>"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model = keras.models.Sequential([\n",
" keras.layers.Dense(4,activation='softmax',input_shape=(vocab_size,))\n",
"])\n",
"model.compile(loss='sparse_categorical_crossentropy',optimizer='adam',metrics=['acc'])\n",
"model.fit(ds_train_bow,validation_data=ds_test_bow)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Пошто имамо 4 класе, тачност изнад 80% је добар резултат.\n",
"\n",
"## Тренирање класификатора као једне мреже\n",
"\n",
"Пошто је векторизатор такође Keras слој, можемо дефинисати мрежу која га укључује и тренирати је од почетка до краја. На овај начин не морамо да векторизујемо скуп података користећи `map`, већ можемо једноставно проследити оригинални скуп података на улаз мреже.\n",
"\n",
"> **Напомена**: И даље бисмо морали да применимо `map` на наш скуп података како бисмо конвертовали поља из речника (као што су `title`, `description` и `label`) у парове. Међутим, када учитавамо податке са диска, можемо одмах направити скуп података са потребном структуром.\n"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model: \"model\"\n",
"_________________________________________________________________\n",
" Layer (type) Output Shape Param # \n",
"=================================================================\n",
" input_1 (InputLayer) [(None, 1)] 0 \n",
" \n",
" text_vectorization (TextVec (None, None) 0 \n",
" torization) \n",
" \n",
" tf.one_hot (TFOpLambda) (None, None, 5335) 0 \n",
" \n",
" tf.math.reduce_sum (TFOpLam (None, 5335) 0 \n",
" bda) \n",
" \n",
" dense_2 (Dense) (None, 4) 21344 \n",
" \n",
"=================================================================\n",
"Total params: 21,344\n",
"Trainable params: 21,344\n",
"Non-trainable params: 0\n",
"_________________________________________________________________\n",
"938/938 [==============================] - 73s 77ms/step - loss: 0.6057 - acc: 0.8414 - val_loss: 0.4202 - val_acc: 0.8736\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.History at 0x20c721521f0>"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"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",
"inp = keras.Input(shape=(1,),dtype=tf.string)\n",
"x = vectorizer(inp)\n",
"x = tf.reduce_sum(tf.one_hot(x,vocab_size),axis=1)\n",
"out = keras.layers.Dense(4,activation='softmax')(x)\n",
"model = keras.models.Model(inp,out)\n",
"model.summary()\n",
"\n",
"model.compile(loss='sparse_categorical_crossentropy',optimizer='adam',metrics=['acc'])\n",
"model.fit(ds_train.map(tupelize).batch(batch_size),validation_data=ds_test.map(tupelize).batch(batch_size))\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Биграми, триграми и n-грамови\n",
"\n",
"Једно од ограничења приступа \"вреће речи\" је то што су неке речи део израза састављених од више речи. На пример, реч 'hot dog' има потпуно другачије значење од речи 'hot' и 'dog' у другим контекстима. Ако речи 'hot' и 'dog' увек представљамо истим векторима, то може збунити наш модел.\n",
"\n",
"Да бисмо ово решили, често се користе **представе n-грамова** у методама класификације докумената, где је учесталост сваке речи, двословне или трословне комбинације корисна карактеристика за тренирање класификатора. У представама биграма, на пример, додајемо све парове речи у речник, поред оригиналних речи.\n",
"\n",
"Испод је пример како да генеришете представу \"вреће речи\" са биграмима користећи Scikit Learn:\n"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Vocabulary:\n",
" {'i': 7, 'like': 11, 'hot': 4, 'dogs': 2, 'i like': 8, 'like hot': 12, 'hot dogs': 5, 'the': 16, 'dog': 0, 'ran': 14, 'fast': 3, 'the dog': 17, 'dog ran': 1, 'ran fast': 15, 'its': 9, 'outside': 13, 'its hot': 10, 'hot outside': 6}\n"
]
},
{
"data": {
"text/plain": [
"array([[1, 0, 1, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],\n",
" dtype=int64)"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bigram_vectorizer = CountVectorizer(ngram_range=(1, 2), token_pattern=r'\\b\\w+\\b', min_df=1)\n",
"corpus = [\n",
" 'I like hot dogs.',\n",
" 'The dog ran fast.',\n",
" 'Its hot outside.',\n",
" ]\n",
"bigram_vectorizer.fit_transform(corpus)\n",
"print(\"Vocabulary:\\n\",bigram_vectorizer.vocabulary_)\n",
"bigram_vectorizer.transform(['My dog likes hot dogs on a hot day.']).toarray()\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Главни недостатак n-грам приступа је што величина речника почиње да расте изузетно брзо. У пракси, потребно је комбиновати n-грам репрезентацију са техником смањења димензионалности, као што су *уграђивања* (*embeddings*), о чему ћемо говорити у наредној јединици.\n",
"\n",
"Да бисмо користили n-грам репрезентацију у нашем **AG News** скупу података, потребно је да проследимо параметар `ngrams` нашем конструктору `TextVectorization`. Дужина речника биграма је **значајно већа**, у нашем случају више од 1,3 милиона токена! Због тога има смисла ограничити број биграм токена на неки разумни број.\n",
"\n",
"Могли бисмо користити исти код као горе за тренирање класификатора, али би то било веома неефикасно у погледу меморије. У наредној јединици ћемо тренирати класификатор биграма користећи уграђивања. У међувремену, можете експериментисати са тренирањем класификатора биграма у овом бележнику и видети да ли можете постићи већу тачност.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Аутоматско израчунавање BoW вектора\n",
"\n",
"У горњем примеру смо ручно израчунавали BoW векторе сабирањем one-hot кодирања појединачних речи. Међутим, најновија верзија TensorFlow-а нам омогућава да аутоматски израчунамо BoW векторе тако што проследимо параметар `output_mode='count` конструктору векторизатора. Ово значајно олакшава дефинисање и тренирање нашег модела:\n"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Training vectorizer\n",
"938/938 [==============================] - 7s 7ms/step - loss: 0.5929 - acc: 0.8486 - val_loss: 0.4168 - val_acc: 0.8772\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.History at 0x20c725217c0>"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model = keras.models.Sequential([\n",
" keras.layers.experimental.preprocessing.TextVectorization(max_tokens=vocab_size,output_mode='count'),\n",
" keras.layers.Dense(4,input_shape=(vocab_size,), activation='softmax')\n",
"])\n",
"print(\"Training vectorizer\")\n",
"model.layers[0].adapt(ds_train.take(500).map(extract_text))\n",
"model.compile(loss='sparse_categorical_crossentropy',optimizer='adam',metrics=['acc'])\n",
"model.fit(ds_train.map(tupelize).batch(batch_size),validation_data=ds_test.map(tupelize).batch(batch_size))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Учесталост термина - инверзна учесталост докумената (TF-IDF)\n",
"\n",
"У представљању BoW, појаве речи се вреднују истом техником без обзира на саму реч. Међутим, јасно је да су честе речи као што су *и* и *у* много мање важне за класификацију од специјализованих термина. У већини задатака обраде природног језика (NLP) неке речи су релевантније од других.\n",
"\n",
"**TF-IDF** означава **учесталост термина - инверзна учесталост докумената**. То је варијација модела \"вреће речи\" (bag-of-words), где се уместо бинарне вредности 0/1, која указује на појаву речи у документу, користи вредност са покретним зарезом, која је повезана са учесталошћу појаве речи у корпусу.\n",
"\n",
"Формалније, тежина $w_{ij}$ речи $i$ у документу $j$ дефинисана је као:\n",
"$$\n",
"w_{ij} = tf_{ij}\\times\\log({N\\over df_i})\n",
"$$\n",
"где су:\n",
"* $tf_{ij}$ број појава речи $i$ у документу $j$, односно BoW вредност коју смо раније видели\n",
"* $N$ број докумената у збирци\n",
"* $df_i$ број докумената који садрже реч $i$ у целој збирци\n",
"\n",
"TF-IDF вредност $w_{ij}$ расте пропорционално броју појава речи у документу и смањује се у зависности од броја докумената у корпусу који садрже ту реч, што помаже у прилагођавању чињеници да се неке речи чешће појављују од других. На пример, ако се реч појављује у *сваком* документу у збирци, $df_i=N$, и $w_{ij}=0$, те би те речи биле потпуно занемарене.\n",
"\n",
"TF-IDF векторизацију текста можете лако креирати помоћу Scikit Learn:\n"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[0.43381609, 0. , 0.43381609, 0. , 0.65985664,\n",
" 0.43381609, 0. , 0. , 0. , 0. ,\n",
" 0. , 0. , 0. , 0. , 0. ,\n",
" 0. ]])"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from sklearn.feature_extraction.text import TfidfVectorizer\n",
"vectorizer = TfidfVectorizer(ngram_range=(1,2))\n",
"vectorizer.fit_transform(corpus)\n",
"vectorizer.transform(['My dog likes hot dogs on a hot day.']).toarray()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"У Керасу, слој `TextVectorization` може аутоматски израчунати TF-IDF фреквенције прослеђивањем параметра `output_mode='tf-idf'`. Хајде да поновимо код који смо користили изнад да видимо да ли употреба TF-IDF повећава тачност:\n"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Training vectorizer\n",
"938/938 [==============================] - 12s 12ms/step - loss: 0.4197 - acc: 0.8662 - val_loss: 0.3432 - val_acc: 0.8849\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.History at 0x20c729dfd30>"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model = keras.models.Sequential([\n",
" keras.layers.experimental.preprocessing.TextVectorization(max_tokens=vocab_size,output_mode='tf-idf'),\n",
" keras.layers.Dense(4,input_shape=(vocab_size,), activation='softmax')\n",
"])\n",
"print(\"Training vectorizer\")\n",
"model.layers[0].adapt(ds_train.take(500).map(extract_text))\n",
"model.compile(loss='sparse_categorical_crossentropy',optimizer='adam',metrics=['acc'])\n",
"model.fit(ds_train.map(tupelize).batch(batch_size),validation_data=ds_test.map(tupelize).batch(batch_size))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Закључак\n",
"\n",
"Иако TF-IDF репрезентације додељују тежине фреквенције различитим речима, оне нису у стању да представе значење или редослед. Као што је чувени лингвиста Џ. Р. Фирт рекао 1935. године: „Потпуно значење речи је увек контекстуално, и ниједно проучавање значења ван контекста не може се сматрати озбиљним.“ Касније у курсу ћемо научити како да ухватимо контекстуалне информације из текста користећи језичко моделирање.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Одрицање од одговорности**: \nОвај документ је преведен коришћењем услуге за превођење помоћу вештачке интелигенције [Co-op Translator](https://github.com/Azure/co-op-translator). Иако се трудимо да превод буде тачан, молимо вас да имате у виду да аутоматизовани преводи могу садржати грешке или нетачности. Оригинални документ на његовом изворном језику треба сматрати ауторитативним извором. За критичне информације препоручује се професионални превод од стране људи. Не преузимамо одговорност за било каква погрешна тумачења или неспоразуме који могу настати услед коришћења овог превода.\n"
]
}
],
"metadata": {
"interpreter": {
"hash": "0cb620c6d4b9f7a635928804c26cf22403d89d98d79684e4529119355ee6d5a5"
},
"kernel_info": {
"name": "conda-env-py37_tensorflow-py"
},
"kernelspec": {
"display_name": "py37_tensorflow",
"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"
},
"nteract": {
"version": "nteract-front-end@1.0.0"
},
"coopTranslator": {
"original_hash": "19b43951d55b377a76209c24c1f017e4",
"translation_date": "2025-08-30T01:17:46+00:00",
"source_file": "lessons/5-NLP/13-TextRep/TextRepresentationTF.ipynb",
"language_code": "sr"
}
},
"nbformat": 4,
"nbformat_minor": 4
}