编程语言
首页 > 编程语言> > Javascript-为什么这个神经网络不渲染(仅)完整的3层路径?

Javascript-为什么这个神经网络不渲染(仅)完整的3层路径?

作者:互联网

所讨论的功能是基于相当简单的数据结构来渲染表示在该图像右侧的神经网络.

努力发展:

enter image description here

演变之后:

enter image description here

每个点代表一个神经元,每条线代表一个连接.存在一个神经元和连接被渲染而没有被渲染的问题,我一直在努力解决这个问题达5个小时,没有休息时间.你们中的一位很可能会指出一个导致问题的愚蠢错误,我很可能会继续努力.

简而言之:连接从上到下运行.我只想渲染从上到下的完整路径.如果没有连接从顶部引出,则不应在中间绘制任何点(神经元).如果顶层神经元连接到中间层神经元,但该中间层神经元未连接到底层神经元,则该连接没有做任何事情,因此不应渲染.

如您所见,有些顶级神经元根本没有连接,而中级神经元根本没有连接.所有连接都是自上而下的,没有连接向上流动.换句话说,网络是前馈的.

传递给该函数的数据结构是大脑,这是传递给以下Neuron和Connection构造函数的大脑,该大脑以删节形式列出,仅显示与所讨论函数相关的属性(从原始文档中编辑,并进一步尝试解决问题. :

神经元

function Neuron(brain, layer) {
    var that = this;
    brain.counter++;
    brain.globalReferenceNeurons[brain.counter] = this;
    this.active = true; //as the brain mutates, some neurons and 
    //connections are disabled via this property
    this.layer = layer;
    this.id = brain.counter;
    this.connected = {};
    this.connections = {};
    this.connect = function(target) {
        if (that.active == true) {
            new Connection(brain, this, target, function(id, connection) {
                brain.globalReferenceConnections[id] = connection;
                that.connections[id] = connection;
            });
        }
    };
}

连接

function Connection(brain, source, target, callback) {
    if (source.layer < target.layer) {
        brain.counter++;
        brain.globalReferenceConnections[brain.counter] = this;
        this.active = true; //as the brain mutates, some neurons and 
        //connections are disabled via this property
        this.id = brain.counter;
        this.source = source;
        this.target = target;
        target.connected[this.id] = this; //connected references 
        //incoming connections to a neuron
        callback(this.id, this);
    }
}

如您所见,brain.globalReferenceNeurons包含在图片中呈现神经网络所需的数据.

这是有问题的渲染功能(再次更新):

function renderBrain(brain, context, canvas) {
  context.clearRect(0, 0, canvas.width, canvas.height);
  var width = canvas.width;
  var height = canvas.height;
  var layers = brain.layers;
  var heightDivision = height / layers;
  var layerList = [];
  for (var i1 = 0; i1 < brain.layers; i1++) {
    layerList.push([]);
    for (var prop1 in brain.globalReferenceNeurons) {
      if (brain.globalReferenceNeurons[prop1].layer === i1) {
        layerList[i1].push(brain.globalReferenceNeurons[prop1]);
      }
    }
  }

  function renderLayer(layer, layerCount, layerTotal) {
    var length = layer.length;
    var widthDivision = width / length;
    var neuronCount = 0;
    for (var i1 = 0; i1 < layer.length; i1++) {
      neuronCount++;
      const getActiveProps = obj => Object.keys(obj).filter(k => obj[k].active)

      function hasActivePathAhead(obj, count) {
        if (!count) {
          count = 0;
        }
        if (obj.active) {
          var targets = getActiveProps(obj.connections);
          if (obj.layer === 2) {
            return true;
          } else if (obj.connections[targets[count]]) {
            for (var i1 = 0; i1 < targets.length; i1++) {
              var result = hasActivePathAhead(obj.connections[targets[count]].target, 
                  count + 1);
              return result;
            }
            return false;
          } else {
            return false;
          }
        } else {
          return false;
        }
      }

      function hasActivePathBehind(obj, count) {
        if (!count) {
          count = 0;
        }
        if (obj.active) {
          var sources = getActiveProps(obj.connected);
          if (obj.layer === 0) {
            return true;
          } else if (obj.connected[sources[count]]) {
            for (var i1 = 0; i1 < sources.length; i1++) {
              var result = 
                  hasActivePathBehind(obj.connected[sources[count]].source, count + 1);
              return result;
            }
            return false;
          } else {
            return false;
          }
        } else {
          return false;
        }
      }
      if (hasActivePathAhead(layer[i1]) && hasActivePathBehind(layer[i1])) {
        context.beginPath();
        context.arc((widthDivision * neuronCount) 
            - (0.5 * widthDivision), 
            (heightDivision * layerCount) 
            - (heightDivision * 0.5), 
            5, 0, 2 * Math.PI, false);
        context.fillStyle = '#adf442';
        context.fill();
        context.lineWidth = 2;
        context.strokeStyle = '#56cc41';
        context.stroke();
        var connectionCount = 0;
        for (var i2 = 0; i2 < Object.keys(layer[i1].connections).length; i2++) {
          var connection = 
              layer[i1].connections[Object.keys(layer[i1].connections)[i2]];
          if (hasActivePathAhead(connection.target) 
              && hasActivePathBehind(connection.target)) {
            var targetLayer = connection.target.layer;
            var index = layerList[targetLayer].findIndex(function(e) {
              return e == connection.target
            });
            if (index > -1) {
              var targetLayerLength = Object.keys(layerList[targetLayer]).length;
              var targetLayerWidthDivision = width / targetLayerLength;
              var p1 = {
                x: (widthDivision * neuronCount) - (0.5 * widthDivision),
                y: (heightDivision * layerCount) - (heightDivision * 0.5)
              };
              var p2 = {
                x: (index * targetLayerWidthDivision) 
                    + (0.5 * targetLayerWidthDivision),
                y: (targetLayer * heightDivision) 
                    + (heightDivision * 0.5)
              };
              connectionCount++;
              context.beginPath();
              context.moveTo(p1.x, p1.y);
              context.lineTo(p2.x, p2.y);
              context.lineWidth = 1;
              context.stroke();
            }
          }
        }
      }
    }
  }
  var layerCount = 0;
  for (i1 = 0; i1 < layerList.length; i1++) {
    layerCount++;
    renderLayer(layerList[i1], layerCount, layerList.length);
  }
}

“工作”测试示例:https://jsfiddle.net/au2Lt6na/4/

5个小时以来,我一直在尝试使用此功能来查找问题,而对于我自己的一生,我一直无法弄清楚.谁能告诉我是什么原因造成了非自上而下的神经通路的产生?

注意:在过去的几天中,我花了很多时间来解决此问题,写出了全新的方法来弄清哪些路径是从上到下完成的,并且仍然遇到与以前相同的问题.我在这里想念东西.

解决方法:

无法放入评论中,由于您没有可用的示例,我们只能猜测.

您的递归在我看来不正确. count变量没有意义,并且您具有多个级别的冗余检查,每次迭代进行3次活动检查,并且在使用count索引到键数组时不进行审核.

没有有效的代码,并且变量名称令人困惑,这只是如何修复的猜测.同样适用于hasActivePathBehind

忽略以下代码

 function hasActivePathAhead(obj) {
    if (obj.active) {
        if (obj.layer === 2) {
            return true;
        }
        var targets = getActiveProps(obj.connections);
        for (var i = 0; i < targets.length; i++) {
            if(hasActivePathAhead(obj.connections[targets[i]].target)){
                return true;
            }
        }
    }
    return false;
 }

更新和工作修复.

由于接受的答案不起作用,因此应进行更严格的测试以进行更新.

正如您在注释中提供的小提琴一样,我看上去您已从函数中删除了计数.尽管功能仍然不正确并且无法正常工作,但该错误在代码的其他位置.该代码过于复杂,隐藏了错误的本质.

有太多的错误要详细介绍,所以我才刚刚开始.

我没有测试每个节点的后向和前向链接,而是从上到下遍历各个层.这样就无需检查反向连接.我有一个检查节点是否连接到底部的函数,一个将所有节点从一个节点绘制到底部的函数,以及一个将所有活动节点绘制到一层的函数(活动从该层向下连接)

您可以通过向节点添加一个标志来优化它,该标志指示它们已经被渲染为代码,因此可以多次渲染某些节点.但是我没有添加,因为我不想修改您的数据结构.或者,您可以添加一个包含已渲染节点对的Map,并检查是否需要渲染节点对.

这里使用fiddle作为模板,这是使用小提琴中提供的随机路径的工作版本.

function Neuron(brain, layer) {
    var that = this;
    brain.counter++;
    brain.globalReferenceNeurons[brain.counter] = this;
    this.active = true; //as the brain mutates, some neurons and 
    //connections are disabled via this property
    this.layer = layer;
    this.id = brain.counter;
    this.connected = {};
    this.connections = {};
    this.connect = function (target) {
        if (that.active == true) {
            new Connection(brain, this, target, function (id, connection) {
                brain.globalReferenceConnections[id] = connection;
                that.connections[id] = connection;
            });
        }
    };
}

function Connection(brain, source, target, callback) {
    if (source.layer < target.layer) {
        brain.counter++;
        brain.globalReferenceConnections[brain.counter] = this;
        this.active = true; //as the brain mutates, some neurons and 
        //connections are disabled via this property
        this.id = brain.counter;
        this.source = source;
        this.target = target;
        target.connected[this.id] = this;
        callback(this.id, this);
    }
}


function renderBrain(brain, ctx, canvas) {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    var width = canvas.width;
    var height = canvas.height;
    var layers = brain.layers;
    var heightDiv = height / layers;
    var layerList = [];
    for (var i1 = 0; i1 < brain.layers; i1++) {
        layerList.push([]);
        for (var prop1 in brain.globalReferenceNeurons) {
            if (brain.globalReferenceNeurons[prop1].layer === i1) {
                layerList[i1].push(brain.globalReferenceNeurons[prop1]);
            }
        }
    }
    var coord;  // to hold node coordinates defined here to prevent pointless memory allocation dealocation cycle
    // Gets the node position based on its ID and layer position
    function nodePosition(node,coord = {}){
        var pos;
        pos = node.id - layerList[node.layer][0].id; // get pos from node id (if this does not hold true you should include the node position in the node data is it is important)
        coord.x = (width / layerList[node.layer].length) * (pos + 0.5);
        coord.y = heightDiv * (node.layer + 0.5);
        return coord;
    }        
    // draws a node
    function drawNode(node){
        ctx.strokeStyle = '#56cc41';
        ctx.fillStyle = '#adf442';
        ctx.lineWidth = 2;
        coord = nodePosition(node,coord);
        ctx.beginPath();
        ctx.arc(coord.x,coord.y, 5, 0, 2 * Math.PI);
        ctx.fill();
        ctx.stroke();
    }
    // draws a link between two nodes
    function drawLink(node,node1){
        ctx.strokeStyle = '#56cc41';
        ctx.lineWidth = 1;
        coord = nodePosition(node,coord);
        ctx.beginPath();
        ctx.moveTo(coord.x,coord.y);
        coord = nodePosition(node1,coord);
        ctx.lineTo(coord.x,coord.y);
        ctx.stroke();
    }
    // returns true if the path from this node jas a connection that leads to the end
    function isPathActive(node){
        var paths, i, nextNode;
        if(node.active){
            if(node.layer === 2){ // is node at end
                return true;
            }
            paths = Object.keys(node.connections).map(key => node.connections[key]);
            for(i = 0; i < paths.length; i ++){
                nextNode = paths[i].target;
                if(nextNode.active){
                    if(nextNode.layer === 2){
                        return true;
                    }
                    if(isPathActive(nextNode)){
                        return true;
                    }
                }
            }
        }
        return false;
    }
    // renders from a node all active pathes to end
    function renderPath(node){
        var i;
        paths = Object.keys(node.connections).map(key => node.connections[key]);
        for(i = 0; i < paths.length; i ++){
            nextNode = paths[i].target;
            if(isPathActive(nextNode)){
                drawLink(node,nextNode)
                renderPath(nextNode);
            }
        }
        drawNode(node,i+ 1)
    }
    // renders from top layer all active paths
    function renderActivePaths(layer){
        var i;
        for(i = 0; i < layer.length; i ++){
            if(isPathActive(layer[i])){
                renderPath(layer[i])
            }
        }
    }
    renderActivePaths(layerList[0]);
}





var brain = {
    counter: 0,
    layers: 3,
    globalReferenceNeurons: {},
    globalReferenceConnections: {},
}
var layer0 = [new Neuron(brain, 0), new Neuron(brain, 0), new Neuron(brain, 0),
    new Neuron(brain, 0), new Neuron(brain, 0), new Neuron(brain, 0), 
    new Neuron(brain, 0), new Neuron(brain, 0),new Neuron(brain, 0), 
    new Neuron(brain, 0)]; //10

var layer1 = [new Neuron(brain, 1), new Neuron(brain, 1), new Neuron(brain, 1), 
    new Neuron(brain, 1), new Neuron(brain, 1), new Neuron(brain, 1), 
    new Neuron(brain, 1), new Neuron(brain, 1), new Neuron(brain, 1),
    new Neuron(brain, 1), new Neuron(brain, 1), new Neuron(brain, 1),
    new Neuron(brain, 1)]; //13

var layer2 = [new Neuron(brain, 2), new Neuron(brain, 2)]; //2

layer0[0].connect(layer1[0]);
layer0[1].connect(layer1[1]);
layer0[2].connect(layer1[2]);
layer0[3].connect(layer1[3]);
layer0[4].connect(layer1[4]);
layer0[5].connect(layer1[5]);
layer0[6].connect(layer1[6]);
layer0[7].connect(layer1[7]);
layer0[8].connect(layer1[8]);
layer0[9].connect(layer1[9]);
layer0[0].connect(layer1[3]);
layer0[1].connect(layer1[4]);
layer0[2].connect(layer1[5]);
layer0[3].connect(layer1[6]);
layer0[4].connect(layer1[7]);
layer0[5].connect(layer1[8]);
layer0[6].connect(layer1[9]);
layer0[7].connect(layer1[10]);
layer0[8].connect(layer1[11]);
layer0[9].connect(layer1[12]);

layer1[0].connect(layer2[0]);
layer1[1].connect(layer2[1]);
layer1[2].connect(layer2[0]);
layer1[3].connect(layer2[1]);
layer1[4].connect(layer2[0]);
layer1[5].connect(layer2[1]);
layer1[6].connect(layer2[0]);
layer1[7].connect(layer2[1]);
layer1[8].connect(layer2[0]);
layer1[9].connect(layer2[1]);
layer1[10].connect(layer2[0]);
layer1[11].connect(layer2[1]);
layer1[12].connect(layer2[0]);

//works! until...

function getRandomInt(min, max) {
	return Math.floor(Math.random() * (max - min + 1)) + min;
}

for (prop in brain.globalReferenceNeurons) {
	var rand = getRandomInt(1,6);
  var neuron = brain.globalReferenceNeurons[prop];
  if (rand == 1 && neuron.layer != 2) neuron.active = false;
}
for (prop in brain.globalReferenceConnections) {
	var rand = getRandomInt(1,6);
  var connection = brain.globalReferenceConnections[prop];
  if (rand == 1) connection.active = false;
}



renderBrain(brain, canvas.getContext("2d"), canvas);
<canvas id="canvas" width= 512 height = 200></canvas>

标签:neural-network,canvas,javascript
来源: https://codeday.me/bug/20191026/1934164.html