kostenloser Webspace werbefrei: lima-city


Logikgatter durch Machine Learning simulieren

lima-cityForumProgrammiersprachenPython

  1. Autor dieses Themas

    thecoody

    thecoody hat kostenlosen Webspace.

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


  2. Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!

    lima-city: Gratis werbefreier Webspace für deine eigene Homepage

  3. 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.
  4. Autor dieses Themas

    thecoody

    thecoody hat kostenlosen Webspace.

    Vielen Dank! :smile:

    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.
  5. Diskutiere mit und stelle Fragen: Jetzt kostenlos anmelden!

    lima-city: Gratis werbefreier Webspace für deine eigene Homepage

Dir gefällt dieses Thema?

Über lima-city

Login zum Webhosting ohne Werbung!