Python利用全连接神经网络求解MNIST问题详解

本文实例讲述了Python利用全连接神经网络求解MNIST问题。分享给大家供大家参考,具体如下:

1、单隐藏层神经网络

人类的神经元在树突接受刺激信息后,经过细胞体处理,判断如果达到阈值,则将信息传递给下一个神经元或输出。类似地,神经元模型在输入层输入特征值x之后,与权重w相乘求和再加上b,经过激活函数判断后传递给下一层隐藏层或输出层。

单神经元的模型只有一个求和节点(如左下图所示)。全连接神经网络(Full Connected Networks)如右下图所示,中间层有多个神经元,并且每层的每个神经元都是与上一层和下一层的节点都对应连接。中间隐藏层只有一层的神经元网络称为单隐藏层神经网络。如果有多个中间隐藏层则称为多隐藏层神经网络。

          

常见的激活函数如下所示:

下面是在单个神经元逻辑回归求解MNIST手写数字识别问题的基础上,采用单隐藏层神经网络进行求解的过程。

首先载入数据,从Tensor FLow提供的数据库中导入MNIST数据

import tensorflow as tf
import tensorflow.examples.tutorials.mnist.input_data as input_data
mnist=input_data.read_data_sets('MNIST_data/',one_hot=True)

构建输入层,其中x是图像的特征值,由于是28×28=784个像素点,所有输入为未知行数、每行784的二维数组。y是图像的标签值,共有0~9十种可能,所有为[None,10]的二维数组

x=tf.placeholder(tf.float32,[None,784],name='x')
y=tf.placeholder(tf.float32,[None,10],name='y')

构建隐藏层,设置隐藏层神经元个数为256,由于输入层输入为784,而隐藏层神经元为h1_num,所以W1为[784,h1_num]形式的二维数组,b为[h1_num]的一维向量。此外采用ReLU作为激活函数处理输出。

h1_num=256                        #设置隐藏层神经元数量
W1=tf.Variable(tf.random_normal([784,h1_num]),name='W1')
b1=tf.Variable(tf.zeros([h1_num]),name='b1')
Y1=tf.nn.relu(tf.matmul(x,W1)+b1)             #激活函数

构建输出层,由于隐藏层有h1_num个神经元输出,输出层输出10种输出结果,所以W2为[h1_num,10]的二维数组,b2为[10]的一维向量。最后结果通过softmax将线性输出Y2转化为独热编码方式。

W2=tf.Variable(tf.random_normal([h1_num,10]),name='W2')
b2=tf.Variable(tf.zeros([10]),name='b2')
Y2=tf.matmul(Y1,W2)+b2
pred=tf.nn.softmax(Y2)

设置训练的超参数、损失函数、优化器,这里采用Adam Optimizer进行优化。准确率是通过比较预测值和标签值是否一致来定义。在定义损失函数时,如果直接使用交叉熵的方式定义,会出现log0值为NaN的情况,导致数据不稳定,无法得出结果。Tensor Flow提供了结合softmax定义交叉熵的方式softmax_cross_entropy_with_logits(),第一个参数为不经softmax处理的前向计算结果Y2,第二个参数为标签值y

train_epochs=20                    #训练轮数
batch_size=50                     #每个批次的样本数
batch_num=int(mnist.train.num_examples/batch_size)  #一轮需要训练多少批
learning_rate=0.01
#定义损失函数、优化器
loss_function=tf.reduce_mean(             #softmax交叉熵损失函数
       tf.nn.softmax_cross_entropy_with_logits(logits=Y2,labels=y))
optimizer=tf.train.AdamOptimizer(learning_rate).minimize(loss_function)
#定义准确率
correct_prediction=tf.equal(tf.argmax(pred,1),tf.argmax(y,1))
accuracy=tf.reduce_mean(tf.cast(correct_prediction,tf.float32))

进行训练并输出损失值与准确率,训练进行多轮,每轮一开始分批次读入数据进行训练,每结束一轮输出一次损失和准确率。

ss=tf.Session()
ss.run(tf.global_variables_initializer())           #进行全部变量的初始化

for epoch in range(train_epochs):
  for batch in range(batch_num):              #分批次读取数据进行训练
    xs,ys=mnist.train.next_batch(batch_size)
    ss.run(optimizer,feed_dict={x:xs,y:ys})
  loss,acc=ss.run([loss_function,accuracy],\
          feed_dict={x:mnist.validation.images,y:mnist.validation.labels})
  print('第%2d轮训练:损失为:%9f,准确率:%.4f'%(epoch+1,loss,acc))

ss.close()

运行结果如下图,与单个神经元相比,可以较快得到较高的准确率

评估模型,将测试集数据填充入占位符x,y去求准确率,

test_res=ss.run(accuracy,feed_dict={x:mnist.test.images,y:mnist.test.labels})
print('测试集的准确率为:%.4f'%(test_res))

2、多层神经网络

多层是指中间的隐藏层有多个,例如使用两层隐藏层,第一个隐藏层在计算后将结果输出到第二个隐藏层,再由第二个隐藏层计算后交给输出层,而第二个隐藏层的设置与第一个基本相同,例如:

#构建输入层
x=tf.placeholder(tf.float32,[None,784],name='x')
y=tf.placeholder(tf.float32,[None,10],name='y')
#构建第一个隐藏层
h1_num=256                            #第一隐藏层神经元数量256
W1=tf.Variable(tf.truncated_normal([784,h1_num],stddev=0.1),name='W1')
b1=tf.Variable(tf.zeros([h1_num]),name='b1')
Y1=tf.nn.relu(tf.matmul(x,W1)+b1)
#构建第二个隐藏层
h2_num=64                             #第二隐藏层神经元数量64
W2=tf.Variable(tf.random_normal([h1_num,h2_num],stddev=0.1),name='W2')
b2=tf.Variable(tf.zeros([h2_num]),name='b2')
Y2=tf.nn.relu(tf.matmul(Y1,W2)+b2)
#构建输出层
W3=tf.Variable(tf.random_normal([h2_num,10],stddev=0.1),name='W3')
b3=tf.Variable(tf.zeros([10]),name='b3')
Y3=tf.matmul(Y2,W3)+b3
pred=tf.nn.softmax(Y3)

在第一隐藏层产生参数W1时采用的是截断正态分布的随机函数tf.truncated_normal(),与普通正太分布相比,截断正态分布生成的值之间的差距不会太大。

设置的第一隐藏层的神经元256个,第二层64个,因此第二层的每个输入有256个特征值,并产生64个输出,相应的W2的shape为[h1_num,h2_num],b2的shape为[h2_num]。输出层W3的shape为[h2_num,10]。函数的其他部分与单层神经网络相同。

经过运算多层的神经网络训练的准确率不一定比单层的高,因为还涉及到训练的超参数的设置等多种因素。但是多层神经网络的运行速度比单层慢,越多层的神经网络意味着更加复杂的计算量。

全连接层函数

通过以上多层神经网络的定义可以看出两个隐藏层与输出层的构建方法基本类似,都是定义对应的变量W、b,在定义W时其shape为[输出维度,输出维度],因此可以将隐藏层与输出层统一定义为一个全连接层函数:

#定义一个通用的全连接层函数模型
def fcn_layer(inputs,in_dim,out_dim,activation=None):
  W=tf.Variable(tf.truncated_normal([in_dim,out_dim],stddev=0.1))
  b=tf.Variable(tf.zeros([out_dim]))
  Y=tf.matmul(inputs,W)+b
  if activation==None:
    output=Y
  else:
    output=activation(Y)
  return output
#构建第一个隐藏层
Y1=fcn_layer(x,784,256,tf.nn.relu)
#构建第二个隐藏层
Y2=fcn_layer(Y1,256,64,tf.nn.relu)
#构建输出层
Y3=fcn_layer(Y2,64,10)
pred=tf.nn.softmax(Y3)

其中inputs为本层的输入,in_dim为本层的输入维度,也就是上一层的输出维度,out_dim为本层的输出维度,activation为激活函数,默认为None。将输入与权重W叉乘再加上偏置值b得到Y,如果定义了激活函数,用激活函数处理Y,否则直接将Y赋给output输出。

3、模型的保存与读取

在模型训练结束后,如果希望下次继续使用或训练模型则需要将储存起来。

模型的储存

首先需要定义模型数据的保存路径:

import os
save_dir='D:/Temp/MachineLearning/ModelSaving/'    #定义模型的保存路径
if not os.path.exists(save_dir):            #如果不存在该路径则创建
  os.makedirs(save_dir)

定义储存粒度与saver,所谓储存粒度即每个几轮数据进行一次储存

save_step=5            #定义存储粒度

saver=tf.train.Saver()      #定义saver

在每轮训练结束后进行判断,每隔5轮储存一次,储存路径中拼接轮数信息,

if epoch%save_step==0:
    saver.save(ss,os.path.join(save_dir,'mnist_fcn_{:02d}.ckpt'.format(epoch+1)))

在所有迭代训练执行结束后,再整体储存一次

saver.save(ss,os.path.join(save_dir,'mnist_fcn.ckpt'))

这样就会在指定目录下生成模型的保存文件:

模型的读取

从定义的模型目录中读取存盘点数据,并将其中的参数赋值给当前的session,然后便可以直接利用session进行测试,其准确率与保存时一致。

save_dir='D:/Temp/MachineLearning/ModelSaving/'    #定义模型的保存路径
saver=tf.train.Saver()                 #定义saver

ss=tf.Session()
ss.run(tf.global_variables_initializer())

ckpt=tf.train.get_checkpoint_state(save_dir)      #读取存盘点
if ckpt and ckpt.model_checkpoint_path:
  saver.restore(ss,ckpt.model_checkpoint_path)    #从存盘中恢复参数到当前的session
  print('数据恢复从',ckpt.model_checkpoint_path)

test_res=accuracy.eval(session=ss,feed_dict={x:mnist.test.images,y:mnist.test.labels})
print('测试集的准确率为:%.4f'%(test_res))

在读取模型时有时候会遇到报错:

NotFoundError (see above for traceback): Restoring from checkpoint failed. This is most likely due to a Variable name or other graph key that is missing from the checkpoint. Please ensure that you have not altered the graph expected based on the checkpoint.

这时只需重启kernel即可。

通过图来保存模型

也可以将训练好的模型以图的形式保存为.pb文件,下次直接可以使用,但不可以继续训练。

通过tf.train.write_graph函数来保存模型如下:

import tensorflow as tf

v=tf.Variable(1.0,'new_var')
with tf.Session() as ss:
  tf.train.write_graph(ss.graph_def,'D:\Temp\MachineLearning\ModelSaving\Graph',
            'test_graph.pb',as_text=False)

读取图文件并还原:

with tf.Session() as ss:
  with tf.gfile.GFile('D:/Temp\MachineLearning/ModelSaving/Graph/test_graph.pb','rb') as pb_file:
    graph_def=tf.GraphDef()
    graph_def.ParseFromString(pb_file.read())
    ss.graph.as_default()
    tf.import_graph_def(graph_def)
    print(graph_def)

更多关于Python相关内容感兴趣的读者可查看本站专题:《Python数据结构与算法教程》、《Python加密解密算法与技巧总结》、《Python编码操作技巧总结》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》及《Python入门与进阶经典教程》

希望本文所述对大家Python程序设计有所帮助。

(0)

相关推荐

  • Python实现的三层BP神经网络算法示例

    本文实例讲述了Python实现的三层BP神经网络算法.分享给大家供大家参考,具体如下: 这是一个非常漂亮的三层反向传播神经网络的python实现,下一步我准备试着将其修改为多层BP神经网络. 下面是运行演示函数的截图,你会发现预测的结果很惊人! 提示:运行演示函数的时候,可以尝试改变隐藏层的节点数,看节点数增加了,预测的精度会否提升 import math import random import string random.seed(0) # 生成区间[a, b)内的随机数 def rand(

  • 详解python实现识别手写MNIST数字集的程序

    我们需要做的第⼀件事情是获取 MNIST 数据.如果你是⼀个 git ⽤⼾,那么你能够通过克隆这本书的代码仓库获得数据,实现我们的⽹络来分类数字 git clone https://github.com/mnielsen/neural-networks-and-deep-learning.git class Network(object): def __init__(self, sizes): self.num_layers = len(sizes) self.sizes = sizes sel

  • Python利用逻辑回归模型解决MNIST手写数字识别问题详解

    本文实例讲述了Python利用逻辑回归模型解决MNIST手写数字识别问题.分享给大家供大家参考,具体如下: 1.MNIST手写识别问题 MNIST手写数字识别问题:输入黑白的手写阿拉伯数字,通过机器学习判断输入的是几.可以通过TensorFLow下载MNIST手写数据集,通过import引入MNIST数据集并进行读取,会自动从网上下载所需文件. %matplotlib inline import tensorflow as tf import tensorflow.examples.tutori

  • 神经网络(BP)算法Python实现及应用

    本文实例为大家分享了Python实现神经网络算法及应用的具体代码,供大家参考,具体内容如下 首先用Python实现简单地神经网络算法: import numpy as np # 定义tanh函数 def tanh(x): return np.tanh(x) # tanh函数的导数 def tan_deriv(x): return 1.0 - np.tanh(x) * np.tan(x) # sigmoid函数 def logistic(x): return 1 / (1 + np.exp(-x)

  • Python编程实现的简单神经网络算法示例

    本文实例讲述了Python编程实现的简单神经网络算法.分享给大家供大家参考,具体如下: python实现二层神经网络 包括输入层和输出层 # -*- coding:utf-8 -*- #! python2 import numpy as np #sigmoid function def nonlin(x, deriv = False): if(deriv == True): return x*(1-x) return 1/(1+np.exp(-x)) #input dataset x = np.

  • Python tensorflow实现mnist手写数字识别示例【非卷积与卷积实现】

    本文实例讲述了Python tensorflow实现mnist手写数字识别.分享给大家供大家参考,具体如下: 非卷积实现 import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data data_path = 'F:\CNN\data\mnist' mnist_data = input_data.read_data_sets(data_path,one_hot=True) #offline da

  • Python与人工神经网络:使用神经网络识别手写图像介绍

    人体的视觉系统是一个相当神奇的存在,对于下面的一串手写图像,可以毫不费力的识别出他们是504192,轻松到让人都忘记了其实这是一个复杂的工作. 实际上在我们的大脑的左脑和右脑的皮层都有一个第一视觉区域,叫做V1,里面有14亿视觉神经元.而且,在我们识别上面的图像的时候,工作的不止有V1,还有V2.V3.V4.V5,所以这么一看,我们确实威武. 但是让计算机进行模式识别,就比较复杂了,主要困难在于我们如何给计算机描述一个数字9在图像上应该是怎样的,比如我们跟计算机说,9的上面是一个圈,下右边是1竖

  • python构建深度神经网络(DNN)

    本文学习Neural Networks and Deep Learning 在线免费书籍,用python构建神经网络识别手写体的一个总结. 代码主要包括两三部分: 1).数据调用和预处理 2).神经网络类构建和方法建立 3).代码测试文件 1)数据调用: #!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2017-03-12 15:11 # @Author : CC # @File : net_load_data.py # @Soft

  • python MNIST手写识别数据调用API的方法

    MNIST数据集比较小,一般入门机器学习都会采用这个数据集来训练 下载地址:yann.lecun.com/exdb/mnist/ 有4个有用的文件: train-images-idx3-ubyte: training set images train-labels-idx1-ubyte: training set labels t10k-images-idx3-ubyte: test set images t10k-labels-idx1-ubyte: test set labels The t

  • python读取二进制mnist实例详解

    python读取二进制mnist实例详解 training data 数据结构: <br>[offset] [type] [value] [description] 0000 32 bit integer 0x00000803(2051) magic number 0004 32 bit integer 60000 number of images 0008 32 bit integer 28 number of rows 0012 32 bit integer 28 number of co

  • TensorFlow平台下Python实现神经网络

    本篇文章主要通过一个简单的例子来实现神经网络.训练数据是随机产生的模拟数据集,解决二分类问题. 下面我们首先说一下,训练神经网络的一般过程: 1.定义神经网络的结构和前向传播的输出结果 2.定义损失函数以及反向传播优化的算法 3.生成会话(Session)并且在训练数据上反复运行反向传播优化算法 要记住的一点是,无论神经网络的结构如何变化,以上三个步骤是不会改变的. 完整代码如下: import tensorflow as tf #导入TensorFlow工具包并简称为tf from numpy

  • Python实现的递归神经网络简单示例

    本文实例讲述了Python实现的递归神经网络.分享给大家供大家参考,具体如下: # Recurrent Neural Networks import copy, numpy as np np.random.seed(0) # compute sigmoid nonlinearity def sigmoid(x): output = 1/(1+np.exp(-x)) return output # convert output of sigmoid function to its derivati

随机推荐