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

关于熵、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函数在两

pytorch损失函数之nn.BCELoss()(为什么用交叉熵作为损失函数)_第1张图片

端的梯度均接近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

你可能感兴趣的:(pytorch,深度学习,机器学习)