7

我想构建一个使用人工神经网络工作的 Connect 4 引擎——只是因为我对 ANN 很着迷。

我创建了以下 ANN 结构草案。它会起作用吗?这些连接是否正确(甚至是交叉连接)?

替代文字

你能帮我为这个ANN起草一个UML类图吗?

我想向 ANN 提供董事会代表作为其输入。输出应该是选择的动作。

稍后应该使用强化学习来完成学习,并且应该应用sigmoid 函数。该引擎将与人类玩家对战。然后根据比赛结果调整权重。

我在找什么...

...主要是编码问题。从抽象思维到编码越远,它就越好。

4

4 回答 4

3

有很多不同的方法可以实现神经网络,从简单/易于理解到高度优化。您链接到的有关反向传播的Wikipedia 文章包含指向C++C#Java等实现的链接,如果您有兴趣了解其他人是如何做到的,这些可以作为很好的参考。

一种简单的架构会将节点和连接建模为单独的实体;节点可能具有到其他节点的传入和传出连接以及激活级别和错误值,而连接将具有权重值。

或者,有更有效的方法来表示这些节点和连接——例如,作为按层组织的浮点值数组。这使代码变得有点棘手,但避免了创建如此多的对象和指向对象的指针。

注意:通常人们会包括一个偏置节点——除了正常的输入节点——它为每个隐藏节点和输出节点提供一个常数值。

于 2010-12-30T21:50:13.143 回答
3

下面是我在搞乱神经网络时如何组织我的设计和代码的。这里的代码(显然)是伪代码,大致遵循面向对象的约定。

从下往上,你将拥有你的神经元。每个神经元都需要能够保存它对传入连接的权重、一个用于保存传入连接数据的缓冲区以及一个其传出边的列表。每个神经元需要能够做三件事:

  • 一种从传入边缘接受数据的方法
  • 一种处理输入数据和权重以制定该神经元将发送的值的方法
  • 一种在传出边缘发送此神经元值的方法

在代码方面,这转化为:

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

我建议从反向传播开始作为你的学习算法,因为它被认为是最容易实现的。当我在做这个的时候,我很难找到一个非常简单的算法解释,但是我的笔记把这个网站列为一个很好的参考。

我希望这足以让你开始!

于 2011-01-09T06:58:46.763 回答
2

我以前实现过神经网络,并看到您提出的架构存在一些问题:

  1. 典型的多层网络具有从每个输入节点到每个隐藏节点以及从每个隐藏节点到每个输出节点的连接。这允许将来自所有输入的信息组合起来并贡献给每个输出。如果您将 4 个隐藏节点专用于每个输入,那么您将失去一些网络识别输入和输出之间关系的能力。

  2. 你将如何提出价值来训练网络?您的网络会在棋盘位置和最佳下一步移动之间创建映射,因此您需要一组提供此信息的训练示例。游戏结束的动作很容易识别,但你如何判断游戏中期的动作是“最佳”的呢?(强化学习可以在这里提供帮助)

最后一个建议是使用双极输入(-1 表示错误,+1 表示正确),因为这可以加快学习速度。Nate Kohl 提出了一个很好的观点:每个隐藏和输出节点都将受益于偏置连接(将其视为另一个具有固定值“1”的输入节点)。

于 2011-01-02T19:20:38.430 回答
1

您的设计将高度依赖于您计划使用的特定类型的强化学习。

最简单的解决方案是使用反向传播。这是通过将误差反馈回网络(以相反的方式)并使用(sigmoid)函数的逆来确定对每个权重的调整来完成的。经过多次迭代后,权重将自动调整以适应输入。

遗传算法是反向传播的替代方法,它产生更好的结果(虽然有点慢)。这是通过将权重视为可以轻松插入和删除的模式来完成的。模式多次被变异版本(使用自然选择原则)替换,直到找到合适的版本。

正如你所看到的,每一个的实现都会有很大的不同。您可以尝试使网络足够通用以适应每种类型的实现,但这可能会使它过于复杂。一旦投入生产,您通常只会接受一种形式的培训(或者理想情况下,您的网络已经经过培训)。

于 2011-01-08T23:39:42.677 回答