毫不是心血来潮:尝试用python本身写一个神经网络

首先,神经网络是什么?人脑由几千亿由突触相互链接的细胞(神经元)组成。突触传入足够的兴奋就会引发神经元的兴奋。这个过程被称为“思考”。python

用9行Python代码编写一个简易神经网络?你敢信?看起来超简单

 

咱们能够在计算机上写一个神经网络来模拟这个过程。不须要在生物分子水平模拟人脑,只需模拟更高层级的规则。咱们使用矩阵(二维数据表格)这一数学工具,而且为了简单明了,只模拟一个有3个输入和一个输出的神经元。网络

咱们将训练神经元解决下面的问题。前四个例子被称做训练集。你可能发现了,输出老是等于输入中最左列的值。因此‘?’应该是1。app

用9行Python代码编写一个简易神经网络?你敢信?看起来超简单

 

训练过程

可是如何使咱们的神经元回答正确呢?赋予每一个输入一个权重,能够是一个正的或负的数字。拥有较大正(或负)权重的输入将决定神经元的输出。首先设置每一个权重的初始值为一个随机数字,而后开始训练过程:dom

  1. 取一个训练样本的输入,使用权重调整它们,经过一个特殊的公式计算神经元的输出。
  2. 计算偏差,即神经元的输出与训练样本中的期待输出之间的差值。
  3. 根据偏差略微地调整权重。
  4. 重复这个过程10万次。

 

用9行Python代码编写一个简易神经网络?你敢信?看起来超简单

 

最终权重将会变为符合训练集的一个最优解。若是使用神经元考虑这种规律的一个新情形,它将会给出一个很棒的预测。函数

这个过程就是BP。工具

计算神经元输出的公式

你可能会想,计算神经元输出的公式是什么?首先,计算神经元输入的加权和,即测试

用9行Python代码编写一个简易神经网络?你敢信?看起来超简单

 

接着使之规范化,结果在0,1之间。为此使用一个数学函数--Sigmoid函数:spa

用9行Python代码编写一个简易神经网络?你敢信?看起来超简单

 

Sigmoid函数的图形是一条“S”状的曲线。3d

用9行Python代码编写一个简易神经网络?你敢信?看起来超简单

 

把第一个方程代入第二个,计算神经元输出的最终公式为:code

用9行Python代码编写一个简易神经网络?你敢信?看起来超简单

 

调整权重的公式

咱们在训练时不断调整权重。可是怎么调整呢?可使用“Error Weighted Derivative”公式:

用9行Python代码编写一个简易神经网络?你敢信?看起来超简单

 

为何使用这个公式?首先,咱们想使调整和偏差的大小成比例。其次,乘以输入(0或1),若是输入是0,权重就不会调整。最后,乘以Sigmoid曲线的斜率(图4)。

Sigmoid曲线的斜率能够经过求导获得:

用9行Python代码编写一个简易神经网络?你敢信?看起来超简单

 

把第二个等式代入第一个等式里,获得调整权重的最终公式:

用9行Python代码编写一个简易神经网络?你敢信?看起来超简单

 

构造Python代码

虽然咱们没有使用神经网络库,可是将导入Python数学库numpy里的4个方法。分别是:

  • exp--天然指数
  • array--建立矩阵
  • dot--进行矩阵乘法
  • random--产生随机数

 

“.T”方法用于矩阵转置(行变列)。因此,计算机这样存储数字:

用9行Python代码编写一个简易神经网络?你敢信?看起来超简单

 

我对每一行源代码都添加了注释来解释全部内容。注意在每次迭代时,咱们同时处理全部训练集数据。因此变量都是矩阵(二维数据表格)。下面是一个用Python写地完整的示例代码。

#numpy导入天然指数,建立矩阵,产生随机数,矩阵乘法的方法 from numpy import exp,array,random,dot class NeuralNetwork(object):     def __init__(self):         #指定随机数发生器种子,保证每次得到相同结果的随机数         random.seed(1)         #对含有3个输入一个输出的单个神经元建模         #即3*1矩阵(树突)赋予随机权重值。范围(-1,1)         #即(a,b)范围的c*d矩阵随机数为(b-a)*random.random((c,d))+a         self.dendritic_weights = 2*random.random((3,1))-1     #Sigmoid函数,s形曲线,用于对输入的加权总和x作(0,1)正规化     #它能够将一个实数映射到(0,1)的区间     def __sigmoid(self,x):         return 1/(1+exp(-x))     #Sigmoid函数的导数(梯度)(当前权重的置信程度,越小表明越可信)     #这里的x指的是1/(1+exp(-x)),即output输出     def __sigmoid_derivative(self,x):         return x*(1-x)     #训练该神经网络,并调整树突的权重     def train(self,training_inputs,training_outputs,number_of_training_iterations):         '''         training_inputs:训练集样本的输入         training_outputs:训练集样本的输出         number_of_training_iterations:训练次数         1.咱们使用Sigmoid曲线计算(输入的加权和映射到0至1之间)做为神经元的输出         2.若是输出是一个大的正(或负)数,这意味着神经元采用这种(或另外一种)方式,         3.从Sigmoid曲线能够看出,在较大数值处,Sigmoid曲线斜率(导数)小,即认为当前权重是正确的,就不会对它进行很大调整。         4.因此,乘以Sigmoid曲线斜率即可以进行调整         '''         for iteration in range(number_of_training_iterations):             #训练集导入神经网络             output = self.think(training_inputs)             #计算偏差(实际值与指望值的差)             error = training_outputs - output             #将偏差乘以输入,再乘以S形曲线的梯度             adjustment = dot(training_inputs.T,error*self.__sigmoid_derivative(output))             #对树突权重进行调整             self.dendritic_weights += adjustment         #神经网络     def think(self,inputs):         #输入与权重相乘并正规化         return self.__sigmoid(dot(inputs,self.dendritic_weights)) if __name__ == '__main__':     #初始化神经网络nn     nn = NeuralNetwork()     #初始权重     print("初始树突权重:{}".format(nn.dendritic_weights))     #训练集,四个样本,每一个样本有3个输入,1个输出     #训练样本的输入     training_inputs_sample = array([[0,0,1],                                     [1,1,1],                                     [1,0,1],                                     [0,1,1]])     #训练样本的输出     training_outputs_sample = array([[0,1,1,0]]).T     #用训练集训练nn,重复一万次,每次作微小的调整     nn.train(training_inputs_sample,training_outputs_sample,100000)     #训练后的树突权重     print("训练后树突权重:{}".format(nn.dendritic_weights))     #用新数据进行测试     test_result = nn.think(array([1,0,0]))     print('测试结果:{}'.format(test_result))

 

 

结语

运行后你应该看到这样的结果:

 

 

咱们作到了!咱们用Python构建了一个简单的神经网络!

首先神经网络对本身赋予随机权重,而后使用训练集训练本身。接着,它考虑一种新的情形[1, 0, 0]而且预测了0.99993704。正确答案是1。很是接近!

相关文章
相关标签/搜索