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

647 lines
26 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Zadatak klasifikacije teksta\n",
"\n",
"U ovom modulu započet ćemo s jednostavnim zadatkom klasifikacije teksta temeljenim na skupu podataka **[AG_NEWS](http://www.di.unipi.it/~gulli/AG_corpus_of_news_articles.html)**: klasificirat ćemo naslove vijesti u jednu od 4 kategorije: Svijet, Sport, Poslovanje i Znanost/Tehnologija.\n",
"\n",
"## Skup podataka\n",
"\n",
"Za učitavanje skupa podataka koristit ćemo API **[TensorFlow Datasets](https://www.tensorflow.org/datasets)**.\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": [
"Sada možemo pristupiti treninzima i testnim dijelovima skupa podataka koristeći `dataset['train']` i `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": [
"Ispišimo prvih 10 novih naslova iz našeg skupa podataka:\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": [
"## Vektorizacija teksta\n",
"\n",
"Sada trebamo pretvoriti tekst u **brojeve** koji se mogu predstaviti kao tenzori. Ako želimo reprezentaciju na razini riječi, trebamo napraviti dvije stvari:\n",
"\n",
"* Koristiti **tokenizator** za razdvajanje teksta na **tokene**.\n",
"* Izgraditi **rječnik** tih tokena.\n",
"\n",
"### Ograničavanje veličine rječnika\n",
"\n",
"U primjeru s AG News skupom podataka, veličina rječnika je prilično velika, više od 100 tisuća riječi. Općenito govoreći, ne trebaju nam riječi koje se rijetko pojavljuju u tekstu — samo nekoliko rečenica će ih sadržavati, a model iz njih neće ništa naučiti. Stoga ima smisla ograničiti veličinu rječnika na manji broj tako da proslijedimo argument konstruktoru vektorizatora:\n",
"\n",
"Oba ova koraka mogu se obaviti pomoću sloja **TextVectorization**. Instancirajmo objekt vektorizatora, a zatim pozovimo metodu `adapt` kako bismo prošli kroz sav tekst i izgradili rječnik:\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": [
"> **Napomena** da koristimo samo podskup cijelog skupa podataka za izgradnju vokabulara. To radimo kako bismo ubrzali vrijeme izvršavanja i ne zadržavali vas. Međutim, preuzimamo rizik da neke riječi iz cijelog skupa podataka neće biti uključene u vokabular i bit će zanemarene tijekom treniranja. Dakle, korištenje cijele veličine vokabulara i prolazak kroz cijeli skup podataka tijekom `adapt` trebalo bi povećati konačnu točnost, ali ne značajno.\n",
"\n",
"Sada možemo pristupiti stvarnom vokabularu:\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": [
"Pomoću vektorizatora možemo lako kodirati bilo koji tekst u skup brojeva:\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": [
"## Reprezentacija teksta pomoću vreće riječi\n",
"\n",
"Budući da riječi prenose značenje, ponekad možemo razumjeti značenje nekog teksta samo promatrajući pojedinačne riječi, bez obzira na njihov redoslijed u rečenici. Na primjer, pri klasifikaciji vijesti, riječi poput *vrijeme* i *snijeg* vjerojatno ukazuju na *vremensku prognozu*, dok bi riječi poput *dionice* i *dolar* bile povezane s *financijskim vijestima*.\n",
"\n",
"**Vreća riječi** (BoW) je najjednostavnija tradicionalna reprezentacija vektora za razumijevanje. Svaka riječ povezana je s indeksom vektora, a element vektora sadrži broj pojavljivanja svake riječi u danom dokumentu.\n",
"\n",
"![Slika koja prikazuje kako je reprezentacija vektora vreće riječi prikazana u memoriji.](../../../../../translated_images/hr/bag-of-words-example.606fc1738f1d7ba9.webp)\n",
"\n",
"> **Note**: BoW možete zamisliti i kao zbroj svih vektora kodiranih metodom \"jedan na jedan\" za pojedinačne riječi u tekstu.\n",
"\n",
"Ispod je primjer kako generirati reprezentaciju vreće riječi koristeći Python biblioteku 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": [
"Također možemo koristiti Keras vektorizator koji smo definirali gore, pretvarajući svaki broj riječi u one-hot kodiranje i zbrajajući sve te vektore:\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": [
"> **Napomena**: Možda ćete biti iznenađeni što se rezultat razlikuje od prethodnog primjera. Razlog je taj što u Keras primjeru duljina vektora odgovara veličini vokabulara, koji je izgrađen iz cijelog AG News skupa podataka, dok smo u Scikit Learn primjeru vokabular izgradili iz uzorka teksta u hodu.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Treniranje BoW klasifikatora\n",
"\n",
"Sada kada smo naučili kako izraditi reprezentaciju teksta pomoću vreće riječi, idemo trenirati klasifikator koji je koristi. Prvo, trebamo naš skup podataka pretvoriti u reprezentaciju vreće riječi. To se može postići korištenjem funkcije `map` na sljedeći način:\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": [
"Sada definirajmo jednostavnu neuronsku mrežu klasifikatora koja sadrži jedan linearni sloj. Veličina ulaza je `vocab_size`, a veličina izlaza odgovara broju klasa (4). Budući da rješavamo zadatak klasifikacije, završna aktivacijska funkcija je **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": [
"Budući da imamo 4 klase, točnost iznad 80% je dobar rezultat.\n",
"\n",
"## Treniranje klasifikatora kao jedne mreže\n",
"\n",
"Budući da je vektorizator također Keras sloj, možemo definirati mrežu koja ga uključuje i trenirati je od početka do kraja. Na taj način ne moramo vektorizirati skup podataka koristeći `map`, već možemo jednostavno proslijediti izvorni skup podataka na ulaz mreže.\n",
"\n",
"> **Napomena**: I dalje bismo morali primijeniti mapiranja na naš skup podataka kako bismo polja iz rječnika (kao što su `title`, `description` i `label`) pretvorili u tuple. Međutim, prilikom učitavanja podataka s diska, možemo odmah izgraditi skup podataka s potrebnom strukturom.\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": [
"## Bigrami, trigrami i n-grami\n",
"\n",
"Jedno ograničenje pristupa vreće riječi (bag-of-words) je to što su neke riječi dio višerječnih izraza. Na primjer, riječ 'hot dog' ima potpuno drugačije značenje od riječi 'hot' i 'dog' u drugim kontekstima. Ako uvijek predstavljamo riječi 'hot' i 'dog' koristeći iste vektore, to može zbuniti naš model.\n",
"\n",
"Kako bismo to riješili, često se koriste **n-gramske reprezentacije** u metodama klasifikacije dokumenata, gdje je učestalost svake riječi, dvorječnih ili trovrječnih izraza korisna značajka za treniranje klasifikatora. U bigramskim reprezentacijama, na primjer, dodajemo sve parove riječi u vokabular, uz originalne riječi.\n",
"\n",
"Ispod je primjer kako generirati bigramsku reprezentaciju vreće riječi koristeći 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": [
"Glavni nedostatak pristupa n-grama je taj što veličina vokabulara počinje iznimno brzo rasti. U praksi, potrebno je kombinirati n-gram reprezentaciju s tehnikom smanjenja dimenzionalnosti, poput *ugradbi* (embeddings), o čemu ćemo raspravljati u sljedećoj jedinici.\n",
"\n",
"Kako bismo koristili n-gram reprezentaciju u našem **AG News** skupu podataka, trebamo proslijediti parametar `ngrams` našem konstruktoru `TextVectorization`. Duljina vokabulara bigrama je **znatno veća**, u našem slučaju više od 1,3 milijuna tokena! Stoga ima smisla ograničiti bigram tokene na neki razuman broj.\n",
"\n",
"Mogli bismo koristiti isti kod kao gore za treniranje klasifikatora, no to bi bilo vrlo neučinkovito u smislu memorije. U sljedećoj jedinici, trenirat ćemo klasifikator bigrama koristeći ugradbe. U međuvremenu, možete eksperimentirati s treniranjem klasifikatora bigrama u ovoj bilježnici i vidjeti možete li postići veću točnost.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Automatsko izračunavanje BoW vektora\n",
"\n",
"U gornjem primjeru izračunali smo BoW vektore ručno zbrajajući one-hot kodiranja pojedinačnih riječi. Međutim, najnovija verzija TensorFlow-a omogućuje nam automatsko izračunavanje BoW vektora prosljeđivanjem parametra `output_mode='count` konstruktoru vektorizatora. Ovo značajno olakšava definiranje i treniranje našeg modela:\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": [
"## Frekvencija pojma - inverzna frekvencija dokumenta (TF-IDF)\n",
"\n",
"U BoW reprezentaciji, pojavljivanja riječi se ponderiraju istom tehnikom bez obzira na samu riječ. Međutim, jasno je da su učestale riječi poput *a* i *in* mnogo manje važne za klasifikaciju od specijaliziranih pojmova. U većini NLP zadataka neke riječi su relevantnije od drugih.\n",
"\n",
"**TF-IDF** označava **frekvenciju pojma - inverznu frekvenciju dokumenta**. To je varijacija vreće riječi, gdje se umjesto binarne vrijednosti 0/1 koja označava pojavljivanje riječi u dokumentu koristi vrijednost s pomičnim zarezom, koja je povezana s učestalošću pojavljivanja riječi u korpusu.\n",
"\n",
"Formalnije, težina $w_{ij}$ riječi $i$ u dokumentu $j$ definirana je kao:\n",
"$$\n",
"w_{ij} = tf_{ij}\\times\\log({N\\over df_i})\n",
"$$\n",
"gdje\n",
"* $tf_{ij}$ je broj pojavljivanja $i$ u $j$, tj. BoW vrijednost koju smo ranije vidjeli\n",
"* $N$ je broj dokumenata u zbirci\n",
"* $df_i$ je broj dokumenata koji sadrže riječ $i$ u cijeloj zbirci\n",
"\n",
"TF-IDF vrijednost $w_{ij}$ raste proporcionalno broju puta koliko se riječ pojavljuje u dokumentu i smanjuje se ovisno o broju dokumenata u korpusu koji sadrže tu riječ, što pomaže u prilagodbi činjenici da se neke riječi pojavljuju češće od drugih. Na primjer, ako se riječ pojavljuje u *svakom* dokumentu u zbirci, $df_i=N$, i $w_{ij}=0$, te bi ti pojmovi bili potpuno zanemareni.\n",
"\n",
"TF-IDF vektorizaciju teksta možete jednostavno kreirati koristeći 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": [
"U Kerasu, sloj `TextVectorization` može automatski izračunati TF-IDF frekvencije prosljeđivanjem parametra `output_mode='tf-idf'`. Ponovimo kod koji smo koristili gore kako bismo vidjeli povećava li korištenje TF-IDF-a točnost:\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": [
"## Zaključak\n",
"\n",
"Iako TF-IDF reprezentacije dodjeljuju težine frekvencijama različitih riječi, one nisu sposobne prikazati značenje ili redoslijed. Kao što je poznati lingvist J. R. Firth rekao 1935. godine: \"Potpuno značenje riječi uvijek je kontekstualno, i nijedno proučavanje značenja izvan konteksta ne može se smatrati ozbiljnim.\" Kasnije u tečaju naučit ćemo kako uhvatiti kontekstualne informacije iz teksta koristeći jezično modeliranje.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Odricanje od odgovornosti**: \nOvaj dokument je preveden korištenjem AI usluge za prevođenje [Co-op Translator](https://github.com/Azure/co-op-translator). Iako nastojimo osigurati točnost, imajte na umu da automatski prijevodi mogu sadržavati pogreške ili netočnosti. Izvorni dokument na izvornom jeziku treba smatrati mjerodavnim izvorom. Za ključne informacije preporučuje se profesionalni prijevod od strane stručnjaka. Ne preuzimamo odgovornost za bilo kakva nesporazuma ili pogrešna tumačenja koja mogu proizaći iz korištenja ovog prijevoda.\n"
]
}
],
"metadata": {
"interpreter": {
"hash": "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-30T08:18:53+00:00",
"source_file": "lessons/5-NLP/13-TextRep/TextRepresentationTF.ipynb",
"language_code": "hr"
}
},
"nbformat": 4,
"nbformat_minor": 4
}