在手写数字识别项目的进阶学习中,为了提高识别准确率,我们选择考虑一下数字图片的二维结构,而不单纯得使用一维数组。我们使用了“输入层(多张28*28的数据)-卷积(32个卷积核)-池化(2*2)-卷积(64个卷积核)-池化(2*2)-全连接层(1024个神经元)-dropout(keep_prog=0.5)-输出层(10个神经元)”的CNN网络模型结构:
代码如下:
import tensorflow as tf import pandas as pd import numpy as np #读入数据 train = pd.read_csv("train.csv") #获得images并归一化 images = train.iloc[:,1:].values images=images.astype(np.float) images=np.multiply(images,1.0/255.0) image_size=images.shape[1] #获得label labels_flat=train.iloc[:,0].values.ravel() labels_count=np.unique(labels_flat).shape[0] #定义转换函数 def dense_to_one_dot(labels_dense,num_classes): num_labels_dense=labels_dense.shape[0]#对于一维数组 shape[0]即一维数组长度 labels_one_dot=np.zeros((num_labels_dense,num_classes)) index_offset=np.arange(num_labels_dense)*num_classes labels_one_dot.flat[index_offset+labels_dense.ravel()]=1 return labels_one_dot #将标签数据转换成one-dot格式 labels=dense_to_one_dot(labels_flat,labels_count) labels=labels.astype(np.uint8) #验证数据 VALIDATION_SIZE=2000 validation_images=images[:VALIDATION_SIZE] validation_labels=labels[:VALIDATION_SIZE] #训练数据 train_images=images[VALIDATION_SIZE:] train_labels=labels[VALIDATION_SIZE:] #数据分批 向下取整 batch_size=100 n_batch=int(len(train_images)/batch_size) #定义占位符 x为训练模型的image数据 y为训练模型的label数据 x=tf.placeholder(tf.float32,shape=[None,image_size]) y=tf.placeholder(tf.uint8,shape=[None,labels_count]) #为了创建这个网络模型 需要创建大量的权重和偏置 因此需要编写函数 #这个模型中的权重在初始化时应该加入少量的噪声来打破对称性以及避免0梯度。 # 由于我们使用的是ReLU神经元,因此比较好的做法是用一个较小的正数来初始化偏置项, # 以避免神经元节点输出恒为0的问题(dead neurons)。 # 为了不在建立模型的时候反复做初始化操作,我们定义两个函数用于初始化。 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) #卷积层用到的函数 卷积操作 # x为输入 W为卷积核,数据类型为tensor,是一系列有待训练的参数 # 返回feature map def conv2d(x,W): return tf.nn.conv2d(x,W,strides=[1,1,1,1],padding="SAME") #池化的输入,一般池化层接在卷积层后面,所以输入通常是feature map,依然是[batch, height, width, channels]这样的shape def max_pool_2x2(x): return tf.nn.max_pool(x,ksize=[1,2,2,1],strides=[1,2,2,1],padding="SAME") #-1处的位置会自动计算维度大小 #第一层卷积层和池化层 x_image=tf.reshape(x,[-1,28,28,1]) W_conv1=weight_variable([3,3,1,32]) b_conv1=bias_variable([32]) h_conv1=tf.nn.relu(conv2d(x_image,W_conv1)+b_conv1) h_pool1=max_pool_2x2(h_conv1) #第二层卷积层和池化层 W_conv2=weight_variable([6,6,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) #每张图片变成了64张7*7大小的特征图 #构造全连接层 h_pool2_flat=tf.reshape(h_pool2,[-1,7*7*64]) W_fc1=weight_variable([7*7*64,1024]) b_fc1=bias_variable([1024]) 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) #输出层 10个神经元 W_fc2=weight_variable([1024,10]) b_fc2=bias_variable([10]) y_=tf.nn.softmax(tf.matmul(h_fc1_drop,W_fc2)+b_fc2) #创建损失函数交叉熵的平均值 loss=tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y,logits=y_)) #使用梯度下降优化算法优化得到参数 train_step=tf.train.AdadeltaOptimizer(0.1).minimize(loss) #初始化变量 init=tf.global_variables_initializer() #创建计算准确度的节点 correct=tf.equal(tf.argmax(y,1),tf.argmax(y_,1)) accuracy=tf.reduce_mean(tf.cast(correct,tf.float32)) global_step=tf.Variable(0,name='global_step',trainable=False) saver=tf.train.Saver() #创建session来运行图 with tf.Session() as sess: sess.run(init) for i in range(20): for batch in range(n_batch): #随机梯度下降算法 batch_x=train_images[batch*batch_size:(batch+1)*batch_size] batch_y = train_labels[batch * batch_size:(batch + 1) * batch_size] #进行训练 sess.run(train_step,feed_dict={x:batch_x,y:batch_y,keep_prob:0.5}) #对于每次循环 计算准确度 a=sess.run(accuracy,feed_dict={x:validation_images,y:validation_labels,keep_prob:1.0}) print("第"+str(i+1)+"轮,准确度为:"+str(a)) #保存训练结果 global_step.assign(i).eval() saver.save(sess,'C:/Users/lenovo/PycharmProjects/testTF/model.ckpt',global_step=global_step)结果可以达到98%的准确率。训练模型的时间,每轮大约2-5分钟,20轮的话至少半小时四十分钟