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

647 lines
26 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Tekstclassificatietaak\n",
"\n",
"In deze module beginnen we met een eenvoudige tekstclassificatietaak gebaseerd op de **[AG_NEWS](http://www.di.unipi.it/~gulli/AG_corpus_of_news_articles.html)** dataset: we classificeren nieuwsheadlines in een van de 4 categorieën: Wereld, Sport, Zakelijk en Wetenschap/Technologie.\n",
"\n",
"## De Dataset\n",
"\n",
"Om de dataset te laden, gebruiken we de **[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": [
"We kunnen nu toegang krijgen tot de trainings- en testgedeelten van de dataset door respectievelijk `dataset['train']` en `dataset['test']` te gebruiken:\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": [
"Laten we de eerste 10 nieuwe koppen uit onze dataset afdrukken:\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": [
"## Tekstvectorisatie\n",
"\n",
"Nu moeten we tekst omzetten in **nummers** die kunnen worden weergegeven als tensors. Als we een woordniveau-representatie willen, moeten we twee dingen doen:\n",
"\n",
"* Gebruik een **tokenizer** om tekst op te splitsen in **tokens**.\n",
"* Bouw een **vocabulaire** van die tokens.\n",
"\n",
"### Beperken van de vocabulairegrootte\n",
"\n",
"In het voorbeeld van de AG News-dataset is de vocabulairegrootte behoorlijk groot, meer dan 100k woorden. Over het algemeen hebben we geen woorden nodig die zelden in de tekst voorkomen — slechts een paar zinnen zullen ze bevatten, en het model zal er niet van leren. Daarom is het logisch om de vocabulairegrootte te beperken tot een kleiner aantal door een argument door te geven aan de vectorizer-constructor:\n",
"\n",
"Beide stappen kunnen worden afgehandeld met behulp van de **TextVectorization**-laag. Laten we het vectorizer-object instantiëren en vervolgens de `adapt`-methode aanroepen om alle tekst door te nemen en een vocabulaire op te bouwen:\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": [
"> **Let op** dat we slechts een deel van de volledige dataset gebruiken om een vocabulaire op te bouwen. We doen dit om de uitvoeringstijd te versnellen en u niet te laten wachten. Echter, we lopen het risico dat sommige woorden uit de volledige dataset niet in de vocabulaire worden opgenomen en tijdens de training worden genegeerd. Het gebruik van de volledige vocabulaire en het doorlopen van de hele dataset tijdens `adapt` zou de uiteindelijke nauwkeurigheid moeten verhogen, maar niet significant.\n",
"\n",
"Nu kunnen we toegang krijgen tot de daadwerkelijke vocabulaire:\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": [
"Met behulp van de vectorizer kunnen we eenvoudig elke tekst coderen in een reeks getallen:\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": [
"## Bag-of-words tekstrepresentatie\n",
"\n",
"Omdat woorden betekenis vertegenwoordigen, kunnen we soms de betekenis van een stuk tekst achterhalen door alleen naar de afzonderlijke woorden te kijken, ongeacht hun volgorde in de zin. Bijvoorbeeld, bij het classificeren van nieuws, zullen woorden zoals *weer* en *sneeuw* waarschijnlijk wijzen op *weersvoorspellingen*, terwijl woorden zoals *aandelen* en *dollar* eerder zouden duiden op *financieel nieuws*.\n",
"\n",
"**Bag-of-words** (BoW) vectorrepresentatie is de meest eenvoudige traditionele vectorrepresentatie om te begrijpen. Elk woord is gekoppeld aan een vectorindex, en een element in de vector bevat het aantal keren dat elk woord voorkomt in een bepaald document.\n",
"\n",
"![Afbeelding die laat zien hoe een bag-of-words vectorrepresentatie in het geheugen wordt weergegeven.](../../../../../translated_images/nl/bag-of-words-example.606fc1738f1d7ba9.webp) \n",
"\n",
"> **Note**: Je kunt BoW ook zien als de som van alle one-hot-gecodeerde vectoren voor individuele woorden in de tekst.\n",
"\n",
"Hieronder staat een voorbeeld van hoe je een bag-of-words representatie kunt genereren met behulp van de Scikit Learn python bibliotheek:\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": [
"We kunnen ook de Keras-vectorizer gebruiken die we hierboven hebben gedefinieerd, waarbij elk woordnummer wordt omgezet in een one-hot encoding en al die vectoren worden opgeteld:\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": [
"> **Opmerking**: Het kan je verrassen dat het resultaat verschilt van het vorige voorbeeld. De reden hiervoor is dat in het Keras-voorbeeld de lengte van de vector overeenkomt met de grootte van de woordenschat, die is opgebouwd uit de hele AG News-dataset, terwijl we in het Scikit Learn-voorbeeld de woordenschat ter plekke hebben opgebouwd uit de voorbeeldtekst.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Het trainen van de BoW-classificator\n",
"\n",
"Nu we hebben geleerd hoe we de bag-of-words-representatie van onze tekst kunnen maken, laten we een classificator trainen die hiervan gebruik maakt. Eerst moeten we onze dataset omzetten naar een bag-of-words-representatie. Dit kan worden gedaan met behulp van de `map`-functie op de volgende manier:\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": [
"Laten we nu een eenvoudige classifier-neuraal netwerk definiëren dat één lineaire laag bevat. De invoergrootte is `vocab_size`, en de uitvoergrootte komt overeen met het aantal klassen (4). Omdat we een classificatietaak oplossen, is de laatste activatiefunctie **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": [
"Aangezien we 4 klassen hebben, is een nauwkeurigheid van boven de 80% een goed resultaat.\n",
"\n",
"## Een classifier trainen als één netwerk\n",
"\n",
"Omdat de vectorizer ook een Keras-laag is, kunnen we een netwerk definiëren dat deze bevat en het end-to-end trainen. Op deze manier hoeven we de dataset niet te vectoriseren met behulp van `map`, we kunnen gewoon de originele dataset doorgeven aan de input van het netwerk.\n",
"\n",
"> **Opmerking**: We zouden nog steeds maps moeten toepassen op onze dataset om velden uit woordenboeken (zoals `title`, `description` en `label`) om te zetten naar tuples. Echter, bij het laden van data vanaf schijf, kunnen we vanaf het begin een dataset bouwen met de vereiste structuur.\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": [
"## Bigrams, trigrams en n-grams\n",
"\n",
"Een beperking van de bag-of-words aanpak is dat sommige woorden deel uitmaken van meerwoordige uitdrukkingen. Bijvoorbeeld, het woord 'hot dog' heeft een compleet andere betekenis dan de woorden 'hot' en 'dog' in andere contexten. Als we de woorden 'hot' en 'dog' altijd met dezelfde vectoren representeren, kan dat ons model in verwarring brengen.\n",
"\n",
"Om dit aan te pakken, worden **n-gram representaties** vaak gebruikt bij methoden voor documentclassificatie, waarbij de frequentie van elk woord, twee-woordcombinatie of drie-woordcombinatie een nuttige eigenschap is voor het trainen van classifiers. Bij bigram representaties voegen we bijvoorbeeld alle woordparen toe aan de woordenschat, naast de oorspronkelijke woorden.\n",
"\n",
"Hieronder staat een voorbeeld van hoe je een bigram bag-of-words representatie kunt genereren met behulp van 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": [
"Het grootste nadeel van de n-gram aanpak is dat de omvang van de woordenschat extreem snel begint te groeien. In de praktijk moeten we de n-gram representatie combineren met een techniek voor dimensiereductie, zoals *embeddings*, waar we in de volgende eenheid op ingaan.\n",
"\n",
"Om een n-gram representatie te gebruiken in ons **AG News** dataset, moeten we de parameter `ngrams` doorgeven aan onze `TextVectorization` constructor. De omvang van een bigram woordenschat is **aanzienlijk groter**, in ons geval meer dan 1,3 miljoen tokens! Daarom is het logisch om ook het aantal bigram tokens te beperken tot een redelijk aantal.\n",
"\n",
"We zouden dezelfde code als hierboven kunnen gebruiken om de classifier te trainen, maar dat zou zeer inefficiënt zijn qua geheugen. In de volgende eenheid zullen we de bigram classifier trainen met behulp van embeddings. In de tussentijd kun je experimenteren met het trainen van de bigram classifier in dit notebook en kijken of je een hogere nauwkeurigheid kunt behalen.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Automatisch BoW-vectoren berekenen\n",
"\n",
"In het bovenstaande voorbeeld hebben we BoW-vectoren met de hand berekend door de één-op-één encoderingen van individuele woorden op te tellen. De nieuwste versie van TensorFlow stelt ons echter in staat om BoW-vectoren automatisch te berekenen door de parameter `output_mode='count` door te geven aan de vectorizer constructor. Dit maakt het definiëren en trainen van ons model aanzienlijk eenvoudiger:\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": [
"## Termfrequentie - inverse documentfrequentie (TF-IDF)\n",
"\n",
"In de BoW-representatie worden woordvoorkomens op dezelfde manier gewogen, ongeacht het woord zelf. Het is echter duidelijk dat veelvoorkomende woorden zoals *een* en *in* veel minder belangrijk zijn voor classificatie dan gespecialiseerde termen. Bij de meeste NLP-taken zijn sommige woorden relevanter dan andere.\n",
"\n",
"**TF-IDF** staat voor **termfrequentie - inverse documentfrequentie**. Het is een variatie op bag-of-words, waarbij in plaats van een binaire 0/1-waarde die aangeeft of een woord in een document voorkomt, een drijvende-kommawaarde wordt gebruikt die gerelateerd is aan de frequentie van het woord in de corpus.\n",
"\n",
"Meer formeel wordt het gewicht $w_{ij}$ van een woord $i$ in document $j$ gedefinieerd als:\n",
"$$\n",
"w_{ij} = tf_{ij}\\times\\log({N\\over df_i})\n",
"$$\n",
"waarbij\n",
"* $tf_{ij}$ het aantal voorkomens van $i$ in $j$ is, oftewel de BoW-waarde die we eerder hebben gezien\n",
"* $N$ het aantal documenten in de collectie is\n",
"* $df_i$ het aantal documenten is waarin het woord $i$ voorkomt in de hele collectie\n",
"\n",
"De TF-IDF-waarde $w_{ij}$ neemt proportioneel toe met het aantal keren dat een woord in een document voorkomt en wordt gecorrigeerd door het aantal documenten in de corpus waarin het woord voorkomt. Dit helpt om te compenseren voor het feit dat sommige woorden vaker voorkomen dan andere. Bijvoorbeeld, als het woord in *elk* document in de collectie voorkomt, geldt $df_i=N$, en $w_{ij}=0$, en die termen worden volledig genegeerd.\n",
"\n",
"Je kunt eenvoudig een TF-IDF-vectorisatie van tekst maken met 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": [
"In Keras kan de `TextVectorization`-laag automatisch TF-IDF-frequenties berekenen door de parameter `output_mode='tf-idf'` door te geven. Laten we de code die we hierboven hebben gebruikt herhalen om te zien of het gebruik van TF-IDF de nauwkeurigheid verhoogt:\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": [
"## Conclusie\n",
"\n",
"Hoewel TF-IDF-representaties frequentiegewichten toekennen aan verschillende woorden, zijn ze niet in staat om betekenis of volgorde weer te geven. Zoals de beroemde taalkundige J. R. Firth in 1935 zei: \"De volledige betekenis van een woord is altijd contextueel, en geen enkele studie van betekenis los van context kan serieus worden genomen.\" Later in de cursus zullen we leren hoe we contextuele informatie uit tekst kunnen vastleggen met behulp van taalmodellen.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Disclaimer**: \nDit document is vertaald met behulp van de AI-vertalingsservice [Co-op Translator](https://github.com/Azure/co-op-translator). Hoewel we streven naar nauwkeurigheid, dient u zich ervan bewust te zijn dat geautomatiseerde vertalingen fouten of onnauwkeurigheden kunnen bevatten. Het originele document in zijn oorspronkelijke taal moet worden beschouwd als de gezaghebbende bron. Voor cruciale informatie wordt professionele menselijke vertaling aanbevolen. Wij zijn niet aansprakelijk voor misverstanden of verkeerde interpretaties die voortvloeien uit het gebruik van deze vertaling.\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-28T22:01:49+00:00",
"source_file": "lessons/5-NLP/13-TextRep/TextRepresentationTF.ipynb",
"language_code": "nl"
}
},
"nbformat": 4,
"nbformat_minor": 4
}