玩转人工智能(1)使用TensorFlow框架训练神经网络模型识别MNIST数据集

本文重点讲解神经网络,深度剖析当红炸子鸡tensorflow开源框架,最后使用科研界的MNIST数据集小试牛刀。目的让读者达到对AI思想的深度理解,同时起“码”上手对神经网络有个直观认识。

所谓‘学习’者,即对直观事物的规律总结,用于找到对于未知事物的判决和认知。周老师的西瓜书中开门见山的讲了‘识’瓜术,老农看一叶便知天下秋来,诸葛亮观察天象预测人间灾情等等,都是对万事万物的规律发现和总结提炼走势,判断未来必然可能或者即将出现的场景和现象。机器学习就是让机器能像人脑一样发现客观世界事务的规律存在,预测未知事物。一言以蔽之,在数学界,就是求解Y=F(X)+b的问题,在直接点讲F(X)就是多个w*f(x)的组合,F就是规则或者规律。函数中求解方程的解,找到方程成立的最优系数,我们可以说是寻找函数规律的过程,这个规律的走势在数学中叫拟合,也叫回归。

神经网络顾名思义来源于仿生学,数学家和生物学家聊天,突然灵感闪现,数学家用公式表现了人类神经结构,而后引述到数学研究中来,完美的体现了Y=F(X)+b的样子。再到后来越来越多的数学家或者叫计算机家把简单的公式变得越来越复杂,复杂到你和我一看就吐的模样。但目的还是寻找让Y=F(X)+b在X的任何未来一时刻都成立的F和b而已。

认真的讲,神经网络就像维基百科讲的那样严肃,从感知机到BP,从CNN到RNN,到现在很火的GAN等等。BP网络就是把多层感知器顺着连,然后还要倒着链接。CNN就是卷积网络,所谓卷积也就是一种比较直观的能在矩阵中寻找特征的方式而已,反而网络结构比较简单。RNN就是循环神经网络,网络一般有多层,输入层、输出层、隐含层等等,循环的意思就是层间信号互通,前后层之间信息有链接。神经网络的变种成百上千,不认真的讲,还是把一堆函数放在一起翻来覆去的蹂躏而已。目的还是寻找规律的表征W和B而已,当然评价W和B好不好,怎么评价,需要使用概率和统计的知识,李航老师在作品中其实说了一句话:一切皆有可能,条件满足的情况下。

所以,熟悉概率统计理论,微积分,线代的基础上重点了解下近年来数据挖掘的几大算法思想,然后来看机器学习理论基本水到渠成。

2015年11月9日,Google发布人工智能系统TensorFlow并宣布开源,下文使用TF代之。这就是个开源包,包中封装了各种用来计算的函数和结构体,这些类,函数,数据结构等恰好是我们在做线性代数,求导,矩阵计算,求目标函数和误差函数最常用的的东西。所以,了解了理论基础的条件下直接上手工具包,好比体格健壮的士兵获得火力强劲的武器一般,赶紧开搞吧!

顺便介绍下TF的基本知识,TF在会话中使用图创建计算,图的基本要素就是tensor张量。创建张量一般在TF中使用占位符。构建图就是构建网络模型的过程。一个网络中一般使用会话调用图来启动网络模型,第一步基本上都要初始化变量。如何评估模型,构建可视化等功能TF也支持。

了解了这么多TF的知识基本就够了,介绍下MNIST数据,这是一个计算机视觉入门级的数据集合,数据集为从1到9的手写图片的组合,一般在Yann LeCun的官网上能找到原始数据。数据集中包含60000张训练图片,10000张测试图片,图片为28*28的灰度图。

http://yann.lecun.com/exdb/mnist/

安装python平台和导入TF库这里不再介绍,这是很基本的东东~~,好,直接上干活吧!

1、我们的目标是构建Y=F(x)+b的函数模型,参考思想是神经网络结构,借助的软件包是TF。OK,原始数据已从网络下载到Python的工程目录下,打开一个新建的py文件,开始我们的代码:导入数据(对于非TF接收的数据格式还需要格式处理);构建网络结构,也就是定义函数的输入输出,权值和偏差等;然后定义评价网络的函数(一般叫损失函数,比如交叉熵);按照TF的框架要求,初始化变量,创建会话,运行构建好的图(网路);最后评估下我们的网路模型,是骡子是马,出来溜溜呗。循环1000次训练结果为0.9096。

__author__ = 'moscar'
#导入数据
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=tf.placeholder(tf.float32,[None,784])
w = tf.Variable(tf.zeros([784,10]))
b = tf.Variable(tf.zeros([10]))
y = tf.nn.softmax(tf.matmul(x,w)+b)
#定义交叉熵函数,用来计算偏差
y_=tf.placeholder("float",[None,10])
cross_entropy=-tf.reduce_sum(y_*tf.log(y))
#选择梯度求导最小化LOSS函数来循环计算权值和偏移量
train_step = tf.train.GradientDescentOptimizer(0.001).minimize(cross_entropy)
#使用会话调用图,启动TF,变量初始化
sess = tf.Session()
sess.run(tf.initialize_all_variables())
#循环训练网络
for i in range(1000):
    batch_x,batch_y = mnist.train.next_batch(100)
    sess.run(train_step,feed_dict={x:batch_x,y_:batch_y})
#评价网络模型的正确率函数,打印输出
correct_prediction = tf.equal(tf.argmax(y,1),tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction,"float"))

print(sess.run(accuracy,feed_dict={x:mnist.test.images,y_:mnist.test.labels}))







2、上文基于TF框架构建了基本的神经网络模型,但是正确率只有90%左右,差强人意但我们要更进一步,怎么办?最简单的方法就是构建个多层的网络,在输入层和中间层使用relu激活函数,增加卷积一层,池化一层,卷积二层和池化二层,增加全连接层,输出层使用softmax把输出结果的概率排到[0,1]的区间。为了防止过拟合,在输出层之前加dropout,剔除概率不变的输入结果。循环20000次,测试结果接近99.3%。

__author__ = 'moscar'
#导入数据
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets('MNIST_data/', one_hot=True)
#定义函数结构
x = tf.placeholder(tf.float32, shape=[None, 784])
y_ = tf.placeholder(tf.float32, shape=[None, 10])
W = tf.Variable(tf.zeros([784,10]))
b = tf.Variable(tf.zeros([10]))
y = tf.matmul(x,W) + b
#使用TF的会话调用图计算并初始化变量
sess = tf.InteractiveSession()
sess.run(tf.global_variables_initializer())
#定义交叉熵用来计算LOSS(真实结果和预测结果的偏差)
cross_entropy = tf.reduce_mean(
    tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y))
#选择优化函数最小化交叉熵
train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)
#循环训练模型
for _ in range(1000):
  batch = mnist.train.next_batch(100)
  train_step.run(feed_dict={x: batch[0], y_: batch[1]})
#定义网络模型评价函数
correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
print(accuracy.eval(feed_dict={x: mnist.test.images, y_: mnist.test.labels}))
#定义权值函数
def weight_variable(shape):
  initial = tf.truncated_normal(shape, stddev=0.1)
  return tf.Variable(initial)
#定义偏置量函数
def bias_variable(shape):
  initial = tf.constant(0.1, shape=shape)
  return tf.Variable(initial)
#定义卷积函数
def conv2d(x, W):
  return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')
#定义池化函数(池化的目的就是寻找特征,举个栗子,对于图像的池化可以认为是扩缩,类似的对于图像的卷积就是对图像的过滤)
def max_pool_2x2(x):
  return tf.nn.max_pool(x, ksize=[1, 2, 2, 1],
                        strides=[1, 2, 2, 1], padding='SAME')
#第一层卷积层的权值和偏置量,以及输入输出
W_conv1 = weight_variable([5, 5, 1, 32])
b_conv1 = bias_variable([32])
x_image = tf.reshape(x, [-1,28,28,1])
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1)
#第二层卷积层的权值和偏置量,以及输入输出
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)
#全连接层的权值和偏移量,池化结果的变形处理,输出结果
W_fc1 = weight_variable([7 * 7 * 64, 1024])
b_fc1 = bias_variable([1024])
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)
#使用Dropout方法减少过拟合
keep_prob = tf.placeholder(tf.float32)
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
#全连接层的权值和偏置
W_fc2 = weight_variable([1024, 10])
b_fc2 = bias_variable([10])
#最终输出结果
y_conv = tf.matmul(h_fc1_drop, W_fc2) + b_fc2
#评估模型使用的求和交叉熵函数,可以对比上文的求均值函数,可以自己尝试使用哪个正确率高
'''
cross_entropy = tf.reduce_sum(
    tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=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, tf.float32))
# 用来保存所有的变量
saver = tf.train.Saver()
#TF下运行会话
sess.run(tf.global_variables_initializer())
#循环训练模型
for i in range(20000):
    #分片,50张图片一批次来运行
  batch = mnist.train.next_batch(50)
  if i%100 == 0:
    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})
#保存模型参数
saver.save(sess, 'model.ckpt')
#打印测试集的训练结果
print("test accuracy %g"%accuracy.eval(feed_dict={
    x: mnist.test.images, y_: mnist.test.labels, keep_prob: 1.0}))
总结:夯实数学基础,重点复习大学数学相关课程,重点了解下研究生期间的概率论和信息论,数据挖掘等课程。参考TF的官方API手册或者GITHUB说明,详细的了解下TF的架构,不要求全部记住,但是基本的一些数据结构和函数要做到手到擒来,比如函数模型中的变量存放在TF的张量中,建模时必须初始化,初始值一般为常量或者随机值。重点了解tf.Variable。使用TF的时候我们会保存模型,最简单的保存和恢复模型的方法是使用tf.train.Saver对象。TensorBoard可视化,使用GPU等等。

最后总结一句:眼里过千边不如手里过一遍,Just do iT! 玩转人工智能的技巧就在这里,无他!

你可能感兴趣的:(玩转人工智能(1)使用TensorFlow框架训练神经网络模型识别MNIST数据集)