Pytorch的损失函数汇总
loss函数都有size_average和reduce.两个都是布尔型的参数。因为一般函数都是直接计算batch的数据,因此返回的loss结果都是维度为(batch_size,)向量.
- reduce=False,那么size_average参数失效,直接返回向量形式的loss
- 如果reduce=True,那么loss返回的是标量
- 如果size_average=True,返回loss.mean()
nn.L1Loss
这里只要求x和y的维度要一样
得到的loss维度也是对应一样的。
nn.SmoothL1Loss
这里都是element-wise的操作,下标i是x的第i个元素
nn.MSELoss
其中loss,x,y的维度都一样,可以是向量或矩阵1
2
3
4
5
6loss_fn = torch.nn.MSELoss(reduce=False, size_average=False)
input = torch.autograd.Variable(torch.randn(3,4))
target = torch.autograd.Variable(torch.randn(3,4))
loss = loss_fn(input, target)
print(input); print(target); print(loss)
print(input.size(), target.size(), loss.size())
nn.BCELoss
二分类用的是交叉熵,用的时候需要在该层前面加上Sigmoid函数.交叉熵的离散版本为:$H(p,q)=-\sum_ip_ilogq_i$,其中p,q都是向量,且都是概率分布.如果二分类的话,因为只有正例和反例,且两者的概率和为1,那么只需要预测一个概率就好了:
注意这里x,y可以是向量或者矩阵,i只是下标;$x_i$表示第i个样本预测为正例的概率1
2
3
4
5
6import torch.nn.functional as F
loss_fn = torch.nn.BCELoss(reduce=False, size_average=False)
input = Variable(torch.randn(3, 4))
target = Variable(torch.FloatTensor(3, 4).random_(2))
loss = loss_fn(F.sigmoid(input), target)
print(input); print(target); print(loss)
有时遇到正负样本不均衡的时候,要设置权重,权重形状与target形状一样1
2
3
4
5class_weight = Variable(torch.FloatTensor([1, 10])) # 这里正例比较少,因此权重要大一些
target = Variable(torch.FloatTensor(3, 4).random_(2))
weight = class_weight[target.long()] # (3, 4)
loss_fn = torch.nn.BCELoss(weight=weight, reduce=False, size_average=False)
# balabala...
nn.BCEWithLogitsLoss
上面的nn.BCELoss需要手动加上一个Sigmoid层,这里结合了两者,这样做能够利用log_sum_exo_trick,使得数值结果更加稳定.建议使用这个损失函数
nn.CrossEntropyLoss
多分类用的交叉熵损失函数,用这个loss前面不需要加Softmax层
这里损失函数的计算,案例说应该也是原始交叉熵公式的形式,但是这里限制了target类型为torch.LongTensor,而且不是多标签意味着标签是one-hot编码形式.
nn.NLLLoss
用于多分类的负对数似然损失函数
在前面接上一个nn.LogSoftmax层就等价于交叉熵损失了.事实上,nn.CrossEntropyLoss也是调用这个函数.注意这里的$x_{label}$和上个交叉熵里的不一样
nn.NLLLoss2d
和上面类似,但是多了几个维度,一般用在图片上
input:(N,C,H,W)
target:(N,H,W)
比如全卷积网络时,最后图片的每个点都会预测一个类别标签
nn.KLDivLoss
KL散度,又叫做相对熵,算的是两个分布之间的距离
这里的x_i是log概率
nn.MarginRankingLoss
评价相似度损失
这里的三个都是标量,y只能取1或者-1.取1时表示$x_1比x_2$要大,反之,$x_2$要大.