CNN--两个Loss层计算的数值问题
写在前面,这篇文章的原创性比较差,因为里面聊的已经是老生长谈的事情,但是为了保持对CNN问题的完整性,还是把它单独拿出来写一篇了。已经知道的童鞋可以忽略,没看过的童鞋可以来瞧瞧。
这次我们来聊一聊在计算Loss部分是可能出现的一些小问题以及现在的解决方法。其实也是仔细阅读下Caffe代码中有关Softmax loss和sigmoid cross entropy loss两个部分的真实计算方法。
Softmax
有关Softmax的起源以及深层含义这里不多说了,我们直接来看看从定义出发的计算方法:
def naive_softmax(x): y = np.exp(x) return y / np.sum(y)
随便生成一组数据,计算一下:
a = np.random.rand(10) print a print naive_softmax(a) [ 0.67362493 0.20352691 0.02024274 0.29988184 0.2319521 0.43930833 0.98219225 0.54569955 0.00298489 0.83399241] [ 0.12203807 0.07626659 0.06349434 0.08398094 0.07846559 0.09654569 0.16615155 0.10738362 0.06240797 0.14326563]
从结果来看比较正常,符合预期,但是如果我们的输入不那么正常呢?
b = np.random.rand(10) * 1000 print b print naive_softmax(b) [ 497.46732916 227.75385779 537.82669096 787.54950048 663.13861524 224.69389572 958.39441314 139.09633232 381.35034548 604.08586655] [ 0. 0. 0. nan 0. 0. nan 0. 0. 0.]
我们发现数值溢出了,因为指数函数是一个很容易让数值爆炸的函数,那么输入大概到多少会溢出呢?蛋疼的我还是做了一个实验:
np.exp(709) 8.2184074615549724e+307
这是在python能够正常输出的单一数字的极限了。实际上这接近double类型的数值极限了。
虽然我们前面讲过有一些方法可以控制住数字,使输出不会那么大,但是终究难免会有个别大数字使得计算溢出。而且实际场景中计算softmax的向量维度可能会比较大,大家累积起来的数字有时还是挺吓人的。
那么如何解决呢?我们只要给每个数字除以一个大数,保证它不溢出,问题不就解决了?老司机给出的方案是找出输入数据中最大的数,然后除以e的最大数次幂,相当于下面的代码:
def high_level_softmax(x): max_val = np.max(x) x -= max_val return naive_softmax(x)
这样一来,之前的问题就解决了,数值不再溢出了。
b = np.random.rand(10) * 1000 print b print high_level_softmax(b) [ 903.27437996 260.68316085 22.31677464 544.80611744 506.26848644 698.38019158 833.72024087 200.55675076 924.07740602 909.39841128] [ 9.23337324e-010 7.79004225e-289 0.00000000e+000 1.92562645e-165 3.53094986e-182 9.57072864e-099 5.73299537e-040 6.01134555e-315 9.99999577e-001 4.21690097e-007]
虽然不溢出了,但是这个结果看着还是有点怪。上面的例子中最大的数字924.07740602的结果高达0.99999,而其他一众数字经过softmax之后都小的可怜,小到我们用肉眼无法从坐标轴上把它们区分出来,这说明softmax的最终结果和scale有很大的关系。
为了让这些小的可怜的数字不那么可怜,使用一点平滑的小技巧还是很有必要的,于是代码又变成:
def practical_softmax(x): max_val = np.max(x) x -= max_val y = np.exp(x) y[y < 1e-20] = 1e-20 return y / np.sum(y)
结果变成了:
[ 9.23337325e-10 9.99999577e-21 9.99999577e-21 9.99999577e-21 9.99999577e-21 9.99999577e-21 9.99999577e-21 9.99999577e-21 9.99999577e-01 4.21690096e-07]
看上去比上面的还是要好一些,虽然不能扭转一家独大的局面。
Sigmoid Cross Entropy Loss
从上面的例子我们可以看出,exp这个函数实在是有毒。下面又轮到另外一个中毒专业户sigmoid出厂了。这里我们同样不解释算法原理,直接出代码:
时间:2018-08-05 01:18 来源: 转发量:次
声明:本站部分作品是由网友自主投稿和发布、编辑整理上传,对此类作品本站仅提供交流平台,转载的目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,不为其版权负责。如果您发现网站上有侵犯您的知识产权的作品,请与我们取得联系,我们会及时修改或删除。
相关文章:
相关推荐:
网友评论: