Ниже показано, как я организовал свой дизайн и код, когда я возился с нейронными сетями. Код здесь (очевидно) psuedocode и примерно соответствует объектно-ориентированным соглашениям.
Начиная со снизу вверх, у вас будет свой нейрон. Каждый нейрон должен уметь удерживать весы, которые он накладывает на входящие соединения, буфер для хранения входящих данных соединения и список его исходящих ребер. Каждый нейрон должен быть в состоянии сделать три вещи:
- образом, чтобы принимать данные из входящего края
- Способ обработки входных данных и весов сформулировать значение этого нейрон будет рассылка
- способ отправки значение этого нейрона на исходящих ребер
Code-накрест это приводит к:
// 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);
}
}
Далее я нашел это проще всего, если вы создали класс Layer, который содержит список нейронов. (Вполне возможно пропустить этот класс, и просто у вашей NeuralNetwork будет список списков нейронов. Я считаю, что для класса Layer проще организационно и отлаживать). Каждый уровень должен предоставить возможность:
- Причина каждый нейрон «огонь»
- Возвращение необработанный массив нейронов, что этот слой оборачивается вокруг. (Это полезно, когда вам нужно делать такие вещи, как ручное заполнение входных данных в первом слое нейронной сети.)
Code-накрест это переводится:
//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;
}
Наконец, у вас есть класс NeuralNetwork, который содержит список слоев, способ создания первого слоя с начальными данными, алгоритм обучения , и способ запуска всей нейронной сети. В моей реализации я собрал окончательные выходные данные, добавив четвертый уровень, состоящий из одного поддельного нейрона, который просто буферизует все свои входящие данные и возвращает это.
// Each neural network needs to keep track of this data.
Layer[] layers;
// Each neural network should expose this functionality
void initialize(float[] input_data) {
foreach (neuron in layers[0].get_neurons()) {
// do setup work here
}
}
void learn() {
foreach (layer in layers) {
foreach (neuron in layer) {
/* compare the neuron's computer value to the value it
* should have generated and adjust the weights accordingly
*/
}
}
}
void run() {
foreach (layer in layers) {
layer.fire();
}
}
Я рекомендую начать с обратного распространения в качестве вашего алгоритма обучения, поскольку он, как предполагается, проще всего реализовать. Когда я работал над этим, я с большим трудом пытался найти очень простое объяснение алгоритма, но мои заметки список this site как хорошая ссылка.
Надеюсь, этого достаточно, чтобы вы начали!