[笔记] Golang小试实现神经网络框架
国庆节宅在家里,看完了40集的电视剧,也刷了4K代码。最近看看Golang,然后想摆弄一下神经网络。虽然如今都是第三方库泛滥,开源代码拿来即用,而这次对自己的要求是没有第三方库,代码自成闭包。这样更有自主控制性,加深对神经网络实现的理解,也省去了学习各种三方包的用法,顺带着熟练下Golang这门新语言。 搜索引擎可以找到各种神经网络的入门文章。 在GitHub上找Golang的机器学习包,还不是很多。这年头,机器学习都被Matlab,R和python占去了风头吧。尤其,Python有着NumPy社区,Theano和TensorFlow等优秀框架。 不多说,直接开始写代码吧:GitHub/hotpot.seafood 首先,就想到最基础的矩阵乘法。那得有Matrix类和一些基础方法。这个就不必搜索了,根据以数学知识实现就好。期间开小差,编译了一下LAPACK和OpenBLAS库,发现Fortron的代码是编译成.o文件的,这样其他语言接extension很容易,只是document太少,不知道api要学到什么时候。 本来学习前辈文章中的Python代码,照猫画虎写好了循环神经网络的add,发现没什么规律。直到看到 nnet 才发现原来TensorFlow,theano等框架都是往程序Graph的结构去的,就连2015年PyCon大会上的Lazy Expression估计也是为机器学习框架设计的。nnet的代码十分易读,建立一个神经网络,里面包含的层也看得很清楚。 nn = nnet.NeuralNetwork(
layers=[
nnet.Conv(
n_feats=12,filter_shape=(5,5),strides=(1,1),weight_scale=0.1,weight_decay=0.001,),nnet.Activation('relu'),nnet.Pool(
pool_shape=(2,2),strides=(2,mode='max',nnet.Conv(
n_feats=16,nnet.Flatten(),nnet.Linear(
n_out=n_classes,weight_decay=0.02,nnet.LogRegression(),],)
于是照着nnet的结构,写起了神经网络计算框架。对于网络的每一层,都会有计算Forward和Backward,然后Update参数。一个神经网络先把所有的Forward计算完,得到的结果就完成了Predict任务。按自己聚类或外部提供的正确结果,再倒着把误差传递一遍运行所有层的Backward过程,能完成Learn任务。最后的Update任务当然就是Update所有层的参数了。 Forward过程其实很容易理解,比如一个线性函数啦y=kx+b,不过这里是用矩阵表示就是了: Backward是计算误差,每层可以从下一层pop上来这一层结果的误差在
最后的Update就比较傻瓜,学习速率和参数更新量相乘后再累加到参数里就搞定了。不过这里的坑也有很多,因为牵涉到神经网络这门学科我觉得最坑爹的点,就是收敛。如果参数更新控制得不好,那么你可能发现新世界新学科:混沌与分形十分典型(
实现xor很顺利,因为是最基础的神经网络调用,LayerLinear和sigmoid层只要不出问题就okay。线性层不带初中学的记得叫截距b的话,只要记住Forward是
在实现add的时候,循环神经网络确实比较复杂,要记录之前的状态。就拿线性层来说,本来
type I interface {
Public () int
Abstract () int
}
type A struct {
I
x int
}
func (a *A) Public () int {
return a.Abstract()
}
func (a *A) Abstract () int {
a.x = 1
return a.x
}
type B struct {
A
}
func (b *B) Abstract () int {
b.x = 2
return b.x
}
虽然是自己傻逼,程序明明在A的Public里写的是 最后是循环神经网络,是耗时最多在调试上的。MNIST识别0-9的手写体数字,因为最初写得程序设置层或参数导致不收敛,或者收敛成输出固定值正确率10%,一度都想还是直接用Python吧。最终偶然把relu函数换成tanh函数,decay参数调小,程序学习的时候就开始比较好得收敛起来。用Python读MNIST数据源,输出了一个减量版的json数据集。这么Golang就好读了, (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |