Softmax函数与交叉熵
来源:互联网 发布:如何选基金 知乎 编辑:程序博客网 时间:2024/05/21 10:15
- Softmax函数
- 背景与定义
- 导数
- softmax的计算与数值稳定性
- Loss function
- 对数似然函数
- 交叉熵
- Loss function求导
- TensorFlow
- 方法1手动实现不建议使用
- 方法2使用tfnnsoftmax_cross_entropy_with_logits推荐使用
- 区别
- 总结
- Reference
Softmax函数
背景与定义
在Logistic regression二分类问题中,我们可以使用sigmoid
函数将输入softmax
函数,对输出的值归一化为概率值。
这里假设在进入softmax
函数之前,已经有模型输出
所以对每个样本,它属于类别
通过上式可以保证
导数
对softmax
函数进行求导,即求
第
代入
softmax
函数表达式,可以得到: 用我们高中就知道的求导规则:对于
它的导数为
所以在我们这个例子中,
上面两个式子只是代表直接进行替换,而非真的等式。
1. 如果
2. 如果
再来看
所以,当
当
其中,为了方便,令
对softmax
函数的求导,我在两年前微信校招面试基础研究岗位一面的时候,就遇到过,这个属于比较基础的问题。
softmax的计算与数值稳定性
在Python中,softmax
函数为:
def softmax(x): exp_x = np.exp(x) return exp_x / np.sum(exp_x)
传入[1, 2, 3, 4, 5]
的向量
>>> softmax([1, 2, 3, 4, 5])array([ 0.01165623, 0.03168492, 0.08612854, 0.23412166, 0.63640865])
但如果输入值较大时:
>>> softmax([1000, 2000, 3000, 4000, 5000])array([ nan, nan, nan, nan, nan])
这是因为在求exp(x)
时候溢出了:
import mathmath.exp(1000)# Traceback (most recent call last):# File "<stdin>", line 1, in <module># OverflowError: math range error
一种简单有效避免该问题的方法就是让exp(x)
中的x
值不要那么大或那么小,在softmax
函数的分式上下分别乘以一个非零常数:
这里
这样子将所有的输入平移到0附近(当然需要假设所有输入之间的数值上较为接近),同时,除了最大值,其他输入值都被平移成负数,
nan
的结果更好。def softmax(x): shift_x = x - np.max(x) exp_x = np.exp(shift_x) return exp_x / np.sum(exp_x)
>>> softmax([1000, 2000, 3000, 4000, 5000])array([ 0., 0., 0., 0., 1.])
当然这种做法也不是最完美的,因为softmax
函数不可能产生0值,但这总比出现nan
的结果好,并且真实的结果也是非常接近0的。
Loss function
对数似然函数
机器学习里面,对模型的训练都是对Loss function进行优化,在分类问题中,我们一般使用最大似然估计(Maximum likelihood estimation)来构造损失函数。对于输入的
其中,
将问题泛化为更一般的情况,多分类问题:
由于连乘可能导致最终结果接近0的问题,一般对似然函数取对数的负数,变成最小化对数似然函数。
交叉熵
说交叉熵之前先介绍相对熵,相对熵又称为KL散度(Kullback-Leibler Divergence),用来衡量两个分布之间的距离,记为
这里
假设有两个分布
从这里可以看出,交叉熵和相对熵相差了
回到我们多分类的问题上,真实的类标签可以看作是分布,对某个样本属于哪个类别可以用One-hot的编码方式,是一个维度为[0, 1, 0, 0, 0]
表示该样本属于第二个类,其概率值为1。我们把真实的类标签分布记为[0.1, 0.8, 0.05, 0.05, 0]
。
对一个样本来说,真实类标签分布与模型预测的类标签分布可以用交叉熵来表示:
可以看出,该等式于上面对数似然函数的形式一样!
最终,对所有的样本,我们有以下loss function:
其中
Loss function求导
对单个样本来说,loss function
上面对
当
当
所以,将求导结果代入上式:
TensorFlow
方法1:手动实现(不建议使用)
在TensorFlow中,已经有实现好softmax
函数,所以我们可以自己构造交叉熵损失函数:
import tensorflow as tfimport input_datax = tf.placeholder("float", shape=[None, 784])label = tf.placeholder("float", shape=[None, 10])w_fc1 = tf.Variable(tf.truncated_normal([784, 1024], stddev=0.1))b_fc1 = tf.Variable(tf.constant(0.1, shape=[1024]))h_fc1 = tf.matmul(x, w_fc1) + b_fc1w_fc2 = tf.Variable(tf.truncated_normal([1024, 10], stddev=0.1))b_fc2 = tf.Variable(tf.constant(0.1, shape=[10]))y = tf.nn.softmax(tf.matmul(h_fc1, w_fc2) + b_fc2)cross_entropy = -tf.reduce_sum(label * tf.log(y))
cross_entropy = -tf.reduce_sum(label * tf.log(y))
是交叉熵的实现。先对所有的输出用softmax
进行转换为概率值,再套用交叉熵的公式。
方法2:使用tf.nn.softmax_cross_entropy_with_logits
(推荐使用)
import tensorflow as tfimport input_datax = tf.placeholder("float", shape=[None, 784])label = tf.placeholder("float", shape=[None, 10])w_fc1 = tf.Variable(tf.truncated_normal([784, 1024], stddev=0.1))b_fc1 = tf.Variable(tf.constant(0.1, shape=[1024]))h_fc1 = tf.matmul(x, w_fc1) + b_fc1w_fc2 = tf.Variable(tf.truncated_normal([1024, 10], stddev=0.1))b_fc2 = tf.Variable(tf.constant(0.1, shape=[10]))y = tf.matmul(h_fc1, w_fc2) + b_fc2cross_entropy = -tf.reduce_sum(tf.nn.softmax_cross_entropy_with_logits(labels=label, logits=y))
TensorFlow已经实现好函数,用来计算label
和logits
的softmax
交叉熵。注意,该函数的参数logits
在函数内会用softmax
进行处理,所以传进来时不能是softmax
的输出了。
区别
既然我们可以自己实现交叉熵的损失函数,为什么TensorFlow还要再实现tf.nn.softmax_cross_entropy_with_logits
函数呢?
这个问题在Stack overflow上已经有Google的人出来回答(传送门),原话是:
If you want to do optimization to minimize the cross entropy, AND you’re softmaxing after your last layer, you should use tf.nn.softmax_cross_entropy_with_logits instead of doing it yourself, because it covers numerically unstable corner cases in the mathematically right way. Otherwise, you’ll end up hacking it by adding little epsilons here and there.
也就是说,方法1自己实现的方法会有在前文说的数值不稳定的问题,需要自己在softmax
函数里面加些trick。所以官方推荐如果使用的loss function是最小化交叉熵,并且,最后一层是要经过softmax函数处理,则最好使用tf.nn.softmax_cross_entropy_with_logits
函数,因为它会帮你处理数值不稳定的问题。
总结
全文到此就要结束了,可以看到,前面介绍这么多概念,其实只是为了解释在具体实现时候要做什么样的选择。可能会觉得有些小题大做,但对于NN这个黑盒子来说,我们现暂不能从理论上证明其有效性,那在工程实现上,我们不能再将它当作黑盒子来使用。
Reference
- http://eli.thegreenplace.net/2016/the-softmax-function-and-its-derivative/
- http://peterroelants.github.io/posts/neural_network_implementation_intermezzo02/
- http://cs231n.github.io/linear-classify/
- http://cs229.stanford.edu/notes/cs229-notes1.pdf
- http://blog.csdn.net/rtygbwwwerr/article/details/50778098
- http://stackoverflow.com/questions/34240703/difference-between-tensorflow-tf-nn-softmax-and-tf-nn-softmax-cross-entropy-with
博客原文地址:http://blog.csdn.net/behamcheung/article/details/71911133
- Softmax函数与交叉熵
- Softmax函数与交叉熵
- Softmax函数与交叉熵
- softmax函数与交叉熵的反向梯度传导
- tensorflow-softmax回归及交叉熵函数
- 深度学习---之softmax与交叉熵
- 神经网络与深度学习 笔记4 交叉熵代价函数 softmax函数
- Softmax和交叉熵
- tensorflow入门7 softmax函数和交叉熵损失函数
- 简单易懂的softmax交叉熵损失函数求导
- 简单易懂的softmax交叉熵损失函数求导
- softmax交叉熵与最大似然估计
- 逻辑回归、交叉熵、softmax
- [深度学习]Softmax 交叉熵
- BP神经网络(输出层采用Softmax激活函数、交叉熵损失函数)公式推导
- softmax_cross_entropy softmax交叉熵 tensorflow numpy
- 交叉熵到logistic和softmax
- softmax 函数
- C/C++二维数组名和二级指针
- HTML5之Canvas绘图——半圆与圆弧的不同画法
- 某场小考(2)
- together进度报告2
- leetcode 4 golang Median of Two Sorted Arrays
- Softmax函数与交叉熵
- Sublime Text
- 如何关闭windows8.1的445,135,137,138,139端口
- Northcott Game HDU
- 从内存的角度理解c++类的属性和方法
- Java parseInt与valueOf
- kafka0.90新版消费者API介绍及使用
- 项目1-正差值-三个数最大值--发工资
- C语言之关键字typedef