AI-For-Beginners/translations/de/lessons/5-NLP/17-GenerativeNetworks/GenerativeTF.ipynb

497 lines
28 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Generative Netzwerke\n",
"\n",
"Rekurrente neuronale Netzwerke (RNNs) und ihre Varianten mit gated Zellen wie Long Short Term Memory Cells (LSTMs) und Gated Recurrent Units (GRUs) bieten einen Mechanismus für Sprachmodellierung, d.h. sie können die Reihenfolge von Wörtern lernen und Vorhersagen für das nächste Wort in einer Sequenz treffen. Dies ermöglicht es uns, RNNs für **generative Aufgaben** zu nutzen, wie z.B. gewöhnliche Textgenerierung, maschinelle Übersetzung und sogar Bildbeschriftung.\n",
"\n",
"In der RNN-Architektur, die wir in der vorherigen Einheit besprochen haben, hat jede RNN-Einheit den nächsten versteckten Zustand als Ausgabe erzeugt. Wir können jedoch auch eine weitere Ausgabe zu jeder rekurrenten Einheit hinzufügen, die es uns ermöglicht, eine **Sequenz** auszugeben (die genauso lang ist wie die ursprüngliche Sequenz). Darüber hinaus können wir RNN-Einheiten verwenden, die bei jedem Schritt keine Eingabe akzeptieren, sondern nur einen anfänglichen Zustandsvektor nehmen und dann eine Sequenz von Ausgaben erzeugen.\n",
"\n",
"In diesem Notebook konzentrieren wir uns auf einfache generative Modelle, die uns helfen, Text zu generieren. Der Einfachheit halber bauen wir ein **zeichenbasiertes Netzwerk**, das Text Buchstabe für Buchstabe generiert. Während des Trainings müssen wir einen Textkorpus nehmen und ihn in Buchstabenfolgen aufteilen.\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",
"import numpy as np\n",
"\n",
"ds_train, ds_test = tfds.load('ag_news_subset').values()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Aufbau eines Zeichen-Vokabulars\n",
"\n",
"Um ein generatives Netzwerk auf Zeichenebene zu erstellen, müssen wir den Text in einzelne Zeichen statt in Wörter aufteilen. Die `TextVectorization`-Schicht, die wir bisher verwendet haben, kann das nicht, daher haben wir zwei Möglichkeiten:\n",
"\n",
"* Den Text manuell laden und die Tokenisierung \"von Hand\" durchführen, wie in [diesem offiziellen Keras-Beispiel](https://keras.io/examples/generative/lstm_character_level_text_generation/)\n",
"* Die `Tokenizer`-Klasse für die Tokenisierung auf Zeichenebene verwenden.\n",
"\n",
"Wir entscheiden uns für die zweite Option. Mit `Tokenizer` kann man auch in Wörter tokenisieren, sodass man relativ einfach zwischen Tokenisierung auf Zeichen- und Wortebene wechseln kann.\n",
"\n",
"Um eine Tokenisierung auf Zeichenebene durchzuführen, müssen wir den Parameter `char_level=True` übergeben:\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"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",
"tokenizer = keras.preprocessing.text.Tokenizer(char_level=True,lower=False)\n",
"tokenizer.fit_on_texts([x['title'].numpy().decode('utf-8') for x in ds_train])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Wir möchten auch ein spezielles Token verwenden, um das **Ende der Sequenz** zu kennzeichnen, das wir `<eos>` nennen werden. Lassen Sie uns dieses manuell zum Vokabular hinzufügen:\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"eos_token = len(tokenizer.word_index)+1\n",
"tokenizer.word_index['<eos>'] = eos_token\n",
"\n",
"vocab_size = eos_token + 1"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Um Text in Zahlenfolgen zu kodieren, können wir verwenden:\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[[48, 2, 10, 10, 5, 44, 1, 25, 5, 8, 10, 13, 78]]"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"tokenizer.texts_to_sequences(['Hello, world!'])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Training eines generativen RNN zur Erstellung von Titeln\n",
"\n",
"Die Methode, mit der wir ein RNN trainieren, um Nachrichtentitel zu generieren, ist wie folgt: In jedem Schritt nehmen wir einen Titel, der in ein RNN eingespeist wird, und für jedes Eingabezeichen bitten wir das Netzwerk, das nächste Ausgabezeichen zu erzeugen:\n",
"\n",
"![Bild zeigt ein Beispiel für die RNN-Generierung des Wortes 'HELLO'.](../../../../../lessons/5-NLP/17-GenerativeNetworks/images/rnn-generate.png)\n",
"\n",
"Für das letzte Zeichen unserer Sequenz bitten wir das Netzwerk, das `<eos>`-Token zu generieren.\n",
"\n",
"Der Hauptunterschied bei dem generativen RNN, das wir hier verwenden, besteht darin, dass wir die Ausgabe von jedem Schritt des RNN nehmen und nicht nur von der letzten Zelle. Dies kann erreicht werden, indem der Parameter `return_sequences` für die RNN-Zelle angegeben wird.\n",
"\n",
"Während des Trainings wäre die Eingabe für das Netzwerk also eine Sequenz von codierten Zeichen einer bestimmten Länge, und die Ausgabe wäre eine Sequenz derselben Länge, jedoch um ein Element verschoben und mit `<eos>` abgeschlossen. Ein Minibatch besteht aus mehreren solchen Sequenzen, und wir müssen **Padding** verwenden, um alle Sequenzen auszurichten.\n",
"\n",
"Lassen Sie uns Funktionen erstellen, die den Datensatz für uns transformieren. Da wir Sequenzen auf Minibatch-Ebene auffüllen möchten, werden wir den Datensatz zunächst durch Aufruf von `.batch()` gruppieren und ihn dann mit `map` transformieren. Die Transformationsfunktion nimmt also ein ganzes Minibatch als Parameter:\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"def title_batch(x):\n",
" x = [t.numpy().decode('utf-8') for t in x]\n",
" z = tokenizer.texts_to_sequences(x)\n",
" z = tf.keras.preprocessing.sequence.pad_sequences(z)\n",
" return tf.one_hot(z,vocab_size), tf.one_hot(tf.concat([z[:,1:],tf.constant(eos_token,shape=(len(z),1))],axis=1),vocab_size)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Einige wichtige Dinge, die wir hier tun: \n",
"* Zuerst extrahieren wir den eigentlichen Text aus dem String-Tensor \n",
"* `text_to_sequences` konvertiert die Liste von Strings in eine Liste von Integer-Tensoren \n",
"* `pad_sequences` füllt diese Tensoren auf ihre maximale Länge auf \n",
"* Schließlich führen wir eine One-Hot-Codierung aller Zeichen durch, verschieben sie und fügen `<eos>` hinzu. Wir werden bald sehen, warum wir One-Hot-codierte Zeichen benötigen \n",
"\n",
"Diese Funktion ist jedoch **Pythonic**, d.h. sie kann nicht automatisch in ein Tensorflow-Berechnungsdiagramm übersetzt werden. Wir erhalten Fehler, wenn wir versuchen, diese Funktion direkt in der `Dataset.map`-Funktion zu verwenden. Wir müssen diesen Pythonic-Aufruf mit dem `py_function`-Wrapper umschließen: \n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"def title_batch_fn(x):\n",
" x = x['title']\n",
" a,b = tf.py_function(title_batch,inp=[x],Tout=(tf.float32,tf.float32))\n",
" return a,b"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **Hinweis**: Der Unterschied zwischen Pythonischen und Tensorflow-Transformationsfunktionen mag etwas zu komplex erscheinen, und Sie fragen sich vielleicht, warum wir den Datensatz nicht mit Standard-Python-Funktionen transformieren, bevor wir ihn an `fit` übergeben. Obwohl dies definitiv möglich ist, hat die Verwendung von `Dataset.map` einen großen Vorteil, da die Datenverarbeitungspipeline mit dem Tensorflow-Berechnungsgraphen ausgeführt wird. Dieser nutzt GPU-Berechnungen und minimiert die Notwendigkeit, Daten zwischen CPU und GPU hin- und herzuschieben.\n",
"\n",
"Nun können wir unser Generator-Netzwerk erstellen und mit dem Training beginnen. Es kann auf jeder rekurrenten Zelle basieren, die wir in der vorherigen Einheit besprochen haben (einfach, LSTM oder GRU). In unserem Beispiel verwenden wir LSTM.\n",
"\n",
"Da das Netzwerk Zeichen als Eingabe erhält und die Vokabulargröße relativ klein ist, benötigen wir keine Embedding-Schicht. Die One-Hot-kodierte Eingabe kann direkt in die LSTM-Zelle eingehen. Die Ausgabeschicht wäre ein `Dense`-Klassifikator, der die LSTM-Ausgabe in One-Hot-kodierte Token-Nummern umwandelt.\n",
"\n",
"Außerdem, da wir es mit Sequenzen variabler Länge zu tun haben, können wir die `Masking`-Schicht verwenden, um eine Maske zu erstellen, die den gepolsterten Teil der Zeichenkette ignoriert. Dies ist nicht unbedingt erforderlich, da wir uns nicht besonders für alles interessieren, was über das `<eos>`-Token hinausgeht. Aber wir werden es verwenden, um etwas Erfahrung mit diesem Schichttyp zu sammeln. `input_shape` wäre `(None, vocab_size)`, wobei `None` die Sequenz variabler Länge angibt, und die Ausgabeschicht ist ebenfalls `(None, vocab_size)`, wie Sie aus der `summary` sehen können:\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model: \"sequential\"\n",
"_________________________________________________________________\n",
"Layer (type) Output Shape Param # \n",
"=================================================================\n",
"masking (Masking) (None, None, 84) 0 \n",
"_________________________________________________________________\n",
"lstm (LSTM) (None, None, 128) 109056 \n",
"_________________________________________________________________\n",
"dense (Dense) (None, None, 84) 10836 \n",
"=================================================================\n",
"Total params: 119,892\n",
"Trainable params: 119,892\n",
"Non-trainable params: 0\n",
"_________________________________________________________________\n",
"15000/15000 [==============================] - 229s 15ms/step - loss: 1.5385\n"
]
},
{
"data": {
"text/plain": [
"<tensorflow.python.keras.callbacks.History at 0x7fa40c1245e0>"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model = keras.models.Sequential([\n",
" keras.layers.Masking(input_shape=(None,vocab_size)),\n",
" keras.layers.LSTM(128,return_sequences=True),\n",
" keras.layers.Dense(vocab_size,activation='softmax')\n",
"])\n",
"\n",
"model.summary()\n",
"model.compile(loss='categorical_crossentropy')\n",
"\n",
"model.fit(ds_train.batch(8).map(title_batch_fn))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Generieren von Ausgaben\n",
"\n",
"Nachdem wir das Modell trainiert haben, möchten wir es verwenden, um einige Ausgaben zu erzeugen. Zunächst benötigen wir eine Möglichkeit, Text zu dekodieren, der durch eine Sequenz von Token-Nummern dargestellt wird. Dafür könnten wir die Funktion `tokenizer.sequences_to_texts` verwenden; allerdings funktioniert sie nicht gut mit einer Tokenisierung auf Zeichenebene. Daher nehmen wir ein Wörterbuch der Tokens aus dem Tokenizer (genannt `word_index`), erstellen eine umgekehrte Zuordnung und schreiben unsere eigene Dekodierungsfunktion:\n"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"reverse_map = {val:key for key, val in tokenizer.word_index.items()}\n",
"\n",
"def decode(x):\n",
" return ''.join([reverse_map[t] for t in x])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Nun beginnen wir mit einer Zeichenkette `start`, kodieren sie in eine Sequenz `inp`, und rufen dann bei jedem Schritt unser Netzwerk auf, um das nächste Zeichen zu bestimmen.\n",
"\n",
"Die Ausgabe des Netzwerks `out` ist ein Vektor mit `vocab_size` Elementen, der die Wahrscheinlichkeiten jedes Tokens darstellt. Mit `argmax` können wir die Nummer des wahrscheinlichsten Tokens finden. Dieses Zeichen fügen wir dann der generierten Liste von Tokens hinzu und setzen die Generierung fort. Dieser Prozess, bei dem ein Zeichen generiert wird, wird `size`-mal wiederholt, um die benötigte Anzahl von Zeichen zu erzeugen. Die Generierung wird vorzeitig beendet, wenn das `eos_token` erreicht wird.\n"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'Today #39;s lead to strike for the strike for the strike for the strike (AFP)'"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def generate(model,size=100,start='Today '):\n",
" inp = tokenizer.texts_to_sequences([start])[0]\n",
" chars = inp\n",
" for i in range(size):\n",
" out = model(tf.expand_dims(tf.one_hot(inp,vocab_size),0))[0][-1]\n",
" nc = tf.argmax(out)\n",
" if nc==eos_token:\n",
" break\n",
" chars.append(nc.numpy())\n",
" inp = inp+[nc]\n",
" return decode(chars)\n",
" \n",
"generate(model)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Ausgabe während des Trainings sampeln\n",
"\n",
"Da wir keine nützlichen Metriken wie *Genauigkeit* haben, ist die einzige Möglichkeit, zu überprüfen, ob unser Modell besser wird, das **Sampeln** von generierten Zeichenketten während des Trainings. Dafür verwenden wir **Callbacks**, also Funktionen, die wir an die `fit`-Funktion übergeben können und die während des Trainings regelmäßig aufgerufen werden.\n"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch 1/3\n",
"15000/15000 [==============================] - 226s 15ms/step - loss: 1.2703\n",
"Today #39;s a lead in the company for the strike\n",
"Epoch 2/3\n",
"15000/15000 [==============================] - 227s 15ms/step - loss: 1.2057\n",
"Today #39;s the Market Service on Security Start (AP)\n",
"Epoch 3/3\n",
"15000/15000 [==============================] - 226s 15ms/step - loss: 1.1752\n",
"Today #39;s a line on the strike to start for the start\n"
]
},
{
"data": {
"text/plain": [
"<tensorflow.python.keras.callbacks.History at 0x7fa40c74e3d0>"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"sampling_callback = keras.callbacks.LambdaCallback(\n",
" on_epoch_end = lambda batch, logs: print(generate(model))\n",
")\n",
"\n",
"model.fit(ds_train.batch(8).map(title_batch_fn),callbacks=[sampling_callback],epochs=3)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Dieses Beispiel erzeugt bereits ziemlich guten Text, aber es gibt mehrere Möglichkeiten, ihn weiter zu verbessern:\n",
"\n",
"* **Mehr Text**. Wir haben nur Titel für unsere Aufgabe verwendet, aber es könnte sinnvoll sein, mit vollständigem Text zu experimentieren. Beachten Sie, dass RNNs nicht besonders gut mit langen Sequenzen umgehen können. Daher macht es Sinn, entweder die Texte in kürzere Sätze aufzuteilen oder immer mit einer festen Sequenzlänge eines vordefinierten Werts `num_chars` (z. B. 256) zu trainieren. Sie könnten das obige Beispiel in eine solche Architektur umwandeln, indem Sie sich vom [offiziellen Keras-Tutorial](https://keras.io/examples/generative/lstm_character_level_text_generation/) inspirieren lassen.\n",
"\n",
"* **Mehrschichtige LSTM**. Es könnte sinnvoll sein, 2 oder 3 Schichten von LSTM-Zellen auszuprobieren. Wie wir in der vorherigen Einheit erwähnt haben, extrahiert jede Schicht eines LSTM bestimmte Muster aus dem Text. Bei einem zeichenbasierten Generator können wir erwarten, dass die unteren LSTM-Schichten für die Extraktion von Silben verantwortlich sind, während die höheren Schichten Wörter und Wortkombinationen erkennen. Dies kann einfach implementiert werden, indem ein Parameter für die Anzahl der Schichten an den LSTM-Konstruktor übergeben wird.\n",
"\n",
"* Sie könnten auch mit **GRU-Einheiten** experimentieren, um zu sehen, welche besser abschneiden, sowie mit **unterschiedlichen Größen der versteckten Schichten**. Eine zu große versteckte Schicht könnte zu Overfitting führen (z. B. lernt das Netzwerk den genauen Text auswendig), während eine kleinere Größe möglicherweise keine guten Ergebnisse liefert.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Weiche Textgenerierung und Temperatur\n",
"\n",
"In der vorherigen Definition von `generate` haben wir immer das Zeichen mit der höchsten Wahrscheinlichkeit als nächstes Zeichen im generierten Text ausgewählt. Dies führte oft dazu, dass sich der Text zwischen denselben Zeichenfolgen immer wieder \"wiederholte\", wie in diesem Beispiel:\n",
"```\n",
"today of the second the company and a second the company ...\n",
"```\n",
"\n",
"Wenn wir uns jedoch die Wahrscheinlichkeitsverteilung für das nächste Zeichen ansehen, könnte es sein, dass der Unterschied zwischen den höchsten Wahrscheinlichkeiten nicht groß ist, z. B. kann ein Zeichen eine Wahrscheinlichkeit von 0,2 haben, ein anderes - 0,19 usw. Wenn wir beispielsweise das nächste Zeichen in der Sequenz '*play*' suchen, könnte das nächste Zeichen genauso gut ein Leerzeichen oder ein **e** sein (wie im Wort *player*).\n",
"\n",
"Das führt uns zu der Erkenntnis, dass es nicht immer \"fair\" ist, das Zeichen mit der höchsten Wahrscheinlichkeit auszuwählen, da die Wahl des zweitwahrscheinlichsten Zeichens dennoch zu sinnvollem Text führen kann. Es ist klüger, Zeichen aus der Wahrscheinlichkeitsverteilung zu **samplen**, die durch die Netzwerkausgabe gegeben ist.\n",
"\n",
"Dieses Sampling kann mit der Funktion `np.multinomial` durchgeführt werden, die die sogenannte **multinomiale Verteilung** implementiert. Eine Funktion, die diese **weiche** Textgenerierung umsetzt, ist unten definiert:\n"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"--- Temperature = 0.3\n",
"Today #39;s strike #39; to start at the store return\n",
"On Sunday PO to Be Data Profit Up (Reuters)\n",
"Moscow, SP wins straight to the Microsoft #39;s control of the space start\n",
"President olding of the blast start for the strike to pay &lt;b&gt;...&lt;/b&gt;\n",
"Little red riding hood ficed to the spam countered in European &lt;b&gt;...&lt;/b&gt;\n",
"\n",
"--- Temperature = 0.8\n",
"Today countie strikes ryder missile faces food market blut\n",
"On Sunday collores lose-toppy of sale of Bullment in &lt;b&gt;...&lt;/b&gt;\n",
"Moscow, IBM Diffeiting in Afghan Software Hotels (Reuters)\n",
"President Ol Luster for Profit Peaced Raised (AP)\n",
"Little red riding hood dace on depart talks #39; bank up\n",
"\n",
"--- Temperature = 1.0\n",
"Today wits House buiting debate fixes #39; supervice stake again\n",
"On Sunday arling digital poaching In for level\n",
"Moscow, DS Up 7, Top Proble Protest Caprey Mamarian Strike\n",
"President teps help of roubler stepted lessabul-Dhalitics (AFP)\n",
"Little red riding hood signs on cash in Carter-youb\n",
"\n",
"--- Temperature = 1.3\n",
"Today wits flawer ro, pSIA figat's co DroftwavesIs Talo up\n",
"On Sunday hround elitwing wint EU Powerburlinetien\n",
"Moscow, Bazz #39;s sentries olymen winnelds' next for Olympite Huc?\n",
"President lost securitys from power Elections in Smiltrials\n",
"Little red riding hood vides profit, exponituity, profitmainalist-at said listers\n",
"\n",
"--- Temperature = 1.8\n",
"Today #39;It: He deat: N.KA Asside\n",
"On Sunday i arry Par aldeup patient Wo stele1\n"
]
},
{
"ename": "KeyError",
"evalue": "0",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-33-db32367a0feb>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mf\"\\n--- Temperature = {i}\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mj\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m5\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 20\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgenerate_soft\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmodel\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0msize\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m300\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mstart\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mwords\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mj\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mtemperature\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;32m<ipython-input-33-db32367a0feb>\u001b[0m in \u001b[0;36mgenerate_soft\u001b[0;34m(model, size, start, temperature)\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0mchars\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnc\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 12\u001b[0m \u001b[0minp\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0minp\u001b[0m\u001b[0;34m+\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mnc\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 13\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mdecode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mchars\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 14\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[0mwords\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m'Today '\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'On Sunday '\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'Moscow, '\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'President '\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'Little red riding hood '\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m<ipython-input-10-3f5fa6130b1d>\u001b[0m in \u001b[0;36mdecode\u001b[0;34m(x)\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mdecode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0;34m''\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mreverse_map\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mt\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mt\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;32m<ipython-input-10-3f5fa6130b1d>\u001b[0m in \u001b[0;36m<listcomp>\u001b[0;34m(.0)\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mdecode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0;34m''\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mreverse_map\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mt\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mt\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mKeyError\u001b[0m: 0"
]
}
],
"source": [
"def generate_soft(model,size=100,start='Today ',temperature=1.0):\n",
" inp = tokenizer.texts_to_sequences([start])[0]\n",
" chars = inp\n",
" for i in range(size):\n",
" out = model(tf.expand_dims(tf.one_hot(inp,vocab_size),0))[0][-1]\n",
" probs = tf.exp(tf.math.log(out)/temperature).numpy().astype(np.float64)\n",
" probs = probs/np.sum(probs)\n",
" nc = np.argmax(np.random.multinomial(1,probs,1))\n",
" if nc==eos_token:\n",
" break\n",
" chars.append(nc)\n",
" inp = inp+[nc]\n",
" return decode(chars)\n",
"\n",
"words = ['Today ','On Sunday ','Moscow, ','President ','Little red riding hood ']\n",
" \n",
"for i in [0.3,0.8,1.0,1.3,1.8]:\n",
" print(f\"\\n--- Temperature = {i}\")\n",
" for j in range(5):\n",
" print(generate_soft(model,size=300,start=words[j],temperature=i))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Wir haben einen weiteren Parameter namens **Temperatur** eingeführt, der angibt, wie strikt wir uns an die höchste Wahrscheinlichkeit halten sollten. Wenn die Temperatur 1,0 beträgt, führen wir eine faire multinomiale Stichprobe durch, und wenn die Temperatur gegen unendlich geht, werden alle Wahrscheinlichkeiten gleich, und wir wählen zufällig das nächste Zeichen aus. Im untenstehenden Beispiel können wir beobachten, dass der Text bedeutungslos wird, wenn wir die Temperatur zu stark erhöhen, und er ähnelt einem \"zyklischen\" hart generierten Text, wenn er sich näher an 0 bewegt.\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": "16af2a8bbb083ea23e5e41c7f5787656b2ce26968575d8763f2c4b17f9cd711f"
},
"kernelspec": {
"display_name": "Python 3.8.12 ('py38')",
"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"
},
"coopTranslator": {
"original_hash": "9fbb7d5fda708537649f71f5f646fcde",
"translation_date": "2025-08-31T16:50:57+00:00",
"source_file": "lessons/5-NLP/17-GenerativeNetworks/GenerativeTF.ipynb",
"language_code": "de"
}
},
"nbformat": 4,
"nbformat_minor": 4
}