1

NEAT (増強トポロジーの神経進化) を実装しようとしています。

「遺伝子」と呼ばれるネットワーク接続のリストがあります。ニューロン 1 とニューロン 2 の間の接続は、gene.from = ニューロン 1、gene.to = ニューロン 2 になります。

私の仕事は、これらの遺伝子からニューラル ネットワークを生成することです (ニューラル ネットワークは単にインデックスからニューロンへのマップであり、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 > 3 であるため、5 は非表示層ノードですが、10 + 3 = 13 未満です。13 は出力ノードですnumPossibleHidden == 10。10 + 3 = 13 でした。次のようにイメージできます: [input input input hidden*10 output*1] 3 つの入力、10 の非表示、および 1 つの出力の場合

これは単純に生成されたネットワークの写真です: Simple Network

ご覧のように、削減されたネットワークには 4 または 5 はまったくないはずです。これらはどの出力にも影響を与えないためです (この場合は 1 つの出力、13 のみ)。削減されたニューラル ネットワークは、0->13 および 1->13 になります。

私はこれを解決する方法についていくつかの最初の考えを持っていました:

A. 1. 各接続をループし、gene.from ID をハッシュします。これらは、何か他のものへの入力であるニューロン ID です。ハッシュ)。3. 何も削除されなくなるまで繰り返します

B. 単純なネットワークを生成します...次に、各出力からネットワーク内を逆方向にクロールし、それ以上進むことができなくなります (繰り返しのサイクルに注意してください)。見つけた各ノードをハッシュします。グラフ検索が完了したら、見つかったノードのハッシュを、遺伝子リストで表されたノードの合計と比較します。見つかったノードのハッシュでニューロンを持つ遺伝子のみを使用し、ネットワークを作り直します。

ネットワーク表現に基づいて、これを行うための最良のアルゴリズムについてフィードバックを得たいと思っていました-BはAよりも優れていると思いますが、私が関与しないよりエレガントなソリューションがあることを望んでいましたグラフ トポロジを解析しています。おそらく、接続をソートすることで何か賢いことができるでしょうか(by to、from)?

ありがとう!

4

2 に答える 2

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 アルゴリズムに費やされる時間の大部分は、シミュレーション自体にあります。つまり、適切なネットワークを生成することは、困難なタスクに対してネットワークをテストすることに比べれば簡単です。

于 2016-03-01T01:11:10.653 に答える