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(pred−y)最小,可以直接对其进行minimize。
而对于分类问题,目标是优化那些分类指标,比如accuracy、F1-score或者AUC等。
预测的是连续的还是离散的值,导致了回归和分类的本质区别。
两者最本质的区别在于分类问题并不能直接去对目标进行最优化,而回归问题可以直接对LOSS进行minimize来求解。要对分类问题的目标优化,可以用分布去拟合样本的分布,然后对分布的参数进行调整。
如果直接对分类问题的目标(比如accuracy)进行SGD来优化求解,主要会出现下面两种问题:
这种问题是因为分类是一个非0即1的问题,比如某个样本输出值为0.4,这样预测就是0号类别,而实际标签是1,这时调整权重使得其输出值为0.45接近了目标值1,但这样预测仍然是0号类别,其它样本也很可能是没有改变输出的标签,因此accuracy在这附近根本就是不变的。
比如某个样本的输出值是0.499预测为0类,调整一点权重使得输出值为0.5001预测为1类,这时accuracy突然就发生了很大的变化,并且这附近的梯度是不连续的。
可以将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=i∑P(i)logP(i)1=−i∑P(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。
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)=−i∑P(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(P∣Q)
其中 D K L ( p ∣ q ) D_{KL}(p|q) DKL(p∣q)是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−(1−y0)log(1−p)
这里 y 0 y_0 y0也就是取第0类的标注值,p是输出的概率(这里表示认为是第0类的概率)。从这个二分类问题的公式可以直观的理解CE可以作为优化目标,比如当样本y=0时,这里最小化CE也就是在最大化 log ( 1 − p ) \log (1-p) log(1−p)也就是在最大化 p p p也就是在最大化y=0的概率,符合直观上的认知。
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)