java - sigmoid 的单神经元 delta 规则收敛

标签 java machine-learning neural-network

我正在尝试使用 AND 示例进行 delta 规则学习,并且我注意到,当我在权重校正中应用 sigmoid 激活的导数时,学习收敛得更快更好.

我正在使用偏差神经元。

如果我理解正确的话,delta规则应该考虑激活函数的导数来进行权重调整: Δ Wk(n) = η*𝑒(𝑛)*𝑔′(ℎ)*𝑥(𝑛) .

其中 e(n) =desired_output - 神经元输出。

这是我用来计算输出的 sigmoid:

public double calc(double sum) {
    return 1 / (1 + Math.pow(Math.E, -sum));
}

根据此 dela rule 第 33 页第 4 步,权重更新应为:

double delta = learningRate * error * estimated * (1 - estimated) * input; 

如果没有以下内容,效果会更好:

estimated * (1 - estimated)

这几乎是使用增量规则进行训练的代码:

@Override
public void train(List<LearningSample> samples, double[] weights, Function<double[], Double> neuronOutput) {

    double[] weightDelta = new double[weights.length];
    for (int i = 0; i < 10000; i++) {
        // Collections.shuffle(samples);
        for (LearningSample sample : samples) {
            // sigmoid of dot product of weights and input vector, including bias
            double estimated = neuronOutput.apply(sample.getInput());
            double error = sample.getDesiredOutput() - estimated;
            // this commented out version actually works better than the one bellow
            // double delta = learningRate * error;
            double delta = learningRate * error * estimated * (1 - estimated);
            // aggregate delta per weight for each sample in epoch
            deltaUpdate(delta, weightDelta, sample.getInput());
        }

        // batch update weights at the end of training epoch
        for (int weight = 0; weight < weights.length; weight++) {
            weights[weight] += weightDelta[weight];
        }

        weightDelta = new double[weights.length];
    }      
}


private void deltaUpdate(double delta, double[] weightsDelta, double[] input) {
    for (int feature = 0; feature < input.length; feature++) {
        weightsDelta[feature] = weightsDelta[feature] + delta * input[feature];
    }
}

AND 的训练样本如下所示:

List<LearningSample> samples = new ArrayList<>();
LearningSample sample1 = new LearningSample(new double[] { 0, 0 }, 0);
LearningSample sample2 = new LearningSample(new double[] { 0, 1 }, 0);
LearningSample sample3 = new LearningSample(new double[] { 1, 0 }, 0);
LearningSample sample4 = new LearningSample(new double[] { 1, 1 }, 1);

偏差1作为构造函数中的第0个组件注入(inject)。

学习后测试输出的顺序:

System.out.println(neuron.output(new double[] { 1,   1, 1 }));
System.out.println(neuron.output(new double[] { 1,   0, 0 }));
System.out.println(neuron.output(new double[] { 1,   0, 1 }));
System.out.println(neuron.output(new double[] { 1,   1, 0 }));

这是我在 delta 计算中省略 sigmoid 导数时的结果:

10000 次迭代

  • 0.9666565909058419
  • 2.05087653022386E-5
  • 0.023803593411627456
  • 0.023803593411627456

35000 次迭代

  • 0.9903810162649429
  • 4.6475933225663785E-7
  • 0.006870001301253153
  • 0.006870001301253153

这些是应用导数的结果:

10000 次迭代

  • 0.8446651307271656
  • 0.004030424878725242
  • 0.129178264332045
  • 0.129178264332045

35000 次迭代

  • 0.9218773156128204
  • 4.169603485934177E-4
  • 0.06555977437019253
  • 0.06555977437019253

学习率为:0.021,偏置起始权重为:-2。

在第一个没有导数的例子中,误差更小,函数的逼近效果更好。 这是为什么?

更新

根据@Umberto 的回答,我想验证以下几件事:

  • 事故实验(其中delta =learningRate * error * input)实际上是有效的,因为这可以最小化交叉熵成本函数?

  • 交叉熵显然更适合分类,那么什么时候应该使用 MSE 作为成本函数呢? 回归

请注意,我正在通过阈值函数运行输出,只是此处未显示,因此这是二元分类。

最佳答案

原因很简单。您可以最小化不同的成本函数。在您的情况下(如幻灯片所示),您可以最小化误差平方。如果您使用我在此处的推导中描述的形式的成本函数(交叉熵)github link ,您将获得更快的权重更新。通常在分类问题中(通常使用 S 形神经元进行二元分类),平方误差实际上并不是一个好的成本函数。

如果您使用交叉熵,则需要使用learningRate * error * input;(根据您定义错误的方式,使用正确的符号)。

作为旁注,您实际上在做的是逻辑回归......

希望有帮助。如果您需要更多信息,请告诉我。检查我的链接,在那里我对其背后的数学进行了完整的推导。

关于java - sigmoid 的单神经元 delta 规则收敛,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46217098/

相关文章:

python - 如何使虚拟生物学习使用神经网络?

java - 为计时器创建 ActionListener

java - java中如何合并2个对象

python - 错误节点: 'binary_crossentropy/Cast' Cast string to float is not supported while train model

python - 小图像分类任务的 Conv2d 层和滤波器的数量

neural-network - 当我在 tensorflow 中对神经网络进行批量评估而不是一一评估时,我得到了不同的结果,这是怎么回事?

java - 使用 Java Controller 类和自定义控件属性

java - struts2:IF 中的枚举

python - 进行 Leave-One-Group-Out 交叉验证时如何应用过采样?

python - `` `AttributeError: ' 模块 ' object has no attribute ' set_random_seed '` `` 当我从终端运行 `` `python2 ./train.py` ``