import numpy as np # Import von NumPy
import pandas as pd # Import von Pandas
import plotly.express as px # Import von Plotly
from sklearn.metrics import confusion_matrix
from sklearn.model_selection import train_test_split
np.random.seed(33)
N = 1000 # Anzahl der Punkte
X1 = np.random.normal(size=N)
X2 = np.random.normal(size=N)
X = np.column_stack((X1, X2))
alpha = np.arctan2(X2, X1)
r = np.sqrt(X1**2 + X2**2)
## Teile the sum of a sin and cosine into 5 intervals
category = pd.cut(np.sin(3*alpha + 2*r) + np.cos(3*alpha + 2*r),
bins=[-1.5, -1.1, -0.6, 0.6, 1.1, 1.5],
labels=[0, 1, 2, 3, 4])
y = category.astype(int)
# Teile in Test und Trainings-Datensatz
X_train, X_test, y_train, y_test = train_test_split(X, y)Künstliche Neuronale Netzwerke

Emotions are enmeshed in the neural networks of reason.
— António R. Damásio
Künstliche Neuronale Netzwerke haben sich in den letzten Jahren zu den wichtigsten Verfahren im Bereich des maschinellen Lernens und der künstlichen Intelligenz entwickelt. Dabei gehören zu den ältesten und grundlegendsten Algorithmen im Bereich des maschinellen Lernens und der Mustererkennung. Die ersten Grundlagen wurden bereits in den 1940er Jahren entwickelt, als ein Neurophysiologe zusammen mit einem Mathematiker ein Modell für das menschliche Denken vorschlug (McCulloch und Pitts 1943), das später u.a. von Rosenblatt zum Perzeptron weiterentwickelt wurde (Rosenblatt 1958).
Sie sind inspiriert von den biologischen neuronalen Netzwerken des menschlichen Gehirns und versuchen dieses mathematisch nachzuempfinden und somit auch ähnliche Lernerfolge zu erzielen. Sie bestehen aus vielen miteinander verbundenen “Neuronen”, die in Schichten organisiert sind und zur Verarbeitung und Analyse komplexer Datenmuster verwendet werden.
Sie werden heutzutage in vielen Anwendungsfällen genutzt insbesondere bei der Verarbeitung unstrukturierter Daten wie Bilder, Texte oder Sprache. Im Bauwesen werden sie eingesetzt zur automatisierten Rissanalyse in Betonbauwerken mittels Bildverarbeitung, zur Suche nach anomalen Vibrationen oder Dehnungsgeräuschen durch Schallemissionsverfahren oder zur Prognose von Feuchte-/Temperaturverläufen in Bauteilen über neuronale Zeitreihenmodelle.
Grundlagen
Neuronen
Neuronen sind die grundlegenden Bausteine eines neuronalen Netzwerks. Ein Neuron empfängt Eingaben, verarbeitet sie und gibt eine Ausgabe weiter. Die Verarbeitung erfolgt durch eine Aktivierungsfunktion \(f(\cdot)\), die den linearen Eingang in eine nichtlineare Ausgabe umwandelt. Das einfachste Neuron ist ein Perceptron (Rosenblatt 1958). Seine Grundstruktur besteht aus mehreren Komponenten, die in ähnlicher Form auch in modernen Neuronen vorkommen:
- Eingaben (Inputs, \(x_1, x_2, ..., x_n\)): Signale oder Datenpunkte, die in das Neuron eingespeist werden.
- Gewichte (Weights, \(w_1, w_2, ..., w_n\)): Faktoren, die die Bedeutung jedes Eingangs steuern.
- Bias (Bias, \(b\)): Ein zusätzlicher Parameter, der den Schwellenwert für die Aktivierung anpasst.
- Aktivierungsfunktion (Activation Function, \(f(\cdot)\)): Eine Funktion, die den Summenwert der gewichteten Eingaben und des Bias in eine Ausgabe umwandelt.
Die Eingaben \(x_1, x_2, ..., x_n\) sind die Signale oder Datenpunkte, die in das Neuron eingespeist werden. Gewichte \(w_1, w_2, ..., w_n\) sind Faktoren, die die Bedeutung jedes Eingangs steuern. Der Bias \(b\) ist ein zusätzlicher Parameter, der den Schwellenwert für die Aktivierung anpasst. Schließlich gibt es die Aktivierungsfunktion \(f(\cdot)\), die den Summenwert der gewichteten Eingaben und des Bias in eine Ausgabe umwandelt.
Die Ausgabe eines Neurons wird durch die folgende Formel berechnet: \[ y = f\left(b + \sum_{i=1}^n w_i x_i\right) \]
Damit gleicht das Neuron in dieser Formel einem Generalisierten Linearem Modell (GLM). Dies trifft aber nur für das einfachste neuronale Netzwerk, das Perceptron, zu. Modernere KNN bestehen aus komplexeren Modellen, die komplexe nichtlineare Zusammenhänge modellieren können. Die Aktivierungsfunktion spielt dabei eine entscheidende Rolle, da sie die Nichtlinearität in das Modell einführt und es dem Netzwerk ermöglicht, komplexe Muster in den Daten zu lernen.
Bei GLM zielt die Transformationsfunktion \(f(\cdot)\) darauf ab, die Verteilung der Ausgangsvariable zu verändern. Die meisten Aktivierungsfunktionen bei KNN zielen darauf ab, das Ausgangssignal entweder klarer zu differenzieren (aktiv/inaktiv) oder nichtlinear zu transformieren, um komplexe Zusammenhänge zu lernen. Einige gängige Aktivierungsfunktionen sind:
Sigmoid: Diese Funktion kennen wir von der logistischen Regression und GLM. Sie transformiert den Eingang in einen Wert zwischen 0 und 1, was sie besonders geeignet für die Ausgabe von Wahrscheinlichkeiten macht.
\[f(x) = (1 + e^{-x})^{-1}.\]
Tanh (Hyperbolic Tangent): Diese Funktion transformiert den Eingang in einen Wert zwischen -1 und 1 und wurde historisch in früheren neuronalen Netzen verwendet. Sie kann in Aufgaben nützlich sein, bei denen sowohl positive als auch negative Werte relevant sind.
\[f(x) = \tanh(x).\]
ReLU (Rectified Linear Unit): Sie ist eine einfache und häufig verwendete Funktion, die den Eingang direkt zurückgibt, wenn er positiv ist, und ansonsten Null. ReLU ist bekannt dafür, neuronale Netze schneller und effizienter zu trainieren.
\[f(x) = \max(0, x).\]
Softmax: Die Softmax-Funktion normalisiert die Ausgabe eines Neurons auf eine Wahrscheinlichkeitsverteilung, wobei die Summe aller Ausgänge 1 ergibt. Sie wird häufig in mehrstufigen Klassifizierungsaufgaben eingesetzt, wo sie die Wahrscheinlichkeiten aller Klassen gleichzeitig ausgibt.
\[f(x_i) = e^{x_i}\left(\sum_{j=1}^K e^{x_j}\right)^{-1}.\]
Die Wahl der richtigen Aktivierungsfunktion hängt von der spezifischen Aufgabe und der Architektur des neuronalen Netzes ab. Generell ist ReLU aufgrund seiner Einfachheit und Effizienz eine beliebte Wahl, während Sigmoid und Tanh in Situationen nützlich sein können, wo negative Werte relevant sind oder eine interpretierbare Ausgabe gewünscht ist. Softmax wird typischerweise für mehrstufige Klassifizierungsaufgaben verwendet.
Schichten
Die Fähigkeit komplexe Zusammenhänge zu erlernen, ergibt sich vor allem daraus, dass Neuronale Netzwerke aus mehreren Schichten von Neuronen bestehen, die in einer bestimmten Architektur angeordnet sind.
- Eingabeschicht (Input Layer) nimmt die Rohdaten entgegen und transformiert sie für die nachfolgenden Schichten .
- Verborgene Schichten (Hidden Layers) enthalten Neuronen, die die eingehenden Daten verarbeiten und transformieren. Bei modernen Tiefen Neuronalen Netzwerken (DNN - Deep Neural Networks) ist die Anzahl der Schichten hoch (3-100 Schichten).
- Ausgabeschicht (Output Layer) transformieren die Ausgaben des Netzwerk in die Ergebnisse. Die Anzahl der Neuronen in der Ausgabeschicht hängt von der Art des zu lösenden Problems ab.
Die erste Schicht ist die Eingabeschicht (Input Layer) und nimmt die Rohdaten des Problems entgegen und leitet sie an die nachfolgenden Schichten weiter. Diese Schicht enthält keine Aktivierungsfunktionen und dient lediglich als Schnittstelle zur Datenaufnahme.
Danach folgen mehrerer verborgene Schichten (Hidden Layers). Diese Schichten enthalten Neuronen, die die eingehenden Daten verarbeiten und transformieren. Die Anzahl der verborgenen Schichten sowie die Anzahl der Neuronen in jeder Schicht können je nach Komplexität des Netzwerks variieren. Bei modernen Tiefen Neuronalen Netzwerken (DNN - Deep Neural Networks) ist die Anzahl der Schichten hoch (3-100 Schichten).
Schließlich gibt es die Ausgabeschicht (Output Layer), die das Ergebnis der Verarbeitung durch das Netzwerk liefert. Die Anzahl der Neuronen in der Ausgabeschicht hängt von der Art des zu lösenden Problems ab. Für binäre Klassifikationsprobleme enthält die Ausgabeschicht oft nur ein Neuron, während für Mehrklassenklassifikationsprobleme mehrere Neuronen erforderlich sind, um die verschiedenen Klassen zu repräsentieren.
Trainingsprozess
Der Grund, weshalb Neuronale Netzwerke fast 60 Jahre lang nicht genutzt wurden, lag in Skalierbarkeit des Trainings. Das oben abgebildete Beispiel zeigt bereits, die hohe Anzahl an 25 Parametern (Gewichte und Bias) für ein kleines Netzwerk mit vier Schichten. Leistungsfähige Netze haben bis zu Milliarden an Parametern.
Aufgrund der Komplexität können die Parameter nicht direkt berechnet werden und werden deshalb normalerweise iterativ angenähert. Dieser Prozess umfasst typischerweise folgende Schritte:
Zufällige Initialisierung aller Parameter \(w\) und \(b\) mit Zufallszahlen.
Vorwärtsausbreitung (Forward Propagation): Die Eingabedaten werden durch das Netzwerk geleitet und die Ausgabe geschätzt. Jedes Neuron berechnet seine Aktivierungsfunktion basierend auf den gewichteten Eingaben und dem Bias mit Hilfe der oben angegeben Formel.
Berechnung des Fehlers (Loss Calculation): Der Fehler oder Verlust wird durch eine Verlustfunktion berechnet, die die Differenz zwischen der vorhergesagten Ausgabe und der tatsächlichen Ausgabe misst. Die passende Verlustfunktionen richtet sich dabei nach dem Datentyp der Ausgangsvariable. Typische Verlustfunktionen kennen wir bereits:
- Mean Square Error für numerische Daten (siehe Lineare Regression).
\[E^{\text{MSE}} = \frac{1}{n} \sum_{j=1}^{n}(\hat y_j - y_j)^2\]
- Kreuzentropie (LogLoss) für binäre oder kategorische Daten (siehe Logistische Regression).
\[E^{\text{LL}} = -\frac{1}{n} \sum_{j=1}^{n} \left[y_j \log(\hat y_j) + (1-y_j) \log(1-\hat y_j)\right]\]
Rückwärtsausbreitung (Backpropagation): Der Fehler wird durch das Netzwerk rückwärts propagiert, um die Gradienten der Verlustfunktion bezüglich der Gewichte und Biases zu berechnen. Dabei wird im Wesentlichen der Fehler rückwärts im Netzwerk verteilt, so dass Neuronen, die einen großen Anteil an der Vorhersage haben (also einen hohen Eingangswert und eine steile Aktivierungsfunktion an dieser Stelle), ein größerer Anteil am Fehler zugeteilt wird. Der Gradient \(\nabla {E(w_{ij})}\) des Gewichtes \(w_{ij}\) kann mit der Kettenregel berechnet werden:
\[ \nabla {E(w_{ij})} = \frac{\partial E}{\partial w_{ij}} \] \[ \nabla {E(b_{i})} = \frac{\partial E}{\partial b_{i}} \]
Die entsprechende partielle Ableitung richtet sich prinzipiell nach der Aktivierungsfunktion und wird in modernen Bibliotheken meist analytisch mit der Kettenregel sowie automatischer Differentiation berechnet.
Gewichtsaktualisierung (Weight Update): Die Gewichte und Biases werden mithilfe eines Optimierungsalgorithmus wie Gradient Descent oder Adam angepasst, um den Fehler zu minimieren. Beim Gradient Descent geschieht dies durch Anwendung der berechneten Gradienten auf die Gewichte und Biases mit Hilfe der Lernrate \(\alpha\):
\[w_{ij} = w_{ij} - \alpha * \nabla E(w_{ij})\] \[b_{i} = b_{i} - \alpha * \nabla E(b_{i})\]
Abbruchkriterium: Wiederholung der Schritte 2.-5. bis ein Konvergenzkriteriums erfüllt wurde oder eine maximale Anzahl an Iterationen erreicht wird.
Der Trainingsprozess wird in der Regel über mehrere Epochen wiederholt, wobei jede Epoche eine Durchführung des gesamten Trainingsdatensatzes darstellt. Dies ermöglicht es dem Netzwerk, die Gewichte iterativ zu verbessern und seine Leistung auf neuen Daten zu generalisieren. Ein entscheidender Grund für den heutigen Erfolg von Neuronalen Netzwerken ist, dass diese Berechnung der Gewichte hoch parallelisierbar ist und somit sehr gut auf modernen Graphikkarten parallelisiert werden können.
Ein häufiges Problem beim Training neuronaler Netzwerke ist Overfitting, bei dem das Netzwerk die Trainingsdaten zu gut lernt und auf neuen Daten schlecht generalisiert. Um Overfitting zu vermeiden und die Leistung des Netzwerks zu verbessern, werden verschiedene Techniken der Regularisierung eingesetzt:
- Regularisierung (z.B. L1, L2): Hinzufügen eines Regularisierungsterms zur Verlustfunktion, um die Komplexität des Modells zu kontrollieren.
- Dropout: Zufälliges Ausschalten von Neuronen während des Trainings, um die Abhängigkeit von bestimmten Neuronen zu reduzieren.
- Datenaugmentation: Erweiterung des Trainingsdatensatzes durch zufällige Transformationen der Daten.
Architekturen
Vorwärtsgerichtete Netze
Ein weiterer wichtiger Faktor für den Erfolg von Neuronalen Netzwerken ist die Fähigkeit, Neuronen in unterschiedlichen Architekturen zu verbinden und sie dadurch zu befähigen, bestimmte Datenstrukturen besser zu lernen.
Die einfachsten Formen neuronaler Netzwerke sind Vorwärtsgerichtete Neuronale Netze (FNN - Feedforward Neural Networks). Bei ihnen fließen die Daten in eine Richtung von der Eingabeschicht zur Ausgabeschicht, ohne rückwärts gerichtete Datenflüsse. Sie entsprechen den oben dargestellten Netzwerken. Sie sind besonders geeignet bei einfachen Problemen, wo keine Autokorrelation oder komplexe Muster vorherrschen.
Rekurrente Netze
Rekurrente oder rückgekoppelte Neuronale Netze (RNN - Recurrent Neural Networks) sind neuronalen Netzen, die sich von Feedforward-Netzen dadurch unterscheiden, dass sie Verbindungen zwischen Neuronen einer Schicht zu Neuronen derselben oder vorheriger Schichten ermöglichen. Diese Art der Verschaltung ähnelt der bevorzugten Struktur neuronaler Netze im Gehirn, insbesondere im Neocortex. RNNs sind ideal für sequenzielle Daten wie Zeitreihen oder Text, da sie über Schleifen verfügen, die Informationen über Zeitpunkte (oder Wortfolgen/Sätze) hinweg speichern. Dadurch lässt sich z.B. gut die Autoregression in Zeitreihen oder komplette Sätze erlernen.
\[ h_t = f\left(b + \sum_{i=1}^n w_i x_{i,t} + v\, h_{t-1} \right) \]
Hierbei ist \(h_t\) der versteckte Zustand (hidden state) zum aktuellen Zeitpunkt \(t\) und \(h_{t-1}\) der versteckte Zustand des vorherigen Zeitpunkts, der über das Gewicht \(v\) zurückgeführt wird.
Faltungsnetze
Faltungsnetze (CNN - Convolutional Neural Networks) sind besonders effektiv bei der Verarbeitung von höherdimensionalen Daten wie Bilddaten oder geospatialer Daten. Sie verwenden Faltungsoperationen, um Merkmale (Kanten, Reliefs, Muster, etc.) aus Eingabebildern zu extrahieren oder zu erlernen und gleichzeitig einen höherendimensionalen Eingang auf einen niedrigdimensionaleren Ausgang zu reduzieren, der diese Merkmale encodiert. Dadurch repräsentiert der Ausgang nur die Relevanz des extrahierten oder gelernten Merkmals und es muss nicht das Gesamtbild gelernt werden. Durch das Schichten mehrerer versteckter Faltungsschichten hintereinander werden so zuerst Merkmale extrahiert und dann Muster daraus im Bild gelernt (z.B. die Form eines Hundes). Auf die Faltung und die Bildverarbeitung werden wir im Nachfolgekurs “Künstliche Intelligenz und Foundation Modelle” noch vertieft eingehen.
Neuronale Netzwerke in Python
Neuronale Netzwerke in sklearn
Es gibt verschiedene Bibliotheken für Neuronale Netzwerke in Python. Wir betrachten zuerst sklearn, da wir dort Neuronale Netzwerke einfach mit der bekannten API nutzen können.
Wir demonstrieren neuronale Netzwerke anhand einer erweiterten Version des Yin-Yang-Beispiels aus der Klassifikation indem wir die Anzahl der Farben auf 4 Kategorien und die Verwirbelung erhöhen. Wieder besteht die Aufgabe darin, die richtige Farbe basierend auf dem Punkt vorherzusagen, also eine Klassifikationsaufgabe. Wir erstellen die Daten wie folgt:
# Darstellung des Datensatzes
fig=px.scatter(x=X2, y=X1, color=y, width=600, height=600)
fig.update_traces(marker_line=dict(width=.3, color="black"))
fig.show()Das Bild zeigt ein komplexes Muster von Spiralarmen in fünf verschiedenen Farben. Dreiarmige gelbe und blauen Arme entsprechen den größten und kleinsten Werten, während sechsarmige Arme in verschiedenen Rot- und Violetttönen den dazwischen liegenden Werten entsprechen. Diese Entscheidungsgrenzen sind sehr schwer mit einfachen Modellen wie logistischer Regression, SVM oder sogar Bäumen zu erfassen, da die Spiralarme stark nicht-konvexe und ineinander verschlungene Klassenregionen bilden: Bäume können solche Regionen nur grob durch viele achsenparallele Splits annähern, und ein SVM mit einem einzelnen festen Kernel findet keine Transformation, die alle Spiralarme gleichzeitig sauber trennt. Prüfen wir das noch einmal mit einer kleinen Visualisierungsfunktion, die wir auch in der Klassifikation genutzt haben.
mcolors=['blue', 'purple', 'violet', 'orange', 'yellow']
def DBPlot(m, X, y, nGrid = 300):
x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1
x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx1, xx2 = np.meshgrid(np.linspace(x1_min, x1_max, nGrid),
np.linspace(x2_min, x2_max, nGrid))
XX = np.column_stack((xx1.ravel(), xx2.ravel()))
hatyy = m.predict(XX).reshape(xx1.shape)
fig = px.imshow(hatyy, width=600, height=600)
fig.add_scatter(x=X[:,0]/(x1_max-x1_min)*nGrid+nGrid/2, y=X[:,1]/(x2_max-x2_min)*nGrid+nGrid/2, mode="markers",
marker=dict(color=[mcolors[i] for i in y]), marker_line=dict(width=.3, color="black"))
fig.update_coloraxes(showscale=False)
fig.update_layout(showlegend=False)
fig.show()Testen wir einen Random Forest, so erhalten wir zwar ein gutes Modell, dass allerdings overfittet und schlecht generalisiert.
from sklearn.ensemble import RandomForestClassifier
m = RandomForestClassifier()
_ = m.fit(X_train, y_train)
m.score(X_test, y_test)0.76
confusion_matrix(y_test, m.predict(X_test))array([[51, 1, 2, 0, 0],
[11, 18, 5, 0, 0],
[ 2, 8, 50, 10, 0],
[ 0, 1, 8, 24, 5],
[ 0, 0, 4, 3, 47]])
DBPlot(m, X_test, y_test)Ein SVM mit radialem Kernel erkennt die Struktur besser, aber hat einen deutlich höheren Fehler.
from sklearn.svm import SVC
m = SVC(kernel="rbf", gamma=1)
_ = m.fit(X_train, y_train)
m.score(X_test, y_test)0.544
confusion_matrix(y_test, m.predict(X_test))array([[43, 0, 11, 0, 0],
[19, 0, 15, 0, 0],
[11, 0, 52, 0, 7],
[ 1, 0, 11, 0, 26],
[ 3, 0, 10, 0, 41]])
DBPlot(m, X_test, y_test)Allerdings können neuronale Netzwerke (und KNN) deutlich besser damit umgehen.
sklearn implementiert einfache Feed-Forward-Neuronale Netzwerke, so genannte Multi-Layer Perceptrons. Dies sind einfache dichte Feed-Forward-Netzwerke mit einer beliebigen Anzahl von versteckten Schichten. Auch wenn sie strukturell einfache neuronaler Netzwerke sind, sind sie dennoch leistungsfähig genug für viele Aufgaben.
Wie bei anderen fortgeschrittenen Modellen bietet sklearn zwei unterschiedlichen Klassen für Klassifikationsaufgaben MLPClassifier und für Regressionsaufgaben MLPRegressor. Die grundlegende Verwendung dieser Modelle ist identisch zu den anderen sklearn-Modellen.
Die wichtigsten Argumente für den MLPClassifier sind:
MLPClassifier(hidden_layer_sizes, activation, max_iter, alpha)Von diesen ist hidden_layer_sizes der zentralste. Dies beschreibt die Anzahl der versteckten Schichten (die Größe der Eingabe- und Ausgabeschicht wird automatisch aus den Daten bestimmt). Es handelt sich um ein Tupel, das die Anzahl der Knoten für jede versteckte Schicht angibt, daher gibt die Länge des Tupels auch die Anzahl der versteckten Schichten an. Zum Beispiel bedeutet hidden_layer_sizes = (32, 16) zwei versteckte Schichten, die erste mit 32 und die folgende mit 16 Knoten. activation beschreibt die Aktivierungsfunktion. Es empfiehlt sich meist es bei der Standardfunktion relu zu lassen, außer es gibt die oben beschriebenen Gründe für andere Aktivierungsfunktionen. alpha ist der L2-Regularisierungsparameter und max_iter gibt die maximale Anzahl von Iterationen an, bevor die Optimierung stoppt. In moderneren Bibliotheken wie Keras oder PyTorch wird die L2-Regularisierung meist nicht global, sondern explizit pro Schicht angegeben, z.B. mit kernel_regularizer=regularizers.L2(alpha) in Keras.
Lassen Sie uns nun die Verwendung von MLPClassifier an den Yin-Yang Beispiel demonstrieren. Beginnen wir mit einem einfachen Perzeptron mit einer einzigen versteckten Schicht von 20 Knoten. Daher verwenden wir hidden_layer_sizes=(20,), ein Tupel mit nur einer Zahl. Das Anpassen des Modells und die Vorhersage sind größtenteils ähnlich wie bei den anderen sklearn-Funktionen, daher diskutieren wir dies hier nicht. Wir erhöhen auch die Anzahl der Iterationen, da die Standardanzahl von 200 in diesem Fall zu gering ist:
from sklearn.neural_network import MLPClassifier
m = MLPClassifier(hidden_layer_sizes = (20,), max_iter=10000)
_ = m.fit(X_train, y_train)
m.score(X_test, y_test)0.588
confusion_matrix(y_test, m.predict(X_test))array([[46, 1, 6, 0, 1],
[18, 2, 13, 0, 1],
[11, 1, 53, 0, 5],
[ 1, 0, 16, 0, 21],
[ 0, 0, 6, 2, 46]])
DBPlot(m, X_test, y_test)Dieses einfache Modell hat zuerst auch nur eine niedrige Genauigkeit. Das liegt daran, dass es zu einfach ist, nur eine einzelne kleine versteckte Schicht reicht nicht aus, um das komplexe Spiralmuster gut zu modellieren. Was sich gut in der Visualisierung erkennen lässt. Wir können dort sehen, dass das Modell die Idee korrekt einfängt: Spiralen in verschiedenen Farben, aber die Form der Spiralen ist nicht genau genug.
Lassen Sie uns das Modell mit einem leistungsstärkeren Netzwerk wiederholen:
m = MLPClassifier(hidden_layer_sizes = (256, 128, 64), max_iter=10000)
_ = m.fit(X_train, y_train)
m.score(X_test, y_test)0.912
confusion_matrix(y_test, m.predict(X_test))array([[52, 1, 1, 0, 0],
[ 6, 26, 2, 0, 0],
[ 1, 2, 66, 1, 0],
[ 0, 0, 4, 34, 0],
[ 0, 0, 0, 4, 50]])
DBPlot(m, X_test, y_test)Jetzt sind die Ergebnisse sehr gut mit einer Genauigkeit von ca. 95 %. Die visuelle Inspektion bestätigt, dass das leistungsstärkere neuronale Netzwerk die Gesamtstruktur des Modells gut erfassen kann.
Die angepassten Netzwerkmodelle haben verschiedene Methoden und Attribute, z.B. gibt coefs_ die Modellgewichte aus (als Liste von Gewichtsmatrizen, eine für jede Schicht), und intercepts_ gibt die Modell-Biaswerte aus (als Liste von Bias-Vektoren, einer für jede Schicht). Zum Beispiel enthält das oben angepasste Modell den akkumilierten Bias-Vektor für die erste versteckte Schicht:
np.sum([b.size for b in m.intercepts_])np.int64(453)
Während sklearn einen einfachen Zugang zu neuronalen Netzwerkmodellen bietet, sind diese Modelle erheblich eingeschränkt. sklearn ist damit gut für kleinere Aufgaben und zum schnellen Prototyping geeignet, aber für tiefere Netzwerke, größere Datenmengen und GPU-Beschleunigung braucht man spezialisierte Frameworks wie tensorflow oder pytorch.
Neuronale Netzwerke in Keras
Tensorflow and Keras
Tensorflow ist eine Bibliothek, die Berechnungsgraphen implementiert, die automatisch Gradienten berechnen können. Sie ermöglicht auch Berechnungen auf der GPU durchzuführen, was potenziell zu erheblichen Geschwindigkeitsverbesserungen gegenüber CPU-Berechnungen führen kann. In vielerlei Hinsicht ähnelt sie numpy, wo man Matrizen und Tensoren erstellen und manipulieren kann. Allerdings ist sie aufgrund des Berechnungsgraphen-Ansatzes und der GPU-bezogenen Überlegungen viel schwieriger zu verwenden.
Keras ist ein TensorFlow-Front-End, ein Submodul, das einen viel benutzerfreundlicheren Zugang zum Aufbau neuronaler Netzwerke bietet. Die Funktionalität umfasst eine Vielzahl von Netzwerkschichten, bei denen man die entsprechenden Parameter anpassen kann. Beim Aufbau des Netzwerks kann man einfach die Schichten hintereinander hinzufügen, die Verbindung zwischen den Schichten wird von Keras selbst übernommen. Eine gute Quelle für die Keras-Dokumentation ist die API-Referenzdokumentation.
Tensorflow kann schwierig und frustrierend zu installieren sein. Normalerweise funktioniert es gut mit conda install tensorflow oder pip install tensorflow. Manchmal können jedoch Probleme auftreten und es kann schwierig sein, die Probleme zu finden und zu beheben. Insbesondere installiert pip normalerweise die neueste Version, auch wenn sie mit dem Rest Ihrer Pakete nicht kompatibel ist. Es installiert auch Abhängigkeiten und kann bestimmte Pakete aktualisieren, was die Python-Installation beeinträchtigen kann. Um Probleme mit dem Rest Ihres Systems zu vermeiden, empfehlen wir dringend, es in einer virtuellen Umgebung wie Anaconda zu installieren.
Beispielnetzwerk in keras
Lassen Sie uns das Farbspiralbeispiel aus dem letzten Abschnitt von sklearn neu implementieren, diesmal jedoch mit keras. Es wird einige bemerkenswerte Unterschiede geben:
Der Aufbau des Netzwerks selbst ist in Keras anders. Keras berechnet nicht die Größe der Eingabe- und Ausgangsschichten aus den Daten. Beide müssen vom Benutzer angegeben werden. Schließlich sagt Keras nur Wahrscheinlichkeiten für alle Kategorien voraus, daher müssen wir Code hinzufügen, der die Spalte (Kategorie) mit der höchsten Wahrscheinlichkeit findet.
Das Modell erzeugen
Zuerst der wichtigste Schritt: Aufbau und Kompilierung des Modells. Dies unterscheidet sich sehr von der Vorgehensweise in sklearn. Lassen Sie uns ein sequentielles Modell mit dichten Schichten aufbauen, die gleiche Architektur, die wir mit sklearn erstellt haben:
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Input
# sequential (not recursive) model (one input, one output)
model=Sequential()
model.add(Input(shape=(2,)))
model.add(Dense(512, activation="relu"))
model.add(Dense(256, activation="relu"))
model.add(Dense(64, activation="relu"))
nCategories = len(np.unique(category))
model.add(Dense(nCategories, activation="softmax"))Wir beginnen mit dem Importieren der Funktionalität, die wir von tensorflow.keras benötigen. Danach erstellen wir ein leeres sequenzielles Modell (d.h. ein Modell, das keine Schleifen und rückwärts fließende Daten enthält) und fangen an, Schichten hinzuzufügen. Wir fügen 3 dichte Schichten (Dense) hinzu. Die erste Schicht enthält 512 Knoten, die zweite 256 und die letzte Schicht enthält 64 Knoten. Alle diese Knoten werden mit der relu Funktion aktiviert.
Das erste wichtige neue Feature ist die explizite Definition der Eingabeform, hier mit Input(shape=(2,)) vor der ersten dichten Schicht. Dies sagt Keras, welche Art von Eingaben zu erwarten sind. Derzeit ist es nur ein Tupel (2,), da unsere X-Matrix nur 2 Spalten enthält. Also (2,) ist nur die Form einer einzelnen Zeile von X, einer einzelnen Instanz der Eingabedaten. Sie können die richtige Form mit X[0].shape finden. Aber die Eingabe muss hier nicht nur ein Vektor sein. Zum Beispiel kann es bei Bildern ein 3-D-Tensor mit der Form (Breite, Höhe, #Farbkanäle) sein. Die folgenden Schichten können diese Form dann automatisch ableiten.
Wir müssen auch eine explizite Ausgabeschicht hinzufügen. Da es sich hier um Klassifizierung handelt, benötigen wir so viele Ausgabeknoten wie Kategorien - wir können diese Anzahl berechnen als
nCategories = len(np.unique(category))Jeder Ausgabeknoten wird die Wahrscheinlichkeit vorhersagen, dass die Eingabe in die entsprechende Kategorie fällt. Wir können die softmax (multi-nomiale Logit)-Aktivierung verwenden, um sicherzustellen, dass die Ergebnisse gültige Wahrscheinlichkeiten sind. Beachten Sie, dass im Falle von nur zwei Kategorien die Softmax-Aktivierung äquivalent zur gewöhnlichen logistischen Regression ist. Aber im Gegensatz zur gewöhnlichen logistischen Regression haben wir eine Reihe anderer Schichten vor der letzten logistischen Schicht.
Dabei ist es hilfreich, zwischen drei Begriffen zu unterscheiden: Logits sind die rohen Ausgaben vor der letzten Aktivierungsfunktion, Wahrscheinlichkeiten sind die durch Sigmoid oder Softmax transformierten Werte, und Klassenlabels erhält man erst durch eine anschließende Entscheidung wie Schwellenwert oder argmax.
Das richtige Festlegen der Eingabeformen und Ausgabeknoten ist eine der Hauptursachen für Frustration, wenn man anfängt, mit keras zu arbeiten. Die Fehlermeldungen sind lang und nicht besonders hilfreich, und es ist schwer zu verstehen, was das Problem ist. Hier ist eine Checkliste, die durchgearbeitet werden kann, wenn etwas nicht funktioniert:
- Ist die Eingabeform explizit definiert, z.B. mit
Input(shape=...)am Anfang des Modells? - Stellt diese Form korrekt eine einzelne Instanz der Eingabedaten dar?
- Haben Sie die richtige Anzahl von Knoten in der Softmax-aktivierten Ausgangsschicht?
Training des Modells
Die nächste Aufgabe besteht darin, das Modell zu kompilieren und anzupassen. Keras-Modelle müssen kompiliert werden - was wir bisher eingerichtet haben, ist nur eine Beschreibung des Modells, nicht das tatsächliche Modell, das für TensorFlow-Tensoren eingerichtet ist und möglicherweise für die GPU-Ausführung. Wir können das Modell wie folgt kompilieren:
Für ein sauberes Training trennt man die Daten typischerweise in Trainings-, Validierungs- und Testdaten. Die Trainingsdaten werden zum Lernen der Gewichte verwendet, die Validierungsdaten zur Kontrolle während des Trainings und zur Wahl von Hyperparametern, und die Testdaten erst ganz am Ende für eine unabhängige Bewertung. Eine häufige Technik ist dabei Early Stopping: Man beendet das Training, wenn sich der Fehler auf den Validierungsdaten nicht weiter verbessert, um Overfitting zu vermeiden.
model.compile(loss='sparse_categorical_crossentropy',
optimizer='adam',
metrics=['accuracy'])
print(model.summary())Model: "sequential"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Layer (type) ┃ Output Shape ┃ Param # ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ dense (Dense) │ (None, 512) │ 1,536 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense_1 (Dense) │ (None, 256) │ 131,328 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense_2 (Dense) │ (None, 64) │ 16,448 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense_3 (Dense) │ (None, 5) │ 325 │ └─────────────────────────────────┴────────────────────────┴───────────────┘
Total params: 149,637 (584.52 KB)
Trainable params: 149,637 (584.52 KB)
Non-trainable params: 0 (0.00 B)
None
Die drei wichtigsten Argumente sind
lossbeschreibt die Modellverlustfunktion,sparse_categorical_crossentropy, im Wesentlichen die Log-Likelihood, ist geeignet für Kategorisierungsaufgaben. Der genaue Typ hängt auch davon ab, wie das Ergebnis genau codiert ist.optimizerist der Optimierer, der für den stochastischen Gradientenabstieg verwendet werden soll.adamundrmspropsind gute Optionen, aber es gibt auch andere Möglichkeiten.metricsist eine Metrik, die während der Optimierung ausgewertet und gedruckt wird und einige Rückmeldungen darüber bietet, wie die Auswertung verläuft.
Die letzte Zeile hier druckt die Modellzusammenfassung aus, eine praktische Übersicht darüber, was wir gemacht haben:
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense (Dense) (None, 512) 1536
_________________________________________________________________
dense_1 (Dense) (None, 256) 131328
_________________________________________________________________
dense_2 (Dense) (None, 64) 16448
_________________________________________________________________
dense_3 (Dense) (None, 5) 325
=================================================================
Total params: 149,637
Trainable params: 149,637
Non-trainable params: 0
Dieses Netzwerk enthält fast 150.000 Parameter, von denen alle trainierbar sind.
Nach erfolgreicher Kompilierung können wir das Modell anpassen:
history = model.fit(X_train, y_train, epochs=200, validation_split=0.2)Epoch 1/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 10s 584ms/step - accuracy: 0.1875 - loss: 1.6100 19/19 ━━━━━━━━━━━━━━━━━━━━ 1s 6ms/step - accuracy: 0.2867 - loss: 1.5816 - val_accuracy: 0.3000 - val_loss: 1.5378 Epoch 2/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.2188 - loss: 1.6405 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.2967 - loss: 1.5445 - val_accuracy: 0.2933 - val_loss: 1.5381 Epoch 3/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 10ms/step - accuracy: 0.2188 - loss: 1.5586 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.3200 - loss: 1.5297 - val_accuracy: 0.3200 - val_loss: 1.5385 Epoch 4/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.3125 - loss: 1.5261 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.3117 - loss: 1.5192 - val_accuracy: 0.3600 - val_loss: 1.5350 Epoch 5/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.2812 - loss: 1.5330 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.3583 - loss: 1.4917 - val_accuracy: 0.3533 - val_loss: 1.5293 Epoch 6/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.3438 - loss: 1.4916 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.3583 - loss: 1.4780 - val_accuracy: 0.4000 - val_loss: 1.5397 Epoch 7/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.3750 - loss: 1.4100 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.3750 - loss: 1.4580 - val_accuracy: 0.3733 - val_loss: 1.5093 Epoch 8/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.3438 - loss: 1.4881 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.3683 - loss: 1.4509 - val_accuracy: 0.4067 - val_loss: 1.5235 Epoch 9/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.3750 - loss: 1.5824 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.4067 - loss: 1.4262 - val_accuracy: 0.3867 - val_loss: 1.5096 Epoch 10/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.3125 - loss: 1.4763 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 3ms/step - accuracy: 0.3867 - loss: 1.4120 - val_accuracy: 0.3800 - val_loss: 1.4904 Epoch 11/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 9ms/step - accuracy: 0.5000 - loss: 1.2922 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 3ms/step - accuracy: 0.4000 - loss: 1.3835 - val_accuracy: 0.4200 - val_loss: 1.4768 Epoch 12/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 9ms/step - accuracy: 0.3750 - loss: 1.4558 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 3ms/step - accuracy: 0.4417 - loss: 1.3603 - val_accuracy: 0.4333 - val_loss: 1.4791 Epoch 13/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.2500 - loss: 1.3855 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.4467 - loss: 1.3330 - val_accuracy: 0.4800 - val_loss: 1.4141 Epoch 14/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.3438 - loss: 1.3761 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.4533 - loss: 1.3042 - val_accuracy: 0.4533 - val_loss: 1.4377 Epoch 15/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.4688 - loss: 1.2445 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.4933 - loss: 1.2666 - val_accuracy: 0.5267 - val_loss: 1.3797 Epoch 16/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.5938 - loss: 1.1447 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.4933 - loss: 1.2277 - val_accuracy: 0.5467 - val_loss: 1.3066 Epoch 17/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.5625 - loss: 1.0881 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.5317 - loss: 1.1725 - val_accuracy: 0.5533 - val_loss: 1.2744 Epoch 18/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.5625 - loss: 1.1445 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.5617 - loss: 1.1278 - val_accuracy: 0.5267 - val_loss: 1.2700 Epoch 19/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.4688 - loss: 1.1546 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.5650 - loss: 1.1005 - val_accuracy: 0.5667 - val_loss: 1.2319 Epoch 20/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.6250 - loss: 1.0752 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.5800 - loss: 1.0533 - val_accuracy: 0.6200 - val_loss: 1.1549 Epoch 21/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.5000 - loss: 1.0695 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.5850 - loss: 1.0363 - val_accuracy: 0.5867 - val_loss: 1.1526 Epoch 22/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.5938 - loss: 0.9721 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.6033 - loss: 0.9872 - val_accuracy: 0.6067 - val_loss: 1.0489 Epoch 23/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.6250 - loss: 0.9482 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.6450 - loss: 0.9295 - val_accuracy: 0.6533 - val_loss: 1.0307 Epoch 24/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.8750 - loss: 0.7105 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.6567 - loss: 0.8896 - val_accuracy: 0.6333 - val_loss: 0.9732 Epoch 25/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.6875 - loss: 0.8916 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.6667 - loss: 0.8671 - val_accuracy: 0.6933 - val_loss: 0.9240 Epoch 26/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.6875 - loss: 0.7156 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 3ms/step - accuracy: 0.6600 - loss: 0.8272 - val_accuracy: 0.6933 - val_loss: 0.9340 Epoch 27/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 9ms/step - accuracy: 0.8125 - loss: 0.6901 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.6917 - loss: 0.8141 - val_accuracy: 0.6867 - val_loss: 0.8841 Epoch 28/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.7188 - loss: 0.6832 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.6950 - loss: 0.7879 - val_accuracy: 0.6933 - val_loss: 0.8115 Epoch 29/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.8125 - loss: 0.7519 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.6850 - loss: 0.7481 - val_accuracy: 0.7333 - val_loss: 0.8229 Epoch 30/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.6875 - loss: 0.8379 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.7433 - loss: 0.7041 - val_accuracy: 0.7000 - val_loss: 0.8023 Epoch 31/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.6562 - loss: 0.7178 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.7433 - loss: 0.6890 - val_accuracy: 0.7200 - val_loss: 0.8332 Epoch 32/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.7812 - loss: 0.6154 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.7317 - loss: 0.6432 - val_accuracy: 0.7333 - val_loss: 0.7270 Epoch 33/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.8750 - loss: 0.5212 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.7617 - loss: 0.6229 - val_accuracy: 0.8000 - val_loss: 0.7078 Epoch 34/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.8438 - loss: 0.4931 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.7850 - loss: 0.5950 - val_accuracy: 0.7200 - val_loss: 0.7695 Epoch 35/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.7812 - loss: 0.6392 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.7917 - loss: 0.5778 - val_accuracy: 0.7400 - val_loss: 0.7574 Epoch 36/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.7500 - loss: 0.5394 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 3ms/step - accuracy: 0.7667 - loss: 0.5840 - val_accuracy: 0.7867 - val_loss: 0.6676 Epoch 37/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.8750 - loss: 0.5509 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.7600 - loss: 0.6006 - val_accuracy: 0.7733 - val_loss: 0.6641 Epoch 38/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9062 - loss: 0.4093 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.8117 - loss: 0.5480 - val_accuracy: 0.7667 - val_loss: 0.6702 Epoch 39/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.7500 - loss: 0.4681 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.8033 - loss: 0.5593 - val_accuracy: 0.7333 - val_loss: 0.7175 Epoch 40/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.8750 - loss: 0.4592 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.7817 - loss: 0.5538 - val_accuracy: 0.7933 - val_loss: 0.6169 Epoch 41/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.8750 - loss: 0.4915 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.8133 - loss: 0.4939 - val_accuracy: 0.8267 - val_loss: 0.6030 Epoch 42/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.7812 - loss: 0.5477 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.8533 - loss: 0.4652 - val_accuracy: 0.8200 - val_loss: 0.6001 Epoch 43/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.3266 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.8383 - loss: 0.4538 - val_accuracy: 0.7867 - val_loss: 0.5607 Epoch 44/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.8125 - loss: 0.5635 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.8617 - loss: 0.4414 - val_accuracy: 0.7867 - val_loss: 0.5932 Epoch 45/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.8438 - loss: 0.4142 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.8883 - loss: 0.4165 - val_accuracy: 0.8400 - val_loss: 0.5707 Epoch 46/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9375 - loss: 0.4071 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.8567 - loss: 0.4124 - val_accuracy: 0.7933 - val_loss: 0.5858 Epoch 47/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.8438 - loss: 0.4313 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.8667 - loss: 0.3927 - val_accuracy: 0.8333 - val_loss: 0.5576 Epoch 48/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 1.0000 - loss: 0.2295 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.8750 - loss: 0.3804 - val_accuracy: 0.8200 - val_loss: 0.5569 Epoch 49/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.8438 - loss: 0.3767 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.8733 - loss: 0.3870 - val_accuracy: 0.8067 - val_loss: 0.6084 Epoch 50/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.8438 - loss: 0.4515 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.8567 - loss: 0.4024 - val_accuracy: 0.8267 - val_loss: 0.5712 Epoch 51/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.8750 - loss: 0.3314 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.8450 - loss: 0.3775 - val_accuracy: 0.7733 - val_loss: 0.6191 Epoch 52/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.8750 - loss: 0.3792 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.8650 - loss: 0.3686 - val_accuracy: 0.8467 - val_loss: 0.5421 Epoch 53/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 9ms/step - accuracy: 0.8438 - loss: 0.3675 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 3ms/step - accuracy: 0.9033 - loss: 0.3486 - val_accuracy: 0.8467 - val_loss: 0.5458 Epoch 54/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.8438 - loss: 0.3588 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.8767 - loss: 0.3460 - val_accuracy: 0.8600 - val_loss: 0.5799 Epoch 55/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.8750 - loss: 0.3358 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.8883 - loss: 0.3333 - val_accuracy: 0.8600 - val_loss: 0.5044 Epoch 56/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9062 - loss: 0.3349 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.8983 - loss: 0.3256 - val_accuracy: 0.8267 - val_loss: 0.5481 Epoch 57/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.2264 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.8633 - loss: 0.3485 - val_accuracy: 0.8467 - val_loss: 0.5763 Epoch 58/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.2343 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.8700 - loss: 0.3346 - val_accuracy: 0.8667 - val_loss: 0.4934 Epoch 59/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.2500 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9017 - loss: 0.3124 - val_accuracy: 0.8200 - val_loss: 0.5418 Epoch 60/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.8750 - loss: 0.2366 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.8967 - loss: 0.2920 - val_accuracy: 0.8600 - val_loss: 0.5292 Epoch 61/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.8750 - loss: 0.2798 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9067 - loss: 0.2928 - val_accuracy: 0.8600 - val_loss: 0.5626 Epoch 62/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.8750 - loss: 0.3018 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9267 - loss: 0.2785 - val_accuracy: 0.8800 - val_loss: 0.4668 Epoch 63/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9062 - loss: 0.3435 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.8983 - loss: 0.3145 - val_accuracy: 0.7267 - val_loss: 0.7593 Epoch 64/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.8125 - loss: 0.5474 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.8667 - loss: 0.3807 - val_accuracy: 0.8667 - val_loss: 0.4581 Epoch 65/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.9688 - loss: 0.1996 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9233 - loss: 0.2805 - val_accuracy: 0.8467 - val_loss: 0.5061 Epoch 66/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 9ms/step - accuracy: 0.9688 - loss: 0.2334 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9333 - loss: 0.2585 - val_accuracy: 0.8200 - val_loss: 0.5355 Epoch 67/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.8750 - loss: 0.3327 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9033 - loss: 0.2921 - val_accuracy: 0.8400 - val_loss: 0.5349 Epoch 68/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9375 - loss: 0.2718 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.8917 - loss: 0.3023 - val_accuracy: 0.8400 - val_loss: 0.5092 Epoch 69/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.8750 - loss: 0.2532 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.8983 - loss: 0.2865 - val_accuracy: 0.8667 - val_loss: 0.4915 Epoch 70/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9375 - loss: 0.2804 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.8967 - loss: 0.2895 - val_accuracy: 0.8533 - val_loss: 0.5395 Epoch 71/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9062 - loss: 0.2707 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9250 - loss: 0.2605 - val_accuracy: 0.8533 - val_loss: 0.4586 Epoch 72/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 1.0000 - loss: 0.1523 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9050 - loss: 0.2544 - val_accuracy: 0.8533 - val_loss: 0.5036 Epoch 73/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.1904 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9100 - loss: 0.2713 - val_accuracy: 0.8467 - val_loss: 0.5249 Epoch 74/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.8438 - loss: 0.3092 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9017 - loss: 0.2682 - val_accuracy: 0.8400 - val_loss: 0.4751 Epoch 75/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.8750 - loss: 0.3079 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9017 - loss: 0.2504 - val_accuracy: 0.8467 - val_loss: 0.5227 Epoch 76/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 13ms/step - accuracy: 0.9375 - loss: 0.2056 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 3ms/step - accuracy: 0.9333 - loss: 0.2230 - val_accuracy: 0.8467 - val_loss: 0.4605 Epoch 77/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.1889 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9317 - loss: 0.2161 - val_accuracy: 0.8600 - val_loss: 0.4976 Epoch 78/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 9ms/step - accuracy: 0.9062 - loss: 0.2442 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9033 - loss: 0.2549 - val_accuracy: 0.8400 - val_loss: 0.5068 Epoch 79/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9375 - loss: 0.1626 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9217 - loss: 0.2227 - val_accuracy: 0.8600 - val_loss: 0.4657 Epoch 80/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.1522 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9200 - loss: 0.2142 - val_accuracy: 0.8467 - val_loss: 0.5299 Epoch 81/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9062 - loss: 0.2431 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9150 - loss: 0.2364 - val_accuracy: 0.8600 - val_loss: 0.4426 Epoch 82/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9375 - loss: 0.2030 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9233 - loss: 0.2396 - val_accuracy: 0.8267 - val_loss: 0.5379 Epoch 83/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.8438 - loss: 0.3066 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9267 - loss: 0.2215 - val_accuracy: 0.8733 - val_loss: 0.4713 Epoch 84/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9062 - loss: 0.1521 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9300 - loss: 0.2174 - val_accuracy: 0.8333 - val_loss: 0.5103 Epoch 85/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.8750 - loss: 0.3088 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.8967 - loss: 0.2727 - val_accuracy: 0.8667 - val_loss: 0.4476 Epoch 86/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 1.0000 - loss: 0.1561 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9150 - loss: 0.2293 - val_accuracy: 0.8800 - val_loss: 0.4429 Epoch 87/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.1350 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9417 - loss: 0.1997 - val_accuracy: 0.8467 - val_loss: 0.4667 Epoch 88/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 1.0000 - loss: 0.1151 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9250 - loss: 0.2145 - val_accuracy: 0.8533 - val_loss: 0.4496 Epoch 89/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.1424 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9317 - loss: 0.2084 - val_accuracy: 0.8333 - val_loss: 0.6013 Epoch 90/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.8750 - loss: 0.2522 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9083 - loss: 0.2316 - val_accuracy: 0.8533 - val_loss: 0.5163 Epoch 91/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.1422 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.8733 - loss: 0.3194 - val_accuracy: 0.7867 - val_loss: 0.5978 Epoch 92/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.8750 - loss: 0.2221 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9017 - loss: 0.2568 - val_accuracy: 0.8267 - val_loss: 0.4979 Epoch 93/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.8438 - loss: 0.4101 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9000 - loss: 0.2290 - val_accuracy: 0.8533 - val_loss: 0.4525 Epoch 94/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.8750 - loss: 0.2595 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9000 - loss: 0.2365 - val_accuracy: 0.8533 - val_loss: 0.4242 Epoch 95/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9375 - loss: 0.2052 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9217 - loss: 0.2164 - val_accuracy: 0.8600 - val_loss: 0.4773 Epoch 96/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.9688 - loss: 0.1605 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9333 - loss: 0.1982 - val_accuracy: 0.8533 - val_loss: 0.4639 Epoch 97/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9375 - loss: 0.1916 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9417 - loss: 0.1817 - val_accuracy: 0.8733 - val_loss: 0.4539 Epoch 98/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 1.0000 - loss: 0.1661 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9267 - loss: 0.1905 - val_accuracy: 0.8667 - val_loss: 0.4825 Epoch 99/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.9062 - loss: 0.1911 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9417 - loss: 0.1855 - val_accuracy: 0.8533 - val_loss: 0.4996 Epoch 100/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9375 - loss: 0.1741 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9367 - loss: 0.1926 - val_accuracy: 0.8600 - val_loss: 0.5019 Epoch 101/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.9688 - loss: 0.1466 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9267 - loss: 0.2065 - val_accuracy: 0.8467 - val_loss: 0.5506 Epoch 102/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.8750 - loss: 0.3293 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9367 - loss: 0.1906 - val_accuracy: 0.8467 - val_loss: 0.5371 Epoch 103/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.9688 - loss: 0.1675 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9383 - loss: 0.1836 - val_accuracy: 0.9000 - val_loss: 0.4135 Epoch 104/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.9375 - loss: 0.2439 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9467 - loss: 0.1721 - val_accuracy: 0.8800 - val_loss: 0.4539 Epoch 105/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9375 - loss: 0.1346 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9367 - loss: 0.1828 - val_accuracy: 0.8400 - val_loss: 0.5049 Epoch 106/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9375 - loss: 0.1809 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9283 - loss: 0.1964 - val_accuracy: 0.9000 - val_loss: 0.4389 Epoch 107/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 1.0000 - loss: 0.1185 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9300 - loss: 0.1961 - val_accuracy: 0.8133 - val_loss: 0.6296 Epoch 108/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.9375 - loss: 0.2075 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9217 - loss: 0.2173 - val_accuracy: 0.8733 - val_loss: 0.3952 Epoch 109/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.9375 - loss: 0.1179 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9400 - loss: 0.1700 - val_accuracy: 0.8600 - val_loss: 0.4714 Epoch 110/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.0741 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9433 - loss: 0.1650 - val_accuracy: 0.8933 - val_loss: 0.4232 Epoch 111/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.9688 - loss: 0.1475 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9433 - loss: 0.1572 - val_accuracy: 0.8867 - val_loss: 0.4396 Epoch 112/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.9688 - loss: 0.1260 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9433 - loss: 0.1683 - val_accuracy: 0.8667 - val_loss: 0.4340 Epoch 113/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.1132 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9400 - loss: 0.1680 - val_accuracy: 0.8600 - val_loss: 0.4911 Epoch 114/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9375 - loss: 0.1633 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9283 - loss: 0.1866 - val_accuracy: 0.8467 - val_loss: 0.5319 Epoch 115/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 1.0000 - loss: 0.0903 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9333 - loss: 0.1893 - val_accuracy: 0.8467 - val_loss: 0.4797 Epoch 116/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9375 - loss: 0.1781 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9367 - loss: 0.1722 - val_accuracy: 0.8667 - val_loss: 0.4681 Epoch 117/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 1.0000 - loss: 0.0998 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9483 - loss: 0.1590 - val_accuracy: 0.8800 - val_loss: 0.4732 Epoch 118/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 1.0000 - loss: 0.1196 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9617 - loss: 0.1407 - val_accuracy: 0.8733 - val_loss: 0.4687 Epoch 119/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.8438 - loss: 0.2167 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9467 - loss: 0.1648 - val_accuracy: 0.8667 - val_loss: 0.4579 Epoch 120/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.9688 - loss: 0.0905 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9333 - loss: 0.1941 - val_accuracy: 0.8533 - val_loss: 0.4393 Epoch 121/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.9375 - loss: 0.1525 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9167 - loss: 0.2020 - val_accuracy: 0.8533 - val_loss: 0.5083 Epoch 122/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.9375 - loss: 0.2242 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9450 - loss: 0.1498 - val_accuracy: 0.8667 - val_loss: 0.5067 Epoch 123/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9062 - loss: 0.1225 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9450 - loss: 0.1515 - val_accuracy: 0.8533 - val_loss: 0.4898 Epoch 124/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.1381 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9567 - loss: 0.1490 - val_accuracy: 0.8800 - val_loss: 0.4441 Epoch 125/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.1381 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9483 - loss: 0.1514 - val_accuracy: 0.8933 - val_loss: 0.4255 Epoch 126/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9375 - loss: 0.1117 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9467 - loss: 0.1397 - val_accuracy: 0.8933 - val_loss: 0.4584 Epoch 127/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9375 - loss: 0.1142 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9417 - loss: 0.1426 - val_accuracy: 0.8733 - val_loss: 0.4350 Epoch 128/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 1.0000 - loss: 0.1252 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9383 - loss: 0.1651 - val_accuracy: 0.8733 - val_loss: 0.4712 Epoch 129/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 10ms/step - accuracy: 1.0000 - loss: 0.1114 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 3ms/step - accuracy: 0.9600 - loss: 0.1507 - val_accuracy: 0.8600 - val_loss: 0.4947 Epoch 130/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.8438 - loss: 0.2308 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9300 - loss: 0.1748 - val_accuracy: 0.8733 - val_loss: 0.4685 Epoch 131/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.1502 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9500 - loss: 0.1469 - val_accuracy: 0.8600 - val_loss: 0.4648 Epoch 132/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9375 - loss: 0.1676 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9450 - loss: 0.1530 - val_accuracy: 0.8400 - val_loss: 0.5693 Epoch 133/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.8438 - loss: 0.2883 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9283 - loss: 0.1783 - val_accuracy: 0.8800 - val_loss: 0.4488 Epoch 134/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9375 - loss: 0.1905 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9383 - loss: 0.1657 - val_accuracy: 0.8800 - val_loss: 0.4884 Epoch 135/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.1362 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9633 - loss: 0.1320 - val_accuracy: 0.9067 - val_loss: 0.4386 Epoch 136/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 1.0000 - loss: 0.0934 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9450 - loss: 0.1411 - val_accuracy: 0.8867 - val_loss: 0.4809 Epoch 137/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.0849 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9333 - loss: 0.1650 - val_accuracy: 0.8800 - val_loss: 0.5075 Epoch 138/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9062 - loss: 0.1989 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9317 - loss: 0.1634 - val_accuracy: 0.8600 - val_loss: 0.4806 Epoch 139/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 1.0000 - loss: 0.0605 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9433 - loss: 0.1589 - val_accuracy: 0.8800 - val_loss: 0.4605 Epoch 140/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.0821 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9400 - loss: 0.1530 - val_accuracy: 0.8600 - val_loss: 0.5356 Epoch 141/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.1569 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9200 - loss: 0.2025 - val_accuracy: 0.8933 - val_loss: 0.4506 Epoch 142/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 1.0000 - loss: 0.1272 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9350 - loss: 0.2026 - val_accuracy: 0.8733 - val_loss: 0.5137 Epoch 143/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 13ms/step - accuracy: 1.0000 - loss: 0.1080 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9483 - loss: 0.1609 - val_accuracy: 0.8533 - val_loss: 0.4935 Epoch 144/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 1.0000 - loss: 0.0755 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9600 - loss: 0.1253 - val_accuracy: 0.9000 - val_loss: 0.4657 Epoch 145/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9062 - loss: 0.1698 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9383 - loss: 0.1433 - val_accuracy: 0.9000 - val_loss: 0.4827 Epoch 146/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.1460 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9367 - loss: 0.1565 - val_accuracy: 0.8400 - val_loss: 0.5308 Epoch 147/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.1161 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9450 - loss: 0.1454 - val_accuracy: 0.9000 - val_loss: 0.4410 Epoch 148/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.1203 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9250 - loss: 0.2012 - val_accuracy: 0.8467 - val_loss: 0.5564 Epoch 149/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9375 - loss: 0.0986 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9517 - loss: 0.1306 - val_accuracy: 0.8867 - val_loss: 0.4923 Epoch 150/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.1034 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9400 - loss: 0.1738 - val_accuracy: 0.8800 - val_loss: 0.5012 Epoch 151/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9062 - loss: 0.2819 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9400 - loss: 0.1585 - val_accuracy: 0.8467 - val_loss: 0.5256 Epoch 152/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 1.0000 - loss: 0.0938 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9600 - loss: 0.1417 - val_accuracy: 0.8733 - val_loss: 0.4613 Epoch 153/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.9688 - loss: 0.0649 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9517 - loss: 0.1337 - val_accuracy: 0.8800 - val_loss: 0.4986 Epoch 154/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.1045 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9517 - loss: 0.1443 - val_accuracy: 0.8667 - val_loss: 0.5049 Epoch 155/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.0803 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9333 - loss: 0.1611 - val_accuracy: 0.8800 - val_loss: 0.5307 Epoch 156/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.9688 - loss: 0.1305 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9617 - loss: 0.1216 - val_accuracy: 0.8667 - val_loss: 0.4871 Epoch 157/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9062 - loss: 0.1954 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9583 - loss: 0.1266 - val_accuracy: 0.8800 - val_loss: 0.4478 Epoch 158/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.1154 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9700 - loss: 0.1063 - val_accuracy: 0.8800 - val_loss: 0.4655 Epoch 159/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 1.0000 - loss: 0.0807 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9617 - loss: 0.1233 - val_accuracy: 0.8867 - val_loss: 0.4907 Epoch 160/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9375 - loss: 0.1425 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9483 - loss: 0.1345 - val_accuracy: 0.8800 - val_loss: 0.4708 Epoch 161/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 1.0000 - loss: 0.1145 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9533 - loss: 0.1228 - val_accuracy: 0.8733 - val_loss: 0.4763 Epoch 162/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.1143 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9600 - loss: 0.1188 - val_accuracy: 0.8800 - val_loss: 0.4717 Epoch 163/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.1005 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9767 - loss: 0.0991 - val_accuracy: 0.8733 - val_loss: 0.4652 Epoch 164/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 1.0000 - loss: 0.0794 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9600 - loss: 0.1231 - val_accuracy: 0.9000 - val_loss: 0.4294 Epoch 165/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 1.0000 - loss: 0.0879 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9733 - loss: 0.1032 - val_accuracy: 0.8600 - val_loss: 0.4850 Epoch 166/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9375 - loss: 0.1603 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9567 - loss: 0.1261 - val_accuracy: 0.8733 - val_loss: 0.4644 Epoch 167/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.9688 - loss: 0.1682 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9600 - loss: 0.1244 - val_accuracy: 0.8533 - val_loss: 0.4968 Epoch 168/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.8750 - loss: 0.2806 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9417 - loss: 0.1369 - val_accuracy: 0.8933 - val_loss: 0.4950 Epoch 169/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9375 - loss: 0.1324 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9417 - loss: 0.1458 - val_accuracy: 0.8467 - val_loss: 0.5546 Epoch 170/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 1.0000 - loss: 0.0686 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9617 - loss: 0.1146 - val_accuracy: 0.8933 - val_loss: 0.5045 Epoch 171/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 9ms/step - accuracy: 0.9062 - loss: 0.1303 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9600 - loss: 0.1030 - val_accuracy: 0.8933 - val_loss: 0.4884 Epoch 172/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.1293 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9583 - loss: 0.1186 - val_accuracy: 0.8600 - val_loss: 0.5266 Epoch 173/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step - accuracy: 0.9688 - loss: 0.1418 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9650 - loss: 0.1157 - val_accuracy: 0.8667 - val_loss: 0.5317 Epoch 174/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9375 - loss: 0.1143 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9567 - loss: 0.1269 - val_accuracy: 0.8733 - val_loss: 0.4806 Epoch 175/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 1.0000 - loss: 0.0496 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9600 - loss: 0.1241 - val_accuracy: 0.8600 - val_loss: 0.5221 Epoch 176/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9375 - loss: 0.1053 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9500 - loss: 0.1310 - val_accuracy: 0.8533 - val_loss: 0.5370 Epoch 177/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 1.0000 - loss: 0.0642 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9500 - loss: 0.1282 - val_accuracy: 0.9000 - val_loss: 0.4583 Epoch 178/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.1185 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9500 - loss: 0.1285 - val_accuracy: 0.8400 - val_loss: 0.5501 Epoch 179/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.1364 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9467 - loss: 0.1330 - val_accuracy: 0.8733 - val_loss: 0.5023 Epoch 180/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9375 - loss: 0.0832 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9533 - loss: 0.1200 - val_accuracy: 0.8800 - val_loss: 0.5336 Epoch 181/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.1003 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9583 - loss: 0.1246 - val_accuracy: 0.8733 - val_loss: 0.5345 Epoch 182/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 1.0000 - loss: 0.0467 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9433 - loss: 0.1615 - val_accuracy: 0.8600 - val_loss: 0.5283 Epoch 183/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9062 - loss: 0.1961 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9150 - loss: 0.2182 - val_accuracy: 0.8733 - val_loss: 0.5385 Epoch 184/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 1.0000 - loss: 0.0927 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9200 - loss: 0.2407 - val_accuracy: 0.8200 - val_loss: 0.7162 Epoch 185/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9062 - loss: 0.3454 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9283 - loss: 0.1870 - val_accuracy: 0.8333 - val_loss: 0.7321 Epoch 186/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 1.0000 - loss: 0.0361 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9300 - loss: 0.1744 - val_accuracy: 0.8867 - val_loss: 0.4387 Epoch 187/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 1.0000 - loss: 0.0810 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9733 - loss: 0.1043 - val_accuracy: 0.8867 - val_loss: 0.4754 Epoch 188/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.1116 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9550 - loss: 0.1256 - val_accuracy: 0.8733 - val_loss: 0.5109 Epoch 189/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9375 - loss: 0.1423 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9500 - loss: 0.1357 - val_accuracy: 0.9000 - val_loss: 0.4611 Epoch 190/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9062 - loss: 0.1618 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9733 - loss: 0.0917 - val_accuracy: 0.8933 - val_loss: 0.4567 Epoch 191/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9375 - loss: 0.1214 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9617 - loss: 0.1040 - val_accuracy: 0.8933 - val_loss: 0.4647 Epoch 192/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 1.0000 - loss: 0.0558 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9633 - loss: 0.1081 - val_accuracy: 0.8800 - val_loss: 0.4807 Epoch 193/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9375 - loss: 0.1588 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9683 - loss: 0.0944 - val_accuracy: 0.8867 - val_loss: 0.4742 Epoch 194/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.0593 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9800 - loss: 0.0800 - val_accuracy: 0.8867 - val_loss: 0.4830 Epoch 195/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 1.0000 - loss: 0.0532 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9617 - loss: 0.1028 - val_accuracy: 0.8867 - val_loss: 0.4583 Epoch 196/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.1218 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9633 - loss: 0.1282 - val_accuracy: 0.8733 - val_loss: 0.5288 Epoch 197/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.1233 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9600 - loss: 0.1215 - val_accuracy: 0.8867 - val_loss: 0.5250 Epoch 198/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 1.0000 - loss: 0.0595 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9683 - loss: 0.1071 - val_accuracy: 0.9000 - val_loss: 0.4805 Epoch 199/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9375 - loss: 0.1002 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9717 - loss: 0.0868 - val_accuracy: 0.9000 - val_loss: 0.5176 Epoch 200/200 1/19 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.9688 - loss: 0.1236 19/19 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9667 - loss: 0.1116 - val_accuracy: 0.8800 - val_loss: 0.4911
In diesem Beispiel ist X die Designmatrix, y der Ergebnisvektor, und das Argument epochs gibt an, wie viele Epochen der Optimierer durchlaufen soll. Keras gibt den Fortschritt beim Optimieren an, es könnte so aussehen
Epoch 1/200
25/25 [==============================] - 0s 2ms/step - loss: 1.5984 - accuracy: 0.2438
Epoch 2/200
25/25 [==============================] - 0s 2ms/step - loss: 1.5709 - accuracy: 0.2763
Epoch 3/200
25/25 [==============================] - 0s 3ms/step - loss: 1.5550 - accuracy: 0.3013
Hierbei kann man die aktuelle Epoche, den Batch (für stochastischen Gradientenabstieg) und die aktuelle Genauigkeit der Trainingsdaten sehen. In diesem Beispiel werden alle Epochen bis zum Abschluss ausgeführt, daher sehen wir 32/32 für Batches, aber normalerweise kann man die Batch-Nummer sehen, die sich während des Trainings fortschreitet. Dieses Beispiel funktioniert sehr schnell, Keras meldet 2 ms pro Schritt (Batch) und die Gesamtzeit für die Epoche ist zu gering, um gemeldet zu werden. Aber eine einzelne Epoche kann bei komplexeren Modellen und mehr Daten viele Minuten dauern.
Die während des Trainings angezeigte Modellqualität (hier Genauigkeit) ist eine laufende Trainingsmetrik und kann zwischen Batches und Epochen schwanken. Sie gibt nur eine grobe Richtlinie für die tatsächliche Modellgüte und sollte durch eine getrennte Auswertung auf Validierungs- oder Testdaten ergänzt werden.
Keras ermöglicht es Ihnen, Vorhersagen mit einem Modell zu treffen, das nicht angepasst ist (im Gegensatz zu scikit-learn, wo das einen Fehler verursacht). Die Ergebnisse werden bestenfalls mittelmäßig aussehen.
Vorhersagen und Plotten
Wenn die Anpassung abgeschlossen ist, können wir das Modell für Vorhersagen verwenden. Die Vorhersage funktioniert ähnlich wie in sklearn, nur dass die predict-Methode die Wahrscheinlichkeit vorhersagt, nicht die Kategorie (analog zu sklearn’s predict_proba).
phat = model.predict(X_test)1/8 ━━━━━━━━━━━━━━━━━━━━ 0s 21ms/step 8/8 ━━━━━━━━━━━━━━━━━━━━ 0s 3ms/step
In diesem Beispiel handelt es sich um eine Matrix mit 5 Spalten, wobei jede Spalte die Wahrscheinlichkeit darstellt, dass der Datenpunkt zur entsprechenden Kategorie gehört. Beispielsweise könnten Zeilen von phat so aussehen:
phat[:5]array([[6.7852611e-30, 4.7236767e-11, 3.7823245e-01, 6.1790609e-01,
3.8614913e-03],
[2.3876208e-01, 7.5912380e-01, 2.1141015e-03, 3.8631465e-13,
8.4735198e-23],
[9.9991900e-01, 8.1076039e-05, 3.2490283e-10, 4.2791960e-22,
1.5502635e-32],
[9.9842817e-01, 1.5717631e-03, 2.1607143e-09, 2.3510848e-21,
2.8858791e-35],
[9.9999034e-01, 9.6942849e-06, 5.6804259e-11, 1.2430986e-23,
2.6429934e-34]], dtype=float32)
Wir sehen, dass für jedes Test-Fall eine Wahrscheinlichkeit für jede Kategorie angegeben ist. Als nächstes wollen wir mit np.argmax(phat, axis=-1) die Spalte (Kategorie) finden, mit der höchsten Wahrscheinlichkeit. Es findet einfach die Position der größten Elemente im Array entlang der letzten Achse (axis=-1), d.h. Spalten. Für jede Zeile finden wir also die entsprechende Spaltennummer. Beachten Sie, dass np.argmax die Spalten ab 0 zählt, nicht ab 1:
yhat = np.argmax(phat, axis=-1)
yhat[:5]array([3, 1, 0, 0, 0])
Endlich können wir die Verwirrungsmatrix mit pd.crosstab berechnen und die Genauigkeit berechnen:
from sklearn.metrics import confusion_matrix
print("confusion matrix:\n", confusion_matrix(y_test, yhat))
print("Accuracy (on test data):", np.mean(y_test == yhat))confusion matrix:
[[52 2 0 0 0]
[ 4 23 6 1 0]
[ 2 2 59 7 0]
[ 0 0 3 31 4]
[ 0 0 0 3 51]]
Accuracy (on test data): 0.864
In diesem Beispiel machen wir Vorhersagen auf Testdaten, aber wir können natürlich auch einen anderen Datensatz für Vorhersagen auswählen. Da der vorhergesagte Wert eine Wahrscheinlichkeitsmatrix mit 5 Spalten sein wird, berechnen wir yhat als die Spaltennummer, die die größte Wahrscheinlichkeit für jede Zeile enthält.
Wie man sehen kann, ist die Verwirrungsmatrix fast ausschließlich auf der Hauptdiagonalen besetzt, und die Genauigkeit ist hoch.
Schließlich müssen wir, wenn wir ein ähnliches Diagramm wie oben erstellen möchten, die DBPlot-Funktion anpassen, um zu berücksichtigen, dass Keras-Modelle nur Wahrscheinlichkeiten vorhersagen.
def DBPlot(m, X, y, nGrid = 300):
x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1
x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx1, xx2 = np.meshgrid(np.linspace(x1_min, x1_max, nGrid),
np.linspace(x2_min, x2_max, nGrid))
XX = np.column_stack((xx1.ravel(), xx2.ravel()))
## predict probability
phat = m.predict(XX, verbose=0)
## find the column that corresponds to the maximum probability
hatyy = np.argmax(phat, axis=-1).reshape(xx1.shape)
fig = px.imshow(hatyy, width=600, height=600)
fig.add_scatter(x=X[:,0]/(x1_max-x1_min)*nGrid+nGrid/2, y=X[:,1]/(x2_max-x2_min)*nGrid+nGrid/2, mode="markers",
marker=dict(color=[mcolors[i] for i in y]), marker_line=dict(width=.3, color="black"))
fig.update_coloraxes(showscale=False)
fig.update_layout(showlegend=False)
fig.show()DBPlot(model, X_test, y_test)Noch einmal, die Funktion ist fast identisch mit der sklearn Version, außer der Zeile, die np.argmax(phat, axis=-1) enthält, die die vorhergesagten Wahrscheinlichkeiten in Kategorien umwandelt.