原文地址:Simplestartificialneuralnetwork
译者&校正:HelloGitHub-小熊熊&卤蛋
在GitHub上一个极简、入门级的神经网络教程,示例代码为Go语言,简洁易懂能用一行公式说明白的道理。
内容分为两部分:
人工神经网络是人工智能的基础,只有夯实基础,才能玩转AI魔法!
温馨提示:公式虽多但只是看起来唬人,实际耐下心读并不难懂。下面正文开始!
通过理论和代码解释和演示的最简单的人工神经网络。
拿最简单的来说,输出值就是输入值乘以权重之后的总和。
现在我们需要调整权重值,从而使得它们可以产生我们预设的输出值。
在初始化时,因为我们不知晓最优值,往往是对权重随机赋值,这里我们为了简单,将它们都初始化为1。
这种情况下,我们得到的就是
通常我们会采用方差(也就是代价函数)来衡量误差:
如果有多套输入输出值,那么误差就是每组方差的平均值。
我们用方差来衡量得到的输出值与我们期望的目标值之间的差距。通过平方的形式就可以去除负偏离值的影响,更加凸显那些偏离较大的偏差值(不管正负)。
然而,神经网络往往涉及到许多不同的输入和输出值,这种情况下我们就需要一个学习算法来帮我们自动完成这一步。
现在是要借助误差来帮我们找到应该被调整的权重值,从而使得误差最小化。但在这之前,让我们了解一下梯度的概念。
对于一个双变量函数,它采用如下形式表示:
什么是梯度下降?下降则可以简单理解为通过梯度来找到我们函数最大斜率的方向,然后通过反方向小步幅的多次尝试,从而找到使函数全局(有时是局部)误差值最小的权重。
然后重复这个过程,直到误差值最小并趋近于零。
附带的示例采用梯度下降法,将如下数据集训练成有两个输入值和一个输出值的神经网络:
一旦训练成功,这个网络将会在输入两个1时输出~0,在输入1和0时,输出~1。
PSD:\github\ai-simplest-network-master\src>gobuild-obin/test.exePSD:\github\ai-simplest-network-master\bin>./test.exeerr:1.7930306267024234err:1.1763080417089242……err:0.00011642621631266815err:0.00010770190838306002err:9.963134967988221e-05Finishedafter111iterationsResults----------------------[11]=>[0.007421243532258703][10]=>[0.9879921757260246]Dockerdockerbuild-tsimplest-network.dockerrun--rmsimplest-network二、最基础的反向传播算法反向传播(英语:Backpropagation,缩写为BP)是“误差反向传播”的简称,是一种与最优化方法(如梯度下降法)结合使用的,用来训练人工神经网络的常见方法。
反向传播技术可以用来训练至少有一个隐藏层的神经网络。下面就来从理论出发结合代码拿下反向传播算法。
在一个神经网络,输入值是前一层节点输出值的权重加成总和,再加上前一层的误差:
如果我们把误差当作层中另外的一个常量为-1的节点,那么我们可以简化这个公式为
反向传播算法可以用来训练人工神经网络,特别是针对具有多于两层的网络。
原理是采用forwardpass来计算网络输出值和误差,再根据误差梯度反向更新输入层的权重值。
在下面的示例中,我们将对不同层节点采用以下激活函数:
在forwardpass中,我们在输入层进行输入,在输出层得到结果。
对于隐藏层的每个节点的输入就是输入层输入值的加权总和:
因为隐藏层的激活函数是sigmoid,那么输出将会是:
同样,输出层的输入值则是
因为我们赋予了恒等函数做为激活函数,所以这一层的输出将等同于输入值。
一旦输入值通过网络进行传播,我们就可以计算出误差值。如果有多套关联,还记得我们第一部分学习的方差吗?这里,我们就可以采用平均方差来计算误差。
现在我们已经得到了误差,就可以通过反向传输,来用误差来修正网络的权重值。
通过第一部分的学习,我们知道对权重的调整可以基于误差对权重的偏导数乘以学习率,即如下形式
我们通过链式法则计算出误差梯度,如下:
类似地,对于隐藏层之间的权重调整,继续以上面的例子为例,输入层和第一个隐藏层之间的权重调整值为
首先,对网络权重值赋予一个小的随机值。
重复以下步骤,直到误差为0:
接下来,我们通过对前一层的加权总和将网络向前传递到J层,如下
最后,我们将这个结果传递到最后的输出层。
针对I和J层节点权重计算其梯度为:
最后一步是用计算出的梯度更新所有的权重值。注意这里如果我们有多于一个的关联,那么便可以针对每组关联的梯度进行累计,然后更新权重值。
可以看到这个权重值变化很小,但如果我们用这个权重再跑一遍forwardpass,一般来说将会得到一个比之前更小的误差。让我们现在来看下……
可见,误差得到了减小!尽管减少值很小,但对于一个真实场景也是很有代表性的。按照该算法重复运行,一般就可以将误差最终减小到0,那么便完成了对神经网络的训练。
本示例中,将一个2X2X1的网络训练出XOR运算符的效果。
注意,XOR运算符是不能通过第一部分中的线性网络进行模拟的,因为数据集分布是非线性的。也就是你不能通过一条直线将XOR的四个输入值正确划分到两类中。如果我们将sigmoid函数换为恒等函数,这个网络也将是不可行的。
讲完这么多,轮到你自己来动手操作啦!试试采用不同的激活函数、学习率和网络拓扑,看看效果如何?