【PyTorch学习笔记】10:Logistic Regression,Cross Entropy Loss

Logistic Regression

简述

Logistic Regression虽然叫Regression,但是都用来解决分类问题,这是一个历史遗留问题。虽然它得到的是一个连续的值,它实际上做的是一个分类的工作(而不是回归)
y = σ ( x w + b ) y=\sigma (xw+b) y=σ(xw+b)
得到的y在0到1之间,可以看做概率值,也就是将x二分类的概率。如果输出0.4就预测为0,如果输出0.6就预测为1。

按视频里老师讲的,如果用MSE而不是CEL来对输出的概率值计算LOSS,然后minimize这个MSE,那就有点Regression的意思了,可能是因为以前都是用MSE所以才管它叫Regression吧,不过它做的就是分类问题。

回归和分类本质的区别

对于回归问题,目标是让预测值和真实值的差距 d i s t ( p r e d − y ) dist(pred-y) dist(predy)最小,可以直接对其进行minimize。

而对于分类问题,目标是优化那些分类指标,比如accuracy、F1-score或者AUC等。

预测的是连续的还是离散的值,导致了回归和分类的本质区别。

两者最本质的区别在于分类问题并不能直接去对目标进行最优化,而回归问题可以直接对LOSS进行minimize来求解。要对分类问题的目标优化,可以用分布去拟合样本的分布,然后对分布的参数进行调整。


如果直接对分类问题的目标(比如accuracy)进行SGD来优化求解,主要会出现下面两种问题:

  • (1)权重变了,但acc并没有变,即在权重w这附近的梯度为0

这种问题是因为分类是一个非0即1的问题,比如某个样本输出值为0.4,这样预测就是0号类别,而实际标签是1,这时调整权重使得其输出值为0.45接近了目标值1,但这样预测仍然是0号类别,其它样本也很可能是没有改变输出的标签,因此accuracy在这附近根本就是不变的。

  • (2)权重变了一点,使acc变化极大,即梯度爆炸或者梯度不连续。

比如某个样本的输出值是0.499预测为0类,调整一点权重使得输出值为0.5001预测为1类,这时accuracy突然就发生了很大的变化,并且这附近的梯度是不连续的。

Cross Entropy Loss

Entropy

可以将Entropy理解为uncertainty,Entropy越高则信息量越小:
E n t r o p y = ∑ i P ( i ) log ⁡ 1 P ( i ) = − ∑ i P ( i ) log ⁡ P ( i ) Entropy =\sum_i P(i)\log \frac{1}{P(i)} = -\sum_i P(i)\log P(i) Entropy=iP(i)logP(i)1=iP(i)logP(i)

import torch


def EL(p):
	"""Entropy Loss"""
	return -(p * torch.log2(p)).sum()


a = torch.tensor([0.1, 0.1, 0.1, 0.7])
b = torch.tensor([0.001, 0.001, 0.001, 0.997])
print(EL(a), EL(b))

运行结果:

tensor(1.3568) tensor(0.0342)

当使用one-hot编码时,理想状态下就只有一个分量是1,其它分量都是0,最终得到的Entropy就是1log1=0。

Cross Entropy

Entropy可以视为只和p这一个分布有关的 H ( p ) H(p) H(p),而Cross Entropy则是和p,q两个分布有关的 H ( p , q ) H(p,q) H(p,q)
H ( P , Q ) = − ∑ i P ( i ) log ⁡ Q ( i ) H(P,Q)=-\sum_i P(i) \log Q(i) H(P,Q)=iP(i)logQ(i)
当P=Q时Cross Entropy就是Entropy。

P在这里是ground truth也就是标注的真实值,Q是模型的输出值。


Cross Entropy可以拆成:
H ( P , Q ) = H ( P ) + D K L ( P ∣ Q ) H(P,Q)=H(P)+D_{KL}(P|Q) H(P,Q)=H(P)+DKL(PQ)
其中 D K L ( p ∣ q ) D_{KL}(p|q) DKL(pq)是KL Divergence(KL散度),用来衡量两个分布(P和Q)之间的不相似性。当P=Q时即这两个分布完全一样,后面一项KL散度为0。


对二分类问题,如标注为0号类别和1号类别:
H ( P , Q ) = − ∑ i = ( 0 , 1 ) P ( i ) log ⁡ Q ( i ) = − y 0 log ⁡ p − ( 1 − y 0 ) log ⁡ ( 1 − p ) H(P,Q)=-\sum_{i=(0,1)} P(i) \log Q(i) \\ = -y_0 \log p - (1-y_0) \log (1-p) H(P,Q)=i=(0,1)P(i)logQ(i)=y0logp(1y0)log(1p)
这里 y 0 y_0 y0也就是取第0类的标注值,p是输出的概率(这里表示认为是第0类的概率)。从这个二分类问题的公式可以直观的理解CE可以作为优化目标,比如当样本y=0时,这里最小化CE也就是在最大化 log ⁡ ( 1 − p ) \log (1-p) log(1p)也就是在最大化 p p p也就是在最大化y=0的概率,符合直观上的认知。

为什么分类常用CEL而不是MSE

  • (1)Sigmoid+MSE可能出现的梯度离散问题。
  • (2)经验性的问题,CEL的梯度一开始很大收敛很快,到接近期望值时又变小使变化缓慢。

PyTorch里有Softmax+CEL在一起的定义好的接口,可以直接用,不必自己分开做。

import torch
from torch.nn import functional as F

x = torch.randn(1, 784)
w = torch.randn(10, 784)
logits = x @ w.t()

# 使用PyTorch自带的Softmax+CEL处理,这里传入的就是未经过Softmax的logits
cel = F.cross_entropy(logits, torch.tensor([3]))
print(cel)

# 自己手动处理
pred = F.softmax(logits, dim=1)  # 先做Softmax转成概率值
pred_log = torch.log(pred)  # 再将其取对数,即公式里的log Q(i)
cel_ = F.nll_loss(pred_log, torch.tensor([3]))
print(cel_)

运行结果:

tensor(11.2806)
tensor(11.2806)

你可能感兴趣的:(#,PyTorch)