交叉熵损失函数本身的公式比较简单,
但是在实际定义的时候需要注意exp(x)函数的溢出问题,
exp(x)函数在numpy或者说tensorflow的底层实现上,当x过大的时候会产生溢出,过小的时候直接范围近似值0
所以我们在定义交叉熵损失函数的时候需要注意这一点;
1.当模型返回的值是sigmoid函数映射过后的值,这里假设输入交叉熵的为x,那么我们计算的就是
-(y*np.log(x)+(1-y)*np.log(1-x))
但是log(0)是没有意义的,如果当输入的x为0,就会出现输出的loss为nan,
这里需要把这个异常点给处理点,这篇文章列举了几个方法:https://blog.csdn.net/wo334499/article/details/52067353
2. 直接把sigmoid的计算也包含在交叉熵损失函数中的时候,这里假设模型的输入还是为x,只不过这个x没有经过sigmoid映射,那么交叉熵损失函数为;
-(y*np.log(sigmoid(x))+(1-y)*np.log(1-sigmoid(x)))
我们还是会遇到1中写的问题,但是这里我们可以先对这个公式进行优化
-(y*log(sigmoid(x))+(1-y)*log(1-sigmoid(x))))
=y*-log(1/1+exp(-x))+(1-y)*-log(exp(-x)/(1+exp(-x)))
=y*log(1+exp(-x))+(1-y)*(-log(exp(-x))+log(1+exp(-x)))
=y*log(1+exp(-x))+(1-y)*x+(1-y)log(1+exp(-x)))
=log(1+exp(-x))+(1-y)*x
这样就简单很多了,但是我们最上面说了,exp(x)函数在x很大的时候会溢出,所以上面的公式中,因为输入exp()的-x,所以x很小的时候会溢出。因此针对x<0的时候单独再优化一下,按如下
log(1+exp(-x))+(1-y)*x
=log(1+exp(-x))+log(exp(x))-y*x
=log(exp(x)+1)-y*x
这样的话就可以跳过因为输入exp()函数的值过大而溢出的问题,因此输入exp()的值很小的时候是会趋向于0的,输出的值直接约等于0。
所以把上面两个合并起来就可以得到最终的公式:
max(x,0)-x*y+log(1+exp(-abs(x)))
这个方法是在看tensorflow源码的时候看到的,感觉还可以。