Обучение нейронной сети с PyBrain не сходится

У меня есть следующий код из учебника PyBrain:

from pybrain.datasets import SupervisedDataSet
from pybrain.supervised.trainers import BackpropTrainer
from pybrain.tools.shortcuts import buildNetwork
from pybrain.structure.modules import TanhLayer

ds = SupervisedDataSet(2, 1)
ds.addSample((0,0), (0,))
ds.addSample((0,1), (1,))
ds.addSample((1,0), (1,))
ds.addSample((1,1), (0,))

net     = buildNetwork(2, 3, 1, bias=True, hiddenclass=TanhLayer)
trainer = BackpropTrainer(net, ds)

for inp, tar in ds:
     print [net.activate(inp), tar]

errors  = trainer.trainUntilConvergence()

for inp, tar in ds:
     print [net.activate(inp), tar]

Однако в результате получается нейронная сеть, которая плохо обучена. При просмотре сообщения об ошибке сеть обучается должным образом, однако она использует аргумент continueEpochs, чтобы обучить еще немного, и сеть снова работает хуже. Итак, сеть сходится, но нет возможности получить наиболее обученную сеть. Документация PyBrain подразумевает, что сеть возвращается, которая лучше всего обучена, однако она возвращает кортеж ошибок.

Если установить continueEpochs на 0, я получаю сообщение об ошибке (ValueError: max () arg - пустая последовательность), поэтому continueEpochs должно быть больше 0.

Поддерживается ли PyBrain, потому что кажется, что существует большая разница в документации и коде.


person avanwieringen    schedule 21.08.2012    source источник
comment
Ух, исходники на Github показывают больше примеров, решенных совершенно другим способом по сравнению с документацией.   -  person avanwieringen    schedule 21.08.2012


Ответы (4)


Еще немного покопавшись, я обнаружил, что пример в руководстве PyBrain совершенно неуместен.

Когда мы смотрим на подпись метода в исходном коде, мы обнаруживаем:

def trainUntilConvergence(self, dataset=None, maxEpochs=None, verbose=None, continueEpochs=10, validationProportion=0.25):

Это означает, что для проверки используется 25% обучающего набора. Хотя это очень действенный метод при обучении сети на данных, вы не собираетесь этого делать, когда в вашем распоряжении полный диапазон возможностей, а именно 4-рядный набор решений XOR 2-in-1-out. Когда кто-то хочет обучить набор XOR и вы удаляете одну из строк для проверки, в результате вы получаете очень разреженный обучающий набор, в котором одна из возможных комбинаций опускается, что автоматически приводит к тому, что эти веса не обучаются.

Обычно, когда вы пропускаете 25% данных для проверки, вы делаете это, предполагая, что эти 25% покрывают «большую часть» пространства решений, с которым сеть уже столкнулась более или менее. В данном случае это неверно, и он покрывает 25% пространства решения, полностью неизвестного сети, так как вы удалили его для проверки.

Итак, тренер обучал сеть правильно, но, пропустив 25% проблемы XOR, это приводит к плохо обученной сети.

Другой пример на веб-сайте PyBrain в качестве быстрого старта был бы очень удобен, потому что этот пример просто неверен в этом конкретном случае XOR. Вы можете задаться вопросом, пробовали ли они этот пример сами, потому что он просто выводит случайные плохо обученные сети.

person avanwieringen    schedule 21.08.2012
comment
Спасибо за это! Этот пример меня так сбил с толку. В документации говорится, что XOR - это классический пример нейронной сети, но тогда этот пример кода дал мне ужасные ответы. - person TG_Matt; 13.03.2013
comment
Это классический пример нейронной сети, потому что он показывает, что с помощью комбинации линейных функций (сигмоидов) вы можете обучить сеть изучению двоичной логики. Однако их руководство ужасно, поскольку они, кажется, сами не понимают концепцию. - person avanwieringen; 17.03.2013
comment
Я рекомендую вам разветвить проект github, сделать пример таким, каким, по вашему мнению, он должен быть, а затем сделать запрос на перенос - person Firestrand; 04.03.2014

Я прошел отличный курс машинного обучения на Coursera, который вел Эндрю Нг, и одну часть Занятия были посвящены обучению небольшой нейронной сети распознаванию xor. Поэтому меня немного смутил пример pybrain, основанный на некоторых частях quickstart, которые не совпадали.

Я думаю, что есть много причин, в том числе приведенная выше о том, что минимальный набор данных разделяется на обучение и проверку. В какой-то момент Эндрю сказал: «Побеждает не тот, у кого лучший алгоритм, а тот, у кого больше всего данных. возрождение ИИ, теперь называемое машинным обучением.

Итак, имея в виду все это, я обнаружил, что

  1. набор проверки может иметь 4 образца, потому что это происходит после фазы обучения.
  2. сети нужны только 2 узла в скрытом слое, как я узнал в классе,
  3. скорость обучения в этом случае должна быть довольно небольшой, например 0,005, иначе при обучении ответ иногда будет пропускаться (это важный момент из класса, который я подтвердил, играя с числами).
  4. чем меньше скорость обучения, тем меньше может быть maxEpochs. Малая скорость обучения означает, что сходимость делает меньшие шаги по градиенту в сторону минимизации. Если он больше, вам нужно больше maxEpochs, чтобы он ждал дольше, прежде чем решить, что он достиг минимума.
  5. Вам нужно смещение = True в сети (которое добавляет постоянный узел 1 к входному и скрытому слоям). Прочтите ответы на этот вопрос о предвзятости.
  6. Наконец, что наиболее важно, вам понадобится большой тренировочный набор. 1000 сходятся на правильном ответе примерно в 75% случаев. Я подозреваю, что это связано с алгоритмом минимизации. Меньшие числа часто терпят неудачу.

Итак, вот код, который работает:

from pybrain.datasets import SupervisedDataSet

dataModel = [
    [(0,0), (0,)],
    [(0,1), (1,)],
    [(1,0), (1,)],
    [(1,1), (0,)],
]

ds = SupervisedDataSet(2, 1)
for input, target in dataModel:
    ds.addSample(input, target)

# create a large random data set
import random
random.seed()
trainingSet = SupervisedDataSet(2, 1);
for ri in range(0,1000):
    input,target = dataModel[random.getrandbits(2)];
    trainingSet.addSample(input, target)

from pybrain.tools.shortcuts import buildNetwork
net = buildNetwork(2, 2, 1, bias=True)

from pybrain.supervised.trainers import BackpropTrainer
trainer = BackpropTrainer(net, ds, learningrate = 0.001, momentum = 0.99)
trainer.trainUntilConvergence(verbose=True,
                              trainingData=trainingSet,
                              validationData=ds,
                              maxEpochs=10)

print '0,0->', net.activate([0,0])
print '0,1->', net.activate([0,1])
print '1,0->', net.activate([1,0])
print '1,1->', net.activate([1,1])
person toddInPortland    schedule 10.12.2013

trainer = BackpropTrainer(net, ds, learningrate = 0.9, momentum=0.0, weightdecay=0.0, verbose=True) 
trainer.trainEpochs(epochs=1000)

Таким образом можно сойтись. если скорость обучения слишком мала (например, 0,01), она теряется в локальном минимуме. Как я тестировал, скорость обучения в 0,3-30, может сходиться.

person lym    schedule 23.03.2014
comment
Это по-прежнему не учитывает тот факт, что пример недействителен, поскольку он использует подмножество для проверки и опускает это подмножество во время обучения при ложном предположении, что оставшийся набор покрывает большую часть пространства решений. - person avanwieringen; 25.03.2014

Следующее, кажется, неизменно дает правильные результаты:

from pybrain.tools.shortcuts import buildNetwork
from pybrain.structure import TanhLayer
from pybrain.datasets import SupervisedDataSet
from pybrain.supervised.trainers import BackpropTrainer

#net = buildNetwork(2, 3, 1, bias=True, hiddenclass=TanhLayer)
net = buildNetwork(2, 3, 1, bias=True)

ds = SupervisedDataSet(2, 1)
ds.addSample((0, 0), (0,))
ds.addSample((0, 1), (1,))
ds.addSample((1, 0), (1,))
ds.addSample((1, 1), (0,))
ds.addSample((0, 0), (0,))
ds.addSample((0, 1), (1,))
ds.addSample((1, 0), (1,))
ds.addSample((1, 1), (0,))
ds.addSample((0, 0), (0,))
ds.addSample((0, 1), (1,))
ds.addSample((1, 0), (1,))
ds.addSample((1, 1), (0,))
ds.addSample((0, 0), (0,))
ds.addSample((0, 1), (1,))
ds.addSample((1, 0), (1,))
ds.addSample((1, 1), (0,))
ds.addSample((0, 0), (0,))
ds.addSample((0, 1), (1,))
ds.addSample((1, 0), (1,))
ds.addSample((1, 1), (0,))
ds.addSample((0, 0), (0,))
ds.addSample((0, 1), (1,))
ds.addSample((1, 0), (1,))
ds.addSample((1, 1), (0,))

trainer = BackpropTrainer(net, ds, learningrate=0.001, momentum=0.99)

trainer.trainUntilConvergence(verbose=True)

print net.activate([0,0])
print net.activate([0,1])
print net.activate([1,0])
print net.activate([1,1])
person bkanber    schedule 04.02.2016
comment
Да, но вы даете несколько раз один и тот же образец, что означает, что, когда алгоритм обучения разделяет набор для обучения и проверки, происходит сильное изменение в том, что набор для обучения завершен. Однако есть вероятность, что это не так ... Хотя вы решили проблему, это не меняет того факта, что пример на веб-сайте явно неверен. - person avanwieringen; 05.02.2016