Machine Learning
  • Introduction
  • 机器学习
    • 前言
      • 符号表
    • 监督式学习
      • 感知机
        • 感知机模型
        • 感知机学习算法
        • 算法python实现
      • Logistic回归
        • Logistic分布
        • Logistic回归模型
        • 算法python实现
      • 线性回归
        • 线性回归模型
        • 算法python实现
      • K近邻法
        • k近邻模型
        • kd树方法
        • kd树python实现
        • knn实例
      • 朴素贝叶斯法
        • 模型和原理
        • 参数估计
        • 算法和实现
      • 决策树
        • 模型与学习
        • 特征选择
        • 生成算法和剪枝
        • python实现
      • 支持向量机
    • 神经网络
      • 神经元模型和感知机
      • 神经网络
      • 神经网络的矩阵表达
      • 反向传播算法
        • 算法证明
        • 算法代码
        • 基于矩阵的计算
      • 改进神经网络的学习方法
        • 交叉熵代价函数
        • softmax
        • regularization
        • 权重初始化
      • 卷积神经网络
        • 基本介绍
    • 数学基础
      • 线性代数
        • 特征值和特征向量
      • 概率统计
        • 随机变量的特征
        • 样本统计量
        • 先验后验概率
      • 微积分
        • 向量内积
        • 方向导数和梯度
        • 梯度下降法
      • 信息论
        • 熵
        • 相对熵和交叉熵
        • 条件熵
        • 互信息
Powered by GitBook
On this page
  • 二次代价函数的问题
  • 引入交叉熵代价函数
  • 改进交叉熵函数代码
  1. 机器学习
  2. 神经网络
  3. 改进神经网络的学习方法

交叉熵代价函数

Previous改进神经网络的学习方法Nextsoftmax

Last updated 6 years ago

二次代价函数的问题

当使用二次代价函数的时候,

C=(y−a)22C=\frac{(y-a)^2}{2}C=2(y−a)2​

其中aaa时神经元的输出,a=σ(z)a=\sigma(z)a=σ(z),其中z=wx+bz=wx+bz=wx+b。这时计算偏导数

∂C∂w=(a−y)σ′(z)x\frac{\partial C}{\partial w}= (a-y)\sigma'(z)x∂w∂C​=(a−y)σ′(z)x
∂C∂b=(a−y)σ′(z)\frac{\partial C}{\partial b}=(a-y)\sigma'(z)∂b∂C​=(a−y)σ′(z)

我们来看一下sigmoidsigmoidsigmoid函数的图形

引入交叉熵代价函数

定义交叉熵代价函数:

同样的,我们可以得到关于偏置的偏导数

交叉熵函数扩展到多神经元的多层神经网络上

那么我们应该在什么时候用交叉熵来替换二次代价函数?

实际上,如果输出神经元是S型时,交叉熵函数一般都是更好的选择。为什么?考虑一下我们初始化网络的权重和偏置时,通常使用某种随机方法。可能会发生这样的情况,这些初始选择会对某些训练输入的误差相当明显,比如说,目标输出是1,而实际值是0,或者完全反过来。如果使用二次代价函数,那么就会导致学习速度下降。

改进交叉熵函数代码

class QuadraticCost(object):

    @staticmethod
    def fn(a, y):
        """Return the cost associated with an output ``a`` and desired output
        ``y``.

        """
        return 0.5*np.linalg.norm(a-y)**2

    @staticmethod
    def delta(z, a, y):
        """Return the error delta from the output layer."""
        return (a-y) * sigmoid_prime(z)


class CrossEntropyCost(object):

    @staticmethod
    def fn(a, y):
        """Return the cost associated with an output ``a`` and desired output
        ``y``.  Note that np.nan_to_num is used to ensure numerical
        stability.  In particular, if both ``a`` and ``y`` have a 1.0
        in the same slot, then the expression (1-y)*np.log(1-a)
        returns nan.  The np.nan_to_num ensures that that is converted
        to the correct value (0.0).

        """
        return np.sum(np.nan_to_num(-y*np.log(a)-(1-y)*np.log(1-a)))

    @staticmethod
    def delta(z, a, y):
        """Return the error delta from the output layer.  Note that the
        parameter ``z`` is not used by the method.  It is included in
        the method's parameters in order to make the interface
        consistent with the delta method for other cost classes.

        """
        return (a-y)

其中 QuadraticCost 是二次代价函数,CrossEntropyCost 是交叉熵代价函数。

从图中可以看出,当神经元的输出接近于1的时候,曲线变得相当平,所以σ′(z)\sigma'(z)σ′(z)就很小,于是∂C∂w\frac{\partial C}{\partial w}∂w∂C​和∂C∂b\frac{\partial C}{\partial b}∂b∂C​也会很小,这个会导致在梯度下降过程中学习变得缓慢。

C=−1n∑x[ylna+(1−y)ln(1−a))]C= -\frac{1}{n}\displaystyle\sum_{x}[y\mathrm{ln}a+(1-y)\mathrm{ln}(1-a))]C=−n1​x∑​[ylna+(1−y)ln(1−a))]

交叉熵有一个比代价函数更好的特性就是它避免了学习速度下降的问题。 我们来计算交叉熵函数的偏导数,将a=σ(z)a = \sigma(z)a=σ(z) 代入上式,并求偏导数

∂C∂wj=−1n∑x(yσ(z)−1−y1−σ(z))∂σ(z)∂wj\frac{\partial C}{\partial w_j}= -\frac{1}{n}\displaystyle\sum_{x}\big(\frac{y}{\sigma(z)}-\frac{1-y}{1-\sigma(z)}\big)\frac{\partial \sigma(z)}{\partial w_j}∂wj​∂C​=−n1​x∑​(σ(z)y​−1−σ(z)1−y​)∂wj​∂σ(z)​
=−1n∑x(yσ(z)−1−y1−σ(z))σ′(z)xj=-\frac{1}{n}\displaystyle\sum_{x}\big(\frac{y}{\sigma(z)}-\frac{1-y}{1-\sigma(z)}\big)\sigma'(z)x_j=−n1​x∑​(σ(z)y​−1−σ(z)1−y​)σ′(z)xj​
=−1n∑xσ(z)−yσ(z)(1−σ(z))σ′(z)xj=-\frac{1}{n}\displaystyle\sum_{x}\frac{\sigma(z)-y}{\sigma(z)(1-\sigma(z))}\sigma'(z)x_j=−n1​x∑​σ(z)(1−σ(z))σ(z)−y​σ′(z)xj​

其中σ(z)=11+e−x\sigma(z)=\frac{1}{1+e^{-x}}σ(z)=1+e−x1​,计算可得σ′(z)=σ(z)(1−σ(z))\sigma'(z)=\sigma(z)(1-\sigma(z))σ′(z)=σ(z)(1−σ(z)),于是得到

∂C∂wj=−1n∑x(σ(z)−y)xj\frac{\partial C}{\partial w_j}=-\frac{1}{n}\displaystyle\sum_{x}(\sigma(z)-y)x_j∂wj​∂C​=−n1​x∑​(σ(z)−y)xj​

这里权重的学习速度受到σ(z)−y\sigma(z)-yσ(z)−y的影响,也就是输出中的误差的控制。更大的误差会有更大的学习速度。

∂C∂b=−1n∑x(σ(z)−y)\frac{\partial C}{\partial b}=-\frac{1}{n}\displaystyle\sum_{x}(\sigma(z)-y)∂b∂C​=−n1​x∑​(σ(z)−y)

假设y=y1,y2,...y=y1,y2,...y=y1,y2,...是输出神经元上的目标值,而a1L,a2L,...a^L_1,a^L_2,...a1L​,a2L​,...时实际的输出值,那么我们定义交叉熵如下

C=−1n∑x∑y[yjlnajL+(1−yj)ln(1−ajL))]C= -\frac{1}{n}\displaystyle\sum_{x}\displaystyle\sum_{y}[y_j\mathrm{ln}a^L_j+(1-y_j)\mathrm{ln}(1-a^L_j))]C=−n1​x∑​y∑​[yj​lnajL​+(1−yj​)ln(1−ajL​))]