【问题标题】:How to correctly train my Neural Network如何正确训练我的神经网络
【发布时间】:2017-06-19 17:57:59
【问题描述】:

我正在尝试教一个神经网络根据其输入的生命水平来决定去哪里。神经网络将始终接收三个输入[x, y, life]。如果life => 0.2,它应该输出从[x, y](1, 1)的角度。如果是life < 0.2,它应该输出从[x, y](0, 0)的角度。

由于神经元的输入和输出应该在01 之间,我将角度除以2 *Math.PI

代码如下:

var network = new synaptic.Architect.Perceptron(3,4,1);

for(var i = 0; i < 50000; i++){
  var x = Math.random();
  var y = Math.random();
  var angle1 = angleToPoint(x, y, 0, 0) / (2 * Math.PI);
  var angle2 = angleToPoint(x, y, 1, 1) / (2 * Math.PI);
  for(var j = 0; j < 100; j++){
    network.activate([x,y,j/100]);
    if(j < 20){
      network.propagate(0.3, [angle1]);
    } else {
      network.propagate(0.3, [angle2]);
    }
  }
}

在这里试试:jsfiddle

因此,当我输入以下输入 [0, 1, 0.19] 时,我希望神经网络输出接近 [0.75] (1.5PI / 2PI) 的内容。但是我的结果完全不一致,并且与给出的任何输入都没有关联。

我在教授神经网络时犯了什么错误?

我已经成功地教一个神经网络在输入[a, b, c]c =&gt; 0.2 时输出1,当输入[a, b, c]c &lt; 0.2 时输出0。我还设法教它根据[x, y] 输入输出到某个位置的角度,但是我似乎无法将它们组合起来


根据要求,我编写了一些代码,使用 2 个神经网络来获得所需的输出。第一个神经网络将生命水平转换为 0 或 1,第二个神经网络根据第一个神经网络输出的 0 或 1 输出一个角度。这是代码:

// This network outputs 1 when life => 0.2, otherwise 0
var network1 = new synaptic.Architect.Perceptron(3,3,1);
// This network outputs the angle to a certain point based on life
var network2 = new synaptic.Architect.Perceptron(3,3,1);

for (var i = 0; i < 50000; i++){
  var x = Math.random();
  var y = Math.random();
  var angle1 = angleToPoint(x, y, 0, 0) / (2 * Math.PI);
  var angle2 = angleToPoint(x, y, 1, 1) / (2 * Math.PI);

  for(var j = 0; j < 100; j++){
    network1.activate([x,y,j/100]);
    if(j < 20){
      network1.propagate(0.1, [0]);
    } else {
      network1.propagate(0.1, [1]);
    }
     network2.activate([x,y,0]);
    network2.propagate(0.1, [angle1]);
    network2.activate([x,y,1]);
    network2.propagate(0.1, [angle2]);
  }
}

在这里试试:jsfiddle

正如您在此示例中所见。它设法非常接近地达到所需的输出,通过增加更多的迭代它会更接近。

【问题讨论】:

  • 我建议在隐藏层添加更多的神经元。
  • @cdm 我试过了,但没有什么不同。我正在尝试通过配置各个层来创建自己的网络。
  • 要么你的层有问题,要么使用多个神经网络是更好的解决方案。
  • @Walfrat hmm 似乎是唯一的解决方案。我会尝试相互投射网络。
  • 否则您可以检查您的 javascript 库是否提供了除神经网络之外的其他东西,对于 0/1 类型的结果,支持向量机 (SVM) 比神经网络轻得多。

标签: javascript neural-network backpropagation


【解决方案1】:

观察

  1. 作为训练集采样的偏态分布

    您的训练集选择for(var j = 0; j &lt; 100; j++) 中的life 参数,该参数高度偏向j&gt;20,因此偏向life&gt;0.2。该子集的训练数据是它的 4 倍,这使您的训练功能优先。

  2. 非混洗训练数据

    您正在针对life 参数进行顺序训练,这可能是有害的。您的网络最终会更加关注更大的js,因为它是网络传播的最新原因。你应该打乱你的训练集以避免这种偏差。

    这将与前一点叠加,因为您再次更加关注life 值的某些子集。

  3. 你也应该衡量你的训练表现

    尽管有之前的观察,您的网络并没有那么糟糕。你的训练错误没有你的测试那么大。这种差异通常意味着您正在对不同的样本分布进行训练和测试。

    您可以说您有两类数据点:带有life&gt;0.2 的数据点和其他没有的数据点。但是因为您在angleToPoint 函数中引入了不连续性,我建议您将其分为三个类:为life&lt;0.2 保留一个类(因为该函数连续运行)并将life&gt;0.2 拆分为“以上(1,1 )”和“低于 (1,1)”。

  4. 网络复杂度

    您可以成功地为每个任务分别训练一个网络。现在您想要堆叠它们。这正是深度学习的目的:每一层都建立在前一层感知的概念之上,因此增加了它可以学习的概念的复杂性。

    因此,我建议您使用 2 层,每层 10 个节点,而不是在单层中使用 20 个节点。这与我在前面提到的类层次结构相匹配。

代码

运行此代码时,我遇到了0.0004/0.0002 的训练/测试错误。

https://jsfiddle.net/hekqj5jq/11/

var network = new synaptic.Architect.Perceptron(3,10,10,1);
var trainer = new synaptic.Trainer(network);
var trainingSet = [];

for(var i = 0; i < 50000; i++){
  // 1st category: above vector (1,1), measure against (1,1)
  var x = getRandom(0.0, 1.0);
  var y = getRandom(x, 1.0);
  var z = getRandom(0.2, 1);
  var angle = angleToPoint(x, y, 1, 1) / (2 * Math.PI);
  trainingSet.push({input: [x,y,z], output: [angle]});
  // 2nd category: below vector (1,1), measure against (1,1)
  var x = getRandom(0.0, 1.0);
  var y = getRandom(0.0, x);
  var z = getRandom(0.2, 1);
  var angle = angleToPoint(x, y, 1, 1) / (2 * Math.PI);
  trainingSet.push({input: [x,y,z], output: [angle]});
  // 3rd category: above/below vector (1,1), measure against (0,0)
  var x = getRandom(0.0, 1.0);
  var y = getRandom(0.0, 1.0);
  var z = getRandom(0.0, 0.2);
  var angle = angleToPoint(x, y, 0, 0) / (2 * Math.PI);
  trainingSet.push({input: [x,y,z], output: [angle]});
}

trainer.train(trainingSet, {
    rate: 0.1,
    error: 0.0001,
    iterations: 50,
    shuffle: true,
    log: 1,
    cost: synaptic.Trainer.cost.MSE
});

testSet = [
    {input: [0,1,0.25], output: [angleToPoint(0, 1, 1, 1) / (2 * Math.PI)]},
    {input: [1,0,0.35], output: [angleToPoint(1, 0, 1, 1) / (2 * Math.PI)]},
    {input: [0,1,0.10], output: [angleToPoint(0, 1, 0, 0) / (2 * Math.PI)]},
    {input: [1,0,0.15], output: [angleToPoint(1, 0, 0, 0) / (2 * Math.PI)]}
];

$('html').append('<p>Train:</p> ' + JSON.stringify(trainer.test(trainingSet)));
$('html').append('<p>Tests:</p> ' + JSON.stringify(trainer.test(testSet)));

$('html').append('<p>1st:</p> ')
$('html').append('<p>Expect:</p> ' + angleToPoint(0, 1, 1, 1) / (2 * Math.PI));
$('html').append('<p>Received: </p> ' + network.activate([0, 1, 0.25]));

$('html').append('<p>2nd:</p> ')
$('html').append('<p>Expect:</p> ' + angleToPoint(1, 0, 1, 1) / (2 * Math.PI));
$('html').append('<p>Received: </p> ' + network.activate([1, 0, 0.25]));

$('html').append('<p>3rd:</p> ')
$('html').append('<p>Expect:</p> ' + angleToPoint(0, 1, 0, 0) / (2 * Math.PI));
$('html').append('<p>Received: </p> ' + network.activate([0, 1, 0.15]));

$('html').append('<p>4th:</p> ')
$('html').append('<p>Expect:</p> ' + angleToPoint(1, 0, 0, 0) / (2 * Math.PI));
$('html').append('<p>Received: </p> ' + network.activate([1, 0, 0.15]));

function angleToPoint(x1, y1, x2, y2){
  var angle = Math.atan2(y2 - y1, x2 - x1);
  if(angle < 0){
    angle += 2 * Math.PI;
  }
  return angle;
}

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

补充说明

正如我在 cmets 和聊天中提到的,没有“(x,y) 和 (0,0) 之间的角度”这样的东西,因为向量之间的角度的概念通常被认为是他们的方向和(0,0) 没有方向。

您的函数angleToPoint(p1, p2) 返回的是 (p1-p2) 的方向。对于 p2 = (0,0),这意味着 p1 和 x 轴之间的角度可以。但是对于 p1=(1,1) 和 p2=(1,0) 它不会返回 45 度。对于 p1=p2,它是未定义的,而不是零。

【讨论】:

  • 顺便说一句,我认为这应该转移到交叉验证网络,在那里你可能会得到更好的答案和对我的分析的一些更正。
猜你喜欢
  • 1970-01-01
  • 2018-11-26
  • 2019-11-16
  • 2019-07-17
  • 1970-01-01
  • 2011-04-07
  • 1970-01-01
  • 2010-11-20
  • 2019-09-15
相关资源
最近更新 更多