手动编写感知机
手动编写感知机
Emmmm,今天是第一篇正式博文,就写一些比较简单的内容吧。我一直觉得最好的学习方式就是直接的上手,如果能够实现程序,也就没有什么大的问题了。
编写一个简单的感知机并不是很困难,无非就是完成两个主要的任务:正向传播的函数设置,反向传播的修正。所以我们先对感知机的正向传播进行设置。
正向的函数的设置
感知机分为两层:第一层是输入层,第二层是输出层,中间只经过一次简单的矩阵乘法即可实现。为了保证准确率,我将输入层和输出层之间的激活函数设置为sigmoid函数。
训练集和测试集采用网络上最常见的手写数字识别的csv格式的测试集,我们用其中的一部分数字作为感知机的训练数据和测试数据。
反向传播的推导
反向传播的修正是神经网络中最重要的部分,如果没有反向传播的修正,也就谈不上什么机器学习了。因为我们是感知机,其中只有一个激活函数,只要明白了它的反向传播的过程,就没有其他的大的问题了。
反向传播是最麻烦的部分,相对于用电脑写出推导公式,我还是更喜欢用手写的方式进行推导,下面是推导的过程图
现在万事具备接下来就是动手开始编写感知机了。
代码编写
虽然大学中最喜欢的语言是java,但是编写感知机这种事情,怎样也比不了用python进行编写,顺便也学习了一下这种语言,哈哈。
我们首先创造一个类,名为:perceptron:
其中包含三个函数:初始化函数、训练函数以及输出函数
首先是初始化函数:
# 初始化函数 def __init__(self, inputnodes, outputnodes, learningrate): # 内容的初始化 self.input_nodes = inputnodes self.output_nodes = outputnodes # 学习率 self.learning_rate = learningrate # 权重,制作一个大小为输入结点*输出结点的权重大小矩阵 self.wio = numpy.random.normal(0.0, pow(self.output_nodes, -0.5), (self.output_nodes, self.input_nodes)) # 激活函数 y = 1/(1+exp(x)) self.activation_function = lambda x: scipy.special.expit(x) pass
接着是训练函数:
# 训练函数 def training(self, inputlist, outputlist): inputs = numpy.array(inputlist, ndmin=2).T outputs = numpy.array(outputlist, ndmin=2).T output_input = numpy.dot(self.wio, inputs) final_output = self.activation_function(output_input) error_list = outputs - final_output self.wio += self.learning_rate*numpy.dot((error_list*final_output*(1.0-final_output)), numpy.transpose(inputs)) pass
可以看到最核心的部分就是对于权重的更新,和上述的推导过程中一模一样。
最后是输出函数:
# 输出结果 def query(self, inputlist): inputs = numpy.array(inputlist, ndmin=2).T output_input = numpy.dot(self.wio, inputs) final_output = self.activation_function(output_input) return final_output pass
pass
就是简单的正向传播的数据,最后进行输出
OK,基本函数编写完毕,让我们来尝试一下。
test_input = 784 test_out = 10 learning = 0.1 n = perceptron(test_input, test_out, learning) # 读取文件的数据 training_data_file = open("data\感知机\mnist_train_100.csv", 'r') training_data_list = training_data_file.readlines() training_data_file.close() for record in training_data_list: all_value = record.split(',') inputs = (numpy.asfarray(all_value[1:])/255.0*0.99)+0.01 targets = numpy.zeros(test_out)+0.01 targets[int(all_value[0])] = 0.99 n.training(inputs, targets) pass"""训练完成""" # 开始测试数据 test_data_file = open("data\感知机\mnist_test_10.csv", 'r') test_data_list = test_data_file.readlines() test_data_file.close() test_score = 0 for record in test_data_list: all_value = record.split(',') correct_answer = all_value[0] inputs = (numpy.asfarray(all_value[1:])/255.0*0.99)+0.01 outputs = n.query(inputs) answer = numpy.argmax(outputs) # 计分器 if int(correct_answer) == int(answer): test_score += 1 else: test_score += 0 passpassprint(test_score)
最后粘贴一下结果:
哈哈,及格了,多尝试几次发现一直在及格线下徘徊,简单的想一下也明白,只有一百组训练数据,以及10组的测试数据,没有办法反应真实的情况,如果大家感兴趣可以自己寻找完整的数据集,应该可以在60%左右徘徊。
当然,这只是一次简单的尝试,下一次我将会编写一个简单的三层神经网络,正式的开始神经网络之旅。
有兴趣的同学可以复制试一试,也可以模仿着自己编写,自己编写以后还是很有成就感的。
- 手动编写LinkedList类
- Struts2校验的两种实现方式(使用内置校验和手动编写)
- mysql数据库连接池 手动编写
- qtday01 ubuntu 下手动编写第一个qt程序
- windowAPI--手动编写一个消息窗口
- 手动编写以DLL为载体的COM
- 夺命雷公狗---PHP开发APP接口---1(手动编写json)
- 手动编写bat,启动selenium server
- 手动编写 Makefile文件
- 编写一个脚本,对至少三个以上记事本窗口做相同操作,对任意一个窗口进行手动操作,其余窗口由脚本执行相同步骤的键鼠操作,记得是键盘操作+鼠标操作。
- [Cocoa]深入浅出Cocoa之Core Data(2)- 手动编写代码
- Android手动编写ButterKnife编译时注解框架
- PHP pathinfo 不支持中文 手动编写解析路径字符串函数
- 手动编写第一个javaWEB文件
- 夺命雷公狗---PHP开发APP接口---2(手动编写XML)
- Servlet学习日记(一)——什么是Servlet及手动编写一个简单的servlet
- 不引用服务而使用WCF,手动编写客户端代理类
- 手动编写以DLL为载体的COM
- 利用Editplus,手动编写第一个Servlet
- 手动编写部署第一个servlet