结论
最后是通过修改初始化函数和添加L2正则化基本解决了,不过偶尔还是会报错
问题现象
loss函数采用交叉熵
使用relu效果更好,但是会出现loss和梯度都变成nan的现象;使用其他激活函数不会出现nan,但是性能不如relu
出现nan的时机:如果inputs比较少,那么在100多个epoch,训练基本已经收敛之后才会nan;但是如果数据比较多(在信号检测里 天线数比较大的时候)基本第一个epoch的前几个batch就会nan
可能原因
上网查了相关问题,可能原因和解决方法包括:
脏数据
交叉熵nan
使用了交叉熵做损失函数,所以有可能出现log0的问题 --> 自己写交叉熵,手动加入一个极小量
但是这里有一个新的问题,即把原始数据fetch出来看没有log0,但是在graph里算却log0了,不知道为什么会产生精度差异?解决办法是使用裁剪tf.clip_by_value,把下界调大一点
inputs nan
检查过了,也没有这个问题
梯度爆炸
解决了loss的nan可能后,发现梯度gradients还是会先于loss出现nan。把梯度fetch出来,发现实际上梯度都很小,基本在1e-4以下,所以也排除梯度特别大的情况,那只能认为是梯度太小最后nan
学习率太大
调小了/采用学习率衰减,没有用
过拟合
试了dropout,L2正则化,没用
初始化
说relu适合he初始化,但我觉得应该不是这个原因。因为我不是一开始nan的,而是几乎收敛了之后才nan,所以感觉不是初始化的问题,但是加上这段代码就解决了nan的问题