Synaptic / Neataptic简单的NEAT XOR解决方案

时间:2017-10-07 19:40:36

标签: javascript node.js machine-learning neural-network

编辑:我成功地聚集了几个简单的例子https://github.com/developer239/neural-network-playground

有没有人能帮我简单巧妙地教网如何解决XOR或其他类似的问题?但是使用NEAT技术以便我不必指定训练数据集?

使用javascript:https://github.com/cazala/synaptichttps://github.com/wagenaartje/neataptic

1. Initialize network 2. Generate generation 3. Go through each genome in generation and evaluate its fitness (how good it is) 4. Take 2 best genomes from generation 5. Merge genomes 50 / 50 at random 6. Mutate final genome 7. Generate second generation

这将非常有帮助。这里使用了相同的teqnique:

https://github.com/ivanseidel/IAMDinosaur

https://www.youtube.com/watch?v=P7XHzqZjXQs

我查看了源代码,但是有很多东西要继续。我理解一般的想法。但是我不知道如何实施解决方案。

谢谢:)

3 个答案:

答案 0 :(得分:1)

有一个关于Neataptic' README.md的例子。

// this network learns the XOR gate (through neuro-evolution)
var network = new Network(2,1);

var trainingSet = [
  { input: [0,0], output: [0] },
  { input: [0,1], output: [1] },
  { input: [1,0], output: [1] },
  { input: [1,1], output: [0] }
];

await network.evolve(trainingSet, {
  equal: true,
  error: 0.03
 });

Neataptic将其全部内置,因此您只需提供一个数据集即可。如果您需要有关如何设置的详细信息,请read this article

对于动态解决方案的问题,必须实现自定义循环和适应度函数。

答案 1 :(得分:1)

我知道这是一个很老的问题,并且消炎药的使用并不广泛,但是我发现了一种更简单的实施方法,因此我想与大家分享

const { Neat } = require('neataptic');

function fitness(network) {
    let score = 0;

    score += Math.abs(0 - network.activate([0,0])[0]);
    score += Math.abs(1 - network.activate([0,1])[0]);
    score += Math.abs(1 - network.activate([1,0])[0]);
    score += Math.abs(0 - network.activate([1,1])[0]);
    score = -score;

    return score;
}

(async () => {
    const neat = new Neat(2 ,1 ,fitness, {});
    for (let i = 0; i < 10000; i++) {
        await neat.evolve();
    }
    const fittest = neat.getFittest();

    console.log(fitness(fittest));
    console.log(fittest.activate([0,0]));
    console.log(fittest.activate([0,1]));
    console.log(fittest.activate([1,0]));
    console.log(fittest.activate([1,1]));
})();

答案 2 :(得分:0)

我设法编写了自己的解决方案。您可以在此处找到它:https://github.com/developer239/neural-network-playground/tree/master/neatXOR

与文档中的解决方案的主要区别在于,genetic.js您可以动态地更改学习过程。

这是输入文件:

const genetic = require('./genetic')


genetic.generateRandomPopulation()

for (let iteration = 0; iteration < 1000; iteration += 1) {
  genetic.live()
  genetic.evolve()
}

const genom = genetic.neat.population[0]

console.log(`
  Result for genom with index 0 in the newest population. Note that selection / mutation happened
  after we called last evolve function so this is not necessarily the best genome in the population.

  [0, 0] = ${genom.activate([0, 0])} (should be 0) 
  [1, 1] = ${genom.activate([1, 1])} (should be 0) 
  [0, 1] = ${genom.activate([0, 1])} (should be 1) 
  [1, 0] = ${genom.activate([1, 0])} (should be 1) 
`)

这是genetic.js档案:

const { Neat, architect } = require('neataptic')


module.exports = {
  neat: null, // https://wagenaartje.github.io/neataptic/docs/neat/
  possibleInputs: [
    [0, 0], // expected output 0
    [1, 1], // expected output 0
    [0, 1], // expected output 1
    [1, 0], // expected output 1
  ],
  generateRandomPopulation: function () {
    this.neat = new Neat(
      2, // number of inputs
      1, // number of outputs
      null, // fitnessFunction - in this example we are calculating fitness inside live method
      {
        elitism: 5, // this sets how many genomes in population will be passed into next generation without mutation https://www.researchgate.net/post/What_is_meant_by_the_term_Elitism_in_the_Genetic_Algorithm
        mutationRate: 0.3, // sets the mutation rate. If set to 0.3, 30% of the new population will be mutated. Default is 0.3
        network: // https://wagenaartje.github.io/neataptic/docs/architecture/network/
          new architect.Random(
            2,
            3,
            1,
          ),
      },
    )
  },
  // the closer the output gets to expectedOutput the better
  // note that optimal fitness in this example is 0 neural network seems to work fine though
  calculateFitness: function (expectedOutput, output) {
    let closeCount = Math.abs(expectedOutput - output)
    let fitness = closeCount * -1
    return fitness
  },
  live: function () {
    // increment generation index
    this.neat.generation += 1

    // loop through each genome
    for (let genomeIndex in this.neat.population) {
      const possibleInputs = this.possibleInputs
      const genome = this.neat.population[genomeIndex]
      genome.score = 0

      // loop through each input
      for (let i = 0; i < possibleInputs.length; i += 1) {
        let input = possibleInputs[i]
        // test each input
        let output = genome.activate(input)[0]

        // calculate fitness for each output
        // we have 4 different inputs so the total score is sum of 4 different fitness values
        if (i <= 1) {
          genome.score += this.calculateFitness(0, output)
        } else {
          genome.score += this.calculateFitness(1, output)
        }
      }
    }
  },
  evolve: function () {
    const neat = this.neat
    console.log(`[generation ${neat.generation}] Average score: ${neat.getAverage()} (the closer to zero the better)`)

    // sort by genome.score in descending order
    neat.sort()

    // our new population will be here
    let newPopulation = []

    // we want to push neat.elitism number of best genomes into the new population automatically
    for (let i = 0; i < neat.elitism; i++) {
      newPopulation.push(neat.population[i])
    }

    // we want to get offspring from the current population and push it into the new population
    for (let i = 0; i < neat.popsize - neat.elitism; i++) {
      newPopulation.push(neat.getOffspring())
    }

    // set new population
    neat.population = newPopulation
    // mutate the population
    neat.mutate()
  },
}