Die offzielle Webseite des Komponisten

Dies ist eine Übersetzung der SmallTalk-Codes aus dem Buch "Agile Artificial Intelligence in Pharo Implementing Neural Networks, Genetic Algorithms, and Neuroevolution" von Alexandre Bergel, das ich wärmstens empfehle. Dies ist zugleich meine Auseinandersetzung mit dem Commoni Lisp Object System CLOS.


(ql:quickload :fiveam)

;; ================== NEURAL NETWORK PACKAGE ==================
(defpackage :neural-network
(:use :cl)
(:export :neuron :feed)) ;; `feed` muss hier exportiert sein

(in-package :neural-network)

;; Neuron-Klasse definieren
(defclass neuron ()
((weights :initarg :weights
:initform nil
:accessor neuron-weights)
(bias :initarg :bias
:initform 0
:accessor neuron-bias)))

;; Setter für Gewichte
(defmethod set-weights ((n neuron) someWeightsAsNumbers)
"Setzt die Gewichte des Neurons. Erwartet eine Liste von Zahlen."
(setf (neuron-weights n) someWeightsAsNumbers))

;; Getter für Gewichte
(defmethod get-weights ((n neuron))
"Gibt die aktuellen Gewichte des Neurons zurück."
(neuron-weights n))

;; Setter für Bias
(defmethod set-bias ((n neuron) aNumber)
"Setzt den Bias des Neurons."
(setf (neuron-bias n) aNumber))

;; Getter für Bias
(defmethod bias ((n neuron))
"Gibt den aktuellen Bias des Neurons zurück."
(neuron-bias n))

(defmethod feed ((n neuron) inputs)
"Berechnet die Ausgabe des Neurons basierend auf den Eingaben und Gewichten."

;; Die Variable `z` berechnet die gewichtete Summe der Eingaben plus den Bias
(let* ((z (+
;; `reduce #'+` summiert die Liste der gewichteten Eingaben
(reduce #'+
;; `mapcar #'*` multipliziert jedes Element von `inputs`
;; mit dem entsprechenden Gewicht in `neuron-weights`
(mapcar #'* inputs (neuron-weights n)))

;; `neuron-bias n` gibt den Bias des Neurons zurück und wird addiert
(neuron-bias n))))

;; Wenn `z` größer als 0 ist, gibt die Methode `1` zurück, sonst `0`
(if (> z 0) 1 0)))

;; Neuron-Instanz testen
(defparameter *newNeuron*
(make-instance 'neuron
:weights '(1 2)
:bias -2))

(feed *newNeuron* '(5 2)) ;; Jetzt korrekt aufrufen

;; ================== TEST-PACKAGE ==================
(ql:quickload "fiveam") ;; Falls FiveAM nicht installiert ist

(defpackage :perceptron-tests
(:use :cl :fiveam)
(:import-from :neural-network :feed)) ;; `neuron` wird NICHT importiert

(in-package :perceptron-tests)

;; Neue Test-Suite anlegen
(def-suite perceptron-suite)
(in-suite perceptron-suite)

;; Testfall definieren
(test test-small-example
(let* ((p (make-instance 'neuron :weights '(1 2) :bias -2))
(result (neural-network::feed p '(5 2)))) ;; `feed` kann jetzt ohne `neural-network:` verwendet werden
(is (= result 1)) ;; Überprüft, ob die Berechnung korrekt ist
result))

;; Tests ausführen
(run! 'perceptron-suite)


(test test-and
(let ((p (make-instance 'neural-network:neuron :weights '(1 1) :bias -1.5)))
(is (= (neural-network:feed p '(0 0)) 0))
(is (= (neural-network:feed p '(0 1)) 0))
(is (= (neural-network:feed p '(1 0)) 0))
(is (= (neural-network:feed p '(1 1)) 1))))

(test test-and
(let ((p (make-instance 'neural-network:neuron :weights '(1 1) :bias -1.5))
(test-cases '(((0 0) 0)
((0 1) 0)
((1 0) 0)
((1 1) 1)))) ;; Eingabe-Erwartungs-Paare
(dolist (case test-cases)
(destructuring-bind ((input1 input2) expected) case
(is (= (neural-network:feed p (list input1 input2)) expected))))))


(run! 'perceptron-suite)

(test test-or
(let ((p (make-instance 'neural-network:neuron :weights '(1 1) :bias -0.5))
(test-cases '(((0 0) 0)
((0 1) 1)
((1 0) 1)
((1 1) 1))))
(dolist (case test-cases)
(destructuring-bind ((input1 input2) expected) case
(is (= (neural-network:feed p (list input1 input2)) expected))))))

(run! 'perceptron-suite)



(test test-nor
(let ((p (make-instance 'neural-network:neuron :weights '(-1 -1) :bias 0.5))
(test-cases '(((0 0) 1)
((0 1) 0)
((1 0) 0)
((1 1) 0))))
(dolist (case test-cases)
(destructuring-bind ((input1 input2) expected) case
(is (= (neural-network:feed p (list input1 input2)) expected))))))

(run! 'perceptron-suite)



(test test-nor
(let ((p (make-instance 'neural-network:neuron :weights '(-1) :bias 0.5)))
(is (= (neural-network:feed p '(1)) 0))
(is (= (neural-network:feed p '(0)) 1))))

(test test-nor
(let ((p (make-instance 'neural-network:neuron :weights '(-1) :bias 0.5))
(test-cases '(((1) 0)
((0) 1))))
(dolist (case test-cases)
(destructuring-bind ((input1) expected) case
(is (= (neural-network:feed p (list input1)) expected))))))

(run! 'perceptron-suite)


(test digital-comparator
;; Wir starten einen Test mit dem Namen "digital-comparator".
(let* ((inputs '(1 0)) ;; Das sind die Eingaben für unseren Test: a = 1, b = 0.

;; Wir holen uns die beiden Eingabewerte aus der Liste.
(a (first inputs)) ;; a = 1
(b (second inputs)) ;; b = 0

;; Jetzt erstellen wir unsere künstlichen Neuronen (Perceptrons).
;; Diese Neuronen haben bestimmte Gewichte und einen Schwellenwert (Bias).

;; UND-Neuron: Gibt 1 zurück, wenn beide Eingaben 1 sind.
(and-neuron (make-instance 'neural-network:neuron :weights '(1 1) :bias -1.5))

;; NICHT-Neuron: Gibt 1 zurück, wenn die Eingabe 0 ist, und 0, wenn die Eingabe 1 ist.
(not-neuron (make-instance 'neural-network:neuron :weights '(-1) :bias 0.5))

;; NOR-Neuron: Gibt 1 zurück, wenn beide Eingaben 0 sind.
(nor-neuron (make-instance 'neural-network:neuron :weights '(-1 -1) :bias 0.5))

;; Jetzt nutzen wir diese Neuronen, um unser digitales Vergleichs-Modell zu bauen.

;; Berechne NOT A: Falls a = 1, dann wird notA = 0. Falls a = 0, dann wird notA = 1.
(notA (neural-network:feed not-neuron (list a)))

;; Berechne NOT B: Falls b = 1, dann wird notB = 0. Falls b = 0, dann wird notB = 1.
(notB (neural-network:feed not-neuron (list b)))

;; Berechne A < B: Dies ist der Fall, wenn A nicht gesetzt (0) und B gesetzt (1) ist.
;; Das wird mit dem UND-Neuron realisiert: notA UND b.
(aLb (neural-network:feed and-neuron (list notA b)))

;; Berechne A > B: Dies ist der Fall, wenn A gesetzt (1) und B nicht gesetzt (0) ist.
;; Das wird mit dem UND-Neuron realisiert: A UND notB.
(aGb (neural-network:feed and-neuron (list a notB)))

;; Berechne A = B: Das passiert, wenn weder A > B noch A < B gilt.
;; Das bedeutet, dass weder aGb noch aLb eine 1 haben dürfen.
(aEb (neural-network:feed nor-neuron (list aGb aLb))))

;; Jetzt überprüfen wir, ob unser Neuronennetz das richtige Ergebnis liefert.
;; Die erwartete Ausgabe für die Eingabe (1 0) ist: (1 0 0), weil:
;; - A ist größer als B (aGb = 1)
;; - A ist nicht gleich B (aEb = 0)
;; - A ist nicht kleiner als B (aLb = 0)
(is (equal (list aGb aEb aLb) '(1 0 0)))))


(defun learn (inputs weights bias desired-output real-output)
"Lernt aus den Eingaben und passt die Gewichte sowie den Bias an."
(let* ((diff (- desired-output real-output)) ;; Berechnet die Differenz zwischen gewünschtem und tatsächlichem Output
(alpha 0.1)) ;; Lernrate: Bestimmt, wie stark wir die Werte anpassen
;; Gehe durch alle Gewichte und aktualisiere sie
(loop for i from 0 below (length weights)
do (setf (nth i weights) ;; Ändere das Gewicht an der Position i
(+ (nth i weights) (* alpha (nth i inputs) diff)))) ;; Passe es basierend auf der Differenz an
;; Bias aktualisieren
(setf bias (+ bias (* alpha diff))) ;; Bias wird mit der Lernrate angepasst
(values weights bias))) ;; Rückgabe der neuen Werte für Gewichte und Bias(defun learn (inputs weights bias desired-output real-output)
(let* ((diff (- desired-output real-output))
(alpha 0.1))
;; Gewichte aktualisieren
(loop for i from 0 below (length weights)
do (setf (nth i weights) (+ (nth i weights) (* alpha (nth i inputs) diff))))
;; Bias aktualisieren
(setf bias (+ bias (* alpha diff)))
(values weights bias))) ;; Rückgabe der aktualisierten Werte


;;===================TO BE CONTINUED ====================

Diese Webseite verwendet Cookies. Cookies erleichtern die Bereitstellung unserer Dienste. Mit der Nutzung unserer Dienste erklären Sie sich damit einverstanden, dass wir Cookies verwenden. Auch stimmen Sie ausdrücklich der Verwendung von Google Analytics zu! Datenschutzerklärung