从神经网络中移除孤儿神经元的算法

时间:2016-02-29 22:26:38

标签: algorithm neural-network evolutionary-algorithm recurrent-neural-network

我正在尝试实施NEAT(增强拓扑的神经演化)。

我有一个网络连接列表,称为“基因”。 neuron1和neuron2之间的联系将是gene.from = neuron1,gene.to = neuron2。

我的任务是从这些基因生成神经网络(神经网络只是从索引到神经元的映射,gene.from和gene.to是映射中神经元的关键)。

我有numPossibleInputs个输入节点,所以我们先添加它们(0-numPossibleInputs-1是输入神经元)。

我有numOutputs个输出节点,所以我们也添加了这些节点。

然后,我们根据他们的“到”连接索引对基因进行排序。

最后,我们基于基因创建隐藏层神经元......由于神经网络是一个地图,我们只是检查连接的来源是否已经是神经元,否则创建一个新神经元。这种算法可以很好地创建网络。

 public void generateNetwork()
{
    neuralNetwork.clear();

    for(int i = 0; i < numPossibleInputs; i++)
    {
        neuralNetwork.put(i, new Neuron());
    }

    for(int i = 0; i < numOutputs; i++)
    {
        neuralNetwork.put(i+numPossibleInputs+numPossibleHidden, new Neuron());
    }

    genes.sort((ConnectionGene g1, ConnectionGene g2)-> Integer.compare(g1.toNeuronIndex, g2.toNeuronIndex));

    for(ConnectionGene gene : getCleanGenes(genes))
    {
        if(gene.enabled)
        {
            if(!neuralNetwork.containsKey(gene.toNeuronIndex))
            {
                neuralNetwork.put(gene.toNeuronIndex, new Neuron());
            }
            neuralNetwork.get(gene.toNeuronIndex).incomingConnections.add(gene); // Add this gene to the incoming of the above neuron

            if(!neuralNetwork.containsKey(gene.fromNeuronIndex))
            {
                neuralNetwork.put(gene.fromNeuronIndex, new Neuron());
            }
        }
    }

}

问题出现在进化算法关闭某些基因时(注意gene.enabled)。例如,考虑以下基因(还有其他基因,但它们被禁用):

2→4

4-→4

13-→4

0→13

1→13

5→13

我们还有残基基因,2-> 5和4-> 13。这些不能在网络中使用,因为它们没有被表达。 (这就是为什么我必须每代都生成一个新网络,可以添加,启用,禁用基因等)。

这是numPossibleInputs ==3,因此0 1和2是输入(2是偏差)。图5是从5开始的隐藏层节点。 3,但小于10 + 3 = 13. 13是输出节点,我有numPossibleHidden == 10所以10 + 3 = 13 ......只有一个输出。 可以这样画: [输入输入隐藏* 10输出* 1]用于3个输入,10个隐藏和1个输出

这是天真生成的网络图片: Simple Network

正如我们所看到的,简化网络不应该有4或5,因为它们对任何输出都没有影响(在这种情况下只有一个输出,13)。减少的神经网络将仅为0-> 13且1-> 13。

我对如何解决这个问题有一些初步想法:

一个。  1.遍历每个连接并散列gene.from ids。这些是神经元id,是其他东西的输入  2.填充哈希后,再次循环并删除任何带有gene.to不在哈希中的基因(如果不在哈希中,则gene.to不是其他任何内容的输入)。  3.重复,直到我们不删除任何东西

B中。生成天真的网络...然后,从网络中向后爬行,从每个输出直到我们不能再继续(注意重复循环)。哈希我们找到的每个节点。完成图搜索后,将找到的节点哈希值与基因列表中表示的总节点进行比较。只在发现的节点的散列中使用带有神经元的基因并重新制作网络。

我希望根据我的网络表示得到一些关于可能是最好的算法的反馈 - 我认为我的B比A更好,但我希望有一个更优雅的解决方案没有'我涉及解析图形拓扑。也许通过对连接进行排序(By to,by from)可以做些聪明的事情?

谢谢!

2 个答案:

答案 0 :(得分:0)

我使用上面的B解决方案,使用各种不同的网络类型对其进行测试,并且工作正常 - 也就是说,网络将摆脱从输入到输出没有正确路径的所有节点。我会在这里发布代码,以防有人想要使用它:

   private List<ConnectionGene> cleanGenes(Map<Integer,Neuron> network)
{
    // For each output, go backwards
    Set<Integer> visited = new HashSet();
    for(int i = 0; i < numOutputs; i++)
    {
        visited.add(i+numPossibleInputs+numPossibleHidden);
        cleanGenes(i+numPossibleInputs+numPossibleHidden, network, visited);
    }

    List<ConnectionGene> slimGenes = new ArrayList();
    for(ConnectionGene gene : genes)
    {
        // Only keep gene if from/to are nodes we visited
        if(visited.contains(gene.fromNeuronIndex) && visited.contains(gene.toNeuronIndex))
        {
            slimGenes.add(gene);
        }
    }
    return slimGenes;
}

private boolean cleanGenes(int neuronIndex, Map<Integer, Neuron> network, Set<Integer> visited)
{
    int numGoodConnections = 0;
    for(ConnectionGene gene : network.get(neuronIndex).incomingConnections)
    {
        numGoodConnections++;
        if(gene.enabled && !visited.contains(gene.fromNeuronIndex))
        {
            visited.add(gene.fromNeuronIndex);
            if(!cleanGenes(gene.fromNeuronIndex, network, visited))
            {
                numGoodConnections--;
                visited.remove(gene.fromNeuronIndex); // We don't want this node in visited, it has no incoming connections and isn't an input.
            }
        }
    }

    if(numGoodConnections == 0)
    {
        return neuronIndex < numPossibleInputs; // True if an input neuron, false if no incoming connections and not input
    }
    return true; // Success
}

根据我的分析器,这个NEAT算法花费的绝大部分时间都在模拟本身。也就是说,与针对艰巨任务测试网络相比,生成适当的网络是微不足道的。

答案 1 :(得分:0)

有一种更有效的方法来添加神经元。您可以采用随机连接,将其分成两个连接并在它们之间添加神经元,而不是仅仅添加一个新神经元并希望它有一天连接。