用Python从零开始设计数字图片识别神经网络--搭建基本架构

从本节开始,我们用python把前几节讲解的神经网络原理实现出来。在最开始时,我们直接调用Kera框架,快速的构建一个能识别数字图片的神经网络,从本节开始,我们自己用代码将整个神经网络重新实现一遍,只有我们能重新制造一个“轮胎”,我们才能说我们真正理解的“轮胎”的内在原理。

我们代码开发也保持着由简单到复杂的原则,就像上楼梯,一步一步的走,直到最后走到“高处不胜寒”的楼顶。一开始,我们先把神经网络的基本架构给搭建出来。我们的代码要导出三个接口,分别完成以下功能:
1,初始化initialisation,设置输入层,中间层,和输出层的节点数。
2,训练train:根据训练数据不断的更新链路的权重值
3,查询query,把新的数据输入给神经网络,网络计算后输出答案。
由此我们先给出如下代码框架:

class  NeuralNetWork:
    def __init__(self):
        #初始化网络,设置输入层,中间层,和输出层节点数
        pass
    def  train(self):
        #根据输入的训练数据更新节点链路权重
        pass
    def  query(self):
        #根据输入数据计算并输出答案
        pass

我们先完成初始化函数,我们需要在这里设置输入层,中间层和输出层的节点数,这样就能决定网络的形状和大小。当然我们不能把这些设置都写死,而是根据输入参数来动态设置网络的形态。由此我们把初始化函数修正如下:

class  NeuralNetWork:
    def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate):
        #初始化网络,设置输入层,中间层,和输出层节点数
        self.inodes = inputnodes
        self.hnodes = hiddennodes
        self.onodes = outputnodes
        
        #设置学习率
        self.lr = learningrate
        #
        pass
    def  train(self):
        #根据输入的训练数据更新节点链路权重
        pass
    def  query(self):
        #根据输入数据计算并输出答案
        pass

如此我们就可以初始化一个3层网络,输入层,中间层和输出层都有3个节点,相应代码如下:

input_nodes = 3
hidden_nodes = 3
output_nodes = 3

learning_rate = 0.3
n = NeuralNetWork(input_nodes, hidden_nodes, output_nodes, learning_rate)

上面代码构造了一个三层,每层三个节点的神经网络对象,当然它的内核还有待我们继续实现。接下来我们要根据输入参数构建网络的节点,特别是节点间的链路权重。链路权重是整个网络的核心,也是网络训练时需要不断改进的参数,链路权重决定了网络最终输出结果的精确度。前面我们提到过,链路权重可以用矩阵组织起来,他们的计算也得通过矩阵运算来进行。

我们要构造的有两个矩阵,一个是由输入层和中间层节点链路间构成的矩阵,我们用
《用Python从零开始设计数字图片识别神经网络--搭建基本架构》 这里写图片描述

来表示,这个矩阵的大小为hidden_nodes * input_nodes。

第二个是用中间层和输出层节点间链路构成的矩阵,我们用

《用Python从零开始设计数字图片识别神经网络--搭建基本架构》 这里写图片描述

来表示,它的大小是output_nodes * hidden_nodes。

一开始时,节点链路间的权重是随机设置的,我们把初始时链路权重随机的设置在0和1间。由于权重不一定都是正的,它完全可以是负数,因此我们在初始化时,把所有权重初始化为-0.5到0.5之间,由于我们的输入层有三个节点,中间层也有三个节点,因此输入层和中间层链路间的权重矩阵可以使用如下方法来初始化:

import numpy
numpy.random.rand(3,3) - 0.5

代码执行后效果如下:

《用Python从零开始设计数字图片识别神经网络--搭建基本架构》 这里写图片描述

仿照上面做法,我们在神经网络的初始化函数中构造两个权重矩阵如下:

def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate):
        #初始化网络,设置输入层,中间层,和输出层节点数
        self.inodes = inputnodes
        self.hnodes = hiddennodes
        self.onodes = outputnodes
        
        #设置学习率
        self.lr = learningrate
        '''
        初始化权重矩阵,我们有两个权重矩阵,一个是wih表示输入层和中间层节点间链路权重形成的矩阵
        一个是who,表示中间层和输出层间链路权重形成的矩阵
        '''
        self.wih = numpy.random.rand(self.hnodes, self.inodes) - 0.5
        self.who = numpy.random.rand(self.onodes, self.inodes) - 0.5
        
        pass

接着我们先看query函数的实现,它接收输入数据,通过神经网络的层层计算后,在输出层输出最终结果。输入数据要依次经过输入层,中间层,和输出层,并且在每层的节点中还得执行激活函数以便形成对下一层节点的输出信号。经过前面的讨论,我们知道可以通过矩阵运算把这一系列复杂的运算流程给统一起来。

如果我们用I表示输入数据,输入数据经过输入层和中间层节点的链路后,形成信号输入到中间层的节点,这个过程可以用下面公式表达:

《用Python从零开始设计数字图片识别神经网络--搭建基本架构》 这里写图片描述

我们用Python代码可以很方便的去实现上面的公式。对应代码实现如下:

 def  query(self, inputs):
        #根据输入数据计算并输出答案
        hidden_inputs = numpy.dot(self.wih, inputs)
        pass

X(hidden)是个一维向量,每个元素对应着中间层某个节点从上一层神经元传过来后的信号量总和,于是每个节点就得执行激活函数,得到的结果将作为信号输出到下一层,我们用下面的式子表示运算过程:

《用Python从零开始设计数字图片识别神经网络--搭建基本架构》 这里写图片描述

sigmod函数在Python中可以直接调用,我们要做的就是准备好参数。我们先把这个函数在初始化函数中设定好,代码如下:

import scipy.special

class  NeuralNetWork:
    def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate):
        #初始化网络,设置输入层,中间层,和输出层节点数
        self.inodes = inputnodes
        self.hnodes = hiddennodes
        self.onodes = outputnodes
        
        #设置学习率
        self.lr = learningrate
        '''
        初始化权重矩阵,我们有两个权重矩阵,一个是wih表示输入层和中间层节点间链路权重形成的矩阵
        一个是who,表示中间层和输出层间链路权重形成的矩阵
        '''
        self.wih = numpy.random.rand(self.hnodes, self.inodes) - 0.5
        self.who = numpy.random.rand(self.onodes, self.inodes) - 0.5
        
        self.activation_function = lambda x:scipy.special.expit(x)
        
        pass
        .....

其中scipy.special.expit对应的正是sigmod函数,里面的lambda是Python关键字,它有点像C语言中的宏定义,当我们调用self.activation_function(x)时,编译器会把其转换为spicy.special_expit(x)。由此我们就可以分别调用激活函数计算中间层的输出信号,以及输出层经过激活函数后形成的输出信号,代码如下:

def  query(self, inputs):
        #根据输入数据计算并输出答案
        #计算中间层从输入层接收到的信号量
        hidden_inputs = numpy.dot(self.wih, inputs)
        #计算中间层经过激活函数后形成的输出信号量
        hidden_outputs = self.activation_function(hidden_inputs)
        #计算最外层接收到的信号量
        final_inputs = numpy.dot(self.who, hidden_outputs)
        #计算最外层神经元经过激活函数后输出的信号量
        final_outputs = self.activation_function(final_inputs)
        print(final_outputs)
        pass

完成以上代码后,神经网络的大体框架就完成了,我们留下最重要的train函数,也就是通过训练样本训练链路权重的流程到下节实现。我们尝试传入一些数据,让后让神经网络输出结果试试:

input_nodes = 3
hidden_nodes = 3
output_nodes = 3

learning_rate = 0.3
n = NeuralNetWork(input_nodes, hidden_nodes, output_nodes, learning_rate)
n.query([1.0, 0.5, -1.5])

代码运行后输出结果为:

《用Python从零开始设计数字图片识别神经网络--搭建基本架构》 这里写图片描述

程序当前运行结果并没有太大意义,但是至少表明,我们到目前为止写下的代码没有太大问题,下节我们将集中精力去实现神经网络的训练流程!

更多技术信息,包括操作系统,编译器,面试算法,机器学习,人工智能,请关照我的公众号:

《用Python从零开始设计数字图片识别神经网络--搭建基本架构》 这里写图片描述

    原文作者:望月从良
    原文地址: https://www.jianshu.com/p/4ee77ee73978
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞