如何识别任意神经网络中的循环连接

How to Identify Recurrent Connections in an Arbitrary Neural Network

我正在尝试在 C# 中实现增强拓扑的神经进化。我 运行 遇到了循环连接的问题。据我所知,对于循环连接,输出基本上是暂时移位的。

http://i.imgur.com/FQYjCLZ.png

在 linked 图像中,我展示了一个非常简单的神经网络,具有 2 个输入、3 个隐藏节点1 个输出。如果没有激活函数或传递函数,我认为它会被评估为:

n3[t] = (i1[t]*a + n6[t-1]*e)*d + i2[t]*b*c) * f

但是我很难弄清楚如何识别 link e 是一个循环连接这一事实。我读到的关于 NEAT 的论文展示了 XOR 问题和双极点无速度问题的最小解如何都具有循环连接。

如果你有一个固定的拓扑,这似乎很简单,因为你可以自己分析拓扑,并确定哪些连接需要延时。

您将如何准确识别这些联系?

当我开始实施这篇论文时,我遇到了类似的问题。我不知道你们现在的网络是什么样的,所以我会向你解释我做了什么。

我的网络一开始只是输入和输出层。为了创建连接和神经元,我实现了某种 DNA(在我的例子中,这是一组指令,如 'connect neuron nr. 2 with neuron nr. 5 and set the weight to 0.4')。我网络中的每个神经元都有一个 "layerNumber",它告诉我神经元在我的网络中的位置。这个 layerNumber 是为每个输入和输出神经元设置的。对于输入神经元,我使用了 Double.minvalue,对于输出神经元,我使用了 Double.maxvalue.

这是基本设置。从现在开始,修改网络时只需遵循以下规则:

  • 每当你想创建连接时,确保 'from' 神经元的 layerNumber < Double.maxValue

  • 每当你想创建连接时,请确保 'to' 神经元的层数大于 'from' 神经元。

  • 每当一个连接被分成 2 个连接和它们之间的一个神经元时,将神经元 layerNumber 设置为 NeuronFrom.layerNumber*0.5 + NeuronTo.layerNumber*0.5 这很重要,你 不能 将它们相加并简单地除以 2,因为这可能会导致 Double.maxValue + 一些东西,这会 return 一些奇怪的数字(我猜会发生溢出,所以你会得到一个负数?)。

如果您遵守所有规则,您应该始终只有转发连接。没有复发的。如果你想要经常性连接,你可以通过在创建新连接时交换 'from' & 'to' 来创建它们。

专业技巧: 仅使用一个神经元 ArrayList。 让 DNA 使用神经元的 ID 来找到它们,但创建一个 'Connection' class ,它将 Neuron 对象作为属性。 过滤 connections/neurons 时使用 ArrayList.stream().filter()

稍后通过网络传播时,您只需按层数对神经元进行排序,设置输入值并使用 for() 循环遍历所有神经元。只需计算神经元输出值并将其传输到每个具有连接的神经元,其中 'from' == 当前神经元。

希望不要太复杂...

好吧,我不是告诉你不要经常性联系,而是要告诉你如何识别它们。

您需要知道的第一件事是,在所有其他连接个神经元之后计算循环连接。那么哪个连接是循环的,哪个不是循环的取决于你的神经网络的计算顺序。 另外,第一次将数据放入系统时,我们假设每个连接都是零,否则无法计算部分或全部神经元。

假设我们有这个神经网络: Neural Network

我们将这个网络分为 3 层(即使在概念上它有 4 层):

Input Layer  [1, 2]
Hidden Layer [5, 6, 7]
Output Layer [3, 4]

第一条规则:输出层的所有输出都是循环连接

第二条规则:可以先计算输入层的所有输出

我们创建两个数组。一个包含所有神经元 连接的计算顺序,一个包含所有(潜在的)循环连接。 现在这些数组看起来有点像这样:

Order of 
calculation: [1->5, 2->7 ]

Recurrent:   [ ]

现在我们从查看输出层开始。我们可以计算神经元 3 吗?不?因为6不见了。我们可以计算6吗?不?因为少了5个。等等。它看起来有点像这样:

3, 6, 5, 7

问题是我们现在陷入了一个循环。所以我们引入一个临时数组来存储我们已经访问过的所有神经元 ID:

[3, 6, 5, 7]

现在我们问:我们能算出7吗?不,因为缺少 6。但是我们已经访问了 6...

[3, 6, 5, 7,] <- 6

第三条规则是:当你访问一个之前已经访问过的神经元时,将你跟随的连接设置为这个神经元的循环连接。 现在你的数组看起来像这样:

Order of 
calculation: [1->5, 2->7 ]

Recurrent:   [6->7 ]

现在你完成了这个过程,最后将计算数组的顺序与你的循环数组连接起来,这样循环数组就在另一个数组之后。 它看起来像这样:

[1->5, 2->7, 7, 7->4, 7->5, 5, 5->6, 6, 6->3, 3, 4, 6->7]

假设我们有 [x->y, y]

其中x->y是x*weight(x->y)的计算

其中 y 是 Sum(对 y 的输入)的计算。所以在这种情况下 Sum(x->y) 或只是 x->y.

这里还有一些问题需要解决。例如:如果神经元的唯一输入是循环连接怎么办?但我想你将能够自己解决这个问题...