深度学习梯度反向传播出现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操作。

浙公网安备 33010602011771号