TensorFlow实现卷积神经网络、深度神经网络识别手写体

(作者:陈玓玏)

分享一个朋友的人工智能教程。零基础!通俗易懂!风趣幽默!还带黄段子!大家可以看看是否对自己有帮助http://www.captainbed.net/luanpeng

因为比较好奇不同神经网络的效果差异,分别使用卷积神经网络、浅层神经网络、深度神经网络来识别手写体,以下给出三种方法的代码:

一、浅层神经网络识别手写体

# -*- coding: utf-8 -*-
"""
Created on Fri Dec 21 09:10:26 2018

@author: chendile
"""
#无论是卷积神经网络还是深度神经网络,构建一个模型无非以下几个步骤:
#1、 定义数据
#2、定义计算图与变量
#3、定义会话
#4、进行计算

# tensorflow建立全连接网络模型预测mnist数据

#==========================构建浅层神经网络的例子================================
import pandas as pd
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data

#加载mnist数据集,我这里数据集直接加载会报错,如果你的也报错,可以直接去网上把压缩文件下载下来放到文件下,然后再读取,也是一样的
mnist = input_data.read_data_sets("D:/Users/chendile/AppData/Local/Temp/pip-uninstall-ktrcfkmd/users/chendile/appdata/local/continuum/anaconda3/lib/site-packages/tensorflow/examples/tutorials/mnist/MNIST_data/",one_hot=True)
#print(pd.DataFrame(mnist))
# 1.定义数据。在神经网络里我们需要定义的数据就是输入训练/测试数据,定义为占位符,以及定义网络模型里的各种参数,定义为变量。
#定义的是输入输出层,输入层有784个节点,输出层有10个节点,因为数字手写体识别是10分类
#placeholder是一个占位符,未定义第一个维度,表示希望输入任意数量的784维的向量
x = tf.placeholder( tf.float32, [None, 784] )
y_ = tf.placeholder( tf.float32, [None, 10] )

# 2.定义计算图与变量。对于神经网络来说,涉及到的操作主要有三部分:网络模型定义,损失函数定义、优化方法定义。
#求得的权重矩阵和偏置向量会存储在这两个Variable中,这里用的是全0的值来初始化权重,深度神经网络中最好是不要这样,会有对称性网络的问题,即最终每个样本输出的结果都一样,这个仔细想一下或者自己拿几个矩阵乘一下就知道了
W = tf.Variable( tf.zeros([784,10]) )  #w为784*10的矩阵,输入层为784个像素点
b = tf.Variable( tf.zeros([10]) )   #输出层有10个神经元,因此输出层有10个偏置项
# 激活函数定义,建立模型,激活函数为softmax的神经网络,就是nn,tf.matmul是x*W,如果是tf.multiply即点乘
y = tf.nn.softmax( tf.matmul(x,W) + b )
# 损失函数定义(交叉熵代价函数),这里是对所有样本的交叉熵和的平均,这里的损失函数和二分类的损失函数是不一样的,少了一项(1-y_)*log(1-y)
cross_entropy = tf.reduce_mean( -tf.reduce_sum(y_*tf.log(y), reduction_indices=[1] ) )  # reduce_sum内第一个参数为交叉熵公式
# 训练/优化方法定义。这里采用的是机器学习中常用的随机梯度下降法。tensorflow会自动根据前面定义的计算图进行forward和backward计算并更新参数。
#这里0.5是学习率,学习的目标是最小化损失函数
train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)

# 3.定义会话,并通过global_variables_initializer初始化所有变量
session = tf.InteractiveSession()
tf.global_variables_initializer().run()

# 4.进行计算。
#共训练1000次,使用mini-batch方法训练,即每一次都不会使用全部数据,而是使用100条打乱后随机抽取的样本,是有放回的抽样,这100条样本替换之前定义的占位符
#采用这种批量随机训练的方法,能够在最大化学习数据集整体特性的同时减小开销
for i in range(1000):
        batch_xs, batch_ys = mnist.train.next_batch(100)
        train_step.run( {x:batch_xs, y_:batch_ys} )
#        print(i)


# 评估模型
correct_prediction = tf.equal( tf.argmax(y,1), tf.argmax(y_,1) )
print(correct_prediction)
#tf.equal( tf.argmax(y,1), tf.argmax(y_,1) )判断预测值和真实值是否相等,返回的是布尔型向量
#布尔型数据构成的向量通过cast转换为浮点型,并求平均,以得到准确率
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32) )
print(accuracy.eval({x:mnist.train.images, y_:mnist.train.labels} ),accuracy.eval({x:mnist.test.images, y_:mnist.test.labels} ))
  • 浅层神经网络的精确度是0.91

二、卷积神经网络识别手写体

#================================构建多层卷积神经网络===================================

import pandas as pd
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data

#以下四个函数是将变量定义和网络定义的步骤抽象出来,提高代码的复用程度
#将权重初始化为非0值,通过设置stddev加入了一定的噪声,避免对称性及0梯度,参数满足截尾高斯分布
def weight_variable(shape):
  initial = tf.truncated_normal(shape, stddev=0.1)
  return tf.Variable(initial)

#定义初始化偏置项的函数,将偏置项初始化为一个较小的正数,避免最终神经元输出恒为0
def bias_variable(shape):
  initial = tf.constant(0.1, shape=shape)
  return tf.Variable(initial)

#定义卷积层,strides定义步长为1,padding定义边距为0,输入图像和输出图像是同样大小的,这一点不确定的时候可以直接打印一层的输出,查看shape
def conv2d(x, W):
  return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')

#池化层采用2*2的池化
def max_pool_2x2(x):
  return tf.nn.max_pool(x, ksize=[1, 2, 2, 1],
                        strides=[1, 2, 2, 1], padding='SAME')
  
#加载mnist数据集
mnist = input_data.read_data_sets("D:/Users/chendile/AppData/Local/Temp/pip-uninstall-ktrcfkmd/users/chendile/appdata/local/continuum/anaconda3/lib/site-packages/tensorflow/examples/tutorials/mnist/MNIST_data/",one_hot=True)
#print(pd.DataFrame(mnist))
# 1.定义数据。在神经网络里我们需要定义的数据就是输入训练/测试数据,而变量用来存储网络模型里的各种参数。
#定义的是输入输出层,输入层有784个节点,输出层有10个节点,因为数字手写体识别是10分类
#placeholder是一个占位符,希望输入任意数量的784维的向量
x = tf.placeholder( tf.float32, [None, 784] )
y_ = tf.placeholder( tf.float32, [None, 10] )

#初始化第一层卷积层的权重矩阵和偏置项,深度神经网络中的权重矩阵都是2*2的,卷积神经网络中是4*4的,
#5和5表示一个过滤器的一层是一个5*5的矩阵,1表示输入的通道数,32表示输出的通道数
#也就是说,输出有32个过滤器
W_conv1 = weight_variable([5, 5, 1, 32])
b_conv1 = bias_variable([32])

#因为是卷积神经网络,输入的x不应当是向量,而是矩阵,因此需要把向量恢复成28*28大小的像素矩阵,
#最后一个1表示这张灰度图像的通道数是1,如果是RGB图像则通道数是3,能够接受的通道数为1/3/4,设置为其他的都是要报错的
#第一个参数-1表示batch size,这里设置为-1是因为x_image是从占位符x重塑来的,还没有实际的数据,所以batch size缺失
x_image = tf.reshape(x, [-1,28,28,1])

#输入reshape后的x,进行卷积操作,并通过relu激活函数,经过这层卷积后,通道数变为32
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1)

#第二层卷积和第二层池化,64个过滤器,每个过滤器有32层,即通过这一层卷积后,通道数会变成64
W_conv2 = weight_variable([5, 5, 32, 64])
b_conv2 = bias_variable([64])

h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
h_pool2 = max_pool_2x2(h_conv2)

#开始全连接层,全连接层的输入不能是矩阵,
#那么经过两层卷积、两层池化后,图片大小变为7*7,通道数变为64,因此全连接层使用1024个神经元
W_fc1 = weight_variable([7 * 7 * 64, 1024])
b_fc1 = bias_variable([1024])
#重新把图片从矩阵变为向量,输入全连接层,通过reshape将池化层2的输出展开为适合输入到全连接层的张量
h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)

#placeholder定义一个dropout的概率,通过对全连接层进行dropout来防止过拟合,如果一开始就是偏差大,则不必dropout
keep_prob = tf.placeholder("float")
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)

#最后一层是输出层,激活函数是softmax,适用于多分类问题,到这里其实和DNN就是一样的了
W_fc2 = weight_variable([1024, 10])
b_fc2 = bias_variable([10])

y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)

#评估模型
#定义损失函数
cross_entropy = -tf.reduce_sum(y_*tf.log(y_conv))
#这里采用的优化方法是Adam,不是随机梯度下降法
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
correct_prediction = tf.equal(tf.argmax(y_conv,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
#开启会话,并在会话中按照计算图执行前向和后向传播
sess = tf.InteractiveSession()
#初始化变量
sess.run(tf.initialize_all_variables())
#迭代2W次,每次使用50个随机抽取的样本,每训练100次输出一个准确率评估结果
for i in range(20000):
  batch = mnist.train.next_batch(50)
  if i%100 == 0:
    #这里设置的keep_prob为1,说明没用dropout
    train_accuracy = accuracy.eval(feed_dict={
        x:batch[0], y_: batch[1], keep_prob: 1.0})
    print("step %d, training accuracy %g"%(i, train_accuracy))
  train_step.run(feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5})

print("test accuracy %g"%accuracy.eval(feed_dict={
    x: mnist.test.images, y_: mnist.test.labels, keep_prob: 1.0}))

卷积神经网络识别手写体准确率:0.97

三、 深度神经网络识别手写体

#==============================用多层深度神经来识别手写体=====================================
def DNN():
    #'''
    import pandas as pd
    import tensorflow as tf
    from tensorflow.examples.tutorials.mnist import input_data
    
    #加载mnist数据集
    mnist = input_data.read_data_sets("D:/Users/chendile/AppData/Local/Temp/pip-uninstall-ktrcfkmd/users/chendile/appdata/local/continuum/anaconda3/lib/site-packages/tensorflow/examples/tutorials/mnist/MNIST_data/",one_hot=True)
    #print(pd.DataFrame(mnist))
    # 1.定义数据。在神经网络里我们需要定义的数据就是输入训练/测试数据,而变量用来存储网络模型里的各种参数。
    #定义的是输入输出层,输入层有784个节点,输出层有10个节点,因为数字手写体识别是十分类
    #placeholder是一个占位符,希望输入任意数量的784维的向量
    x = tf.placeholder( tf.float32, [None, 784] )
    y_ = tf.placeholder( tf.float32, [None, 10] )
    # 2.定义计算图与变量。对于神经网络来说,涉及到的操作主要有三部分:网络模型定义,损失函数定义、训练/优化方法定义。
    W_1 = tf.Variable( tf.truncated_normal([784,600], stddev=0.1) )  #w为784*10的矩阵,输入层为784个像素点
    b_1 = tf.Variable( tf.truncated_normal([600], stddev=0.1) )  
    # 计算函数定义,建立模型
    y_1 = tf.nn.relu( tf.matmul(x,W_1) + b_1 )
    #placeholder定义一个dropout的概率
    #keep_prob = tf.placeholder("float")
    #y_1 = tf.nn.dropout(y_1, keep_prob)
    print("完成输入层定义")
    
    W_2 = tf.Variable( tf.truncated_normal([1000,2000], stddev=0.1) )  #w为784*10的矩阵,输入层为784个像素点
    b_2 = tf.Variable( tf.truncated_normal([2000], stddev=0.1) )   #输出为10,偏离值也为10
    # 计算函数定义,建立模型
    y_2 = tf.nn.relu( tf.matmul(y_1,W_2) + b_2 )
    #placeholder定义一个dropout的概率
    
    #keep_prob = tf.placeholder("float")
    #y_2 = tf.nn.dropout(y_2, keep_prob)
    print("完成第2层定义")
    
    W_3 = tf.Variable( tf.truncated_normal([2000,3000], stddev=0.1) )  #w为784*10的矩阵,输入层为784个像素点
    b_3 = tf.Variable( tf.truncated_normal([3000], stddev=0.1) )   
    # 计算函数定义,建立模型
    y_3 = tf.nn.relu( tf.matmul(y_2,W_3) + b_3 )
    #placeholder定义一个dropout的概率
    #keep_prob = tf.placeholder("float")
    #y_3 = tf.nn.dropout(y_3, keep_prob)
    print("完成第3层定义")
    
    W_4 = tf.Variable( tf.truncated_normal([600,500], stddev=0.1) )  #w为784*10的矩阵,输入层为784个像素点
    b_4 = tf.Variable( tf.truncated_normal([500], stddev=0.1) )   
    # 计算函数定义,建立模型
    y_4 = tf.nn.relu( tf.matmul(y_3,W_4) + b_4 )
    #placeholder定义一个dropout的概率
    #keep_prob = tf.placeholder("float")
    #y_4 = tf.nn.dropout(y_4, keep_prob)
    print("完成第4层定义")
    
    W_5 = tf.Variable( tf.truncated_normal([500,10], stddev=0.1) )  #w为784*10的矩阵,输入层为784个像素点
    b_5 = tf.Variable( tf.truncated_normal([10], stddev=0.1) )   
    # 计算函数定义,建立模型
    y = tf.nn.softmax( tf.matmul(y_4,W_5) + b_5 )
    print("完成输出层定义")
    
    # 损失函数定义
    cross_entropy = tf.reduce_mean( -tf.reduce_sum(y_*tf.log(y), reduction_indices=[1] ) )  # reduce_sum内第一个参数为交叉熵公式
    # 训练/优化方法定义
    train_step = tf.train.GradientDescentOptimizer(0.1).minimize(cross_entropy)
    # 3.定义会话,并通过global_variables_initializer初始化所有变量
    session = tf.InteractiveSession()
    tf.global_variables_initializer().run()
    # 4.进行计算。对于神经网络来说,就是要开始迭代进行训练和评估,降低损失函数。
    #共训练1000次,每一次都不会使用全部数据,而是使用100条样本,这100条样本替换之前定义的占位符
    #采用这种批量随机训练的方法,能够在最大化学习数据集整体特性的同时减小开销
    for i in range(1000):
            batch_xs, batch_ys = mnist.train.next_batch(100)
            print('batch_xs:',batch_xs)
            print('batch_ys:',len(batch_ys[0]))
            print('------',session.run(W_1))
            #到run这一步才是真正的向x和y_这两个placeholder传入数据
            train_step.run( {x:batch_xs, y_:batch_ys} )
    #        print(i)
    
    
    # 评估模型
    correct_prediction = tf.equal( tf.argmax(y,1), tf.argmax(y_,1) )
    print(correct_prediction)
    #tf.equal( tf.argmax(y,1), tf.argmax(y_,1) )
    #布尔型数据构成的向量通过cast转换为浮点型,并求平均,以得到准确率
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32) )
    print(accuracy.eval({x:mnist.train.images, y_:mnist.train.labels} ),accuracy.eval({x:mnist.test.images, y_:mnist.test.labels} ))
    #'''

DNN()

深度神经网络识别手写体准确率:0.96

你可能感兴趣的:(深度学习,Tensorflow,卷积,深度学习,手写体)