北京 切换校区

全国24小时免费热线

400-009-1906

CNN–两个Loss层计算的数值问题

时间:2018-12-10   来源:尚学堂   阅读:210
首页> CNN–两个Loss层计算的数值问题

        这次我们来聊一聊在计算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出厂了。这里我们同样不解释算法原理,直接出代码:

def naive_sigmoid_loss(x, t): y = 1 / (1 + np.exp(-x)) return -np.sum(t * np.log(y) + (1 - t) * np.log(1 - y)) / y.shape[0]

        我们给出一个温和的例子:

a = np.random.rand(10) b = a > 0.5 print a print b print naive_sigmoid_loss(a,b) [ 0.39962673 0.04308825 0.18672843 0.05445796 0.82770513 0.16295996 0.18544111 0.57409273 0.63078192 0.62763516] [False False False False True False False True True True] 0.63712381656

        下面自然是一个暴力的例子:

a = np.random.rand(10)* 1000 b = a > 500 print a print b print naive_sigmoid_loss(a,b) [ 63.20798359 958.94378279 250.75385942 895.49371345 965.62635077 81.1217712 423.36466749 532.20604694 333.45425951 185.72621262] [False True False True True False False True False False] nan

        果然不出所料,我们的程序又一次溢出了。

        那怎么办呢?这里节省点笔墨,直接照搬老司机的推导过程:(侵删,我就自己推一遍了……)

CNN--两个Loss层计算的数值问题

        于是,代码变成了:

def high_level_sigmoid_loss(x, t): first = (t - (x > 0)) * x second = np.log(1 + np.exp(x - 2 * x * (x > 0))) return -np.sum(first - second) / x.shape[0]

        举一个例子:

a = np.random.rand(10)* 1000 - 500 b = a > 0 print a print b print high_level_sigmoid_loss(a,b) [-173.48716596 462.06216262 -417.78666769 6.10480948 340.13986055 23.64615392 256.33358957 -332.46689674 416.88593348 -246.51402684] [False True False True True True True False True False] 0.000222961919658

        这样一来数值的问题也就解决了!

 

       就剩一句话了

       计算中遇到Exp要小心溢出!

相关资讯

  • 北京校区
  • 山西校区
  • 郑州校区
  • 武汉校区
  • 四川校区
  • 长沙校区
  • 深圳校区
  • 上海校区
  • 广州校区
  • 保定招生办

北京海淀区校区(总部):北京市海淀区西三旗街道建材城西路中腾建华商务大厦东侧二层尚学堂
北京京南校区:北京亦庄经济开发区科创十四街6号院1号楼 赛蒂国际工业园
咨询电话:400-009-1906 / 010-56233821
面授课程: JavaEE培训大数据就业班培训大数据云计算周末班培训零基础大数据连读班培训大数据云计算高手班培训人工智能周末班培训人工智能+Python全栈培训H5+PHP全栈工程师培训

山西学区地址:山西省晋中市榆次区大学城大学生活广场万科商业A1座702

郑州学区地址:河南电子商务产业园6号楼4层407
咨询电话:0371-55177956

武汉学区地址:湖北省武汉市江夏区江夏大道26号 宏信悦谷创业园4楼
咨询电话:027-87989193

四川学区地址:成都市高新区锦晖西一街99号布鲁明顿大厦2栋1003室
咨询电话:028-65176856 / 13880900114

网址:http://www.cssxt.com/
咨询电话:0731-83072091

深圳校区地址:深圳市宝安区航城街道航城大道航城创新创业园A4栋210(固戍地铁站C出口)
咨询电话:0755-23061965 / 18898413781

上海尚学堂松江校区地址:上海市松江区荣乐东路2369弄45号绿地伯顿大厦2层
咨询电话:021-67690939

广州校区地址:广州市天河区元岗横路31号慧通产业广场B区B1栋6楼尚学堂(地铁3号线或6号线到“天河客运站”D出口,右拐直走约800米)
咨询电话:020-2989 6995

保定招生办公室

地址:河北省保定市竞秀区朝阳南大街777号鸿悦国际1101室

电话:15132423123

Copyright 2006-2019 北京尚学堂科技有限公司  京ICP备13018289号-19  京公网安备11010802015183  
媒体联系:18610174079 闫老师  

Java基础班,免费试学三周