介绍我不懂机器学习,但是上个月我在GitHub上找到了一个极简的入门级神经网络教程,有Go语言的示例代码。简明易懂,不用写一个字废话,就可以用一行公式把浅显的道理说清楚。读完后,我迷上了。这么好的东西要让更多的人看到,但是原文是英文的,不能直接分享,所以要联系作者取得翻译的授权,然后小雄雄翻译了这个项目,最后你可以看这篇文章。过程艰辛,历时一个月,实属不易。如果您看完后觉得还不错,请点个赞,分享给更多的人。内容分为两部分:第1部分:最简单的人工神经网络第2部分:最基本的反向传播算法人工神经网络是人工智能的基础。只有打好基础,才能玩出AI魔法!温馨提示:虽然公式很多,看起来只是唬人的,但仔细阅读后并不难理解。下面正文开始!1.最简单的人工神经网络最简单的人工神经网络通过理论和代码进行讲解和演示。示例代码:https://github.com/gokadin/ai-simplest-network理论模拟神经元受人脑工作机制的启发,人工神经网络具有相互连接的模拟神经元,用于存储模式并相互通信。在最简单的形式中,一个模拟神经元有一个或多个输入值和一个输出值,每个输出值都有一个权重。用最简单的话来说,输出值就是输入值乘以权重的总和。一个简单的示例网络是通过多个参数来模拟一个复杂的函数,从而在给定一系列输入值的情况下得到一个特定的输出值,而这些参数通常是我们很难制定的。假设我们现在的网络有两个输入值,分别对应两个权重值and。现在我们需要调整权重值,使它们产生我们预设的输出值。在初始化的时候,因为不知道最优值,所以权重往往是随机分配的。为简单起见,这里我们将它们初始化为1。在这种情况下,我们得到的是错误值。如果输出值与我们期望的输出值不一致,那么就会出错。比如我们要目标值是,那么这里的差值通常是我们会用方差(也就是代价函数)来衡量误差:如果有多组输入输出值,那么误差是每组方差的平均值。我们使用方差来衡量获得的输出值与我们期望的目标值之间的差异。负偏差值的影响可以通过平方去除,那些偏差值较大(不管是正还是负)的偏差值更加突出。为了纠正错误,我们需要调整权重值,使结果趋于我们的目标值。在我们的例子中,从1.0降到0.5可以达到目的,但是,因为神经网络通常涉及许多不同的输入和输出值,在这种情况下我们需要一个学习算法来帮助我们自动完成这一步。梯度下降现在使用误差来帮助我们找到应该调整的权重值,从而使误差最小化。但在此之前,让我们了解梯度的概念。什么是渐变?梯度本质上是一个指向函数最大斜率的向量。我们用梯度来表示,简单的说,就是函数变量的偏导数的向量形式。对于两个变量的函数,它采用以下形式:让我们用一些数字来模拟一个简单的例子。假设我们有一个函数,即梯度下降中的梯度是多少?下降可以简单理解为通过梯度找到我们函数最大斜率的方向,然后通过多次向相反方向的小步尝试,找到使函数全局(有时是局部)误差值最小的权重。我们用称为学习率的常量表示在相反方向上的这一小步,我们将其用于公式中的表示。如果值太大,有可能直接错过最小值,但是如果值太小,那么我们的网络学习时间会更长,也有可能陷入浅层的局部最小值。对于我们例子中的两个权重值之和,我们需要求出这两个权重值相对于误差函数的梯度。还记得我们上面的公式和吗?对于and,我们可以通过微积分中的链式推导规则将它们带入并分别计算它们的梯度。为了简洁起见,我们稍后将使用这个术语来表达它。一旦我们有了梯度,我们就可以通过引入我们建议的学习率来更新权重值,如下所示:然后重复这个过程,直到误差值最小化并接近于零。代码示例附带的示例使用梯度下降将以下数据集训练成具有两个输入值和一个输出值的神经网络:一旦训练完成,网络将在输入两个1时输出~0,并在输入1时输出~0和0,输出~1。它是如何工作的?GoPSD:\github\ai-simplest-network-master\src>gobuild-obin/test.exePSD:\github\ai-simplest-network-master\bin>./test.exe错误:1.7930306267024234err:1.1763080417089242…错误:0.00011642621631266815err:0.00010770190838306002err:9.963134967988221e-05Finishedafter111iterationsResults----------------------[11]=>[0.007421243532258703][10]=>[0.9879921757260246]Dockerdockerbuild-tsimplest-network.dockerrun--rmsimplest-network2.最基本的反向传播算法反向传播(英文:Backpropagation,缩写为BP)是“误差反向传播”的缩写,是一种优化方法(如梯度下降法)是一种用于训练人工神经网络的常用方法。反向传播技术可用于训练具有至少一个隐藏层的神经网络。下面我们从理论出发,结合代码来赢取反向传播算法。示例代码:https://github.com/gokadin/ai-backpropagationTheory感知器简介感知器是一个处理单元,它接受输入,使用激活函数对其进行转换,然后输出结果。在神经网络中,输入值是上一层节点输出值的加权和,加上上一层的误差:如果我们把误差看成是该层中另一个节点的常数为-1、那我们可以把这个公式化简成一个激活函数为什么需要激活函数呢?如果不是,我们每个节点的输出都会是线性的,这样整个神经网络就会是根据输入值进行线性运算的输出。由于线性函数组合仍然是线性的,因此需要引入非线性函数,使神经网络区别于线性回归模型。对于,一个典型的激活函数有如下形式:Sigmoid函数:线性整流函数:tanh函数:反向传播反向传播算法可以用来训练人工神经网络,尤其是两层以上的网络。原理是利用正向传播计算网络输出值和误差,然后根据误差梯度反向更新输入层的权值。项分别为I、J、K层节点的输入值。分别是I、J、K层节点的输出值。是K个输出节点的期望输出值。分别是I层到J层和J层到K层的权重值。代表T组关联中的当前一组关联。在下面的例子中,我们会对不同的层节点使用如下激活函数:输入层->身份函数隐藏层->Sigmoid函数输出层->身份函数Forwardpass在forwardpass中,我们进行Input,得到结果在输出层。隐藏层每个节点的输入是输入层输入值的加权和:因为隐藏层的激活函数是sigmoid,那么输出将是:同理,输出层的输入值是因为我们给identityfunction做的是激活函数,所以这一层的输出会等于输入值。一旦输入值通过网络传播,我们就可以计算误差值。如果有多组关联,还记得我们在第一部分学到的方差吗?在这里,我们可以使用平均方差来计算误差。反向传播既然我们已经得到了误差,那么我们就可以利用误差通过反向传输来修正网络的权重值。通过第一部分的学习,我们知道权重的调整可以基于误差对权重乘以学习率的偏导数,即如下形式。我们通过链式法则计算误差梯度,如下:因此,权重的调整是针对多个关联的,那么权重调整将是每个关联的权重调整值之和。同样,对于隐藏层之间的权值调整,继续上面的例子,输入层和第一个隐藏层之间是第一个隐藏层。如果权重调整值是,那么基于所有关联的权重调整就是为每个关联计算的调整值的总和。在这里,我们可以做进一步的探索。以上,我们看到了。对于前半部分,我们可以有后半部分,因为我们在这一层使用了sigmoid函数,我们知道sigmoid函数的导数形式是,因此,结合上面,我们可以得到计算公式如下算法总结首先,为网络权重值分配一个小的随机值。重复以下步骤直到误差为0:对于每个关联,通过神经网络前向传递得到输出值计算每个输出节点的误差()Overlay计算每个输出权重的梯度()计算每个输出的隐藏层node()overlay为每个隐藏层计算梯度weight()更新所有权重值,重置overlaygradient()反向传播图解在这个例子中,我们通过真实数据模拟神经网络中的每个步骤。输入值为[1.0,1.0],预期输出值为[0.5]。为简单起见,我们将权重初始化为0.5(尽管在实践中,经常使用随机值)。对于输入层、隐藏层和输出层,我们分别使用恒等函数、sigmoid函数和恒等函数作为激活函数,学习率设置为0.01。在正向传递操作开始时,我们将输入层的节点输入值的输入值设置为。因为我们使用恒等函数作为输入层的激活函数,所以有。接下来,我们通过对前一层的总和进行加权,将网络向前传递到第J层,如下所示。然后,我们将第J层节点的值输入到sigmoid函数(,将代入,得到0.731)进行激活。最后,我们将这个结果传递给最终的输出层。因为我们输出层的激活函数也是恒等函数,Backwardpassbackpropagation的第一步就是计算输出节点,利用计算J和K两层节点之间的权重梯度:接下来,在同一个计算way每个隐藏层的值(在这个例子中,只有一个隐藏层):它的梯度是针对I和J层节点权重计算为:最后一步是用计算出的梯度更新所有的权重值。注意,如果我们这里有多个关联,我们可以累加每一组关联的梯度,然后更新权重值。可以看出这个权重值变化很小,但是如果我们用这个权重再跑一次forwardpass,一般会得到比之前更小的error。现在让我们看看......我们在第一遍中得到了什么,用新的权重值计算。因此,和。可以看出错误减少了!虽然减少量很小,但它代表了真实场景。按照算法反复运行,一般最终可以将误差降为0,神经网络的训练就完成了。代码示例在此示例中,训练2X2X1网络以实现XOR运算符的效果。这里,f是隐藏层的sigmoid激活函数。请注意,第一部分中的线性网络无法模拟XOR运算符,因为数据集分布是非线性的。也就是你不能通过一条直线将XOR的四个输入值正确的分成两类。如果我们用恒等函数替换sigmoid函数,这个网络也不可行。说了这么多,轮到你自己动手了!尝试不同的激活函数、学习率和网络拓扑,看看会发生什么?感谢原作者授权:
