pytorch损失函数之nn.BCELoss()(为什么用交叉熵作为损失函数)

本文详细解析了交叉熵损失函数在深度学习中的应用,包括二分类与多分类问题的处理方式,以及如何避免梯度消失问题。同时介绍了PyTorch中实现交叉熵损失的函数。
关于熵、KL散度、交叉熵的讲解在这一篇文章中
一个二项分布,随机变量只有两种可能值,所以是一个二分类。二分类的交叉熵形式: − y l o g y ^ − ( 1 − y ) l o g ( 1 − y ^ ) ( 1 ) -ylog\hat{y}-(1-y)log(1-\hat{y})(1) ylogy^(1y)log(1y^)(1) 其中 y ^ \hat{y} y^是输出值在0-1之间。对于批量样本 ( x 1 , y 1 ) , ( x 2 , y 2 ) . . . {(x_1,y_1),(x_2,y_2)...} (x1,y1),(x2,y2)...则可以对交叉熵求和或者求均值: ∑ i − y i l o g y i ^ − ( 1 − y i ) l o g ( 1 − y i ^ ) ( 2 ) \sum_{i}-y_ilog\hat{y_i}-(1-y_i)log(1-\hat{y_i})(2) iyilogyi^(1yi)log(1yi^)(2),注意公式(1)是两个交叉熵和的形式,因为随即变量有两个可能的值,一个概率为 y ^ \hat{y} y^,一个概率为 1 − y ^ 1-\hat{y} 1y^。(这里我们将标签值y视作先验分布, y ^ \hat{y} y^为模型分布)
pytorch中 class torch.nn.BCELoss(weight=None, size_average=None, reduce=None, reduction=‘elementwise_mean’) 表示求一个二分类的交叉熵。它的loss如下:
l ( x , y ) = L = { l 1 , l 2 , . . . , l n } , 其 中 l n = − w n [ y n l o g y n ^ + ( 1 − y n ) l o g ( 1 − y n ^ ) ] l(x,y)=L=\{l_1,l_2,...,l_n\},其中l_n=-w_n[y_nlog\hat{y_n}+(1-y_n)log(1-\hat{y_n})] l(x,y)=L={l1,l2,...,ln},ln=wn[ynlogyn^+(1yn)log(1yn^)],这里n表示批量大小。 w n w_n wn表示权重。
当参数reduce设置为 True,且参数size_average设置为True时,表示对交叉熵求均值,当size_average设置为Flase时,表示对交叉熵求和。参数weight设置的是 w n w_n wn,其是一个tensor且size与批量数一样(不设置时可能都为1)。目标值 y y y的范围是0-1之间。输入输出的维度都是 ( N , ∗ ) (N,*) N,N是批量数,*表示目标值维度。
为什么是用交叉熵作为损失函数?
在深度学习中我们常用的损失函数是二次函数 L = ( y − y ^ ) 2 2 ( 3 ) L=\frac{(y-\hat{y})^2}{2} (3) L=2(yy^)2(3),若激活函数使用的是sigmoid函数,则 y ^ = σ ( z ) \hat{y}=\sigma(z) y^=σ(z),其中 z = w x + b z=wx+b z=wx+b。采用链式法则求导,则有:

∂ L ∂ w = ( y ^ − y ) σ ( z ) ′ x \frac{\partial L}{\partial w}=(\hat{y}-y){\sigma(z)}'x wL=(y^y)σ(z)x ∂ L ∂ b = ( y ^ − y ) σ ( z ) ′ \frac{\partial L}{\partial b}=(\hat{y}-y){\sigma(z)}' bL=(y^y)σ(z)

可以看出梯度都与sigmoid函数的梯度有关,如下图所示,sigmoid函数在两

在这里插入图片描述

端的梯度均接近0,这导致反向传播的梯度也很小,这就这就不利于网络训练,这就是 梯度消失问题
再来看看以交叉熵作为损失函数.对 1 n ∑ i − y i l o g y i ^ − ( 1 − y i ) l o g ( 1 − y i ^ ) ( 2 ) \frac{1}{n}\sum_{i}-y_ilog\hat{y_i}-(1-y_i)log(1-\hat{y_i})(2) n1iyilogyi^(1yi)log(1yi^)(2)求导,可得: ∂ L ∂ w = − 1 n ∑ i ( y σ ( z ) − 1 − y 1 − σ ( z ) ) ∂ σ ∂ w = − 1 n ∑ i ( y σ ( z ) − 1 − y 1 − σ ( z ) ) σ ′ x \frac{\partial L}{\partial w}=-\frac{1}{n}\sum_i(\frac{y}{\sigma(z)}-\frac{1-y}{1-\sigma(z)})\frac{\partial \sigma}{\partial w}=-\frac{1}{n}\sum_i(\frac{y}{\sigma(z)}-\frac{1-y}{1-\sigma(z)}) {\sigma}'x wL=n1i(σ(z)y1σ(z)1y)wσ=n1i(σ(z)y1σ(z)1y)σx 由于 σ ( z ) = 1 / ( 1 + e − z ) \sigma(z)=1/(1+e^{-z}) σ(z)=1/(1+ez)所以最终得到: ∂ L ∂ w = 1 n ∑ i x ( σ ( z ) − y ) \frac{\partial L}{\partial w}=\frac{1}{n}\sum_i x(\sigma(z)-y) wL=n1ix(σ(z)y)而对偏置的导数也等于 ∂ L ∂ b = 1 n ∑ i ( σ ( z ) − y ) \frac{\partial L}{\partial b}=\frac{1}{n}\sum_i (\sigma(z)-y) bL=n1i(σ(z)y)可以看见使用交叉熵作为损失函数后,反向传播的梯度不在于sigmoid函数的导数有关了。这就从一定程度上避免了梯度消失。
若是遇到多分类问题怎么使用交交叉熵呢?
比如我们有3个类别,那么我们通过softmax得到 y ^ = [ 0.2 , 0.5 , 0.3 ] \hat{y}=[0.2,0.5,0.3] y^=[0.2,0.5,0.3]的到的一个一个样本的分类结果,这个结果的通俗解释就是:为第一类的概率为0.2,为第二类的概率为0.5,为第三类的结果过0.3。
假设这个样本真实类别为第二类,那么我们希望模型输出的结果过应该是 y = [ 0 , 1 , 0 ] y=[0,1,0] y=[0,1,0],这个就是标签值。那么损失函数可以使用交叉熵:

L = − ∑ k 3 y k l o g ( y ^ ) L=-\sum_k^3y_klog(\hat{y}) L=k3yklog(y^),可以看见实际上这个求和只有一项。也就是 L = − l o g ( 0.5 ) L=-log(0.5) L=log(0.5)
pytorch中提供了多分类使用的损失函数nn.CrossEntropyLoss()使用的原理,与这里类似。

Neural Network and Deep Learning ,Michael Nielsen(中文)
pytorch官方文档
http://www.cnblogs.com/pinard/p/6437495.html

`nn.BCELoss()` 是 PyTorch 中的一个损失函数,用于二分类任务。它计算的是输入预测值与真实标签之间的二元交叉熵(Binary Cross Entropy)损失。 ### 基本概念 - **输入**:通常是一个形状为 `(N,)` 或 `(N, *)` 的张量,其中 `N` 表示样本数量,`*` 表示任意维度。每个元素表示模型对相应样本属于正类的概率估计。 - **目标**:也是一个形状为 `(N,)` 或 `(N, *)` 的张量,每个元素取值为 0 或 1,分别表示负类和正类的真实标签。 - **输出**:一个标量,表示所有样本的平均损失。 ### 数学公式 二元交叉熵损失的数学公式如下: \[ L = -\frac{1}{N} \sum_{i=1}^{N} [y_i \log(p_i) + (1 - y_i) \log(1 - p_i)] \] 其中: - \( N \) 是样本数量。 - \( y_i \) 是第 \( i \) 个样本的真实标签(0 或 1)。 - \( p_i \) 是第 \( i \) 个样本的预测概率。 ### 使用示例 ```python import torch import torch.nn as nn # 定义损失函数 criterion = nn.BCELoss() # 预测值,每个元素在 [0, 1] 范围内 predictions = torch.tensor([0.9, 0.1, 0.8, 0.2]) # 真实标签,每个元素为 0 或 1 targets = torch.tensor([1.0, 0.0, 1.0, 0.0]) # 计算损失 loss = criterion(predictions, targets) print(loss) # 输出损失值 ``` ### 参数 - **weight**:可选参数,用于对不同样本的损失进行加权。形状与输入相同。 - **reduction**:指定如何对多个样本的损失进行聚合,默认为 `'mean'`,可以设置为 `'none'`(不聚合,返回每个样本的损失)或 `'sum'`(求和)。 ### 注意事项 - 输入预测值应经过 sigmoid 函数处理,使其范围在 [0, 1] 之间。如果直接使用模型的原始输出,建议使用 `nn.BCEWithLogitsLoss`,该损失函数内部会自动应用 sigmoid 函数。 - 如果目标标签中有非 0 和 1 的值,可能会导致 NaN 或其他错误。 希望这些解释对你理解 `nn.BCELoss()` 有所帮助!如果有更多问题,请随时提问。
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值