Соедините 4 с нейронной сетью: оценка проекта + дальнейшие шаги - PullRequest
7 голосов
/ 26 декабря 2010

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

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

alt text

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

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

Обучение должно быть позже выполнено с использованием усиленного обучения и должна применяться сигмовидная функция .Двигатель будет играть против игроков-людей.И в зависимости от результата игры весы должны быть скорректированы.

Что я ищу ...

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

Ответы [ 4 ]

3 голосов
/ 09 января 2011

Ниже показано, как я организовал свой дизайн и код, когда связывался с нейронными сетями. Код здесь (очевидно) psuedocode и примерно соответствует объектно-ориентированным соглашениям.

Начиная снизу вверх, у вас будет свой нейрон. Каждый нейрон должен иметь возможность удерживать веса, которые он помещает для входящих соединений, буфер для хранения данных о входящих соединениях и список его исходящих ребер. Каждый нейрон должен уметь делать три вещи:

  • Способ приема данных от входящего фронта
  • Метод обработки входных данных и весов для определения значения, которое этот нейрон будет отправлять
  • Способ отправки значения этого нейрона на исходящие ребра

В коде это означает:

// 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.) Каждый слой должен предоставлять возможность:

  • Вызвать каждый нейрон "огнем"
  • Вернуть необработанный массив нейронов, который окружает этот слой. (Это полезно, когда вам нужно выполнить такие вещи, как ручное заполнение входных данных в первом слое нейронной сети.)

В коде это означает:

//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();
    }
}

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

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

3 голосов
/ 31 декабря 2010

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

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

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

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

2 голосов
/ 02 января 2011

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

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

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

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

1 голос
/ 09 января 2011

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

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

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

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

...