2010-12-26 2 views
7

Я хотел бы построить двигатель Connect 4, который работает с использованием искусственной нейронной сети - только потому, что меня увлекают ANN.Подключение 4 с нейронной сетью: оценка чертежа + дальнейшие шаги

Я создал следующий проект структуры ANN. Будет ли это работать? И являются ли эти соединения правильными (даже крестными)?

alt text

Не могли бы вы помочь мне составить до класса UML диаграммы для этого ИНС?

Я хочу предоставить представление платы ANN в качестве своего ввода. И выход должен быть выбранным.

Обучение должно быть выполнено с использованием reinforcement learning и должно применяться sigmoid function. Двигатель будет играть против игроков. И в зависимости от результата игры весы должны корректироваться.

Что я ищу ...

... в основном кодирования вопросов. Чем больше он отходит от абстрактного мышления к кодированию, тем лучше.

ответ

2

Ниже показано, как я организовал свой дизайн и код, когда я возился с нейронными сетями. Код здесь (очевидно) 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 как хорошая ссылка.

Надеюсь, этого достаточно, чтобы вы начали!

3

Существует множество различных способов реализации нейронных сетей, которые варьируются от простых/простых в понимании до высоко оптимизированных. У Wikipedia article on backpropagation, с которыми вы связались, есть ссылки на реализации в C++, C#, Java и т. Д., Которые могли бы служить хорошими ссылками, если вам интересно узнать, как это сделали другие люди.

Одна простая архитектура будет моделировать как узлы, так и соединения как отдельные объекты; узлы имели бы возможные входящие и исходящие соединения с другими узлами, а также уровни активации и значения ошибок, тогда как соединения имели бы весовые значения.

В качестве альтернативы есть более эффективные способы представления этих узлов и соединений - например массивы значений с плавающей запятой, организованные слоем. Это делает вещи более сложными для кодирования, но позволяет избежать создания множества объектов и указателей на объекты.

Одно примечание: часто люди будут включать в себя a bias node - в дополнение к обычным входным узлам - который обеспечивает постоянное значение для каждого скрытого и выходного узлов.

2

Я реализовал нейронные сети до того, чтобы увидеть некоторые проблемы с вашей предлагаемой архитектурой:

  1. Типичная сеть многослойной имеет соединение с каждым входного узла к каждому скрытому узлу, и от каждого скрытого узла до каждого выходного узла. Это позволяет объединить все входы и вносить вклад в каждый выход. Если вы выделите 4 скрытых узла для каждого входа, вы потеряете часть мощности сети, чтобы идентифицировать отношения между входами и выходами.

  2. Как вы придумаете значения для обучения сети? Ваша сеть создает сопоставление между позициями доски и оптимальным следующим шагом, поэтому вам нужен набор примеров обучения, которые обеспечивают это. Конец игровых движений легко идентифицировать, но как вы скажете, что ход в середине игры «оптимален»?(Армирование обучение может помочь здесь)

последнее предложение заключается в использовании биполярных входов (-1 для ложного, +1 за истину), так как это может ускорить обучение. И Nate Kohl делает хороший момент: каждый скрытый вывод & выиграет от наличия смещения (подумайте об этом как о другом входном узле с фиксированным значением «1»).

1

Ваш дизайн будет сильно зависеть от конкретного типа обучения по усилению, которое вы планируете использовать.

Простейшим решением было бы использовать обратное протагонирование. Это делается путем подачи ошибки обратно в сеть (в обратном порядке) и использования инверсии функции (сигмоида) для определения корректировки для каждого веса. После нескольких итераций весы будут автоматически настроены так, чтобы они соответствовали входу.

Генетические алгоритмы являются альтернативой обратной связи, которые дают лучшие результаты (хотя и немного медленнее). Это делается путем обработки весов как схемы, которая может быть легко вставлена ​​и удалена. Схема заменяется мутированной версией (с использованием принципов естественного отбора) несколько раз до тех пор, пока не будет найдена подгонка.

Как вы можете видеть, реализация для каждого из них была бы совершенно иной. Вы можете попытаться сделать общий родовой набор, чтобы адаптироваться к каждому типу реализации, но это может привести к чрезмерному его усложнению. Как только вы на производстве, у вас обычно будет только одна форма обучения (или, в идеале, ваша сеть уже будет тренироваться).

Смежные вопросы