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

647 lines
27 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Compito di classificazione del testo\n",
"\n",
"In questo modulo, inizieremo con un semplice compito di classificazione del testo basato sul dataset **[AG_NEWS](http://www.di.unipi.it/~gulli/AG_corpus_of_news_articles.html)**: classificheremo i titoli delle notizie in una delle 4 categorie: Mondo, Sport, Economia e Scienza/Tecnologia.\n",
"\n",
"## Il Dataset\n",
"\n",
"Per caricare il dataset, utilizzeremo l'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": [
"Possiamo ora accedere alle parti di addestramento e di test del dataset utilizzando rispettivamente `dataset['train']` e `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": [
"Stampiamo i primi 10 nuovi titoli dal nostro dataset:\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": [
"## Vettorizzazione del testo\n",
"\n",
"Ora dobbiamo convertire il testo in **numeri** che possano essere rappresentati come tensori. Se vogliamo una rappresentazione a livello di parola, dobbiamo fare due cose:\n",
"\n",
"* Usare un **tokenizzatore** per suddividere il testo in **token**.\n",
"* Costruire un **vocabolario** di quei token.\n",
"\n",
"### Limitare la dimensione del vocabolario\n",
"\n",
"Nell'esempio del dataset AG News, la dimensione del vocabolario è piuttosto grande, con più di 100.000 parole. In generale, non abbiamo bisogno di parole che compaiono raramente nel testo — solo poche frasi le conterranno, e il modello non imparerà da esse. Pertanto, ha senso limitare la dimensione del vocabolario a un numero più piccolo passando un argomento al costruttore del vettorizzatore:\n",
"\n",
"Entrambi questi passaggi possono essere gestiti utilizzando il livello **TextVectorization**. Creiamo l'oggetto vettorizzatore e poi chiamiamo il metodo `adapt` per analizzare tutto il testo e costruire un vocabolario:\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": [
"> **Nota** che stiamo utilizzando solo un sottoinsieme dell'intero dataset per costruire un vocabolario. Lo facciamo per velocizzare il tempo di esecuzione e non farti aspettare. Tuttavia, corriamo il rischio che alcune parole dell'intero dataset non vengano incluse nel vocabolario e vengano ignorate durante l'addestramento. Pertanto, utilizzare l'intera dimensione del vocabolario e scorrere tutto il dataset durante `adapt` dovrebbe aumentare l'accuratezza finale, ma non in modo significativo.\n",
"\n",
"Ora possiamo accedere al vocabolario effettivo:\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": [
"Utilizzando il vettorizzatore, possiamo facilmente codificare qualsiasi testo in un insieme di numeri:\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": [
"## Rappresentazione testuale Bag-of-words\n",
"\n",
"Poiché le parole rappresentano significati, a volte possiamo capire il senso di un testo semplicemente osservando le singole parole, indipendentemente dal loro ordine nella frase. Ad esempio, quando si classificano notizie, parole come *meteo* e *neve* probabilmente indicano una *previsione del tempo*, mentre parole come *azioni* e *dollaro* sarebbero associate a *notizie finanziarie*.\n",
"\n",
"La rappresentazione vettoriale **Bag-of-words** (BoW) è la più semplice da comprendere tra le rappresentazioni vettoriali tradizionali. Ogni parola è collegata a un indice vettoriale, e un elemento del vettore contiene il numero di occorrenze di ciascuna parola in un determinato documento.\n",
"\n",
"![Immagine che mostra come una rappresentazione vettoriale bag-of-words è rappresentata in memoria.](../../../../../translated_images/it/bag-of-words-example.606fc1738f1d7ba9.webp) \n",
"\n",
"> **Nota**: Puoi anche pensare al BoW come alla somma di tutti i vettori one-hot-encoded per le singole parole nel testo.\n",
"\n",
"Di seguito è riportato un esempio di come generare una rappresentazione bag-of-words utilizzando la libreria 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": [
"Possiamo anche utilizzare il vettorizzatore Keras che abbiamo definito sopra, convertendo ogni numero di parola in una codifica one-hot e sommando tutti quei vettori.\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": [
"> **Nota**: Potresti essere sorpreso dal fatto che il risultato differisca dall'esempio precedente. La ragione è che nell'esempio di Keras la lunghezza del vettore corrisponde alla dimensione del vocabolario, che è stato costruito sull'intero dataset AG News, mentre nell'esempio di Scikit Learn abbiamo costruito il vocabolario direttamente dal testo di esempio.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Addestrare il classificatore BoW\n",
"\n",
"Ora che abbiamo imparato a costruire la rappresentazione bag-of-words del nostro testo, alleniamo un classificatore che la utilizza. Per prima cosa, dobbiamo convertire il nostro dataset in una rappresentazione bag-of-words. Questo può essere fatto utilizzando la funzione `map` nel seguente modo:\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": [
"Ora definiamo una semplice rete neurale classificatrice che contiene un unico strato lineare. La dimensione dell'input è `vocab_size`, e la dimensione dell'output corrisponde al numero di classi (4). Poiché stiamo risolvendo un compito di classificazione, la funzione di attivazione finale è **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": [
"Dal momento che abbiamo 4 classi, un'accuratezza superiore all'80% è un buon risultato.\n",
"\n",
"## Addestrare un classificatore come una rete unica\n",
"\n",
"Poiché il vettorizzatore è anche un livello di Keras, possiamo definire una rete che lo include e addestrarla end-to-end. In questo modo, non è necessario vettorizzare il dataset utilizzando `map`, possiamo semplicemente passare il dataset originale come input della rete.\n",
"\n",
"> **Nota**: Dovremmo comunque applicare mappe al nostro dataset per convertire i campi dai dizionari (come `title`, `description` e `label`) in tuple. Tuttavia, quando carichiamo i dati dal disco, possiamo costruire un dataset con la struttura richiesta fin dall'inizio.\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": [
"## Bigrammi, trigrammi e n-grammi\n",
"\n",
"Una limitazione dell'approccio bag-of-words è che alcune parole fanno parte di espressioni composte da più termini. Ad esempio, la parola 'hot dog' ha un significato completamente diverso rispetto alle parole 'hot' e 'dog' prese singolarmente in altri contesti. Se rappresentiamo sempre le parole 'hot' e 'dog' utilizzando gli stessi vettori, potremmo confondere il nostro modello.\n",
"\n",
"Per affrontare questo problema, si utilizzano spesso le **rappresentazioni n-gram** nei metodi di classificazione dei documenti, dove la frequenza di ogni parola, coppia di parole o terzina di parole rappresenta una caratteristica utile per addestrare i classificatori. Nelle rappresentazioni bigrammi, ad esempio, aggiungiamo al vocabolario tutte le coppie di parole, oltre alle parole originali.\n",
"\n",
"Di seguito è riportato un esempio di come generare una rappresentazione bag-of-words con bigrammi utilizzando 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": [
"Lo svantaggio principale dell'approccio n-gram è che la dimensione del vocabolario inizia a crescere estremamente rapidamente. In pratica, è necessario combinare la rappresentazione n-gram con una tecnica di riduzione della dimensionalità, come le *embedding*, di cui parleremo nella prossima unità.\n",
"\n",
"Per utilizzare una rappresentazione n-gram nel nostro dataset **AG News**, dobbiamo passare il parametro `ngrams` al costruttore di `TextVectorization`. La lunghezza di un vocabolario di bigrammi è **significativamente più grande**, nel nostro caso supera 1,3 milioni di token! Pertanto, ha senso limitare anche i token dei bigrammi a un numero ragionevole.\n",
"\n",
"Potremmo utilizzare lo stesso codice di cui sopra per addestrare il classificatore, tuttavia, sarebbe molto inefficiente in termini di memoria. Nella prossima unità, addestreremo il classificatore di bigrammi utilizzando le embedding. Nel frattempo, puoi sperimentare l'addestramento del classificatore di bigrammi in questo notebook e vedere se riesci a ottenere una precisione maggiore.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Calcolo automatico dei vettori BoW\n",
"\n",
"Nell'esempio sopra abbiamo calcolato i vettori BoW manualmente sommando le codifiche one-hot delle singole parole. Tuttavia, l'ultima versione di TensorFlow ci consente di calcolare automaticamente i vettori BoW passando il parametro `output_mode='count` al costruttore del vettorizzatore. Questo rende la definizione e l'addestramento del nostro modello significativamente più semplice:\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": [
"## Frequenza termine - frequenza inversa del documento (TF-IDF)\n",
"\n",
"Nella rappresentazione BoW, le occorrenze delle parole vengono pesate utilizzando la stessa tecnica indipendentemente dalla parola stessa. Tuttavia, è evidente che parole frequenti come *a* e *in* sono molto meno importanti per la classificazione rispetto ai termini specializzati. Nella maggior parte dei compiti di NLP alcune parole sono più rilevanti di altre.\n",
"\n",
"**TF-IDF** sta per **frequenza termine - frequenza inversa del documento**. È una variazione del bag-of-words, dove invece di un valore binario 0/1 che indica la presenza di una parola in un documento, viene utilizzato un valore in virgola mobile, che è correlato alla frequenza di occorrenza della parola nel corpus.\n",
"\n",
"Più formalmente, il peso $w_{ij}$ di una parola $i$ nel documento $j$ è definito come:\n",
"$$\n",
"w_{ij} = tf_{ij}\\times\\log({N\\over df_i})\n",
"$$\n",
"dove\n",
"* $tf_{ij}$ è il numero di occorrenze di $i$ in $j$, ovvero il valore BoW che abbiamo visto prima\n",
"* $N$ è il numero di documenti nella collezione\n",
"* $df_i$ è il numero di documenti che contengono la parola $i$ nell'intera collezione\n",
"\n",
"Il valore TF-IDF $w_{ij}$ aumenta proporzionalmente al numero di volte in cui una parola appare in un documento ed è compensato dal numero di documenti nel corpus che contengono la parola, il che aiuta a correggere il fatto che alcune parole appaiono più frequentemente di altre. Ad esempio, se la parola appare in *ogni* documento della collezione, $df_i=N$, e $w_{ij}=0$, e quei termini verrebbero completamente ignorati.\n",
"\n",
"Puoi facilmente creare una vettorizzazione TF-IDF del testo utilizzando 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, il livello `TextVectorization` può calcolare automaticamente le frequenze TF-IDF passando il parametro `output_mode='tf-idf'`. Ripetiamo il codice che abbiamo utilizzato sopra per vedere se l'uso di TF-IDF aumenta l'accuratezza:\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": [
"## Conclusione\n",
"\n",
"Anche se le rappresentazioni TF-IDF assegnano pesi di frequenza a diverse parole, non sono in grado di rappresentare il significato o l'ordine. Come disse il famoso linguista J. R. Firth nel 1935: \"Il significato completo di una parola è sempre contestuale, e nessuno studio del significato al di fuori del contesto può essere preso sul serio.\" Più avanti nel corso impareremo come catturare le informazioni contestuali dai testi utilizzando il language modeling.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Disclaimer**: \nQuesto documento è stato tradotto utilizzando il servizio di traduzione automatica [Co-op Translator](https://github.com/Azure/co-op-translator). Sebbene ci impegniamo per garantire l'accuratezza, si prega di notare che le traduzioni automatiche possono contenere errori o imprecisioni. Il documento originale nella sua lingua nativa dovrebbe essere considerato la fonte autorevole. Per informazioni critiche, si raccomanda una traduzione professionale effettuata da un traduttore umano. Non siamo responsabili per eventuali incomprensioni o interpretazioni errate derivanti dall'uso di questa traduzione.\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-28T14:36:25+00:00",
"source_file": "lessons/5-NLP/13-TextRep/TextRepresentationTF.ipynb",
"language_code": "it"
}
},
"nbformat": 4,
"nbformat_minor": 4
}