2010-12-26 6 views
7

Ich möchte eine Connect 4 Engine bauen, die mit einem künstlichen neuronalen Netzwerk arbeitet - nur weil mich ANNs fasziniert.Connect 4 mit neuronalem Netzwerk: Auswertung des Entwurfs + weitere Schritte

Ich habe den folgenden Entwurf der ANN-Struktur erstellt. Würde es funktionieren? Und sind diese Verbindungen richtig (sogar die Kreuzigen)?

alt text

Können Sie mir helfen, ein UML-Klassendiagramm für dieses ANN zu entwerfen up?

Ich möchte die Board-Darstellung der ANN als Eingabe geben. Und die Ausgabe sollte die Entscheidung sein.

Das Lernen sollte später mit reinforcement learning durchgeführt werden und die sigmoid function sollte angewendet werden. Der Motor wird gegen menschliche Spieler spielen. Und abhängig vom Ergebnis des Spiels sollten die Gewichte dann angepasst werden.

Was ich suche ...

... hauptsächlich Codierung Probleme. Je mehr es sich vom abstrakten Denken zur Codierung bewegt, desto besser ist es.

Antwort

2

Im Folgenden habe ich meinen Entwurf und meinen Code organisiert, als ich mit neuronalen Netzen herumhantierte. Der Code hier ist (offensichtlich) psuedocode und folgt grob objektorientierten Konventionen.

Beginnend von unten nach oben haben Sie Ihr Neuron. Jedes Neuron muss in der Lage sein, die Gewichte zu halten, die es auf die eingehenden Verbindungen legt, einen Puffer, um die eingehenden Verbindungsdaten zu halten, und eine Liste seiner ausgehenden Kanten. Jedes Neuron muss in der Lage sein, drei Dinge zu tun:

  • eine Möglichkeit, Daten von einem ankommenden Kante zu akzeptieren
  • Verfahren zur Verarbeitung der Eingangsdaten und Gewichte, den Wert zu formulieren dieses Neuron Senden werden aus
  • Ein Weg, um dieses Neuron des Wert des Sendens

-Code-weise auf den abgehenden Kanten aus dieser übersetzt:

// Each neuron needs to keep track of this data 
float in_data[]; // Values sent to this neuron 
float weights[]; // The weights on each edge 
float value; // The value this neuron will be sending out 
Neuron out_edges[]; // Each Neuron that this neuron should send data to 

// Each neuron should expose this functionality 
void accept_data(float data) { 
    in_data.append(data); // Add the data to the incoming data buffer 
} 
void process() { 
    value = /* result of combining weights and incoming data here */; 
} 
void send_value() { 
    foreach (neuron in out_edges) { 
     neuron.accept_data(value); 
    } 
} 

Als nächstes fand ich es am einfachsten, wenn Sie eine Schichtklasse erstellen, die eine Liste von Neuronen enthält. (Es ist durchaus möglich, diese Klasse zu überspringen, und Ihr neuronales Netzwerk kann nur eine Liste mit Neuronen enthalten. Ich fand es organisatorisch und debuggens leichter, eine Schichtklasse zu haben.) Jede Schicht sollte die Fähigkeit haben:

  • Ursache jedes Neuron zu ‚Feuer‘
  • Rückkehr der rohe Array von Neuronen, die diese Schicht um hüllt. (Dies ist nützlich, wenn Sie z. B. manuell Eingabedaten in der ersten Schicht eines neuronalen Netzwerks eingeben müssen.
  • )

-Code-weise dies führt zu:

//Each layer needs to keep track of this data. 
Neuron[] neurons; 

//Each layer should expose this functionality. 
void fire() { 
    foreach (neuron in neurons) { 
     float value = neuron.process(); 
     neuron.send_value(value); 
    } 
} 
Neuron[] get_neurons() { 
    return neurons; 
} 

Schließlich Sie eine NeuralNetwork Klasse, die eine Liste von Schichten hält, eine Art und Weise der Einstellung der ersten Schicht mit Anfangsdaten auf, ein Lernalgorithmus und eine Möglichkeit, das gesamte neuronale Netzwerk zu betreiben. In meiner Implementierung sammelte ich die endgültigen Ausgabedaten, indem ich eine vierte Ebene hinzufügte, die aus einem einzelnen falschen Neuron bestand, das einfach alle eingehenden Daten zwischenspeicherte und zurückgab.

Ich empfehle mit Backwards Propagation als Lernalgorithmus zu beginnen, da es angeblich am einfachsten zu implementieren ist. Als ich daran arbeitete, hatte ich große Schwierigkeiten, eine sehr einfache Erklärung des Algorithmus zu finden, aber meine Notizen listen this site als eine gute Referenz auf.

Ich hoffe, dass es genug ist, um loszulegen!

3

Es gibt viele verschiedene Möglichkeiten, um neuronale Netze zu implementieren, die von einfach/leicht zu hoch-optimiert reichen. Die Wikipedia article on backpropagation, mit der Sie verlinkt haben, enthält Links zu Implementierungen in C++, C#, Java usw., die als gute Referenzen dienen könnten, wenn Sie daran interessiert sind, zu sehen, wie andere Leute es gemacht haben.

Eine einfache Architektur würde sowohl Knoten als auch Verbindungen als separate Entitäten modellieren; Knoten hätten mögliche eingehende und ausgehende Verbindungen zu anderen Knoten sowie Aktivierungsebenen und Fehlerwerte, während Verbindungen Gewichtungswerte hätten.

Alternativ dazu gibt es effizientere Möglichkeiten, diese Knoten und Verbindungen darzustellen - z. B. Arrays von Gleitkommawerten, die nach Layer organisiert sind. Das macht den Code etwas komplizierter, aber vermeidet so viele Objekte und Zeiger auf Objekte.

Eine Anmerkung: oft Leute enthalten a bias node - zusätzlich zu den normalen Eingabeknoten - die einen konstanten Wert für jeden versteckten und Ausgabeknoten bietet.

2

Ich habe vor neuronalen Netze implementiert, und ein paar Probleme mit Ihrer vorgeschlagene Architektur sehen:

  1. Ein typisches Netzwerk Multi-Layer-Verbindungen von jedem jeden Eingangsknoten zu hat versteckten Knoten, und von jedem versteckten Knoten zu jedem Ausgangsknoten. Dies ermöglicht, dass Informationen von allen Eingängen kombiniert werden und zu jeder Ausgabe beitragen. Wenn Sie jedem Eingang 4 versteckte Knoten zuweisen, verlieren Sie einen Teil der Leistung des Netzwerks, um Beziehungen zwischen den Ein- und Ausgängen zu identifizieren.

  2. Wie werden Sie mit Werten zum Trainieren des Netzwerks kommen? Ihr Netzwerk erstellt eine Zuordnung zwischen den Positionen des Boards und der optimalen nächsten Bewegung. Daher benötigen Sie eine Reihe von Trainingsbeispielen, die dies bereitstellen. Ende Spielzüge sind leicht zu identifizieren, aber wie sagen Sie, dass eine Mid-Game-Bewegung "optimal" ist?(Verstärkung Lernen kann hier helfen)

Ein letzter Vorschlag bipolare Eingänge zu verwenden ist (-1 für falsch, +1 für true), da dies kann das Lernen beschleunigen. Und Nate Kohl macht einen guten Punkt: Jeder versteckte & Ausgangsknoten profitiert von einer Bias-Verbindung (man denke an einen anderen Eingangsknoten mit einem festen Wert von "1").

1

Ihr Entwurf hängt stark von der spezifischen Art des Verstärkungslernens ab, das Sie verwenden möchten.

Die einfachste Lösung wäre die Verwendung von Backpropagation. Dies geschieht, indem der Fehler (umgekehrt) in das Netzwerk eingespeist wird und die Umkehrung der (Sigmoid-) Funktion verwendet wird, um die Einstellung für jedes Gewicht zu bestimmen. Nach einer Reihe von Iterationen werden die Gewichte automatisch an die Eingabe angepasst.

Genetische Algorithmen sind eine Alternative zur Rückpropagation, die zu besseren Ergebnissen führt (wenn auch etwas langsamer). Dies geschieht, indem die Gewichte als ein Schema behandelt werden, das leicht eingefügt und entfernt werden kann. Das Schema wird mehrmals durch eine mutierte Version (unter Verwendung der Prinzipien der natürlichen Selektion) ersetzt, bis eine Übereinstimmung gefunden wird.

Wie Sie sehen können, würde die Implementierung für jede dieser drastisch anders sein. Sie könnten versuchen, das Netzwerk generisch genug zu machen, um es an jede Art von Implementierung anzupassen, aber das kann es zu kompliziert machen. Sobald Sie in Produktion sind, haben Sie normalerweise nur eine Form des Trainings (oder Ihr Netzwerk wäre im Idealfall bereits trainiert).

Verwandte Themen