Softmax分类以及交叉熵详解

Softmax分类以及交叉熵详解

Softmax分类

写这篇文章的目的是记录下实现分类时所遇到的问题在李沐的动手学深度学习中有这样的代码

y = torch.tensor([0, 2])
y_hat = torch.tensor([[0.1, 0.3, 0.6], [0.3, 0.2, 0.5]])
y_hat[[0, 1], y]

即使有如下解释:

我们[创建一个数据样本y_hat,其中包含2个样本在3个类别的预测概率, 以及它们对应的标签y] 有了y,我们知道在第一个样本中,第一类是正确的预测; 而在第二个样本中,第三类是正确的预测。 然后(使用y作为y_hat中概率的索引), 我们选择第一个样本中第一个类的概率和第二个样本中第三个类的概率。我也不太明白。

现在我引入实例现在有两张图片对应的标签就是图片所代表的真实的类别:

Softmax分类以及交叉熵详解_第1张图片

Softmax分类以及交叉熵详解_第2张图片

三个类别分别为猫,狗,兔子,两个样本代表两个图像,那么y[0,2]代表第一张图真实标签猫,第二张图代表真实标签兔子。

兔子
预测概率(y_hat)猫图 0.1 0.3 0.6
预测概率(y_hat)兔图 0.3 0.2 0.5

进行试验操作看结果是否与推断一样

y = torch.tensor([0, 2])
y_hat = torch.tensor([[0.1, 0.3, 0.6], [0.3, 0.2, 0.5]])
y_hat[[0, 1], y]  # 作用是得到真实类别下的预测概率(二维索引)
tensor([0.1000, 0.5000])

输出则为图一判定为猫的概率为0.1,图二判定为兔子的概率为0.5

下面我们改为y = torch.tensor([0, 0])

y = torch.tensor([0, 0])
y_hat = torch.tensor([[0.1, 0.3, 0.6], [0.3, 0.2, 0.5]])
y_hat[[0, 1], y]  # 作用是得到真实类别下的预测概率(二维索引)
tensor([0.1000, 0.3000])

结果是输出两张照片的第一个类别(猫)的概率

交叉熵

动手学深度学习交叉熵代码如下

def cross_entropy(y_hat, y):
    return - torch.log(y_hat[range(len(y_hat)), y])  #  torch.log以自然对数为底

cross_entropy(y_hat, y)
tensor([2.3026, 0.6931])

初次看到这行代码我非常疑惑我知道信息熵的公式是
H ( X ) = − ∑ i = 1 n P ( x i ) log ⁡ ( P ( x i ) ) ) ( X = x 1 , x 2 , x 3 … , x n ) \left.H(\mathbf{X})=-\sum_{i=1}^{n} P\left(x_{i}\right) \log \left(P\left(x_{i}\right)\right)\right) \quad\left(\mathbf{X}=x_{1}, x_{2}, x_{3} \ldots, x_{n}\right) H(X)=i=1nP(xi)log(P(xi)))(X=x1,x2,x3,xn)
但是代码中log(y_hat[range(len(y_hat)), y])中的式子我不太理解那么我就从信息熵开始来解析下交叉熵的真面目

交叉熵是信息论中的一个重要概念,主要用于度量两个概率分布间的差异性。公式表示为:
H ( p , q ) = − ∑ i = 1 n p ( x i ) log ⁡ ( q ( x i ) ) H(p, q)=-\sum_{i=1}^{n} p\left(x_{i}\right) \log \left(q\left(x_{i}\right)\right) H(p,q)=i=1np(xi)log(q(xi))
在机器学习中,常常使用P(x)来表示样本的真实分布Q(x)来表示模型所预测的分布,比如在一个三分类任务中 (例如,猫狗兔分类器),x1,x2,x3分别代表猫,狗,马,例如一张猫的图片真实分布P(X)=[1,0,0], 预测分布 Q(X)=[0.7,0.2,0.1]

看到这里是不是理解进了一步,好了我们又回到上面的例子。

兔子
预测概率(y_hat)猫图 0.1 0.3 0.6
预测概率(y_hat)兔图 0.3 0.2 0.5
兔子
p(x)(第一张样本图片的真实概率) 1 0 0
q(x)第一张样本图片的预测概率) 0.1 0.3 0.6
p(x)(第二张样本图片的真实概率) 0 0 1
q(x)第二张样本图片的预测概率) 0.3 0.2 0.5

现在有了两张样本图像的真实分布和预测分布那么我们就可以算出交叉熵损失了。
H ( p , q ) = − ∑ i = 1 n p ( x i ) log ⁡ ( q ( x i ) ) = − 1 ∗ l n ( 0.1 ) = 2.3025 H ( p , q ) = − ∑ i = 1 n p ( x i ) log ⁡ ( q ( x i ) ) = − 1 ∗ l n ( 0.5 ) = 0.6931 与 输 出 t e n s o r ( [ 2.3026 , 0.6931 ] ) 保 持 一 致 H(p, q)=-\sum_{i=1}^{n} p\left(x_{i}\right) \log \left(q\left(x_{i}\right)\right)=-1*ln(0.1)=2.3025\\ H(p, q)=-\sum_{i=1}^{n} p\left(x_{i}\right) \log \left(q\left(x_{i}\right)\right)=-1*ln(0.5)=0.6931\\与输出tensor([2.3026, 0.6931])保持一致 H(p,q)=i=1np(xi)log(q(xi))=1ln(0.1)=2.3025H(p,q)=i=1np(xi)log(q(xi))=1ln(0.5)=0.6931tensor([2.3026,0.6931])
现在我们应该很清楚 **- torch.log(y_hat[range(len(y_hat)), y])**的含义了,让我们回想一下上一次用到类似的语句是在哪里,代码如下

y = torch.tensor([0, 2])
y_hat = torch.tensor([[0.1, 0.3, 0.6], [0.3, 0.2, 0.5]])
torch.tensor([[0.1, 0.3, 0.6], [0.3, 0.2, 0.5]])[[0, 1], y]
tensor([0.1000, 0.5000])

利用y加入的二维索引来导出真实类别的概率,然而交叉熵代码也是同样的的道理

def cross_entropy(y_hat, y):
    return - torch.log(y_hat[range(len(y_hat)), y])  # torch.log以自然对数为底
#  此处range(len(y_hat))=[0,1]索引出0.1和0.5 将-ln(0.1)+-ln(0.5)赋值给cross_entropy
cross_entropy(y_hat, y)

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