32

我有以下代码,来自 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 是否真的被维护了,因为文档和代码似乎有很大的不同。

4

4 回答 4

35

经过一番挖掘后,我发现 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 情况下,这个示例完全是错误的。你可能想知道他们是否自己尝试过这个例子,因为它只是随机输出训练有素的网络。

于 2012-08-21T08:23:06.910 回答
17

我在 Coursera 上学习了由 Andrew Ng 教授的优秀机器学习课程,课程的一部分内容包括训练一个小型神经网络来识别异或。所以我对基于快速入门部分没有收敛的pybrain示例有点困扰

我认为有很多原因,包括上面关于最小数据集被分成训练和验证的原因。在课程的某一时刻,Andrew 说“获胜的不是拥有最佳算法的人,而是拥有最多数据的人。他接着解释说,2000 年代数据可用性的爆炸式增长是导致人工智能的复兴,现在称为机器学习。

因此,考虑到所有这些,我发现

  1. 验证集可以有 4 个样本,因为那是在训练阶段之后。
  2. 正如我在课堂上学到的,网络只需要隐藏层中的 2 个节点,
  3. 在这种情况下,学习率需要非常小,例如 0.005,否则训练有时会跳过答案(这是课堂上的一个重要点,我通过玩数字确认了这一点)。
  4. 学习率越小,maxEpochs 可以越小。小的学习率意味着收敛沿着梯度向最小化采取更小的步骤。如果它更大,则需要更大的 maxEpochs 以便它在确定达到最小值之前等待更长时间。
  5. 您需要在网络中设置一个bias=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])
于 2013-12-10T04:30:43.723 回答
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 之间,它可以收敛。

于 2014-03-23T14:42:39.223 回答
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])
于 2016-02-04T19:16:33.750 回答