使用 PyBrain 进行神经网络训练不会收敛

Posted

技术标签:

【中文标题】使用 PyBrain 进行神经网络训练不会收敛【英文标题】:Neural Network training with PyBrain won't converge 【发布时间】:2012-08-16 12:55:54 【问题描述】:

我有以下代码,来自 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 is an empty sequence)所以 continueEpochs 必须大于 0。

是否真的维护了 PyBrain,因为文档和代码似乎存在很大差异。

【问题讨论】:

呃,与文档相比,Github 源代码显示了更多以完全不同的方式解决的示例。 【参考方案1】:

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

【讨论】:

谢谢!这个例子让我很困惑。文档说 XOR 是一个经典的神经网络示例,但是示例代码给了我可怕的答案。 这是一个经典的神经网络示例,因为它表明使用线性函数(sigmoids)的组合可以训练网络学习二进制逻辑。然而,他们的教程很糟糕,因为他们自己似乎没有掌握这个概念。 我建议你 fork github 项目,把例子做成你认为应该的样子,然后提出 pull request【参考方案2】:

我参加了由 Andrew Ng 教授的出色的 Machine Learning class on Coursera,课程的一部分内容包括训练一个小型神经网络来识别异或。所以我对基于quickstart部分不收敛的pybrain示例有点困扰。

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

考虑到这一切,我发现

    验证集可以有 4 个样本,因为这是在训练阶段之后进行的。 网络只需要隐藏层中的 2 个节点,正如我在课堂上学到的, 在这种情况下,学习率需要非常小,例如 0.005,否则训练有时会跳过答案(这是我通过玩数字确认的课程中的一个重要点)。 学习率越小,maxEpochs 可以越小。小的学习率意味着收敛沿着梯度向最小化采取更小的步骤。如果它更大,您需要更大的 maxEpochs,以便它在确定达到最小值之前等待更长时间。 您需要在网络中设置一个bias=True(向输入层和隐藏层添加一个常数1 节点)。阅读this question 关于偏见的答案。 最后,也是最重要的,您需要一个大型训练集。 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])

【讨论】:

【参考方案3】:
trainer = BackpropTrainer(net, ds, learningrate = 0.9, momentum=0.0, weightdecay=0.0, verbose=True) 
trainer.trainEpochs(epochs=1000)

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

【讨论】:

这仍然没有解决该示例无效的事实,因为它使用子集进行验证并在训练期间省略该子集,假设剩余集覆盖了大部分解决方案空间的错误假设.【参考方案4】:

以下似乎始终给出正确的结果:

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

【讨论】:

是的,但是您多次给出相同的样本,这意味着当训练算法将训练集和验证集分开时,训练集完成的变化很大。但是,也有可能不是……尽管您已经解决了问题,但这并不能改变网站上的示例明显错误的事实。

以上是关于使用 PyBrain 进行神经网络训练不会收敛的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 pybrain 黑盒优化训练神经网络以监督数据集?

训练 LSTM 神经网络以预测 pybrain、python 中的时间序列

神经网络训练中一个时代的意义

数据挖掘入门系列教程之使用神经网络(基于pybrain)识别数字手写集MNIST

使用 pybrain 进行神经网络回归

MLP 神经网络未正确训练,可能收敛到局部最小值