2018年11月24日 / 19,950次阅读
人工神经网络
在使用numpy进行神经网络算法计算的时候,有的时候会遇到Runtime Warning,比如下面的这样的显示:
>> test.test5()
MNIST data is loaded.
/home/xinlin/repo/MNIST_lab/src/costfunc.py:29: RuntimeWarning: divide by zero encountered in log
(1-y)*np.log(1-a)))
/home/xinlin/repo/MNIST_lab/src/costfunc.py:29: RuntimeWarning: invalid value encountered in multiply
(1-y)*np.log(1-a)))
/home/xinlin/repo/MNIST_lab/src/f3cl_nn.py:54: RuntimeWarning: overflow encountered in double_scalars
for x in data)/len(data)
/home/xinlin/.local/share/virtualenvs/MNIST_lab-KQoRsFip/lib/python3.7/site-packages/numpy/core/fromnumeric.py:83: RuntimeWarning: overflow encountered in reduce
return ufunc.reduce(obj, axis, dtype, out, **passkwargs)
Epoch 1: 989/10000, Cost: inf
/home/xinlin/repo/MNIST_lab/src/neuron.py:20: RuntimeWarning: overflow encountered in exp
return 1.0/(1.0+np.exp(-z))
/home/xinlin/repo/MNIST_lab/src/costfunc.py:28: RuntimeWarning: divide by zero encountered in log
return np.sum(np.nan_to_num(-y*np.log(a)-
/home/xinlin/repo/MNIST_lab/src/costfunc.py:28: RuntimeWarning: invalid value encountered in multiply
return np.sum(np.nan_to_num(-y*np.log(a)-
问题的原因是,数字太大了,溢出,计算过程出现inf,inf再做其它运算,大部分还是inf。
np.exp(800),区区800就会出现overflow,这时再计算sigmoid函数,就是0,然后再算np.log(0)(crossentropy),就会出现divied by zero ...
np.nan_to_num可以起一点作用,将inf转换成最大的浮点数,可以让计算继续下去,但是这么大的数,在后续计算的时候,还是会容易出现overflow encountered in double_scalars,这个doubel_scalars应该只是双精度的浮点数。还有的时候是显示overflow encountered in multiply。
一些解决方法和思考:
1, 我最先考虑的是,是否可以限制神经元函数的输出,比如sigmoid函数,将其限制在一个精度足够高的范围内;但是,存在的问题是,在output layer,如果多个神经元函数的输出都超限,经过处理之后,这多个神经元的输出就变成一样的了,就无法比较判断了。所以放弃了这个方法。
2, 经过测试发现,出现大量的这些runtime warning,主要是因为np.log这个函数;
这个函数被用来计算total cost,如果在训练过程中,不去计算cost,基本上所有这些warnning就没有了。
3, 如第2点,如果采用quadratic cost function,就没有这些warning出现。
4, sigmoid函数的np.exp overflow是不是可以忽略?因为不会出现inf和nan的情况。
np.log的warning显然不能忽视,后面的计算已经不能正常进行下去了。
5, 出现warning的网络配置:
(1)784:10,对,没有hidden layer,feedforward fully connected layered nn;
(2)cross-entropy cost function;
(3)learning rate = 2;
(4)网络中的w和b采用np.random.randn方式配置;
(5)sigmoid neuron;
(6)最极端的SGD,每一轮梯度下降,只随机取一个数据;(BGD,SGD,MBGD)
(7)MNIST dataset;
-------
(a)以上配置,如果仅仅将网络修改为784:100:30:10,增加两个hidden layer,就没有warning了;
也就是说,这些warning可能不太重要,因为在production环境下,几乎不可能没有hidden layer。
(b)以上配置,如果仅仅将w和b全部初始化为0,warnning依然存在。
(c)以上配置,如果仅仅将SGD修改为BGD,warning消失;
其实,极端的SGD可能只有实验价值,并没有实用价值。
(d)以上配置,如果采用MBGD,mini batch size取不同的值,结果略有不同:
mini batch size = 100,没有warning;
mini batch size = 50,没有warning;
mini batch size = 30,没有warning;
mini batch size = 10,有warning,但明显感觉数量减少了一些。
似乎可以得出一个经验总结:在计算梯度的时候,越是平均,越不会出现这些烦人的warning。
6, 采用cross-entropy是为了解决learning slowdown的问题,在这个配置下,learning rate的设置一般要比quadratic cost要小一些。
我测试过,按照第5点的配置,只是将learning rate改为0.02,这些warning就消失了。
继续分析:
重新写了一段测试代码,直接观察在SGD的情况下,即只随机用一个数据来做梯度下降,然后停止计算cost,而是找一个数(我用的MNIST dataset的第一个数),计算output layer的a和z,然后将a和z打印出来,由于w和b是随机方式,我测试了几次,就发现了如下数据:
>> test.test6()
MNIST data is loaded.
[[-118.58708751]
[ 2.98852622]
[ -16.61383826]
[ 140.26884215]
[-116.31244446]
[-127.53373432]
[ -5.48993549]
[ -1.57377646]
[ -6.68414129]
[ -1.80108273]]
-----
[[3.14979486e-52]
[9.52053080e-01]
[6.09118363e-08]
[1.00000000e+00]
[3.06300138e-51]
[4.10018007e-56]
[4.11113925e-03]
[1.71678694e-01]
[1.24902616e-03]
[1.41719316e-01]]
>>> import numpy as np
>>> import neuron
>>> neuron.sigmoid(140.2689)
1.0
>>> np.exp(-140.2689)
1.2077881029207517e-61
>>> 1/(1+1.207788e-61)
1.0
>>>
发现一个a是1,这样如果计算cost,就是warning,算不出来;
这个a对应的z是140.2688这个数,我在下面有自己计算了一下,确实算sigmoid得到的是1.0.
以上测试,learning rate是2,这也解释了为什么将learning rate设置为0.02时,就没有warning,因为2太大了,加大了z值的变化幅度。区区140就让sigmoid饱和了,这个饱和的sigmoid神经元,可是有784个输入呀。。。
这个时候,softmax的优势就提现出来了,output layer不再使用sigmoid函数,就规避了这个问题。
output layer如果是sigmoid,就是取值最大的那个位置所代表的结果;
output layer如果是softmax,我们得到的是一个概率分布,哪个位置概率高,就是哪个结果。
用一个数来计算梯度,容易在那个数据的梯度上出现比较大值,如果learning rate也比较大,就容易导致z值过大,然后再计算np.log,就进入warning区域。
上面写的有点乱,总结一下:
只用一个数据来做梯度下降计算没有错,只是如果learning rate也比较大的话,容易导致warning的出现,导致无法在计算下去,64位的计算机,也是由计算上的限制的。增加hidden layer有效果,是因为cost的计算,只与output layer的输出有关,我上面的测试,距离output layer的那个hidden layer的神经元数量只有30。用mini batch来计算的思路是很不错的,比BGD快很多,而且也不容易出现各种warning。w和b的初始化,随机还是全零,在这个问题上没什么关系。使用quadratic cost function就是会导致learning slowdown,如果无惧slowdown,可以尽情地使用这个cost函数。softmax应该是更好的选择,下一个commit实现softmax。
同时,我也在质疑,为什么一定要计算cost的值?计算cost的值可能更多的只是实验方面的意义;cost的计算也不需要连续,网络连续计算,在output layer的所有输出都在某个限制内的时候,再计算一个cost的点值,这样行不行?其实,cost计算过程出现的各种warning,并没有影响网络中的梯度计算,从这个角度看,可以忽略计算过程中的warning(注意上文第4点)。
2018-12-03:
本文链接:https://www.maixj.net/ict/numpy-warning-19356
《训练神经网络,numpy出现runtime warning的解决思路》有4条留言
©Copyright 麦新杰 Since 2014 云上小悟独立博客版权所有 备案号:苏ICP备14045477号-1。云上小悟网站部分内容来源于网络,转载目的是为了整合信息,收藏学习,服务大家,有些转载内容也难以判断是否有侵权问题,如果侵犯了您的权益,请及时联系站长,我会立即删除。
貌似使用numba的JIT技术之后,warning被抑制了,但是cost计算还是会出现nan和inf。 [ ]
当y为0时,a也为0,这时是一个正确的对应,说明在这一个点上,网络学习很成功。但是这时做计算,就会有warning,可以考虑换一种计算方式,y为0的时候,就不要算y*np.log(a),y为1时,就不要算(1-y)*np.log(1-a)。 [ ]
通过初始化更小的weight,warning的问题可以得到缓解,甚至消失不见。 [ ]