Autoencoder in TensorFlow mit Beispiel
Was ist Autoencoder im Deep Learning?
An Autoencoder ist ein Tool zum effizienten Erlernen der Datencodierung auf unbeaufsichtigte Weise. Dabei handelt es sich um eine Art künstliches neuronales Netzwerk, das Ihnen hilft, die Darstellung von Datensätzen zur Dimensionsreduzierung zu erlernen, indem es das neuronale Netzwerk so trainiert, dass es das Signalrauschen ignoriert. Es ist ein großartiges Werkzeug zum Wiederherstellen einer Eingabe.
Mit einfachen Worten: Die Maschine nimmt beispielsweise ein Bild auf und kann ein eng damit verbundenes Bild erzeugen. Der Input in diese Art von neuronalem Netzwerk ist unbeschriftet, was bedeutet, dass das Netzwerk ohne Aufsicht lernen kann. Genauer gesagt wird die Eingabe vom Netzwerk codiert, um sich nur auf das kritischste Merkmal zu konzentrieren. Dies ist einer der Gründe, warum Autoencoder zur Dimensionsreduzierung beliebt sind. Außerdem können Autoencoder zur Produktion verwendet werden generative Lernmodelle. Beispielsweise kann das neuronale Netzwerk mit einer Reihe von Gesichtern trainiert werden und dann neue Gesichter erzeugen.
Wie funktioniert der TensorFlow Autoencoder?
Der Zweck eines Autoencoders besteht darin, eine Annäherung an die Eingabe zu erzeugen, indem er sich nur auf die wesentlichen Merkmale konzentriert. Sie denken vielleicht, warum nicht einfach lernen, wie man die Eingabe kopiert und einfügt, um die Ausgabe zu erzeugen. Tatsächlich handelt es sich bei einem Autoencoder um eine Reihe von Einschränkungen, die das Netzwerk dazu zwingen, neue Wege zur Darstellung der Daten zu erlernen, die sich vom bloßen Kopieren der Ausgabe unterscheiden.
Ein typischer Autoencoder ist mit einer Eingabe, einer internen Darstellung und einer Ausgabe (einer Näherung der Eingabe) definiert. Das Lernen erfolgt in den Schichten, die mit der internen Darstellung verbunden sind. Tatsächlich gibt es zwei Hauptschichtenblöcke, die wie ein traditionelles neuronales Netzwerk aussehen. Der kleine Unterschied besteht darin, dass die Ebene, die die Ausgabe enthält, der Eingabe entsprechen muss. Im Bild unten geht die ursprüngliche Eingabe in den ersten Block mit der Bezeichnung Encoder. Diese interne Darstellung komprimiert (reduziert) die Größe der Eingabe. Im zweiten Block erfolgt die Rekonstruktion der Eingabe. Dies ist die Dekodierungsphase.
Das Modell aktualisiert die Gewichte durch Minimierung der Verlustfunktion. Das Modell wird bestraft, wenn sich die Rekonstruktionsausgabe von der Eingabe unterscheidet.
Stellen Sie sich konkret ein Bild mit einer Größe von 50×50 (also 250 Pixel) und ein neuronales Netzwerk mit nur einer verborgenen Schicht vor, die aus hundert Neuronen besteht. Das Lernen erfolgt auf einer Feature-Map, die doppelt so groß ist wie die Eingabe. Das bedeutet, dass das Netzwerk einen Weg finden muss, 250 Pixel mit nur einem Neuronenvektor von 100 zu rekonstruieren.
Beispiel für einen gestapelten Autoencoder
In diesem Autoencoder-Tutorial lernen Sie, wie Sie einen gestapelten Autoencoder verwenden. Die Architektur ähnelt einem herkömmlichen neuronalen Netzwerk. Die Eingabe geht an eine verborgene Schicht, um komprimiert oder verkleinert zu werden, und erreicht dann die Rekonstruktionsschichten. Ziel ist es, ein Ausgabebild zu erzeugen, das dem Original so nahe kommt. Das Modell muss einen Weg finden, seine Aufgabe unter bestimmten Einschränkungen zu erfüllen, d. h. mit einer niedrigeren Dimension.
Heutzutage sind Autoencoder in Tiefes Lernen werden hauptsächlich zum Entrauschen eines Bildes verwendet. Stellen Sie sich ein Bild mit Kratzern vor; ein Mensch ist immer noch in der Lage, den Inhalt zu erkennen. Die Idee des Autoencoders zur Rauschunterdrückung besteht darin, dem Bild Rauschen hinzuzufügen, um das Netzwerk zu zwingen, das Muster hinter den Daten zu lernen.
Die andere nützliche Familie von Autoencoder Deep Learning ist der Variations-Autoencoder. Diese Art von Netzwerk kann neue Bilder generieren. Stellen Sie sich vor, Sie trainieren ein Netzwerk mit dem Bild eines Mannes. Ein solches Netzwerk kann neue Gesichter hervorbringen.
So erstellen Sie einen Autoencoder mit TensorFlow
In diesem Tutorial erfahren Sie, wie Sie einen gestapelten Autoencoder erstellen, um ein Bild zu rekonstruieren.
Sie werden die verwenden CIFAR-10-Datensatz die 60000 32×32 Farbbilder enthält. Der Autoencoder-Datensatz ist bereits in 50000 Bilder für das Training und 10000 für Tests aufgeteilt. Es gibt bis zu zehn Klassen:
- Flugzeug
- Automobile
- Vogel
- Katze
- Hirsch
- Hund
- Frosch
- Pferd
- Schiff
- LKW
Sie müssen die Bilder unter dieser URL https://www.cs.toronto.edu/~kriz/cifar.html herunterladen und entpacken. Der Ordner for-10-batches-py enthält fünf Datenstapel mit jeweils 10000 Bildern in zufälliger Reihenfolge.
Bevor Sie Ihr Modell erstellen und trainieren, müssen Sie einige Datenverarbeitungsvorgänge durchführen. Sie gehen wie folgt vor:
- Importieren Sie die Daten
- Konvertieren Sie die Daten in das Schwarzweißformat
- Hängen Sie alle Stapel an
- Konstruieren Sie den Trainingsdatensatz
- Konstruieren Sie einen Bildvisualisierer
Bildvorverarbeitung
Schritt 1) Importieren Sie die Daten
Laut der offiziellen Website können Sie die Daten mit dem folgenden Code hochladen. Der Autoencoder-Code lädt die Daten in ein Wörterbuch mit dem die Datenerfassung und den Etikette. Beachten Sie, dass der Code eine Funktion ist.
import numpy as np import tensorflow as tf import pickle def unpickle(file): import pickle with open(file, 'rb') as fo: dict = pickle.load(fo, encoding='latin1') return dict
Schritt 2) Konvertieren Sie die Daten in das Schwarzweißformat
Der Einfachheit halber konvertieren Sie die Daten in Graustufen. Das heißt, mit nur einer Dimension gegenüber drei für das Farbbild. Die meisten neuronalen Netzwerke funktionieren nur mit einer eindimensionalen Eingabe.
def grayscale(im): return im.reshape(im.shape[0], 3, 32, 32).mean(1).reshape(im.shape[0], -1)
Schritt 3) Hängen Sie alle Stapel an
Nachdem beide Funktionen erstellt und der Datensatz geladen wurden, können Sie eine Schleife schreiben, um die Daten im Speicher anzuhängen. Wenn Sie sorgfältig prüfen, heißt die Entpackdatei mit den Daten data_batch_ und hat eine Zahl von 1 bis 5. Sie können die Dateien durchlaufen und an die Daten anhängen.
Wenn dieser Schritt abgeschlossen ist, konvertieren Sie die Farbdaten in ein Graustufenformat. Wie Sie sehen können, ist die Form der Daten 50000 und 1024. Die 32*32 Pixel sind jetzt auf 2014 reduziert.
# Load the data into memory data, labels = [], [] ## Loop over the b for i in range(1, 6): filename = './cifar-10-batches-py/data_batch_' + str(i) open_data = unpickle(filename) if len(data) > 0: data = np.vstack((data, open_data['data'])) labels = np.hstack((labels, open_data['labels'])) else: data = open_data['data'] labels = open_data['labels'] data = grayscale(data) x = np.matrix(data) y = np.array(labels) print(x.shape) (50000, 1024)
Hinweis: Ändern Sie „./cifar-10-batches-py/data_batch_“ in den tatsächlichen Speicherort Ihrer Datei. Zum Beispiel für Windows Maschine, der Pfad könnte sein: filename = 'E:\cifar-10-batches-py\data_batch_' + str(i)
Schritt 4) Erstellen Sie den Trainingsdatensatz
Um das Training schneller und einfacher zu gestalten, trainieren Sie ein Modell nur anhand der Pferdebilder. Die Pferde sind in den Labeldaten die siebte Klasse. Wie in der Dokumentation des CIFAR-10-Datensatzes erwähnt, enthält jede Klasse 5000 Bilder. Sie können die Form der Daten ausdrucken, um zu bestätigen, dass 5.000 Bilder mit 1024 Spalten vorhanden sind, wie unten gezeigt TensorFlow Beispielschritt für den Autoencoder.
horse_i = np.where(y == 7)[0] horse_x = x[horse_i] print(np.shape(horse_x)) (5000, 1024)
Schritt 5) Erstellen Sie einen Bildvisualisierer
Schließlich erstellen Sie eine Funktion zum Plotten der Bilder. Sie benötigen diese Funktion, um das rekonstruierte Bild vom Autoencoder zu drucken.
Eine einfache Möglichkeit, Bilder zu drucken, ist die Verwendung des Objekts imshow aus der Matplotlib-Bibliothek. Beachten Sie, dass Sie die Form der Daten von 1024 in 32*32 konvertieren müssen (dh das Format eines Bildes).
# To plot pretty figures %matplotlib inline import matplotlib import matplotlib.pyplot as plt def plot_image(image, shape=[32, 32], cmap = "Greys_r"): plt.imshow(image.reshape(shape), cmap=cmap,interpolation="nearest") plt.axis("off")
Die Funktion benötigt 3 Argumente:
- Bild: die Eingabe
- Form: Liste, die Dimension des Bildes
- Karte:Wählen Sie die Farbkarte. Standardmäßig grau
Sie können versuchen, das erste Bild im Datensatz darzustellen. Sie sollten einen Mann auf einem Pferd sehen.
plot_image(horse_x[1], shape=[32, 32], cmap = "Greys_r")
Stellen Sie den Datensatzschätzer ein
Nun gut, da der Datensatz nun einsatzbereit ist, können Sie mit der Verwendung von Tensorflow beginnen. Bevor wir das Modell erstellen, verwenden wir den Dataset-Schätzer von Tensorflow, um das Netzwerk zu versorgen.
Sie erstellen einen Datensatz mit dem TensorFlow-Schätzer. Um Ihren Geist zu erfrischen, müssen Sie Folgendes verwenden:
- from_tensor_slices
- wiederholen
- Portion
Der vollständige Code zum Erstellen des Datensatzes lautet:
dataset = tf.data.Dataset.from_tensor_slices(x).repeat().batch(batch_size)
Beachten Sie, dass x ein Platzhalter mit der folgenden Form ist:
- [None,n_inputs]: Auf „Keine“ setzen, da die Anzahl der Bildeinspeisungen in das Netzwerk gleich der Stapelgröße ist.
Weitere Einzelheiten finden Sie im Tutorial auf lineare Regression.
Danach müssen Sie den Iterator erstellen. Ohne diese Codezeile werden keine Daten durch die Pipeline geleitet.
iter = dataset.make_initializable_iterator() # create the iteratorfeatures = iter.get_next()
Da die Pipeline nun fertig ist, können Sie überprüfen, ob das erste Bild dasselbe wie zuvor ist (z. B. ein Mann auf einem Pferd).
Sie setzen die Batchgröße auf 1, weil Sie den Datensatz nur mit einem Bild füttern möchten. Sie können die Dimension der Daten mit print(sess.run(features).shape) sehen. Sie ist gleich (1, 1024). 1 bedeutet, dass jeweils nur ein Bild mit 1024 eingespeist wird. Wenn die Batchgröße auf zwei gesetzt ist, durchlaufen zwei Bilder die Pipeline. (Ändern Sie die Batchgröße nicht. Andernfalls wird ein Fehler ausgegeben. Es kann immer nur ein Bild gleichzeitig an die Funktion plot_image() gehen.
## Parameters n_inputs = 32 * 32 BATCH_SIZE = 1 batch_size = tf.placeholder(tf.int64) # using a placeholder x = tf.placeholder(tf.float32, shape=[None,n_inputs]) ## Dataset dataset = tf.data.Dataset.from_tensor_slices(x).repeat().batch(batch_size) iter = dataset.make_initializable_iterator() # create the iterator features = iter.get_next() ## Print the image with tf.Session() as sess: # feed the placeholder with data sess.run(iter.initializer, feed_dict={x: horse_x, batch_size: BATCH_SIZE}) print(sess.run(features).shape) plot_image(sess.run(features), shape=[32, 32], cmap = "Greys_r") (1, 1024)
Bauen Sie das Netzwerk auf
Es ist Zeit, das Netzwerk aufzubauen. Sie trainieren einen gestapelten Autoencoder, also ein Netzwerk mit mehreren verborgenen Schichten.
Ihr Netzwerk verfügt über eine Eingabeebene mit 1024 Punkten, also 32×32, der Form des Bildes.
Der Encoderblock verfügt über eine obere verborgene Schicht mit 300 Neuronen und eine zentrale Schicht mit 150 Neuronen. Der Decoderblock ist symmetrisch zum Encoder. Sie können das Netzwerk im Bild unten visualisieren. Beachten Sie, dass Sie die Werte versteckter und zentraler Ebenen ändern können.
Der Aufbau eines Autoencoders ist jedem anderen Deep-Learning-Modell sehr ähnlich.
Sie erstellen das Modell in den folgenden Schritten:
- Definieren Sie die Parameter
- Definieren Sie die Ebenen
- Definieren Sie die Architektur
- Definieren Sie die Optimierung
- Führen Sie das Modell aus
- Bewerten Sie das Modell
Im vorherigen Abschnitt haben Sie erfahren, wie Sie eine Pipeline zur Versorgung des Modells erstellen, sodass Sie den Datensatz nicht noch einmal erstellen müssen. Sie erstellen einen Autoencoder mit vier Ebenen. Sie verwenden die Xavier-Initialisierung. Dies ist eine Technik, um die anfänglichen Gewichte gleich der Varianz sowohl der Eingabe als auch der Ausgabe festzulegen. Abschließend nutzen Sie die Elu-Aktivierungsfunktion. Sie regulieren die Verlustfunktion mit dem L2-Regularisierer.
Schritt 1) Definieren Sie die Parameter
Der erste Schritt besteht darin, die Anzahl der Neuronen in jeder Schicht, die Lernrate und den Hyperparameter des Regularisierers zu definieren.
Davor importieren Sie die Funktion teilweise. Dies ist eine bessere Methode, um die Parameter der dichten Schichten zu definieren. Der folgende Code definiert die Werte der Autoencoder-Architektur. Wie bereits aufgeführt, hat der Autoencoder zwei Schichten, mit 300 Neuronen in der ersten Schicht und 150 in der zweiten Schicht. Ihre Werte werden in n_hidden_1 und n_hidden_2 gespeichert.
Sie müssen die Lernrate und den L2-Hyperparameter definieren. Die Werte werden in learning_rate und l2_reg gespeichert
from functools import partial ## Encoder n_hidden_1 = 300 n_hidden_2 = 150 # codings ## Decoder n_hidden_3 = n_hidden_1 n_outputs = n_inputs learning_rate = 0.01 l2_reg = 0.0001
Die Xavier-Initialisierungstechnik wird mit dem Objekt xavier_initializer aus dem Schätzer-Beitrag aufgerufen. Im selben Schätzer können Sie den Regularisierer mit l2_regularizer hinzufügen
## Define the Xavier initialization xav_init = tf.contrib.layers.xavier_initializer() ## Define the L2 regularizer l2_regularizer = tf.contrib.layers.l2_regularizer(l2_reg)
Schritt 2) Definieren Sie die Ebenen
Alle Parameter der dichten Schichten wurden eingestellt; Sie können alles in die Variable „dense_layer“ packen, indem Sie das Objekt „partial“ verwenden. dichte_Schicht, die die ELU-Aktivierung, die Xavier-Initialisierung und die L2-Regularisierung verwendet.
## Create the dense layer dense_layer = partial(tf.layers.dense, activation=tf.nn.elu, kernel_initializer=xav_init, kernel_regularizer=l2_regularizer)
Schritt 3) Definieren Sie die Architektur
Wenn Sie sich das Bild der Architektur ansehen, stellen Sie fest, dass das Netzwerk drei Schichten mit einer Ausgabeschicht stapelt. Im folgenden Code verbinden Sie die entsprechenden Schichten. Beispielsweise berechnet die erste Schicht das Skalarprodukt zwischen den Eingabematrizenmerkmalen und den Matrizen, die die 300 Gewichte enthalten. Nachdem das Skalarprodukt berechnet wurde, geht die Ausgabe an die Elu-Aktivierungsfunktion. Die Ausgabe wird zur Eingabe der nächsten Schicht, deshalb verwenden Sie sie, um hidden_2 usw. zu berechnen. Die Matrizenmultiplikation ist für jede Schicht gleich, da Sie dieselbe Aktivierungsfunktion verwenden. Beachten Sie, dass die letzte Schicht, Ausgaben, keine Aktivierungsfunktion anwendet. Das ist sinnvoll, da dies die rekonstruierte Eingabe ist
## Make the mat mul hidden_1 = dense_layer(features, n_hidden_1) hidden_2 = dense_layer(hidden_1, n_hidden_2) hidden_3 = dense_layer(hidden_2, n_hidden_3) outputs = dense_layer(hidden_3, n_outputs, activation=None)
Schritt 4) Definieren Sie die Optimierung
Der letzte Schritt besteht darin, den Optimierer zu konstruieren. Sie verwenden den mittleren quadratischen Fehler als Verlustfunktion. Wenn Sie sich an das Tutorial zur linearen Regression erinnern, wissen Sie, dass der MSE anhand der Differenz zwischen der vorhergesagten Ausgabe und der tatsächlichen Bezeichnung berechnet wird. Hier ist die Bezeichnung das Merkmal, da das Modell versucht, die Eingabe zu rekonstruieren. Daher benötigen Sie den Mittelwert der Differenzsumme des Quadrats zwischen vorhergesagter Ausgabe und Eingabe. Mit TensorFlow können Sie die Verlustfunktion wie folgt codieren:
loss = tf.reduce_mean(tf.square(outputs - features))
Dann müssen Sie die Verlustfunktion optimieren. Sie verwenden den Adam-Optimierer, um die Farbverläufe zu berechnen. Die Zielfunktion besteht darin, den Verlust zu minimieren.
## Optimize loss = tf.reduce_mean(tf.square(outputs - features)) optimizer = tf.train.AdamOptimizer(learning_rate) train = optimizer.minimize(loss)
Noch eine Einstellung vor dem Training des Modells. Sie möchten eine Stapelgröße von 150 verwenden, d. h. die Pipeline mit 150 Bildern pro Iteration versorgen. Sie müssen die Anzahl der Iterationen manuell berechnen. Dies ist trivial:
Wenn Sie jedes Mal 150 Bilder übergeben möchten und wissen, dass der Datensatz 5000 Bilder enthält, ist die Anzahl der Iterationen gleich . In Python können Sie die folgenden Codes ausführen und sicherstellen, dass die Ausgabe 33 ist:
BATCH_SIZE = 150 ### Number of batches : length dataset / batch size n_batches = horse_x.shape[0] // BATCH_SIZE print(n_batches) 33
Schritt 5) Führen Sie das Modell aus
Zu guter Letzt trainieren Sie das Modell. Sie trainieren das Modell mit 100 Epochen. Das heißt, das Modell sieht 100-mal so viele Bilder mit optimierten Gewichten.
Sie sind bereits mit den Codes zum Trainieren eines Modells in Tensorflow vertraut. Der kleine Unterschied besteht darin, dass die Daten vor der Ausführung des Trainings weitergeleitet werden. Auf diese Weise trainiert das Modell schneller.
Sie möchten den Verlust nach zehn Epochen ausdrucken, um zu sehen, ob das Modell etwas lernt (dh der Verlust abnimmt). Die Schulung dauert je nach Maschinenhardware 2 bis 5 Minuten.
## Set params n_epochs = 100 ## Call Saver to save the model and re-use it later during evaluation saver = tf.train.Saver() with tf.Session() as sess: sess.run(tf.global_variables_initializer()) # initialise iterator with train data sess.run(iter.initializer, feed_dict={x: horse_x, batch_size: BATCH_SIZE}) print('Training...') print(sess.run(features).shape) for epoch in range(n_epochs): for iteration in range(n_batches): sess.run(train) if epoch % 10 == 0: loss_train = loss.eval() # not shown print("\r{}".format(epoch), "Train MSE:", loss_train) #saver.save(sess, "./my_model_all_layers.ckpt") save_path = saver.save(sess, "./model.ckpt") print("Model saved in path: %s" % save_path) Training... (150, 1024) 0 Train MSE: 2934.455 10 Train MSE: 1672.676 20 Train MSE: 1514.709 30 Train MSE: 1404.3118 40 Train MSE: 1425.058 50 Train MSE: 1479.0631 60 Train MSE: 1609.5259 70 Train MSE: 1482.3223 80 Train MSE: 1445.7035 90 Train MSE: 1453.8597 Model saved in path: ./model.ckpt
Schritt 6) Bewerten Sie das Modell
Nachdem Sie Ihr Modell nun trainiert haben, ist es an der Zeit, es zu bewerten. Sie müssen den Testsatz aus der Datei /cifar-10-batches-py/ importieren.
test_data = unpickle('./cifar-10-batches-py/test_batch') test_x = grayscale(test_data['data']) #test_labels = np.array(test_data['labels'])
HINWEIS: Für ein Windows Maschine wird der Code zu test_data = unpickle(r“E:\cifar-10-batches-py\test_batch“)
Sie können versuchen, die Bilder 13 auszudrucken, bei denen es sich um ein Pferd handelt
plot_image(test_x[13], shape=[32, 32], cmap = "Greys_r")
Um das Modell auszuwerten, verwenden Sie den Pixelwert dieses Bildes und prüfen, ob der Encoder dasselbe Bild nach der Verkleinerung um 1024 Pixel rekonstruieren kann. Beachten Sie, dass Sie eine Funktion definieren, um das Modell anhand verschiedener Bilder auszuwerten. Lediglich bei Pferden dürfte das Modell besser funktionieren.
Die Funktion benötigt zwei Argumente:
- df: Testdaten importieren
- Bildnummer: Geben Sie an, welches Bild importiert werden soll
Die Funktion gliedert sich in drei Teile:
- Formen Sie das Bild auf die richtige Dimension um, z. B. 1, 1024
- Füttere das Modell mit dem unsichtbaren Bild und kodiere/dekodiere das Bild
- Drucken Sie das echte und rekonstruierte Bild
def reconstruct_image(df, image_number = 1): ## Part 1: Reshape the image to the correct dimension i.e 1, 1024 x_test = df[image_number] x_test_1 = x_test.reshape((1, 32*32)) ## Part 2: Feed the model with the unseen image, encode/decode the image with tf.Session() as sess: sess.run(tf.global_variables_initializer()) sess.run(iter.initializer, feed_dict={x: x_test_1, batch_size: 1}) ## Part 3: Print the real and reconstructed image # Restore variables from disk. saver.restore(sess, "./model.ckpt") print("Model restored.") # Reconstruct image outputs_val = outputs.eval() print(outputs_val.shape) fig = plt.figure() # Plot real ax1 = fig.add_subplot(121) plot_image(x_test_1, shape=[32, 32], cmap = "Greys_r") # Plot estimated ax2 = fig.add_subplot(122) plot_image(outputs_val, shape=[32, 32], cmap = "Greys_r") plt.tight_layout() fig = plt.gcf()
Nachdem die Auswertefunktion nun definiert ist, können Sie einen Blick auf das rekonstruierte Bild Nummer dreizehn werfen
reconstruct_image(df =test_x, image_number = 13)
INFO:tensorflow:Restoring parameters from ./model.ckpt Model restored. (1, 1024)
Zusammenfassung
- Der Hauptzweck eines Autoencoders besteht darin, die Eingabedaten zu komprimieren und sie dann in eine Ausgabe zu dekomprimieren, die den Originaldaten sehr ähnlich sieht.
- Die Architektur eines Autoencoders ist symmetrisch mit einer Pivot-Schicht, die als zentrale Schicht bezeichnet wird.
- Sie können den Autoencoder erstellen mit:
Teilweise-: um die dichten Schichten mit der typischen Einstellung zu erstellen:
tf.layers.dense, activation=tf.nn.elu, kernel_initializer=xav_init, kernel_regularizer=l2_regularizer
dichte_schicht(): um die Matrixmultiplikation durchzuführen
loss = tf.reduce_mean(tf.square(outputs - features)) optimizer = tf.train.AdamOptimizer(learning_rate) train = optimizer.minimize(loss)