十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
转自:
创新互联从2013年成立,我们提供高端网站建设、小程序制作、电商视觉设计、app软件开发公司及网络营销搜索优化服务,在传统互联网与移动互联网发展的背景下,我们坚守着用标准的设计方案与技术开发实力作基础,以企业及品牌的互联网商业目标为核心,为客户打造具商业价值与用户体验的互联网+产品。
注意 :tensorflow交叉熵计算函数输入中的logits都不是softmax或sigmoid的 输出 ,而是softmax或sigmoid函数的 输入 ,因为它在 函数内部进行sigmoid或softmax操作
tf.nn.sigmoid_cross_entropy_with_logits(_sentinel=None,labels=None, logits=None, name=None)
参数: _sentinel:本质上是不用的参数,不用填
logits:一个数据类型(type)是float32或float64;
shape:[batch_size,num_classes],单样本是[num_classes]
labels:和logits具有相同的type(float)和shape的张量(tensor),
name:操作的名字,可填可不填
输出:
loss,shape:[batch_size,num_classes]
Note: 它对于输入的logits先通过sigmoid函数计算,再计算它们的交叉熵,但是它对交叉熵的计算方式进行了优化,使得结果不至于溢出。它适用于每个类别相互独立但互不排斥的情况:例如一幅图可以同时包含一条狗和一只大象。output不是一个数,而是一个batch中每个样本的loss,所以一般配合tf.reduce_mea(loss)使用
计算公式:
Python 程序:
输出的E1,E2结果相同
tf.nn.softmax_cross_entropy_with_logits(_sentinel=None, labels=None, logits=None, dim=-1, name=None)argument:
_sentinel: 本质上是不用的参数,不用填
logits:一个数据类型(type)是float32或float64;
shape :[batch_size,num_classes]
labels:和logits具有相同type和shape的张量(tensor),,是一个有效的概率,sum(labels)=1, one_hot=True(向量中只有一个值为1.0,其他值为0.0)
name:操作的名字,可填可不填
output: loss,shape:[batch_size]
Note: 它对于输入的logits先通过softmax( 不同于sigmoid )函数计算,再计算它们的交叉熵,但是它对交叉熵的计算方式进行了优化,使得结果不至于溢出。它适用于每个类别相互独立且排斥的情况,一幅图只能属于一类,而不能同时包含一条狗和一只大象。output不是一个数,而是一个batch中每个样本的loss,所以一般配合tf.reduce_mean(loss)使用。
计算公式:
Python程序:
import tensorflow as tf
import numpy as np
def softmax(x):
sum_raw = np.sum(np.exp(x),axis=-1)
x1 = np.ones(np.shape(x))
for i in range(np.shape(x)[0]):
x1[i] = np.exp(x[i])/sum_raw[i]
return x1
y = np.array([[1,0,0],[0,1,0],[0,0,1],[1,0,0],[0,1,0]])#每一行只有一个1
logits =np.array([[12,3,2],[3,10,1],[1,2,5],[4,6.5,1.2],[3,6,1]])
y_pred =softmax(logits)
E1 = -np.sum(y*np.log(y_pred),-1)
print(E1)
sess = tf.Session()
y = np.array(y).astype(np.float64)
E2 = sess.run(tf.nn.softmax_cross_entropy_with_logits(labels=y,logits=logits))
print(E2)
输出的E1,E2结果相同
tf.nn.sparse_softmax_cross_entropy_with_logits(_sentinel=None,labels=None,logits=None, name=None)
argument:
_sentinel:本质上是不用的参数,不用填
logits:一个数据类型(type)是float32或float64;
shape:[batch_size,num_classes]
labels: shape为[batch_size],labels[i]是{0,1,2,……,num_classes-1}的一个索引, type为int32或int64
name:操作的名字,可填可不填
output:
loss,shape:[batch_size]
Note:它对于输入的logits先通过softmax函数计算,再计算它们的交叉熵,但是它对交叉熵的计算方式进行了优化,使得结果不至于溢出
它适用于每个类别相互独立且排斥的情况,一幅图只能属于一类,而不能同时包含一条狗和一只大象
output不是一个数,而是一个batch中每个样本的loss,所以一般配合tf.reduce_mean(loss)使用
计算公式:
和tf.nn.softmax_cross_entropy_with_logits()一样,只是要将labels转换成tf.nn.softmax_cross_entropy_with_logits()中labels的形式
tf.nn.weighted_cross_entropy_with_logits(labels,logits, pos_weight, name=None)
计算具有权重的sigmoid交叉熵sigmoid_cross_entropy_with_logits()
argument:
_sentinel:本质上是不用的参数,不用填
logits:一个数据类型(type)是float32或float64;
shape:[batch_size,num_classes],单样本是[num_classes]
labels:和logits具有相同的type(float)和shape的张量(tensor),
pos_weight:正样本的一个系数
name:操作的名字,可填可不填
output:
loss,shape:[batch_size,num_classes]
计算公式:
平滑函数。
交叉熵损失函数,也称为对数损失或者logistic损失。当模型产生了预测值之后,将对类别的预测概率与真实值(由0或1组成)进行不比较,计算所产生的损失,然后基于此损失设置对数形式的惩罚项。
在神经网络中,所使用的Softmax函数是连续可导函数,这使得可以计算出损失函数相对于神经网络中每个权重的导数(在《机器学习数学基础》中有对此的完整推导过程和案例,这样就可以相应地调整模型的权重以最小化损失函数。
扩展资料:
注意事项:
当预测类别为二分类时,交叉熵损失函数的计算公式如下图,其中y是真实类别(值为0或1),p是预测类别的概率(值为0~1之间的小数)。
计算二分类的交叉熵损失函数的python代码如下图,其中esp是一个极小值,第五行代码clip的目的是保证预测概率的值在0~1之间,输出的损失值数组求和后,就是损失函数最后的返回值。
参考资料来源:百度百科-交叉熵
参考资料来源:百度百科-损失函数
一条信息的信息量大小和它的不确定性有很大的关系 。一句话如果需要很多外部信息才能确定,我们就称这句话的信息量比较大。比如你听到“云南西双版纳下雪了”,那你需要去看天气预报、问当地人等等查证(因为云南西双版纳从没下过雪)。相反,如果和你说“人一天要吃三顿饭”,那这条信息的信息量就很小,因为这条信息的确定性很高。
那我们就能将事件 的信息量定义如下(其中 表示事件 发生的概率):
信息量是对于单个事件来说的 ,但是实际情况一件事有很多种发生的可能,比如掷骰子有可能出现6种情况,明天的天气可能晴、多云或者下雨等等。 熵是表示随机变量不确定的度量,是对所有可能发生的事件产生的信息量的期望 。公式如下:
的曲线如下:
结合熵的公式(2)以及 曲线,当这些所有可能发生事件的概率比较小(接近0)或者比较大(接近1)时,熵的值会比较小;如果事件发生的概率既远离0也远离1时,熵的值就会比较大。
例如,如下三组事件比较:
1)事件概率均等,[0.2500, 0.2500, 0.2500, 0.2500],熵为2;
2)事件概率比较靠近0或者1,[0.1, 0.1, 0.1, 0.7],熵为1.3568;
3)事件概率极其靠近0或者1,[0.001, 0.001, 0.001, 0.999],熵为0.0313.
熵的一种比较特殊的情况就是掷硬币 ,只有正、反两种情况,该种情况(二项分布或者0-1分布)熵的计算可以简化如下:
其中, 表示正面概率。
相对熵又称KL散度,用于衡量对于同一个随机变量 的两个分布 和 之间的差异 。在机器学习中, 常用于描述样本的真实分布 ,例如[1,0,0,0]表示样本属于第一类,而 则常常用于表示预测的分布 ,例如[0.7,0.1,0.1,0.1]。显然使用q(x)来描述样本不如 准确, 需要不断地学习来拟合准确的分布 。
KL散度的公式如下:
KL散度的值越小表示两个分布越接近。
我们将KL散度的公式进行变形,得到:
前半部分就是 的熵,后半部分就是我们的交叉熵:
机器学习中,我们常常使用KL散度来评估predict和label之间的差别,但是由于KL散度的前半部分是一个常量,所以我们常常将后半部分的交叉熵作为损失函数,其实二者是一样的。
交叉熵代价函数(Cross-entropy cost function)是用来衡量人工神经网络(ANN)的预测值与实际值的一种方式。与二次代价函数相比,它能更有效地促进ANN的训练。在介绍交叉熵代价函数之前,本文先简要介绍二次代价函数,以及其存在的不足。
ANN的设计目的之一是为了使机器可以像人一样学习知识。人在学习分析新事物时,当发现自己犯的错误越大时,改正的力度就越大。比如投篮:当运动员发现自己的投篮方向离正确方向越远,那么他调整的投篮角度就应该越大,篮球就更容易投进篮筐。同理, 我们希望:ANN在训练时,如果预测值与实际值的误差越大,那么在反向传播训练的过程中,各种参数调整的幅度就要更大,从而使训练更快收敛。 然而,如果使用二次代价函数训练ANN,看到的实际效果是,如果误差越大,参数调整的幅度可能更小,训练更缓慢。
以一个神经元的二类分类训练为例,进行两次实验(ANN常用的激活函数为sigmoid函数,该实验也采用该函数):输入一个相同的样本数据x=1.0(该样本对应的实际分类y=0);两次实验各自随机初始化参数,从而在各自的第一次前向传播后得到不同的输出值,形成不同的代价(误差):
在实验1中,随机初始化参数,使得第一次输出值为0.82(该样本对应的实际值为0);经过300次迭代训练后,输出值由0.82降到0.09,逼近实际值。而在实验2中,第一次输出值为0.98,同样经过300迭代训练,输出值只降到了0.20。
从两次实验的代价曲线中可以看出: 实验1的代价随着训练次数增加而快速降低,但实验2的代价在一开始下降得非常缓慢;直观上看,初始的误差越大,收敛得越缓慢。
其实,误差大导致训练缓慢的原因在于使用了二次代价函数。二次代价函数的公式如下:
其中, 表示代价, 表示样本, 表示实际值, 表示输出值, 表示样本的总数。为简单起见,同样一个样本为例进行说明,此时二次代价函数为:
目前训练ANN最有效的算法是反向传播算法 。简而言之,训练ANN就是通过反向传播代价,以减少代价为导向,调整参数。参数主要有:神经元之间的连接权重 ,以及每个神经元本身的偏置 。调参的方式是采用梯度下降算法(Gradient descent),沿着梯度方向调整参数大小。 和 的梯度推导如下:
其中, 表示神经元的输入, 表示激活函数。从以上公式可以看出, 和 的梯度跟激活函数的梯度成正比,激活函数的梯度越大, 和 的大小调整得越快,训练收敛得就越快。而神经网络常用的激活函数为sigmoid函数,该函数的曲线如下所示:
如图所示, 实验2的初始输出值(0.98)对应的梯度明显小于实验1的输出值(0.82),因此实验2的参数梯度下降得比实验1慢。这就是初始的代价(误差)越大,导致训练越慢的原因。 与我们的期望不符,即:不能像人一样,错误越大,改正的幅度越大,从而学习得越快。
可能有人会说,那就选择一个梯度不变化或变化不明显的激活函数不就解决问题了吗?那样虽然简单粗暴地解决了这个问题,但可能会引起其他更多更麻烦的问题。而且,类似sigmoid这样的函数(比如tanh函数)有很多优点,非常适合用来做激活函数,具体请自行google之。
换个思路,我们不换激活函数,而是换掉二次代价函数,改用交叉熵代价函数:
其中, 表示样本, 表示样本的总数。那么,重新计算参数 的梯度:
因此, 的梯度公式中原来的 被消掉了;另外,该梯度公式中的 表示输出值与实际值之间的误差。所以,当误差越大,梯度就越大,参数 调整得越快,训练速度也就越快。 实际情况证明,交叉熵代价函数带来的训练效果往往比二次代价函数要好。
在实际分类任务中,要先将输出层的输出值经过Softmax函数,再经过log函数,最后才用交叉熵损失函数计算损失。
pytorch中有计算交叉熵损失的接口,即 F.cross_entropy() ,不过该接口包含了Softmax函数、log函数、交叉熵损失函数。也就是说 F.cross_entropy() = F.softmax() + torch.log() + F.nnl_loss() 。即使如此,也要使用 F.cross_entropy() ,不仅是因为它简单,更因为它能保证数值稳定。
机器学习的过程就是希望在训练数据熵 模型学到的分布 和 真实的分布 越近越好,我们知道KL散度可以表示两个分布之间的不同。
但我们没有真实数据的分布,那么只能退而求其次,希望模型学到的分布和训练数据的分布 ,也就是把训练数据当做模型和真实数据之间的代理人 。假设训练数据是从总体中独立同步分布采样(Independent and identically distributed sampled)而来,那么我们可以利用最小化训练数据的经验误差来降低模型的泛化误差。简单说:
由此非常理想化的看法是如果 模型(左) 能够学到 训练数据(中) 的分布,那么应该近似的学到了 真实数据(右) 的分布: 近似于 近似于
简单的交叉熵,你真的懂了吗?
交叉熵损失函数
在使用pytorch深度学习框架,计算损失函数的时候经常回到这么一个个函数:
该损失函数结合了 和 两个函数。它在做分类(具体几类)训练的时候是非常有用的。在训练过程中,对于每个类分配权值,可选的参数权值应该是一个1D张量。当你有一个不平衡的训练集时,这是是非常有用的。那么针对这个函数,下面将做详细的介绍。
交叉熵主要是用来判定实际的输出与期望的输出的接近程度 ,为什么这么说呢,举个例子:在做分类的训练的时候,如果一个样本属于第K类,那么这个类别所对应的的输出节点的输出值应该为1,而其他节点的输出都为0,即[0,0,1,0,….0,0],这个数组也就是样本的Label,是神经网络最期望的输出结果。也就是说用它来衡量网络的输出与标签的差异,利用这种差异经过反向传播去更新网络参数。
在说交叉熵之前,先说一下 信息量 与 熵 。
信息量: 它是用来衡量一个事件的不确定性的;一个事件发生的概率越大,不确定性越小,则它所携带的信息量就越小。假设X是一个离散型随机变量,其取值集合为X,概率分布函数为 ,我们定义事件 的信息量为:
当 时,熵将等于0,也就是说该事件的发生不会导致任何信息量的增加。
熵: 它是用来衡量一个系统的混乱程度的,代表一个系统中信息量的总和;信息量总和越大,表明这个系统不确定性就越大。
举个例子:假如小明和小王去打靶,那么打靶结果其实是一个0-1分布,X的取值有{0:打中,1:打不中}。在打靶之前我们知道小明和小王打中的先验概率为10%,99.9%。根据上面的信息量的介绍,我们可以分别得到小明和小王打靶打中的信息量。但是如果我们想进一步度量小明打靶结果的不确定度,这就需要用到熵的概念了。那么如何度量呢,那就要采用 期望 了。我们对所有可能事件所带来的信息量求期望,其结果就能衡量小明打靶的不确定度:
与之对应的,小王的熵(打靶的不确定度)为: 虽然小明打靶结果的不确定度较低,毕竟十次有9次都脱靶;但是小王打靶结果的不确定度更低,1000次射击只有1次脱靶,结果相当的确定。
交叉熵: 它主要刻画的是实际输出(概率)与期望输出(概率)的距离,也就是交叉熵的值越小,两个概率分布就越接近。假设概率分布p为期望输出,概率分布q为实际输出, 为交叉熵,则 那么该公式如何表示,举个例子,假设N=3,期望输出为 ,实际输出 , ,那么: 通过上面可以看出,q2与p更为接近,它的交叉熵也更小。
Pytorch中计算的交叉熵并不是采用 这种方式计算得到的,而是交叉熵的另外一种方式计算得到的: 它是交叉熵的另外一种方式。
Pytorch中CrossEntropyLoss()函数的主要是将softmax-log-NLLLoss合并到一块得到的结果。
1、Softmax后的数值都在0~1之间,所以ln之后值域是负无穷到0。
2、然后将Softmax之后的结果取log,将乘法改成加法减少计算量,同时保障函数的单调性
3、NLLLoss的结果就是把上面的输出与Label对应的那个值拿出来(下面例子中就是:将log_output\logsoftmax_output中与y_target对应的值拿出来),去掉负号,再求均值。
下面是我仿真写的一个例子:
最计算得到的结果为:
通过上面的结果可以看出,直接使用pytorch中的loss_func=nn.CrossEntropyLoss()计算得到的结果与softmax-log-NLLLoss计算得到的结果是一致的。
[1]
[2]
[3]
更多自然语言处理、pytorch相关知识,还请关注 AINLPer 公众号,极品干货即刻送达。