NEAT 中的前馈算法(增强拓扑的神经进化)

Feedforward Algorithm in NEAT (Neural Evolution of Augmenting Topologies)

我不明白 NEAT 算法如何根据连接基因获取输入然后输出数字,我熟悉在固定拓扑神经网络中使用矩阵来前馈输入,但是由于 NEAT 中的每个节点都有自己的连接数并且不一定连接到每个其他节点,我不明白,经过大量搜索后我找不到关于 NEAT 如何根据输入生成输出的答案。

有人可以解释一下它是如何工作的吗?

这也是我在实现自己的算法版本时遇到的一个问题。

您可以在 NEAT 用户页面中找到答案:https://www.cs.ucf.edu/~kstanley/neat.html 作者说:

How are networks with arbitrary topologies activated?

The activation function, bool Network::activate(), gives the specifics. The implementation is of course considerably different than for a simple layered feedforward network. Each node adds up the activation from all incoming nodes from the previous timestep. (The function also handles a special "time delayed" connection, but that is not used by the current version of NEAT in any experiments that we have published.) Another way to understand it is to realize that activation does not travel all the way from the input layer to the output layer in a single timestep. In a single timestep, activation only travels from one neuron to the next. So it takes several timesteps for activation to get from the inputs to the outputs. If you think about it, this is the way it works in a real brain, where it takes time for a signal hitting your eyes to get to the cortex because it travels over several neural connections.

因此,如果其中一个进化网络不是前馈网络,则网络的输出将在不同的时间步长发生变化,这在环境不是静态的连续控制问题中特别有用,但在分类问题中也有问题.作者也回答:

How do I ensure that a network stabilizes before taking its output(s) for a classification problem?

The cheap and dirty way to do this is just to activate n times in a row where n>1, and hope there are not too many loops or long pathways of hidden nodes.

The proper (and quite nice) way to do it is to check every hidden node and output node from one timestep to the next, and see if nothing has changed, or at least not changed within some delta. Once this criterion is met, the output must be stable.

Note that output may not always stabilize in some cases. Also, for continuous control problems, do not check for stabilization as the network never "settles" but rather continuously reacts to a changing environment. Generally, stabilization is used in classification problems, or in board games.

当我处理这个问题时,我研究了使用矩阵方法等的环路检测。 https://en.wikipedia.org/wiki/Adjacency_matrix#Matrix_powers

但我发现前馈输入和获取输出的最佳方法是在每个节点使用超时传播延迟进行循环检测:

前馈实现很简单,我从那里开始:

等到节点的所有传入连接都有信号,然后 sum-squash 激活并发送到该节点的所有输出连接。从已经具有来自输入向量的信号的输入节点开始。一旦没有更多的节点需要处理以获得输出向量,手动 'shunt' 输出节点并进行 sum-squash 操作。

为了循环(传统的 NEAT 实现)我做了与前馈相同的事情,但多了一项功能:

计算网络的“最大可能循环大小”。一个简单的计算方法是 ~2*(节点总数)。在没有循环的情况下,从输入到网络中任何节点的步行都不会比这个大,因此节点必须以这么多的时间步长传播,除非它是循环的一部分。 然后我等到所有输入连接信号都到达节点或发生超时(信号未在最大循环大小步长内到达连接)。如果发生超时,则将没有信号的输入连接标记为循环。 一旦连接被标记为经常性,重新启动所有节点上的所有计时器(以防止检测到的周期后期的节点由于传播延迟而被标记为经常性)

现在前向传播与前馈网络相同,除了:不等待循环连接,所有非循环连接一到达就进行 sum-squash(0 表示循环连接没有一个信号)。这确保了循环中到达的第一个节点被设置为循环,使其对于任何给定的拓扑都是确定的,并且循环连接将数据传递到下一个传播时间步长。

这有一些第一次的开销,但很简洁,并且每次 运行 都会使用给定的拓扑产生相同的结果。请注意,这仅在所有节点都有输出路径时才有效,因此您不能在不考虑的情况下禁用拆分连接(由节点添加操作建立的连接)并在进化过程中修剪 运行domly。

(P.S。这也创建了一个传统的残差循环网络,理论上可以将其实现为 矩阵运算 。如果我有大型网络,我首先会'express' 通过 运行 前向传播一次以获得循环连接,然后使用循环、权重和信号连接属性为矩阵乘法运算创建 'tensor per layer' 表示,循环连接属性作为稀疏二进制掩码. 我实际上开始编写一个 Tensorflow 实现,它执行所有 mutation/augmentation 操作和 tf.sparse_matrix 操作并且没有使用任何树对象但是我不得不使用密集操作和 n^2 space 消耗对我的需要来说太多了,但这允许使用前面提到的邻接矩阵幂技巧,因为它是矩阵形式!Github 上至少有一个人完成了 tf NEAT,但我不确定他们的实现。我也发现这个很有趣 https://neat-python.readthedocs.io/en/latest/neat_overview.html)

祝黑客愉快!