Logikgatter durch Machine Learning simulieren
lima-city → Forum → Programmiersprachen → Python
-
Guten Tag,
aktuell bin ich dabei ein Neuronales Netz mittels Python zu erstellen, welches mit Daten von Logikgattern (XOR, NAND) trainiert werden soll.
Dazu habe ich zwei Neuronen in der Eingangsschicht und ein hidden Neuron. Sofern ich die Theorie korrekt verstanden habe sollte dies reichen.
Leider können immer nur drei der vier Eingabemöglichkeiten (nahezu) korrekt vorhergesagt werden.
Gibt es eventuell einen Fehler in meinem Code (https://codeshare.io/LogicGate) oder meinen theoretischen Überlegungen (https://thecoody.lima-city.de/wp-content/uploads/2021/01/XOR_Gate-1.pdf)?
# Program to mimic a logic gate (XOR, NAND, AND, ...) # Import packages import numpy as np import matplotlib.pyplot as plt # Define class class LogicGate: def __init__(self): self.initializeRandom() # Class to initialize the weights and biases randomly with numbers in the range of [-1, 1] def initializeRandom(self): self.w11 = 2 * np.random.rand() - 1 self.w12 = 2 * np.random.rand() - 1 self.w21 = 2 * np.random.rand() - 1 self.w22 = 2 * np.random.rand() - 1 self.w31 = 2 * np.random.rand() - 1 self.w32 = 2 * np.random.rand() - 1 self.b1 = 2 * np.random.rand() - 1 self.b2 = 2 * np.random.rand() - 1 self.b3 = 2 * np.random.rand() - 1 # Print weights and biases: print(f"Weights\nw_11 = {self.w11}\nw_21 = {self.w21}\nw_13 = {self.w12}\nw_22 = {self.w22}\nLayer 2\nw_31 = {self.w31}\nw_32 = {self.w32}\n") print(f"Biases\nb_1 = {self.b1}\nb_2 = {self.b2}\nb3 = {self.b3}") # Define the sigmoid function given def sigmoid (self, x): return 1/(1 + np.exp(-x)) #Define the derivative of the sigmoid def sigmoid_derivative(self, x): return self.sigmoid(x) * (1 - self.sigmoid(x)) # Function to test a set of two given inputs e.g [0, 0] or [1, 0] etc. def test(self, input1, input2, predict = False): # Calculate the value of the neurons 1 and 2 neuron1 = self.w11 * input1 + self.w21 * input2 + self.b1 neuron2 = self.w12 * input1 + self.w22 * input2 + self.b2 # Calculate the activation of the neurons 1 and 2 neuron1_activation = self.sigmoid(neuron1) neuron2_activation = self.sigmoid(neuron2) # Caltulate the neuron 3 and it's activation which is also the output of the network neuron3 = self.w31 * neuron1_activation + self.w32 * neuron2_activation + self.b3 neuron3_activation = self.sigmoid(neuron3) if predict: return neuron3_activation else: return neuron3_activation, neuron1, neuron2, neuron3 # Function to train the network def train(self, epochs, learning_rate, inputs, expected_outputs): self.initializeRandom() errors = [] weights = [] biases = [] for i in range(epochs): # Start with input 1, 2, 3, 4 and begin again to train for 1, 2.... rand = i % 4 input1 = inputs[rand][0] input2 = inputs[rand][1] expected_output = expected_outputs[rand][0] neuron3_activation, neuron1, neuron2, neuron3 = XOR.test(input1, input2) # Backpropatation e3 = (expected_output - neuron3_activation) e1 = self.w31 / (self.w31 + self.w32) * e3 e2 = self.w32 / (self.w31 + self.w32) * e3 # Adjusting weights and biases self.w31 += learning_rate * e3 * self.sigmoid_derivative(neuron3) * neuron1 self.w32 += learning_rate * e3 * self.sigmoid_derivative(neuron3) * neuron2 self.w11 += learning_rate * e1 * self.sigmoid_derivative(neuron1) * input1 self.w21 += learning_rate * e1 * self.sigmoid_derivative(neuron1) * input2 self.w12 += learning_rate * e2 * self.sigmoid_derivative(neuron2) * input1 self.w22 += learning_rate * e2 * self.sigmoid_derivative(neuron2) * input2 self.b3 += learning_rate * e3 * self.sigmoid_derivative(neuron3) self.b2 += learning_rate * e2 * self.sigmoid_derivative(neuron2) self.b1 += learning_rate * e1 * self.sigmoid_derivative(neuron1) # Only important for graphical representation errors.append(e3) biases.append(self.b1) biases.append(self.b2) biases.append(self.b3) weights.append(self.w11) weights.append(self.w12) weights.append(self.w21) weights.append(self.w22) weights.append(self.w31) weights.append(self.w32) # Plot of the weights and biases x_axis = np.linspace(0, int(epochs), int(epochs)) fig = plt.figure(figsize=(16, 9)) s1 = plt.subplot(311) s2 = plt.subplot(312) s3 = plt.subplot(313) s1.plot(x_axis, biases[0::3], "o", label="Bias b1") s1.plot(x_axis, biases[1::3], "o", label="Bias b2") s1.plot(x_axis, biases[2::3], "o", label="Bias b3") s2.plot(x_axis, weights[0::6], "o", label="Weights w11") s2.plot(x_axis, weights[1::6], "o", label="Weights w21") s2.plot(x_axis, weights[2::6], "o", label="Weights w12") s2.plot(x_axis, weights[3::6], "o", label="Weights w22") s2.plot(x_axis, weights[4::6], "o", label="Weights w31") s2.plot(x_axis, weights[5::6], "o", label="Weights w32") s3.plot(np.linspace(0, epochs, int(epochs)), errors, label="Errors") s1.legend() s2.legend() s3.legend() return errors # Input datasets # XOR Gate inputs_XOR = np.array([[0,0],[0,1],[1,0],[1,1]]) expected_outputs_XOR = np.array([[0],[1],[1],[0]]) # NAND Gate inputs_NAND = np.array([[0,0],[0,1],[1,0],[1,1]]) expected_outputs_NAND = np.array([[1],[1],[1],[0]]) # Parameter settings epochs = 140000 learning_rate = 0.01 # XOR Gate XOR = LogicGate() errors = XOR.train(epochs, learning_rate, inputs_XOR, expected_outputs_XOR) print(f"Test[0, 0] -> 0 = {XOR.test(0, 0, predict=True)}") print(f"Test[0, 1] -> 1 = {XOR.test(0, 1, predict=True)}") print(f"Test[1, 0] -> 1 = {XOR.test(1, 0, predict=True)}") print(f"Test[1, 1] -> 0 = {XOR.test(1, 1, predict=True)}") plt.show() # NAND Gate NAND = LogicGate() errors = NAND.train(epochs, learning_rate, inputs_NAND, expected_outputs_NAND) print(f"Test[0, 0] -> 1 = {NAND.test(0, 0, predict=True)}") print(f"Test[0, 1] -> 1 = {NAND.test(0, 1, predict=True)}") print(f"Test[1, 0] -> 1 = {NAND.test(1, 0, predict=True)}") print(f"Test[1, 1] -> 0 = {NAND.test(1, 1, predict=True)}") plt.show()
-
Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!
lima-city: Gratis werbefreier Webspace für deine eigene Homepage
-
Hallo thecoody,
zunächst einmal habe ich zwei kleine Anpassungen durchgeführt:
In Zeile 82 steht:
XOR.test(input1, input2)
Da sollte eher 'self' stehen:
self.test(input1, input2)
Und bei der Berechnung der Backpropagation habe ich die Formel etwas abgeändert.
Aus diesem Teil
e1 = self.w31 / (self.w31 + self.w32) * e3 e2 = self.w32 / (self.w31 + self.w32) * e3
habe ich das hier gemacht:e1 = self.w31 * e3 * self.sigmoid_derivative(neuron3) e2 = self.w32 * e3 * self.sigmoid_derivative(neuron3)
Begründung:
Die Ableitung der Propagierungsfunktion in Neuron 3 ist für das Endergebnis relevant, deshalb sollte diese auftauchen. Dagegen spielt die Summe aus den beiden Gewichten bei der Ableitung keine Rolle, sondern nur das jeweils individuelle Gewicht.
An dieser Stelle zeigt das NAND-Gatter schon sehr gute Ergebnisse, nur das XOR-Gatter will noch nicht so richtig.
Generell scheint es mir, als sei das XOR-Gatter um einiges schwieriger zu trainieren als das NAND-Gatter.
Ich habe testweise zum Trainingsbeginn statt zufalligen Parametern einen Parametersatz vorgegeben, der bereits "in die Richtung" von XOR geht:
XOR.w11 = 2.0 XOR.w12 = 2.0 XOR.w21 = 2.0 XOR.w22 = 2.0 XOR.w31 = 2.0 XOR.w32 = -2.0 XOR.b1 = -1.0 XOR.b2 = -3.0 XOR.b3 = -1.0
Und ich habe die Trainingsparameter stark verändert. (1,4 Millionen Epochen, learning_rate=0.3)
Nun "akzeptiert" das neuronale Netz seine Aufgabe und trainiert in die richtige Richtung, aber die Optimierung verläuft sehr, sehr langsam.
Ich hoffe, ich konnte damit ein klein wenig weiter helfen. -
Vielen Dank!
Das hat mir sehr beim Verständnis geholfen. Mir ist klar, dass es unzählige effizientere Algorithmen dazu gibt, daher werde ich mich in Zukunft auf diese fokussieren. -
Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!
lima-city: Gratis werbefreier Webspace für deine eigene Homepage