[PYTHON] Einführung in das tiefe Lernen ~ Funktionsnäherung ~

Zielperson

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.

Umgebung

Der Code läuft auf einem Jupyter-Notebook. Die Einführung des Jupyter-Notizbuchs wird unter hier vorgestellt. Erforderliche Pakete

  1. numpy
  2. matplotlib
  3. 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.

Inhaltsverzeichnis

Verwendete Codes

Den detaillierten Produktionsprozess finden Sie in [Frühere Artikel](#Deep Learning Series).

`_layererror.py`

_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`

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`

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`

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`

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`

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`

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`

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`

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`

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`

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
Fügen Sie diese Codes in jede Zelle einer Jupyter-Notebook-Datei (Erweiterung `.ipynb`) ein und fügen Sie schließlich den folgenden Testcode ein und führen Sie ihn aus.

Testcode

Unten ist der experimentelle Code.

`test.py`

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.

Zielsetzung lernen

Lernzieleinstellungen

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)
Hier werden die Trainingsdaten "x_train" und die Testdaten "x_test" basierend auf der Funktion "sin" erzeugt, die das Lernziel ist. Die Funktion `split_test` ist eine Funktion zum Teilen der Daten in zwei. "x_left" und "x_right" sind die unteren und oberen Grenzen der Trainingsdaten. `y_top` und` y_bottom` sind die Ober- und Unterseite für das Plotten.

Anfangswerteinstellung

Anfangswerteinstellung

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
Der Name jedes Anfangswertes ist ziemlich angemessen. Nun, es wird bis zur letzten Minute übertragen, also lasst es uns akzeptieren.

Netzwerkaufbau

Netzwerkaufbau

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)
Wir bauen hier ein neuronales Netzwerk auf. Die Anzahl der Eingänge "n_in" und die Anzahl der Ausgänge "n_out" sind diesmal beide 1. Hier wird der Layer-Manager "lm" verwendet, um ein dreischichtiges Netzwerk aufzubauen. ![test_layer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/640911/2c1818a6-07ab-9f5a-7ab3-5a97f2edd55e.png)

Grundlage für Animation schaffen

Erstellen einer Grundlage für die Animation

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")
Ich erstelle eine Grundlage für das Einfügen von Animationen. Der Titel, die Einstellungen der vertikalen / horizontalen Achse, die Gitterlinien, das richtige Antwortdiagramm und die Aufteilung zwischen Trainingsdaten und Testdaten werden auf der Basis der Animation aufgezeichnet.

Lernen

Lernen

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()
Es ist eine Implementierung des Lernkörpers. "Szenenerstellung" erstellt eine Szene, um den Lernfortschritt mit Animation anzuzeigen. Bei "Fehlerberechnung" werden Testdaten gesendet und die Summe der Fehler erhalten. Bei der "Konvergenzbeurteilung" wird die Konvergenzbeurteilung durch Vergleichen mit dem vorherigen Fehler durchgeführt. Wenn die Differenz kleiner als "Schwelle" ist, wird beurteilt, dass sie konvergiert hat. Danach wird für die Daten die Vorwärtsausbreitung → Rückwärtsausbreitung → Parameteraktualisierung (Lernen) wiederholt und eine Epoche gelernt.

Animation und Fehlerübergangsanzeige

Anzeige von Animation und Fehlerübergang

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 ")
Die Animationserstellung verwendet die Funktion "ArtistAnimation". `repeat_delay` legt die Pausenzeit am Wiederholungsbegrenzer fest. Die Fehlerübergangsanzeige zeigt den Fehler an, der während des Lernprozesses überwacht wurde.

Versuchsergebnis

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. fitting_sin.gif error_transition.png 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.

Portierte Funktionalität auf "LayerManager"

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.

Ändern Sie die Anfangseinstellungen von `test.py`

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)
Portieren Sie die Standardeinstellungen auf `__init__` in` layermanager.py`

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.

Ändern Sie den Lerncode von `test.py`

test.py


#Fang an zu lernen
lm.training(epoch, threshold=threshold, n_batch=n_batch)
Portieren Sie den Lerncode auf `layermanager.py`

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.

Ändert den Animationscode von `test.py`

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)
Portieren Sie den Animationscode auf `layermanager.py`

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])
Damit ist die Portierung abgeschlossen. Der gesamte geänderte Code sieht folgendermaßen aus:
`test.py` ganzes

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` gesamt

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])

abschließend

Damit ist das DNN-Experiment (Deep Neural Network) abgeschlossen. Versuchen Sie, mit anderen verschiedenen Funktionen herumzuspielen.

Deep Learning-Serie

Recommended Posts

Einführung in das tiefe Lernen ~ Funktionsnäherung ~
Einführung in Deep Learning ~ Lernregeln ~
Tiefe Stärkung des Lernens 1 Einführung in die Stärkung des Lernens
Einführung in Deep Learning ~ Backpropagation ~
Einführung in Deep Learning ~ Lokalisierungs- und Verlustfunktion ~
Einführung in Deep Learning ~ Codierungsvorbereitung ~
Einführung in Deep Learning ~ Dropout Edition ~
Einführung in Deep Learning ~ Forward Propagation ~
Einführung in Deep Learning ~ CNN Experiment ~
Einführung in Deep Learning ~ Falten und Pooling ~
Einführung in das maschinelle Lernen
Deep Learning / Softmax-Funktion
Chainer und Deep Learning durch Funktionsnäherung gelernt
[Lernmemorandum] Einführung in vim
Eine Einführung in das maschinelle Lernen
Super Einführung in das maschinelle Lernen
Einführung in das maschinelle Lernen Schreiben von Notizen
Tiefes Lernen, um ohne GPU zu beginnen
Einführung in die Bibliothek für maschinelles Lernen SHOGUN
Tiefes Lernen
Einführung in Deep Learning (2) - Versuchen Sie Ihre eigene nichtlineare Regression mit Chainer-
Zusammenfassender Hinweis zu Deep Learning -4.2 Verlustfunktion-
Verbessertes Lernen, um von null bis tief zu lernen
[Einführung in die Udemy Python3 + -Anwendung] 48. Funktionsdefinition
Eine Einführung in OpenCV für maschinelles Lernen
[Einführung in die Udemy Python3 + -Anwendung] 45. Aufzählungsfunktion
So studieren Sie den Deep Learning G-Test
[Einführung in die Udemy Python3 + -Anwendung] 41. Eingabefunktion
[Einführung in die Udemy Python3 + -Anwendung] 44. Bereichsfunktion
[Einführung in die Udemy Python3 + -Anwendung] 46. Zip-Funktion
Bildausrichtung: von SIFT bis Deep Learning
Eine Einführung in Python für maschinelles Lernen
Einführung in TensorFlow - Erläuterung der Begriffe und Konzepte des maschinellen Lernens
Einführung in MQTT (Einführung)
Einführung in Scrapy (1)
Einführung in Scrapy (3)
[Einführung] Stärkung des Lernens
Erste Schritte mit Supervisor
Einführung in Tkinter 1: Einführung
Deep Learning Memorandum
Einführung in PyQt
Einführung in Scrapy (2)
Starten Sie Deep Learning
[Linux] Einführung in Linux
Python Deep Learning
Einführung in Scrapy (4)
Deep Learning × Python
Einführung in discord.py (2)
[Deep Learning von Grund auf neu] Layer-Implementierung von der Softmax-Funktion zum Überkreuzen von Entropiefehlern
[Python] Einfache Einführung in das maschinelle Lernen mit Python (SVM)
[Super Einführung in das maschinelle Lernen] Lernen Sie Pytorch-Tutorials
Eine Einführung in maschinelles Lernen für Bot-Entwickler
Einführung in die Thano-Funktionsdefinition und automatische Differenzierung
Ein Amateur versuchte Deep Learning mit Caffe (Einführung)
Deep Learning von Grund auf neu ① Kapitel 6 "Lerntechniken"
Deep Learning / Fehler-Backpropagation der Sigmoid-Funktion
Eine Einführung in Cython, ohne tief zu gehen
[Einführung in StyleGAN2] Unabhängiges Lernen mit 10 Anime-Gesichtern ♬
[Super Einführung in das maschinelle Lernen] Lernen Sie Pytorch-Tutorials