PyTorch 0.3中F.cross_entropy()的weight参数为何失效?如何正确使用?
我来帮你搞清楚PyTorch 0.3里F.cross_entropy()的weight参数到底怎么工作,以及为什么你改了权重却看不到输出变化。
问题出在哪:单个样本 + 默认的
size_average=True 你的代码里只用了一个样本,而PyTorch 0.3中F.cross_entropy()默认开启size_average=True——这个参数会让计算最终损失时,把加权后的总损失除以所有目标样本对应类别的权重总和。
对你的单个样本来说,这个总和就是该样本所属类别(类别1)的权重值本身。比如你设w=[1.0,10.0,1.0]时,分子是10 * 原始损失,分母是10,一除就把权重的影响完全抵消了,结果自然和没加权重时一样。
weight参数的作用机制 F.cross_entropy()其实是两步操作的组合:先对输入做log_softmax,再调用F.nll_loss()(负对数似然损失),weight参数会直接传给nll_loss(),具体逻辑是:
weight是一个1维张量,长度等于你的类别总数,每个元素对应一个类别的损失权重- 计算每个样本的损失时,会把该样本对应类别的基础损失乘以
weight中对应的元素 - 如果
size_average=True(默认),最终损失是加权总损失除以目标样本的权重总和;如果设为False,则直接返回加权后的总损失,不做除法
正确使用
weight的两种方式 要看到权重对损失的影响,你可以选下面两种方法之一:
方法1:关闭size_average
直接设置size_average=False,这样就不会做除法抵消权重,能直接看到加权后的损失值:
import torch from torch.autograd import Variable import torch.nn.functional as F x = Variable(torch.Tensor([[1.0,2.0,3.0]])) y = Variable(torch.LongTensor([1])) # 权重全为1 w = torch.Tensor([1.0,1.0,1.0]) print(F.cross_entropy(x, y, w, size_average=False)) # 输出: tensor(1.4076) # 类别1的权重设为10 w = torch.Tensor([1.0,10.0,1.0]) print(F.cross_entropy(x, y, w, size_average=False)) # 输出: tensor(14.0761)
方法2:使用多个不同类别的样本
当你有多个属于不同类别的样本时,目标样本的权重总和不再等于单个样本的权重,权重的影响就会体现出来。比如下面的例子,两个样本分别属于类别0和1,且它们的基础损失不同:
import torch from torch.autograd import Variable import torch.nn.functional as F # 两个样本,分别属于类别0和1,基础损失差异明显 x = Variable(torch.Tensor([[3.0,1.0,1.0], [1.0,2.0,3.0]])) y = Variable(torch.LongTensor([0, 1])) # 所有类别权重都是1 w = torch.Tensor([1.0,1.0,1.0]) print(F.cross_entropy(x, y, w)) # 输出约0.8233 # 类别0的权重设为10,其他为1 w = torch.Tensor([10.0,1.0,1.0]) print(F.cross_entropy(x, y, w)) # 输出约0.3452,和之前结果差异明显
总结一下
- 单个样本+
size_average=True的组合会抵消权重的影响,这就是你看不到变化的原因 weight是给每个类别分配损失权重,用来平衡不同类别样本数量不均或者重要性差异的场景- 要验证权重效果,要么关闭
size_average,要么用多个不同类别的样本
内容的提问来源于stack exchange,提问作者konchy
相关产品推荐
相关产品推荐

