机器学习中的各种损失函数解析:若博文有不妥之处,望加以指点,笔者一定及时修正。
文章目录
① 损失函数
损失函数:计算一个样本的误差;
代价函数:整个训练集上所有样本误差的平均;
目标函数:代价函数+正则化项
方差:衡量随机变量或者一组数据的离散程度。方差越大,数据越离散。
标准差:方差的算术平方根,反映组类个体之间的离散程度。
1、Softmax Loss
S o f t m a x Softmax Softmax :将特征图扁平化后的输出映射到(0,1)之间,给出每个类的概率。假设最后一层特征图尺度是: 5 ∗ 5 ∗ 1000 5*5*1000 5∗5∗1000 。再将这些特征输入给扁平化 为 [ N N N X 1 1 1] 个向量(这里的 N N N 是 5 ∗ 5 ∗ 1000 = 25000 5*5*1000=25000 5∗5∗1000=25000)。下面扁平化的 [ N N N X 1 1 1] 的向量进入全连接层,全连接层的参数权重是 W W W[ T T T X N N N](这里的 T T T 表示分类的类别数),经过全连接层处理就会得到一个 [ T T T x 1 1 1] 的向量,但是这个向量里面都每个数值的大小都没有限制,或许是无穷大,也有可能是无穷小,均有可能。因此多分类时候,往往在全连接层后面接个 S o f t m a x Softmax Softmax 层。这个层的输入是 [ T T T x 1 1 1] 的向量,输出也是 [ T T T x 1 1 1] 的向量。但是输出的每个向量都归一化到 [ 0 , 1 ] [0,1] [0,1] 之间。这里的 S o f t m a x Softmax Softmax 输出的向量是该样本属于每一类的概率。
S
o
f
t
m
a
x
Softmax
Softmax公式:
P
j
=
e
a
j
∑
k
=
1
T
e
a
k
P_j=\frac{e^{a_j}}{\sum_{k=1}^{T}{e}^{a_k}}
Pj=∑k=1Teakeaj
上面公式中的
a
j
a_j
aj 表示这 [
T
T
T x
1
1
1] 个向量中的第
j
j
j 个值,而下面分母表示所有值的求和。上式成功的把
P
j
P_j
Pj 归一化到
(
0
,
1
)
(0,1)
(0,1) 之间。优化目标:属于正确标签的预测概率最高。
下面介绍
S
o
f
t
m
a
x
L
o
s
s
Softmax \ Loss
Softmax Loss:
L
=
−
∑
j
=
1
T
y
i
log
p
j
L=-\sum_{j=1}^{T}{y_i} \ {\log{p_j}}
L=−j=1∑Tyi logpj上式中的
p
j
p_j
pj 表示
S
o
f
t
m
a
x
Softmax
Softmax 层输出的第
j
j
j 的概率值。
y
y
y 表示一个 [
1
1
1 x
T
T
T] 的向量,里面的
T
T
T 列中只有一个为1,其余为0(真实标签的那个为1,其余不是正确的为0)。这个公式有一个更简单的形式是:
L
=
−
log
p
j
L=-\log p_j
L=−logpj其中的
j
j
j 是指当前样本的真实标签。
l
o
g
log
log函数是个递增的函数,你预测错的概率会比你预测对的概率要大,因为前面加了一个负号。
所以分类里面常用 S o f t m a x L o s s Softmax \ Loss Softmax Loss。
2、交叉熵(Cross Entropy)
p
(
x
)
p(x)
p(x) 为真实分布,根据真实分布
p
(
x
)
p(x)
p(x) 来衡量识别一个样本的所需要的编码长度的期望(平均编码长度)为:
H
(
p
)
=
∑
x
p
(
x
)
log
1
p
(
x
)
H(p)=\sum_{x}{p(x) \log \frac{1}{p(x)}}
H(p)=x∑p(x)logp(x)1 而交叉熵是使用预测的分布来表示来自真实分布的平均编码长度。也就是评估当前训练得到的概率分布与真实分布的差异情况,也就是使用错误分布来表示真实分布的平均编码程度。
H
(
p
,
q
)
=
−
∑
x
p
(
x
)
log
2
1
q
(
x
)
H(p,q)=-\sum_x{p(x) \log_2 \frac{1}{q(x)} }
H(p,q)=−x∑p(x)log2q(x)1其中
p
(
x
)
p(x)
p(x) 为真实分布,
q
(
x
)
q(x)
q(x) 是模型通过数据计算出来分布的概率。
减少交叉熵损失就是在提高模型的准确率。
预测的分布
q
(
x
)
q(x)
q(x)得到的平均编码长度
H
(
p
,
q
)
H(p,q)
H(p,q) > 真实分布
p
(
x
)
p(x)
p(x)得到的平均编码长度
H
(
p
)
H(p)
H(p)。
我们定义:由
q
(
x
)
q(x)
q(x)得到的平均编码长度比由
p
(
x
)
p(x)
p(x)得到的平均编码长度多出的部分称为 相对熵。
3、相对熵(KLD散度、Relative entropy)
D K L ( p , q ) = H ( p , q ) − H ( p ) = ∑ x p ( x ) log p ( x ) q ( x ) D_{KL}(p,q)=H(p,q)-H(p)=\sum_{x}{p(x)} \log\frac{p(x)}{q(x)} DKL(p,q)=H(p,q)−H(p)=x∑p(x)logq(x)p(x)它表示两个函数或者概率分布的差异性:差异性越大则相对熵越大,反之,差异越小,相对熵越小。这个量来衡量近似分布相比原分布究竟损失了多少信息量,而不是两个分布在空间中的远近距离,所以散度不是距离, D K L ( p , q ) ≠ D K L ( q , p ) D_{KL}(p,q) \ne D_{KL}(q,p) DKL(p,q)̸=DKL(q,p)不具有交换性。
3、平方损失函数、均方误差(MSE,Mean Squared Error)
通过对真实值和预测值的差求平方,直接测量输出与输入之间的距离,这就是线性回归的损失函数,常常用于回归中。定义输入为
y
i
y_i
yi,输出为
y
^
i
\hat y_i
y^i。那么平方损失函数定义为:(这边假设最终结果都服从于高斯分布)
L
(
x
)
=
1
N
∑
i
=
1
N
(
y
i
−
y
^
i
)
2
L(x)=\frac{1}{N} \sum_{i=1}^N{ ( y_i - \hat y_i)^2}
L(x)=N1i=1∑N(yi−y^i)2
4、均方误差与Softmax Loss的区别
均方误差用于多分类的时候,对每一类输出结果都很看重,交叉熵函数只对正确的分类结果看重。使用的一般原则:如果致力于解决的问题是回归问题的连续变量,使用均方误差比较合适;如果是分类问题的离散 O n e − h o t One-hot One−hot 向量,则交叉熵损失函数较合适。
举个例子,对于一个模型的输出为:
(
x
,
y
,
z
)
(x,y,z)
(x,y,z),真实结果是
(
0
,
1
,
0
)
(0,1,0)
(0,1,0),那么这个损失函数可以描述为:
S
o
f
t
m
a
x
L
o
s
s
:
L
S
=
−
0
∗
l
o
g
x
−
1
∗
l
o
g
y
−
0
∗
l
o
g
z
=
−
l
o
g
y
Softmax \ Loss:L_S =-0*logx-1*logy-0*logz=-logy
Softmax Loss:LS=−0∗logx−1∗logy−0∗logz=−logy
M
S
E
:
L
M
S
E
=
(
x
−
0
)
2
+
(
y
−
1
)
2
+
(
z
−
0
)
2
=
x
2
+
(
y
−
1
)
2
+
z
2
MSE:L_{MSE}=(x-0)^2 +(y-1)^2+(z-0)^2=x^2+(y-1)^2+z^2
MSE:LMSE=(x−0)2+(y−1)2+(z−0)2=x2+(y−1)2+z2我们可以看出均方误差只是将正确的分类尽可能大,其余让错误分类变得更加平均。这对回归问题特别重要,对分类作用不大。
5、平方绝对误差(MAE,Mean Absolute Error)
L
(
x
)
=
1
N
∑
i
=
1
N
∣
y
i
−
y
^
i
∣
L(x)=\frac{1}{N} \sum_{i=1}^N{ |y_i - \hat y_i|}
L(x)=N1i=1∑N∣yi−y^i∣
绝对损失函数的意义与均方误差差不多,只不过没有取平方,而是取绝对值,差距不会被平方放大。利用均方误差更容易求解,但是平方值误差对于异常值更为稳健。
6、最大均值差异(MMD,Maximum mean discrepancy)
参考链接:https://blog.csdn.net/a529975125/article/details/81176029, 十分推荐!
MMD 是迁移学习,尤其是预适应
(
d
o
m
a
i
n
a
d
a
p
t
a
t
i
o
n
)
(domain \ adaptation)
(domain adaptation)中应用广泛的一种损失函数。主要度量两个不同但相关的分布的距离。这两个分布的距离定义为:
M
M
D
(
X
,
Y
)
=
∣
∣
1
n
∑
i
=
1
n
ϕ
(
x
i
)
−
1
m
∑
j
=
1
m
ϕ
(
y
j
)
∣
∣
H
2
MMD(X,Y)=||\frac{1}{n}\sum_{i=1}^{n}\phi(x_i) - \frac{1}{m}\sum_{j=1}^{m}{\phi(y_j)}||_{H}^2
MMD(X,Y)=∣∣n1i=1∑nϕ(xi)−m1j=1∑mϕ(yj)∣∣H2这边的
H
H
H表示这个距离是由
ϕ
(
)
\phi()
ϕ() 将数据映射到再生希尔伯特空间
(
R
K
H
S
)
(RKHS)
(RKHS)中进行度量的。
为什么要使用MMD?
域适应的目的:将源域中学到的知识可以应用到不同但相关的目标域。本质和关键上要找到一个变换函数,使变换后的源域数据与目标域数据的距离是最小的。那么如何度量两个域中数据分布差异的问题,因此也用到了 MMD。
MMD的理论推导:寻找一个变换函数,但是这个变换函数在不同的任务中都不是固定的。并且这个映射可能是高维空间中的映射,所以很难去选取和定义。 如果这个映射函数
ϕ
(
)
\phi()
ϕ() 未知,那
M
M
D
MMD
MMD 如何求取呢?
将
M
M
D
MMD
MMD 展开:
M
M
D
(
X
,
Y
)
=
∣
∣
1
n
2
∑
i
,
i
′
n
ϕ
(
x
i
)
ϕ
(
x
i
′
)
−
2
n
m
∑
i
,
j
n
ϕ
(
x
i
)
ϕ
(
y
j
)
+
1
m
2
∑
j
,
j
′
n
ϕ
(
y
i
)
ϕ
(
y
i
′
)
∣
∣
H
2
MMD(X,Y)=||\frac{1}{n^2}\sum_{i,i^{'}}^{n}{\phi(x_i)\phi(x_{i^{'}})}-\frac{2}{nm}\sum_{i,j}^{n}\phi(x_i)\phi(y_j)+\frac{1}{m^2}\sum_{j,j_{'}}^{n}\phi({y_i})\phi({y_i}^{'})||^2_{H}
MMD(X,Y)=∣∣n21i,i′∑nϕ(xi)ϕ(xi′)−nm2i,j∑nϕ(xi)ϕ(yj)+m21j,j′∑nϕ(yi)ϕ(yi′)∣∣H2展开后就出现
ϕ
(
x
i
)
ϕ
(
x
i
′
)
\phi({x_i})\phi({x_i}^{'})
ϕ(xi)ϕ(xi′)的形式,这里面的
ϕ
(
)
\phi()
ϕ()就类似于
S
V
M
SVM
SVM 的核函数
k
(
∗
)
k(*)
k(∗),就可以直接跳过
ϕ
(
)
\phi()
ϕ() 的部分,直接求
k
(
x
i
)
k
(
x
i
′
)
k({x_i})k({x_i}^{'})
k(xi)k(xi′)。这里
M
M
D
MMD
MMD 又可以表示为:
M
M
D
(
X
,
Y
)
=
∣
∣
1
n
2
∑
i
,
i
′
n
k
(
x
i
)
k
(
x
i
′
)
−
2
n
m
∑
i
,
j
n
k
(
x
i
)
k
(
y
j
)
+
1
m
2
∑
j
,
j
′
n
k
(
y
i
)
k
(
y
i
′
)
∣
∣
H
2
MMD(X,Y)=||\frac{1}{n^2}\sum_{i,i^{'}}^{n}{k(x_i)k(x_i^{'})}-\frac{2}{nm}\sum_{i,j}^{n}k(x_i)k(y_j)+\frac{1}{m^2}\sum_{j,j_{'}}^{n}k({y_i})k({y_i}^{'})||^2_{H}
MMD(X,Y)=∣∣n21i,i′∑nk(xi)k(xi′)−nm2i,j∑nk(xi)k(yj)+m21j,j′∑nk(yi)k(yi′)∣∣H2
这里的核函数
k
(
∗
)
k(*)
k(∗) 一般用高斯核函数
k
(
u
,
v
)
=
e
−
∣
∣
u
−
v
∣
∣
2
σ
k(u,v)=e^{\frac{-||u-v||^2}{\sigma}}
k(u,v)=eσ−∣∣u−v∣∣2,因为使用高斯核函数可以映射到无穷维空间。
代码参考:https://blog.csdn.net/zkq_1986/article/details/86747841
我跑编码器实验的时候用的就是这个函数,亲证有效:
import torch
def guassian_kernel(source, target, kernel_mul=2.0, kernel_num=5, fix_sigma=None):
'''
将源域数据和目标域数据转化为核矩阵,即上文中的K
Params:
source: 源域数据(n * len(x))
target: 目标域数据(m * len(y))
kernel_mul:
kernel_num: 取不同高斯核的数量
fix_sigma: 不同高斯核的sigma值
Return:
sum(kernel_val): 多个核矩阵之和
'''
n_samples = int(source.size()[0])+int(target.size()[0])
# 求矩阵的行数,一般source和target的尺度是一样的,这样便于计算
total = torch.cat([source, target], dim=0)
#将source,target按列方向合并
#将total复制(n+m)份
total0 = total.unsqueeze(0).expand(int(total.size(0)), int(total.size(0)), int(total.size(1)))
#将total的每一行都复制成(n+m)行,即每个数据都扩展成(n+m)份
total1 = total.unsqueeze(1).expand(int(total.size(0)), int(total.size(0)), int(total.size(1)))
#求任意两个数据之间的和,得到的矩阵中坐标(i,j)代表total中第i行数据和第j行数据之间的l2 distance(i==j时为0)
L2_distance = ((total0-total1)**2).sum(2)
#调整高斯核函数的sigma值
if fix_sigma:
bandwidth = fix_sigma
else:
bandwidth = torch.sum(L2_distance.data) / (n_samples**2-n_samples)
#以fix_sigma为中值,以kernel_mul为倍数取kernel_num个bandwidth值(比如fix_sigma为1时,得到[0.25,0.5,1,2,4]
bandwidth /= kernel_mul ** (kernel_num // 2)
bandwidth_list = [bandwidth * (kernel_mul**i) for i in range(kernel_num)]
#高斯核函数的数学表达式
kernel_val = [torch.exp(-L2_distance / bandwidth_temp) for bandwidth_temp in bandwidth_list]
#得到最终的核矩阵
return sum(kernel_val)#/len(kernel_val)
def mmd_rbf(source, target, kernel_mul=2.0, kernel_num=5, fix_sigma=None):
'''
计算源域数据和目标域数据的MMD距离
Params:
source: 源域数据(n * len(x))
target: 目标域数据(m * len(y))
kernel_mul:
kernel_num: 取不同高斯核的数量
fix_sigma: 不同高斯核的sigma值
Return:
loss: MMD loss
'''
batch_size = int(source.size()[0])
#一般默认为源域和目标域的batchsize相同
kernels = guassian_kernel(source, target, kernel_mul=kernel_mul, kernel_num=kernel_num, fix_sigma=fix_sigma)
#根据式(3)将核矩阵分成4部分
XX = kernels[:batch_size, :batch_size]
YY = kernels[batch_size:, batch_size:]
XY = kernels[:batch_size, batch_size:]
YX = kernels[batch_size:, :batch_size]
loss = torch.mean(XX + YY - XY -YX)
return loss#因为一般都是n==m,所以L矩阵一般不加入计算
② 参考博客
这几位的博客十分好,隆重推荐!
- https://blog.csdn.net/dwenjun/article/details/81914683
- https://blog.csdn.net/m_buddy/article/details/80224409
- https://blog.csdn.net/zkq_1986/article/details/86747841
- https://blog.csdn.net/a529975125/article/details/81176029