查看原文
其他

【他山之石】浅谈数据标准化与Pytorch中NLLLoss和CrossEntropyLoss损失函数的区别

作者:Jermy·Lu

地址:https://www.zhihu.com/people/jian-helloai


01

数据标准化

1.1 Why
在实际问题中,训练数据通常具有多个特征维度,且多个特征维度的数据级是不同的。例如,在预测房价的回归问题中,影响房价的特征有:房屋面积、卧室数量等。显然,卧室数量的数量级为1~10,而房屋面积(假设以  为单位)的数量级为  ~  。如果直接使用原始数据值,则会导致由于不同特征维度的数据级不同而造成的对预测结果的偏差,甚至在训练过程中出现  或不收敛的情况。
1.2 How
因此,当原始数据的不同特征维度的数据级不一致时,需要对原始数据进行标准化(Normalization)
1.2.1 Min-Max标准化
Min-Max标准化也称作离差标准化,是对原始数据进行的一种线性变换,变换结果值被映射到  之间。转换函数如下所示,其中max为样本数据该维度的最大值,min为样本数据该维度的 最小值。
1.2.2 Z-score标准化
Z-score标准化使用原始数据对应特征维度的均值(  )和标准差(  )进行数据的标准化,若原始数据分布为正态分布,经过Z-score标准化过的数据分布符合标准正态分布,其转化函数如下所示。

02

Pytorch中Softmax、LogSoftmax、NLLLoss和CrossEntropyLoss损失函数的关系

2.1 Softmax
 激活函数的计算方式是对输入向量的每个值  求以自然常数  为底的指数,然后再除以每个值  对应的以  为底的指数和,其计算公式如下所示:
举例:假设张量  的每一行表示模型预测的一张图片属于cat、dog和pig的得分。然后对张量  计算  ,即可得到每张图片分别属于cat、dog和pig的概率。显然,模型认为第一张、第二张图片、第四张图片更可能属于pig、第三张图片更可能属于cat。
>>> import torch>>> import torch.nn as nn>>> output = torch.rand(4, 3)>>> outputtensor([[0.8013, 0.3554, 0.8037], [0.6099, 0.7061, 0.7492], [0.6697, 0.3425, 0.1116], [0.4505, 0.1743, 0.5942]])>>> sfm = nn.Softmax(dim=1)>>> sfm(output)tensor([[0.3784, 0.2423, 0.3793], [0.3076, 0.3387, 0.3536], [0.4360, 0.3144, 0.2496], [0.3433, 0.2604, 0.3963]])
2.2 LogSoftmax
顾名思义, 就是对  得到的值再进行一次  变换,其计算公式如下所示。
举例:直接对上面的  进行  变换 和 直接对上面的  进行  变换,结果分别如下所示。显然,两者的结果是一致的。
>>> logsfm = torch.log(sfm(output))>>> logsfmtensor([[-0.9718, -1.4177, -0.9694], [-1.1788, -1.0826, -1.0395], [-0.8300, -1.1571, -1.3881], [-1.0693, -1.3454, -0.9255]])>>> logsfm = nn.LogSoftmax(dim=1)>>> logsfm(output)tensor([[-0.9718, -1.4177, -0.9694], [-1.1788, -1.0826, -1.0395], [-0.8300, -1.1571, -1.3881], [-1.0693, -1.3454, -0.9255]])
2.3 NLLLoss
首先,简单地谈下我对NLLLoss损失函数的理解。
经过上面的计算我们知道,  计算出来的值范围在  ,值的含义表示对应类别的概率。也就是说,每行中最接近于  的值对应的类别,就是该图片所属概率最大的类别。这时,目标是最大化概率。但在机器学习中,通常最小化某个函数值,因此,对概率值再进行一次  变换。经过  变换之后,最大概率值即为最接近于  的值。其它概率值经  变换之后,均为小于  的实值。为了满足最小化的条件,  函数通常会取个负号(  )。此时,若实际标签张量在模型输出结果  的对应位置的值越接近0,则具有越小的损失值;否则,损失值越大。
举例: 假设实际标签张量为  (pig, pig, cat, dog),而模型输出结果为  。因此,直接使用NLLLoss损失函数计算预测结果和Real Label之间的损失值如下所示。
>>>logsfm(output)tensor([[-0.9718, -1.4177, -0.9694], [-1.1788, -1.0826, -1.0395], [-0.8300, -1.1571, -1.3881], [-1.0693, -1.3454, -0.9255]])>>> loss = nn.NLLLoss()>>> target = torch.tensor([2, 2, 0, 1])>>> loss(logsfm(output), target)tensor(1.0461)
Of course, 实际标签张量为  ,因此我们可以手动计算NLLLoss损失函数对应的损失值。显然,两者的计算结果是一致的。
>>> loss = logsfm(output)[0, 2] + logsfm(output)[1, 2] + logsfm(output)[2, 0] + logsfm(output)[3, 1]>>> losstensor(-4.1843)>>> -loss / logsfm(output).size()[0]tensor(1.0461)
2.4 CrossEntropyLoss
 损失函数即为  ,一步到位。  的输入就是模型的直接输出,如下所示。显然,结果与之前计算的  值一致。
>>> loss = nn.CrossEntropyLoss()>>> targettensor([2, 2, 0, 1])>>> outputtensor([[0.8013, 0.3554, 0.8037], [0.6099, 0.7061, 0.7492], [0.6697, 0.3425, 0.1116], [0.4505, 0.1743, 0.5942]])>>> loss(output, target)tensor(1.0461)


本文目的在于学术交流,并不代表本公众号赞同其观点或对其内容真实性负责,版权归原作者所有,如有侵权请告知删除。

直播预告




历史文章推荐



分享、点赞、在看,给个三连击呗!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存