[英]How to correctly train my Neural Network
我正在嘗試教一個神經網絡,根據輸入的生命水平決定去哪里。 神經網絡將始終接收三個輸入[x, y, life]
。 如果life => 0.2
,它應該輸出從[x, y]
到(1, 1)
。 如果life < 0.2
,則應輸出從[x, y]
到(0, 0)
。
由於神經元的輸入和輸出應該在0
和1
之間,我將角度除以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]
1.5PI / 2PI
[0, 1, 0.19]
,我希望神經網絡輸出接近[0.75]
( 1.5PI / 2PI
)的1.5PI / 2PI
。 但是我的結果完全不一致,並且與任何輸入都沒有任何關聯。
我在教授神經網絡時犯了什么錯誤?
我已成功地教神經網絡來輸出
1
時輸入[a, b, c]
與c => 0.2
和0
時輸入[a, b, c]
與c < 0.2
。 我還設法教它根據[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
正如您在此示例中看到的那樣。 它設法非常接近地達到期望的輸出,通過添加更多迭代它將更加接近。
傾斜分布作為訓練集采樣
你的訓練集是選擇里面的life
參數for(var j = 0; j < 100; j++)
,它高度偏向於j>20
,因此life>0.2
。 它為該子集提供了4倍的訓練數據,這使您的訓練功能優先。
非混亂的訓練數據
您正在按life
參數順序訓練,這可能是有害的。 你的網絡將最終關注更大的j
s,因為它是網絡傳播的最新原因。 你應該改變你的訓練集以避免這種偏見。
這將與前一點疊加,因為您再次關注life
值的某些子集。
您還應該衡量您的訓練表現
盡管以前有過觀察,你的網絡並不是那么糟糕。 您的訓練錯誤不如您的測試那么大。 這種差異通常意味着您正在對不同的樣本分布進行培訓和測試。
你可以說你有兩類數據點: life>0.2
而其他數據點不是。 但是因為你在angleToPoint
函數中引入了一個不連續性,我建議你將它分成三個類:保持一個life<0.2
類life<0.2
(因為函數連續運行)並在“above(1,1)”中拆分life>0.2
和“下面(1,1)。”
網絡復雜性
您可以分別為每個任務成功訓練網絡。 現在你想要堆疊它們。 這是深度學習的目的:每一層都建立在前一層感知的概念之上,因此增加了它可以學習的概念的復雜性。
因此,我建議您使用2層10個節點,而不是在單個層中使用20個節點。 這與我在前一點中提到的類層次結構相匹配。
運行此代碼我的訓練/測試誤差為0.0004
/ 0.0002
。
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;
}
正如我在評論和聊天中提到的,沒有“(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,它是未定義的而不是零。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.