Bernd Thomas
Beck et al.
Published in
13 min readNov 13, 2019

--

5.3 Ein NN mit Transfer Learning lernt Vielfache von 7 erkennen

Ob eine Zahl Vielfaches von 7 ist, lernt man anhand einer einfachen Regel, die ähnlich der Vielfache von 3 Erkennung in zwei Teile zerlget werden kann. Allerdings im ersten Teil ganz anders.

Die beiden Teilaufgaben sind:

(1) Lernen, eine Zahl nach einem bestimmten Verfahren sukzessive zu reduzieren

(2) Zweistellige Zahlen als Vielfache von 7 zu erkennen, also die 0, 7 und 14

Das Modell für (2) kennen wir im Wesentlichen schon. Es muss nur neu trainiert werden, eben auf Vielfache von 7 und für einen erweiterten Basis-Zahlenbereich.

Ausserdem muss bei größeren Zahlen die Reduktion mehrfach durchgeführt werden, also die Reduktion von der Reduktion von der Reduktion usw., bis das Ergebnis zweistellig wird. Zweistellig deshalb, weil anders als beim Quersummen-Test die Reduktion nicht unbedingt zu einstelligen Zahlen führt, sondern zu Zahlen zwischen -18 und 18. Mit der Aktivierungsfunktion abs() werden negative Ergebnisse positiv gemacht, so dass der Basis-Zahlenraum auf 0 ... 18 beschränkt bleibt.

Wenn wir also ein Modell haben, das lernt, die Reduktion zu bilden, müsste dieses Modell iterativ auf seinen eigenen Output angewendet werden, bis der Output im Basis-Zahlenbereich liegt. Dem folgt dann eine Modell-Schicht für die Aufgabe (2), die dazu den Output der letzten Reduktion aufnimmt.

Eine solche Modell-Architektur kann man durch eine Kette, oder Schleife, von Modellschichten abbilden, also eine Adaption der Recurrent Neural Network (RNN) Methodik. Eine weitere Methodik, meist aus der Bildinterpretation und zusammen mit CNN eingesetzt, ist das Transfer Learning (TL).

Beim TL werden bereits trainierte Modelle bzw “Modellvorstufen” verwendet und nur noch die neuen “Schichten” dahinter nachgeschaltet und trainiert. D.h. der Output des bereits trainierten Teils wird Input des noch nicht trainierten Teils (Transfer). Man kann das auch so interpretieren: Was schon gelernt wurde, wird nicht noch mal neu gelernt, wenn es bei einer neuen Lernaufgabe verwendet werden kann. (Entsprechend werden die Parameter dieses Teils auf trainable = False gesetzt (keras)).

In unserem Fall wird das gleiche, einmal trainierte Modell (für die Reduktion) mehrfach “hintereinander geschaltet” und mit dem Modell für (2) per Output-Input-Beziehung verbunden. Nur noch dieser letzte Layer wird trainiert.

Das [X,y] Datenset hat dann in y die Klassifikation der Zahl (aus X) als Vielfaches von 7 (y=0) oder nicht (y=1).

Eine wichtige Rolle spielt wieder die Repräsentation der Input-Daten — insbesondere bei der Output-Input Propagation.

Um das zu verstehen und zu erproben, entwickeln wir das hier teilweise “per Hand”.

  1. Pre-Trainng: Einfaches Perzeptron (in keras), das lernt, die Reduktion einer Zahl zu berechnen. Diese Reduktion einer Zahl x besteht hier konkret darin, das Doppelte der letzten Ziffer von der Zahl, die durch Wegfall der letzten Ziffer entsteht, zu subtrahieren. Also formal: x -> (x'b) -> y = x' - 2*b
  2. Mit dem trainierten Modell wird eine Kette von pre-trainierten Modellen durchlaufen; dazwischen Output-Input Konvertierung.
  3. Training des Gesamtmodells mit einem “zweistellige Vielfache” Modell als letzte Schicht

Die Trainingsdaten sind Zahlen einer festen bzw. maximalen Länge, die zeichenweise als Input angeboten werden. Der Output der inneren Modellschichten ist eine Zahl. Dieser wird wieder zum Input der nächsten Schicht konvertiert. Die Konvertierungen erfolgen durch allgemeine Funktionen, die nicht Gegenstand der Lernaufgabe sind. Für die Transfers zwischen den pre-trained Schichten verwenden wir die Abbildung to_digits, die eine Zahl in ihre Ziffernfolge wandelt. Für den Transfer in die letzte Modellschicht wird die übliche one-hot-Kodierung verwendet, nun aber auf 19-dim Einheitsvektoren statt 10-dim, da die Vielfachen von 7 unter den zweistelligen (nicht-negativen) Zahlen erlernt werden müssen.

5.3.1 Pre-Training: Einfaches Perzeptron, das lernt, die “Reduktion” zu berechnen

Die Datasets bestehen aus einer Input-Zahl x und dem Zielwert y = x'-2*b, wobei b die Einer-Ziffer der Zahl x ist und x' die "Restzahl", die durch Weglassen von b entsteht. Beispiel: x = 17059 -> y = 1705-2*9 = 1687.

Das NN für die Reduktion soll lernen, einen Reduktionsschritt durchzuführen, also von 17059 auf 1687 als Target zu schließen.

Um die Targetwerte y zu den Zahlen des Pre-Training Datasets X zu generieren - einmalig - definieren wir die Helfer-Funktionen split_num und to_reduced. Damit können wir die Aufteilung programmatisch erstellen statt ein X,y Set per Hand zu definieren.

Die Festlegung der Problemparameter und die Generierung von Trainings- und Test- Datasets für die Teilaufgabe erfolgt wie beim NN für Quersummen, allerdings angepaßt auf die Reduktionsaufgabe.

# Generate a set of integers between 0 and 9999
# For y calculate the the reduction

import numpy as np
import random as rd
import matplotlib.pyplot as plt # Für plots verwenden wir die mathplotlib
from keras.models import Sequential
from keras.layers import Dense
from keras.optimizers import sgd, adam # stochastic gradient descent or adam

n_pos = 4
nmin,nmax = 0,10000 # nmax = Anzahl der Ziffern (0..9)
n_cases = 700
prange = range(10) # print output typical range

# pad_zeros() - as in 5.1
# to_string() - as in 5.1
# to_digits() - as in 5.1
# Generate data set and convert to digits
X = np.random.randint(nmin,nmax,size=(n_cases))
X = to_digits(X,n_pos)
print(X[:10])

# We now have a dataset X that consists of the digits of the random numbers generated above

# New Helper functions for reduction targets definition

def split_num(x,cut=-1):
# x is a sequence of digits
# cut is where the number is cut in two. Default is -1.
scale = 1
num = 0
for d in reversed(x[:cut]):
num += d*scale
scale *= 10
return num

def to_reduced(x):
# x is a (padded) sequence of digits
d = x[-1] # Last digit
reduced = split_num(x) - 2*d
reduced = int(reduced)
reduced_abs = abs(reduced)
# Muss zur Aktivierung (K.abs) passen
return reduced_abs

# Generate target values y from data set X using helper function
y = np.array(list(to_reduced(x) for x in X))
print(list((X[i],y[i]) for i in prange))

# Aufteilung in Traings- und Testdaten - simple partitioning
n_test = 150
partition = n_cases - n_test
X_train = X[:partition]
y_train = y[:partition]
X_test = X[partition:]
y_test = y[partition:]

['8557' '6248' '7441' '6847' '5864' '1237' '6528' '6536' '2462' '1380']
[[8 5 5 7]
[6 2 4 8]
[7 4 4 1]
[6 8 4 7]
[5 8 6 4]
[1 2 3 7]
[6 5 2 8]
[6 5 3 6]
[2 4 6 2]
[1 3 8 0]]
[(array([8, 5, 5, 7]), 841), (array([6, 2, 4, 8]), 608), (array([7, 4, 4, 1]), 742), (array([6, 8, 4, 7]), 670), (array([5, 8, 6, 4]), 578), (array([1, 2, 3, 7]), 109), (array([6, 5, 2, 8]), 636), (array([6, 5, 3, 6]), 641), (array([2, 4, 6, 2]), 242), (array([1, 3, 8, 0]), 138)]

Die Ausgabe zeigt unten die ersten 10 Zahlen als Ziffernfolge und den zugehörigen Wert der ersten Reduktionsstufe.

Entwurf und Training des Modells für das Lernen der Aufteilung und Reduktion einer Zahl

Mit keras reicht ein simples Perzeptron, wie schon beim Quersummen-Modell in 5.1.

# Design keras Model for Reduction 

from keras import backend as K # For activation function abs()
global n_pos # In this example, n_pos = 4

mred = Sequential() # Model Reduce - mred
mred.add(Dense(1,activation=K.abs,use_bias=False,
input_shape=(n_pos,)))
# Zum besseren Verständnis Knoten ohne bias Parameter
# Als activation wird K.abs verwendet um negative Zahlen zu
# vermeiden, die bei "linear" auftreten könnten

ms = mred
ms.summary()

# Compile keras model specificaion
sgd1 = sgd(lr= 0.01) # sgd with learning rate
ms.compile(optimizer=sgd1,loss='mean_squared_error',metrics=['accuracy'])
# Display initial weights
ms.get_weights()
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense_4 (Dense) (None, 1) 4
=================================================================
Total params: 4
Trainable params: 4
Non-trainable params: 0
_________________________________________________________________
[array([[ 0.6753278 ],
[-0.30307811],
[-0.14772236],
[-0.2984851 ]], dtype=float32)]

Training mit Optionen für batch_size und Anzahl epochs und Anlegen der History

# Train checksum model, saving epoch historyep = 400
bs = 100
hist = ms.fit(X_train,y_train,epochs=ep,batch_size=bs,verbose=0)
print([hist.history['loss'][i] for i in range(0,20,1)])
ms.get_weights() # show trained weights[86646.22771661932, 7092.914306640625, 568.5847112482244, 113.48939687555486, 15.78437987240878, 1.7087099768898704, 0.3372399414127523, 0.027334700846536594, 0.0020112023736477236, 0.00012916671998523682, 1.7503663664022248e-05, 2.4331575745732565e-06, 3.22016036462132e-07, 5.3793485383318344e-08, 7.402643629397041e-09, 3.677280621419951e-09, 4.492527532118878e-10, 1.7677683496323965e-11, 1.7697112714659173e-11, 1.746560542972589e-11][array([[100. ],
[ 9.999998 ],
[ 1.0000011],
[ -1.9999992]], dtype=float32)]

Das sieht gut aus: Die Gewichte entwickeln sich schnell zu einer Lösung (langsamer bei größerer batch_size), die man sich als theoretischen Lösung überlegen kann: bei maximal vierstelligen Zahlen (100, 10, 1, -2). Wir verzichten hier auf Plots.

Es gibt hier offensichtlich kein Problem mit den unterschiedlichen Größenordnungen der Gewichte und damit kein Regularisierungsbedarf. Es wäre zu prüfen, ob das Verhalten skaliert oder ob mit größerer Stellenzahl Schwierigkeiten entstehen.

Evaluation mit den Testdaten:

# Check training quality on test data (not used in training)

y_pred = list(ms.predict(X_test))

print('x_test y_test y_pred y_class')
acc = 0 # Counter for accuracy
for i in range(len(y_pred)):
y_class = int(round(y_pred[i][0]))
# Prediction yields floats, comparison needs intergers
print(X_test[i], y_test[i],y_pred[i][0],y_class)
acc += 1 if y_test[i] == y_class else 0

if acc == len(y_pred):
print('All',acc,'predicitons correct')
else:
print(acc,' predictions correct out of',len(y_pred),'test caes. Accuracy:',acc/len(y_pred))
x_test y_test y_pred y_class
[6 7 6 8] 660 660.0 660
[3 4 3 7] 329 329.0 329
[6 9 4 6] 682 682.0 682
[5 2 6 6] 514 514.0 514
[4 8 4 8] 468 468.0 468
[6 6 0 2] 656 656.0 656
[5 8 7 2] 583 583.0 583
[8 0 9 3] 803 803.0 803
[5 4 5 4] 537 537.0 537
[5 9 6 1] 594 594.0 594
[0 0 0 9] 18 17.999992 18
[5 0 8 6] 496 496.0 496
[2 7 9 2] 275 275.0 275
[1 5 7 8] 141 141.0 141
...
[5 3 1 7] 517 517.0 517
[3 0 6 2] 302 302.0 302
[8 4 2 2] 838 838.0 838
[7 1 4 4] 706 706.0 706
All 150 predicitons correct

Perfekt! — Das pre-trained Modell ist damit erstellt und getestet.

Es kann jetzt abgespeichert werden und bei Bedarf mitsamt den trainierten Gewichten verwendet werden. Verwendung bedeutet, ein Set von zu klassifizierenden Zahlen als Input vorzugeben (ohne Klassifikation) und das Modell mit model.predict(X) aufzurufen. Dabei ist vorher das Eingabeset mit to_digits zu konvertieren: X = to_digits(X,n_pos) (n_pos ist die gewünschte fixe Stellenanzahl).

Die mathematische Regel ist: eine Zahl ist Vielfaches von 7, wenn ihre Reduktion ein Vielfaches von 7 ist. Wieder herrlich rekursiv! Und direkt in einen Berechnungsalgorithmus umzusetzen. Als ML Aufgabe aber …

5.3.2 Transfer Learning Modell und Training des Gesamt-Modells

Generierung von Datasets für Training und Test

Die Zufallszahlen X werden klassifizert nach Rest bei Division durch 7. Dabei wird y=0 gesetzt, wenn die Division aufgeht, y=1, wenn nicht.

# Imports

import numpy as np
import random as rd
import matplotlib.pyplot as plt # Für plots verwenden wir die mathplotlib
from keras.models import Sequential
from keras.layers import Dense
from keras.utils import to_categorical
from keras.optimizers import sgd, adam # stochastic gradient descent or adam

# Problem settings
n_pos = 4
nmin,nmax = 0,10000 # nmax = Anzahl der Ziffern (0..9)
n_cases = 700
prange = range(10) # print output typical range

# Helper functions
# pad_zeros() - as in 5.1
# to_string() - as in 5.1
# to_digits() - as in 5.1
# to_class() - as in 5.1
# Generating Datasets for multiples of 7 training
# With a not-too-small subset of numbers that are
# multiples of 7 for better training results

X = np.random.randint(nmin,nmax,size=(n_cases))
idx = list(rd.choice(range(n_cases))for i in range(n_cases))
print([idx[i] for i in prange])
for i in idx:
X[i]= X[i]*7 if X[i]*7<nmax else X[i]
# Da es hier nur auf die Erzeugung von Trainingsdaten ankommt,
# machen wir das per mod-7 Funktion
y = np.array(list(x%7 for x in X))
y = np.where(y>0,1,y) # Restklassen > 0 zu y=1

print(np.count_nonzero(y)) # Anzahl Fälle mit y > 0

n_test = 200
n_train = n_cases - n_test
X_train = X[:n_train]
y_train = y[:n_train]
X_test = X[n_train:]
y_test = y[n_train:]

[379, 75, 413, 162, 498, 38, 9, 31, 561, 264]
556

Data-Sets: Die erste Zeile zeigt die ersten 10 Indizes der Zahlen, die zu Vielfachen von 7 gemacht wurden. 556 ist die Anzahl der Zahlen, die nicht Vielfache von 7 sind.

Das komplette NN Modell mit Transfer Learning

Das Bestimmen der Reduktion wurde schon durch das Modell mred oben gelernt. Wir verwenden das als pre-trained model. Die prinzipielle Mehrstufigkeit der Reduktionsbildung wird über mehrere Schichten (hier) des geichen Modells abgebildet. Die Modellschichten werden über direkte Output-Input-Beziehung verbunden, d.h. die Aktivierungsfunktion ist die Identität (activation = 'linear').

Die noch zu trainierende Modell-Schicht ist die, die lernt, eine Zahl zwischen 0 und 18 als Vielfaches von 7 zu erkennen.

Anm.: Die iterierte Reduktion hat ähnlich wie die iterierte Quersumme die Eigenschaft, dass die Zahlen schrittweise kleiner werden. Bei der Quersumme werden sie schließlich einstellig und bleiben bei weiteren Schritten unverändert. Bei der Reduktion erreichen sie den Zahlenbereich 0,..18, aus dem weitere Reduktionsschritte nicht mehr heraus führen.

# Only model for the final task needs to be trained: two digit (<=18) classificationmdd7 = Sequential()          # Model Double Digit 7 (msd7)# Add dense layer which takes input as one 19-dim unit vector, 
# which represents the potential one-hot coded output of the previous model step
one_hot_input_shape = (19,) # Only 0 to 18 may occur
mdd7.add(Dense(1, activation='linear',use_bias=False,
input_shape=one_hot_input_shape))
mdd7.summary()
# Compile Model mdd7
sgd1 = sgd(lr= 0.01) # sgd with learning rate
mdd7.compile(optimizer=sgd1,loss='mean_squared_error',
metrics=['accuracy'])
mdd7.weights
print(mdd7.get_weights()) # Show initial weights
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense_5 (Dense) (None, 1) 19
=================================================================
Total params: 19
Trainable params: 19
Non-trainable params: 0
_________________________________________________________________
[array([[ 0.13626736],
[ 0.28966093],
[ 0.47749066],
[ 0.1657446 ],
[-0.00558561],
[-0.24149784],
[-0.3412344 ],
[-0.3234121 ],
[-0.49548167],
[ 0.12363046],
[ 0.07026035],
[-0.457448 ],
[ 0.18412983],
[-0.54558355],
[-0.13022551],
[-0.3641327 ],
[ 0.33014858],
[-0.48987323],
[-0.1408894 ]], dtype=float32)]

Training des Gesamtmodells:

# Sequence of mred models written as loop 
# Using mred.predict is equivalent to include mred layers in training with trainable=False

global mred # Trained simple reduction model

max_loops = 5 # Task parameter (related to n_pos)
loops = 0
T = X_train
print(T.shape)

while loops < max_loops:
loops +=1
T = to_digits(T,n_pos)
pred = mred.predict(T) # Deploying pre-trained reduction model
T = to_class(pred)
# 'Prediction' of mred is a float as a result of weighted sums
print(y_train[:10])
print('Pre-trained reduction model depth:',loops)
print(T.shape,T[:10])

# Now connect last output T as input to mdd7 and train mdd7
# But first convert to one-hot coded input

T = to_categorical(T)
print(T.shape,T[:10])
ep = 100 # Set number of epochs
bs = 10 # Set bacth size
hist1 = mdd7.fit(T,y_train,epochs=ep,batch_size=bs,verbose=0)

print([hist1.history['loss'][i] for i in range(0,ep,5)])
(500,)
['2775' '5990' '5923' '0475' '7983' '6555' '8792' '3116' '0685' '8667']
['0267' '0599' '0586' '0037' '0792' '0645' '0875' '0299' '0058' '0852']
['0012' '0041' '0046' '0011' '0075' '0054' '0077' '0011' '0011' '0081']
['0003' '0002' '0008' '0001' '0003' '0003' '0007' '0001' '0001' '0006']
['0006' '0004' '0016' '0002' '0006' '0006' '0014' '0002' '0002' '0012']
[1 1 1 1 1 1 0 1 1 1]
Pre-trained reduction model depth: 5
(500,) [12 8 11 4 12 12 7 4 4 3]
[[ 0 1 2 3 4 5 6 7 8 9 10 11 12 14 15 16 18]
[41 27 45 40 50 5 19 52 40 5 11 35 46 21 21 29 13]]
(500, 19) [[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]]
[0.8056468772888183, 0.42088206827640534, 0.23500484451651574, 0.1405103149265051, 0.0897863313369453, 0.060919525427743794, 0.043482736479490997, 0.03236340740462765, 0.02490873616072349, 0.019701617323444224, 0.015926971696608234, 0.013110966523818206, 0.010959237421338912, 0.009267768580466509, 0.007921689008608155, 0.006828344389823542, 0.0059300835256749455, 0.00518212722395674, 0.004550199149996388, 0.004013759337119041]

Die Ausgabe illustriert die Abfolge der Reduktionsbildung für die ersten 10 Zahlen durch die mred Layer. Zuviele mred Schichten stören nicht, da Werte zwischen 0 und 18 durch die Reduktion wieder zwischen 0 und 18 landen (hier hätten evtl. auch 4 gereicht). Anschließend wird der final output des Quersummen-Stapels gezeigt (wieder für die ersten 10 Trainingszahlen) und die one-hot Codierung. Als letztes die Loss-Entwicklung aus der Training-History.

Konvergenz der Accuracy und Loss-Funktion tut sich schwer, aber mit genügend Trainingsepochen sieht das gut aus. Batches scheinen besser als Gesamt-Set. Je kleiner die Batchgrösse, desto besser scheint die Konvergenz zu sein. Bei batch_size=2 reichen wieder 50 Epochen oder weniger. (Code für Plots weggelassen.)

Abb. 1: Accuracy-Ewicklung (batch_size = 2)
Abb. 2: Konvergenz der Loss-Funktion (batch_size = 2)

Die trainierten Gewichte entsprechen den erwarteten, theoretischen Werten. (Wir verzichten auf Plots.)

# Anzeige der Gewichteprint('Trainierte Gewichte Reduction Layers:\n',mred.get_weights())
print('Trainierte Gewichte Identification:\n',mdd7.get_weights())
Trainierte Gewichte Reduction Layers:
[array([[100. ],
[ 9.999998 ],
[ 1.0000011],
[ -1.9999992]], dtype=float32)]
Trainierte Gewichte Identification:
[array([[ 3.6899655e-05],
[ 9.9681699e-01],
[ 9.9993616e-01],
[ 9.9972403e-01],
[ 9.9995565e-01],
[ 5.4377419e-01],
[ 9.7014248e-01],
[-9.6457125e-06],
[ 9.9950516e-01],
[ 6.7794877e-01],
[ 8.9724958e-01],
[ 9.9868590e-01],
[ 9.9991882e-01],
[-5.4558355e-01],
[-1.9418772e-03],
[ 9.7966236e-01],
[ 9.9798989e-01],
[-4.8987323e-01],
[ 9.1553086e-01]], dtype=float32)]

Die trainierten Gewichte der letzten Schicht zeigen ein alternierendes Muster auf 7, d.h. nahe Null für 0, 7, 14 und nahe 1.0 für die anderen.

Evaluation mit Test-Dataset und “Forward Propagation” der predict Ergebnisse.

# Prediction for test data and test targets

max_loops = 5 # Task parameter specific (related to n_pos)
loops = 0
T = X_test

while loops < max_loops:
# Apply reduction layers
loops +=1
T = to_digits(T,n_pos)
pred = mred.predict(T)
T = to_class(pred)

# Apply double digit layer
T = to_categorical(T)
pred = mdd7.predict(T)
y_pred = to_class(pred)

acc = 1.0 - np.sum(np.abs(y_test - y_pred))/n_test
print('Accuracy Testset:',acc)
for i in range(n_test):
print(X_test[i],y_pred[i],y_test[i])
['9565' '1970' '5881' '4226' '9324' '2189' '7007' '9110' '1672' '0073']
['0946' '0197' '0586' '0410' '0924' '0200' '0686' '0911' '0163' '0001']
['0082' '0005' '0046' '0041' '0084' '0020' '0056' '0089' '0010' '0002']
['0004' '0010' '0008' '0002' '0000' '0002' '0007' '0010' '0001' '0004']
['0008' '0001' '0016' '0004' '0000' '0004' '0014' '0001' '0002' '0008']
Accuracy Testset: 1.0
9565 1 1
1970 1 1
5881 1 1
4226 1 1
9324 0 0
2189 1 1
7007 0 0
9110 1 1
1672 1 1
73 1 1
...
3273 1 1
8743 0 0
2556 1 1

Es gelingt also perfekt, mit diesem NN Modell-Ansatz (RNN, Tansfer Learning) Vielfache von 7 zu klassifizieren.

Weiter lesen: 5.4 Erkenntnisse und Diskussion

Zurück auf Anfang

bernhard.thomas@becketal.com
www.becketal.com

--

--

Bernd Thomas
Beck et al.

Dr. Bernhard Thomas — Mathematics, Theor. Biology, Computational Sciences, AI and advanced Technologies for the Enterprise. Beck et al. Consultant