经过神经网络解决多分类问题时,最经常使用的一种方式就是在最后一层设置n个输出节点,不管在浅层神经网络仍是在CNN中都是如此,好比,在AlexNet中最后的输出层有1000个节点:
而即使是ResNet取消了全链接层,也会在最后有一个1000个节点的输出层:
git
通常状况下,最后一个输出层的节点个数与分类任务的目标数相等。假设最后的节点数为N,那么对于每个样例,神经网络能够获得一个N维的数组做为输出结果,数组中每个维度会对应一个类别。在最理想的状况下,若是一个样本属于k,那么这个类别所对应的的输出节点的输出值应该为1,而其余节点的输出都为0,即[0,0,1,0,….0,0],这个数组也就是样本的Label,是神经网络最指望的输出结果,交叉熵就是用来断定实际的输出与指望的输出的接近程度!数组
神经网络的原始输出不是一个几率值,实质上只是输入的数值作了复杂的加权和与非线性处理以后的一个值而已,那么如何将这个输出变为几率分布?
这就是Softmax层的做用,假设神经网络的原始输出为y1,y2,….,yn,那么通过Softmax回归处理以后的输出为:
很显然的是:
而单个节点的输出变成的一个几率值,通过Softmax处理后结果做为神经网络最后的输出。网络
交叉熵刻画的是实际输出(几率)与指望输出(几率)的距离,也就是交叉熵的值越小,两个几率分布就越接近。假设几率分布p为指望输出,几率分布q为实际输出,H(p,q)为交叉熵,则:函数
这个公式如何表征距离呢,举个例子:
假设N=3,指望输出为p=(1,0,0),实际输出q1=(0.5,0.2,0.3),q2=(0.8,0.1,0.1),那么:spa
很显然,q2与p更为接近,它的交叉熵也更小。
除此以外,交叉熵还有另外一种表达形式,仍是使用上面的假设条件:3d
其结果为:code
以上的全部说明针对的都是单个样例的状况,而在实际的使用训练过程当中,数据每每是组合成为一个batch来使用,因此对用的神经网络的输出应该是一个m*n的二维矩阵,其中m为batch的个数,n为分类数目,而对应的Label也是一个二维矩阵,仍是拿上面的数据,组合成一个batch=2的矩阵:blog
因此交叉熵的结果应该是一个列向量(根据第一种方法):
而对于一个batch,最后取平均为0.2。图片
在TensorFlow能够采用这种形式:ip
cross_entropy = -tf.reduce_mean(y_ * tf.log(tf.clip_by_value(y, 1e-10, 1.0)))
其中y_表示指望的输出,y表示实际的输出(几率值),*为矩阵元素间相乘,而不是矩阵乘。
上述代码实现了第一种形式的交叉熵计算,须要说明的是,计算的过程其实和上面提到的公式有些区别,按照上面的步骤,平均交叉熵应该是先计算batch中每个样本的交叉熵后取平均计算获得的,而利用tf.reduce_mean函数其实计算的是整个矩阵的平均值,这样作的结果会有差别,可是并不改变实际意义。
除了tf.reduce_mean函数,tf.clip_by_value函数是为了限制输出的大小,为了不log0为负无穷的状况,将输出的值限定在(1e-10, 1.0)之间,其实1.0的限制是没有意义的,由于几率怎么会超过1呢。
因为在神经网络中,交叉熵经常与Sorfmax函数组合使用,因此TensorFlow对其进行了封装,即:
cross_entropy = tf.nn.sorfmax_cross_entropy_with_logits(y_ ,y)
与第一个代码的区别在于,这里的y用神经网络最后一层的原始输出就行了。