我如何在反向传播中采用softmax输出的导数

时间:2019-08-23 18:39:59

标签: java machine-learning backpropagation derivative softmax

因此,我是ML的新手,并试图创建一个简单的“库”,以便我可以了解有关神经网络的更多信息。

我的问题: 根据我的理解,我必须根据它们的激活函数取每一层的导数,以便我可以计算它们的增量并调整它们的权重等。

对于ReLU,Sigmoid,tanh,使用Java(这是我使用的BTW语言)实现它们非常简单

但是要从输出转到输入,我必须(显然)从具有softmax激活功能的输出开始。

那么我是否也必须采用输出层的导数,或者它仅适用于其他所有层?

如果必须获取派生类,如何在Java中实现派生类? 谢谢。

我已经阅读了很多关于softmax算法导数的页面,但是对我来说它们确实很复杂,正如我所说的,我刚刚开始学习ML,我不想使用现成的图书馆所以我在这里。

这是我存储激活函数的类。

public class ActivationFunction {

    public static double tanh(double val) {
        return Math.tanh(val);
    }

    public static double sigmoid(double val) {
        return 1 / 1 + Math.exp(-val);
    }

    public static double relu(double val) {
        return Math.max(val, 0);
    }

    public static double leaky_relu(double val) {
        double result = 0;
        if (val > 0) result = val;
        else result = val * 0.01;
        return result;
    }

    public static double[] softmax(double[] array) {
        double max = max(array);
        for (int i = 0; i < array.length; i++) {
            array[i] = array[i] - max;
        }

        double sum = 0;
        double[] result = new double[array.length];
        for (int i = 0; i < array.length; i++) {
            sum += Math.exp(array[i]);
        }
        for (int i = 0; i < result.length; i++) {
            result[i] = Math.exp(array[i]) / sum;
        }
        return result;
    }

    public static double dTanh(double x) {
        double tan = Math.tanh(x);
        return (1 / tan) - tan;
    }

    public static double dSigmoid(double x) {
        return x * (1 - x);
    }

    public static double dRelu(double x) {
        double result;
        if (x > 0) result = 1;
        else result = 0;
        return result;
    }

    public static double dLeaky_Relu(double x) {
        double result;
        if (x > 0) result = 1;
        else if (x < 0) result = 0.01;
        else result = 0;
        return result;
    }

    private static double max(double[] array) {
        double result = Double.MIN_VALUE;
        for (int i = 0; i < array.length; i++) {
            if (array[i] > result) result = array[i];
        }
        return result;
    }
}

我期望得到以下问题的答案:是否需要softmax的派生词? 如果可以,该如何实施?

1 个答案:

答案 0 :(得分:0)

第一个问题的简短答案是 ,您需要计算softmax的导数。

较长的版本将涉及一些计算,因为要实现反向传播,您需要借助一阶优化算法来训练网络,该算法需要计算权重不等于成本函数的偏导数,即:

enter image description here

但是 ,由于您在最后一层使用softmax,因此很有可能在训练神经网络时将优化交叉熵代价函数网络,即:

enter image description here

其中 t j 是目标值, a j 是类 j 的softmax结果。

Softmax本身代表 n 类上的概率分布:

enter image description here

其中所有 z 都是前一层激活函数的结果与相应权重的简单和:

enter image description here

其中 n 是层数, i 是前一层的神经元数, j 是我们softmax层中神经元的数量。

因此,为了对这些权重中的任何一个取偏导数,应该计算:

enter image description here

其中二阶导数 ∂a k /∂z j 确实是softmax导数,可以是计算方法如下:

enter image description here

但是 ,如果您尝试计算上述成本函数w.r.t的导数之和项。重量,您将得到:

enter image description here enter image description here enter image description here

因此,在这种特殊情况下,结果是计算的最终结果非常整洁,并且代表了网络输出与目标值之间的简单差异,仅此而已,即,您需要计算出的总和偏导数的项就是:

enter image description here

因此,要回答您的第二个问题,您可以将交叉熵成本函数w.r.t输出激活的偏导数(即softmax)的计算与输出激活w.r.t的偏导数结合起来。 z j 会导致实现简短明了,如果您使用的是非矢量化形式,则将如下所示:

for (int i = 0; i < lenOfClasses; ++i)
{
    dCdz[i] = t[i] - a[i];
}

随后,您可以使用 dCdz 向后传播到神经网络的其余层。