使用 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 中的时间序列