我正在尝试用C#实现拓扑增强的neuro-evolution(神经进化)。我遇到了一个关于循环连接的问题。我明白,对于循环连接,输出基本上是时间上被延迟的。
https://i.sstatic.net/bI4Pc.png
在链接的图片中,我展示了一个非常简单的神经网络,具有2个输入,3个隐藏节点和一个输出。如果没有激活函数或传输函数,我认为它会被评估为:
n3[t] = (i1[t]*a + n6[t-1]*e)*d + i2[t]*b*c) * f
然而,我很难弄清楚如何识别连接e是一个循环连接。我读到的关于NEAT的论文展示了XOR问题和双极无速度问题的 Minimal 解决方案都具有循环连接。
如果您有一个固定的拓扑结构,这似乎相当简单,因为您可以自己分析拓扑结构,并识别出哪些连接需要时间延迟。
您究竟如何识别这些连接呢?
回答:
当我开始实施这篇论文时,我也遇到了类似的问题。我不知道你现在的网络是什么样的,所以我会向你解释我是怎么做的。
我的网络开始时只有输入和输出层。为了创建连接和神经元,我实现了一种DNA(在我这里,这是一个指令数组,例如’将神经元编号2与神经元编号5连接,并将权重设置为0.4’)。我网络中的每个神经元都有一个“层号”,它告诉我神经元在我网络中的位置。对于输入神经元,我使用了Double.minvalue,对于输出神经元,我使用了Double.maxvalue。
这是基本设置。从现在开始,在修改网络时只需遵循这些规则:
-
每当你想创建一个连接时,请确保“from”神经元的层号 < Double.maxValue
-
每当你想创建一个连接时,请确保“to”神经元的层号大于“from”神经元的层号。
-
每当一个连接被分成两个连接和它们之间的一个神经元时,将神经元的层号设置为NeuronFrom.layerNumber*0.5 + NeuronTo.layerNumber*0.5这很重要,你不能将它们相加然后简单地除以2,因为这可能会导致Double.maxValue + 某物,返回一些奇怪的数字(我猜会发生溢出,所以你会得到一个负数?)。
如果你遵循所有规则,你应该始终只有前向连接,没有循环连接。如果你想要循环连接,你可以通过在创建新连接时交换“from”和“to”来创建它们。
专业技巧:只使用一个Neurons的ArrayList。让DNA使用神经元的ID来查找它们,但创建一个’Connection’类,其中包含Neuron对象作为属性。在过滤你的连接/神经元时使用ArrayList.stream().filter()
在后续通过网络传播时,你可以按层号对神经元进行排序,设置输入值,然后使用for()循环遍历所有神经元。只需计算神经元的输出值,并将其传输到每个连接的“from”等于当前神经元的神经元。
希望这不太复杂…