0. 前言
- 文章来源:CSDN@LawsonAbs
log_softmax
是计算损失的时候常用的一个函数,那么这个函数的内部到底是怎么做到的呢?这里详细的解释一下。
1. 代码
写代码前,回忆一下log_softmax
的公式
−
l
o
g
e
x
p
(
p
j
)
∑
i
e
x
p
(
p
i
)
-log\frac{exp(p_j)}{\sum_{i}exp(p_i)}
−log∑iexp(pi)exp(pj),其实就是 log + softmax
。 下面就来实现一下这个函数。
'''自己实现log_softmax 函数
(1)使用torch.exp()函数计算各个logit的e次幂
(2)使用torch.sum()函数计算求和
(3)使用torch.log对比例求对数
可以发现,二者最终的结果是相同的
'''
import torch as t
import torch.nn.functional as F
logit = t.tensor([0.1,0.1,0.1,0.7])
a = t.exp(logit)
print("a=",a)
b = t.sum(a,dim=0,keepdim=True)
print("b=",b)
c=t.log(a/b)
print(c)
print(F.log_softmax(logit))
执行结果:
2. 思考
尽管二者输出一致,但是二者实现过程是相同的吗?可以肯定的回答:不相同!
这里实现的log + softmax
还是有很多bug的,比如存在上溢出的风险,从而得到nan
的结果。
∑
e
x
p
(
x
i
)
\sum exp(x_i)
∑exp(xi) 是很容易上溢出的,那么有什么办法解决这个问题呢?如下所述就是一种简单的方法,这里就不展开叙述了。
l
o
g
_
s
o
f
t
m
a
x
=
l
o
g
e
x
p
(
x
j
)
∑
i
e
x
p
(
x
i
)
=
l
o
g
e
x
p
(
x
j
)
/
e
x
p
(
c
)
∑
i
e
x
p
(
x
i
)
/
e
x
p
(
c
)
=
l
o
g
e
x
p
(
x
j
−
c
)
∑
i
e
x
p
(
x
i
−
c
)
\begin{aligned} log\_softmax &= log \frac{exp(x_j)}{\sum _i exp_(x_i)} \\ &= log \frac{exp(x_j)/exp(c)}{\sum _i exp_(x_i)/exp(c)} \\ &= log \frac{exp(x_j-c)}{\sum _i exp_(x_i-c)} \\ \end{aligned}
log_softmax=log∑iexp(xi)exp(xj)=log∑iexp(xi)/exp(c)exp(xj)/exp(c)=log∑iexp(xi−c)exp(xj−c)
其中
c
=
m
a
x
(
x
i
)
c = max(x_i)
c=max(xi)
我想说的只有一点:以后想用log_softmax
的话,可以直接使用pytorch中的log_softmax()
函数即可,如果想自己分开搞大概率会出错。
要对论文中的公式非常敏感。很多损失其实就是 log_softmax
的变形而已。