可直接阅读原文:http://c.raqsoft.com.cn/article/1540374496048?r=alice
识别手写的阿拉伯数字,对于人类来说十分简单,但是对于程序来说还是有些复杂的。
不过随着机器学习技术的普及,使用10几行代码,实现一个能够识别手写数字的程序,并不是一件难事。这是因为有太多的机器学习模型可以拿来直接用,比如tensorflow、caffe,在python下都有现成的安装包,写一个识别数字的程序,10几行代码足够了。
然而我想做的,是不借助任何第三方的库,从零开始,完全自己实现一个这样的程序。之所以这么做,是因为自己动手实现,才能深入了解机器学习的原理。
1 模型实现
1.1 原理
熟悉神经网络回归算法的,可以略过这一节了。
学习了一些基本概念,决定使用回归算法。首先下载了著名的MNIST数据集,这个数据集有60000个训练样本,和10000个测试样本。每个数字图片都是28*28的灰度图片,所以输入可以认为是一个28*28的矩阵,也可以认为是一个28*28=784个像素值。
这里定义一个模型用于判断一个图片数字,每个模型包括每个输入的权重,加一个截距,最后再做个归一。模型的表达式:
Out5= sigmoid(X0*W0+ X1*W1+……X783*W783+bias)
X0到X783是784个输入,W0到W783是784个权重,bias是一个常量。sigmoid函数可以将较大范围的数挤压到(0,1)区间内,也就是归一。
例如我们用这一组权重和bias来判断数字5,期望当图片是5时输出是1,当不是5时输出是0。然后训练的过程就是根据每个样本的输入,计算Out5的值和正确值(0或1)的差距,然后根据这个差距,调整权重和bias。转换一下公式,就是在努力使得(Out5-正确值)接近于0,即所谓损失最小。
同理,10个数字就要有10套模型,每个判断不同的数字。训练好以后,一个图片来了,用这10套模型进行计算,哪个模型计算的结果更接近于1,就认为这个图片是哪个数字。
1.2 训练
按照上面的思路,使用集算器的SPL(结构化处理语言)来编码实现:
A |
B |
C |
|
1 |
=file("train-imgs.btx").cursor@bi() |
||
2 |
>x=[],wei=[],bia=[],v=0.0625,cnt=0 |
||
3 |
for 10 |
>wei.insert(0,[to(28*28).(0)]), bia.insert(0,0.01) |
|
4 |
for 50000 |
>label=A1.fetch(1)(1) |
|
5 |
>y=to(10).(0), y(label+1)=1,x=[] |
||
6 |
>x.insert(0,A1.fetch(28*28)) |
>x=x.(~/255) |
|
7 |
=wei.(~**x).(~.sum()) ++ bia |
||
8 |
=B7.(1/(1+exp(-~))) |
||
9 |
=(B8--y)**(B8.(1-~))**B8 |
||
10 |
for 10 |
>wei(B10)=wei(B10)--x.(~*v*B9(B10)), bia(B10)=bia(B10) - v*B9(B10) |
|
11 |
>file("MNIST模型.btx").export@b(wei),file("MNIST模型.btx").export@ba(bia) |
不用再找了,训练模型的所有代码都在这里了,没有用到任何第三方库,下面解析一下:
A1,用游标导入MNIST训练样本,这个是我转换过的格式,可以被集算器直接访问;
A2,定义变量:输入x,权重wei,训练速度v,等;
A3,B3,初始化10组模型(每组是784个权重+1个bias);
A4,循环取5万个样本进行训练,10模型同时训练;
B4,取出来label,即这个图片是几;
B5,计算正确的10个输出,保存到变量y;
B6,取出来这个图片的28*28个像素点作为输入,C6把每个输入除以255,这是为了归一化;
B7,计算X0*W0+ X1*W1+……X783*W783+bias
B8,计算sigmoid(B7)
B9,计算B8的偏导,或者叫梯度;
B10,C10,根据B9的值,循环调整10个模型的参数;
A11,训练完毕,把模型保存到文件。
测试效果和优化,以及编码可看原文:http://c.raqsoft.com.cn/article/1540374496048?r=alice
作者:liwei
来源:乾学院
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。