损失函数
损失函数(loss function)是用来估量模型的预测值(我们例子中的output
)与真实值(例子中的y_train
)的不一致程度,它是一个非负实值函数,损失函数越小,模型的鲁棒性就越好。
我们训练模型的过程,就是通过不断的迭代计算,使用梯度下降的优化算法,使得损失函数越来越小。损失函数越小就表示算法达到意义上的最优。
这里有一个重点:因为PyTorch是使用mini-batch来进行计算的,所以损失函数的计算出来的结果已经对mini-batch取了平均。
1.范数
1.1 nn.L1Loss
L1范数损失函数,也被称为最小绝对值偏差(LAD),最小绝对值误差(LAE)。总的说来,它是把目标值 Y i Y_i Yi与估计值 f ( x i ) f(x_i) f(xi)的绝对差值的总和最小化:
l o s s ( Y i , f ( x i ) ) = 1 n ∑ ∣ Y i − f ( x i ) ∣ loss(Y_i,f(x_i))=\frac{1}{n} \sum|Y_i-f(x_i)| loss(Yi,f(xi))=n1∑∣Yi−f(xi)∣
优点:
- 收敛速度比L2损失函数要快,L1能提供更大且稳定的梯度。
- 对异常的离群点有更好的鲁棒性
缺点:
- 梯度恒定,不论预测值是否接近真实值,这很容易导致发散,或者错过极值点。
- 导数不连续,导致求解困难。这也是L1损失函数不广泛使用的主要原因。
1.2 均方误差损失(L2范数)
均方损失函数 ,输入x和目标y之间均方差
l o s s ( x , y ) = 1 n ∑ ( x i − y i ) 2 loss(x,y)=\frac{1}{n} \sum(x_i-y_i)^2 loss(x,y)=n1∑(xi−yi)2
优点:
- 使训练更容易,因为它的梯度随着预测值接近真实值而不断减小,那么它不会轻易错过极值点,但也容易陷入局部最优。
- 它的导数具有封闭解,优化和编程非常容易,所以很多回归任务都是用MSE作为损失函数。
缺点:
- 收敛速度比L1慢,因为梯度会随着预测值接近真实值而不断减小。
- 对异常数据比L1敏感,这是平方项引起的,异常数据会引起很大的损失。
2. 交叉熵损失
2.1 nn.NLLLoss
用于多分类的负对数似然损失函数
l o s s ( x , c l a s s ) = − x [ c l a s s ] loss(x, class) = -x[class] loss(x,class)=−x[class]
NLLLoss中如果传递了weights参数,会对损失进行加权,公式就变成了
l o s s ( x , c l a s s ) = − w e i g h t s [ c l a s s ] ∗ x [ c l a s s ] loss(x, class) = -weights[class] * x[class] loss(x,class)=−weights[class]∗x[class]
2.2 nn.CrossEntropyLoss
多分类用的交叉熵损失函数,LogSoftMax和NLLLoss集成到一个类中,会调用nn.NLLLoss函数,我们可以理解为CrossEntropyLoss()=log_softmax() + NLLLoss()
l o s s ( x , c l a s s ) = − l o g e x p ( x [ c l a s s ] ) ∑ j e x p ( x [ j ] ) ) = − x [ c l a s s ] + l o g ( ∑ j e x p ( x [ j ] ) ) loss(x,class)=−log\frac{exp(x[class])}{∑_jexp(x[j]))} =−x[class]+log(∑_j exp(x[j])) loss(x,class)=−log∑jexp(x[j]))exp(x[class])=−x[class]+log(j∑exp(x[j]))
因为使用了NLLLoss,所以也可以传入weight参数,这时loss的计算公式变为:
l o s s ( x , c l a s s ) = w e i g h t s [ c l a s s ] ∗ ( − x [ c l a s s ] + l o g ( ∑ j e x p ( x [ j ] ) ) ) loss(x, class) = weights[class] * (-x[class] + log(\sum_j exp(x[j]))) loss(x,class)=weights[class]∗(−x[class]+log(j∑exp(x[j])))
所以一般多分类的情况会使用这个损失函数
2.3 nn.BCELoss
BCELoss 是CrossEntropyLoss的一个特例,只用于二分类问题
l o s s ( o , t ) = − 1 n ∑ i ( t [ i ] l o g ( o [ i ] ) + ( 1 − t [ i ] ) l o g ( 1 − o [ i ] ) ) loss(o,t)=-\frac{1}{n}\sum_i(t[i] log(o[i])+(1-t[i]) log(1-o[i])) loss(o,t)=−n1i∑(t[i]log(o[i])+(1−t[i])log(1−o[i]))
与NLLLoss类似,也可以添加权重参数:
l o s s ( o , t ) = − 1 n ∑ i w e i g h t s [ i ] ( t [ i ] l o g ( o [ i ] ) + ( 1 − t [ i ] ) ∗ l o g ( 1 − o [ i ] ) ) loss(o,t)=-\frac{1}{n}\sum_iweights[i] (t[i] log(o[i])+(1-t[i])* log(1-o[i])) loss(o,t)=−n1i∑weights[i](t[i]log(o[i])+(1−t[i])∗log(1−o[i]))
用的时候需要在该层前面加上 Sigmoid 函数
Loss_function = torch.nn.BCELoss()
loss = Loss_function(output, target)
2.4 BCEWithLogitsLoss
在BCELoss的基础上融合了Sigmoid
torch.nn.BCEWithLogitsLoss(weight: Optional[torch.Tensor] = None, size_average=None, reduce=None, reduction: str = 'mean', pos_weight: Optional[torch.Tensor] = None)
参数:
-
weight:每个分类的缩放权重,传入的大小必须和类别数量一至
-
size_average:bool类型,为True时,返回的loss为平均值,为False时,返回的各样本的loss之和
-
reduce:bool类型,返回值是否为标量,默认为True
-
reduction:string类型,‘none’ | ‘mean’ | 'sum’三种参数值
-
pos_weight:正样本的权重, 当p>1,提高召回率,当p<1,提高精确度。可达到权衡召回率(Recall)和精确度(Precision)的作用。
3. KL散度
KL散度(相对熵)是用来衡量两个概率分布之间的差异。
D ( P ∥ Q ) = ∑ P ( x ) l o g Q ( x ) P ( x ) D(P∥Q)=∑P(x)log \frac{Q(x)}{P(x)} D(P∥Q)=∑P(x)logP(x)Q(x)
torch.nn.KLDivLoss(size_average=None, reduce=None, reduction: str = 'mean', log_target: bool = False)
参数:
- size_average:bool类型,为True时,返回的loss为平均值,为False时,返回的各样本的loss之和
- reduce:bool类型,返回值是否为标量,默认为True
- reduction-三个值,none: 不使用约简;mean:返回loss和的平均值;sum:返回loss的和。默认:mean
- log_target:默认False,指定是否在日志空间中传递目标
4.合页损失
有人把hinge loss称为铰链损失函数,它可用于“最大间隔(max-margin)”分类,其最著名的应用是作为SVM的损失函数。
torch.nn.HingeEmbeddingLoss(margin: float = 1.0, size_average=None, reduce=None, reduction: str = 'mean')
5.余弦相似度
余弦相似度是机器学习中的一个重要概念,在Mahout等MLlib中有几种常用的相似度计算方法,如欧氏相似度,皮尔逊相似度,余弦相似度,Tanimoto相似度等。其中,余弦相似度是其中重要的一种。余弦相似度用向量空间中两个向量夹角的余弦值作为衡量两个个体间差异的大小。相比距离度量,余弦相似度更加注重两个向量在方向上的差异,而非距离或长度上。
余弦相似度更多的是从方向上区分差异,而对绝对的数值不敏感,更多的用于使用用户对内容评分来区分用户兴趣的相似度和差异,同时修正了用户间可能存在的度量标准不统一的问题(因为余弦相似度对绝对数值不敏感),公式如下:
s i m ( X , Y ) = c o s θ = x ⃗ ⋅ y ⃗ ∥ x ⃗ ∥ ∥ y ⃗ ∥ sim(X,Y)=cos\theta=\frac{\vec{x} \cdot \vec{y}}{\left \| \vec{x} \right \| \left \| \vec{y} \right \|} sim(X,Y)=cosθ=∥x∥∥y∥x⋅y
torch.nn.CosineEmbeddingLoss(margin: float = 0.0, size_average=None, reduce=None, reduction: str = 'mean')