一、softmax函数
softmax用于多分类过程中,它将多个神经元的输出,映射到(0,1)区间内,可以看成概率来理解,从而来进行多分类!
假设我们有一个数组,Z,Zi表示Z中的第i个元素,那么这个元素的softmax值就是:
更形象的如下图表示:
softmax直白来说就是将原来输出是3,1,-3通过softmax函数一作用,就映射成为(0,1)的值,而这些值的累和为1(满足概率的性质),那么我们就可以将它理解成概率,在最后选取输出结点的时候,我们就可以选取概率最大(也就是值对应最大的)结点,作为我们的预测目标!
1.1 引入指数形式的优点
从上述 y = e x y = e^{x} y=ex函数图像指数函数中可以看出,曲线呈现递增趋势,最重要的是斜率逐渐增大,也就是说在x轴上一个很小的变化,可以导致y轴上很大的变化。这种函数曲线能够将输出的数值拉开距离。
假设拥有三个输出节点的输出值为为[2, 3, 5]。我们来尝试 不使用指数函数
和 使用指数函数的Softmax函数
计算会产生什么区别。
import tensorflow as tf
print(tf.__version__) # 2.0.0
a = tf.constant([2, 3, 5], dtype = tf.float32)
b1 = a / tf.reduce_sum(a) # 不使用指数
print(b1) # tf.Tensor([0.2 0.3 0.5], shape=(3,), dtype=float32)
b2 = tf.nn.softmax(a) # 使用指数的Softmax
print(b2) # tf.Tensor([0.04201007 0.11419519 0.8437947 ], shape=(3,), dtype=float32)
结果还是挺明显的,经过使用指数形式的Softmax函数能够将差距大的数值距离拉的更大。
另外,在深度学习中通常使用反向传播求解梯度进而使用梯度下降进行参数更新的过程,使用指数函数在求导的时候比较方便。
1.2 引入指数形式的缺点
指数函数的曲线斜率逐渐增大虽然能够将输出值拉开距离,但是也带来了缺点,当 z i z_{i} zi 值非常大的话,计算得到的数值也会变的非常大,数值可能会溢出。
import numpy as np
scores = np.array([123, 456, 789])
softmax = np.exp(scores) / np.sum(np.exp(scores))
print(softmax) # [ 0. 0. nan]
当然针对数值溢出有其对应的优化方法,将每一个输出值减去输出值中最大的值。
import numpy as np
scores = np.array([123, 456, 789])
scores -= np.max(scores)
p = np.exp(scores) / np.sum(np.exp(scores))
print(p) # [5.75274406e-290 2.39848787e-145 1.00000000e+000]
二、交叉熵损失函数
2.1 交叉熵损失函数
交叉熵函数为在处理分类问题中常用的一种损失函数,用于描述模型预测值与真实值的差距大小,其具体公式为:
其中,p为真实值,q为预测值。
这里,关于交叉熵的具体介绍参见博客:损失函数——交叉熵损失函数(CrossEntropy Loss)
交叉熵损失函数在Python中的具体实现如下:
# tensorflow version
loss = tf.reduce_mean(-tf.reduce_sum(y_*tf.log(y), reduction_indices=[1]))
# numpy version
loss = np.mean(-np.sum(y_*np.log(y), axis=1))
# pytorch version
entroy=nn.CrossEntropyLoss()
2.2 softmax与交叉熵损失
当使用Softmax函数作为输出节点的激活函数的时候,一般使用交叉熵作为损失函数。
由于Softmax函数的数值计算过程中,很容易因为输出节点的输出值比较大而发生数值溢出的现象,在计算交叉熵的时候也可能会出现数值溢出的问题。为了数值计算的稳定性,TensorFlow提供了一个统一的接口,将Softmax与交叉熵损失函数同时实现,同时也处理了数值不稳定的异常,使用TensorFlow深度学习框架的时候,一般推荐使用这个统一的接口,避免分开使用Softmax函数与交叉熵损失函数。
TensorFlow提供的统一函数式接口为:
import tensorflow as tf
print(tf.__version__) # 2.0.0
tf.keras.losses.categorical_crossentropy(y_true, y_pred, from_logits = False)
中y_true代表了One-hot编码后的真实标签,y_pred表示网络的实际预测值:
- 当from_logits设置为True时,y_pred表示未经Softmax函数的输出值;
- 当from_logits设置为False时,y_pred表示为经过Softmax函数后的输出值;
为了在计算Softmax函数时候数值的稳定,一般将from_logits设置为True,此时 tf.keras.losses.categorical_crossentropy
将在内部进行Softmax的计算,所以在不需要在输出节点上添加Softmax激活函数。