我最近阅读了有关NeuroEvolution的原始paper 由Kenneth O. Stanley撰写的扩充拓扑结构,我现在正在尝试使用JavaScript自行编写原型。我偶然发现了一些我无法回答的问题。
"结构创新"的定义是什么?我如何存储这些以便我可以检查以前是否已经发生过创新?
然而, 通过保留当前一代中发生的创新列表,它 可以确保当相同结构通过独立出现不止一次时 在同一代中突变,每个相同的突变被分配 相同的创新数字
是否有理由存储节点类型(输入,隐藏,输出)?
在原始论文中,只有连接具有创新编号,但在other sources中,节点也可以。交叉是否必要? (已经问过here.)
如何限制突变功能不添加循环连接?
我认为现在就是这样。感谢所有帮助。
class Genome {
constructor(inputs, outputs) {
this.inputs = inputs;
this.outputs = outputs;
this.nodes = [];
this.connections = [];
for (let i = 0; i < inputs + outputs; i++) {
this.nodes.push(new Node());
}
for (let i = 0; i < inputs; i++) {
for (let o = 0; o < outputs; o++) {
let c = new Connection(this.nodes[i], this.nodes[inputs + o], outputs * i + o);
this.connections.push(c);
}
}
innovation = inputs * outputs;
}
weightMutatePerturb() {
let w = this.connections[Math.floor(random(this.connections.length))].weight;
w += random(-0.5, 0.5);
}
weightMutateCreate() {
this.connections[Math.floor(random(this.connections.length))].weight = random(-2, 2);
}
connectionMutate() {
let i = this.nodes[Math.floor(random(this.nodes.length))];
let o = this.nodes[Math.floor(random(this.inputs, this.nodes.length))];
let c = Connection.exists(this.connections, i, o);
if (c) {
c.enabled = true;
} else {
this.connections.push(new Connection(i, o, innovation));
innovation++;
}
}
nodeMutate() {
let oldCon = this.connections[Math.floor(Math.random(this.connections.length))];
oldCon.enabled = false;
let newNode = new Node();
this.nodes.push(newNode);
this.connections.push(new Connection(oldCon.input, newNode, innovation, 1));
innovation++;
this.connections.push(new Connection(newNode, oldCon.output, innovation, oldCon.weight));
innovation++;
}
}
class Node {
constructor() {
this.value = 0;
this.previousValue = 0;
}
}
class Connection {
constructor(input, output, innov, weight) {
this.input = input;
this.output = output;
this.innov = innov;
this.weight = weight ? weight : random(-2, 2);
this.enabled = true;
}
static exists(connections, i, o) {
for (let c = 0; c < connections.length; c++) {
if (connections[c].input === i && connections[c].output === o) {
return connections[c];
}
}
return false;
}
}
所有答案都欢迎来源。 (你是一个很棒的人!)
答案 0 :(得分:1)
首先,我非常强烈建议不要自己实施NEAT。如果你看一下(很多)可用的实现,这是一个相当大的项目!
如果您有更多疑问,我建议您查看Colin Green的this implementation作为参考。如果他不是那些更了解NEAT实施的人,他就会接近。
答案 1 :(得分:0)
这不是普通的JS问题!感谢这些链接,这是一篇非常有趣的论文。我不能自称是专家,我只做过玩具GA问题,但我确实读过这篇论文及相关论文。以下是我的理解:
我认为你需要担心的是,父母是否通过突变,在一代人中不止一次产生相同的新基因。也就是说,两个孩子,其最新创新号的基因是相同的。你可以马上剔除它们。我认为他们说同一基因有可能同时出现在两个物种中,他们基本上说这很好,这种情况很少见,不用担心。
我至少可以找到一个原因:“在NEAT中,偏差是一个可以连接到除输入之外的任何节点的节点。”
一些作用于这种DNA的突变让人想起NEAT。但是,不是单个节点,一个突变可以插入整个层 - 即。一次有几十到几百个节点。我们还允许删除这些层,以便演化过程可以简化架构以及复杂化。
根据您对问题4动机的评论,我认为您错了。在原始论文的XOR示例中,图5显示了一个不涉及隐藏层的起始表型。这种起始表型不是XOR问题的解决方案,但它提供了一个很好的起点:“NEAT在寻找解决方案时非常一致。在100次模拟中它没有失败一次。”这对于复发没有任何惩罚。