【问题标题】:Algorithm to remove orphan neurons from a neural network从神经网络中删除孤儿神经元的算法
【发布时间】:2016-02-29 22:26:38
【问题描述】:

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

我有一个网络连接列表,称为“基因”。神经元 1 和神经元 2 之间的连接是gene.from = neuron1,gene.to = neuron2。

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

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

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

然后,我们根据基因的“to”连接指数对基因进行排序。

最后,我们根据基因创建隐藏层神经元......由于神经网络是一个映射,我们只需检查连接的 to 或 from 是否已经是一个神经元,否则创建一个新的。该算法可以很好地创建网络。

 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。

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

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

B.生成朴素的网络......然后,在网络中向后爬行,从每个输出开始,直到我们不能再进一步(注意重复循环)。散列我们找到的每个节点。一旦我们的图搜索完成,将我们找到的节点散列与我们基因列表中表达的总节点进行比较。仅在找到的节点的哈希中使用带有神经元的基因并重新构建网络。

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

谢谢!

【问题讨论】:

  • 我建议您使用 Wharshall 算法来创建传递闭包。

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


【解决方案1】:

我在上面使用了我的 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 算法中花费的大部分时间都花在了模拟本身上。也就是说,与针对一项艰巨的任务测试网络相比,生成正确的网络是微不足道的。

【讨论】:

    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 2016-09-02
      • 2017-09-11
      • 1970-01-01
      • 1970-01-01
      • 2016-12-23
      • 1970-01-01
      • 1970-01-01
      • 2016-09-08
      • 1970-01-01
      相关资源
      最近更新 更多