Проблема с простой искусственной нейронной сетью - добавление

Я пытаюсь сделать простую искусственную работу нейронной сети с алгоритмом backpropagation. Я создал ANN, и я считаю, что я правильно реализовал алгоритм BP, но я, конечно, ошибаюсь.

Прямо сейчас, я пытаюсь обучить сеть, предоставив ей два случайных числа (a, b) между 0 и 0.5 и добавив их. Затем, разумеется, каждый раз, когда выдает сеть, сравнивается с теоретическим ответом a + b (который всегда будет достижим сигмоидной функцией).

Как ни странно, вывод всегда сходится к числу от 0 до 1 (как и должно быть из-за сигмоидной функции), но случайные числа, которые я помещаю, похоже, не влияют на него.

Изменить: Извините, похоже, что он не сходится. Вот изображение вывода:

enter image description here

Весы распределены случайным образом между -1 и 1, но я также пытался между 0 и 1.

Я также попытался дать ему два постоянных числа (0,35,0,9) и попытаться обучить его выплевывать 0,5. Это работает и сходится очень быстро до 0,5. Я также обучил его выплевывать 0,5, если я даю ему два случайных числа от 0 до 1, и это также работает.

Если вместо этого моя цель:

vector<double> target;
target.push_back(.5);

Затем он сходится очень быстро, даже со случайными входами:

enter image description here

Я пробовал пару разных сетей, так как я очень легко добавлял слои в свою сеть. Стандартным я использую один с двумя входами, один слой из 2 нейронов и второй слой только одного нейрона (выходного нейрона). Тем не менее, я также попытался добавить несколько слоев и добавить к ним нейроны. Кажется, это ничего не меняет. Моя скорость обучения равна 1,0, хотя я пробовал его равным 0,5, и он не сильно отличался.

Кто-нибудь может понять, что я могу попробовать?

Это даже то, на что способен ANN? Я не могу себе представить, что этого не будет, поскольку их можно обучить таким сложным вещам.

Любые советы? Спасибо!

Вот где я его тренирую:

//Initialize it. This will be one with 2 layers, the first having 2 Neurons and the second (output layer) having 1.
vector<int> networkSize;
networkSize.push_back(2);
networkSize.push_back(1);
NeuralNetwork myNet(networkSize,2);

for(int i = 0; i<5000; i++){
    double a = randSmallNum();
    double b = randSmallNum();
    cout << "\n\n\nInputs: " << a << ", " << b << " with expected target: " << a + b;

    vector<double> myInput;
    myInput.push_back(a);   
    myInput.push_back(b);   

    vector<double> target;
    target.push_back(a + b);

    cout << endl << "Iteration " << i;
    vector<double> output = myNet.backPropagate(myInput,target);
    cout << "Output gotten: " << output[0];
    resultPlot << i << "\t" << abs(output[0] - target[0]) << endl;
}

Изменить: я настроил свою сеть и следил за этим руководством: A pdf. Я реализовал "Worked example 3.1" и получил те же точные результаты, что и они, поэтому я считаю, что моя реализация верна, по крайней мере, насколько это возможно.

Ответ 1

Как указано в @macs, максимальный вывод стандартного сигмоида равен 1, поэтому, если вы попытаетесь добавить n чисел из [0, 1], тогда ваша цель должна быть нормализована, то есть сумма (A1, A2,..., An)/n.

Ответ 2

В такой модели, как сигмоидальная функция (как в выходном, так и в промежуточном слоях) используется в основном для создания чего-то, что напоминает переключение 0/1, но все же является непрерывной функцией, поэтому использование его для представления диапазон номеров - это не то, для чего предназначена такая сеть. Это связано с тем, что он разработан в основном с учетом проблем классификации. Конечно, есть и другие модели NN, которые могут делать такие вещи (например, удаление сигмоида на выходе и просто сохранение его как суммы его дочерних элементов).

Если вы можете переопределить свою модель с точки зрения классификации ввода, вы, вероятно, получите лучшие результаты.

Некоторые примеры подобных задач, для которых сеть будет более подходящей:

  • Проверьте, больше или меньше результат, чем определенная константа - это должно быть очень просто.
  • Выход: серия выходов, каждая из которых представляет другое потенциальное значение (например, каждый выводит каждый для значений от 0 до 10, один для "более 10" и один для "меньше 0" ). Вы хотите, чтобы ваша сеть округляла результат до ближайшего целого числа
  • Трудным будет попытка создать логическое представление вывода с помощью нескольких выходных узлов.

Ни одно из них не даст вам точной точности, которую вы, возможно, захотите, поскольку по своей природе NNs более "нечеткие"