美文网首页
神经网络入门-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