读后总结

上周就把神经网络编程的书看完了,但是一直没有时间总结一下,书里面的代码也没有进行实现,国庆七天假期,趁着这个空闲把博客写了。
神经网络是一种模拟人脑的神经网络,以期能够实现类人工智能的机器学习技术。
神经网络编程在我看来就是模拟神经元的工作机制,用代码构建多层神经元一样的节点,每一层的节点都与前后层的神经元相连接,而数据就从起始层输入,经过一层层的处理到最后输出层得到我们想要的数据。
书中使用的神经网络,需要设定神经网络的层数、每层的节点数、层与层之间的权重以及节点的阈值函数这四个东西基本就可以了。一个简单的神经网络框架也比较简单,包含三个函数:(1)初始化函数(2)训练函数(3)查询函数。下面的识别数字的神经网络代码其实也就只包含了上面的这几个东西。我读的这本书中,神经网络并没有针对某一场景的具体处理算法,他只是利用一些数学函数,和训练数据,训练出了一个数学模型。你并不知道这个模型是如何得到最后的结果,它的内部就像一个黑盒,你通过大量的数据不断优化层与层之间的权重,从而得到一个训练好的模型。
神经网络的运行流程大概就是下面这样(字很多,但是很简单详细):
network.png
想要学习python神经网络编程大概需要学习下面这几种库或模块的使用:


当然,数学的基础也是必不可少的,像矩阵分布、概率分布之类的都是在神经网络中经常使用的,学习神经网络之前最好也对线性代数、概率论等有所了解。
其实不只是神经网络,在人工智能领域,上面所说的这些也都是非常重要的(神经网络是人工智能的一个重要的分支)。

代码实现:手写数字的识别

要实现下面这个神经网络,需要训练数据集和测试数据集,下面是相应数据集的百度网盘地址:

(1)60000条训练数据:
链接:https://pan.baidu.com/s/1WSPqSBQ2FRLi2Yfu3iNg-g
提取码:pfm7
(2)100条训练数据:
链接:https://pan.baidu.com/s/15y1OojW1adQ6Buppcs3YNA
提取码:f5eh
(3)10条测试数据:
链接:https://pan.baidu.com/s/1sJ5dwNF70Epu4-xHiONKwA
提取码:dcgs

上面每条数据由785个数字组成,第一个数字代表着这条数据代表的数字,剩余的是这张数字图片的像素值,是28*28大小的,截图中表示这条数据表示的是数字7:
TIM截图20191004220104.png
我们可以使用绘图库把除了第一个数字的其他数字组成的图片绘制出来,会看到一个清晰的7的轮廓:
TIM截图20191004220449.png
下面开始上代码,首先引入我们所需要使用的库,这几个库在上面的总结中已经介绍了,想要详细学习的可以百度一下相关的教程:

import numpy
import scipy.special
import matplotlib.pyplot

然后开始编写代码,首先我们创建一个神经网络类,它拥有三个函数:初始化函数、训练函数、查询函数,注释写的已经很清楚了,还有不懂得地方可以在博客下面留言:

# 定义神经网络类
class neuralNetwork:
#     定义类的初始化函数
    def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate):
#         初始化函数设置了类的输入层、隐藏层和输出层的节点数,另外用numpy创建了层与层之间的权重矩阵,也确定了学习率和每个节点的激活函数
        self.inodes = inputnodes
        self.hnodes = hiddennodes
        self.onodes = outputnodes
        self.wih = numpy.random.normal(0.0, pow(self.hnodes, -0.5), (self.hnodes, self.inodes))
        self.who = numpy.random.normal(0.0, pow(self.onodes, -0.5), (self.onodes, self.hnodes))
        self.lr = learningrate
        self.activation_function = lambda x: scipy.special.expit(x)
    
    
#     定义了神经网络的训练函数,参数有输入列表和正确结果列列表
    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
#         计算隐藏层的误差
        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
#         计算隐藏层的输入矩阵
        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)
        return final_outputs

训练模型

训练模型要写在主函数中,我们要先导入我们的训练数据集,60000条和100条都可以选,100条的训练速度会比较快,60000条自然会比较慢,大概要2-3分钟。建议大家使用jupyter notebook来写神经网络,因为jupyter notebook可以分步执行我们的代码,他会自动保存你运行过的代码块的状态(我是这么理解的)。当然,使用pycharm或者其他的开发工具也行,就是你每运行一次就相当于训练了一次。
下面是训练模型的代码,使用了100条训练数据,博客最后会拿60000条训练数据训练出来的模型来对比:

# 设置输入、隐藏、输出层的节点数量还有学习率
input_nodes = 784
hidden_nodes = 100
output_nodes = 10
learningrate = 0.3
# 实例化一个神经网络对象
network = neuralNetwork(input_nodes, hidden_nodes, output_nodes, learningrate)
# 导入训练数据,一共100条数据
training_data_file = open("python_network/mnist_train_100.csv", 'r')
training_data_list = training_data_file.readlines()
training_data_file.close()
# 下面开始训练我们的神经网络
for record in training_data_list:
#     先把训练数据都分开,得到像素数值列表
    all_values = record.split(',')
#     将列表处理成输入矩阵,并把所有数值范围定成0-1
#     像素数值范围0-255,所以把列表所有像素数值全部除255,数值的范围就变成了0-1,再乘0.99,数值范围就变成0-0.99
#     为了避免出现0的情况下,加上0.01,数值范围就成功变成0.01-1
    inputs = (numpy.asfarray(all_values[1:])/255.0 * 0.99) + 0.01
#     初始化正确数值矩阵,全部为0/.01
    targets = numpy.zeros(output_nodes) + 0.01
#     设置正确的输出节点值为0.99
    targets[int(all_values[0])] = 0.99
#     调用训练函数
    network.train(inputs, targets)

查询训练结果

当训练完模型之后,我们可以用测试数据,来测试我们的模型正确度怎么样:

# 上面训练模型之后,我们可以用测试数据来对我们的模型进行测试
test_data_file = open("python_network/mnist_test_10.csv")
test_data_list = test_data_file.readlines()
test_data_file.close()
# 接下来我们用训练好的模型来看看成果
for record in test_data_list:
    values = record.split(",")
    correct_answer = values[0]
    result_array = network.query((numpy.asfarray(values[1:])/255.0 * 0.99) + 0.01)
    print("图片中的数字的正确答案是" + str(correct_answer))
    print("系统识别图片数字为:" + str(numpy.argmax(result_array)))
# result_array = network.query((numpy.asfarray(all_values[1:])/255.0 * 0.99) + 0.01)
# print(result_array)
# print(numpy.argmax(result_array))

从下图中可以看出,100条训练数据训练出的模型,正确率是60%:
TIM截图20191004223841.png
下面再来看一下60000条训练数据训练出来的模型,正确率是100%,当然,训练数据只有10条,如果更多的话,正确率大约会是90多,数据充足的情况下,我们完全可以训练出来一个正确率较高的模型。
TIM截图20191004224353.png

最后修改:2019 年 10 月 05 日
如果觉得我的文章对你有用,请随意赞赏