深度学习梯度反向传播出现Nan值的原因归类

症状:前向计算一切正常、梯度反向传播的时候就出现异常,梯度从某一层开始出现Nan值(Nan: Not a number缩写,在numpy中,np.nan != np.nan,是唯一个不等于自身的数)。

根因:原因目前遇到的分为五种:

其一:

你使用了power(x, a) (a < 1)这样的算子,因为power函数这样的算子,在梯度反向传播阶段时,求导会产生1/(x^(a-1))这样的形式,

而如果前向时某层的某个值为0或者趋近于0的数,那么求导后,梯度为无穷大,超出表示范围,成为INF类型,这一类型会弥散到整个网络直至下一轮迭代出现loss为Nan被发现。

所以,任何能导致梯度爆炸出现Nan的算子都应该重点关注,求导后才产生的‘’除零错误”极易被忽略,因此这一点尤其需要注意。包括ln(x),1/x,pow(x, a<1)等等。

其二:

采用了归一化操作,隐含了除零错误的隐患:如x = x / mean(x),能将x的分布更加接近在(0,1)之间的均匀分布,但如果一开始网络初始化不好,导致某层输出全为0,这样mean(x)==0!

就会出现除零错误。这一点有时也是很难发现的。

其三:

输入数据本身有问题,比如有些图片格式损坏,数据文件格式错误,文件部分缺失,数据预处理中存在除零错误导致出现INF值等等。

其四:

在采用多线程读取数据集进行训练的时候因为没有使用exception机制导致线程callback返回的batch为空指针,从而训练输入或GT成为全是NAN的数据。这一点在使用keras的fit_generator函数

并设置worker数量大于1的时候容易出现,解决办法就是设置exception处理机制,通过阻塞式的重复数据读取来避免batch生成接口返回无效的内存地址(空指针)。

其五:

采用的优化器如Adam,NAdam等内部参数设置有问题,而loss本身很大,就容易出现返回梯度为INF(无穷大),进而参数全都变成NAN。这样就需要改变学习率和动量惯性系数等参数,

并且对loss进行必要的clip max操作。

posted @ 2019-03-08 10:01  xchk138  阅读(4774)  评论(1)    收藏  举报