交叉熵损失公式与手动计算

1、交叉熵损失函数
交叉熵的公式有多种形式,一般写作
l o s s = − 1 n ∑ j = 1 n y j l n a j ( ∗ ∗ ) loss=-\frac{1}{n}\sum_{j=1}^{n}y_jlna_j (**) loss=n1j=1nyjlnaj
l o s s j = − y j l n a j ( 1 ) loss_j=-y_jlna_j (1) lossj=yjlnaj1

l o s s j loss_j lossj表示第j个样本的损失。 a j a_j aj表示softmax函数输出。 y j y_j yj表示第j个样本的真实标签,为one-hot形式,所以上式可以变为
l o s s j = − y j l n e x p ( z j ) ∑ e x p ( z m ) = − y j z j + y j l n ∑ e x p ( z m ) = − z j + l n ∑ e x p ( z m ) loss_j=-y_jln\frac{exp(z_j)}{\sum{exp(z_m)}} \\=-y_jz_j+y_jln\sum{exp(z_m)}\\ =-z_j+ln\sum{exp(z_m)} lossj=yjlnexp(zm)exp(zj)=yjzj+yjlnexp(zm)=zj+lnexp(zm)
其中 y j y_j yj选取1所在的位置,所以有另一种表示:
l o s s i = − x [ c l a s s ] + l n ∑ j = 1 n e x p ( x [ j ] ) ( 2 ) loss_i=-x[class]+ln\sum_{j=1}^{n}exp(x[j]) (2) lossi=x[class]+lnj=1nexp(x[j])2
实际计算如下:
真实标签,label:[1, 0, 0]
预测标签,pred:[ [-0.7715, -0.6205, -0.2562]]
利用公式(2),
l o s s = − x [ 0 ] + l o g ∑ j e x p ( x [ j ] ) = 0.7715 + l o g [ e x p ( − 0.7715 ) + e x p ( − 0.6205 ) + e x p ( − 0.2562 ) ] = 1.344726 loss=-x[0]+log\sum_{j}exp(x[j])\\=0.7715+log[exp(-0.7715)+exp(-0.6205)+exp(-0.2562)]\\=1.344726 loss=x[0]+logjexp(x[j])=0.7715+log[exp(0.7715)+exp(0.6205)+exp(0.2562)]=1.344726
利用公式(1),
p r e d _ s o f t m a x = s o f t m a x ( p r e d ) = [ [ 0.2606 , 0.3031 , 0.4363 ] ] p r e d _ l o g = [ [ − 1.3447 , − 1.1937 , − 0.8294 ] ] r e s = l a b e l ∗ p r e d _ l o g = [ 1 , 0 , 0 ] ∗ [ [ − 1.3447 , − 1.1937 , − 0.8294 ] ] = [ [ − 1.3447 , 0 , 0 ] ] = − 1.3447 pred\_softmax=softmax(pred)=[[0.2606,0.3031,0.4363]] \\ pred\_log = [[-1.3447,-1.1937,-0.8294]]\\ res=label*pred\_log=[1,0,0]*[[-1.3447,-1.1937,-0.8294]]\\=[[-1.3447,0,0]]=-1.3447 pred_softmax=softmax(pred)=[[0.2606,0.3031,0.4363]]pred_log=[[1.3447,1.1937,0.8294]]res=labelpred_log=[1,0,0][[1.3447,1.1937,0.8294]]=[[1.3447,0,0]]=1.3447
所以有 l o s s = − r e s = 1.3447 loss=-res=1.3447 loss=res=1.3447。可以看到,两种方法的计算结果相同。
2、Pytorch中的使用
Pytorch中使用交叉熵损失有三种方法,分别为nn.CrossEntropy、nn.NLLLoss、手动写。

y_pred = torch.tensor([[-0.7715, -0.6205, -0.2562], [-0.7627, -0.6284, -0.2547]]) # [B, num_labels]
y_label = torch.tensor([[1, 0, 0], [1, 0, 0]])  # [B, num_labels]
y_label_1 = torch.tensor([0, 0])  #


y_pred_softmax = nn.Softmax(dim=-1)(y_pred)
y_pred_log=torch.log(y_pred_softmax)

loss_1 = nn.NLLLoss()(y_pred_log, y_label_1)
print('NLLLoss计算出的loss:{}'.format(loss_1)) # 1.3406

loss_2 = nn.CrossEntropyLoss()(y_pred, y_label_1)
print('CrossEntropy计算出的loss:{}'.format(loss_2)) # 1.3406

loss_3 = -torch.mean(torch.sum(y_pred_log*y_label.float(), dim=-1))  # [-1.3447, -1.3365]
print('手动写计算出的loss:{}'.format(loss_3))  # 1.3406

由上面代码可以得到,loss_1=loss_2=loss_3。
上面计算了两个样本,loss_3在求-mean之前的结果为[-1.3447, -1.3365],1.3447即为在第一部分求得的loss结果,同样可以看出,最终的loss=1.3446,是由多个样本求-mean得到的,对应公式(**)。

你可能感兴趣的:(Pytorch使用,NLP,交叉熵损失,损失函数,CrossEntropy,NLLLoss,手动计算损失)