AI-For-Beginners/translations/de/lessons/5-NLP/16-RNN/RNNTF.ipynb

460 lines
25 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Rekurrente neuronale Netze\n",
"\n",
"Im vorherigen Modul haben wir uns mit reichhaltigen semantischen Repräsentationen von Texten beschäftigt. Die Architektur, die wir verwendet haben, erfasst die aggregierte Bedeutung der Wörter in einem Satz, berücksichtigt jedoch nicht die **Reihenfolge** der Wörter, da die Aggregationsoperation, die den Einbettungen folgt, diese Information aus dem ursprünglichen Text entfernt. Da diese Modelle die Wortreihenfolge nicht darstellen können, sind sie nicht in der Lage, komplexere oder mehrdeutige Aufgaben wie Textgenerierung oder Beantwortung von Fragen zu lösen.\n",
"\n",
"Um die Bedeutung einer Textsequenz zu erfassen, verwenden wir eine neuronale Netzwerkarchitektur namens **rekurrentes neuronales Netz** (RNN). Bei der Verwendung eines RNN führen wir unseren Satz Token für Token durch das Netzwerk, und das Netzwerk erzeugt einen **Zustand**, den wir dann mit dem nächsten Token erneut in das Netzwerk einspeisen.\n",
"\n",
"![Bild, das ein Beispiel für die Generierung eines rekurrenten neuronalen Netzes zeigt.](../../../../../lessons/5-NLP/16-RNN/images/rnn.png)\n",
"\n",
"Angenommen, wir haben eine Eingabesequenz von Tokens $X_0,\\dots,X_n$, dann erstellt das RNN eine Sequenz von neuronalen Netzwerkblöcken und trainiert diese Sequenz end-to-end mithilfe von Backpropagation. Jeder Netzwerkblock nimmt ein Paar $(X_i,S_i)$ als Eingabe und erzeugt $S_{i+1}$ als Ergebnis. Der finale Zustand $S_n$ oder die Ausgabe $Y_n$ wird in einen linearen Klassifikator eingespeist, um das Ergebnis zu erzeugen. Alle Netzwerkblöcke teilen sich die gleichen Gewichte und werden in einem einzigen Backpropagation-Durchlauf end-to-end trainiert.\n",
"\n",
"> Die obige Abbildung zeigt ein rekurrentes neuronales Netz in entfalteter Form (links) und in kompakter rekurrenter Darstellung (rechts). Es ist wichtig zu verstehen, dass alle RNN-Zellen die gleichen **teilbaren Gewichte** haben.\n",
"\n",
"Da Zustandsvektoren $S_0,\\dots,S_n$ durch das Netzwerk weitergegeben werden, kann das RNN sequentielle Abhängigkeiten zwischen Wörtern lernen. Zum Beispiel kann es, wenn das Wort *nicht* irgendwo in der Sequenz erscheint, lernen, bestimmte Elemente innerhalb des Zustandsvektors zu negieren.\n",
"\n",
"Innerhalb jeder RNN-Zelle befinden sich zwei Gewichtsmatrizen: $W_H$ und $W_I$, sowie ein Bias $b$. Bei jedem RNN-Schritt wird der Ausgabestatus wie folgt berechnet: $S_{i+1} = f(W_H\\times S_i + W_I\\times X_i+b)$, wobei $f$ eine Aktivierungsfunktion ist (oft $\\tanh$).\n",
"\n",
"> Bei Problemen wie der Textgenerierung (die wir im nächsten Abschnitt behandeln werden) oder der maschinellen Übersetzung möchten wir auch bei jedem RNN-Schritt einen Ausgabewert erhalten. In diesem Fall gibt es eine weitere Matrix $W_O$, und die Ausgabe wird berechnet als $Y_i=f(W_O\\times S_i+b_O)$.\n",
"\n",
"Schauen wir uns an, wie rekurrente neuronale Netze uns dabei helfen können, unser Nachrichten-Dataset zu klassifizieren.\n",
"\n",
"> Für die Sandbox-Umgebung müssen wir die folgende Zelle ausführen, um sicherzustellen, dass die erforderliche Bibliothek installiert ist und die Daten vorab geladen werden. Wenn Sie lokal arbeiten, können Sie die folgende Zelle überspringen.\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import sys\n",
"!{sys.executable} -m pip install --quiet tensorflow_datasets==4.4.0\n",
"!cd ~ && wget -q -O - https://mslearntensorflowlp.blob.core.windows.net/data/tfds-ag-news.tgz | tar xz"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"import tensorflow as tf\n",
"from tensorflow import keras\n",
"import tensorflow_datasets as tfds\n",
"import numpy as np\n",
"\n",
"# We are going to be training pretty large models. In order not to face errors, we need\n",
"# to 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",
"ds_train, ds_test = tfds.load('ag_news_subset').values()"
]
},
{
"cell_type": "markdown",
"metadata": {
"nteract": {
"transient": {
"deleting": false
}
}
},
"source": [
"Beim Training großer Modelle kann die Zuweisung von GPU-Speicher problematisch werden. Außerdem müssen wir möglicherweise mit verschiedenen Minibatch-Größen experimentieren, damit die Daten in den GPU-Speicher passen und das Training dennoch schnell genug ist. Wenn Sie diesen Code auf Ihrer eigenen GPU-Maschine ausführen, können Sie mit der Anpassung der Minibatch-Größe experimentieren, um das Training zu beschleunigen.\n",
"\n",
"> **Hinweis**: Es ist bekannt, dass bestimmte Versionen von NVidia-Treibern den Speicher nach dem Training des Modells nicht freigeben. In diesem Notebook führen wir mehrere Beispiele aus, was dazu führen kann, dass der Speicher in bestimmten Konfigurationen erschöpft wird, insbesondere wenn Sie eigene Experimente im selben Notebook durchführen. Wenn Sie auf seltsame Fehler stoßen, wenn Sie mit dem Training des Modells beginnen, sollten Sie den Notebook-Kernel neu starten.\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": true,
"jupyter": {
"outputs_hidden": false,
"source_hidden": false
},
"nteract": {
"transient": {
"deleting": false
}
}
},
"outputs": [],
"source": [
"batch_size = 16\n",
"embed_size = 64"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Einfacher RNN-Klassifikator\n",
"\n",
"Bei einem einfachen RNN ist jede rekurrente Einheit ein einfaches lineares Netzwerk, das einen Eingabevektor und einen Zustandsvektor aufnimmt und einen neuen Zustandsvektor erzeugt. In Keras kann dies durch die `SimpleRNN`-Schicht dargestellt werden.\n",
"\n",
"Obwohl wir der RNN-Schicht direkt one-hot-codierte Tokens übergeben könnten, ist dies aufgrund ihrer hohen Dimensionalität keine gute Idee. Daher verwenden wir eine Embedding-Schicht, um die Dimensionalität der Wortvektoren zu reduzieren, gefolgt von einer RNN-Schicht und schließlich einem `Dense`-Klassifikator.\n",
"\n",
"> **Hinweis**: In Fällen, in denen die Dimensionalität nicht so hoch ist, wie beispielsweise bei der Tokenisierung auf Zeichenebene, könnte es sinnvoll sein, one-hot-codierte Tokens direkt in die RNN-Zelle einzuspeisen.\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model: \"sequential\"\n",
"_________________________________________________________________\n",
"Layer (type) Output Shape Param # \n",
"=================================================================\n",
"text_vectorization (TextVect (None, None) 0 \n",
"_________________________________________________________________\n",
"embedding (Embedding) (None, None, 64) 1280000 \n",
"_________________________________________________________________\n",
"simple_rnn (SimpleRNN) (None, 16) 1296 \n",
"_________________________________________________________________\n",
"dense (Dense) (None, 4) 68 \n",
"=================================================================\n",
"Total params: 1,281,364\n",
"Trainable params: 1,281,364\n",
"Non-trainable params: 0\n",
"_________________________________________________________________\n"
]
}
],
"source": [
"vocab_size = 20000\n",
"\n",
"vectorizer = keras.layers.experimental.preprocessing.TextVectorization(\n",
" max_tokens=vocab_size,\n",
" input_shape=(1,))\n",
"\n",
"model = keras.models.Sequential([\n",
" vectorizer,\n",
" keras.layers.Embedding(vocab_size, embed_size),\n",
" keras.layers.SimpleRNN(16),\n",
" keras.layers.Dense(4,activation='softmax')\n",
"])\n",
"\n",
"model.summary()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **Hinweis:** Hier verwenden wir eine untrainierte Einbettungsschicht zur Vereinfachung, aber für bessere Ergebnisse können wir eine vortrainierte Einbettungsschicht mit Word2Vec verwenden, wie im vorherigen Abschnitt beschrieben. Es wäre eine gute Übung für dich, diesen Code so anzupassen, dass er mit vortrainierten Einbettungen funktioniert.\n",
"\n",
"Nun lassen wir unser RNN trainieren. RNNs sind im Allgemeinen recht schwierig zu trainieren, da die Anzahl der Schichten, die bei der Rückpropagation beteiligt sind, sehr groß wird, sobald die RNN-Zellen entlang der Sequenzlänge entfaltet werden. Daher müssen wir eine kleinere Lernrate wählen und das Netzwerk auf einem größeren Datensatz trainieren, um gute Ergebnisse zu erzielen. Dies kann ziemlich lange dauern, daher wird die Verwendung einer GPU empfohlen.\n",
"\n",
"Um den Prozess zu beschleunigen, werden wir das RNN-Modell nur mit Nachrichtentiteln trainieren und die Beschreibung weglassen. Du kannst versuchen, mit der Beschreibung zu trainieren und sehen, ob du das Modell zum Laufen bringen kannst.\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Training vectorizer\n"
]
}
],
"source": [
"def extract_title(x):\n",
" return x['title']\n",
"\n",
"def tupelize_title(x):\n",
" return (extract_title(x),x['label'])\n",
"\n",
"print('Training vectorizer')\n",
"vectorizer.adapt(ds_train.take(2000).map(extract_title))"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"7500/7500 [==============================] - 82s 11ms/step - loss: 0.6629 - acc: 0.7623 - val_loss: 0.5559 - val_acc: 0.7995\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n"
]
},
{
"data": {
"text/plain": [
"<tensorflow.python.keras.callbacks.History at 0x7f3e0030d350>"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'], optimizer='adam')\n",
"model.fit(ds_train.map(tupelize_title).batch(batch_size),validation_data=ds_test.map(tupelize_title).batch(batch_size))"
]
},
{
"cell_type": "markdown",
"metadata": {
"nteract": {
"transient": {
"deleting": false
}
}
},
"source": [
"> **Hinweis**: Die Genauigkeit ist hier wahrscheinlich geringer, da wir nur mit Nachrichtentiteln trainieren.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Überprüfung von variablen Sequenzen\n",
"\n",
"Denken Sie daran, dass die `TextVectorization`-Schicht automatisch Sequenzen mit variabler Länge in einem Minibatch mit Pad-Tokens auffüllt. Es stellt sich heraus, dass diese Tokens auch am Training teilnehmen und die Konvergenz des Modells erschweren können.\n",
"\n",
"Es gibt mehrere Ansätze, die wir verfolgen können, um die Menge an Padding zu minimieren. Einer davon ist, den Datensatz nach Sequenzlänge neu zu ordnen und alle Sequenzen nach Größe zu gruppieren. Dies kann mit der Funktion `tf.data.experimental.bucket_by_sequence_length` durchgeführt werden (siehe [Dokumentation](https://www.tensorflow.org/api_docs/python/tf/data/experimental/bucket_by_sequence_length)).\n",
"\n",
"Ein weiterer Ansatz ist die Verwendung von **Maskierung**. In Keras unterstützen einige Schichten zusätzliche Eingaben, die zeigen, welche Tokens beim Training berücksichtigt werden sollen. Um Maskierung in unser Modell zu integrieren, können wir entweder eine separate `Masking`-Schicht einfügen ([Dokumentation](https://keras.io/api/layers/core_layers/masking/)) oder den Parameter `mask_zero=True` in unserer `Embedding`-Schicht angeben.\n",
"\n",
"> **Note**: Dieses Training wird etwa 5 Minuten dauern, um eine Epoche auf dem gesamten Datensatz abzuschließen. Sie können das Training jederzeit unterbrechen, wenn Sie die Geduld verlieren. Alternativ können Sie die Menge der für das Training verwendeten Daten begrenzen, indem Sie nach den Datensätzen `ds_train` und `ds_test` eine `.take(...)`-Klausel hinzufügen.\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"7500/7500 [==============================] - 371s 49ms/step - loss: 0.5401 - acc: 0.8079 - val_loss: 0.3780 - val_acc: 0.8822\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n"
]
},
{
"data": {
"text/plain": [
"<tensorflow.python.keras.callbacks.History at 0x7f3dec118850>"
]
},
"execution_count": 7,
"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",
"model = keras.models.Sequential([\n",
" vectorizer,\n",
" keras.layers.Embedding(vocab_size,embed_size,mask_zero=True),\n",
" keras.layers.SimpleRNN(16),\n",
" keras.layers.Dense(4,activation='softmax')\n",
"])\n",
"\n",
"model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'], optimizer='adam')\n",
"model.fit(ds_train.map(tupelize).batch(batch_size),validation_data=ds_test.map(tupelize).batch(batch_size))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Jetzt, da wir Maskierung verwenden, können wir das Modell mit dem gesamten Datensatz aus Titeln und Beschreibungen trainieren.\n",
"\n",
"> **Hinweis**: Ist Ihnen aufgefallen, dass wir einen Vektorisierer verwenden, der auf den Nachrichtentiteln trainiert wurde, und nicht auf dem gesamten Artikeltext? Das könnte dazu führen, dass einige Tokens ignoriert werden. Es wäre daher besser, den Vektorisierer neu zu trainieren. Allerdings könnte der Effekt nur sehr gering sein, daher bleiben wir der Einfachheit halber beim vorher trainierten Vektorisierer.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## LSTM: Langzeit-Kurzzeitspeicher\n",
"\n",
"Eines der Hauptprobleme von RNNs sind **verschwindende Gradienten**. RNNs können ziemlich lang sein und haben möglicherweise Schwierigkeiten, die Gradienten während der Rückwärtspropagation bis zur ersten Schicht des Netzwerks zurückzuführen. Wenn dies passiert, kann das Netzwerk keine Beziehungen zwischen weit entfernten Tokens lernen. Eine Möglichkeit, dieses Problem zu vermeiden, besteht darin, **explizites Zustandsmanagement** durch den Einsatz von **Gates** einzuführen. Die beiden gängigsten Architekturen, die Gates verwenden, sind **Langzeit-Kurzzeitspeicher** (LSTM) und **Gated Relay Unit** (GRU). Hier werden wir uns mit LSTMs beschäftigen.\n",
"\n",
"![Bild, das eine Beispielzelle eines Langzeit-Kurzzeitspeichers zeigt](../../../../../lessons/5-NLP/16-RNN/images/long-short-term-memory-cell.svg)\n",
"\n",
"Ein LSTM-Netzwerk ist ähnlich wie ein RNN organisiert, aber es gibt zwei Zustände, die von Schicht zu Schicht weitergegeben werden: den tatsächlichen Zustand $c$ und den versteckten Vektor $h$. In jeder Einheit wird der versteckte Vektor $h_{t-1}$ mit der Eingabe $x_t$ kombiniert, und zusammen steuern sie, was mit dem Zustand $c_t$ und der Ausgabe $h_{t}$ durch **Gates** geschieht. Jedes Gate hat eine Sigmoid-Aktivierung (Ausgabe im Bereich $[0,1]$), die als bitweises Maskieren betrachtet werden kann, wenn sie mit dem Zustandsvektor multipliziert wird. LSTMs haben die folgenden Gates (von links nach rechts im obigen Bild):\n",
"* **Vergessens-Gate**, das bestimmt, welche Komponenten des Vektors $c_{t-1}$ wir vergessen und welche wir durchlassen müssen.\n",
"* **Eingabe-Gate**, das bestimmt, wie viele Informationen aus dem Eingabevektor und dem vorherigen versteckten Vektor in den Zustandsvektor aufgenommen werden sollen.\n",
"* **Ausgabe-Gate**, das den neuen Zustandsvektor nimmt und entscheidet, welche seiner Komponenten verwendet werden, um den neuen versteckten Vektor $h_t$ zu erzeugen.\n",
"\n",
"Die Komponenten des Zustands $c$ können als Flags betrachtet werden, die ein- und ausgeschaltet werden können. Zum Beispiel, wenn wir im Sequenzverlauf den Namen *Alice* sehen, vermuten wir, dass es sich um eine Frau handelt, und setzen das Flag im Zustand, das anzeigt, dass wir ein weibliches Substantiv im Satz haben. Wenn wir später die Wörter *und Tom* sehen, setzen wir das Flag, das anzeigt, dass wir ein Plural-Substantiv haben. Durch die Manipulation des Zustands können wir also die grammatikalischen Eigenschaften des Satzes verfolgen.\n",
"\n",
"> **Note**: Hier ist eine großartige Ressource, um die Interna von LSTMs zu verstehen: [Understanding LSTM Networks](https://colah.github.io/posts/2015-08-Understanding-LSTMs/) von Christopher Olah.\n",
"\n",
"Obwohl die interne Struktur einer LSTM-Zelle komplex erscheinen mag, verbirgt Keras diese Implementierung in der `LSTM`-Schicht. Das Einzige, was wir im obigen Beispiel tun müssen, ist, die rekurrente Schicht zu ersetzen:\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"15000/15000 [==============================] - 188s 13ms/step - loss: 0.5692 - acc: 0.7916 - val_loss: 0.3441 - val_acc: 0.8870\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n"
]
},
{
"data": {
"text/plain": [
"<tensorflow.python.keras.callbacks.History at 0x7f3d6af5c350>"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model = keras.models.Sequential([\n",
" vectorizer,\n",
" keras.layers.Embedding(vocab_size, embed_size),\n",
" keras.layers.LSTM(8),\n",
" keras.layers.Dense(4,activation='softmax')\n",
"])\n",
"\n",
"model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'], optimizer='adam')\n",
"model.fit(ds_train.map(tupelize).batch(8),validation_data=ds_test.map(tupelize).batch(8))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Bidirektionale und mehrschichtige RNNs\n",
"\n",
"In unseren bisherigen Beispielen arbeiten die rekurrenten Netzwerke von Anfang bis Ende einer Sequenz. Das erscheint uns natürlich, da es der Richtung entspricht, in der wir lesen oder Sprache hören. Für Szenarien, die einen zufälligen Zugriff auf die Eingabesequenz erfordern, ist es jedoch sinnvoller, die rekurrente Berechnung in beide Richtungen auszuführen. RNNs, die Berechnungen in beide Richtungen ermöglichen, werden als **bidirektionale** RNNs bezeichnet, und sie können erstellt werden, indem die rekurrente Schicht mit einer speziellen `Bidirectional`-Schicht umwickelt wird.\n",
"\n",
"> **Note**: Die `Bidirectional`-Schicht erstellt zwei Kopien der darin enthaltenen Schicht und setzt die Eigenschaft `go_backwards` einer dieser Kopien auf `True`, sodass sie in die entgegengesetzte Richtung entlang der Sequenz läuft.\n",
"\n",
"Rekurrente Netzwerke, ob unidirektional oder bidirektional, erfassen Muster innerhalb einer Sequenz und speichern sie in Zustandsvektoren oder geben sie als Ausgabe zurück. Wie bei konvolutionalen Netzwerken können wir eine weitere rekurrente Schicht hinzufügen, die der ersten folgt, um höherwertige Muster zu erfassen, die aus niedrigeren Mustern bestehen, die von der ersten Schicht extrahiert wurden. Dies führt uns zum Konzept eines **mehrschichtigen RNN**, das aus zwei oder mehr rekurrenten Netzwerken besteht, wobei die Ausgabe der vorherigen Schicht als Eingabe an die nächste Schicht weitergegeben wird.\n",
"\n",
"![Bild, das ein mehrschichtiges Long-Short-Term-Memory-RNN zeigt](../../../../../lessons/5-NLP/16-RNN/images/multi-layer-lstm.jpg)\n",
"\n",
"*Bild aus [diesem großartigen Beitrag](https://towardsdatascience.com/from-a-lstm-cell-to-a-multilayer-lstm-network-with-pytorch-2899eb5696f3) von Fernando López.*\n",
"\n",
"Keras macht den Aufbau dieser Netzwerke zu einer einfachen Aufgabe, da Sie einfach weitere rekurrente Schichten zum Modell hinzufügen müssen. Für alle Schichten außer der letzten müssen wir den Parameter `return_sequences=True` angeben, da wir möchten, dass die Schicht alle Zwischenzustände zurückgibt und nicht nur den Endzustand der rekurrenten Berechnung.\n",
"\n",
"Lassen Sie uns ein zweischichtiges bidirektionales LSTM für unser Klassifizierungsproblem erstellen.\n",
"\n",
"> **Note** Dieser Code benötigt erneut ziemlich viel Zeit, um abgeschlossen zu werden, aber er liefert uns die höchste Genauigkeit, die wir bisher gesehen haben. Es könnte sich also lohnen, zu warten und das Ergebnis zu sehen.\n"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"5044/7500 [===================>..........] - ETA: 2:33 - loss: 0.3709 - acc: 0.8706\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r5045/7500 [===================>..........] - ETA: 2:33 - loss: 0.3709 - acc: 0.8706"
]
}
],
"source": [
"model = keras.models.Sequential([\n",
" vectorizer,\n",
" keras.layers.Embedding(vocab_size, 128, mask_zero=True),\n",
" keras.layers.Bidirectional(keras.layers.LSTM(64,return_sequences=True)),\n",
" keras.layers.Bidirectional(keras.layers.LSTM(64)), \n",
" keras.layers.Dense(4,activation='softmax')\n",
"])\n",
"\n",
"model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'], optimizer='adam')\n",
"model.fit(ds_train.map(tupelize).batch(batch_size),\n",
" validation_data=ds_test.map(tupelize).batch(batch_size))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## RNNs für andere Aufgaben\n",
"\n",
"Bis jetzt haben wir uns darauf konzentriert, RNNs zur Klassifikation von Textsequenzen zu verwenden. Aber sie können noch viele weitere Aufgaben bewältigen, wie zum Beispiel Textgenerierung und maschinelle Übersetzung — diese Aufgaben werden wir in der nächsten Einheit betrachten.\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": {
"kernel_info": {
"name": "conda-env-py37_tensorflow-py"
},
"kernelspec": {
"display_name": "py37_tensorflow",
"language": "python",
"name": "conda-env-py37_tensorflow-py"
},
"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.7.9"
},
"nteract": {
"version": "nteract-front-end@1.0.0"
},
"coopTranslator": {
"original_hash": "81351e61f619b432ff51010a4f993194",
"translation_date": "2025-08-31T17:05:22+00:00",
"source_file": "lessons/5-NLP/16-RNN/RNNTF.ipynb",
"language_code": "de"
}
},
"nbformat": 4,
"nbformat_minor": 4
}