我正在努力全面理解神经网络的概念,因此我从创建自己的简单感知器算法开始。
这是我的代码(用JavaScript编写):
var lr = 0.1;//学习率//随机初始化权重function initWeights(weights, trainingSets){ for(var i=0; i<trainingSets[0].in.length; i++){ weights[i] = Math.random()*2 - 1; } weights.push(Math.random()*2 - 1); //b}//返回给定训练集的原始激活值function getSum(weights, trainingSet){ var sum = 0; for(var i=0; i < trainingSet.in.length; i++){ sum += weights[i]*trainingSet.in[i]; } sum += 1 * weights[weights.length-1]; return sum;}//激活函数function activate(value){ return (value >= 0)? 1 : 0;}function train(weights, trainingSets){ var error = 0; for(var i=0; i<trainingSets.length; i++){ var currentSet = trainingSets[i]; var activationValue = getSum(weights, currentSet); var error = currentSet.out - activate(activationValue); error += error; for(var j=0; j<weights.length-1; j++){ var deltaW = error * lr * currentSet.in[j]; weights[j] += deltaW; } weights[weights.length-1] += error * lr * 1; } return error/(weights.length);}var inp = [ {in:[1,1], out:1}, {in:[0,0], out:0}, {in:[0,1], out:0},];var w = [];initWeights(w, inp);//for(var j = 0; j < inp.length; j++){ var error = 1; while(error >= 0.01){ error = train(w, inp); }//}console.log("===")var tester = {in:[1,0], out: NaN};console.log(getSum(w, tester)) //应为负值console.log("y=("+w[1]+"*x+"+w[2]+")/"+w[1])
结果并不一致(我使用的是AND算法进行学习)。
图表应该看起来像这样:
但通常看起来像这样:
我确定这里遗漏了一些小细节,
提前感谢您的帮助。
回答:
你的代码至少存在三个问题:
- 你重新声明了error变量,最初它被设计为一个总和误差,然后你再次声明它为每个输出神经元的误差,这导致了关于整个过程的信息丢失
- 你的停止标准不好 – 它应该是误差的平均绝对值,而不仅仅是误差的总和 – 考虑一个简单的网络,它将一个标签为
0
的训练样本分类为1
,这将在你的代码中导致负误差,因此训练停止,尽管它远未结束 -
训练后使用
var inp = [ {in:[1,1], out:1}, {in:[0,0], out:0}, {in:[0,1], out:0},];
你不会得到
f( [1,0] ) == 0
,这不是感知器的工作方式。它只会在二维平面上找到一条线,使[1,1]
位于其一侧,而[0,0]
和[0,1]
位于另一侧。没有保证[1,0]
与[0,0]
和[0,1]
位于同一侧,这是预期的行为。使用提供的数据,感知器没有理由不使用x=0.5
的垂直线,这完美地分隔了你的数据,但f( [1,0] ) == 1
。你的训练数据并没有“定义”与操作,而只是一组简单的规则,这些规则被无限数量的分类器遵守。function train(weights, trainingSets){var error = 0;for(var i=0; i<trainingSets.length; i++){ var currentSet = trainingSets[i]; var activationValue = getSum(weights, currentSet); var error_current = currentSet.out - activate(activationValue); error += Math.abs( error_current ); for(var j=0; j<weights.length-1; j++){ var deltaW = error_current * lr * currentSet.in[j]; weights[j] += deltaW; } weights[weights.length-1] += error_current * lr * 1;}return error/(weights.length);}
如评论中所述,如果你用点(1,0)、(0,1)和(1,1)的值训练你的网络,它会自己推断出(0,0)的值
var inp = [ {in:[1,1], out:1}, {in:[0,1], out:0}, {in:[1,0], out:0},];var w = [];initWeights(w, inp);//for(var j = 0; j < inp.length; j++){ var error = 1; while(error >= 0.01){ error = train(w, inp); }//}console.log("===")var test = [ {in:[1,1], out:1}, {in:[0,0], out:0}, {in:[0,1], out:0}, {in:[1,0], out:0},];for(var i=0; i<test.length; ++i){ console.log(test[i].in + " out: " +test[i].out + " nn: " + activate(getSum(w, test[i]) ) );}
产生
1,1 out: 1 nn: 1 0,0 out: 0 nn: 0 0,1 out: 0 nn: 0 1,0 out: 0 nn: 0