XOR-with-relu

这几天在尝试手写双层神经网络解决XOR问题–也就是所谓的classic问题
看似简单的问题其实藏了很多坑
下面随便说说自己解决问题的思路和过程,还有一些实验图像

一开始我是打算用sigmoid + Cross Entropy来解决的
但是阴差阳错发现了ReLU是Sigmoid的上位互换(轻喷)
所以实现的时候用了ReLu, 一开始的设计如图所示
[图]

实现好之后,出现了各种稀奇古怪的问题
因为我是第一次手写实现所以对自己宽容一点
去问了同领域的大佬,然后帮我改了个Bug: 求导的时候乘错了vector(dw才对,结果乘了w)

本来这个问题解决了就该走上人生巅峰, 这时候tricky的事情开始了,大佬跑了1w遍,告诉我除了那个bug其他实现是对的,Loss收敛了
我看了一下他的结果确实没问题,
然后把大佬的代码拿过来(就改了个bug,其他基本没动) 跑了一千遍,发现没有收敛
怎么回事?
因为大佬说是对的,然后结果也出来了,我就默认代码是对的
那是不是只能怪ReLU函数了?
因为我学的课程比较古典,对线性函数还是相当有好感的,现在告诉我非线性的ReLU是Sigmoid的上位互换
内心总是有些不服,嗯,一定是ReLU的锅

但是改也要不少时间
想到肯定不止我一个人打算手写XOR
就跑到谷歌去搜了几个关键字”relu XOR not work”(对relu就是那么偏见)
然后浏览了不少答案
首先是leaky-relu,可以解决unit死掉的问题(后来我确认过,绝大多数bug都出自dead unit)
这个就先记下了
然后果然有一些人跟我有同样的问题,但是下面的回答基本都没什么帮助

我一边敲着run(),发现了一个问题, 那就是一个样本的Loss值减少了,另一个样本的Loss会增加
这不就是压住一边另一边翘起来嘛,一定是这个的锅
怎么解决呢? 因为样本就只有4个,那我直接用Cost函数代替Loss如何,一次性考虑4个Loss, 每次update都确实地走向成功, 岂不美哉
然后今天早上我就把这个想法付诸了实践
写好后想着这次总该成功了吧,就run了一千次,发现Cost在0.13左右的地方就更新不动了
结果大概像是这样子:
[图]

这不跟昨天一样嘛,什么都没有解决
这次真的手足无措了,我又到谷歌去找解决方案
这时候看到一个实现,仔细一看,中间层用了几个unit? 3个吗。。? 居然是30个!
准备直接关掉浏览器,但是转念一想, 如果增加神经元会不会有不同的结果?

今早的重写不是没有意义的,我将所有用到vector的地方做了泛化
所以想要增加中间层的unit,就几句命令的事情
所以我把神经元加到了5个,结果是一发通过

我开始思考一个可能性: 神经网咯并不是那么严谨的东西,在训练的过程中,网络是有可能走到死状态的
只有这个能够解释训练成功率的问题, 这一瞬间,神经网络被拉下了神的宝座

这时候还有一个悬念。
明明是用着最严谨的数学语言,各种导数都用上了, 在更新的过程中,理想状态应该是Loss平滑归零才对啊
但是在我手动run的过程中,Loss总有一种趋近某个莫名其妙数值的感觉
所以我输出了Loss vs RunTimes的图
发现在偶然成功归零的过程中,往往会经过一个非常平坦的平原,经过这个平原之后,才会出现第二次下滑
我再次理解到神经网络不是那么Robust的东西
[图]

最后一个猜测:如果用leaky-relu会不会有望离开死状态?
直接上结论: 不能
只要gradient趋近0,那weights的更新基本是不动的了,不管是relu还是leaky-relu都一样
下面是用了leaky-relu的图:
[图]

我实验了各种更新rate,各种隐藏层神经元数量(2-5)
rate在0.1的时候是比较合适的,0.5就基本没有成功过了
然后神经元数量越多越好,简直就是强欲的神经网络

以上就是实验总结