Heim >Backend-Entwicklung >Python-Tutorial >Erstellen eines einfachen und effizienten genetischen Algorithmus für ein neuronales Netzwerk mit Python und NumPy
Es ist der erste Artikel aus dem Kurs über Evolutionsalgorithmen in ML.
Ein genetischer Algorithmus ist erforderlich, wenn Sie die Parameter Ihres neuronalen Netzwerks kennen, aber nicht wissen, wie die Ausgabe aussehen soll. Dieser Algorithmus kann beispielsweise zum Spielen von Google Dinosaur oder Flappy Bird verwendet werden, da Sie dort keine Ahnung haben was die Ausgabe sein soll, aber Sie haben die Möglichkeit, die sinnvollsten Optionen zu sortieren, zum Beispiel nach Zeit, das nennt man Fitnessfunktionen.
Ich konnte noch nie einen solchen Algorithmus finden, der funktioniert, einfach und verwendbar ist, also habe ich angefangen, meinen eigenen leichten, einfachen und perfekt funktionierenden genetischen Algorithmus zu entwickeln.
Mein Ziel ist es nicht, das Schreiben dieses Artikels in die Länge zu ziehen und die Leser mit seiner Länge zu quälen, also kommen wir gleich zum Code. Wie bereits erwähnt, ist der Code einfach, sodass das meiste davon nicht in ganzen Aufsätzen beschrieben werden muss.
Zuerst müssen wir die Module importieren:
import numpy as np import random
Dann fügen wir den Datensatz und die Antworten hinzu, aber nicht, um den Backpropagation-Algorithmus zu verwenden, sondern einfach, um die Anzahl der richtigen Antworten zu zählen. Dann können Sie es an anderen Varianten testen, die jetzt auskommentiert sind
x = np.array([[1, 1, 0], [0, 0, 1], [1, 0, 1], [0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 1, 0], [0, 1, 1], [1, 1, 1]]) y = np.array([[0],[1],[1], [0], [0], [0], [0], [1], [1]]) #x = np.array([[0, 1, 1], [0, 0, 1], [1, 0, 1], [0, 1, 0], [1, 0, 0], [1, 1, 0], [0, 0, 0], [1, 1, 0], [1, 1, 1]]) #y = np.array([[1],[0], [0], [1], [0], [1], [0], [1], [1]]) #x = np.array([[1, 1, 0], [0, 0, 1], [1, 0, 1], [0, 1, 0], [1, 0, 0], [0, 0, 0], [1, 1, 0], [0, 1, 1], [1, 1, 1]]) #y = np.array([[1],[0],[1], [0], [1], [0], [1], [0], [1]])
Listen und Aktivierungsfunktionen hinzufügen. Die Bedeutung der Listen wird später klar werden. Die erste Aktivierungsfunktion ist das Sigmoid und die zweite ist der Schwellenwert.
listNet = [] NewNet = [] goodNET = [] GoodNet0 = [] GoodNet1 = [] GoodNet2 = [] GoodNet3 = [] GoodNet4 = [] GoodNet5 = [] GoodNet6 = [] good = 0 epoch = 0 good = 0 epoch = 0 def sigmoid(x): return 1/(1 + np.exp(-x)) def finfunc(x): if x[0] >= 0.5: x[0] = 1 return x[0] else: x[0] = 0 return x[0]
Als nächstes müssen wir zwei Klassen erstellen, die erste wird benötigt, um die Anfangspopulation zu erstellen, und die zweite für alle nachfolgenden, da wir beim ersten Mal zufällig Gewichte erstellen müssen und dann nur und kreuzen müssen mutieren sie. Die Funktion init() wird zum Erstellen oder Hinzufügen von Gewichten verwendet, Predict() wird für den Algorithmus selbst und zur Berechnung der besten Optionen benötigt und die Funktion Fredict() unterscheidet sich dadurch, dass sie die Antwort und die Fitnessfunktion zur Anzeige von Zahlen zurückgibt auf dem Bildschirm und sehen Sie sich die Trainingsphasen an. Auf der Ausgabeebene wird zunächst die Sigmoidfunktion verwendet, um die Antwort näher an eine der Optionen zu bringen, und erst dann die Schwellenwertfunktion.
class Network(): def __init__(self): self.H1 = np.random.randn(3, 6) self.O1 = np.random.randn(6, 1) def predict(self, x, y): t1 = x @ self.H1 t1 = sigmoid(t1) t2 = t1 @ self.O1 t2 = sigmoid(t2) t2 = finfunc(t2) if t2 == y[0]: global good good += 1 def Fpredict(self, x, y): t1 = x @ self.H1 t1 = sigmoid(t1) t2 = t1 @ self.O1 t2 = sigmoid(t2) t2 = finfunc(t2) if t2 == y[0]: global good good += 1 return t2, good class Network1(): def __init__(self, H1, O1): self.H1 = H1 self.O1 = O1 def predict(self, x, y): t1 = x @ self.H1 t1 = sigmoid(t1) t2 = t1 @ self.O1 t2 = sigmoid(t2) t2 = finfunc(t2) if t2 == y[0]: global good good += 1 def Fpredict(self, x, y): t1 = x @ self.H1 t1 = sigmoid(t1) t2 = t1 @ self.O1 t2 = sigmoid(t2) t2 = finfunc(t2) if t2 == y[0]: global good good += 1 return t2, good
Wir geben die ersten Antworten und die Variable gut aus, die hier die Fitnessfunktion ist, dann setzen wir sie für das nächste neuronale Netzwerk zurück, der Ausdruck „wait0“ (Sie können hier schreiben, was Sie wollen) ist notwendig, um dies nicht zu tun Seien Sie verwirrt darüber, wo die Antworten verschiedener neuronaler Netze beginnen.
import numpy as np import random
Der erste Zyklus vergeht, hier und in allen folgenden Zyklen stellen wir nur sechs Fragen, um zu prüfen, wie gut es die Aufgabe bewältigen wird, die es nicht erfüllt hat, das heißt, wir prüfen es auf Überfüllung, und das passiert manchmal. Und jetzt gehen wir näher ins Detail: Je nachdem, wie viele Antworten es richtig beantwortet hat, ordnen wir es einer der Klassen zu, wenn viele richtig sind, dann müssen wir ein solches neuronales Netzwerk unterstützen und seine Anzahl erhöhen, damit mit dem Durch die nachfolgende Mutation wird es klügere geben. Um das zu verstehen, können Sie sich vorstellen, dass es auf 100 Menschen ein Genie gibt, aber das reicht nicht für alle aus, und das bedeutet, dass sein Genie in den nächsten Generationen verschwinden wird, das bedeutet das entweder das neuronale Netzwerk wird sehr langsam lernen oder wird überhaupt nicht existieren. Um dies zu vermeiden, erhöhen wir die Anzahl neuronaler Netze mit einer großen Anzahl richtiger Antworten im Zyklus. Am Ende leeren wir die HauptlistNet-Liste, weisen ihr neue Werte der GoodNet-Listen in der Reihenfolge vom Besten zum Schlechtesten zu und machen einen Schnitt für die 100 besten Individuen für die nachfolgende Mutation.
x = np.array([[1, 1, 0], [0, 0, 1], [1, 0, 1], [0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 1, 0], [0, 1, 1], [1, 1, 1]]) y = np.array([[0],[1],[1], [0], [0], [0], [0], [1], [1]]) #x = np.array([[0, 1, 1], [0, 0, 1], [1, 0, 1], [0, 1, 0], [1, 0, 0], [1, 1, 0], [0, 0, 0], [1, 1, 0], [1, 1, 1]]) #y = np.array([[1],[0], [0], [1], [0], [1], [0], [1], [1]]) #x = np.array([[1, 1, 0], [0, 0, 1], [1, 0, 1], [0, 1, 0], [1, 0, 0], [0, 0, 0], [1, 1, 0], [0, 1, 1], [1, 1, 1]]) #y = np.array([[1],[0],[1], [0], [1], [0], [1], [0], [1]])
Die Kreuzung und Mutation selbst: Wir nehmen einen Teil vom ersten Elternteil, den zweiten vom zweiten, mutieren und wir bekommen ein Kind in die NewNet-Liste, also 1000 Mal.
listNet = [] NewNet = [] goodNET = [] GoodNet0 = [] GoodNet1 = [] GoodNet2 = [] GoodNet3 = [] GoodNet4 = [] GoodNet5 = [] GoodNet6 = [] good = 0 epoch = 0 good = 0 epoch = 0 def sigmoid(x): return 1/(1 + np.exp(-x)) def finfunc(x): if x[0] >= 0.5: x[0] = 1 return x[0] else: x[0] = 0 return x[0]
Ab dem vorherigen Teil des Codes verwenden wir Network1(), da wir jetzt kreuzen und mutieren, aber nicht zufällig erstellen. Wir müssen also 1000 Mal wiederholen (das ist ein Hyperparameter, Sie können also die Anzahl der Epochen selbst wählen, 15 reichten mir), wir zeigen die Antworten in der ersten Epoche und die 1000. ist die endgültige Version (falls vorhanden, zum Beispiel 20, dann geben Sie 20 an). Hier wird der Code wiederholt, daher werde ich ihn nicht beschreiben, da ist dort alles sehr klar.
import numpy as np import random
Das ist alles, das Muster, das das neuronale Netzwerk finden soll. Von dieser Zahl (erste, zweite, dritte) hängt die endgültige Version ab und der Rest wird ignoriert. Sie können beispielsweise logische Operationen (XOR, NOT, AND ...) ausführen, nur in diesem Fall ändern Sie in der Netzwerkklasse die Eingabedaten um zwei. Ich habe auch die Regel befolgt, dass Neuronen in der verborgenen Schicht gleich der Eingabe sind Daten mit zwei multipliziert, es hat funktioniert, aber Sie können Ihre Optionen ausprobieren. Es ist auch sehr wichtig, dem neuronalen Netzwerk die gleiche Anzahl einiger Antworten und anderer Antworten bereitzustellen, damit die Anzahl der richtigen Antworten, zum Beispiel „a“, wäre gleich „b“, sonst antwortet das neuronale Netz Alle antworten auf die gleiche Weise, das heißt, wenn es mehr a gibt, dann wird es auf alles antworten und es wird nichts dabei herauskommen. Geben Sie ihm im Trainingsbeispiel auch völlig andere Optionen, damit es das Muster versteht, z. B. wenn Wenn Sie einen XOR-Block erstellen, müssen Sie eine Option mit zwei Einsen hinzufügen. Bei logischen Operationen müssen Sie jedoch alle Optionen angeben, da es zu wenige davon gibt und es nichts versteht.
Das ist es!!! Nächster Artikel (unbedingt lesen!): Bald…
Code: https://github.com/LanskoyKirill/GenNumPy.git
Meine Website (wird möglicherweise überarbeitet): selfrobotics.space
Das obige ist der detaillierte Inhalt vonErstellen eines einfachen und effizienten genetischen Algorithmus für ein neuronales Netzwerk mit Python und NumPy. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!