交叉熵损失函数和softmax笔记


注:本文代码参考李沐书籍,这里只做代码解析。

1. 交叉熵定义

交叉熵是信息论中的一个重要概念,主要用于度量两个概率分布间的差异性,要理解交叉熵,需要先了解下面几个概念

  • 信息量
    香农大佬说过"信息是用来消除随机不确定的东西",就是用信息量来表示一个事件从不确定到确定这种状态的量度单位。信息量的大小和信息发生的概率成反比。假设某一事件发生的概率为P(X),我们将信息量I(X)定义如下
    I ( X ) = − log ⁡ ( P ( X ) ) (1) I(X)=-\log(P(X))\tag1 I(X)=log(P(X))(1)
  • 信息熵 H(X)
    信息熵表示的信息量的期望的和,我们知道,期望就是概率乘以值;那么可以得到。
    H ( X ) = − ∑ i = 1 n P ( x i ) log ⁡ P ( x i ) (2) H(X)=-\sum_{i=1}^{n}P(x_i)\log P(x_i)\tag2 H(X)=i=1nP(xi)logP(xi)(2)
    注:当我们求得的结果为两种情况,即二项式分布时候, n =2 时。那么
    H ( X ) = − [ P ( x i ) log ⁡ P ( x i ) + ( 1 − P ( x i ) ) log ⁡ ( 1 − P ( x i ) ) ] (3) H(X)=-[P(x_i)\log P(x_i)+(1-P(x_i))\log(1-P(x_i))]\tag3 H(X)=[P(xi)logP(xi)+(1P(xi))log(1P(xi))](3)
  • 相对熵(KL 散度)
    如果对于同一个随机变量X有两个单独概率分布,P(X) 和 Q(X),我们通过 KL散度来描述两个概率分布之间的差异。那为什么要这样做呢?因为我们已经有了概率分布 P(X)的具体参数,我们希望对于未知的概率分布 Q(X) 的进行分析,最好是有一个参数 KL 散度 来描述这两个概率分布的差异,当 KL散度很小时,那么我们就可以说明这两个分布相似。
    D K L ( p ∣ ∣ q ) = ∑ i = 1 n p ( x i ) log ⁡ ( p ( x i ) q ( x i ) ) (4) D_{KL}(p||q)=\sum_{i=1}^np(x_i)\log{(\frac{p(x_i)}{q(x_i)})}\tag 4 DKL(pq)=i=1np(xi)log(q(xi)p(xi))(4)
    D K L ( p ∣ ∣ q ) = ∑ i = 1 n p ( x i ) log ⁡ ( p ( x i ) ) ⏟ p ( x i ) 的 信 息 熵 + − ∑ i = 1 n p ( x i ) log ⁡ ( q ( x i ) ) ⏟ p ( x i ) 和 q ( x i ) 的 交 叉 熵 (5) D_{KL}(p||q)=\underbrace{\sum_{i=1}^np(x_i)\log{(p(x_i))}}_{p(x_i)的信息熵}+\underbrace{-\sum_{i=1}^np(x_i)\log{(q(x_i))}}_{p(x_i)和q(x_i)的交叉熵}\tag {5} DKL(pq)=p(xi) i=1np(xi)log(p(xi))+p(xi)q(xi) i=1np(xi)log(q(xi))(5)
    注:这里我们就出现了交叉熵了:
  • 交叉熵:
    − ∑ i = 1 n p ( x i ) log ⁡ ( q ( x i ) ) (6) -\sum_{i=1}^np(x_i)\log{(q(x_i))}\tag{6} i=1np(xi)log(q(xi))(6)

2.交叉熵损失思考

那为什么交叉熵能够表示两个概率之间的差异呢?为什么它就很方便的表达了。这里我们假设这里的 p ( x i ) p(x_i) p(xi)为模型中实际的概率标签 y i y_i yi, q ( x i ) q(x_i) q(xi)为模型预测的 y i ^ \hat{y_i} yi^,假设 类别数n = q代入上式可得:
l ( y i , y i ^ ) = − ∑ j = 1 q y i log ⁡ y i ^ (7) l(y_i,\hat{y_i})=-\sum_{j=1}^q y_i\log{\hat{y_i}}\tag{7} l(yi,yi^)=j=1qyilogyi^(7)
假设模型预测的 y i ^ \hat{y_i} yi^是通过 softmax运算得到的,满足如下:
y j ^ = s o f t m a x ( o j ) = e x p ( o j ) ∑ k e x p ( o k ) (8) \hat{y_j}=softmax(o_j)=\frac{exp(o_j)}{\sum_kexp(o_k)}\tag{8} yj^=softmax(oj)=kexp(ok)exp(oj)(8)
将 (8) 带入到 (7) 可得:
l ( y i , y i ^ ) = − ∑ j = 1 q y j log ⁡ e x p ( o j ) ∑ k e x p ( o k ) (9) l(y_i,\hat{y_i})=-\sum_{j=1}^q y_j\log{\frac{exp(o_j)}{\sum_kexp(o_k)}}\tag{9} l(yi,yi^)=j=1qyjlogkexp(ok)exp(oj)(9)
l ( y i , y i ^ ) = ∑ j = 1 q y j log ⁡ ∑ k e x p ( o k ) − ∑ j = 1 q y j o j (10) l(y_i,\hat{y_i})=\sum_{j=1}^q y_j\log\sum_kexp(o_k)-\sum_{j=1}^qy_jo_j\tag{10} l(yi,yi^)=j=1qyjlogkexp(ok)j=1qyjoj(10)
注:当我们用 one-hot 独热编码表示 y i y_i yi时,那么除了第 j 项为1,其他均为 0 ,则:
l ( y i , y i ^ ) = log ⁡ ∑ k = 1 q e x p ( o k ) − ∑ j = 1 q y j o j (11) l(y_i,\hat{y_i})=\log\sum_{k=1}^qexp(o_k)-\sum_{j=1}^qy_jo_j\tag{11} l(yi,yi^)=logk=1qexp(ok)j=1qyjoj(11)
对上式求导可得:
∂ l ( y i , y i ^ ) ∂ o j = e x p ( o j ) ∑ k = 1 q e x p ( o k ) − y j (12) \frac{\partial l(y_i,\hat{y_i})}{\partial o_j}=\frac{exp(o_j)}{\sum_{k=1}^qexp(o_k)}-y_j\tag{12} ojl(yi,yi^)=k=1qexp(ok)exp(oj)yj(12)
注意:此时我们发现 y j ^ = s o f t m a x ( o j ) = e x p ( o j ) ∑ k e x p ( o k ) \hat{y_j}=softmax(o_j)=\frac{exp(o_j)}{\sum_kexp(o_k)} yj^=softmax(oj)=kexp(ok)exp(oj)
∂ l ( y i , y i ^ ) ∂ o j = y j ^ − y j (13) \frac{\partial l(y_i,\hat{y_i})}{\partial o_j}=\hat{y_j}-y_j\tag{13} ojl(yi,yi^)=yj^yj(13)
重点:上式说明了,当我们用交叉熵表示损失函数的时候,我们模型中预测用到 softmax 时候,交叉熵的导数即为预测标签 y i ^ \hat{y_i} yi^与真实标签 y i y_i yi的差。这样就非常方便了,我们只需要用交叉熵为损失函数就可以了。
我们可以类比最小二乘法的损失函数 :
l ( y i , y i ^ ) = 1 2 ( y j ^ − y j ) 2 (14) l(y_i,\hat{y_i})=\frac{1}{2}(\hat{y_j}-y_j)^2\tag{14} l(yi,yi^)=21(yj^yj)2(14)
∂ l ( y i , y i ^ ) ∂ o j = y j ^ − y j (15) \frac{\partial l(y_i,\hat{y_i})}{\partial o_j}=\hat{y_j}-y_j\tag{15} ojl(yi,yi^)=yj^yj(15)
这样类比后,我们发现,用交叉熵做损失函数也能跟用最小二乘法表示一样实现。

3.交叉熵损失代码

  • 代码核心思想:交叉熵采用真实标签的预测概率的负对数似然
    举例1 :
    假设我们有真实标签 y i y_i yi,用它来表示样本中真实样本的位置
y = torch.tensor([0,2]) # 0,2 表示样本中真实正确标签的位置

我们用 y i ^ \hat{y_i} yi^来表示样本中各个类别的概率分布,并用 y 来告诉程序哪个概率是正确的。

y_hat = torch.tensor([[0.1, 0.3, 0.6], [0.3, 0.2, 0.5]])

结合起来如下:

y_hat[[0, 1], y] # 等价于 y_hat[[0, 1], [0,2]]
# 就是 0 对应于0; 1 对应于 2
# 第 0 个 [0.1, 0.3, 0.6] 中选择 第 0 个 ,即 0.1
# 第 1 个 [0.3, 0.2, 0.5] 中选择 第 2 个 ,即 0.5
# 所以以上代码输出结果为:tensor([0.1000, 0.5000])

那么我们就可以将上述得到的值求负对数似然即可

  • 交叉熵代码
def cross_entropy(y_hat, y):
	return -torch.log(y_hat[range(len(y_hat)), y])

4. softmax 回归的简洁实现

我们这里应用pytorch 框架的相关函数来搭建 softmax 回归,在搭建过程中十分的方便。

4.1 代码

# -*- coding: utf-8 -*-
# @Project: zc
# @Author: zc
# @File name: softmax的简洁实现
# @Create time: 2021/11/22 18:09

# 1.导入相关库
import torch
from torch import nn
from d2l import torch as d2l
import matplotlib.pyplot as plt

# 2.将数据导入并生成train_iter训练集,test_iter 测试集
batch_size = 256  # 设置批量大小
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)  # 将数据加载到迭代器中

# 3. 定义模型
# PyTorch不会隐式地调整输⼊的形状。因此,
# 我们在线性层前定义了展平层(flatten),来调整⽹络输⼊的形状
net = nn.Sequential(
	nn.Flatten(), nn.Linear(784, 10)
)


# 4.初始化模型值
def init_weights(m):
	if type(m) == nn.Linear:
		nn.init.normal_(m.weight, std=0.01)


net.apply(init_weights)

# 5. 定义损失函数

loss = nn.CrossEntropyLoss()

# 6. 定义优化器

trainer = torch.optim.SGD(net.parameters(), lr=0.1)

# 7.开始训练模型
num_epochs = 10  # 训练次数为 10

# 8.开始训练
d2l.train_ch3(net=net, train_iter=train_iter, test_iter=test_iter, loss=loss, num_epochs=num_epochs, updater=trainer)
# 9.预测
d2l.predict_ch3(net,test_iter) 
plt.show() # 显示结果

4.2 结果

  • 训练
    在这里插入图片描述
  • 预测
    在这里插入图片描述

5. torch.nn.Softmax代码测试

5.1 说明

softmax的作用是将张量中的值变成非负值,并且总和值为1;

  • 官网解释
    将Softmax函数应用于一个n维输入张量,对其进行缩放,使n维输出张量的元素位于[0,1]范围内,总和为1
  • 公式
    S o f t m a x ( x i ) = exp ⁡ ( x i ) ∑ j exp ⁡ ( x j ) Softmax(x_i)=\frac{\exp(x_i)}{\sum_j\exp(x_j)} Softmax(xi)=jexp(xj)exp(xi)
  • 函数
torch.nn.Softmax(dim=None)
  • dim
    表示对指定维度进行Softmax计算
    dim=0,是 行与行 之间进行 Softmax 计算;dim=1,是 列与列 之间进行 Softmax 计算;
  • 代码
import torch
from torch.nn import functional as F

x = torch.Tensor([[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]])

# dim=0 ,先将此x[i]求指数再除以行与行之间的指数值的和
# y_dim_0[0,0] = [exp^(1)]/{[exp^(1)]+[exp^(1)]+[exp^(1)]}=0.333
y_dim_0 = F.softmax(x, dim=0)
# dim=1 ,先将此x[i]求指数再除以列与列之间的指数值的和
# y_dim_1[0,0] = [exp^(1)]/{[exp^(1)]+[exp^(2)]+[exp^(3)]+[exp^(4)]}=0.321
y_dim_1 = F.softmax(x, dim=1)
print(f'x={x}')
print(f'x={x.shape}')
print(f'y_dim_0={y_dim_0}')
print(f'y_dim_0_shape={y_dim_0.shape}')
print(f'y_dim_1={y_dim_1}')
print(f'y_dim_1_shape={y_dim_1.shape}')
  • 结果
x=tensor([[1., 2., 3., 4.],
        [1., 2., 3., 4.],
        [1., 2., 3., 4.]])
x=torch.Size([3, 4])
y_dim_0=tensor([[0.3333, 0.3333, 0.3333, 0.3333],
        [0.3333, 0.3333, 0.3333, 0.3333],
        [0.3333, 0.3333, 0.3333, 0.3333]])
y_dim_0_shape=torch.Size([3, 4])
y_dim_1=tensor([[0.0321, 0.0871, 0.2369, 0.6439],
        [0.0321, 0.0871, 0.2369, 0.6439],
        [0.0321, 0.0871, 0.2369, 0.6439]])
y_dim_1_shape=torch.Size([3, 4])
  • 小结
    程序计算的结果跟分析的一致。
引用\[1\]: CIoU损失函数是一种用于目标检测中的损失函数,它合了中心点距离、重叠面积和高宽比等几何因素,可以帮助算法更好地匹配两个框。相比于传统的IoU损失函数,在非重叠情况下和水平垂直情况下有更小的误差。CIoU Loss的定义为1.5 - IoU + (d^2/c^2 + αv),其中d是中心点距离,c是对角线长度,α是一个平衡参数,v是一个修正项。\[1\] 引用\[2\]: CIoU损失函数与置信度损失类似,都是通过预测框的类别分数和目标框类别的one-hot表现来计算损失。目标置信度损失和类别损失使用的是带sigmoid的二进制交叉熵函数BCEWithLogitsLoss。\[2\] 引用\[3\]: YOLOv5中的CIoU损失函数是用于多标签分类的。与传统的分类器不同,YOLOv5使用多个独立的逻辑分类器来计算输入属于特定标签的可能性,而不是使用softmax函数。在计算分类损失时,YOLOv5使用二元交叉熵损失。这种方法避免了使用softmax函数,降低了计算复杂度。\[3\] 综上所述,YOLOv5中的CIoU损失函数是一种合了几何因素的目标检测损失函数,它在计算目标框的位置和分类损失时使用了CIoU损失和二元交叉熵损失。这种损失函数可以帮助提高目标检测算法的准确性和收敛速度。 #### 引用[.reference_title] - *1* *3* [【目标检测算法】IOU、GIOU、DIOU、CIOU与YOLOv5损失函数](https://blog.csdn.net/weixin_45751396/article/details/127150065)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [YOLOV5学习笔记(九)——损失函数](https://blog.csdn.net/HUASHUDEYANJING/article/details/127455934)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值