从零开始训练神经网络

您所在的位置:网站首页 epochs是训练次数吗 从零开始训练神经网络

从零开始训练神经网络

2023-07-09 12:46| 来源: 网络整理| 查看: 265

用Keras实现一个简单神经网络

Keras: Keras是由纯python编写的基于theano/tensorflow的深度学习框架。 Keras是一个高层神经网络API,支持快速实验,能够把你的idea迅速转换为结果,如果有如下需 求,可以优先选择Keras: a)简易和快速的原型设计(keras具有高度模块化,极简,和可扩充特性) b)支持CNN和RNN,或二者的结合 c)无缝CPU和GPU切换

[1] ''' 将训练数据和检测数据加载到内存中(第一次运行需要下载数据,会比较慢): train_images是用于训练系统的手写数字图片; train_labels是用于标注图片的信息; test_images是用于检测系统训练效果的图片; test_labels是test_images图片对应的数字标签。 ''' from tensorflow.keras.datasets import mnist (train_images, train_labels), (test_images, test_labels) = mnist.load_data() print('train_images.shape = ',train_images.shape) print('tran_labels = ', train_labels) print('test_images.shape = ', test_images.shape) print('test_labels', test_labels) ''' 1.train_images.shape打印结果表明,train_images是一个含有60000个元素的数组. 数组中的元素是一个二维数组,二维数组的行和列都是28. 也就是说,一个数字图片的大小是28*28. 2.train_lables打印结果表明,第一张手写数字图片的内容是数字5,第二种图片是数字0,以此类推. 3.test_images.shape的打印结果表示,用于检验训练效果的图片有10000张。 4.test_labels输出结果表明,用于检测的第一张图片内容是数字7,第二张是数字2,依次类推。 ''' [2] ''' 把用于测试的第一张图片打印出来看看 ''' digit = test_images[0] import matplotlib.pyplot as plt plt.imshow(digit, cmap=plt.cm.binary) plt.show() [3] ''' 使用tensorflow.Keras搭建一个有效识别图案的神经网络, 1.layers:表示神经网络中的一个数据处理层。(dense:全连接层) 2.models.Sequential():表示把每一个数据处理层串联起来. 3.layers.Dense(…):构造一个数据处理层。 4.input_shape(28*28,):表示当前处理层接收的数据格式必须是长和宽都是28的二维数组, 后面的“,“表示数组里面的每一个元素到底包含多少个数字都没有关系. ''' from tensorflow.keras import models from tensorflow.keras import layers network = models.Sequential() network.add(layers.Dense(512, activation='relu', input_shape=(28*28,))) network.add(layers.Dense(10, activation='softmax')) network.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy']) [4] ''' 在把数据输入到网络模型之前,把数据做归一化处理: 1.reshape(60000, 28*28):train_images数组原来含有60000个元素,每个元素是一个28行,28列的二维数组, 现在把每个二维数组转变为一个含有28*28个元素的一维数组. 2.由于数字图案是一个灰度图,图片中每个像素点值的大小范围在0到255之间. 3.train_images.astype(“float32”)/255 把每个像素点的值从范围0-255转变为范围在0-1之间的浮点值。 ''' train_images = train_images.reshape((60000, 28*28)) train_images = train_images.astype('float32') / 255 test_images = test_images.reshape((10000, 28*28)) test_images = test_images.astype('float32') / 255 ''' 把图片对应的标记也做一个更改: 目前所有图片的数字图案对应的是0到9。 例如test_images[0]对应的是数字7的手写图案,那么其对应的标记test_labels[0]的值就是7。 我们需要把数值7变成一个含有10个元素的数组,然后在第8个元素设置为1,其他元素设置为0。 例如test_lables[0] 的值由7转变为数组[0,0,0,0,0,0,0,1,0,0] ---one hot ''' from tensorflow.keras.utils import to_categorical print("before change:" ,test_labels[0]) train_labels = to_categorical(train_labels) test_labels = to_categorical(test_labels) print("after change: ", test_labels[0]) [5] ''' 把数据输入网络进行训练: train_images:用于训练的手写数字图片; train_labels:对应的是图片的标记; batch_size:每次网络从输入的图片数组中随机选取128个作为一组进行计算。 epochs:每次计算的循环是五次 ''' network.fit(train_images, train_labels, epochs=5, batch_size = 128) [6] ''' 测试数据输入,检验网络学习后的图片识别效果. 识别效果与硬件有关(CPU/GPU). ''' test_loss, test_acc = network.evaluate(test_images, test_labels, verbose=1) print(test_loss) print('test_acc', test_acc) [7] ''' 输入一张手写数字图片到网络中,看看它的识别效果 ''' (train_images, train_labels), (test_images, test_labels) = mnist.load_data() digit = test_images[1] plt.imshow(digit, cmap=plt.cm.binary) plt.show() test_images = test_images.reshape((10000, 28*28)) res = network.predict(test_images) for i in range(res[1].shape[0]): if (res[1][i] == 1): print("the number for the picture is : ", i) break 从零开始训练神经网络

网络的最终目标是,输入一张手写数字图片后,网络输出该图片对应的数字。 我们的代码要导出三个接口,分别完成以下功能:

初始化initialisation,设置输入层,中间层,和输出层的节点数。训练train:根据训练数据不断的更新权重值查询query,把新的数据输入给神经网络,网络计算后输出答案。(推理) # NeuralNetWork_init.py [1] ''' 我们先给出如下代码框架: ''' class NeuralNetWork: def __init__(self): #初始化网络,设置输入层,中间层,和输出层节点数 pass def train(self): #根据输入的训练数据更新节点链路权重 pass def query(self): #根据输入数据计算并输出答案 pass [2] ''' 我们先完成初始化函数,我们需要在这里设置输入层,中间层和输出层的节点数,这样就能决定网络的形状和大小。 当然我们不能把这些设置都写死,而是根据输入参数来动态设置网络的形态。 由此我们把初始化函数修正如下: ''' class NeuralNetWork: def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate): #初始化网络,设置输入层,中间层,和输出层节点数 self.inodes = inputnodes self.hnodes = hiddennodes self.onodes = outputnodes #设置学习率 self.lr = learningrate # pass def train(self): #根据输入的训练数据更新节点链路权重 pass def query(self): #根据输入数据计算并输出答案 pass [3] ''' 此处举例说明: 如此我们就可以初始化一个3层网络,输入层,中间层和输出层都有3个节点 ''' input_nodes = 3 hidden_nodes = 3 output_nodes = 3 learning_rate = 0.3 n = NeuralNetWork(input_nodes, hidden_nodes, output_nodes, learning_rate) [4] ''' 初始化权重矩阵。 由于权重不一定都是正的,它完全可以是负数,因此我们在初始化时,把所有权重初始化为-0.5到0.5之间 ''' def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate): #初始化网络,设置输入层,中间层,和输出层节点数 self.inodes = inputnodes self.hnodes = hiddennodes self.onodes = outputnodes #设置学习率 self.lr = learningrate ''' 初始化权重矩阵,我们有两个权重矩阵,一个是wih表示输入层和中间层节点间链路权重形成的矩阵 一个是who,表示中间层和输出层间链路权重形成的矩阵 ''' self.wih = numpy.random.rand(self.hnodes, self.inodes) - 0.5 self.who = numpy.random.rand(self.onodes, self.hnodes) - 0.5 pass [5] ''' 接着我们先看query函数的实现,它接收输入数据,通过神经网络的层层计算后,在输出层输出最终结果。 输入数据要依次经过输入层,中间层,和输出层,并且在每层的节点中还得执行激活函数以便形成对下一层节点的输出信号。 我们知道可以通过矩阵运算把这一系列复杂的运算流程给统一起来。 ''' import numpy def query(self, inputs): #根据输入数据计算并输出答案 hidden_inputs = numpy.dot(self.wih, inputs) pass [6] ''' hidden是个一维向量,每个元素对应着中间层某个节点从上一层神经元传过来后的信号量总和. 于是每个节点就得执行激活函数,得到的结果将作为信号输出到下一层. sigmod函数在Python中可以直接调用,我们要做的就是准备好参数。 我们先把这个函数在初始化函数中设定好, ''' import scipy.special class NeuralNetWork: def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate): #初始化网络,设置输入层,中间层,和输出层节点数 self.inodes = inputnodes self.hnodes = hiddennodes self.onodes = outputnodes #设置学习率 self.lr = learningrate ''' 初始化权重矩阵,我们有两个权重矩阵,一个是wih表示输入层和中间层节点间链路权重形成的矩阵 一个是who,表示中间层和输出层间链路权重形成的矩阵 ''' self.wih = numpy.random.rand(self.hnodes, self.inodes) - 0.5 self.who = numpy.random.rand(self.onodes, self.inodes) - 0.5 ''' scipy.special.expit对应的是sigmod函数. lambda是Python关键字,类似C语言中的宏定义. 我们调用self.activation_function(x)时,编译器会把其转换为spicy.special_expit(x)。 ''' self.activation_function = lambda x:scipy.special.expit(x) pass ''' 由此我们就可以分别调用激活函数计算中间层的输出信号,以及输出层经过激活函数后形成的输出信号, ''' def query(self, inputs): #根据输入数据计算并输出答案 #计算中间层从输入层接收到的信号量 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) print(final_outputs) return final_outputs

可运行代码

import scipy.special import numpy class NeuralNetWork: def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate): #初始化网络,设置输入层,中间层,和输出层节点数 self.inodes = inputnodes self.hnodes = hiddennodes self.onodes = outputnodes #设置学习率 self.lr = learningrate ''' 初始化权重矩阵,我们有两个权重矩阵,一个是wih表示输入层和中间层节点间链路权重形成的矩阵 一个是who,表示中间层和输出层间链路权重形成的矩阵 ''' self.wih = numpy.random.rand(self.hnodes, self.inodes) - 0.5 self.who = numpy.random.rand(self.onodes, self.hnodes) - 0.5 ''' scipy.special.expit对应的是sigmod函数. lambda是Python关键字,类似C语言中的宏定义,当我们调用self.activation_function(x)时,编译器会把其转换为spicy.special_expit(x)。 ''' self.activation_function = lambda x:scipy.special.expit(x) pass def train(self): #根据输入的训练数据更新节点链路权重 pass def query(self, inputs): #根据输入数据计算并输出答案 #计算中间层从输入层接收到的信号量 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) print(final_outputs) return final_outputs ''' 我们尝试传入一些数据,让神经网络输出结果试试. 程序当前运行结果并没有太大意义,但是至少表明,我们到目前为止写下的代码没有太大问题, ''' input_nodes = 3 hidden_nodes = 3 output_nodes = 3 learning_rate = 0.3 n = NeuralNetWork(input_nodes, hidden_nodes, output_nodes, learning_rate) n.query([1.0, 0.5, -1.5])

实现网络训练功能 自我训练过程分两步:

第一步是计算输入训练数据,给出网络的计算结果,这点跟我们前面实现的query()功能很像。第二步是将计算结果与正确结果相比对,获取误差,采用误差反向传播法更新网络里的每条 链路权重。

获取训练数据及预处理 接下来我们就得拿实际数据来训练我们的神经网络了。 我们要做的是读取训练数据,以及数据的预处理(归一化)

启动网络,进行训练 网络的最终目标是,输入一张手写数字图片后,网络输出该图片对应的数字。 由于网络需要从0到9一共十个数字中挑选出一个,于是我们的网络最终输出层应该有十个节点,每 个节点对应一个数字。

假设图片对应的是数字0,那么输出层网络中,第一个节点应该输出一个高百分比,其他节点输出低 百分比,如果图片对应的数字是9,那么输出层最后一个节点应该输出高百分比,其他节点输出低百 分比。

[1] ''' 训练过程分两步: 第一步是计算输入训练数据,给出网络的计算结果,这点跟我们前面实现的query()功能很像。 第二步是将计算结果与正确结果相比对,获取误差,采用误差反向传播法更新网络里的每条链路权重。 我们先用代码完成第一步. inputs_list:输入的训练数据; targets_list:训练数据对应的正确结果。 ''' def train(self, inputs_list, targets_list): #根据输入的训练数据更新节点链路权重 ''' 把inputs_list, targets_list转换成numpy支持的二维矩阵 .T表示做矩阵的转置 ''' inputs = numpy.array(inputs_list, ndmin=2).T targets = numpy.array(targets_list, nmin=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) [2] ''' 上面代码根据输入数据计算出结果后,我们先要获得计算误差. 误差就是用正确结果减去网络的计算结果。 在代码中对应的就是(targets - final_outputs). ''' def train(self, inputs_list, targets_list): #根据输入的训练数据更新节点链路权重 ''' 把inputs_list, targets_list转换成numpy支持的二维矩阵 .T表示做矩阵的转置 ''' inputs = numpy.array(inputs_list, ndmin=2).T targets = numpy.array(targets_list, nmin=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*final_outputs*(1-final_outputs)) #根据误差计算链路权重的更新量,然后把更新加到原来链路权重上 self.who += self.lr * numpy.dot((output_errors * final_outputs *(1 - final_outputs)), numpy.transpose(hidden_outputs)) self.wih += self.lr * numpy.dot((hidden_errors * hidden_outputs * (1 - hidden_outputs)), numpy.transpose(inputs)) pass [3] ''' 使用实际数据来训练我们的神经网络 ''' #open函数里的路径根据数据存储的路径来设定 data_file = open("dataset/mnist_test.csv") data_list = data_file.readlines() data_file.close() len(data_list) data_list[0] ''' 这里我们可以利用画图.py将输入绘制出来 ''' [4] ''' 从绘制的结果看,数据代表的确实是一个黑白图片的手写数字。 数据读取完毕后,我们再对数据格式做些调整,以便输入到神经网络中进行分析。 我们需要做的是将数据“归一化”,也就是把所有数值全部转换到0.01到1.0之间。 由于表示图片的二维数组中,每个数大小不超过255,由此我们只要把所有数组除以255,就能让数据全部落入到0和1之间。 有些数值很小,除以255后会变为0,这样会导致链路权重更新出问题。 所以我们需要把除以255后的结果先乘以0.99,然后再加上0.01,这样所有数据就处于0.01到1之间。 ''' scaled_input = image_array / 255.0 * 0.99 + 0.01 import numpy import matplotlib.pyplot as plt [1] #open函数里的路径根据数据存储的路径来设定 data_file = open("dataset/mnist_test.csv") data_list = data_file.readlines() data_file.close() print(len(data_list)) print(data_list[0]) #把数据依靠','区分,并分别读入 all_values = data_list[0].split(',') #第一个值对应的是图片的表示的数字,所以我们读取图片数据时要去掉第一个数值 image_array = numpy.asfarray(all_values[1:]).reshape((28, 28)) #最外层有10个输出节点 onodes = 10 targets = numpy.zeros(onodes) + 0.01 targets[int(all_values[0])] = 0.99 print(targets) #targets第8个元素的值是0.99,这表示图片对应的数字是7(数组是从编号0开始的). [2] ''' 根据上述做法,我们就能把输入图片给对应的正确数字建立联系,这种联系就可以用于输入到网络中,进行训练。 由于一张图片总共有28*28 = 784个数值,因此我们需要让网络的输入层具备784个输入节点。 这里需要注意的是,中间层的节点我们选择了100个神经元,这个选择是经验值。 中间层的节点数没有专门的办法去规定,其数量会根据不同的问题而变化。 确定中间层神经元节点数最好的办法是实验,不停的选取各种数量,看看那种数量能使得网络的表现最好。 ''' #初始化网络 input_nodes = 784 hidden_nodes = 100 output_nodes = 10 learning_rate = 0.3 n = NeuralNetWork(input_nodes, hidden_nodes, output_nodes, learning_rate) #读入训练数据 #open函数里的路径根据数据存储的路径来设定 training_data_file = open("dataset/mnist_train.csv") trainning_data_list = training_data_file.readlines() training_data_file.close() #把数据依靠','区分,并分别读入 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(output_nodes) + 0.01 targets[int(all_values[0])] = 0.99 n.train(inputs, targets) [3] ''' 最后我们把所有测试图片都输入网络,看看它检测的效果如何 ''' scores = [] for record in test_data_list: all_values = record.split(',') correct_number = int(all_values[0]) print("该图片对应的数字为:",correct_number) #预处理数字图片 inputs = (numpy.asfarray(all_values[1:])) / 255.0 * 0.99 + 0.01 #让网络判断图片对应的数字,推理 outputs = n.query(inputs) #找到数值最大的神经元对应的 编号 label = numpy.argmax(outputs) print("output reslut is : ", label) #print("网络认为图片的数字是:", label) if label == correct_number: scores.append(1) else: scores.append(0) print(scores) #计算图片判断的成功率 scores_array = numpy.asarray(scores) print("perfermance = ", scores_array.sum() / scores_array.size) [4] ''' 在原来网络训练的基础上再加上一层外循环 但是对于普通电脑而言执行的时间会很长。 epochs 的数值越大,网络被训练的就越精准,但如果超过一个阈值,网络就会引发一个过拟合的问题. ''' #加入epocs,设定网络的训练循环次数 epochs = 10 for e in range(epochs): #把数据依靠','区分,并分别读入 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(output_nodes) + 0.01 targets[int(all_values[0])] = 0.99 n.train(inputs, targets) 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 ''' 初始化权重矩阵,我们有两个权重矩阵,一个是wih表示输入层和中间层节点间链路权重形成的矩阵 一个是who,表示中间层和输出层间链路权重形成的矩阵 ''' # self.wih = numpy.random.rand(self.hnodes, self.inodes) - 0.5 # self.who = numpy.random.rand(self.onodes, self.hnodes) - 0.5 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))) ''' 每个节点执行激活函数,得到的结果将作为信号输出到下一层,我们用sigmoid作为激活函数 ''' self.activation_function = lambda x: scipy.special.expit(x) pass def train(self, inputs_list, targets_list): # 根据输入的训练数据更新节点链路权重 ''' 把inputs_list, targets_list转换成numpy支持的二维矩阵 .T表示做矩阵的转置 ''' 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*final_outputs*(1-final_outputs)) # 根据误差计算链路权重的更新量,然后把更新加到原来链路权重上 self.who += self.lr * numpy.dot((output_errors * final_outputs * (1 - final_outputs)), numpy.transpose(hidden_outputs)) self.wih += self.lr * numpy.dot((hidden_errors * hidden_outputs * (1 - hidden_outputs)), numpy.transpose(inputs)) pass def query(self, inputs): # 根据输入数据计算并输出答案 # 计算中间层从输入层接收到的信号量 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) print(final_outputs) return final_outputs # 初始化网络 ''' 由于一张图片总共有28*28 = 784个数值,因此我们需要让网络的输入层具备784个输入节点 ''' input_nodes = 784 hidden_nodes = 200 output_nodes = 10 learning_rate = 0.1 n = NeuralNetWork(input_nodes, hidden_nodes, output_nodes, learning_rate) # 读入训练数据 # open函数里的路径根据数据存储的路径来设定 training_data_file = open("dataset/mnist_train.csv", 'r') training_data_list = training_data_file.readlines() training_data_file.close() # 加入epocs,设定网络的训练循环次数 epochs = 5 for e in range(epochs): # 把数据依靠','区分,并分别读入 for record in training_data_list: all_values = record.split(',') inputs = (numpy.asfarray(all_values[1:]))/255.0 * 0.99 + 0.01 # 设置图片与数值的对应关系 targets = numpy.zeros(output_nodes) + 0.01 targets[int(all_values[0])] = 0.99 n.train(inputs, targets) test_data_file = open("dataset/mnist_test.csv") test_data_list = test_data_file.readlines() test_data_file.close() scores = [] for record in test_data_list: all_values = record.split(',') correct_number = int(all_values[0]) print("该图片对应的数字为:", correct_number) # 预处理数字图片 inputs = (numpy.asfarray(all_values[1:])) / 255.0 * 0.99 + 0.01 # 让网络判断图片对应的数字 outputs = n.query(inputs) # 找到数值最大的神经元对应的编号 label = numpy.argmax(outputs) print("网络认为图片的数字是:", label) if label == correct_number: scores.append(1) else: scores.append(0) print(scores) # 计算图片判断的成功率 scores_array = numpy.asarray(scores) print("perfermance = ", scores_array.sum() / scores_array.size)


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3