1. softmax层的作用

通过神经网络解决多分类问题时,最常用的一种方式就是在最后一层设置n个输出节点,无论在浅层神经网络还是在CNN中都是如此,比如,在AlexNet中最后的输出层有1000个节点,即便是ResNet取消了全连接层,但1000个节点的输出层还在。

一般情况下,最后一个输出层的节点个数与分类任务的目标数相等。
假设最后的节点数为N,那么对于每一个样例,神经网络可以得到一个N维的数组作为输出结果,数组中每一个维度会对应一个类别。在最理想的情况下,如果一个样本属于k,那么这个类别所对应的的输出节点的输出值应该为1,而其他节点的输出都为0,即 [0,0,1,0,….0,0][0,0,1,0,….0,0][0,0,1,0,….0,0],这个数组也就是样本的Label,是神经网络最期望的输出结果,但实际是这样的输出[0.01,0.01,0.6,....0.02,0.01][0.01,0.01,0.6,....0.02,0.01][0.01,0.01,0.6,....0.02,0.01],这其实是在原始输出的基础上加入了softmax的结果,原始的输出是输入的数值做了复杂的加权和与非线性处理之后的一个值而已,这个值可以是任意的值,但是经过softmax层后就成了一个概率值,而且概率和为1。
假设神经网络的原始输出为y_1,y_2,….,y_n,那么经过Softmax回归处理之后的输出为 :

y′=softmax(yi)=eyi∑nj=1eyjy′=softmax(yi)=eyi∑j=1neyj

y'=softmax(y_i)=\frac{e^{y_{i}}}{\sum_{j=1}^{n}e^{y_{j} }}
以上可以看出: ∑y′=1∑y′=1\sum y'=1
这也是为什么softmax层的每个节点的输出值成为了概率和为1的概率分布。

2. 交叉熵损失函数的数学原理

上面说过实际的期望输出,也就是标签是[0,0,1,0,….0,0][0,0,1,0,….0,0][0,0,1,0,….0,0]这种形式,而实际的输出是[0.01,0.01,0.6,....0.02,0.01][0.01,0.01,0.6,....0.02,0.01][0.01,0.01,0.6,....0.02,0.01]这种形式,这时按照常理就需要有一个损失函数来判定实际输出和期望输出的差距,交叉熵就是用来判定实际的输出与期望的输出的接近程度!下面就简单介绍下交叉熵的原理。

交叉熵刻画的是实际输出(概率)与期望输出(概率)的距离,也就是交叉熵的值越小,两个概率分布就越接近。假设概率分布p为期望输出(标签),概率分布q为实际输出,H(p,q)为交叉熵。

  • 第一种交叉熵损失函数的形式:

    H(p,q)=−∑xp(x)logq(x)H(p,q)=−∑xp(x)logq(x)

    H(p,q)=-\sum _x p(x)log q(x)

举个例子:
假设N=3,期望输出为p=(1,0,0),实际输出q1=(0.5,0.2,0.3),q2=(0.8,0.1,0.1)q1=(0.5,0.2,0.3),q2=(0.8,0.1,0.1)q_1=(0.5,0.2,0.3),q_2=(0.8,0.1,0.1),这里的q1,q2两个输出分别代表在不同的神经网络参数下的实际输出,通过计算其对应的交叉熵来优化神经网络参数,计算过程:
H(p,q1)=−1(1×log0.5+0×log0.2+0×log0.3)H(p,q1)=−1(1×log0.5+0×log0.2+0×log0.3)H(p,q_1)=-1(1\times log^{0.5}+0\times log^{0.2}+0\times log^{0.3})
假设结果:H(p,q1)=0.3H(p,q1)=0.3H(p,q_1)=0.3
H(p,q2)=−1(1×log0.8+0×log0.1+0×log0.1)H(p,q2)=−1(1×log0.8+0×log0.1+0×log0.1)H(p,q_2)=-1(1\times log^{0.8}+0\times log^{0.1}+0\times log^{0.1})
假设结果:H(p,q2)=0.1H(p,q2)=0.1H(p,q_2)=0.1
这时得到了q2q2q_2是相对正确的分类结果。

  • 第二种交叉熵损失函数形式:

    H(p,q)=−∑x(p(x)logq(x)+(1−p(x))log(1−q(x)))H(p,q)=−∑x(p(x)logq(x)+(1−p(x))log(1−q(x)))

    H(p,q)=-\sum _x (p(x)logq(x)+(1-p(x))log(1-q(x)))
    下面简单推到其过程:
    我们知道,在二分类问题模型:例如逻辑回归「Logistic Regression」、神经网络「Neural Network」等,真实样本的标签为 [0,1],分别表示负类和正类。模型的最后通常会经过一个 Sigmoid 函数,输出一个概率值,这个概率值反映了预测为正类的可能性:概率越大,可能性越大。
    Sigmoid 函数的表达式和图形如下所示:g(s)=11+e−sg(s)=11+e−sg(s)=\frac{1}{1+e^{-s}}
    其中 s 是模型上一层的输出,Sigmoid 函数有这样的特点:s = 0 时,g(s) = 0.5;s >> 0 时, g ≈ 1,s << 0 时,g ≈ 0。显然,g(s) 将前一级的线性输出映射到 [0,1] 之间的数值概率上。
    其中预测输出即 Sigmoid 函数的输出g(s)表征了当前样本标签为 1 的概率:
    P(y=1|x)=ŷ P(y=1|x)=y^P(y=1|x)=\hat y
    p(y=0|x)=1−ŷ p(y=0|x)=1−y^p(y=0|x)=1-\hat y
    这个时候从极大似然性的角度出发,把上面两种情况整合到一起:
    p(y|x)=ŷ y(1−ŷ )(1−y)p(y|x)=y^y(1−y^)(1−y)p(y|x)=\hat y^y(1-\hat y)^{(1-y)}
    这个函数式表征的是:
    当真实样本标签 y = 1 时,上面式子第二项就为 1,概率等式转化为:
    P(y=1|x)=ŷ P(y=1|x)=y^P(y=1|x)=\hat y
    当真实样本标签 y = 0 时,上面式子第一项就为 1,概率等式转化为:
    P(y=0|x)=1−ŷ P(y=0|x)=1−y^P(y=0|x)=1−\hat y
    两种情况下概率表达式跟之前的完全一致,只不过我们把两种情况整合在一起了。那这个时候应用极大似然估计应该得到的是所有的概率值乘积应该最大,即:
    L=∑Ni=1ŷ yii(1−ŷ i)(1−yi)L=∑i=1Ny^iyi(1−y^i)(1−yi)L=\sum _{i=1} ^N \hat y_i^{y_i}(1-\hat y_i)^{(1-y_i)}
    引入log函数后得到:
    L′=log(L)=∑Ni=1yilogŷ i+(1−yi)log(1−ŷ i)L′=log(L)=∑i=1Nyilogy^i+(1−yi)log(1−y^i)L'=log(L)=\sum _{i=1} ^N y_i log\hat y_i+(1-y_i)log(1-\hat y_i)
    这时令loss=-log(L)=-L',也就是损失函数越小越好,而此时也就是 L'越大越好。

而在实际的使用训练过程中,数据往往是组合成为一个batch来使用,所以对用的神经网络的输出应该是一个m*n的二维矩阵,其中m为batch的个数,n为分类数目,而对应的Label也是一个二维矩阵,还是拿上面的数据,组合成一个batch=2的矩阵

q=[0.50.80.20.10.30.1]q=[0.50.20.30.80.10.1]

q={\begin{bmatrix}0.5&0.2 &0.3 \\ 0.8&0.1 &0.1 \end{bmatrix}}

p=[110000]p=[100100]

p={\begin{bmatrix}1&0&0 \\ 1&0&0 \end{bmatrix}}
根据第一种交叉熵的形式得到:

H(p,q)=[0.30.1]H(p,q)=[0.30.1]

H(p,q)={\begin{bmatrix} 0.3\\ 0.1 \end{bmatrix}}
而对于一个batch,最后取平均为0.2

3. 在TensorFlow中实现交叉熵

在TensorFlow可以采用这种形式:

cross_entropy = -tf.reduce_mean(y_ * tf.log(tf.clip_by_value(y, 1e-10, 1.0))) 

其中y_表示期望的输出,y表示实际的输出(概率值)*为矩阵元素间相乘,而不是矩阵乘。
并且通过tf.clip_by_value函数可以将一个张量中的数值限制在一个范围之内,这样可以避免一些运算错误(比如log0是无效的),tf.clip_by_value函数是为了限制输出的大小,为了避免log0为负无穷的情况,将输出的值限定在(1e-10, 1.0)之间,其实1.0的限制是没有意义的,因为概率怎么会超过1呢。比如:

import tensorflow as tfv=tf.constant([[1.0,2.0,3.0],[4.0,5.0,6.0]])
with tf.Session() as sess:print(tf.clip_by_value(v,2.5,4.5).eval(session=sess))

结果:

[[2.5 2.5 3. ][4.  4.5 4.5]]

上述代码实现了第一种形式的交叉熵计算,需要说明的是,计算的过程其实和上面提到的公式有些区别,按照上面的步骤,平均交叉熵应该是先计算batch中每一个样本的交叉熵后取平均计算得到的,而利用tf.reduce_mean函数其实计算的是整个矩阵的平均值,这样做的结果会有差异,但是并不改变实际意义。

import tensorflow as tfv=tf.constant([[1.0,2.0,3.0],[4.0,5.0,6.0]])
with tf.Session() as sess:# 输出3.5print(tf.reduce_mean(v).eval())

由于在神经网络中,交叉熵常常与Sorfmax函数组合使用,所以TensorFlow对其进行了封装,即:

cross_entropy = tf.nn.sorfmax_cross_entropy_with_logits(y_ ,y) 

与第一个代码的区别在于,这里的y用神经网络最后一层的原始输出就好了,而不是经过softmax层的概率值。

参考:https://blog.csdn.net/red_stone1/article/details/80735068
https://blog.csdn.net/chaipp0607/article/details/73392175

深度学习中softmax交叉熵损失函数的理解相关推荐

  1. softmax交叉熵损失函数深入理解(二)

    0.前言 前期博文提到经过两步smooth化之后,我们将一个难以收敛的函数逐步改造成了softmax交叉熵损失函数,解决了原始的目标函数难以优化的问题.Softmax 交叉熵损失函数是目前最常用的分类 ...

  2. 【深度学习原理】交叉熵损失函数的实现

    交叉熵损失函数 一般我们学习交叉熵损失函数是在二元分类情况下: L=−[ylogy^+(1−y)log(1−y^)]L=−[ylog ŷ +(1−y)log (1−ŷ )]L=−[ylogy^​+ ...

  3. Keras深度学习实战(4)——深度学习中常用激活函数和损失函数详解

    Keras深度学习实战(4)--深度学习中常用激活函数和损失函数详解 常用激活函数 Sigmoid 激活函数 Tanh 激活函数 ReLU 激活函数 线性激活函数 Softmax 激活函数 损失函数 ...

  4. 简单易懂的softmax交叉熵损失函数求导

    简单易懂的softmax交叉熵损失函数求导 本博客转自:http://m.blog.csdn.net/qian99/article/details/78046329 来写一个softmax求导的推导过 ...

  5. 深度学习相关概念:交叉熵损失

    深度学习相关概念:交叉熵损失 交叉熵损失详解 1.激活函数与损失函数 1.1激活函数: 1.2损失函数: 2.对数损失函数(常用于二分类问题): 3.交叉熵.熵.相对熵三者之间的关系 4.交叉熵损失函 ...

  6. 一文看尽深度学习中的15种损失函数

    点击上方"计算机视觉工坊",选择"星标" 干货第一时间送达 作者丨CVHub 来源丨CVHub 编辑丨极市平台 导读 本文详细介绍了深度学习中的各种损失函数的优 ...

  7. 交叉熵损失函数的理解

    转载自:https://blog.csdn.net/red_stone1/article/details/80735068 交叉熵损失函数的公式: 1.交叉熵损失函数的原理 我们知道,在二分类问题模型 ...

  8. softmax交叉熵损失函数

    1.推导 softmax的损失函数推导依然要用到最大似然估计MLE m代表有m条样本,k代表k个类别 2.softmax损失函数可以简写成 逻辑回归LR损失函数可以写成 因此由公式可以看出逻辑回归就是 ...

  9. 深度学习中的常用的损失函数(PyTorch)

    目录 定义 分类问题(Classification) Cross-Entropy Loss Dice Loss Focal Loss Jaccard/Intersection over Union ( ...

最新文章

  1. rxjava获取异步请求的结果_我为什么不再推荐用 RxJava
  2. 【玩转cocos2d-x之三十五】Earth Warrior 3D大揭秘
  3. C++输出字符变量地址
  4. Flutter PageView左右滑动切换视图
  5. APICloud App定制平台的操作指南
  6. 12年后,索尼重启机器人业务
  7. sdut 1500 Message Flood(Trie树)
  8. 9.数据结构 --- 查找
  9. 团队作业 -- beta版本
  10. 重金求购一份回合制手游源码
  11. 超像素分割SLIC与SLIC0(SLIC Zero)算法的区别
  12. 时钟同步显示屏(NTP时间显示屏)子母钟系统介绍
  13. 计算机基金经理排名,科班出身的基金经理业绩一定比非科班的好吗?
  14. 一些时间日期函数,转自华软
  15. QPS、TPS、并发用户数、吞吐量
  16. 上海黄山自游二日游攻略
  17. AutoCAD如何设置A0A1图纸
  18. 少吃调料竟然是错的!这9种调料原来是长寿高手
  19. Jetson TX2 安装 D435i ROS驱动
  20. 想跟应届毕业生聊聊的三个话题

热门文章

  1. VTK:图表之GraphToPolyData
  2. OpenGL 2D Prefix Sum 2维前缀总和的实例
  3. C++打印STAIRS 图案算法(附完整源码)
  4. C++实现connected component连通分量(附完整源码)
  5. 简单的C++程序求圆的周长和面积
  6. C/C++从代码到可执行文件
  7. C语言与C++的区别,从7个角度来区分C语言与C++
  8. 去掉字符串中的单引号和双引号_同时搞定Android和iOS的Dart语言(4):字符串类型...
  9. 怎么用matlab处理数据,如何用Matlab处理.wfm格式的数据
  10. 19_clickhouse,数据查询与写入优化,分布式子查询优化,外部聚合/排序优化,基于JOIN引擎的优化,SQL优化案例,物化视图提速,查询优化常用经验法则,选择和主键不一样的排序键,数据入库优化