多层感知器总是选择它最后训练指定的类别。反向传播

我正在尝试编写一个MLP来将输入分类为三个对象。我用一个数字来表示每个对象。

1-10 : 香蕉11-20 : 苹果21-30 : 胡萝卜

MLP只有两层:一个隐藏层(2个单元)和一个输出层(3个单元)。
每个单元具有以下属性:

  • inputs[](传递给该单元的输入)
  • weights[]
  • delta
  • sum(输入与权重的加权和)
  • output(激活后的和)

每个单元还有一个激活函数:

double activate(double[] inputs) {        this.inputs = inputs;        sum = 0;        for (int i = 0; i < inputs.length; i++)            sum += weights[i] * inputs[i];        output = 1.0 / (1.0 + (Math.exp(-sum))); // 激活        return output;    }

还有一个用于修正权重的函数:

void correctWeights(double momentum, double learningRate) {        for (int i = 0; i < weights.length; i++) {            weights[i] = weights[i] * momentum + learningRate * delta * (output * (1 - output)) * inputs[i];        }    }

其中 (output * (1 - output)) 是导数。

为了训练网络,我有一个函数,它会循环N次,在循环中我会生成与对象相关的输入,然后将其传播到网络中并使用反向传播。

private void train() {        for (int i = 0; i < 10000; i++) {            int[] expectedOutput = new int[3];            double[] inputs = {ThreadLocalRandom.current().nextInt(1, 30 + 1)};            if (inputs[0] <= 10) {                expectedOutput[0] = 1;                expectedOutput[1] = 0;                expectedOutput[2] = 0;            }            if (inputs[0] <= 20 && inputs[0] > 10) {                expectedOutput[0] = 0;                expectedOutput[1] = 1;                expectedOutput[2] = 0;            }            if (inputs[0] <= 30 && inputs[0] > 20) {                expectedOutput[0] = 0;                expectedOutput[1] = 0;                expectedOutput[2] = 1;            }            double[] outputs = propagate(inputs);            backPropagate(expectedOutput, outputs);        }    }

传播函数只是通过整个网络并激活单元。

private double[] propagate(double[] inputs) {        double[] hiddenOutputs = new double[hiddenLayer.length];        for (int i = 0; i < hiddenLayer.length; i++)            hiddenOutputs[i] = hiddenLayer[i].activate(inputs);        double[] outputs = new double[outputLayer.length];        for (int i = 0; i < outputs.length; i++)            outputs[i] = outputLayer[i].activate(hiddenOutputs);        return outputs;    }

反向传播算法取自 http://home.agh.edu.pl/~vlsi/AI/backp_t_en/backprop.html

private void backPropagate(int[] expectedOutput, double[] output) {        for (int i = 0; i < outputLayer.length; i++) {            outputLayer[i].setDelta(expectedOutput[i] - output[i]);        }        for (int i = 0; i < hiddenLayer.length; i++) {            double delta = 0;            for (int j = 0; j < outputLayer.length; j++) {                delta += outputLayer[j].getDelta() * outputLayer[j].getWeight(i);            }            hiddenLayer[i].setDelta(delta);        }        for (int i = 0; i < hiddenLayer.length; i++)            hiddenLayer[i].correctWeights(momentum, learningRate);        for (int i = 0; i < outputLayer.length; i++)            outputLayer[i].correctWeights(momentum, learningRate);    }

它还具有在训练后识别对象的功能

private void recognize(String number) {        double[] inputs = {Double.parseDouble(number)};        double[] outputs = propagate(inputs);        System.out.println("香蕉: " + outputs[0]);        System.out.println("苹果: " + outputs[1]);        System.out.println("胡萝卜: " + outputs[2]);    }

所以问题是,当我将任何数字传递给recognize函数时,我得到的输出类似于这样:

香蕉: 0.49984367018594233苹果: 0.49984367018594233胡萝卜: 0.5001563298140577

每次都选择胡萝卜(胡萝卜也是网络最后训练的对象)。所以如果我输入5,它会输出这是胡萝卜。如果我输入15,它会输出这是胡萝卜。如果我在train函数中更改学习对象的顺序,使香蕉成为最后学习的对象,那么网络将始终选择香蕉作为答案。

我已经为此工作了几天了,我找不到任何解决方案,请帮助我,我做错了什么?


回答:

我注意到您选择了一个0到30之间的随机数,然后为它确定一个输出,但是您忘记了对输入进行归一化。神经网络在输入范围在0-1之间时(取决于您使用的激活函数)表现最佳。

所以您需要做的就是对输入进行归一化。这意味着,将输入等比例转换为01之间的数字。

您的输入是一个数值,所以您所要做的就是选择一个最大值,并用它来除以所有值。在您的案例中,这可以是30,因为没有输入高于30。所以每个数字的转换如下:

10 -> 10 / 30 -> 0.3315 -> 15 / 30 -> 0.50etc.

关于归一化的更多信息,请阅读这里

Related Posts

L1-L2正则化的不同系数

我想对网络的权重同时应用L1和L2正则化。然而,我找不…

使用scikit-learn的无监督方法将列表分类成不同组别,有没有办法?

我有一系列实例,每个实例都有一份列表,代表它所遵循的不…

f1_score metric in lightgbm

我想使用自定义指标f1_score来训练一个lgb模型…

通过相关系数矩阵进行特征选择

我在测试不同的算法时,如逻辑回归、高斯朴素贝叶斯、随机…

可以将机器学习库用于流式输入和输出吗?

已关闭。此问题需要更加聚焦。目前不接受回答。 想要改进…

在TensorFlow中,queue.dequeue_up_to()方法的用途是什么?

我对这个方法感到非常困惑,特别是当我发现这个令人费解的…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注