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!