Java Modellierung von Collections

Krik

Fleet Admiral
Registriert
Juni 2005
Beiträge
12.000
Moin,


ich stehe gerade irgendwie auf dem Schlauch.

Ich will ein einfaches Perzeptron programmieren, dass etwa so aussehen soll:
- zweidimensionale Eingabe-Matrix (Input-Neuronen)
- eindimensionale Ausgabe-Matrix (Output-Neuronen)
- jedes Ausgabe-Neuron ist mit jedem Eingabe-Neuron verbunden
- und jede dieser Verbindungen hat eine eigene Wichtung

img9.gif



Ich hab mit dem ganzen Kram kein Problem, nur ich finde keinen eleganten Weg jeder Verbindung eine eigene Wichtung zuzuweisen.
Im Moment habe ich bei jedem Ausgabe-Neuronen eine Referenz auf ein zweidimensionales Array mit allen Eingabe-Neuronen. (Das werde ich später vermutlich noch static machen, die Liste ist ja bei jedem Ausgabe-Neuron gleich.)
Und ich habe bei jedem Ausgabe-Neuron ein zweidimensionales Array für die Wichtungen.

Es irritiert mich sehr, dass die beiden Arrays nicht direkt miteinander verbunden sind, obwohl sie eigentlich zusammen gehören. Ich finde einfach nur keinen Weg, sie sinnvoll miteinander zu verbinden.
Ich hab auch schon daran gedacht, einfach alle Daten in ein Array zu tun und überhaupt nicht mit extra Neuron-Objekten zu arbeiten, aber das widerstrebt mir auch.

Habt ihr da eine Idee?


Gruß, Laurin
 
Zuletzt bearbeitet:
Du arbeitest mit Arrays. Wie wäre es mit einer dynamischen Liste? Dort kannst du bei jedem Eintrag ja mehrere Sachen speichern. Zum Beispiel den Eingabewert und dessen Wichtung.
 
Wenn ich die Menge der Neuronen einmal festgelegt habe, ist eine Änderung der Größe nicht mehr notwendig. Ich brauche dann nicht die Eigenschaften einer Liste nicht. Arrays sind dann etwas schneller.

Es werden Pi mal Daumen 160x160 Eingabe-Neuronen und um die 10 bis 20 Ausgabe-Neuronen werden.
 
Versteh dein Problem vielleicht nicht ganz aber im Grunde brauchst du doch nur eine Tabelle

xxx| o1 | o2 | o3 |
-------------------------
x0 | w01 | w02 | w03|
-------------------------
x1 | w11 | w12 | w13|
-------------------------
xn | wn1 | wn2 | wn3|
 
Schön wenn ich das Brett vor deinem Kopf entfernen konnte :)

Wenn sich die Anzahl der Elemente nicht verändert und du weißt wie groß dein Array entsprechend wird, ist ein Array selbstverständlich die performanteste Lösung
 
Hier mal das KNN. Sollte so funktionieren, ist aber ungetestet und ein paar Kommentare mehr wären auch nicht schlecht.
Am Ende sind es dann 4 Arrays (Eingabe, Wichtungen, Schwellenwerte, Ausgabe) geworden. :rolleyes:

Der Konstruktor verlangt die Größe des Arrays der Wichtungen (x, y) und die Menge der Ausgabeneuronen (z). Die Wichtungen und die Schwellenwerte werden randomisiert.

Das neuronale Netz muss danach trainiert werden (learn()-Methode), indem man ihm ein Satz Eingabevektoren/Eingabeneuronen und das erwartete Ergebnis vor die Nase setzt. Die Lernfunktion sollte je nach Menge der Neuronen bis zu mehrere tausend Male wiederholt werden. Eben so lange, bis einem die Ausgabe des neuronalen Netzes passt.
Als Beispiel: Ein Netz mit ca. 50 Eingabe und 25 Ausgabeneuronen braucht ungefähr 200 bis 1000 Lerniterationen, bis es brauchbar wird.

Falls es einem zu langsam lernt, kann man versuchen die Lernrate zu erhöhen. Man darf sie aber nicht zu stark erhöhen, sonst kommt nur Murks heraus. Der beste Wert lässt sich eigentlich nur durch Experimentieren herausbekommen. Übliche Werte liegen meist zwischen 0.1 und 1.0 (selten auch mal 2.0 oder 3.0).

Wenn es dann genügend gelernt hat, kann man es über die fire()-Methode anwenden. Einfach eine Ausgangssituation bestimmen, übergeben, arbeiten lassen und am Ende den Status der Ausgabeneuronen zurückbekommen.

Code:
import java.io.Serializable;

/**
 * @author e-Laurin
 * https://www.computerbase.de/forum/threads/modellierung-von-collections.922690/
 */
public final class ANN implements Serializable {

	private static final long serialVersionUID = -1832083414154078932L;

	private final float[][] weight;		// Wichtungen zwischen den Eingabe- und Ausgabeneuronen
	private final float[] threshold;	// Schwellenwerte der Ausgabeneuronen
	private final boolean[] output;		// Ausgabeneuronen / Ausgabevektoren
	private final float learningRate = 0.2f; // Lernrate
	
	// Konstruktor
	public ANN(final int x, final int y, final int z) {
		
		// Wichtungen
		weight = new float[x][y];
		for (int i = 0; i < x; i++) {
			for (int j = 0; j < y; j++) {
				weight[i][j] = (float) Math.random();
			}
		}
		
		// Schwellenwerte und Ausgabeneuronen
		threshold = new float[z];
		output = new boolean[z];
		for (int k = 0; k < z; k++) {
			threshold[k] = (float) Math.random();
			output[k] = false;
		}
	}
	
	// KNN zur Arbeit anstoßen
	public boolean[] fire(final boolean[][] input) {
		float net; // Netzaktivität
		
		// für jedes Ausgabeneutron berechnen, ob es feuert
		for (int k = 0; k < output.length; k++) {
			net = 0f;
			
			// Netzaktivität berechnen, in dem man alle Eingabeneutronen überprüft und die Wichtungen beachtet 
			for (int i = 0; i < input.length; i++) { // input.length gibt die Breite des Arrays zurück
				for (int j = 0; j < input[0].length; j++) { // input[0].length gibt die Höhe des Arrays zurück
					if (input[i][j]) {
						net += weight[i][j]; // Netzaktivität
					}
				}
			}
			
			// Aktivierung berechnen, einfache Schwellenfunktion
			output[k] = net > threshold[k] ? true : false; 
		}
		
		return output;
	}
	
	// KNN lernen lassen, nur ein Lernzyklus bzw. -iteration
	public void learn(final boolean[][] input, final boolean[] desiredOutput) {
		float delta = 0f; // Fehlerrate
		
		// Einmal das KNN die Daten ansehen lassen
		fire(input);
		
		for (int k = 0; k < output.length; k++) {
			// Deltaregel zur Fehlerbestimmung
			delta = (desiredOutput[k] ? 1f : 0f) - (output[k] ? 1f : 0f);
			
			if (delta != 0f) { // es liegt ein Fehler vor, also das Netz lernen lassen
				// alle Wichtungen anpassen
				for (int i = 0; i < input.length; i++) { // input.length gibt die Breite des Arrays zurück
					for (int j = 0; j < input[0].length; j++) { // input[0].length gibt die Höhe des Arrays zurück
						weight[i][j] += learningRate * (input[i][j] ? 1f : 0f) * delta;
					}
				}
				
				// Schwellenwert anpassen
				threshold[k] -= learningRate * delta;				
			}
		}		
	}
}

Edit:
Fast vergessen zu schreiben:
Anwenden lässt sich dieses Netz zB bei Buchstabenerkennung (OCR). Die Eingabeneuronen bilden dann ein schwarz/weißes Pixelraster (schwarz/weiß weil wir ja nur Boolean verwenden) und die Ausgabeneuronen entsprechen dann den Buchstaben, die das KNN erkennen soll (Ausgabeneuron, dass zB dem Buchstaben 'A' entspricht, steht dann auf true, die anderen sollten auf false geschaltet sein).
 
Zuletzt bearbeitet:

Ähnliche Themen

Zurück
Oben