Der vorherige Artikel war hier In diesem Artikel werden wir versuchen, die "sin" -Funktion mithilfe des Codes zu approximieren, der in der [Einführung in die Deep Learning-Reihe](#Deep Learning Series) eingeführt wurde. Übrigens habe ich in diesem Prozess viele Fehler und Korrekturen gefunden, daher reflektiere ich sie in jedem Artikel.
Der Code läuft auf einem Jupyter-Notebook. Die Einführung des Jupyter-Notizbuchs wird unter hier vorgestellt. Erforderliche Pakete
numpy
matplotlib
tqdm
Es ist geworden.
tqdm
zeigt den Fortschritt nur auf leicht verständliche Weise an. Wenn es also problematisch ist, entfernen Sie das relevante Teil aus dem Testcode und es wird funktionieren.
Der experimentelle Code (test.ipynb
) dieses Artikels wird unverändert auf github hochgeladen.
Den detaillierten Produktionsprozess finden Sie in [Frühere Artikel](#Deep Learning Series).
_layererror.py
class LayerManagerError(Exception):
"""Basisklasse für benutzerdefinierte Fehler in Layer-Modulen"""
pass
class AssignError(LayerManagerError):
def __init__(self, value=None):
if not value is None:
self.value = value
self.message = (str(value)
+ ": Assigning that value is prohibited.")
else:
self.value = None
self.message = "Assigning that value is prohibited."
def __str__(self):
return self.message
class UnmatchUnitError(LayerManagerError):
def __init__(self, prev, n):
self.prev = prev
self.n = n
self.message = "Unmatch units: {} and {}.".format(prev, n)
def __str__(self):
return self.message
class UndefinedLayerError(LayerManagerError):
def __init__(self, type_name):
self.type = type_name
self.message = str(type_name) + ": Undefined layer type."
def __str__(self):
return self.message
baselayer.py
import numpy as np
class BaseLayer():
"""
Alle zugrunde liegenden Ebenenklassen
Beschreiben Sie die Verarbeitung, die der Zwischenschicht und der Ausgabeschicht gemeinsam ist.
"""
def __init__(self, *, prev=1, n=1,
name="", wb_width=5e-2,
act="ReLU", opt="Adam",
act_dic={}, opt_dic={}, **kwds):
self.prev = prev #Anzahl der Ausgänge der vorherigen Ebene=Anzahl der Eingaben in diese Ebene
self.n = n #Anzahl der Ausgänge in dieser Ebene=Anzahl der Eingaben in die nächste Ebene
self.name = name #Der Name dieser Ebene
#Stellen Sie Gewicht und Vorspannung ein
self.w = wb_width*np.random.randn(prev, n)
self.b = wb_width*np.random.randn(n)
#Aktivierungsfunktion(Klasse)Erhalten
self.act = get_act(act, **act_dic)
#Optimierer(Klasse)Erhalten
self.opt = get_opt(opt, **opt_dic)
def forward(self, x):
"""
Implementierung der Vorwärtsausbreitung
"""
#Erinnern Sie sich an Ihre Eingabe
self.x = x.copy()
#Vorwärtsausbreitung
self.u = [email protected] + self.b
self.y = self.act.forward(self.u)
return self.y
def backward(self, grad):
"""
Implementierung der Backpropagation
"""
dact = grad*self.act.backward(self.u, self.y)
self.grad_w = self.x.T@dact
self.grad_b = np.sum(dact, axis=0)
self.grad_x = [email protected]
return self.grad_x
def update(self, **kwds):
"""
Implementierung des Parameterlernens
"""
dw, db = self.opt.update(self.grad_w, self.grad_b, **kwds)
self.w += dw
self.b += db
middlelayer.py
import numpy as np
class MiddleLayer(BaseLayer):
"""
Mittelklasse
Die Eingangsschicht wird auch hinsichtlich der Montage als eine der Zwischenschichten behandelt.
"""
pass
outputlayer.py
import numpy as np
class OutputLayer(BaseLayer):
"""
Ausgabeebenenklasse
"""
def __init__(self, *, err_func="Square", **kwds):
#Verlustfunktion(Klasse)Erhalten
self.errfunc = get_err(err_func)
super().__init__(**kwds)
def backward(self, t):
"""
Implementierung der Backpropagation
"""
#Wenn die Aktivierungsfunktion der Ausgangsschicht die Softmax-Funktion und die Verlustfunktion der Kreuzentropiefehler ist
#Separate Fälle von Fehlerausbreitung
if isinstance(self.act, type(get_act("softmax"))) \
and isinstance(self.errfunc, type(get_err("Cross"))):
dact = self.y - t
self.grad_w = self.x.T@dact
self.grad_b = np.sum(dact, axis=0)
self.grad_x = [email protected]
return self.grad_x
elif isinstance(self.act, type(get_act("sigmoid"))) \
and isinstance(self.errfunc, type(get_err("Binary"))):
dact = self.y - t
self.grad_w = self.x.T@dact
self.grad_b = np.sum(dact, axis=0)
self.grad_x = [email protected]
return self.grad_x
else:
grad = self.errfunc.backward(self.y, t)
return super().backward(grad)
def get_error(self, t):
self.error = self.errfunc.forward(self.y, t)
return self.errfunc.total_error()
layermanager.py
import numpy as np
class _TypeManager():
"""
Manager-Klasse für Ebenentypen
"""
N_TYPE = 2 #Anzahl der Ebenentypen
MIDDLE = 0 #Nummerierung der mittleren Schicht
OUTPUT = 1 #Nummerierung der Ausgabeebene
class LayerManager(_TypeManager):
"""
Manager-Klasse zum Verwalten von Ebenen
"""
def __init__(self):
self.__layer_list = [] #Liste der Ebenen
self.__name_list = [] #Namensliste für jede Schicht
self.__ntype = np.zeros(self.N_TYPE, dtype=int) #Anzahl der Ebenen nach Typ
def __repr__(self):
layerRepr= "layer_list: " + repr(self.__layer_list)
nameRepr = "name_list: " + repr(self.__name_list)
ntypeRepr = "ntype: " + repr(self.__ntype)
return (layerRepr + "\n"
+ nameRepr + "\n"
+ ntypeRepr)
def __str__(self):
layerStr = "layer_list: " + str(self.__layer_list)
nameStr = "name_list: " + str(self.__name_list)
ntypeStr = "ntype: " + str(self.__ntype)
return (layerStr + "\n"
+ nameStr + "\n"
+ ntypeStr)
def __len__(self):
"""
In Python integrierte Funktionen`len`Beschreibt den Vorgang beim Aufruf von.
Gibt die Summe der Anzahl der Ebenen nach Typ zurück.
"""
return int(np.sum(self.__ntype))
def __getitem__(self, key):
"""
Zum Beispiel
lm = LayerManager()
+----------------+
| (Element zu lm hinzufügen) |
+----------------+
x = lm[3].~~
Wird aufgerufen, wenn auf ein Element einer Liste oder eines Arrays zugegriffen wird, z
Beschreiben Sie den Vorgang zu diesem Zeitpunkt.
Scheibe und str,Zugriff nur über int zulassen.
"""
if isinstance(key, slice):
#Wenn der Schlüssel ein Slice ist, beziehen Sie sich auf die Liste der Ebenen mit Slice.
#Ungewöhnlicher Wert(Index außerhalb des Bereichs usw.)Wann wird eingegeben
#Python gibt mir einen Fehler.
return self.__layer_list[key]
elif isinstance(key, str):
#Wenn der Schlüssel eine Zeichenfolge ist, rufen Sie den Index aus der Namensliste jeder Ebene und ab
#Gibt die Elemente der Liste der anwendbaren Ebenen zurück.
if key in self.__name_list:
index = self.__name_list.index(key)
return self.__layer_list[index]
else:
#Wenn der Schlüssel nicht vorhanden ist, wird ein KeyError ausgegeben.
raise KeyError("{}: No such item".format(key))
elif isinstance(key, int):
#Wenn key eine Ganzzahl ist, wird das entsprechende Element in der Liste der Ebenen zurückgegeben.
#Ungewöhnlicher Wert(Index außerhalb des Bereichs usw.)Wann wird eingegeben
#Python gibt mir einen Fehler.
return self.__layer_list[key]
else:
raise KeyError(key, ": Undefined such key type.")
def __setitem__(self, key, value):
"""
Zum Beispiel
lm = LayerManager()
+----------------+
| (Element zu lm hinzufügen) |
+----------------+
lm[1] = x
Wird aufgerufen, wenn auf ein Element einer Liste oder eines Arrays zugegriffen wird, z
Beschreiben Sie den Vorgang zu diesem Zeitpunkt.
Es ist nur das Überschreiben von Elementen zulässig, und das Hinzufügen neuer Elemente ist verboten.
"""
value_type = ""
if isinstance(value, list):
#Auf der rechten Seite angegeben'value'Aber'list'Wenn
#Alle Elemente'BaseLayer'Fehler, wenn die Klasse sie erbt oder nicht.
if not np.all(
np.where(isinstance(value, BaseLayer), True, False)):
self.AssignError()
value_type = "list"
elif isinstance(value, BaseLayer):
#Auf der rechten Seite angegeben'value'Aber'BaseLayer'Ist es eine Klasse?
#Fehler, wenn es nicht vererbt wird.
self.AssignError(type(value))
if value_type == "":
value_type = "BaseLayer"
if isinstance(key, slice):
#Wenn der Schlüssel ein Slice ist, überschreiben Sie das Element in der Liste der Ebenen.
#jedoch'value_type'Aber'list'Sonst ein Fehler.
#Ungewöhnlicher Wert(Index außerhalb des Bereichs usw.)Wann wird eingegeben
#Python gibt mir einen Fehler.
if value_type != "list":
self.AssignError(value_type)
self.__layer_list[key] = value
elif isinstance(key, str):
#Wenn der Schlüssel eine Zeichenfolge ist, rufen Sie den Index aus der Namensliste jeder Ebene und ab
#Überschreiben Sie die Elemente in der Liste der zutreffenden Ebenen.
#jedoch'value_type'Aber'BaseLayer'Sonst ein Fehler.
if value_type != "BaseLayer":
raise AssignError(value_type)
if key in self.__name_list:
index = self.__name_list.index(key)
self.__layer_list[index] = value
else:
#Wenn der Schlüssel nicht vorhanden ist, wird ein KeyError ausgegeben.
raise KeyError("{}: No such item".format(key))
elif isinstance(key, int):
#Wenn key eine Ganzzahl ist, überschreiben Sie das entsprechende Element in der Liste der Ebenen.
#jedoch'value_type'Aber'BaseLayer'Sonst ein Fehler.
#Auch ein abnormaler Wert(Index außerhalb des Bereichs usw.)Wann wird eingegeben
#Python gibt mir einen Fehler.
if value_type != "BaseLayer":
raise AssignError(value_type)
self.__layer_list[key] = value
else:
raise KeyError(key, ": Undefined such key type.")
def __delitem__(self, key):
"""
Zum Beispiel
lm = LayerManager()
+----------------+
| (Element zu lm hinzufügen) |
+----------------+
del lm[2]
Weil es aufgerufen wird, wenn auf das Element der Liste oder des Arrays von der del-Anweisung wie zugegriffen wird
Beschreiben Sie den Vorgang zu diesem Zeitpunkt.
Wenn das angegebene Element vorhanden ist, wird es gelöscht und umbenannt.
"""
if isinstance(key, slice):
#Wenn der Schlüssel ein Slice ist, löschen Sie das angegebene Element unverändert
#Ungewöhnlicher Wert(Index außerhalb des Bereichs usw.)Wann wird eingegeben
#Python gibt mir einen Fehler.
del self.__layer_list[slice]
del self.__name_list[slice]
elif isinstance(key, str):
#Wenn der Schlüssel eine Zeichenfolge ist, rufen Sie den Index aus der Namensliste jeder Ebene und ab
#Löschen Sie das entsprechende Element.
if key in self.__name_list:
del self.__layer_list[index]
del self.__name_list[index]
else:
#Wenn der Schlüssel nicht vorhanden ist, wird ein KeyError ausgegeben.
raise KeyError("{}: No such item".format(key))
elif isinstance(key, int):
#Wenn der Schlüssel eine Ganzzahl ist, löschen Sie das entsprechende Element in der Ebenenliste.
#Ungewöhnlicher Wert(Index außerhalb des Bereichs usw.)Wann wird eingegeben
#Python gibt mir einen Fehler.
del self.__layer_list[key]
else:
raise KeyError(key, ": Undefined such key type.")
#Umbenennen
self._rename()
def _rename(self):
"""
Wenn die Benennung der Namensliste aufgrund der Listenoperation gegen die Regeln verstößt
Benennen Sie die Namensliste und jede Ebene um, um die Regeln erneut zu erfüllen.
Die Namensregel lautet[Ebenentyp][Welche Nummer]Wird besorgt.
Wenn der Ebenentyp Mittlere Ebene ist, Mittlere Ebene
Ausgabe für Ausgabeschicht
Es wird als abgekürzt.
Die Nummer wird nach Typ gezählt.
Auch hier wieder__Zählt nTypen.
"""
#Initialisieren Sie die Anzahl der Ebenen nach Typ
self.__ntype = np.zeros(self.N_TYPE)
#Zählen Sie jede Ebene neu und benennen Sie sie um
for i in range(len(self)):
if "Middle" in self.__name_list[i]:
self.__ntype[self.MIDDLE] += 1
self.__name_list[i] = "Middle{}".format(
self.__ntype[self.MIDDLE])
self.__layer_list[i].name = "Middle{}".format(
self.__ntype[self.MIDDLE])
elif "Output" in self.__name_list[i]:
self.__ntype[self.OUTPUT] += 1
self.__name_list[i] = "Output{}".format(
self.__ntype[self.OUTPUT])
self.__layer_list[i].name = "Output{}".format(
self.__ntype[self.OUTPUT])
else:
raise UndefinedLayerType(self.__name_list[i])
def append(self, *, name="Middle", **kwds):
"""
Implementierung der bekannten Append-Methode, bei der Elemente zu einer Liste hinzugefügt werden.
"""
if "prev" in kwds:
# 'prev'Ist im Schlüsselwort enthalten
#Dies bedeutet, dass die Anzahl der Elemente in der vorherigen Ebene angegeben wird.
#Grundsätzlich soll es also an der Zeit sein, die erste Schicht einzufügen
#Davon abgesehen wird es grundsätzlich automatisch ermittelt und nicht angegeben.
if len(self) != 0:
if kwds["prev"] != self.__layer_list[-1].n:
#Fehler, wenn er nicht mit der Anzahl der Einheiten am Ende übereinstimmt.
raise UnmatchUnitError(self.__layer_list[-1].n,
kwds["prev"])
else:
if len(self) == 0:
#Die erste Ebene muss immer die Anzahl der Eingabeeinheiten angeben.
raise UnmatchUnitError("Input units", "Unspecified")
else:
#Die Anzahl der Einheiten in der letzten Ebene'kwds'Hinzufügen
kwds["prev"] = self.__layer_list[-1].n
#Lesen Sie den Layertyp und ändern Sie den Namen gemäß der Namensregel
if name == "Middle" or name == "mid" or name == "m":
name = "Middle"
elif name == "Output" or name == "out" or name == "o":
name = "Output"
else:
raise UndefinedLayerError(name)
#Fügen Sie eine Ebene hinzu.
if name == "Middle":
#Erhöhen Sie die Ebene nach Typ
self.__ntype[self.MIDDLE] += 1
#Zum Namen hinzufügen
name += str(self.__ntype[self.MIDDLE])
#Zur Namensliste hinzufügen
self.__name_list.append(name)
#Erstellen Sie abschließend eine Ebene und fügen Sie sie der Liste hinzu.
self.__layer_list.append(
MiddleLayer(name=name, **kwds))
elif name == "Output":
#Dies ist auch das gleiche.
self.__ntype[self.OUTPUT] += 1
name += str(self.__ntype[self.OUTPUT])
self.__name_list.append(name)
self.__layer_list.append(
OutputLayer(name=name, **kwds))
#Wenn Sie hier keine else-Anweisung zeichnen, ändern Sie den Namen gemäß der Namensregel
#Schon abnormal auf der Bühne'name'Wurde weggelassen.
def extend(self, lm):
"""
Ein weiterer Layer-Manager, der bereits in der Extend-Methode vorhanden ist'lm'Elemente von
Füge alle Hinzu.
"""
if not isinstance(lm, LayerManager):
# 'lm'Fehler, wenn die Instanz von nicht LayerManager ist.
raise TypeError(type(lm), ": Unexpected type.")
if len(self) != 0:
if self.__layer_list[-1].n != lm[0].prev:
#Mit der Anzahl der Einheiten in Ihrer letzten Ebene
# 'lm'Fehler, wenn die Anzahl der Eingaben in der ersten Schicht von nicht gleich ist.
raise UnmatchUnitError(self.__layer_list[-1].n,
lm[0].prev)
#Beziehungsweise'extend'Nach Methode hinzufügen
self.__layer_list.extend(lm.layer_list)
self.__name_list.extend(lm.name_list)
#Umbenennen
self._rename()
def insert(self, prev_name, name="Middle", **kwds):
"""
Geben Sie in der Einfügemethode den Namen der vorherigen Ebene an und kombinieren Sie ihn mit dieser Ebene.
Fügen Sie ein Element hinzu.
"""
# 'prev_name'Fehler, wenn nicht vorhanden.
if not prev_name in self.__name_list:
raise KeyError(prev_name, ": No such key.")
# 'prev'Ist im Schlüsselwort enthalten
# 'prev_name'Fehler, wenn er nicht mit der Anzahl der Einheiten in der in angegebenen Ebene übereinstimmt.
if "prev" in kwds:
if kwds["prev"] \
!= self.__layer_list[self.index(prev_name)].n:
raise UnmatchUnitError(
kwds["prev"],
self.__layer_list[self.index(prev_name)].n)
# 'n'Ist im Schlüsselwort enthalten
if "n" in kwds:
# 'prev_name'Wenn ist nicht der letzte
if prev_name != self.__name_list[-1]:
#Fehler, wenn er nicht mit der Anzahl der Einheiten in der nächsten Ebene übereinstimmt.
if kwds["n"] != self.__layer_list[
self.index(prev_name)+1].prev:
raise UnmatchUnitError(
kwds["n"],
self.__layer_list[self.index(prev_name)].prev)
#Wenn es noch keine Elemente gibt'append'Geben Sie einen Fehler bei der Verwendung der Methode ein.
if len(self) == 0:
raise RuntimeError(
"You have to use 'append' method instead.")
#Index der Einfügeposition abrufen
index = self.index(prev_name) + 1
#Lesen Sie den Layertyp und ändern Sie den Namen gemäß der Namensregel
if name == "Middle" or name == "mid" or name == "m":
name = "Middle"
elif name == "Output" or name == "out" or name == "o":
name = "Output"
else:
raise UndefinedLayerError(name)
#Element einfügen
#In diesem Moment,'name'Befolgen Sie noch nicht die Namensregeln,
#Ich werde es später umbenennen, also mach dir keine Sorgen.
if "Middle" in name:
self.__layer_list.insert(index,
MiddleLayer(name=name, **kwds))
self.__name_list.insert(index, name)
elif "Output" in name:
self.__layer_list.insert(index,
OutputLayer(name=name, **kwds))
self.__name_list.insert(index, name)
#Umbenennen
self._rename()
def extend_insert(self, prev_name, lm):
"""
Dies ist die ursprüngliche Funktion.
Es verhält sich wie eine Kombination aus der Extend-Methode und der Insert-Methode.
Einfach ausgedrückt ist es wie das Einfügen eines weiteren Ebenenmanagers.
"""
if not isinstance(lm, LayerManager):
# 'lm'Fehler, wenn die Instanz von nicht LayerManager ist.
raise TypeError(type(lm), ": Unexpected type.")
# 'prev_name'Fehler, wenn nicht vorhanden.
if not prev_name in self.__name_list:
raise KeyError(prev_name, ": No such key.")
#Die Anzahl der Einheiten der Schichten vor und nach dem angegebenen Ort sowie der ersten und letzten Schicht von lm
#Wenn sie nicht übereinstimmen, tritt ein Fehler auf.
if len(self) != 0:
if self.__layer_list[self.index(prev_name)].n \
!= lm.layer_list[0].prev:
#Mit der Anzahl der Einheiten an Ihrem angegebenen Standort'lm'Die erste Anzahl von Einheiten in
#Wenn sie nicht übereinstimmen, tritt ein Fehler auf.
raise UnmatchUnitError(
self.__layer_list[self.index(prev_name)].n,
lm.layer_list[0].prev)
if prev_name != self.__name_list[-1]:
# 'prev_name'Ist nicht meine letzte Schicht
if lm.layer_list[-1].n \
!= self.__layer_list[self.index(prev_name)+1].prev:
# 'lm'Die Anzahl der Einheiten am Ende und die nächste Schicht Ihres festgelegten Standorts
# 'prev'Fehler, wenn er nicht mit der Anzahl der Einheiten übereinstimmt.
raise UnmatchUnitError(
lm.layer_list[-1].n,
self.__layer_list[self.index(prev_name)+1].prev)
else:
#Wenn Sie keine Elemente haben'extend'Ich erhalte eine Fehlermeldung bei der Verwendung der Methode.
raise RuntimeError(
"You have to use 'extend' method instead.")
#Index der Einfügeposition abrufen
index = self.index(prev_name) + 1
#Elemente nach der Einfügeposition'buf'Entfernen Sie es nach dem Evakuieren einmal
#Fügen Sie ein Element mit der Extend-Methode hinzu
layer_buf = self.__layer_list[index:]
name_buf = self.__name_list[index:]
del self.__layer_list[index:]
del self.__name_list[index:]
self.extend(lm)
#Fügen Sie das evakuierte Element hinzu
self.__layer_list.extend(layer_buf)
self.__name_list.extend(name_buf)
#Umbenennen
self._rename()
def remove(self, key):
"""
Die Methode remove entfernt das Element mit dem angegebenen Namen.
Es darf auch durch Index angegeben werden.
"""
#Bereits implementiert'del'Der Satz ist in Ordnung.
del self[key]
def index(self, target):
return self.__name_list.index(target)
def name(self, indices):
return self.__name_list[indices]
@property
def layer_list(self):
return self.__layer_list
@property
def name_list(self):
return self.__name_list
@property
def ntype(self):
return self.__ntype
errors.py
import numpy as np
class Error():
def __init__(self, *args,**kwds):
self.error = 0
def forward(self, *args,**kwds):
pass
def backward(self, *args,**kwds):
pass
def total_error(self, *args,**kwds):
return np.sum(self.error)/self.error.size
class SquareError(Error):
def forward(self, y, t, *args,**kwds):
self.error = 0.5 * (y - t)**2
return self.error
def backward(self, y, t, *args,**kwds):
return y - t
class BinaryCrossEntropy(Error):
def forward(self, y, t, *args,**kwds):
self.error = - t*np.log(y) - (1 - t)*np.log(1 - y)
return self.error
def backward(self, y, t, *args,**kwds):
return (y - t) / (y*(1 - y))
class CrossEntropy(Error):
def forward(self, y, t, *args,**kwds):
self.error = - t*np.log(y)
return self.error
def backward(self, y, t, *args,**kwds):
return - t/y
get_err.py
_err_dic = {"Square": SquareError,
"Binary": BinaryCrossEntropy,
"Cross": CrossEntropy,
}
def get_err(name, *args,**kwds):
if name in _err_dic.keys():
errfunc = _err_dic[name](*args,**kwds)
else:
raise ValueError(name + ": Unknown error function")
return errfunc
activations.py
import numpy as np
class Activator():
def __init__(self, *args,**kwds):
pass
def forward(self, *args,**kwds):
raise Exception("Not Implemented")
def backward(self, *args,**kwds):
raise Exception("Not Implemented")
def update(self, *args,**kwds):
pass
class step(Activator):
def forward(self, x, *args,**kwds):
return np.where(x > 0, 1, 0)
def backward(self, x, *args,**kwds):
return np.zeros_like(x)
class identity(Activator):
def forward(self, x, *args,**kwds):
return x
def backward(self, x, *args,**kwds):
return np.ones_like(x)
class bentIdentity(Activator):
def forward(self, x, *args,**kwds):
return 0.5*(np.sqrt(x**2 + 1) - 1) + x
def backward(self, x, *args,**kwds):
return 0.5*x/np.sqrt(x**2 + 1) + 1
class hardShrink(Activator):
def __init__(self, lambda_=0.5, *args,**kwds):
self.lambda_ = lambda_
super().__init__(*args,**kwds)
def forward(self, x, *args,**kwds):
return np.where((-self.lambda_ <= x) & (x <= self.lambda_),
0, x)
def backward(self, x, *args,**kwds):
return np.where((-self.lambda_ <= x) & (x <= self.lambda_),
0, 1)
class softShrink(Activator):
def __init__(self, lambda_=0.5, *args,**kwds):
self.lambda_ = lambda_
super().__init__(*args,**kwds)
def forward(self, x, *args,**kwds):
return np.where(x < -self.lambda_, x + self.lambda_,
np.where(x > self.lambda_, x - self.lambda_, 0))
def backward(self, x, *args,**kwds):
return np.where((-self.lambda_ <= x) & (x <= self.lambda_),
0, 1)
class threshold(Activator):
def __init__(self, threshold, value, *args,**kwds):
self.threshold = threshold
self.value = value
super().__init__(*args,**kwds)
def forward(self, x, *args,**kwds):
return np.where(x > self.threshold, x, self.value)
def backward(self, x, *args,**kwds):
return np.where(x > self.threshold, 1, 0)
class sigmoid(Activator):
def forward(self, x, *args,**kwds):
return 1/(1 + np.exp(-x))
def backward(self, x, y, *args,**kwds):
return y*(1 - y)
class hardSigmoid(Activator):
def forward(self, x, *args,**kwds):
return np.clip(0.2*x + 0.5, 0, 1)
def backward(self, x, *args,**kwds):
return np.where((x > 2.5) | (x < -2.5), 0, 0.2)
class logSigmoid(Activator):
def forward(self, x, *args,**kwds):
return -np.log(1 + np.exp(-x))
def backward(self, x, *args,**kwds):
return 1/(1 + np.exp(x))
class act_tanh(Activator):
def forward(self, x, *args,**kwds):
return np.tanh(x)
def backward(self, x, *args,**kwds):
return 1 - np.tanh(x)**2
class hardtanh(Activator):
def forward(self, x, *args,**kwds):
return np.clip(x, -1, 1)
def backward(self, x, *args,**kwds):
return np.where((-1 <= x) & (x <= 1), 1, 0)
class tanhShrink(Activator):
def forward(self, x, *args,**kwds):
return x - np.tanh(x)
def backward(self, x, *args,**kwds):
return np.tanh(x)**2
class ReLU(Activator):
def forward(self, x, *args,**kwds):
return np.maximum(0, x)
def backward(self, x, *args,**kwds):
return np.where(x > 0, 1, 0)
class ReLU6(Activator):
def forward(self, x, *args,**kwds):
return np.clip(x, 0, 6)
def backward(self, x, *args,**kwds):
return np.where((0 < x) & (x < 6), 1, 0)
class leakyReLU(Activator):
def __init__(self, alpha=1e-2, *args,**kwds):
self.alpha = alpha
super().__init__(*args,**kwds)
def forward(self, x, *args,**kwds):
return np.maximum(self.alpha * x, x)
def backward(self, x, *args,**kwds):
return np.where(x < 0, self.alpha, 1)
class ELU(Activator):
def __init__(self, alpha=1., *args,**kwds):
self.alpha = alpha
super().__init__(*args,**kwds)
def forward(self, x, *args,**kwds):
return np.where(x >= 0, x, self.alpha*(np.exp(x) - 1))
def backward(self, x, *args,**kwds):
return np.where(x >= 0, 1, self.alpha*np.exp(x))
class SELU(Activator):
def __init__(self, lambda_=1.0507, alpha=1.67326, *args,**kwds):
self.lambda_ = lambda_
self.alpha = alpha
super().__init__(*args,**kwds)
def forward(self, x, *args,**kwds):
return np.where(x >= 0,
self.lambda_*x,
self.lambda_*self.alpha*(np.exp(x) - 1))
def backward(self, x, *args,**kwds):
return np.where(x >= 0,
self.lambda_,
self.lambda_*self.alpha*np.exp(x))
class CELU(Activator):
def __init__(self, alpha=1., *args,**kwds):
self.alpha = alpha
super().__init__(*args,**kwds)
def forward(self, x, *args,**kwds):
return np.where(x >= 0,
x,
self.alpha*(np.exp(x/self.alpha) - 1))
def backward(self, x, *args,**kwds):
return np.where(x >= 0, 1, np.exp(x/self.alpha))
class softmax(Activator):
def forward(self, x, *args,**kwds):
return np.exp(x)/np.sum(np.exp(x))
def backward(self, x, *args,**kwds):
return np.exp(x)*(np.sum(np.exp(x))
- np.exp(x))/np.sum(np.exp(x))**2
class softmin(Activator):
def forward(self, x, *args,**kwds):
return np.exp(-x)/np.sum(np.exp(-x))
def backward(self, x, *args,**kwds):
return -(np.exp(x)*(np.sum(np.exp(-x)) - np.exp(x))
/np.sum(np.exp(-x))**2)
class logSoftmax(Activator):
def forward(self, x, *args,**kwds):
return np.log(np.exp(x)/np.sum(np.exp(x)))
def backward(self, x, *args,**kwds):
y = np.sum(np.exp(x))
return (y - np.exp(x))/y
class softplus(Activator):
def forward(self, x, *args,**kwds):
return np.logaddexp(x, 0)
def backward(self, x, *args,**kwds):
return 1/(1 + np.exp(-x))
class softsign(Activator):
def forward(self, x, *args,**kwds):
return x/(1 + np.abs(x))
def backward(self, x, *args,**kwds):
return 1/(1 + np.abs(x)) ** 2
class Swish(Activator):
def __init__(self, beta=1, *args,**kwds):
self.beta = beta
super().__init__(*args,**kwds)
def forward(self, x, *args,**kwds):
return x/(1 + np.exp(-self.beta*x))
def backward(self, x, y, *args,**kwds):
return self.beta*y + (1 - self.beta*y)/(1 + np.exp(-self.beta*x))
def d2y(self, x, *args,**kwds):
return (-0.25*self.beta*(self.beta*x*np.tanh(0.5*self.beta*x) - 2)
*(1 - np.tanh(0.5*self.beta*x)**2))
class Mish(Activator):
def forward(self, x, *args,**kwds):
return x*np.tanh(np.logaddexp(x, 0))
def backward(self, x, *args,**kwds):
omega = (4*(x + 1) + 4*np.exp(2*x)
+ np.exp(3*x) + (4*x + 6)*np.exp(x))
delta = 2*np.exp(x) + np.exp(2*x) + 2
return np.exp(x)*omega/delta**2
def d2y(self, x, *args,**kwds):
omega = (2*(x + 2)
+ np.exp(x)*(np.exp(x)*(-2*np.exp(x)*(x - 1) - 3*x + 6)
+ 2*(x + 4)))
delta = np.exp(x)*(np.exp(x) + 2) + 2
return 4*np.exp(x)*omega/delta**3
class tanhExp(Activator):
def forward(self, x, *args,**kwds):
return x*np.tanh(np.exp(x))
def backward(self, x, *args,**kwds):
tanh_exp = np.tanh(np.exp(x))
return tanh_exp - x*np.exp(x)*(tanh_exp**2 - 1)
def d2y(self, x, *args,**kwds):
tanh_exp = np.tanh(np.exp(x))
return (np.exp(x)*(-x + 2*np.exp(x)*x*tanh_exp - 2)
*(tanh_exp**2 - 1))
class maxout(Activator):
def __init__(self, n_prev, n, k, wb_width=5e-2, *args,**kwds):
self.n_prev = n_prev
self.n = n
self.k = k
self.w = wb_width*np.random.rand((n_prev, n*k))
self.b = wb_width*np.random.rand(n*k)
super().__init__(*args,**kwds)
def forward(self, x, *args,**kwds):
self.x = x.copy()
self.z = np.dot(self.w.T, x) + self.b
self.z = self.z.reshape(self.n, self.k)
self.y = np.max(self.z, axis=1)
return self.y
def backward(self, g, *args,**kwds):
self.dw = np.sum(np.dot(self.w, self.x))
get_act.py
_act_dic = {"step": step,
"identity": identity,
"bent-identity": bentIdentity,
"hard-shrink": hardShrink,
"soft-shrink": softShrink,
"threshold": threshold,
"sigmoid": sigmoid,
"hard-sigmoid": hardSigmoid,
"log-sigmoid": logSigmoid,
"tanh": act_tanh,
"tanh-shrink": tanhShrink,
"hard-tanh":hardtanh,
"ReLU": ReLU,
"ReLU6": ReLU6,
"leaky-ReLU": leakyReLU,
"ELU": ELU,
"SELU": SELU,
"CELU": CELU,
"softmax": softmax,
"softmin": softmin,
"log-softmax": logSoftmax,
"softplus": softplus,
"softsign": softsign,
"Swish": Swish,
"Mish": Mish,
"tanhExp": tanhExp,
}
def get_act(name, *args,**kwds):
if name in _act_dic.keys():
activator = _act_dic[name](*args,**kwds)
else:
raise ValueError(name + ": Unknown activator")
return activator
optimizers.py
import numpy as np
class Optimizer():
"""
Eine Superklasse, die von der Optimierungsmethode geerbt wurde.
"""
def __init__(self, *args,**kwds):
pass
def update(self, *args,**kwds):
pass
class SGD(Optimizer):
def __init__(self, eta=1e-2, *args,**kwds):
super().__init__(*args,**kwds)
self.eta = eta
def update(self, grad_w, grad_b, *args,**kwds):
dw = -self.eta*grad_w
db = -self.eta*grad_b
return dw, db
class MSGD(Optimizer):
def __init__(self, eta=1e-2, mu=0.9, *args,**kwds):
super().__init__(*args,**kwds)
self.eta = eta
self.mu = mu
#Halten Sie den Wert des vorherigen Schritts
self.dw = 0
self.db = 0
def update(self, grad_w, grad_b, *args,**kwds):
dw = self.mu*self.dw - (1-self.mu)*self.eta*grad_w
db = self.mu*self.db - (1-self.mu)*self.eta*grad_b
#Das Zuweisen in der Ansicht anstelle des Kopierens liegt daran, dass diese Werte verwendet werden können
#Dies liegt daran, dass es nicht geändert wird.
self.dw = dw
self.db = db
return dw, db
class NAG(Optimizer):
def __init__(self, eta=1e-2, mu=0.9, *args,**kwds):
super().__init__(*args,**kwds)
self.eta = eta
self.mu = mu
#Enthält den Wert des vorherigen Schritts
self.dw = 0
self.db = 0
def update(self, grad_w, grad_b, w=0, b=0, dfw=None, dfb=None,
nargs=2, *args,**kwds):
if nargs == 1:
grad_w = dfw(w + self.mu*self.dw)
grad_b = 0
elif nargs == 2:
grad_w = dfw(w + self.mu*self.dw, b + self.mu*self.db)
grad_b = dfb(w + self.mu*self.dw, b + self.mu*self.db)
dw = self.mu*self.dw - (1-self.mu)*self.eta*grad_w
db = self.mu*self.db - (1-self.mu)*self.eta*grad_b
#Das Zuweisen in der Ansicht anstelle des Kopierens liegt daran, dass diese Werte verwendet werden können
#Dies liegt daran, dass es nicht geändert wird.
self.dw = dw
self.db = db
return dw, db
class AdaGrad(Optimizer):
def __init__(self, eta=1e-3, *args,**kwds):
super().__init__(*args,**kwds)
self.eta = eta
#Halten Sie den Wert des vorherigen Schritts
self.gw = 0
self.gb = 0
def update(self, grad_w, grad_b, *args,**kwds):
self.gw += grad_w*grad_w
self.gb += grad_b*grad_b
dw = -self.eta*grad_w/np.sqrt(self.gw)
db = -self.eta*grad_b/np.sqrt(self.gb)
return dw, db
class RMSprop(Optimizer):
def __init__(self, eta=1e-2, rho=0.99, eps=1e-8, *args,**kwds):
super().__init__(*args,**kwds)
self.eta = eta
self.rho = rho
self.eps = eps
#Halten Sie den Wert des vorherigen Schritts
self.vw = 0
self.vb = 0
def update(self, grad_w, grad_b, *args,**kwds):
self.vw += (1-self.rho)*(grad_w**2 - self.vw)
self.vb += (1-self.rho)*(grad_b**2 - self.vb)
dw = -self.eta*grad_w/np.sqrt(self.vw+self.eps)
db = -self.eta*grad_b/np.sqrt(self.vb+self.eps)
return dw, db
class AdaDelta(Optimizer):
def __init__(self, rho=0.95, eps=1e-6, *args,**kwds):
super().__init__(*args,**kwds)
self.rho = rho
self.eps = eps
#Halten Sie den Wert des vorherigen Schritts
self.vw = 0
self.vb = 0
self.uw = 0
self.ub = 0
def update(self, grad_w, grad_b, *args,**kwds):
self.vw += (1-self.rho)*(grad_w**2 - self.vw)
self.vb += (1-self.rho)*(grad_b**2 - self.vb)
dw = -grad_w*np.sqrt(self.uw+self.eps)/np.sqrt(self.vw+self.eps)
db = -grad_b*np.sqrt(self.ub+self.eps)/np.sqrt(self.vb+self.eps)
self.uw += (1-self.rho)*(dw**2 - self.uw)
self.ub += (1-self.rho)*(db**2 - self.ub)
return dw, db
class Adam(Optimizer):
def __init__(self, alpha=1e-3, beta1=0.9, beta2=0.999, eps=1e-8,
*args,**kwds):
super().__init__(*args,**kwds)
self.alpha = alpha
self.beta1 = beta1
self.beta2 = beta2
self.eps = eps
#Halten Sie den Wert des vorherigen Schritts
self.mw = 0
self.mb = 0
self.vw = 0
self.vb = 0
def update(self, grad_w, grad_b, t=1, *args,**kwds):
self.mw += (1-self.beta1)*(grad_w - self.mw)
self.mb += (1-self.beta1)*(grad_b - self.mb)
self.vw += (1-self.beta2)*(grad_w**2 - self.vw)
self.vb += (1-self.beta2)*(grad_b**2 - self.vb)
alpha_t = self.alpha*np.sqrt(1-self.beta2**t)/(1-self.beta1**t)
dw = -alpha_t*self.mw/(np.sqrt(self.vw+self.eps))
db = -alpha_t*self.mb/(np.sqrt(self.vb+self.eps))
return dw, db
class RMSpropGraves(Optimizer):
def __init__(self, eta=1e-4, rho=0.95, eps=1e-4, *args,**kwds):
super().__init__(*args,**kwds)
self.eta = eta
self.rho = rho
self.eps = eps
#Halten Sie den Wert des vorherigen Schritts
self.mw = 0
self.mb = 0
self.vw = 0
self.vb = 0
def update(self,grad_w, grad_b, *args,**kwds):
self.mw += (1-self.rho)*(grad_w - self.mw)
self.mb += (1-self.rho)*(grad_b - self.mb)
self.vw += (1-self.rho)*(grad_w**2 - self.vw)
self.vb += (1-self.rho)*(grad_b**2 - self.vb)
dw = -self.eta*grad_w/np.sqrt(self.vw - self.mw**2 + self.eps)
db = -self.eta*grad_b/np.sqrt(self.vb - self.mb**2 + self.eps)
return dw, db
class SMORMS3(Optimizer):
def __init__(self, eta=1e-3, eps=1e-8, *args,**kwds):
super().__init__(*args,**kwds)
self.eta = eta
self.eps = eps
#Halten Sie den Wert des vorherigen Schritts
self.zetaw = 0
self.zetab = 0
self.sw = 1
self.sb = 1
self.mw = 0
self.mb = 0
self.vw = 0
self.vb = 0
def update(self, grad_w, grad_b, *args,**kwds):
rhow = 1/(1+self.sw)
rhob = 1/(1+self.sb)
self.mw += (1-rhow)*(grad_w - self.mw)
self.mb += (1-rhob)*(grad_b - self.mb)
self.vw += (1-rhow)*(grad_w**2 - self.vw)
self.vb += (1-rhob)*(grad_b**2 - self.vb)
self.zetaw = self.mw**2 / (self.vw + self.eps)
self.zetaw = self.mb**2 / (self.vb + self.eps)
dw = -grad_w*(np.minimum(self.eta, self.zetaw)
/np.sqrt(self.vw + self.eps))
db = -grad_b*(np.minimum(self.eta, self.zetab)
/np.sqrt(self.vb + self.eps))
self.sw = 1 + (1 - self.zetaw)*self.sw
self.sb = 1 + (1 - self.zetab)*self.sb
return dw, db
class AdaMax(Optimizer):
def __init__(self, alpha=2e-3, beta1=0.9, beta2=0.999,
*args,**kwds):
super().__init__(*args,**kwds)
self.alpha = alpha
self.beta1 = beta1
self.beta2 = beta2
#Halten Sie den Wert des vorherigen Schritts
self.mw = 0
self.mb = 0
self.uw = 0
self.ub = 0
def update(self, grad_w, grad_b, t=1, *args,**kwds):
self.mw += (1-self.beta1)*(grad_w - self.mw)
self.mb += (1-self.beta1)*(grad_b - self.mb)
self.uw = np.maximum(self.beta2*self.uw, np.abs(grad_w))
self.ub = np.maximum(self.beta2*self.ub, np.abs(grad_b))
alpha_t = self.alpha/(1 - self.beta1**t)
dw = -alpha_t*self.mw/self.uw
db = -alpha_t*self.mb/self.ub
return dw, db
class Nadam(Optimizer):
def __init__(self, alpha=2e-3, mu=0.975, nu=0.999, eps=1e-8,
*args,**kwds):
super().__init__(*args,**kwds)
self.alpha = alpha
self.mu = mu
self.nu = nu
self.eps = eps
#Halten Sie den Wert des vorherigen Schritts
self.mw = 0
self.mb = 0
self.vw = 0
self.vb = 0
def update(self, grad_w, grad_b, t=1, *args,**kwds):
self.mw += (1-self.mu)*(grad_w - self.mw)
self.mb += (1-self.mu)*(grad_b - self.mb)
self.vw += (1-self.nu)*(grad_w**2 - self.vw)
self.vb += (1-self.nu)*(grad_b**2 - self.vb)
mhatw = (self.mu*self.mw/(1-self.mu**(t+1))
+ (1-self.mu)*grad_w/(1-self.mu**t))
mhatb = (self.mu*self.mb/(1-self.mu**(t+1))
+ (1-self.mu)*grad_b/(1-self.mu**t))
vhatw = self.nu*self.vw/(1-self.nu**t)
vhatb = self.nu*self.vb/(1-self.nu**t)
dw = -self.alpha*mhatw/np.sqrt(vhatw + self.eps)
db = -self.alpha*mhatb/np.sqrt(vhatb + self.eps)
return dw, db
class Eve(Optimizer):
def __init__(self, alpha=1e-3, beta1=0.9, beta2=0.999, beta3=0.999,
c=10, eps=1e-8, fstar=0, *args,**kwds):
super().__init__(*args,**kwds)
self.alpha = alpha
self.beta1 = beta1
self.beta2 = beta2
self.beta3 = beta3
self.c = c
self.eps = eps
#Halten Sie den Wert des vorherigen Schritts
self.mw = 0
self.mb = 0
self.vw = 0
self.vb = 0
self.f = 0
self.fstar = fstar
self.dtilde_w = 0
self.dtilde_b = 0
def update(self, grad_w, grad_b, t=1, f=1, *args,**kwds):
self.mw += (1-self.beta1)*(grad_w - self.mw)
self.mb += (1-self.beta1)*(grad_b - self.mb)
self.vw += (1-self.beta2)*(grad_w**2 - self.vw)
self.vb += (1-self.beta2)*(grad_b**2 - self.vb)
mhatw = self.mw/(1 - self.beta1**t)
mhatb = self.mb/(1 - self.beta1**t)
vhatw = self.vw/(1 - self.beta2**t)
vhatb = self.vb/(1 - self.beta2**t)
if t > 1:
d_w = (np.abs(f-self.fstar)
/(np.minimum(f, self.f) - self.fstar))
d_b = (np.abs(f-self.fstar)
/(np.minimum(f, self.f) - self.fstar))
dhat_w = np.clip(d_w, 1/self.c, self.c)
dhat_b = np.clip(d_b, 1/self.c, self.c)
self.dtilde_w += (1 - self.beta3)*(dhat_w - self.dtilde_w)
self.dtilde_b += (1 - self.beta3)*(dhat_b - self.dtilde_b)
else:
self.dtilde_w = 1
self.dtilde_b = 1
self.f = f
dw = -(self.alpha*mhatw
/(self.dtilde_w*(np.sqrt(vhatw) + self.eps)))
db = -(self.alpha*mhatb
/(self.dtilde_b*(np.sqrt(vhatb) + self.eps)))
return dw, db
class SantaE(Optimizer):
def __init__(self, eta=1e-2, sigma=0.95, lambda_=1e-8,
anne_func=lambda t, n: t**n, anne_rate=0.5,
burnin=100, C=5, N=16,
*args,**kwds):
"""
Args:
eta: Learning rate
sigma: Maybe in other cases;
'rho' in RMSprop, AdaDelta, RMSpropGraves.
'rhow' or 'rhob' in SMORMS3.
'beta2' in Adam, Eve.
'nu' in Nadam.
To use calculation 'v'.
lambda_: Named 'eps'(ε) in other cases.
anne_func: Annealing function.
To use calculation 'beta' at each timestep.
Default is 'timestep'**'annealing rate'.
The calculated value should be towards infinity
as 't' increases.
anne_rate: Annealing rate.
To use calculation 'beta' at each timestep.
The second Argument of 'anne_func'.
burnin: Swith exploration and refinement.
This should be specified by users.
C: To calculate first 'alpha'.
N: Number of minibatch.
"""
super().__init__(*args,**kwds)
self.eta = eta
self.sigma = sigma
self.lambda_ = lambda_
self.anne_func = anne_func
self.anne_rate = anne_rate
self.burnin = burnin
self.N = N
# Keep one step before and Initialize.
self.alpha_w = np.sqrt(eta)*C
self.alpha_b = np.sqrt(eta)*C
self.vw = 0
self.vb = 0
self.gw = 0
self.gb = 0
def update(self, grad_w, grad_b, t=1, *args,**kwds):
try:
shape_w = grad_w.shape
except:
shape_w = (1, )
try:
shape_b = grad_b.shape
except:
shape_b = (1, )
if t == 1:
# Initialize uw, ub.
self.uw = np.sqrt(self.eta)*np.random.randn(*shape_w)
self.ub = np.sqrt(self.eta)*np.random.randn(*shape_b)
self.vw = (self.sigma*self.vw
+ grad_w*grad_w * (1 - self.sigma) / self.N**2)
self.vb = (self.sigma*self.vb
+ grad_b*grad_b * (1 - self.sigma) / self.N**2)
gw = 1/np.sqrt(self.lambda_ + np.sqrt(self.vw))
gb = 1/np.sqrt(self.lambda_ + np.sqrt(self.vb))
beta = self.anne_func(t, self.anne_rate)
if t < self.burnin:
# Exploration.
self.alpha_w += self.uw*self.uw - self.eta/beta
self.alpha_b += self.ub*self.ub - self.eta/beta
uw = (self.eta/beta * (1 - self.gw/gw)/self.uw
+ np.sqrt(2*self.eta/beta * self.gw)
* np.random.randn(*shape_w))
ub = (self.eta/beta * (1 - self.gb/gb)/self.ub
+ np.sqrt(2*self.eta/beta * self.gb)
* np.random.randn(*shape_b))
else:
# Refinement.
uw = 0
ub = 0
uw += (1 - self.alpha_w)*self.uw - self.eta*gw*grad_w
ub += (1 - self.alpha_b)*self.ub - self.eta*gb*grad_b
# Update values.
self.uw = uw
self.ub = ub
self.gw = gw
self.gb = gb
dw = gw*uw
db = gb*ub
return dw, db
class SantaSSS(Optimizer):
def __init__(self, eta=1e-2, sigma=0.95, lambda_=1e-8,
anne_func=lambda t, n: t**n, anne_rate=0.5,
burnin=100, C=5, N=16,
*args,**kwds):
"""
Args:
eta: Learning rate
sigma: Maybe in other cases;
'rho' in RMSprop, AdaDelta, RMSpropGraves.
'rhow' or 'rhob' in SMORMS3.
'beta2' in Adam, Eve.
'nu' in Nadam.
To use calculation 'v'.
lambda_: Named 'eps'(ε) in other cases.
anne_func: Annealing function.
To use calculation 'beta' at each timestep.
Default is 'timestep'**'annealing rate'.
The calculated value should be towards infinity
as 't' increases.
anne_rate: Annealing rate.
To use calculation 'beta' at each timestep.
The second Argument of 'anne_func'.
burnin: Swith exploration and refinement.
This should be specified by users.
C: To calculate first 'alpha'.
N: Number of minibatch.
"""
super().__init__(*args,**kwds)
self.eta = eta
self.sigma = sigma
self.lambda_ = lambda_
self.anne_func = anne_func
self.anne_rate = anne_rate
self.burnin = burnin
self.N = N
# Keep one step before and Initialize.
self.alpha_w = np.sqrt(eta)*C
self.alpha_b = np.sqrt(eta)*C
self.vw = 0
self.vb = 0
self.gw = 0
self.gb = 0
def update(self, grad_w, grad_b, t=1, *args,**kwds):
try:
shape_w = grad_w.shape
except:
shape_w = (1, )
try:
shape_b = grad_b.shape
except:
shape_b = (1, )
if t == 1:
# Initialize uw, ub.
self.uw = np.sqrt(self.eta)*np.random.randn(*shape_w)
self.ub = np.sqrt(self.eta)*np.random.randn(*shape_b)
self.vw = (self.sigma*self.vw
+ grad_w*grad_w * (1 - self.sigma) / self.N**2)
self.vb = (self.sigma*self.vb
+ grad_b*grad_b * (1 - self.sigma) / self.N**2)
gw = 1/np.sqrt(self.lambda_ + np.sqrt(self.vw))
gb = 1/np.sqrt(self.lambda_ + np.sqrt(self.vb))
dw = 0.5*gw*self.uw
db = 0.5*gb*self.ub
beta = self.anne_func(t, self.anne_rate)
if t < self.burnin:
# Exploration.
self.alpha_w += (self.uw*self.uw - self.eta/beta)*0.5
self.alpha_b += (self.ub*self.ub - self.eta/beta)*0.5
uw = np.exp(-0.5*self.alpha_w)*self.uw
ub = np.exp(-0.5*self.alpha_b)*self.ub
uw += (-gw*grad_w*self.eta
+ np.sqrt(2*self.gw*self.eta/beta)
* np.random.randn(*shape_w)
+ self.eta/beta*(1-self.gw/gw)/self.uw)
ub += (-gb*grad_b*self.eta
+ np.sqrt(2*self.gb*self.eta/beta)
* np.random.randn(*shape_b)
+ self.eta/beta*(1-self.gb/gb)/self.ub)
uw *= np.exp(-0.5*self.alpha_w)
ub *= np.exp(-0.5*self.alpha_b)
self.alpha_w += (uw*uw - self.eta/beta)*0.5
self.alpha_b += (ub*ub - self.eta/beta)*0.5
else:
# Refinement.
uw = np.exp(-0.5*self.alpha_w)*self.uw
ub = np.exp(-0.5*self.alpha_b)*self.ub
uw -= gw*grad_w*self.eta
ub -= gb*grad_b*self.eta
uw *= np.exp(-0.5*self.alpha_w)
ub *= np.exp(-0.5*self.alpha_b)
# Update values.
self.uw = uw
self.ub = ub
self.gw = gw
self.gb = gb
dw = gw*uw*0.5
db = gb*ub*0.5
return dw, db
class AMSGrad(Optimizer):
def __init__(self, alpha=1e-3, beta1=0.9, beta2=0.999, eps=1e-8,
*args,**kwds):
super().__init__(*args,**kwds)
self.alpha = alpha
self.beta1 = beta1
self.beta2 = beta2
self.eps = eps
#Halten Sie den Wert des vorherigen Schritts
self.mw = 0
self.mb = 0
self.vw = 0
self.vb = 0
self.vhatw = 0
self.vhatb = 0
def update(self, grad_w, grad_b, t=1, *args,**kwds):
self.mw += (1-self.beta1)*(grad_w - self.mw)
self.mb += (1-self.beta1)*(grad_b - self.mb)
self.vw += (1-self.beta2)*(grad_w**2 - self.vw)
self.vb += (1-self.beta2)*(grad_b**2 - self.vb)
self.vhatw = np.maximum(self.vhatw, self.vw)
self.vhatb = np.maximum(self.vhatb, self.vb)
alpha_t = self.alpha / np.sqrt(t)
dw = - alpha_t * self.mw/np.sqrt(self.vhatw + self.eps)
db = - alpha_t * self.mb/np.sqrt(self.vhatb + self.eps)
return dw, db
class AdaBound(Optimizer):
def __init__(self, alpha=1e-3, eta=1e-1, beta1=0.9, beta2=0.999,
eps=1e-8, *args,**kwds):
super().__init__(*args,**kwds)
self.alpha = alpha
self.eta = eta
self.beta1 = beta1
self.beta2 = beta2
self.eps = eps
#Halten Sie den Wert des vorherigen Schritts
self.mw = 0
self.mb = 0
self.vw = 0
self.vb = 0
def update(self, grad_w, grad_b, t=1, *args,**kwds):
self.mw += (1-self.beta1)*(grad_w - self.mw)
self.mb += (1-self.beta1)*(grad_b - self.mb)
self.vw += (1-self.beta2)*(grad_w**2 - self.vw)
self.vb += (1-self.beta2)*(grad_b**2 - self.vb)
etal = self.eta*(1 - 1/((1-self.beta2)*t + 1))
etau = self.eta*(1 + 1/((1-self.beta2)*t + self.eps))
etahatw_t = np.clip(self.alpha/np.sqrt(self.vw), etal, etau)
etahatb_t = np.clip(self.alpha/np.sqrt(self.vb), etal, etau)
etaw_t = etahatw_t/np.sqrt(t)
etab_t = etahatb_t/np.sqrt(t)
dw = - etaw_t*self.mw
db = - etab_t*self.mb
return dw, db
class AMSBound(Optimizer):
def __init__(self, alpha=1e-3, eta=1e-1, beta1=0.9, beta2=0.999,
eps=1e-8, *args,**kwds):
super().__init__(*args,**kwds)
self.alpha = alpha
self.eta = eta
self.beta1 = beta1
self.beta2 = beta2
self.eps = eps
#Halten Sie den Wert des vorherigen Schritts
self.mw = 0
self.mb = 0
self.vw = 0
self.vb = 0
self.vhatw = 0
self.vhatb = 0
def update(self, grad_w, grad_b, t=1, *args,**kwds):
self.mw += (1-self.beta1)*(grad_w - self.mw)
self.mb += (1-self.beta1)*(grad_b - self.mb)
self.vw += (1-self.beta2)*(grad_w**2 - self.vw)
self.vb += (1-self.beta2)*(grad_b**2 - self.vb)
self.vhatw = np.maximum(self.vhatw, self.vw)
self.vhatb = np.maximum(self.vhatb, self.vb)
etal = self.eta*(1 - 1/((1-self.beta2)*t + 1))
etau = self.eta*(1 + 1/((1-self.beta2)*t + self.eps))
etahatw_t = np.clip(self.alpha/np.sqrt(self.vhatw), etal, etau)
etahatb_t = np.clip(self.alpha/np.sqrt(self.vhatb), etal, etau)
etaw_t = etahatw_t/np.sqrt(t)
etab_t = etahatb_t/np.sqrt(t)
dw = - etaw_t*self.mw
db = - etab_t*self.mb
return dw, db
get_opt.py
_opt_dic = {
"SGD": SGD,
"MSGD": MSGD,
"NAG": NAG,
"AdaGrad": AdaGrad,
"RMSprop": RMSprop,
"AdaDelta": AdaDelta,
"Adam": Adam,
"RMSpropGraves": RMSpropGraves,
"SMORMS3": SMORMS3,
"AdaMax": AdaMax,
"Nadam": Nadam,
"Eve": Eve,
"SantaE": SantaE,
"SantaSSS": SantaSSS,
"AMSGrad": AMSGrad,
"AdaBound": AdaBound,
"AMSBound": AMSBound,
}
def get_opt(name, *args,**kwds):
if name in _opt_dic.keys():
optimizer = _opt_dic[name](*args,**kwds)
else:
raise ValueError(name + ": Unknown optimizer")
return optimizer
Unten ist der experimentelle Code.
test.py
%matplotlib nbagg
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import tqdm
#Zielsetzung lernen
def split_test(target, train_indices):
return target[train_indices], target[~ train_indices]
x = np.arange(0, 4, 5e-2)
y = np.sin(x)
x_left = 1
x_right = 3
y_top = np.max(y) + 1
y_bottom = np.min(y) - 1
indices = (x_left <= x) & (x <= x_right)
x_train, x_test = split_test(x, indices)
y_train, y_test = split_test(y, indices)
#Grundeinstellung
epoch = 10000
error_prev = 0
error = 0
error_list = []
threshold = 1e-8
n_batch = 4
n_train = x_train.size//n_batch
n_test = x_test.size
#Netzwerkaufbau
n_in = 1
n_out = 1
lm = LayerManager()
lm.append(prev=n_in, n=30, act="sigmoid", wb_width=1)
lm.append(n=30, act="sigmoid", wb_width=1)
lm.append(n=n_out, name="o", act="identity", wb_width=1)
#Erstellen einer Grundlage für Animationsdiagramme
n_image = 100
interval = 50
images = []
fig, ax = plt.subplots(1)
fig.suptitle("fitting animation")
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_xlim(np.min(x), np.max(x))
ax.set_ylim(y_bottom, y_top)
ax.grid()
ax.plot(x, y, color="r")
ax.plot(np.full_like(np.arange(y_bottom, y_top+1), x_left),
np.arange(y_bottom, y_top+1),
color="g")
ax.plot(np.full_like(np.arange(y_bottom, y_top+1), x_right),
np.arange(y_bottom, y_top+1),
color="g")
#Fang an zu lernen
rand_index = np.arange(x_train.size)
for t in tqdm.tqdm(range(1, epoch+1)):
#Szenenerstellung
if t % (epoch/n_image) == 1:
x_in = x.reshape(-1, 1)
for ll in lm.layer_list:
x_in = ll.forward(x_in)
im, = ax.plot(x, ll.y, color="b")
images.append([im])
#Fehlerberechnung
x_in = x_test.reshape(n_test, n_in)
for ll in lm.layer_list:
x_in = ll.forward(x_in)
error = lm[-1].get_error(y_test.reshape(n_test, n_out))
error_list.append(error)
#Konvergenzurteil
if abs(error - error_prev) < threshold:
print("end learning...")
break
else:
error_prev = error
#print("t", t)
np.random.shuffle(rand_index)
for i in range(n_train):
rand = rand_index[i*n_in : (i+n_batch)*n_in]
x_in = x_train[rand].reshape(-1, n_in)
#print("x_in", x_in)
for ll in lm.layer_list:
x_in = ll.forward(x_in)
y_in = y_train[rand].reshape(-1, n_out)
#print("y_in", y_in)
for ll in lm.layer_list[::-1]:
y_in = ll.backward(y_in)
for ll in lm.layer_list:
ll.update()
#Passende Animation erstellen
anim = animation.ArtistAnimation(fig, images, interval=interval, repeat_delay=3000)
#Fehlerübergangsanzeige
fig2, ax2 = plt.subplots(1)
fig2.suptitle("error transition")
ax2.set_yscale("log")
ax2.set_xlabel("epoch")
ax2.set_ylabel("error")
ax2.grid()
ax2.plot(error_list)
fig2.show()
fig2.savefig("error_transition.png ")
Ich werde jeden von ihnen erklären.
test.py
#Zielsetzung lernen
def split_test(target, train_indices):
return target[train_indices], target[~ train_indices]
x = np.arange(0, 4, 5e-2)
y = np.sin(x)
x_left = 1
x_right = 3
y_top = np.max(y) + 1
y_bottom = np.min(y) - 1
indices = (x_left <= x) & (x <= x_right)
x_train, x_test = split_test(x, indices)
y_train, y_test = split_test(y, indices)
test.py
#Grundeinstellung
epoch = 10000
error_prev = 0
error = 0
error_list = []
threshold = 1e-8
n_batch = 4
n_train = x_train.size//n_batch
n_test = x_test.size
test.py
#Netzwerkaufbau
n_in = 1
n_out = 1
lm = LayerManager()
lm.append(prev=n_in, n=30, act="sigmoid", wb_width=1)
lm.append(n=30, act="sigmoid", wb_width=1)
lm.append(n=n_out, name="o", act="identity", wb_width=1)
test.py
#Erstellen einer Grundlage für Animationsdiagramme
n_image = 100
interval = 50
images = []
fig, ax = plt.subplots(1)
fig.suptitle("fitting animation")
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_xlim(np.min(x), np.max(x))
ax.set_ylim(y_bottom, y_top)
ax.grid()
ax.plot(x, y, color="r")
ax.plot(np.full_like(np.arange(y_bottom, y_top+1), x_left),
np.arange(y_bottom, y_top+1),
color="g")
ax.plot(np.full_like(np.arange(y_bottom, y_top+1), x_right),
np.arange(y_bottom, y_top+1),
color="g")
test.py
#Fang an zu lernen
rand_index = np.arange(x_train.size)
for t in tqdm.tqdm(range(1, epoch+1)):
#Szenenerstellung
if t % (epoch/n_image) == 1:
x_in = x.reshape(-1, 1)
for ll in lm.layer_list:
x_in = ll.forward(x_in)
im, = ax.plot(x, ll.y, color="b")
images.append([im])
#Fehlerberechnung
x_in = x_test.reshape(n_test, n_in)
for ll in lm.layer_list:
x_in = ll.forward(x_in)
error = lm[-1].get_error(y_test.reshape(n_test, n_out))
error_list.append(error)
#Konvergenzurteil
if abs(error - error_prev) < threshold:
print("end learning...")
break
else:
error_prev = error
#print("t", t)
np.random.shuffle(rand_index)
for i in range(n_train):
rand = rand_index[i*n_in : (i+n_batch)*n_in]
x_in = x_train[rand].reshape(-1, n_in)
#print("x_in", x_in)
for ll in lm.layer_list:
x_in = ll.forward(x_in)
y_in = y_train[rand].reshape(-1, n_out)
#print("y_in", y_in)
for ll in lm.layer_list[::-1]:
y_in = ll.backward(y_in)
for ll in lm.layer_list:
ll.update()
test.py
#Passende Animation erstellen
anim = animation.ArtistAnimation(fig, images, interval=interval, repeat_delay=3000)
#Fehlerübergangsanzeige
fig2, ax2 = plt.subplots(1)
fig2.suptitle("error transition")
ax2.set_yscale("log")
ax2.set_xlabel("epoch")
ax2.set_ylabel("error")
ax2.grid()
ax2.plot(error_list)
fig2.show()
fig2.savefig("error_transition.png ")
Ein Beispiel für die erstellte Animation und den Fehlerübergang ist wie folgt. Dies ist nur ein Beispiel, da die Anfangsparameter mit Zufallszahlen generiert werden und bei jeder Ausführung unterschiedliche Ergebnisse angegeben werden. Was die Trainingsdaten betrifft, ist die Anpassung so schnell wie möglich abgeschlossen, und die Testdaten sind auch gut angepasst, so dass sie verfolgt werden können. Da die Testdaten nicht trainiert werden, gewinnt sie natürlich an Vielseitigkeit für unbekannte Daten.
Lassen Sie uns nun einige der Funktionen, die direkt im Testcode geschrieben sind, auf "LayerManager" portieren. Lassen Sie den Ebenenmanager zunächst verschiedene Dinge halten.
test.py
#Grundeinstellung
epoch = 10000
#error_prev = 0
#error = 0
#error_list = []
threshold = 1e-8
n_batch = 4
#n_train = x_train.size//n_batch
#n_test = x_test.size
#Netzwerkaufbau
n_in = 1
n_out = 1
lm = LayerManager((x_train, x_test), (y_train, y_test))
lm.append(prev=n_in, n=30, act="sigmoid", wb_width=1)
lm.append(n=30, act="sigmoid", wb_width=1)
lm.append(n=n_out, name="o", act="identity", wb_width=1)
layermanager.py
def __init__(self, x, y):
self.x_train, self.x_test = x
self.y_train, self.y_test = y
self.__layer_list = [] #Liste der Ebenen
self.__name_list = [] #Namensliste für jede Schicht
self.__ntype = np.zeros(self.N_TYPE, dtype=int) #Anzahl der Ebenen nach Typ
Als nächstes portieren wir den Lernkörper und die Fehlerübergangsanzeige.
test.py
#Fang an zu lernen
lm.training(epoch, threshold=threshold, n_batch=n_batch)
layermanager.py
def training(self, epoch, n_batch=16, threshold=1e-8, show_error=True):
if show_error:
self.error_list = []
n_in = self.__layer_list[0].prev
n_out = self.__layer_list[-1].n
n_train = self.x_train.size//n_batch
n_test = self.x_test.size
#Fang an zu lernen
error = 0
error_prev = 0
rand_index = np.arange(self.x_train.size)
for t in tqdm.tqdm(range(1, epoch+1)):
#Fehlerberechnung
x_in = self.x_test.reshape(n_test, n_in)
for ll in self.__layer_list:
x_in = ll.forward(x_in)
error = lm[-1].get_error(self.y_test.reshape(n_test, n_out))
if show_error:
error_list.append(error)
#Konvergenzurteil
if abs(error - error_prev) < threshold:
print("end learning...")
break
else:
error_prev = error
#print("t", t)
np.random.shuffle(rand_index)
for i in range(n_train):
rand = rand_index[i*n_in : (i+n_batch)*n_in]
x_in = self.x_train[rand].reshape(-1, n_in)
#print("x_in", x_in)
for ll in self.__layer_list:
x_in = ll.forward(x_in)
y_in = self.y_train[rand].reshape(-1, n_out)
#print("y_in", y_in)
for ll in self.__layer_list[::-1]:
y_in = ll.backward(y_in)
for ll in self.__layer_list:
ll.update()
if show_error:
#Fehlerübergangsanzeige
self.show_error(**kwds)
def show_errors(self, title="error transition",
xlabel="epoch", ylabel="error", fname="error_transition.png "):
fig, ax = plt.subplots(1)
fig.suptitle(title)
ax.set_yscale("log")
ax.set_xlabel(xlabel)
ax.set_ylabel(ylabel)
ax.grid()
ax.plot(error_list)
fig.show()
if len(fname) != 0:
fig.savefig(fname)
Schließlich ist es eine Animation. Ich habe darüber nachgedacht, aber ich konnte mir keine Möglichkeit vorstellen, Animationen mit hoher Vielseitigkeit einzufügen, also ist es angemessen ... Wenn Ihnen etwas einfällt, ändern Sie es.
test.py
#Erstellen einer Grundlage für Animationsdiagramme
n_image = 100
interval = 100
fig, ax = lm.ready_anim(n_image, x, y, title="fitting animation")
#images = []
#fig, ax = plt.subplots(1)
#fig.suptitle("fitting animation")
#ax.set_xlabel("x")
#ax.set_ylabel("y")
#ax.set_xlim(np.min(x), np.max(x))
#ax.set_ylim(y_bottom, y_top)
#ax.grid()
#ax.plot(x, y, color="r")
ax.plot(np.full_like(np.arange(y_bottom, y_top+1), x_left),
np.arange(y_bottom, y_top+1),
color="g")
ax.plot(np.full_like(np.arange(y_bottom, y_top+1), x_right),
np.arange(y_bottom, y_top+1),
color="g")
#Fang an zu lernen
lm.training(epoch, threshold=threshold, n_batch=n_batch)
#Passende Animation erstellen
anim = animation.ArtistAnimation(lm.anim_fig, lm.images,
interval=interval, repeat_delay=3000)
layermanager.py
def training(self, epoch, n_batch=16, threshold=1e-8,
show_error=True, **kwds):
if show_error:
self.error_list = []
if self.make_anim:
self.images = []
n_in = self.__layer_list[0].prev
n_out = self.__layer_list[-1].n
n_train = self.x_train.size//n_batch
n_test = self.x_test.size
#Fang an zu lernen
error = 0
error_prev = 0
rand_index = np.arange(self.x_train.size)
for t in tqdm.tqdm(range(1, epoch+1)):
#Szenenerstellung
if self.make_anim:
self.make_scene(t, epoch)
#Fehlerberechnung
Folgendes wird weggelassen
def show_errors(self, title="error transition",
xlabel="epoch", ylabel="error", fname="error_transition.png ",
**kwds):
Folgendes wird weggelassen
def ready_anim(self, n_image, x, y, title="animation",
xlabel="x", ylabel="y", ex_color="r", color="b",
x_left=0, x_right=0, y_down = 1, y_up = 1):
self.n_image = n_image
self.x = x
self.color = color
self.make_anim = True
self.anim_fig, self.anim_ax = plt.subplots(1)
self.anim_fig.suptitle(title)
self.anim_ax.set_xlabel(xlabel)
self.anim_ax.set_ylabel(ylabel)
self.anim_ax.set_xlim(np.min(x) - x_left, np.max(x) + x_right)
self.anim_ax.set_ylim(np.min(y) - y_down, np.max(y) + y_up)
self.anim_ax.grid()
self.anim_ax.plot(x, y, color=ex_color)
return self.anim_fig, self.anim_ax
def make_scene(self, t, epoch):
#Szenenerstellung
if t % (epoch/self.n_image) == 1:
x_in = self.x.reshape(-1, 1)
for ll in self.__layer_list:
x_in = ll.forward(x_in)
im, = self.anim_ax.plot(self.x, ll.y, color=self.color)
self.images.append([im])
test.py
%matplotlib nbagg
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import tqdm
#Zielsetzung lernen
def split_test(target, train_indices):
return (target[train_indices], target[~ train_indices])
x = np.arange(0, 4, 5e-2)
y = np.sin(x)
x_left = 1
x_right = 3
y_top = np.max(y) + 1
y_bottom = np.min(y) - 1
indices = (x_left <= x) & (x <= x_right)
x_train, x_test = split_test(x, indices)
y_train, y_test = split_test(y, indices)
#Grundeinstellung
epoch = 10000
threshold = 1e-5
n_batch = 4
#Netzwerkaufbau
n_in = 1
n_out = 1
lm = LayerManager((x_train, x_test), (y_train, y_test))
lm.append(prev=n_in, n=30, act="sigmoid", wb_width=1)
lm.append(n=30, act="sigmoid", wb_width=1)
lm.append(n=n_out, name="o", act="identity", wb_width=1)
#Erstellen einer Grundlage für Animationsdiagramme
n_image = 100
interval = 100
fig, ax = lm.ready_anim(n_image, x, y, title="fitting animation")
ax.plot(np.full_like(np.arange(y_bottom, y_top+1), x_left),
np.arange(y_bottom, y_top+1),
color="g")
ax.plot(np.full_like(np.arange(y_bottom, y_top+1), x_right),
np.arange(y_bottom, y_top+1),
color="g")
#Fang an zu lernen
lm.training(epoch, threshold=threshold, n_batch=n_batch)
#Passende Animation erstellen
anim = animation.ArtistAnimation(lm.anim_fig, lm.images,
interval=interval, repeat_delay=3000)
layermanager.py
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import tqdm
class _TypeManager():
"""
Manager-Klasse für Ebenentypen
"""
N_TYPE = 2 #Anzahl der Ebenentypen
MIDDLE = 0 #Nummerierung der mittleren Schicht
OUTPUT = 1 #Nummerierung der Ausgabeebene
class LayerManager(_TypeManager):
"""
Manager-Klasse zum Verwalten von Ebenen
"""
def __init__(self, x, y):
self.x_train, self.x_test = x
self.y_train, self.y_test = y
self.__layer_list = [] #Liste der Ebenen
self.__name_list = [] #Namensliste für jede Schicht
self.__ntype = np.zeros(self.N_TYPE, dtype=int) #Anzahl der Ebenen nach Typ
def __repr__(self):
layerRepr= "layer_list: " + repr(self.__layer_list)
nameRepr = "name_list: " + repr(self.__name_list)
ntypeRepr = "ntype: " + repr(self.__ntype)
return (layerRepr + "\n"
+ nameRepr + "\n"
+ ntypeRepr)
def __str__(self):
layerStr = "layer_list: " + str(self.__layer_list)
nameStr = "name_list: " + str(self.__name_list)
ntypeStr = "ntype: " + str(self.__ntype)
return (layerStr + "\n"
+ nameStr + "\n"
+ ntypeStr)
def __len__(self):
"""
In Python integrierte Funktionen`len`Beschreibt den Vorgang beim Aufruf von.
Gibt die Summe der Anzahl der Ebenen nach Typ zurück.
"""
return int(np.sum(self.__ntype))
def __getitem__(self, key):
"""
Zum Beispiel
lm = LayerManager()
+----------------+
| (Element zu lm hinzufügen) |
+----------------+
x = lm[3].~~
Wird aufgerufen, wenn auf ein Element einer Liste oder eines Arrays zugegriffen wird, z
Beschreiben Sie den Vorgang zu diesem Zeitpunkt.
Scheibe und str,Zugriff nur über int zulassen.
"""
if isinstance(key, slice):
#Wenn der Schlüssel ein Slice ist, beziehen Sie sich auf die Liste der Ebenen mit Slice.
#Ungewöhnlicher Wert(Index außerhalb des Bereichs usw.)Wann wird eingegeben
#Python gibt mir einen Fehler.
return self.__layer_list[key]
elif isinstance(key, str):
#Wenn der Schlüssel eine Zeichenfolge ist, rufen Sie den Index aus der Namensliste jeder Ebene und ab
#Gibt die Elemente der Liste der anwendbaren Ebenen zurück.
if key in self.__name_list:
index = self.__name_list.index(key)
return self.__layer_list[index]
else:
#Wenn der Schlüssel nicht vorhanden ist, wird ein KeyError ausgegeben.
raise KeyError("{}: No such item".format(key))
elif isinstance(key, int):
#Wenn key eine Ganzzahl ist, wird das entsprechende Element in der Liste der Ebenen zurückgegeben.
#()
#
return self.__layer_list[key]
else:
raise KeyError(key, ": Undefined such key type.")
def __setitem__(self, key, value):
"""
lm = LayerManager()
+----------------+
| () |
+----------------+
lm[1] = x
Python gibt eine Fehlermeldung aus, wenn Sie einen Index außerhalb des Bereichs eingeben. Wird aufgerufen, wenn auf ein Element einer Liste oder eines Arrays zugegriffen wird, z. B. um ein Element zu lm hinzuzufügen.
Beschreiben Sie den Vorgang zu diesem Zeitpunkt.
Es ist nur das Überschreiben von Elementen zulässig, und das Hinzufügen neuer Elemente ist verboten.
"""
value_type = ""
if isinstance(value, list):
#Auf der rechten Seite angegeben'value'Aber'list'Wenn
#Alle Elemente'BaseLayer'Fehler, wenn die Klasse sie erbt oder nicht.
if not np.all(
np.where(isinstance(value, BaseLayer), True, False)):
self.AssignError()
value_type = "list"
elif isinstance(value, BaseLayer):
#Auf der rechten Seite angegeben'value'Aber'BaseLayer'Ist es eine Klasse?
#Fehler, wenn es nicht vererbt wird.
self.AssignError(type(value))
if value_type == "":
value_type = "BaseLayer"
if isinstance(key, slice):
#Wenn der Schlüssel ein Slice ist, überschreiben Sie das Element in der Liste der Ebenen.
#jedoch'value_type'Aber'list'Sonst ein Fehler.
#Ungewöhnlicher Wert(Index außerhalb des Bereichs usw.)Wann wird eingegeben
#Python gibt mir einen Fehler.
if value_type != "list":
self.AssignError(value_type)
self.__layer_list[key] = value
elif isinstance(key, str):
#Wenn der Schlüssel eine Zeichenfolge ist, rufen Sie den Index aus der Namensliste jeder Ebene und ab
#Überschreiben Sie die Elemente in der Liste der zutreffenden Ebenen.
#jedoch'value_type'Aber'BaseLayer'Sonst ein Fehler.
if value_type != "BaseLayer":
raise AssignError(value_type)
if key in self.__name_list:
index = self.__name_list.index(key)
self.__layer_list[index] = value
else:
#Wenn der Schlüssel nicht vorhanden ist, wird ein KeyError ausgegeben.
raise KeyError("{}: No such item".format(key))
elif isinstance(key, int):
#Wenn key eine Ganzzahl ist, überschreiben Sie das entsprechende Element in der Liste der Ebenen.
#jedoch'value_type'Aber'BaseLayer'Sonst ein Fehler.
#Auch ein abnormaler Wert(Index außerhalb des Bereichs usw.)Wann wird eingegeben
#Python gibt mir einen Fehler.
if value_type != "BaseLayer":
raise AssignError(value_type)
self.__layer_list[key] = value
else:
raise KeyError(key, ": Undefined such key type.")
def __delitem__(self, key):
"""
Zum Beispiel
lm = LayerManager()
+----------------+
| (Element zu lm hinzufügen) |
+----------------+
del lm[2]
Weil es aufgerufen wird, wenn auf das Element der Liste oder des Arrays von der del-Anweisung wie zugegriffen wird
Beschreiben Sie den Vorgang zu diesem Zeitpunkt.
Wenn das angegebene Element vorhanden ist, wird es gelöscht und umbenannt.
"""
if isinstance(key, slice):
#Wenn der Schlüssel ein Slice ist, löschen Sie das angegebene Element unverändert
#Ungewöhnlicher Wert(Index außerhalb des Bereichs usw.)Wann wird eingegeben
#Python gibt mir einen Fehler.
del self.__layer_list[slice]
del self.__name_list[slice]
elif isinstance(key, str):
#Wenn der Schlüssel eine Zeichenfolge ist, rufen Sie den Index aus der Namensliste jeder Ebene und ab
#Löschen Sie das entsprechende Element.
if key in self.__name_list:
del self.__layer_list[index]
del self.__name_list[index]
else:
#Wenn der Schlüssel nicht vorhanden ist, wird ein KeyError ausgegeben.
raise KeyError("{}: No such item".format(key))
elif isinstance(key, int):
#Wenn der Schlüssel eine Ganzzahl ist, löschen Sie das entsprechende Element in der Ebenenliste.
#Ungewöhnlicher Wert(Index außerhalb des Bereichs usw.)Wann wird eingegeben
#Python gibt mir einen Fehler.
del self.__layer_list[key]
else:
raise KeyError(key, ": Undefined such key type.")
#Umbenennen
self._rename()
def _rename(self):
"""
Wenn die Benennung der Namensliste aufgrund der Listenoperation gegen die Regeln verstößt
Benennen Sie die Namensliste und jede Ebene um, um die Regeln erneut zu erfüllen.
Die Namensregel lautet[Ebenentyp][Welche Nummer]Wird besorgt.
Wenn der Ebenentyp Mittlere Ebene ist, Mittlere Ebene
Ausgabe für Ausgabeschicht
Es wird als abgekürzt.
Die Nummer wird nach Typ gezählt.
Auch hier wieder__Zählt nTypen.
"""
#Initialisieren Sie die Anzahl der Ebenen nach Typ
self.__ntype = np.zeros(self.N_TYPE)
#Zählen Sie jede Ebene neu und benennen Sie sie um
for i in range(len(self)):
if "Middle" in self.__name_list[i]:
self.__ntype[self.MIDDLE] += 1
self.__name_list[i] = "Middle{}".format(
self.__ntype[self.MIDDLE])
self.__layer_list[i].name = "Middle{}".format(
self.__ntype[self.MIDDLE])
elif "Output" in self.__name_list[i]:
self.__ntype[self.OUTPUT] += 1
self.__name_list[i] = "Output{}".format(
self.__ntype[self.OUTPUT])
self.__layer_list[i].name = "Output{}".format(
self.__ntype[self.OUTPUT])
else:
raise UndefinedLayerType(self.__name_list[i])
def append(self, *, name="Middle", **kwds):
"""
Implementierung der bekannten Append-Methode, bei der Elemente zu einer Liste hinzugefügt werden.
"""
if "prev" in kwds:
# 'prev'Ist im Schlüsselwort enthalten
#Dies bedeutet, dass die Anzahl der Elemente in der vorherigen Ebene angegeben wird.
#Grundsätzlich soll es also an der Zeit sein, die erste Schicht einzufügen
#Davon abgesehen wird es grundsätzlich automatisch ermittelt und nicht angegeben.
if len(self) != 0:
if kwds["prev"] != self.__layer_list[-1].n:
#Fehler, wenn er nicht mit der Anzahl der Einheiten am Ende übereinstimmt.
raise UnmatchUnitError(self.__layer_list[-1].n,
kwds["prev"])
else:
if len(self) == 0:
#Die erste Ebene muss immer die Anzahl der Eingabeeinheiten angeben.
raise UnmatchUnitError("Input units", "Unspecified")
else:
#Die Anzahl der Einheiten in der letzten Ebene'kwds'Hinzufügen
kwds["prev"] = self.__layer_list[-1].n
#Lesen Sie den Layertyp und ändern Sie den Namen gemäß der Namensregel
if name == "Middle" or name == "mid" or name == "m":
name = "Middle"
elif name == "Output" or name == "out" or name == "o":
name = "Output"
else:
raise UndefinedLayerError(name)
#Fügen Sie eine Ebene hinzu.
if name == "Middle":
#Erhöhen Sie die Ebene nach Typ
self.__ntype[self.MIDDLE] += 1
#Zum Namen hinzufügen
name += str(self.__ntype[self.MIDDLE])
#Zur Namensliste hinzufügen
self.__name_list.append(name)
#Erstellen Sie abschließend eine Ebene und fügen Sie sie der Liste hinzu.
self.__layer_list.append(
MiddleLayer(name=name, **kwds))
elif name == "Output":
#Dies ist auch das gleiche.
self.__ntype[self.OUTPUT] += 1
name += str(self.__ntype[self.OUTPUT])
self.__name_list.append(name)
self.__layer_list.append(
OutputLayer(name=name, **kwds))
#Wenn Sie hier keine else-Anweisung zeichnen, ändern Sie den Namen gemäß den Namensregeln.
#Schon abnormal auf der Bühne'name'Wurde weggelassen.
def extend(self, lm):
"""
Ein weiterer Layer-Manager, der bereits in der Extend-Methode vorhanden ist'lm'Elemente von
Füge alle Hinzu.
"""
if not isinstance(lm, LayerManager):
# 'lm'Fehler, wenn die Instanz von nicht LayerManager ist.
raise TypeError(type(lm), ": Unexpected type.")
if len(self) != 0:
if self.__layer_list[-1].n != lm[0].prev:
#Mit der Anzahl der Einheiten in Ihrer letzten Ebene
# 'lm'Fehler, wenn die Anzahl der Eingaben in der ersten Schicht von nicht gleich ist.
raise UnmatchUnitError(self.__layer_list[-1].n,
lm[0].prev)
#Beziehungsweise'extend'Nach Methode hinzufügen
self.__layer_list.extend(lm.layer_list)
self.__name_list.extend(lm.name_list)
#Umbenennen
self._rename()
def insert(self, prev_name, name="Middle", **kwds):
"""
Geben Sie in der Einfügemethode den Namen der vorherigen Ebene an und kombinieren Sie ihn mit dieser Ebene.
Fügen Sie ein Element hinzu.
"""
# 'prev_name'Fehler, wenn nicht vorhanden.
if not prev_name in self.__name_list:
raise KeyError(prev_name, ": No such key.")
# 'prev'Ist im Schlüsselwort enthalten
# 'prev_name'Fehler, wenn er nicht mit der Anzahl der Einheiten in der in angegebenen Ebene übereinstimmt.
if "prev" in kwds:
if kwds["prev"] \
!= self.__layer_list[self.index(prev_name)].n:
raise UnmatchUnitError(
kwds["prev"],
self.__layer_list[self.index(prev_name)].n)
# 'n'Ist im Schlüsselwort enthalten
if "n" in kwds:
# 'prev_name'Wenn ist nicht der letzte
if prev_name != self.__name_list[-1]:
#Fehler, wenn er nicht mit der Anzahl der Einheiten in der nächsten Ebene übereinstimmt.
if kwds["n"] != self.__layer_list[
self.index(prev_name)+1].prev:
raise UnmatchUnitError(
kwds["n"],
self.__layer_list[self.index(prev_name)].prev)
#Wenn es noch keine Elemente gibt'append'Geben Sie einen Fehler bei der Verwendung der Methode ein.
if len(self) == 0:
raise RuntimeError(
"You have to use 'append' method instead.")
#Index der Einfügeposition abrufen
index = self.index(prev_name) + 1
#Lesen Sie den Layertyp und ändern Sie den Namen gemäß der Namensregel
if name == "Middle" or name == "mid" or name == "m":
name = "Middle"
elif name == "Output" or name == "out" or name == "o":
name = "Output"
else:
raise UndefinedLayerError(name)
#Element einfügen
#In diesem Moment,'name'Befolgen Sie noch nicht die Namensregeln,
#Ich werde es später umbenennen, also mach dir keine Sorgen.
if "Middle" in name:
self.__layer_list.insert(index,
MiddleLayer(name=name, **kwds))
self.__name_list.insert(index, name)
elif "Output" in name:
self.__layer_list.insert(index,
OutputLayer(name=name, **kwds))
self.__name_list.insert(index, name)
#Umbenennen
self._rename()
def extend_insert(self, prev_name, lm):
"""
Dies ist die ursprüngliche Funktion.
Es verhält sich wie eine Kombination aus der Extend-Methode und der Insert-Methode.
Einfach ausgedrückt ist es wie das Einfügen eines weiteren Ebenenmanagers.
"""
if not isinstance(lm, LayerManager):
# 'lm'Fehler, wenn die Instanz von nicht LayerManager ist.
raise TypeError(type(lm), ": Unexpected type.")
# 'prev_name'Fehler, wenn nicht vorhanden.
if not prev_name in self.__name_list:
raise KeyError(prev_name, ": No such key.")
#Die Anzahl der Einheiten der Schichten vor und nach dem angegebenen Ort sowie der ersten und letzten Schicht von lm
#Wenn sie nicht übereinstimmen, tritt ein Fehler auf.
if len(self) != 0:
if self.__layer_list[self.index(prev_name)].n \
!= lm.layer_list[0].prev:
#Mit der Anzahl der Einheiten an Ihrem angegebenen Standort'lm'Die erste Anzahl von Einheiten in
#Wenn sie nicht übereinstimmen, tritt ein Fehler auf.
raise UnmatchUnitError(
self.__layer_list[self.index(prev_name)].n,
lm.layer_list[0].prev)
if prev_name != self.__name_list[-1]:
# 'prev_name'Ist nicht meine letzte Schicht
if lm.layer_list[-1].n \
!= self.__layer_list[self.index(prev_name)+1].prev:
# 'lm'Die Anzahl der Einheiten am Ende und die nächste Schicht Ihres festgelegten Standorts
# 'prev'Fehler, wenn er nicht mit der Anzahl der Einheiten übereinstimmt.
raise UnmatchUnitError(
lm.layer_list[-1].n,
self.__layer_list[self.index(prev_name)+1].prev)
else:
#Wenn Sie keine Elemente haben'extend'Ich erhalte eine Fehlermeldung bei der Verwendung der Methode.
raise RuntimeError(
"You have to use 'extend' method instead.")
#Index der Einfügeposition abrufen
index = self.index(prev_name) + 1
#Elemente nach der Einfügeposition'buf'Entfernen Sie es nach dem Evakuieren einmal
#Fügen Sie ein Element mit der Extend-Methode hinzu
layer_buf = self.__layer_list[index:]
name_buf = self.__name_list[index:]
del self.__layer_list[index:]
del self.__name_list[index:]
self.extend(lm)
#Fügen Sie das evakuierte Element hinzu
self.__layer_list.extend(layer_buf)
self.__name_list.extend(name_buf)
#Umbenennen
self._rename()
def remove(self, key):
"""
Die Methode remove entfernt das Element mit dem angegebenen Namen.
Es darf auch durch Index angegeben werden.
"""
#Bereits implementiert'del'Der Satz ist in Ordnung.
del self[key]
def index(self, target):
return self.__name_list.index(target)
def name(self, indices):
return self.__name_list[indices]
@property
def layer_list(self):
return self.__layer_list
@property
def name_list(self):
return self.__name_list
@property
def ntype(self):
return self.__ntype
def training(self, epoch, n_batch=16, threshold=1e-8,
show_error=True, **kwds):
if show_error:
self.error_list = []
if self.make_anim:
self.images = []
n_in = self.__layer_list[0].prev
n_out = self.__layer_list[-1].n
n_train = self.x_train.size//n_batch
n_test = self.x_test.size
#Fang an zu lernen
error = 0
error_prev = 0
rand_index = np.arange(self.x_train.size)
for t in tqdm.tqdm(range(1, epoch+1)):
#Szenenerstellung
if self.make_anim:
self.make_scene(t, epoch)
#Fehlerberechnung
x_in = self.x_test.reshape(n_test, n_in)
for ll in self.__layer_list:
x_in = ll.forward(x_in)
error = lm[-1].get_error(self.y_test.reshape(n_test, n_out))
if show_error:
self.error_list.append(error)
#Konvergenzurteil
if abs(error - error_prev) < threshold:
print("end learning...")
break
else:
error_prev = error
np.random.shuffle(rand_index)
for i in range(n_train):
rand = rand_index[i*n_in : (i+n_batch)*n_in]
x_in = self.x_train[rand].reshape(-1, n_in)
for ll in self.__layer_list:
x_in = ll.forward(x_in)
y_in = self.y_train[rand].reshape(-1, n_out)
for ll in self.__layer_list[::-1]:
y_in = ll.backward(y_in)
for ll in self.__layer_list:
ll.update()
if show_error:
#Fehlerübergangsanzeige
self.show_errors(**kwds)
def show_errors(self, title="error transition",
xlabel="epoch", ylabel="error", fname="error_transition.png ",
**kwds):
fig, ax = plt.subplots(1)
fig.suptitle(title)
ax.set_yscale("log")
ax.set_xlabel(xlabel)
ax.set_ylabel(ylabel)
ax.grid()
ax.plot(self.error_list)
fig.show()
if len(fname) != 0:
fig.savefig(fname)
def ready_anim(self, n_image, x, y, title="animation",
xlabel="x", ylabel="y", ex_color="r", color="b",
x_left=0, x_right=0, y_down = 1, y_up = 1):
self.n_image = n_image
self.x = x
self.color = color
self.make_anim = True
self.anim_fig, self.anim_ax = plt.subplots(1)
self.anim_fig.suptitle(title)
self.anim_ax.set_xlabel(xlabel)
self.anim_ax.set_ylabel(ylabel)
self.anim_ax.set_xlim(np.min(x) - x_left, np.max(x) + x_right)
self.anim_ax.set_ylim(np.min(y) - y_down, np.max(y) + y_up)
self.anim_ax.grid()
self.anim_ax.plot(x, y, color=ex_color)
return self.anim_fig, self.anim_ax
def make_scene(self, t, epoch):
#Szenenerstellung
if t % (epoch/self.n_image) == 1:
x_in = self.x.reshape(-1, 1)
for ll in self.__layer_list:
x_in = ll.forward(x_in)
im, = self.anim_ax.plot(self.x, ll.y, color=self.color)
self.images.append([im])
Damit ist das DNN-Experiment (Deep Neural Network) abgeschlossen. Versuchen Sie, mit anderen verschiedenen Funktionen herumzuspielen.
Recommended Posts