Это удивительно, потому что вы используете достаточно большую сеть (едва) для изучения XOR.Ваш алгоритм выглядит правильно, поэтому я не знаю, что происходит.Это может помочь узнать, как вы генерируете свои тренировочные данные: вы просто повторяете образцы (1,0,1),(1,1,0),(0,1,1),(0,0,0)
или что-то подобное снова и снова?Возможно, проблема в том, что стохастический градиентный спуск заставляет вас прыгать вокруг стабилизирующих минимумов.Вы можете попробовать некоторые вещи, чтобы исправить это: возможно, случайные выборки из ваших обучающих примеров вместо того, чтобы повторять их (если это то, что вы делаете).Или, в качестве альтернативы, вы можете изменить свой алгоритм обучения:
в настоящее время у вас есть что-то эквивалентное:
weight(epoch) = weight(epoch - 1) + deltaWeight(epoch)
deltaWeight(epoch) = mu * errorGradient(epoch)
, где mu
- это скорость обучения
Один из вариантов -на очень медленно уменьшайте значение mu
.
Альтернативой может быть изменение определения deltaWeight
для включения «импульса»
deltaWeight(epoch) = mu * errorGradient(epoch) + alpha * deltaWeight(epoch -1)
где alpha
- параметр импульса (между 0 и 1).
Визуально вы можете представить градиентный спуск как попытку найти минимальную точку криволинейной поверхности, поместив объект на эту поверхность, а затемшаг за шагом перемещая этот объект в небольших количествах, в которых любое направление направлено вниз в зависимости от того, где он находится в данный момент.Проблема в том, что вы на самом деле не делаете градиентное спуск: вместо этого вы делаете стохастический градиентный спуск, когда вы двигаетесь в направлении, отбирая образцы из набора обучающих векторов и двигаясь в любом направлении, из которого выглядит выборка, вниз.В среднем по всем тренировочным данным стохастический градиентный спуск должен работать, но это не гарантируется, потому что вы можете попасть в ситуацию, в которой вы прыгаете назад и вперед, никогда не делая успехов.Медленно уменьшая скорость обучения, вы каждый раз делаете все меньше и меньше шагов, чтобы не застрять в бесконечном цикле.
С другой стороны, импульс превращает алгоритм в нечто похожее на вращение резинового шарика.Когда мяч играет роль, он имеет тенденцию двигаться в нисходящем направлении, но он также имеет тенденцию продолжать двигаться в том направлении, в котором он шел раньше, и если он когда-либо будет на участке, где наклон вниз будет в одном и том же направлении какое-то время, он будетускоритьСледовательно, мяч будет перепрыгивать через некоторые локальные минимумы, и он будет более устойчивым к тому, чтобы переступать через цель вперед-назад, потому что это означает работу против силы импульса.
Имея некоторый код и думая об этом еще немного, совершенно ясно, что ваша проблема в обучении ранних уровней.Все функции, которые вы успешно изучили, линейно разделимы, поэтому имеет смысл, что только один слой изучается должным образом.Я согласен с LiKao о стратегиях реализации в целом, хотя ваш подход должен работать.Мое предложение о том, как это отладить, - выяснить, как выглядит прогрессирование весов на соединениях между входным слоем и выходным слоем.
Вы должны опубликовать остальные реализации Neuron
.