PyBrain的神经网络训练不会收敛

时间:2012-08-21 07:53:50

标签: python neural-network 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的文档意味着返回的网络被训练得最好,但它会返回一个错误元组。

Whens etting continueEpochs to 0我得到一个错误(ValueError:max()arg是一个空序列)所以continueEpochs必须大于0。

PyBrain是否实际维护,因为它似乎在文档和代码方面存在很大差异。

4 个答案:

答案 0 :(得分:35)

经过一番挖掘后,我发现PyBrain教程中的示例完全不合适。

当我们查看源代码中的方法签名时,我们发现:

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

这意味着25%的训练集用于验证。虽然在训练网络数据时这是一种非常有效的方法,但是当您拥有可用的全部可能性时,您将不会这样做,即4行XOR 2合1解决方案集。当一个人想要训练一个XOR集并且你删除其中一行进行验证时,你会得到一个非常稀疏的训练集,其中一个可能的组合被省略,导致自动进入那些未被训练的权重。

通常,当您省略25%的数据进行验证时,您可以假设25%的数据覆盖网络已经或多或少地遇到的“大部分”解决方案空间。在这种情况下,这不是真的,它覆盖了网络完全未知的解决方案空间的25%,因为您将其删除以进行验证。

因此,培训师正在正确地训练网络,但是通过省略25%的XOR问题,这会导致训练有素的网络。

作为快速入门的PyBrain网站上的另一个例子非常方便,因为这个例子在这个特定的XOR案例中是完全错误的。您可能想知道他们是否自己尝试了这个例子,因为它只输出随机训练有素的网络。

答案 1 :(得分:17)

我接受了由Andrew Ng教授的优秀Machine Learning class on Coursera,并且该课程的一部分涵盖了训练小神经网络来识别xor。所以我对基于quickstart部分没有收敛的pybrain示例感到有点困扰。

我认为有很多原因,包括上面关于将最小数据集分成训练和验证的原因。在课程的某一点,安德鲁说“它不是拥有最佳算法的人,而是拥有最多数据的人。他接着解释说,2000年的数据可用性爆炸是其中一部分原因。人工智能的复兴,现在称为机器学习。

所以考虑到这一点我找到了

  1. 验证集可以有4个样本,因为它来自训练阶段。
  2. 网络在隐藏层中只需要2个节点,正如我在课堂上学到的那样,
  3. 在这种情况下,学习率需要相当小,如0.005,否则训练有时会跳过答案(这是我通过玩数字确认的课程中的重点)。
  4. 学习率越小,maxEpochs越小。较小的学习率意味着收敛沿着梯度向最小化采取较小的步骤。如果它更大,你需要一个更大的maxEpochs,以便在决定它达到最小值之前等待更长时间。
  5. 您需要在网络中使用bias = True(这会在输入和隐藏图层中添加一个常量1节点)。阅读this question关于偏见的答案。
  6. 最后,最重要的是,你需要一个大的训练集。在大约75%的时间里,1000汇聚在正确的答案上。我怀疑这与最小化算法有关。较小的数字会频繁失败。
  7. 所以这里有一些有用的代码:

    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])
    

答案 2 :(得分:2)

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

这种方式可以收敛。如果学习率太小(例如0.01),它就会失去局部最小值。正如我测试的那样,在0.3-30中学习,它可以收敛。

答案 3 :(得分:0)

以下似乎始终如一地给出了正确的结果:

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])