美文网首页
神经网络入门-MNIST的数字识别

神经网络入门-MNIST的数字识别

作者: 小的橘子 | 来源:发表于2019-06-12 22:27 被阅读0次

    一 、基本原理

    分类器

    形如y=ax+b的简单线性分类器

    误差值 = (期望目标值 - 实际输出值)
    E=t-y
    E=(ΔA)x ΔA是斜率差

    ΔA=L(E/x) L为调节系数,称为学习率

    激活函数

    神经元是输出超过了阈值(threshold)才会产生输出信号,可以通过激活函数完成。阶跃函数就是一种激活函数。阶跃函数变得平滑一些更符合实际,称为S函数(Sigmoid function),信号函数。

    S函数有时也称为逻辑函数:
    y = \frac{1}{1+e^{-x}}

    输入值及输出值计算

    如果神经网络有多层,则x为组合调节后的信号,表示:X=W\cdot I
    W是权重矩阵,I是输入矩阵。神经网络层输出:O=sigmoid(X),O代表输出矩阵
    以隐藏层组合调节输入值为例,X看做XhiddenX_{hidden}=W_{input\_hidden}\cdot I
    对应两个输入的矩阵如下:
    X_{hidden}= \begin{pmatrix} W_{1,1} & W_{2,1}\\ W_{1,2} & W_{2,2} \end{pmatrix} \cdot \begin{pmatrix} I_{1}\\ I_{2} \end{pmatrix}
    其中I为上一层输入,W为隐藏层权重

    矩阵相乘,第一个矩阵的列数应该等于第二个矩阵的行数。矩阵乘法又称为点乘(dot product)或内积(inner product)

    每层输出都需要应用激活函数,例如:O_{hidden}=sigmoid(X_{hidden})

    反向误差传播

    输出节点的误差等于所需值与实际值的差值。但是内部节点的误差并不显而易见,一种方法就是按照链路权重比例分割输出层的误差,然后在每个内部节点充足这些误差。隐藏层误差公式:e_{hidden,1} = e_{output,1}* \frac{W_{1,1}}{W_{1,1}+W_{2,1}} +e_{output,2}*\frac{W_{1,2}}{W_{1,2}+W_{2,2}}

    隐藏层矩阵误差表示如下:
    error_{hidden} = \begin{pmatrix} \frac{W_{1,1}}{W_{1,1}+W_{2,1}} & \frac{W_{1,2}}{W_{1,2}+W_{2,2}} \\ \frac{W_{2,1}}{W_{1,1}+W_{2,1}} & \frac{W_{2,2}}{W_{1,2}+W_{2,2}}\end{pmatrix}\cdot \begin{pmatrix} e_{1} \\ e_{2} \end{pmatrix}
    这些分数的分母是归一化因子,如果我们忽略因子,仅仅失去后馈误差的大小。我们可以通过e1*w1,1 代替e1 * w1,1/(w1,1+w2,1)
    那么隐藏层矩阵误差表示如下:
    error_{hidden} = \begin{pmatrix} W_{1,1} & W_{1,2} \\ W_{2,1} & W_{2,2} \end{pmatrix}\cdot \begin{pmatrix} e_{1} \\ e_{2} \end{pmatrix}
    我们可以发现这个W矩阵是组合调节后的信号公式中W矩阵的转置,故此处可以通过wT表示该处的矩阵。
    error_{hidden} = W^{T}_{hidden\_output}\cdot error_{output}

    权重更新

    二、数字识别神经网络

    神经网络分为三部分

    1. 神经网络初始化
    2. 训练神经网络
    3. 调用神经网络

    下面展示了最简单数字识别神经网络

    import numpy
    import scipy.special
    
    # 该神经网络有三层,输入层、隐藏层和输出层
    class NeuralNetwork:
        # 初始化神经网络
        def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate):
            # 设置每层节点数量
            self.inodes = inputnodes
            self.hnodes = hiddennodes
            self.onodes = outputnodes
            
            # 学习率
            self.lr = learningrate
    
            # 权重形式
            # w11 w21
            # w21 w22 etc,故对于W_input_hidden来说列数为inodes,行数为hnodes
            # self.wih = numpy.random.rand(self.hnodes, self.inodes) - 0.5
            # self.who = numpy.random.rand(self.onodes, self.hnodes) - 0.5
    
            # 采用正太分布优化权重取值,标准差为1/(传入连接数目的0.5次方)
            self.wih = numpy.random.normal(0.0, pow(self.inodes, -0.5), (self.hnodes, self.inodes))
            self.who = numpy.random.normal(0.0, pow(self.hnodes, -0.5), (self.onodes, self.hnodes))
            # 激活函数
            self.activation_function = lambda x: scipy.special.expit(x)
            pass
        # 根据正确的输入值和目标值训练神经网络,找到更合适的权重
        def train(self, inputs_list, targets_list):
            inputs = numpy.array(inputs_list, ndmin=2).T; # 列表转化为二维数组
            targets = numpy.array(targets_list, ndmin=2).T;
    
            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)
            output_errors = targets - final_outputs;
            # errors_hidden = W_hidden_output.T error_output
            hidden_errors = numpy.dot(self.who.T, output_errors)
            self.who += self.lr * numpy.dot(output_errors * final_outputs * (1.0 - final_outputs),
                                            numpy.transpose(hidden_outputs))
            self.wih += self.lr * numpy.dot(hidden_errors * hidden_outputs * (1.0 - hidden_outputs),
                                            numpy.transpose(inputs))
        # 根据输入求输出
        def query(self, inputs_list):
            inputs = numpy.array(inputs_list, ndmin=2).T 
            # X_hidden = W_input_hidden I
            hidden_inputs = numpy.dot(self.wih, inputs)
            # O_hidden = sigmoid(X_hidden)
            hidden_outputs = self.activation_function(hidden_inputs)
            # 输出层计算
            final_inputs = numpy.dot(self.who, hidden_outputs)
            final_outputs = self.activation_function(final_inputs)
            return final_outputs
    

    训练神经网络

    input_nodes = 784  # 数字的像素为28x28,故输入节点为784个
    hidden_nodes = 100
    output_nodes = 10 # 表示0~9,10个数字
    learning_rate = 0.3
    n = NeuralNetwork(input_nodes, hidden_nodes, output_nodes, learning_rate)
    
    training_data_file = open("mnist_dataset/mnist_train.csv", 'r') # 训练数据
    training_data_list = training_data_file.readlines()
    training_data_file.close()
    
    for record in training_data_list:
        all_values = record.split(',')
        inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01 #  输入数据要在[0.01,1]之内
        targets = numpy.zeros(output_nodes) + 0.01  # 初始10个为0.01的列表
        targets[int(all_values[0])] = 0.99  # 目标值为0.99
        n.train(inputs, targets) # 调用神经网络进行训练
    

    测试神经网络

    test_data_file = open('mnist_dataset/mnist_test.csv', 'r') # 测试数据
    test_data_list = test_data_file.readlines()
    test_data_file.close()
    scorecard = []
    for record in test_data_list:
        all_values = record.split(',')
        correct_label = int(all_values[0])
        # print('correct_label={0}'.format(correct_label))
        inputs_list = numpy.asfarray(all_values[1:])/255.0 * 0.99 + 0.01
        outputs = n.query(inputs_list)
        label = numpy.argmax(outputs) # 找到输出数组中最大值的索引,其对应的就是实际识别的数字
        # print("network's answer={0}",label)
        if(label == correct_label) : # 数字识别正确加1,否则加0
            scorecard.append(1)
        else :
            scorecard.append(0)
    scorecard_array = numpy.asarray(scorecard)
    print('performance = ', scorecard_array.sum()/scorecard_array.size) 
    

    最终识别率在94.7%

    一些改进

    1. 调整学习率


      性能与学习率关系

      学习要选取合适,并不是越大越好,也不能偏小,可以根据多次实验选取最佳学习率,该例学习率为0.2时,性能更好为95.13%

    2. 多次运行
      训练一次称为1个世代,看看同样的训练数据是否会改善性能


      性能和世代关系

      在7个世代性能高达96.28%

    在提高世代时调低学习率也会有一定改善



    学习率分别为0.1,和0.2,学习率为0.1时,世代为5时性能最高,达96.89%

    1. 改变网络形状
      输入和输出不能改变,但隐藏层节点个数可以调整。


      性能和隐藏层节点个数关系

      整体看来隐藏层节点越大,性能越高,前100个节点性能增长非常快,在到达200个节点时性能已经基本没有改善,为了神经网络的执行时间更短,我们可以选择节点200。

    相关文章

      网友评论

          本文标题:神经网络入门-MNIST的数字识别

          本文链接:https://www.haomeiwen.com/subject/zlwftctx.html