为什么我的多层感知器只能线性分类?

数据挖掘 机器学习 分类 神经网络
2022-02-15 07:37:56

我用 Python 写了一个多层感知器。我试图让它做非线性分类。它有两个隐藏层,所以它应该是完全有能力的。不幸的是,它似乎只能线性分类。我不愿称其为“欠拟合”,因为我尚未正确实现非线性分类,甚至是欠拟合的非线性分类。在下图中,我尝试对正弦函数上方和下方的点进行分类,但它只是在数据集上画了一条直线。

不确定点(输出约为 0.5)为黄色。

我使用 sigmoid 作为激活函数,很简单1/(1+((math.e) ** (-sum)))

我使用两个输入节点,两个隐藏层中的二十个隐藏节点(每个十个)和一个输出节点。我对每个隐藏层和输出节点都有一个偏差。我的输入没有标准化。

我前馈数百个随机点并计算输出和期望之间的差异。我计算均方误差并在每一代进化算法中保持最低均方误差。我不会在这里展示它,因为它似乎可以很好地降低错误,尽管我的 MSE 函数可能不正确。

d=0
error = 0
while d < (tPoints): # while all the points in the list have not been feedforwarded
    output1 = feedForward(n, [xValsAbove[d], yValsAbove[d]]) # feedforwards a point above the function, returns output (0,1)
    output2 = feedForward(n, [xValsBelow[d], yValsBelow[d]]) # feedforwards a point below the function, returns output (0,1)

    if output1 < 0.99:
        error += (output1)**2
    if output2 > 0.01:
        error += (1-output2)**2
    d+=1
error = error/tPoints
return error # return mean-squared error

我的神经元做线性回归线就好了。因为我有一个有几层的 MLP,所以我写了一个前馈算法。它只是将前一层的输出作为下一层的输入。

def feedForward(n, inputs): # (inputs, inputList, hidden1, hidden2, outputs, bias):

    inputList = n.getNeuronList()[0]
    hidden1 = n.getNeuronList()[1]
    hidden2 = n.getNeuronList()[2]
    outputs = n.getNeuronList()[3]
    bias = n.getNeuronList()[4]

    FFInputs = []
    FFHidden1 = []
    FFHidden2 = []
    FFOutputs = []

    for inp in inputList:
        FFInputs.append(inp.feedForward(inp.getWeights(), inp.getInputs()))
    for hidden in hidden1:
        FFHidden1.append(hidden.feedForward(hidden.getWeights(), FFInputs, bias[0]))
    for hidden in hidden2:
        FFHidden2.append(hidden.feedForward(hidden.getWeights(), FFHidden1, bias[1]))
    for out in outputs:
        FFOutputs.append(out.feedForward(out.getWeights(), FFHidden2, bias[2]))

    return FFOutputs

失败

用 matplotlib 完成的图形。

有人工神经网络经验的人知道为什么会这样做吗?我应该只使用一层吗?我正在用进化算法进化权重,所以我应该做更多代吗?我应该使用不同的激活函数吗?

1个回答

您的错误计算看起来错误:

if output1 < 0.99:
    error += (output1)**2
if output2 > 0.01:
    error += (1-output2)**2

如果我没看错,那么 output1 = 1.0 是一个正确的分类,因为您将任何高于 0.99 的值都视为没有错误。但是,您随后将平方误差测量为output1 ** 20.99,这意味着最大误差为 0.99。这会使网络感到困惑,如果得分 > 0.99,它将把线以上的分类视为完美的 1.0,或者想要调整权重以使分类为 0.0。对线下的得分情况正好相反。

你需要要么

  1. 交换条件(更改< 0.99> 0.01,反之亦然)

或者

  1. 替换(output1)(1-output1)(1-output2)_(output2)

为了使逻辑自洽。您选择哪个取决于线上方的点是正类还是负类。如果线上为正,则应使用选项 2。

此外,正如评论所指出的,您的方法可能有点雄心勃勃。我发现以下使您的工作变得更加困难的事情:

  • 使用遗传算法搜索。虽然可以使用 GA 训练像您这样的小型 NN,但效率较低。GA 可能是控制系统或生命场景的不错选择,但远远落后于监督学习的前沿。

  • 使用均方误差度量进行分类。您应该使用logloss,它会更严重地惩罚错误的猜测。使用均方误差,如果网络也得到一些其他合理的错误分类,则网络更有可能解决一些错误的错误分类。

  • 雄心勃勃的功能分离。神经网络应该能够对你的函数进行分类,但对于一个起始问题来说,这是一个很大的曲率。开始时将其减少到几个周期应该可以帮助您调试实际问题。

  • 没有输入标准化。这可能会导致网络中的值饱和——接近 1.0 或 0.0,从而很难区分权重的好坏。你没有显示你的权重初始化 - 大的初始权重也会导致这种效果(尽管在这里使用 GA 实际上可能会有所帮助,这取决于你如何改变权重)。