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

647 lines
27 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Textklassifizierungsaufgabe\n",
"\n",
"In diesem Modul beginnen wir mit einer einfachen Textklassifizierungsaufgabe basierend auf dem **[AG_NEWS](http://www.di.unipi.it/~gulli/AG_corpus_of_news_articles.html)**-Datensatz: Wir werden Nachrichtenüberschriften in eine von vier Kategorien einordnen: Welt, Sport, Wirtschaft und Wissenschaft/Technik.\n",
"\n",
"## Der Datensatz\n",
"\n",
"Um den Datensatz zu laden, verwenden wir die **[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": [
"Wir können nun auf die Trainings- und Testteile des Datensatzes zugreifen, indem wir `dataset['train']` und `dataset['test']` verwenden:\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": [
"Lassen Sie uns die ersten 10 neuen Schlagzeilen aus unserem Datensatz ausdrucken:\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": [
"## Textvektorisierung\n",
"\n",
"Nun müssen wir Text in **Zahlen** umwandeln, die als Tensoren dargestellt werden können. Wenn wir eine Wortebene-Darstellung möchten, müssen wir zwei Dinge tun:\n",
"\n",
"* Einen **Tokenizer** verwenden, um den Text in **Token** zu zerlegen.\n",
"* Ein **Vokabular** dieser Token erstellen.\n",
"\n",
"### Begrenzung der Vokabulargröße\n",
"\n",
"Im Beispiel des AG News-Datensatzes ist die Vokabulargröße ziemlich groß, mehr als 100.000 Wörter. Allgemein gesprochen benötigen wir keine Wörter, die selten im Text vorkommen — nur wenige Sätze enthalten sie, und das Modell wird nicht von ihnen lernen. Daher ist es sinnvoll, die Vokabulargröße auf eine kleinere Anzahl zu begrenzen, indem ein Argument an den Vektorisierer-Konstruktor übergeben wird:\n",
"\n",
"Beide dieser Schritte können mit der **TextVectorization**-Schicht durchgeführt werden. Lassen Sie uns das Vektorisierungsobjekt instanziieren und anschließend die `adapt`-Methode aufrufen, um den gesamten Text zu durchlaufen und ein Vokabular zu erstellen:\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": [
"> **Hinweis**: Wir verwenden nur einen Teil des gesamten Datensatzes, um ein Vokabular zu erstellen. Dies tun wir, um die Ausführungszeit zu verkürzen und Sie nicht warten zu lassen. Allerdings gehen wir das Risiko ein, dass einige Wörter aus dem gesamten Datensatz nicht in das Vokabular aufgenommen werden und während des Trainings ignoriert werden. Die Verwendung der gesamten Vokabulargröße und das Durchlaufen des gesamten Datensatzes während `adapt` sollte die endgültige Genauigkeit erhöhen, jedoch nicht signifikant.\n",
"\n",
"Nun können wir auf das tatsächliche Vokabular zugreifen:\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": [
"Mit dem Vektorisierer können wir problemlos jeden Text in eine Zahlenmenge kodieren:\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 Textdarstellung\n",
"\n",
"Da Wörter Bedeutung vermitteln, können wir manchmal die Bedeutung eines Textes allein durch die Betrachtung der einzelnen Wörter erkennen, unabhängig von ihrer Reihenfolge im Satz. Zum Beispiel deuten beim Klassifizieren von Nachrichten Wörter wie *Wetter* und *Schnee* wahrscheinlich auf eine *Wettervorhersage* hin, während Wörter wie *Aktien* und *Dollar* eher auf *Finanznachrichten* hindeuten.\n",
"\n",
"Die **Bag-of-words** (BoW)-Vektordarstellung ist die einfachste und am leichtesten verständliche traditionelle Vektordarstellung. Jedes Wort wird einem Vektorindex zugeordnet, und ein Vektorelement enthält die Anzahl der Vorkommen jedes Wortes in einem bestimmten Dokument.\n",
"\n",
"![Bild, das zeigt, wie eine Bag-of-words-Vektordarstellung im Speicher repräsentiert wird.](../../../../../lessons/5-NLP/13-TextRep/images/bag-of-words-example.png) \n",
"\n",
"> **Note**: Sie können sich BoW auch als die Summe aller One-Hot-encodierten Vektoren für die einzelnen Wörter im Text vorstellen.\n",
"\n",
"Unten sehen Sie ein Beispiel, wie man mit der Scikit Learn Python-Bibliothek eine Bag-of-words-Darstellung erzeugen kann:\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": [
"Wir können auch den Keras-Vektorisierer verwenden, den wir oben definiert haben, indem wir jede Wortnummer in eine One-Hot-Codierung umwandeln und alle diese Vektoren addieren:\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": [
"> **Hinweis**: Es könnte Sie überraschen, dass das Ergebnis sich vom vorherigen Beispiel unterscheidet. Der Grund dafür ist, dass im Keras-Beispiel die Länge des Vektors der Größe des Vokabulars entspricht, das aus dem gesamten AG News-Datensatz erstellt wurde, während wir im Scikit-Learn-Beispiel das Vokabular spontan aus dem Beispieltext erstellt haben.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Training des BoW-Klassifikators\n",
"\n",
"Jetzt, da wir gelernt haben, wie man die Bag-of-Words-Darstellung unseres Textes erstellt, können wir einen Klassifikator trainieren, der diese verwendet. Zuerst müssen wir unser Dataset in eine Bag-of-Words-Darstellung umwandeln. Dies kann mit der `map`-Funktion auf folgende Weise erreicht werden:\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": [
"Lassen Sie uns nun ein einfaches Klassifikator-Neuronales Netzwerk definieren, das eine lineare Schicht enthält. Die Eingabegröße ist `vocab_size`, und die Ausgabengröße entspricht der Anzahl der Klassen (4). Da wir eine Klassifikationsaufgabe lösen, ist die endgültige Aktivierungsfunktion **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": [
"Da wir 4 Klassen haben, ist eine Genauigkeit von über 80 % ein gutes Ergebnis.\n",
"\n",
"## Einen Klassifikator als ein Netzwerk trainieren\n",
"\n",
"Da der Vektorisierer ebenfalls eine Keras-Schicht ist, können wir ein Netzwerk definieren, das ihn einschließt, und es vollständig trainieren. Auf diese Weise müssen wir den Datensatz nicht mit `map` vektorisieren, sondern können den ursprünglichen Datensatz direkt an den Eingang des Netzwerks übergeben.\n",
"\n",
"> **Hinweis**: Wir müssten dennoch `map` auf unseren Datensatz anwenden, um Felder aus Wörterbüchern (wie `title`, `description` und `label`) in Tupel umzuwandeln. Wenn wir die Daten jedoch von der Festplatte laden, können wir von Anfang an einen Datensatz mit der erforderlichen Struktur erstellen.\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": [
"## Bigramme, Trigramme und N-Gramme\n",
"\n",
"Eine Einschränkung des Bag-of-Words-Ansatzes ist, dass einige Wörter Teil von mehrwortigen Ausdrücken sind. Zum Beispiel hat das Wort 'Hot Dog' eine völlig andere Bedeutung als die Wörter 'hot' und 'dog' in anderen Kontexten. Wenn wir die Wörter 'hot' und 'dog' immer mit denselben Vektoren darstellen, kann dies unser Modell verwirren.\n",
"\n",
"Um dies zu lösen, werden häufig **N-Gramm-Darstellungen** in Methoden der Dokumentklassifikation verwendet, bei denen die Häufigkeit jedes Wortes, Zwei-Wort- oder Drei-Wort-Ausdrucks eine nützliche Eigenschaft für das Training von Klassifikatoren darstellt. In Bigramm-Darstellungen fügen wir beispielsweise alle Wortpaare zusätzlich zu den ursprünglichen Wörtern dem Vokabular hinzu.\n",
"\n",
"Unten sehen Sie ein Beispiel, wie man eine Bigramm-Bag-of-Words-Darstellung mit Scikit Learn erzeugt:\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": [
"Der Hauptnachteil des n-Gramm-Ansatzes ist, dass die Größe des Vokabulars extrem schnell wächst. In der Praxis müssen wir die n-Gramm-Repräsentation mit einer Technik zur Dimensionsreduktion kombinieren, wie zum Beispiel *Embeddings*, die wir in der nächsten Einheit besprechen werden.\n",
"\n",
"Um eine n-Gramm-Repräsentation in unserem **AG News**-Datensatz zu verwenden, müssen wir den Parameter `ngrams` an den `TextVectorization`-Konstruktor übergeben. Die Länge eines Bigramm-Vokabulars ist **deutlich größer**, in unserem Fall sind es mehr als 1,3 Millionen Tokens! Daher ist es sinnvoll, auch die Bigramm-Tokens auf eine vernünftige Anzahl zu begrenzen.\n",
"\n",
"Wir könnten denselben Code wie oben verwenden, um den Klassifikator zu trainieren, allerdings wäre das sehr speicherineffizient. In der nächsten Einheit werden wir den Bigramm-Klassifikator mithilfe von Embeddings trainieren. In der Zwischenzeit kannst du mit dem Training eines Bigramm-Klassifikators in diesem Notebook experimentieren und sehen, ob du eine höhere Genauigkeit erzielen kannst.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Automatisches Berechnen von BoW-Vektoren\n",
"\n",
"Im obigen Beispiel haben wir BoW-Vektoren manuell berechnet, indem wir die One-Hot-Codierungen einzelner Wörter summiert haben. Die neueste Version von TensorFlow ermöglicht es uns jedoch, BoW-Vektoren automatisch zu berechnen, indem wir den Parameter `output_mode='count'` an den Konstruktor des Vektorisierers übergeben. Dies vereinfacht das Definieren und Trainieren unseres Modells erheblich:\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": [
"## Termfrequenz - inverse Dokumentfrequenz (TF-IDF)\n",
"\n",
"In der BoW-Darstellung werden Wortvorkommen unabhängig vom Wort selbst mit derselben Technik gewichtet. Es ist jedoch offensichtlich, dass häufige Wörter wie *a* und *in* für die Klassifikation viel weniger wichtig sind als spezialisierte Begriffe. Bei den meisten NLP-Aufgaben sind einige Wörter relevanter als andere.\n",
"\n",
"**TF-IDF** steht für **Termfrequenz - inverse Dokumentfrequenz**. Es handelt sich um eine Variation des Bag-of-Words-Modells, bei der anstelle eines binären 0/1-Wertes, der das Auftreten eines Wortes in einem Dokument angibt, ein Gleitkommawert verwendet wird, der mit der Häufigkeit des Wortvorkommens im Korpus zusammenhängt.\n",
"\n",
"Formal wird das Gewicht $w_{ij}$ eines Wortes $i$ im Dokument $j$ wie folgt definiert:\n",
"$$\n",
"w_{ij} = tf_{ij}\\times\\log({N\\over df_i})\n",
"$$\n",
"wobei\n",
"* $tf_{ij}$ die Anzahl der Vorkommen von $i$ in $j$ ist, also der BoW-Wert, den wir zuvor gesehen haben\n",
"* $N$ die Anzahl der Dokumente in der Sammlung ist\n",
"* $df_i$ die Anzahl der Dokumente ist, die das Wort $i$ in der gesamten Sammlung enthalten\n",
"\n",
"Der TF-IDF-Wert $w_{ij}$ steigt proportional zur Häufigkeit, mit der ein Wort in einem Dokument erscheint, und wird durch die Anzahl der Dokumente im Korpus, die das Wort enthalten, ausgeglichen. Dies hilft, den Umstand zu berücksichtigen, dass einige Wörter häufiger vorkommen als andere. Wenn beispielsweise ein Wort in *jedem* Dokument der Sammlung vorkommt, gilt $df_i=N$, und $w_{ij}=0$, und diese Begriffe würden vollständig ignoriert.\n",
"\n",
"Mit Scikit Learn können Sie ganz einfach eine TF-IDF-Vektorisierung von Text erstellen:\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 kann die `TextVectorization`-Schicht automatisch TF-IDF-Frequenzen berechnen, indem der Parameter `output_mode='tf-idf'` übergeben wird. Lassen Sie uns den oben verwendeten Code wiederholen, um zu sehen, ob die Verwendung von TF-IDF die Genauigkeit erhöht:\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": [
"## Fazit\n",
"\n",
"Auch wenn TF-IDF-Darstellungen Häufigkeitsgewichte für verschiedene Wörter bereitstellen, sind sie nicht in der Lage, Bedeutung oder Reihenfolge abzubilden. Wie der berühmte Linguist J. R. Firth 1935 sagte: \"Die vollständige Bedeutung eines Wortes ist immer kontextabhängig, und keine Untersuchung der Bedeutung ohne Kontext kann ernst genommen werden.\" Später im Kurs werden wir lernen, wie man kontextuelle Informationen aus Texten mithilfe von Sprachmodellen erfasst.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n---\n\n**Haftungsausschluss**: \nDieses Dokument wurde mit dem KI-Übersetzungsdienst [Co-op Translator](https://github.com/Azure/co-op-translator) übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.\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-31T17:18:38+00:00",
"source_file": "lessons/5-NLP/13-TextRep/TextRepresentationTF.ipynb",
"language_code": "de"
}
},
"nbformat": 4,
"nbformat_minor": 4
}