使用python搭建一个简易的神经网络 实现对手写数字的识别(每行代码都有注释)

一些简单的介绍

如果一个简单的线性分类器不能对数据进行划分,我们就需要使用多个线性分类器来划分数据;使用多个分类器一起工作,这是神经网络的核心思想

神经元不会立刻有输入就产生反应,而是会抑制输出,知道输入增强,强大到可以触发输出,一般我们会用sigmod函数来模拟阶跃函数。

输入到下一层结果矩阵中的信号,可以表示为X = W·I,W表示权值矩阵,I表示输入矩阵。这样一来,第二层的最终输出就称为O = sigmod(X)使用python搭建一个简易的神经网络 实现对手写数字的识别(每行代码都有注释)_第1张图片

神经网络通过调整链接权重进行学习,这种方法由误差引导。

内部节点相关联的误差:一种方法是按照链接权重的比例来分割输出层的误差,然后在每个内部节点处重组这些误差。(反向传播误差)

反向传播误差和前向馈送信号都可以使用矩阵实现。

梯度下降法是求解函数最小值的一种很好的办法,函数有很多参数的时候,这种方法仍然可以使用。

两个很常见的问题是饱和和零值权重:大信号(可能由大权重导致)导致了应用在信号上的激活函数的斜率变得非常平缓,这会降低神经网络学习到更好权重的能力;零权值的问题可能导致网络丧失学习更好权重的能力。

输入应该调整到较小值(参考sigmod函数的近0点),但不能为0;输出应该在激活函数能生成的值的范围内。

代码实现

代码逻辑:
通过反向传播误差来实现对神经网络链接权值的更新
代码输入节点,隐藏层节点,输出层节点分别为784,200,10个,目前的代码是通过调整了训练次数,学习率,隐藏层节点数量之后形成的,拥有最好的学习效果的模型,预测的准确率可以达到96%以上

import numpy
import scipy.special

class neuralNetwork:
    def __init__(self, inputNode, hiddenNode, outputNode, learningRate):
        self.inodes = inputNode
        self.hnodes = hiddenNode
        self.onodes = outputNode

        # 设置权重 input--hidden
        self.wih = numpy.random.normal(0.0, pow(self.hnodes, -0.5), (self.hnodes, self.inodes))
        # 设置权重 input--hidden
        self.who = numpy.random.normal(0.0, pow(self.onodes, -0.5), (self.onodes, self.hnodes))

        # learning rate
        self.lr = learningRate

        # activation function
        self.activation_fun = lambda x:scipy.special.expit(x)

        pass

    def train(self, inputs_list, targets_list):
        # 将输入的矩阵转换为numpy二维矩阵
        inputs = numpy.array(inputs_list, ndmin=2).T
        targets = numpy.array(targets_list, ndmin=2).T

        # 计算输入隐藏层的信号,隐藏层输出的信号
        hiddenInputs = numpy.dot(self.wih, inputs)
        hiddenOutputs = self.activation_fun(hiddenInputs)

        # 计算输入输出层的信号,输出层输出的信号
        final_inputs = numpy.dot(self.who, hiddenOutputs)
        final_outputs = self.activation_fun(final_inputs)

        # 误差
        outputError = targets - final_outputs
        hiddenError = numpy.dot(self.who.T, outputError)

        # 更新链接权重
        self.who += self.lr * numpy.dot((outputError * final_outputs * (1.0 - final_outputs)), numpy.transpose(hiddenOutputs))
        self.wih += self.lr * numpy.dot((hiddenError * hiddenOutputs * (1.0 - hiddenOutputs)), numpy.transpose(inputs))
        pass


    def query(self, inputs_list):
        # 输入等于inputs_list的转置,ndmin表示数组的最小维度
        inputs = numpy.array(inputs_list, ndmin=2).T

        # 计算输入隐藏层的信号,隐藏层输出的信号
        hidden_inputs = numpy.dot(self.wih, inputs)
        hidden_outputs = self.activation_fun(hidden_inputs)

        # 计算输入输出层的信号,输出层输出的信号
        final_inputs = numpy.dot(self.who, hidden_outputs)
        final_outputs = self.activation_fun(final_inputs)

        return final_outputs


if __name__ == '__main__':
    # 定义参数
    inputNodes = 784
    hiddenNodes = 200
    outputNodes = 10
    learningRate = 0.2
    n = neuralNetwork(inputNodes, hiddenNodes, outputNodes, learningRate)

    # 导入训练数据集
    trainning_data_file = open("/Users/lizhihan/PycharmProjects/NeuralNetwork/data/mnist_train.csv", "r")
    trainning_data_list = trainning_data_file.readlines()
    trainning_data_file.close()

    # 导入测试数据集
    test_data_file = open("/Users/lizhihan/PycharmProjects/NeuralNetwork/data/mnist_test.csv", "r")
    test_data_list = test_data_file.readlines()
    test_data_file.close()

    # 训练神经网络
    times = 10
    for episode in range(times):
        for record in trainning_data_list:
            # 构建输入
            all_values = record.split(',')
            inputs = (numpy.asfarray(all_values[1:])/255.0*0.99+0.01)

            # 构建目标输出
            targets = numpy.zeros(outputNodes)+0.01
            targets[int(all_values[0])] = 0.99

            # 训练
            n.train(inputs, targets)
            pass
    pass


    # # 简单的测试
    # test_value = test_data_list[0].split(",")
    # print("目标值为:", test_value[0])
    # print(n.query((numpy.asfarray(test_value[1:]))/255.0*0.99)+0.01)


    # 一个真实的测试

    # 先设置计分卡
    scordCard = []

    #遍历test中的所有数据
    for record in test_data_list:
        # 打印正确的数字
        all_values = record.split(',')
        correct_label = all_values[0]
#        print(correct_label, "correct label!")   # 在训练大量数据时设置为不显示

        # 打印神经网络预测的数字
        inputs = (numpy.asfarray(all_values[1:])/255.0*0.99)+0.01
        outputs = n.query(inputs)   # 预测
        label = numpy.argmax(outputs)
#        print(label, "predicted label!")    # 在训练大量数据时设置为不显示

        # 实现记分卡
        if(int(label) == int(correct_label)):   # 注意本身的correct_label类型为str,label类型为numpy.int64,不能直接进行比较,需要进行格式转换
            scordCard.append(1)
        else:
            scordCard.append(0)
            pass
        pass

    # 输出得分卡记录的分数
    scordCard_array = numpy.asarray(scordCard)
    final_score = scordCard_array.sum()/scordCard_array.size
    print("最终得分为", final_score)

最后补充训练数据和测试数据的下载地址:
测试数据
训练数据

你可能感兴趣的:(神经网络,python)