损失函数的作用是衡量实际输出与预计输出之间的差异,损失函数的设计是深度学习中十分重要的部分,不仅会影响到训练的速度,还会影响隐含层中数据的分布情况。目前仅仅是总结了部分常用损失函数的计算方法,其中涉及很多统计学最优化知识,对此仅仅是浅尝辄止,其中更多的原理还需要以后慢慢总结体会,以下仅简要记录其计算方法。
目前记录的损失函数有限,后续会继续更新
1 MSE
均方误差算是最简单也是最经典的一种计算损失的方法,其中
y
^
\hat y
y^ 为实际输出,
y
y
y 为标签。
m
s
e
_
l
o
s
s
=
1
N
∑
i
=
1
N
(
y
i
−
y
^
i
)
2
mse\_loss =\frac{1}{N} \sum _{i=1} ^N (y_i - \hat y_i)^2
mse_loss=N1i=1∑N(yi−y^i)2
2 CrossEntropy
交叉熵是从KL散度中引出,用于衡量两个分布之间差异的大小,其值总是大于等于0,两个分布越相似其值越接近于0。训练时的标签可以当成一种分布,实际输出堪称另一种分布,常与softmax层结合用于分类模型。
C
r
o
s
s
E
n
t
r
o
p
y
_
l
o
s
s
=
−
∑
i
y
i
⋅
l
o
g
y
^
i
CrossEntropy\_loss = -\sum _i y_i·log\hat y_i
CrossEntropy_loss=−i∑yi⋅logy^i
上面说到KL散度(KL divergence)用于衡量两个分布之间的大小的差异,这和MSE的度量方法是不一样的。下面讲到的log损失函数也是 divergence 的一种。
3 log损失函数
log损失通常用于逻辑回归,是二分类中常用的损失函数,若二分类中使用mse损失会造成最后优化函数为非凹函数,不利于训练。其中
x
x
x 表示输出该特征,
y
y
y 表示所属类别,
p
(
1
/
x
)
p(1/x)
p(1/x) 表示输入特征
x
x
x 属于类别
1
1
1 的概率。
l
o
g
_
l
o
s
s
=
{
−
l
o
g
[
p
(
1
/
x
)
]
,
y
=
1
−
l
o
g
[
1
−
p
(
1
/
x
)
]
,
y
=
0
log\_loss = \begin{cases} -log[p(1/x)], &&&y=1 \\ -log[1-p(1/x)],&&&y=0 \end{cases}
log_loss={−log[p(1/x)],−log[1−p(1/x)],y=1y=0
将上面分类书写的形式变换一下,便得到了BCE_loss,只不过是换了一个名字而已,效果与上式相同
B
C
E
_
l
o
s
s
=
−
y
⋅
l
o
g
(
p
(
y
/
x
)
)
−
(
1
−
y
)
⋅
l
o
g
(
1
−
p
(
y
/
x
)
)
BCE\_loss = -y·log(p(y/x)) - (1-y)·log(1 - p(y/x))
BCE_loss=−y⋅log(p(y/x))−(1−y)⋅log(1−p(y/x))
逻辑回归是分类网络中基础又重要的一个网络,GAN网络中的discriminator便是使用这种二分类网络。比较GAN网络的损失函数便会发现相似之处
m
i
n
G
m
a
x
D
V
(
G
,
D
)
=
E
x
∼
p
d
a
t
a
(
x
)
[
l
o
g
D
(
x
)
]
+
E
z
∼
p
z
(
z
)
[
l
o
g
(
1
−
D
(
G
(
x
)
)
)
]
\mathop{min} \limits_G\mathop{max} \limits_ D V(G,D) = E_{x∼pdata(x)}[logD(x)]+E_{z∼pz(z)}[log(1−D(G(x)))]
GminDmaxV(G,D)=Ex∼pdata(x)[logD(x)]+Ez∼pz(z)[log(1−D(G(x)))]
4 L1 Loss
l1loss即是L1范数下度量的距离,就是计算网络输出与标签之间对应元素绝对值然后求和。使用pytorch中的定义如下
ℓ
(
x
,
y
)
=
L
=
{
l
1
,
…
,
l
N
}
′
,
l
n
=
∣
x
n
−
y
n
∣
\ell(x, y)=L=\left\{l_{1}, \ldots, l_{N}\right\}^{\prime}, \quad l_{n}=\left|x_{n}-y_{n}\right|
ℓ(x,y)=L={l1,…,lN}′,ln=∣xn−yn∣其中N表示batch的大小。
ℓ
(
x
,
y
)
=
{
mean
(
L
)
,
if size-average
=
True;
sum
(
L
)
,
if size-average
=
False.
\ell(x, y)=\left\{\begin{array}{ll}{\operatorname{mean}(L),} & {\text { if size-average }=\text { True; }} \\ {\operatorname{sum}(L),} & {\text { if size-average }=\text { False. }}\end{array}\right.
ℓ(x,y)={mean(L),sum(L), if size-average = True; if size-average = False.
5 L2 Loss
6 Smooth L1
smooth L1是何凯明提出的优化的MSE损失,能有有效地优化梯度爆炸问题。这个例子表明我们可以根据我们网络的具体表现适当调节我们的损失函数从而解决特定的训练问题。
z
i
=
{
0.5
(
x
i
−
y
i
)
2
,
if
∣
x
i
−
y
i
∣
<
1
∣
x
i
−
y
i
∣
−
0.5
,
otherwise
z_{i}=\left\{\begin{array}{ll}{0.5\left(x_{i}-y_{i}\right)^{2},} & {\text { if }\left|x_{i}-y_{i}\right|<1} \\ {\left|x_{i}-y_{i}\right|-0.5,} & {\text { otherwise }}\end{array}\right.
zi={0.5(xi−yi)2,∣xi−yi∣−0.5, if ∣xi−yi∣<1 otherwise
7 F-divergence
F-divergence是一个大的类,其中
F
F
F 表示特定的函数,当函数
F
F
F 不同便表示的不同的散度,上面提到的交叉熵便是 KL散度即 KL-divergence。其中KL使用的
F
F
F 为
t
⋅
l
o
g
t
t·logt
t⋅logt 。F-divergence损失函数如下:
D
f
(
P
d
a
t
a
∣
∣
P
g
)
=
∫
x
P
g
(
x
)
f
(
P
d
a
t
a
(
x
)
P
g
(
x
)
)
 
d
x
D_f (P_{data}||P_g) = \int_x P_g(x)f(\frac{P_{data}(x)}{P_g(x)})\, dx
Df(Pdata∣∣Pg)=∫xPg(x)f(Pg(x)Pdata(x))dx
8 TV Loss
The total variation (TV) loss encourages spatial smoothness in the generated image.(总变差(TV)损失促进了生成的图像中的空间平滑性。)详细定义见维基百科–Total variation
TV Loss Rubin等人在1990年左右观察到受噪声污染的图像的TV比无噪图像的总变分明显的大。 那么最小化TV理论上就可以最小化噪声。图片中相邻像素值的差异可以通过降低TV loss来一定程度上解决。比如降噪,对抗checkerboard等等。
实现代码如下:
#TV loss(total variation regularizer)
class TVLoss(nn.Module):
def __init__(self,TVLoss_weight=1):
super(TVLoss,self).__init__()
self.TVLoss_weight = TVLoss_weight
def forward(self,x):
batch_size = x.size()[0]
h_x = x.size()[2]
w_x = x.size()[3]
count_h = self._tensor_size(x[:,:,1:,:])
count_w = self._tensor_size(x[:,:,:,1:])
h_tv = torch.pow((x[:,:,1:,:]-x[:,:,:h_x-1,:]),2).sum()
w_tv = torch.pow((x[:,:,:,1:]-x[:,:,:,:w_x-1]),2).sum()
return self.TVLoss_weight*2*(h_tv/count_h+w_tv/count_w)/batch_size
def _tensor_size(self,t):
return t.size()[1]*t.size()[2]*t.size()[3]
目前还有很多损失函数没有总结,比如用于人脸识别的TripletMarginLoss 比起一般的损失函数能够很好地将不同的人脸特征分开。总之损失函数对深度学习的影响非常重要,很多时候使用一种损失导致训练崩坏而换一种损失便能得到不错的效果。