关键字:tensorflow、cnn、mnist、神经网络、卷积、验证码、识别
时间:2017年5月
目录
前言
CNN介绍
Tensorflow介绍
MNIST介绍
定义网络结构及参数
代码及说明
注意事项
前言
工作原因需要抓取一个网站的数据,但这个网站有验证码,很自然的想到了验证码识别。起初通过使用了一些常规的验证码识别的方法,但到了分割字符这一步是,发现非常困难。通过搜索发现了卷积神经网络可以很简单的完成识别工作,于是开始了卷积神经网络的学习。
继续向下阅读需要你对神经网络的基本概念有所认识。
CNN介绍
卷积神经网络(CNN),完全可以按字面去理解它,就是神经网络,并在网络中引入了卷积算法。CNN目前已经在图像识别上取得了广泛的应用。
Tensorflow介绍
Tensorflow是Google开源的一个神经网络框架,支持Python语言,是主流神经网络框架之一。
MNIST介绍
MNIST是一个非常好的分类算法研究的样本库。它由0~9的手写数字灰度图片构成,6万个训练样本,1万个测试样本。
定义网络结构及参数
这里采用了2层卷积和2层全连接构建网络结构。这是一个比较通用的层数,完全可以用于任意位数的验证码识别。但用于多位验证码图片识别时,需要调整输入层和输出层。
输入层(reshape) | 输入节点: 784 | 输出节点: 28*28 |
隐层1(卷积) | 输入节点: 28*28 | 输出节点: 32*14*14 |
隐层2(卷积) | 输入节点: 32*14*14 | 输出节点: 64*7*7 |
隐层3(全连接) | 输入节点: 64*7*7 | 输出节点: 1024 |
隐层4(全连接) | 输入节点: 1024 | 输出节点: 10 |
输出层(Softmax) | 输入节点: 10 | 输出节点: 10 |
代码及说明
tensor,是tensorflow的核心,tf.Variable()、tf.reshape()、tf.nn.relu()、tf.matmul()、tf.nn.softmax()、tf.reduce_mean()等,几乎所有函数的输入输出都是tensor,因此他们之间可以任意连接,构造网络。
reshape中的-1,对矩阵数据进行形状变换时,可以在一个维度上使用-1代替。例如:把一个[1,2,3,4,5,6,7,8,9,0]变成[[1,2,3,4,5],[6,7,8,9,0]],可以使用reshape(x,[2,5])或reshape(x,[-1,5])。
# -*- coding:utf-8 -*- import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data X = tf.placeholder(tf.float32, [None, 784]) # 图片分辨率为28x28,但样本是 Y = tf.placeholder(tf.float32, [None, 10]) # placeholder(),占位函数,session.run的参数feed_dict={X: , Y:}中的X和Y对应的就是它。 inputs = tf.reshape(X,[-1,28,28,1]) # 样本是n个长度为784的1维向量,把它转成n个高28x宽28x通道数1的矩阵 # # 第一层,卷积层 # l1_weights = tf.Variable(tf.truncated_normal([5,5,1,32], stddev=0.1)) l1_biases = tf.Variable(tf.constant(0.1, shape=[32])) # 卷积核[5,5],输入1张28x28图片,输出32张28x28特征图片 l1 = tf.nn.conv2d(inputs, l1_weights, strides=[1,1,1,1], padding='SAME') + l1_biases # strides=[1,1,1,1],所有方向步进为1进行卷积 # padding='SAME',输出大小和输入大小相同28x28 l1 = tf.nn.relu(l1) # 激活函数,例如:relu([0.5,-0.3,-0.13,1.2,-0.7] = [0.5,0,0,1.2,0] l1 = tf.nn.max_pool(l1, ksize=[1,2,2,1], strides=[1,2,2,1], padding='SAME') # 池化,strides=[1,2,2,1]使得输出为14x14 # # 第二层,卷积层,与第一层类似 # l2_weights = tf.Variable(tf.truncated_normal([5,5,32,64], stddev=0.1)) l2_biases = tf.Variable(tf.constant(0.1, shape=[64])) # 卷积核[5,5],输入32张14x14图片,输出64张14x14特征图片 l2 = tf.nn.conv2d(l1, l2_weights, strides=[1,1,1,1], padding='SAME') + l2_biases l2 = tf.nn.relu(l2) l2 = tf.nn.max_pool(l2, ksize=[1,2,2,1], strides[1,2,2,1], padding='SAME') # 池化,strides=[1,2,2,1]使得输出为7x7 # # 第三层,全连接层 # l3_weights = tf.Variable(tf.truncated_normal([7*7*64, 1024], stddev=0.1)) l3_biases = tf.Variable(tf.constant(0.1, shape=[1024])) # 7*7*64个输入,1024个输出 l3 = tf.reshape(l2, [-1,7*7*64]) # 把64张7x7的特征转换成1维进行输入给全连接 l3 = tf.matmul(l3, l3_weights) + l3_biases l3 = tf.nn.relu(l3) # #第四层,全连接层 # l4_weights = tf.Variable(tf.truncated_normal([1024, 10], stddev=0.1)) l4_biases = tf.Variable(tf.constant(0.1, shape=[10])) # 1024个输入,10个输出 l4 = tf.matmul(l3, l4_weights) + l4_biases # y = W * x + b outputs = tf.nn.softmax(l4) # softmax([1,2,2]) = [1/(1+2+2),2/(1+2+2),2/(1+2+2)] = [0.2,0.4,0.4] cross_entropy = -tf.reduce_sum(Y*tf.log(outputs)) # 计算交叉熵 train_op = tf.train.AdamOptimizer(0.0001).minimize(cross_entropy) correct_prediction = tf.equal(tf.argmax(outputs, axis=1), tf.argmax(Y, axis=1)) # tf.argmax找某个轴上的最大值的位置,理解起来比较困难,简单理解就是把[1,0,0,0,0,0,0,0,0,0]转成[0],[0,1,0,0,0,0,0,0,0,0]转成[1],以此类推。 # tf.equal比较两个矩阵相同位置的值,相同为True,否则为False,例如:[[0,1],[1,0]]与[[0,0],[1,1]]比较,结果为[[True,False],[True,False]] accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float")) # tf.cast()数据类型转换,True/False转成浮点1./0. sess = tf.Session() sess.run(tf.initialize_all_variables()) mnist = input_data.read_data_sets('MNIST_data', one_hot=True) # 加载MNIST库,本地没有则从网络下载,下载完成后在当前目录有个MNIST_data/目录 for i in range(1000): # 训练1000次 batch_xs, batch_ys = mnist.train.next_batch(100) # 100个样本一批,进行1次训练 sess.run(train_op, feed_dict={X:batch_xs, Y:batch_ys}) if i%50==0: print "step %d, accuracy %f"%(i, sess.run(accuracy, feed_dict={X:batch_xs,Y:batch_ys})) # 每50次训练,输出准确率 print "test accuracy: ",sess.run(accuracy, feed_dict{X:mnist.test.images, Y:mnist.test.labels}) # 使用测试集计算准确率
注意事项
mnist样本库文件大小约10MB,但下载比较慢。
为了代码简单,没有加入tf.nn.dropout()、tf.train.Saver()等函数。tf.nn.dropout(),可防止过拟合。tf.train.Saver(),可以保存或回复模型,主要用于暂停训练和恢复训练,以及训练好的模型直接加载使用。