文章目录
1 Loss 介绍
在机器学习中,损失函数是代价函数的一部分,而代价函数则是目标函数的一种类型。
Loss function,即损失函数:用于定义单个训练样本与真实值之间的误差;
Cost function,即代价函数:用于定义单个批次/整个训练集样本与真实值之间的误差;
Objective function,即目标函数:泛指任意可以被优化的函数。
KL散度 = 交叉熵 - 熵
回归损失:用于预测连续的值。如预测房价、年龄等。
分类损失:用于预测离散的值。如图像分类,语义分割等。
排序损失:用于预测输入数据之间的相对距离。如行人重识别。
pytorch里的weight decay相当于l2正则
2 常见 Loss
L1 loss
L o s s ( p r e d , y ) = ∣ y − p r e d ∣ Loss( pred , y ) = | y - pred | Loss(pred,y)=∣y−pred∣
import torch
input = torch.randn(3, 5, requires_grad=True)
target = torch.randn(3, 5)
mae_loss = torch.nn.L1Loss()
output = mae_loss(input, target)
等价于
for i in range(3):
for j in range(5):
result += abs(input[i][j] - target[i][j])
result /= 15
L2 loss
L o s s ( p r e d , y ) = ∑ ∣ y − p r e d ∣ 2 Loss( pred , y ) = \sum| y - pred |^2 Loss(pred,y)=∑∣y−pred∣2
input = torch.randn(3, 5, requires_grad=True)
target = torch.randn(3, 5)
mse_loss = torch.nn.MSELoss()
output = mse_loss(input, target)
等价于
for i in range(3):
for j in range(5):
result += (input[i][j] - target[i][j])**2
result /= 15
Negative Log-Likelihood(NLL)
它的特性是惩罚预测准确而预测概率不高的情况
l o s s ( p r e d , y ) = − ( l o g p r e d ) loss( pred, y) = - (log pred) loss(pred,y)=−(logpred)
注:NLL 要求网络最后一层使用 softmax 作为激活函数。通过 softmax 将输出值映射为每个类别的概率值。
# size of input (N x C) is = 3 x 5
input = torch.randn(3, 5, requires_grad=True)
# every element in target should have 0 <= value < C
target = torch.tensor([1, 0, 4])
m = torch.nn.LogSoftmax(dim=1)
nll_loss = torch.nn.NLLLoss()
output = nll_loss(m(input), target)
补充
Softmax 函数常用的用法是指定参数 dim
1)dim=0:对每一列
2)dim=1:对每一行
LogSoftmax 对 softmax 的结果进行 log,即 Log(Softmax(x))
logsoftmax 解决函数 overflow 和 underflow,加快运算速度,提高数据稳性定。
防止溢出
Binary Cross-Entropy
import torch
a = torch.randn(3,3)
target = torch.FloatTensor([[0,1,1],
[0,0,1],
[1,0,1]])
"compute torch without sigmoid"
loss2 = torch.nn.BCEWithLogitsLoss()
print(loss2(a, target))
"compute torch with sigmoid"
s = a.sigmoid()
loss1 = torch.nn.BCELoss()
print(loss1(s, target))
"compute yourself"
loss_mul = 0
for i in range(3):
for j in range(3):
x = target[i][j]*torch.log(s[i][j]) + (1-target[i][j])*torch.log(1-s[i][j])
loss_mul += x
print(-loss_mul/9)
Cross-Entropy
交叉熵损失函数的与 logsoftmax+NLL 损失函数结果一致
l o s s ( p r e d , y ) = − ∑ y l o g p r e d loss( pred, y) = - \sum ylogpred loss(pred,y)=−∑ylogpred
input = torch.randn(3, 5, requires_grad=True)
target = torch.empty(3, dtype=torch.long).random_(5) # 0~4
cross_entropy_loss = torch.nn.CrossEntropyLoss()
output = cross_entropy_loss(input, target)
等价于
m = torch.nn.LogSoftmax(dim=1)
nll_loss = torch.nn.NLLLoss()
output = nll_loss(m(input), target)
Hinge Embedding
l o s s ( p r e d , y ) = m a x ( 0 , 1 − y ∗ p r e d ) loss(pred, y) = max(0, 1 - y * pred ) loss(pred,y)=max(0,1−y∗pred)
其中 y 为 1 或 -1。
应用场景:
- 分类问题,特别是在确定两个输入是否不同或相似时。
- 学习非线性嵌入或半监督学习任务。
input = torch.randn(3, 5, requires_grad=True)
target = torch.randn(3, 5)
hinge_loss = torch.nn.HingeEmbeddingLoss()
output = hinge_loss(input, target)
Margin Ranking Loss
l
o
s
s
(
p
r
e
d
,
y
)
=
m
a
x
(
0
,
−
y
∗
(
p
r
e
d
1
−
p
r
e
d
2
)
+
m
a
r
g
i
n
)
loss(pred, y) = max(0, -y*(pred1 - pred2) + margin)
loss(pred,y)=max(0,−y∗(pred1−pred2)+margin)
标签张量 y(包含 1 或 -1)。
当 y == 1 时,第一个输入将被假定为更大的值。它将排名高于第二个输入。如果 y == -1,则第二个输入将排名更高。
应用场景:排名问题
input_one = torch.randn(3, requires_grad=True)
input_two = torch.randn(3, requires_grad=True)
target = torch.randn(3).sign() # 1 or -1
ranking_loss = torch.nn.MarginRankingLoss()
output = ranking_loss(input_one, input_two, target)
Triplet Margin Loss
L o s s ( a , p , n ) = m a x 0 , d ( a i , p i ) − d ( a i , n i ) + m a r g i n Loss (a, p, n) = max{0, d(ai, pi) - d(ai, ni) + margin} Loss(a,p,n)=max0,d(ai,pi)−d(ai,ni)+margin
三元组由 a (anchor),p (正样本) 和 n (负样本)组成.
应用场景:
- 确定样本之间的相对相似性
- 用于基于内容的检索问题
anchor = torch.randn(100, 128, requires_grad=True)
positive = torch.randn(100, 128, requires_grad=True)
negative = torch.randn(100, 128, requires_grad=True)
triplet_margin_loss = torch.nn.TripletMarginLoss(margin=1.0, p=2)
output = triplet_margin_loss(anchor, positive, negative)
图片来源 一文理解Ranking Loss/Margin Loss/Triplet Loss
KL Divergence Loss
计算两个概率分布之间的差异。
l o s s ( p r e d , y ) = y ∗ ( l o g y − p r e d ) loss (pred, y) = y*( log y - pred) loss(pred,y)=y∗(logy−pred)
输出表示两个概率分布的接近程度。如果预测的概率分布与真实的概率分布相差很远,就会导致很大的损失。如果 KL Divergence 的值为零,则表示概率分布相同。
应用场景:
- 逼近复杂函数
- 多类分类任务
- 确保预测的分布与训练数据的分布相似
input = torch.randn(2, 3, requires_grad=True)
target = torch.randn(2, 3)
kl_loss = torch.nn.KLDivLoss(reduction = 'batchmean')
output = kl_loss(input, target)
下面手动对比计算一下
import torch
import torch.nn as nn
batch_size = 32
embedding = 3*128*128
random_q = torch.randn(batch_size, embedding)
random_p = torch.randn(batch_size, embedding)
# generate random probabilities
q = nn.functional.softmax(random_q, dim=-1)
p = nn.functional.softmax(random_p, dim=-1)
k1_loss = nn.KLDivLoss(reduction="batchmean")
loss = k1_loss(q.log(), p)
print(loss)
# equivalent to the following calculation, log = log e
loos_pointwise = p*(p.log() - q.log())
loss = loos_pointwise.sum(dim=-1).mean()
print(loss)
"""
tensor(1.0018)
tensor(1.0018)
"""
3 Loss 设计
作者:Alan Huang
https://www.zhihu.com/question/268105631/answer/335246543
Multi-task learning 还需要解决的是 Gradient domination 的问题。这个问题产生的原因是不同任务的 loss 的梯度相差过大, 导致梯度小的 loss 在训练过程中被梯度大的 loss 所带走。
如果一开始就给不同的 Loss 进行加权, 让它们有相近的梯度, 是不是就能训练的好呢? 结果往往不是这样的。 不同的loss, 他们的梯度在训练过程中变化情况也是不一样的;而且不同的 loss, 在梯度值相同的时候, 它们在 task 上的表现也是不同的。在训练开始的时候,虽然 balance 了, 但是随着训练过程的进行, 中间又发生 gradient domination 了。 所以要想解决这个问题, 还是要合适地对不同 loss 做合适的均衡。
如果A和B单独训练, 他们在收敛的时候的梯度大小分别记为 Grad_a, Grad_b, 那么我们只需要在两个任务一起训练的时候, 分别用各自梯度的倒数(1/Grad_a, 1/Grad_b)对两个任务做平衡, 然后统一乘一个scalar就可以了。(根据单任务的收敛时候的loss梯度去确定multi-task训练中不同任务的权重。)
作者:刘诗昆
https://www.zhihu.com/question/268105631/answer/333738561
Gradient balancing method 一定需要建立在网络设计足够好的基础上,不然光凭平衡梯度并不会对网络泛化能力有着显著的改变。
自定义 loss pytorch 代码
class MyLoss(torch.nn.Moudle):
def __init__(self):
super(MyLoss, self).__init__()
def forward(self, x, y):
loss = torch.mean((x - y) ** 2)
return loss
4 softmax 及其变体
声明:学习笔记,摘抄来自网络
soft softmax loss
知识蒸馏里面的
Large-Margin Softmax Loss(L-softmax)
m是一个控制距离的变量,它越大训练会变得越困难,因为类内不可能无限紧凑
作者的实现是通过一个 LargeMargin 全连接层+softmax loss来共同实现,可参考代码。
angular softmax loss(A-softmax)
large margin softmax loss的基础上添加了两个限制条件||W||=1和b=0,使得预测仅取决于W和x之间的角度θ
L2-constrained softmax loss
上面式就是将其归一化到固定值α。实际训练的时候都不需要修改代码,只需要添加L2-norm层与scale层,如下图。
scale 更有利于优化
additive margin softmax loss
就是把L-Softmax的乘法改成了减法,同时加上了尺度因子s。作者这样改变之后前向后向传播变得更加简单。其中W和f都是归一化过的,作者在论文中将m设为0.35。
argface additive angular margin
在 hardmax 中,真正最大的那个数,一定是以1(100%) 的概率被选出来,其他的值根本一点机会没有。但是在 softmax 中,所有的值都有机会被作为最大值选出来。只不过,由于 softmax 的 “马太效应”,次大的数,即使跟真正最大的那个数差别非常少,在概率上跟真正最大的数相比也小了很多。
“softmax 的作用是把 一个序列,变成概率。” 这个概率不是别的,而是被选为 max 的概率。
cross entropy 是用来衡量两个概率分布之间的距离的,softmax能把一切转换成概率分布,那么自然二者经常在一起使用。但是你只需要简单推导一下,就会发现,softmax + cross entropy 就好像
“往东走五米,再往西走十米”,
cross_entropy = log_softmax + nll_loss
作者:董鑫
链接:https://www.zhihu.com/question/294679135/answer/885285177
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
5 Loss 异常
错误数据
通过设置 batch_size = 1,shuffle = False 一步一步地将sample定位到了所有可能的脏数据,删掉
弱化场景,将你的样本简化,各个学习率等参数采用典型配置,比如10万样本都是同一张复制的,让这个网络去拟合,如果有问题,则是网络的问题。否则则是各个参数的问题。
附录A——激活函数
A1 mish
def mish(x):
return x * torch.tanh(torch.nn.functional.softplus(x))
x = torch.arange(start=-10, end=10, step=0.01)
y = mish(x)
plt.plot(x.numpy(), y.numpy())
plt.title("mish")
plt.savefig("mish.png")