赞
踩
q 1 = exp ( z i / T ) ∑ j exp ( z j / T ) . q_1 = \frac{\exp(z_i/T)}{\sum_j \exp(z_j/T)}. q1=∑jexp(zj/T)exp(zi/T).
这篇文章或许重点是在迁移学习上, 一个重点就是其认为soft labels (即概率向量)比hard target (one-hot向量)含有更多的信息. 比如, 数字模型判别数字 2 2 2为 3 3 3和 7 7 7的概率分别是0.1, 0.01, 这说明这个数字 2 2 2很有可能和 3 3 3长的比较像, 这是one-hot无法带来的信息.
于是乎, 现在的情况是:
以及有一个训练好的且往往效果比较好但是计量大的模型 t t t;
我们打算用一个小的模型 s s s去近似这个已有的模型;
策略是每个样本 x x x, 先根据 t ( x ) t(x) t(x)获得soft logits z ∈ R K z \in \mathbb{R}^K z∈RK, 其中 K K K是类别数, 且 z z z未经softmax.
最后我们希望根据下面的损失函数来训练
s
s
s:
L
(
x
,
y
)
=
T
2
⋅
L
s
o
f
t
(
x
,
y
)
+
λ
⋅
L
h
a
r
d
(
x
,
y
)
\mathcal{L(x, y)} = T^2 \cdot \mathcal{L}_{soft}(x, y) + \lambda \cdot\mathcal{L}_{hard}(x, y)
L(x,y)=T2⋅Lsoft(x,y)+λ⋅Lhard(x,y)
其中
L
s
o
f
t
(
x
,
y
)
=
−
∑
i
=
1
K
p
i
(
x
)
log
q
i
(
x
)
=
−
∑
i
=
1
K
exp
(
v
i
(
x
)
/
T
)
∑
j
exp
(
v
j
(
x
)
/
T
)
log
exp
(
z
i
(
x
)
/
T
)
∑
j
exp
(
z
j
(
x
)
/
T
)
\mathcal{L}_{soft}(x, y) = -\sum_{i=1}^K p_i(x) \log q_i (x) = -\sum_{i=1}^K \frac{\exp(v_i(x)/T)}{\sum_j \exp(v_j(x)/T)} \log \frac{\exp(z_i(x)/T)}{\sum_j \exp(z_j(x)/T)}
Lsoft(x,y)=−i=1∑Kpi(x)logqi(x)=−i=1∑K∑jexp(vj(x)/T)exp(vi(x)/T)log∑jexp(zj(x)/T)exp(zi(x)/T)
L h a r d ( x , y ) = − log exp ( z y ( x ) ) ∑ j exp ( z j ( x ) ) \mathcal{L}_{hard}(x, y) = -\log \frac{\exp(z_y(x))}{\sum_j \exp(z_j(x))} Lhard(x,y)=−log∑jexp(zj(x))exp(zy(x))
至于 T 2 T^2 T2是怎么来的, 这是为了配平梯度的magnitude.
∂
L
s
o
f
t
∂
z
k
=
−
∑
i
=
1
K
p
i
q
i
∂
q
i
∂
z
k
=
−
1
T
p
k
−
∑
i
=
1
K
p
i
q
i
⋅
(
−
1
T
q
i
q
k
)
=
−
1
T
(
p
k
−
∑
i
=
1
K
p
i
q
k
)
=
1
T
(
q
k
−
p
k
)
=
1
T
(
e
z
i
/
T
∑
j
e
z
j
/
T
−
e
v
i
/
T
∑
j
e
v
j
/
T
)
.
当
T
T
T足够大的时候, 并假设
∑
j
z
j
=
0
=
∑
j
v
j
=
0
\sum_j z_j=0 = \sum_j v_j =0
∑jzj=0=∑jvj=0, 有
∂
L
s
o
f
t
∂
z
k
≈
1
K
T
2
(
z
k
−
v
k
)
.
\frac{\partial \mathcal{L}_{soft}}{\partial z_k} \approx \frac{1}{KT^2} (z_k - v_k).
∂zk∂Lsoft≈KT21(zk−vk).
故需要加个
T
2
T^2
T2取抵消这部分的影响.
其实一直很好奇的一点是这部分代码在pytorch里是怎么实现的, 毕竟pytorch里的交叉熵是
−
log
p
y
(
x
)
-\log p_y(x)
−logpy(x)
另外很恶心的一点是, 我看大家都用的是 KLDivLOSS, 但是其实现居然是:
L
(
x
,
y
)
=
y
⋅
log
y
−
y
⋅
x
,
\mathcal{L}(x, y) = y \cdot \log y - y \cdot x,
L(x,y)=y⋅logy−y⋅x,
注: 这里的
⋅
\cdot
⋅是逐项的.
def kl_div(x, y):
return y * (torch.log(y) - x)
x = torch.randn(2, 3)
y = torch.randn(2, 3).abs() + 1
loss1 = F.kl_div(x, y, reduction="none")
loss2 = kl_div(x, y)
这时, 出来的结果长这样
tensor([[-1.5965, 2.2040, -0.8753],
[ 3.9795, 0.0910, 1.0761]])
tensor([[-1.5965, 2.2040, -0.8753],
[ 3.9795, 0.0910, 1.0761]])
又或者:
def kl_div(x, y):
return (y * (torch.log(y) - x)).sum(dim=1).mean()
torch.manual_seed(10086)
x = torch.randn(2, 3)
y = torch.randn(2, 3).abs() + 1
loss1 = F.kl_div(x, y, reduction="batchmean")
loss2 = kl_div(x, y)
print(loss1)
print(loss2)
tensor(2.4394)
tensor(2.4394)
所以如果真要弄, 应该要
def soft_loss(z, v, T=10.):
# z: logits
# v: targets
z = F.log_softmax(z / T, dim=1)
v = F.softmax(v / T, dim=1)
return F.kl_div(z, v, reduction="batchmean")
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。