使用PyBrain进行神经网络回归

9
我需要使用前馈网络解决一个回归问题,我一直在尝试使用PyBrain来完成。由于pybrain的参考文献中没有回归问题的示例,我试图将其分类示例适应为回归问题,但没有成功(分类示例可以在这里找到:http://pybrain.org/docs/tutorial/fnn.html)。以下是我的代码:

这个函数将我的数据从numpy数组转换为pybrain的SupervisedDataset。我使用SupervisedDataset,因为根据pybrain的参考文献,当问题是回归时需要使用该数据集。参数是一个包含特征向量(data)和它们的期望输出(values)的数组:

def convertDataNeuralNetwork(data, values):

fulldata = SupervisedDataSet(data.shape[1], 1)

for d, v in zip(data, values):

    fulldata.addSample(d, v)    

return fulldata

下面是运行回归的函数。train_data和train_values是训练特征向量及其期望输出,test_data和test_values是测试特征向量及其期望输出:
regressionTrain = convertDataNeuralNetwork(train_data, train_values)

regressionTest = convertDataNeuralNetwork(test_data, test_values)

fnn = FeedForwardNetwork()

inLayer = LinearLayer(regressionTrain.indim)
hiddenLayer = LinearLayer(5)
outLayer = GaussianLayer(regressionTrain.outdim)

fnn.addInputModule(inLayer)
fnn.addModule(hiddenLayer)
fnn.addOutputModule(outLayer)

in_to_hidden = FullConnection(inLayer, hiddenLayer)
hidden_to_out = FullConnection(hiddenLayer, outLayer)

fnn.addConnection(in_to_hidden)
fnn.addConnection(hidden_to_out)

fnn.sortModules()

trainer = BackpropTrainer(fnn, dataset=regressionTrain, momentum=0.1, verbose=True, weightdecay=0.01)

for i in range(10):

    trainer.trainEpochs(5)

    res = trainer.testOnClassData(dataset=regressionTest )

    print res

当我打印res时,所有的值都是0。我尝试使用buildNetwork函数作为构建网络的快捷方式,但它也没有起作用。我还尝试了不同类型的层和不同数量的隐藏层节点,但都没有成功。
有人知道我错在哪里吗?此外,一些pybrain回归示例会非常有帮助!我找不到任何相关信息。
谢谢。

如果你对神经网络感兴趣,可以考虑加入这个机器学习网站:http://area51.stackexchange.com/proposals/41738/machine-learning - travisbartley
2
非常确定您希望输出层用于回归是线性的 - 您可能还希望使用Sigmoid / tanh隐藏单元。 - Ben Allison
1
严格来说,并不一定是线性的,但它不能是一个输出范围被限制在 0..1 之类的激活函数。此外,我不确定线性隐藏层(如代码所示)的目的是什么,这通常可以通过权重吸收到下一层中。 - Andre Holzner
我知道这是一个老问题,但我想知道你是否解决了你的问题,如果解决了,能否分享一下方法? - Philip O'Brien
4个回答

5

pybrain.tools.neuralnets.NNregression是一个工具,可以学习数值预测一组数据的目标,可选显示在线进度图。因此,它似乎非常适合构建用于回归任务的神经网络。


4
我觉得这里可能有几个问题。
首先,我建议你使用不同的层激活配置。特别是,首先尝试在网络的隐藏层中使用Sigmoid非线性函数,并在输出层中使用线性激活。这是典型监督网络最常见的设置,应该可以帮助你入门。
第二件引起我的注意的事情是,你的训练器中的weightDecay参数值相对较大(虽然“相对较大”取决于输入和输出值的自然比例)。我建议你首先移除该参数,或将其值设为0。重量衰减是一种正则化方法,可以帮助防止过度拟合,但如果将该参数的值设置得太大,网络权重会很快全部变为0(然后网络的梯度基本上为0,学习会停止)。只有在训练期间验证数据集的表现开始下降时,才将weightDecay设置为非零值。

4
作为 Ben Allison 最初指出的,为了让网络能够逼近任意值(即不一定在 0..1 范围内),最后一层不应该使用输出范围有限的激活函数。例如,线性激活函数应该有效。
这里有一个简单的回归示例,由 pybrain 的基本组件构建而成:
#----------
# build the dataset
#----------
from pybrain.datasets import SupervisedDataSet
import numpy, math

xvalues = numpy.linspace(0,2 * math.pi, 1001)
yvalues = 5 * numpy.sin(xvalues)

ds = SupervisedDataSet(1, 1)
for x, y in zip(xvalues, yvalues):
    ds.addSample((x,), (y,))

#----------
# build the network
#----------
from pybrain.structure import SigmoidLayer, LinearLayer
from pybrain.tools.shortcuts import buildNetwork

net = buildNetwork(1,
                   100, # number of hidden units
                   1,
                   bias = True,
                   hiddenclass = SigmoidLayer,
                   outclass = LinearLayer
                   )
#----------
# train
#----------
from pybrain.supervised.trainers import BackpropTrainer
trainer = BackpropTrainer(net, ds, verbose = True)
trainer.trainUntilConvergence(maxEpochs = 100)

#----------
# evaluate
#----------
import pylab
# neural net approximation
pylab.plot(xvalues,
           [ net.activate([x]) for x in xvalues ], linewidth = 2,
           color = 'blue', label = 'NN output')

# target function
pylab.plot(xvalues,
           yvalues, linewidth = 2, color = 'red', label = 'target')

pylab.grid()
pylab.legend()
pylab.show()

顺带一提(因为在您的代码示例中,您有一个使用线性激活函数的隐藏层):在线性层中使用线性函数是没有用处的,因为:

  • 输入到此层的权重形成了线性变换
  • 激活函数是线性的
  • 输出到此层的权重形成了线性变换

这可以被简化为单个线性变换,即相应的层可以被消除而不会减少可以逼近的函数集。神经网络的一个重要点是隐藏层中的激活函数是非线性的。


0
正如Andre Holzner所解释的那样,隐藏层应该是非线性的。Andre的代码示例很棒,但是当您拥有更多特征而数据不够充足时,它的效果并不好。在这种情况下,由于隐藏层较大,我们得到了相当不错的近似值,但是当您处理更复杂的数据时,仅使用输出层中的线性函数是不够的,您应该将特征和目标归一化到[0..1]范围内。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接