学习Make your own neural network 记录(二)
通过前面的理论学习,以及关于Error和weight的关系分析,得出的公式,练习做一个自己的三层神经网络,based on Python3.5:
跟随书上的python introduction,介绍下numpy中的zeros():
import numpy a = numpy.zeros([3,2]) a[0,0] = 1 a[1,1] = 2 a[2,1] = 5 print(a)
结果是:
[[1. 0.]
[0. 2.]
[0. 5.]]
可以用这个方法来生成矩阵。
接下来用python搭建神经网络的骨骼:
搭建一下基本的模型:
import numpy class neuralNetwork: def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate): self.inodes = inputnodes self.hnodes = hiddennodes self.onodes = outputnodes self.lr = learningrate # generate the link weights between the range of -1 to +1 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)) pass def train(self): pass def query(self): pass #Test input_nodes = 3 hidden_nodes = 3 output_nodes = 3 learning_rate = 0.5 # create instance of neural network n = neuralNetwork(input_nodes, hidden_nodes, output_nodes, learning_rate)
cunstructor里面有开始节点,hidden节点,以及output节点,包括learning rate.
各个link weight使用numpy随机数的形式,初始化生成一系列的weight然后再通过training data 去寻找error,进行反向modify
接下来,我们来完成各个functions:
首先来完成query()方法,这个方法需要传入一个参数,也就是一个input_arrayList, 也就是input layer的值,然后通过hidden layer,和output layer,最终得出output,所以在这个过程中,包含了weight的矩阵相乘,以及sidmond方法,去计算hidden layer的output,以及output layer的output,先上代码:
#takes input to a neural network and returns the network's output #输入input,return output def query(self, inputs_list): # Convert input list to 2d array 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
这里面包含了很多数学计算的方法,比如先把传入的数组转化为二维数组,numpy.dot方法计算了weight矩阵和input的值; 而self.activation_function(hidden_inputs)是我们通过函数式编程定义的function,代码如下:
self.activation_function = lambda x: scipy.special.expit(x)
把这个方法放在constructor里,在实例化对象的时候一同加载, 同时回忆下,在java的lambda表达式中,调用的接口必须是带有注解@functional Interface的,也就是一个接口中只有一个唯一的方法,才可以调用lambda。
在实现train()方法之前,先测试一下query()方法,输入一个array,打印出随机的结果:
Okay,没有问题, 接下来继续实现train()方法,有两步需要完成:
首先完成第一步,比较简单,只是比query方法多了一个target_list参数,代码如下:
# backpropagating result to modify weight # 通过output来反向修正weight的值,需要用到之前推倒的公式 # targets_list is the real effective data, which used to compare with training outputs 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)
接下来第二部,要把之前推倒的公式,用python表现出来,很幸运numpy有太多强大的功能了,把tutorial的作者源码贴出来,以便有一个良好的对比:
对应的颜色 对应的一块儿代码对应的函数.
然后接着完成hidden layer到input layer的反向modify
Boom! Three-layer nerual network has been accomplished!
这段代码可以作为基于三层神经网络几乎任何的人工智能机器学习模板。
下一章,跟随者Tutorial的作者,尝试着用这个模板来做 字符识别。
全部代码如下:
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 # generate the link weights between the range of -1 to +1 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.activation_function = lambda x: scipy.special.expit(x) pass # backpropagating result to modify weight # 通过output来反向修正weight的值,需要用到之前推倒的公式 # targets_list is the real effective data, which used to compare with training outputs 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) # 反向推倒,去modify weight的矩阵 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)) pass #takes input to a neural network and returns the network's output #输入input,return output def query(self, inputs_list): # Convert input list to 2d array 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 # Test if __name__ == '__main__': input_nodes = 3 hidden_nodes = 3 output_nodes = 3 learning_rate = 0.5 # create instance of neural network n = neuralNetwork(input_nodes, hidden_nodes, output_nodes, learning_rate) print(n.query([1.0,0.5,-1.5]))