Ответ 1
Наблюдения
-
Скорректированное распределение, выбранное как набор для обучения
Ваш обучающий набор выбирает параметр
life
внутриfor(var j = 0; j < 100; j++)
, который сильно смещен в сторонуj>20
и, следовательно,life>0.2
. Он имеет в 4 раза больше данных обучения для этого подмножества, что делает приоритет вашей тренировочной функции. -
Неперетасованные данные обучения
Вы тренируетесь последовательно с параметром
life
, что может быть вредным. Ваша сеть в конечном итоге будет уделять больше внимания более крупномуj
, поскольку это самая последняя причина распространения сети. Вы должны перетасовать свой тренировочный набор, чтобы избежать этого смещения.Это будет складываться с предыдущей точкой, потому что вы снова уделяете больше внимания некоторому подмножеству значений
life
. -
Вы также должны измерить свою производительность обучения
Ваша сеть, несмотря на предыдущие наблюдения, была не так уж плоха. Ваша ошибка обучения была не такой большой, как ваши тесты. Это расхождение обычно означает, что вы тренируетесь и тестируете различные дистрибутивы.
Можно сказать, что у вас есть два класса точек данных: те, у которых
life>0.2
, а другие нет. Но поскольку вы ввели разрыв в функцииangleToPoint
, я бы рекомендовал вам разделить три класса: сохранить класс дляlife<0.2
(потому что функция ведет себя непрерывно) и splitlife>0.2
in "выше (1,1 )" и "ниже (1,1)." -
Сложность сети
Вы можете успешно организовать сеть для каждой задачи отдельно. Теперь вы хотите стек их. Это и есть цель глубокого обучения: каждый слой опирается на концепции, воспринимаемые предыдущим слоем, тем самым увеличивая сложность понятий, которые он может изучить.
Поэтому вместо того, чтобы использовать 20 узлов в одном слое, я бы рекомендовал вам использовать 2 слоя из 10 узлов. Это соответствует иерархии классов, о которой я упомянул в предыдущей точке.
Код
Запустив этот код, у меня была ошибка обучения/тестирования 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 оно undefined вместо нуля.