我们在博文,使用CNN做Kaggle比赛手写数字识别准确率99%+,在此基础之上,我们进行对科赛网TibetanMNIST藏文手写数字数据集训练,来验证网络的正确性。
——袁明奇、才让先木、汤吉安等
中央民族大学创业团队巨神人工智能科技
# coding: utf-8
import os
os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"
# In[1]:
import os
import numpy as np
import tensorflow as tf
from tensorflow.keras import utils
import pandas as pd
import matplotlib.pyplot as plt
excl = lambda x:os.popen(x).readlines()
# In[3]:
data_path = "./1CNN/TIbeiMNISTApp/TibetanMNIST/TibetanMNIST.npz"
data = np.load(data_path)
x_data = data['image'].reshape(17768, 784)
y_data = utils.to_categorical(data['label'], 10)
datas = []
for (x,y) in zip(x_data,y_data):
datas.append({"x":x/255,"y":y})
datas = np.array(datas)
np.random.shuffle(datas)
seq = 0.8
lens = len(datas)
trains = datas[0:int(seq*lens)]
tests = datas[int(seq*lens):]
x_train = []
y_train = []
x_test = []
y_test = []
for t in trains:
x_train.append(t["x"])
y_train.append(t["y"])
for t in tests:
x_test.append(t["x"])
y_test.append(t["y"])
x_train = np.array(x_train).astype(np.float32)
y_train = np.array(y_train).astype(np.float32)
x_test = np.array(x_test).astype(np.float32)
y_test = np.array(y_test).astype(np.float32)
lens_train,_=x_train.shape
lens_test,_=x_test.shape
lens_train,lens_test,x_train.shape,y_train.shape
# In[4]:
#训练数据
x = tf.placeholder("float", shape=[None, 784],name="x")
#训练标签数据
y_ = tf.placeholder("float", shape=[None, 10],name="y_")
#把x更改为4维张量,第1维代表样本数量,第2维和第3维代表图像长宽, 第4维代表图像通道数, 1表示灰度
x_image = tf.reshape(x, [-1,28,28,1])
#第一层:卷积层
conv1_weights = tf.get_variable("conv1_weights", [5, 5, 1, 32], initializer=tf.truncated_normal_initializer(stddev=0.1)) #过滤器大小为5*5, 当前层深度为1, 过滤器的深度为32
conv1_biases = tf.get_variable("conv1_biases", [32], initializer=tf.constant_initializer(0.0))
conv1 = tf.nn.conv2d(x_image, conv1_weights, strides=[1, 1, 1, 1], padding='SAME') #移动步长为1, 使用全0填充
relu1 = tf.nn.relu( tf.nn.bias_add(conv1, conv1_biases) ) #激活函数Relu去线性化
#第二层:最大池化层
#池化层过滤器的大小为2*2, 移动步长为2,使用全0填充
pool1 = tf.nn.max_pool(relu1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
#第三层:卷积层
conv2_weights = tf.get_variable("conv2_weights", [5, 5, 32, 64], initializer=tf.truncated_normal_initializer(stddev=0.1)) #过滤器大小为5*5, 当前层深度为32, 过滤器的深度为64
conv2_biases = tf.get_variable("conv2_biases", [64], initializer=tf.constant_initializer(0.0))
conv2 = tf.nn.conv2d(pool1, conv2_weights, strides=[1, 1, 1, 1], padding='SAME') #移动步长为1, 使用全0填充
relu2 = tf.nn.relu( tf.nn.bias_add(conv2, conv2_biases) )
#第四层:最大池化层
#池化层过滤器的大小为2*2, 移动步长为2,使用全0填充
pool2 = tf.nn.max_pool(relu2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
#第五层:全连接层
fc1_weights = tf.get_variable("fc1_weights", [7 * 7 * 64, 1024], initializer=tf.truncated_normal_initializer(stddev=0.1)) #7*7*64=3136把前一层的输出变成特征向量
fc1_baises = tf.get_variable("fc1_baises", [1024], initializer=tf.constant_initializer(0.1))
pool2_vector = tf.reshape(pool2, [-1, 7 * 7 * 64])
fc1 = tf.nn.relu(tf.matmul(pool2_vector, fc1_weights) + fc1_baises)
#为了减少过拟合,加入Dropout层
keep_prob = tf.placeholder(tf.float32,name="keep_prob")
fc1_dropout = tf.nn.dropout(fc1, keep_prob)
#第六层:全连接层
fc2_weights = tf.get_variable("fc2_weights", [1024, 10], initializer=tf.truncated_normal_initializer(stddev=0.1)) #神经元节点数1024, 分类节点10
fc2_biases = tf.get_variable("fc2_biases", [10], initializer=tf.constant_initializer(0.1))
fc2 = tf.matmul(fc1_dropout, fc2_weights) + fc2_biases
#第七层:输出层
# softmax
y_conv = tf.nn.softmax(fc2,name="y_conv")
y_conv_labels = tf.argmax(y_conv,1,name='y_conv_labels')
#定义交叉熵损失函数
y_conv = tf.clip_by_value(y_conv,1e-4,1.99)
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y_conv), reduction_indices=[1]))
#选择优化器,并让优化器最小化损失函数/收敛, 反向传播
train_step = tf.train.AdamOptimizer(0.00008).minimize(cross_entropy)
# tf.argmax()返回的是某一维度上其数据最大所在的索引值,在这里即代表预测值和真实值
# 判断预测值y和真实值y_中最大数的索引是否一致,y的值为1-10概率
correct_prediction = tf.equal(y_conv_labels, tf.argmax(y_,1))
# 用平均值来统计测试准确率
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32),name="accuracy")
# In[1]:
with tf.Session() as sess:
#开始训练
srun = sess.run
srun(tf.global_variables_initializer())
saver = tf.train.Saver()
for i in range(4501):
start_step = i*100 % lens_train
stop_step = start_step+100
batch_x, batch_y = x_train[start_step:stop_astep,:], y_train[start_step:stop_step,:]
cross_entropy_val,_=srun([cross_entropy,train_step],feed_dict={x: batch_x, y_: batch_y, keep_prob: 0.5}) #训练阶段使用50%的Dropout
if i%100 == 0:
train_accuracy = srun(accuracy,feed_dict={x:x_test[:200], y_:y_test[:200], keep_prob: 1.0}) #评估阶段不使用Dropout
print("step %d, loss %f test accuracy %f" % (i, cross_entropy_val, train_accuracy))
saver_path = saver.save(sess, "./1CNN/TIbeiMNISTApp/ckpt1/my_model.ckpt",global_step=i) # 将模型保存到save/model.ckpt文件
print("Model saved in file:", saver_path)
#在测试数据上测试准确率
print("final test accuracy %g" % srun(accuracy,feed_dict={x: x_test, y_: y_test, keep_prob: 1.0}))
step 4100, loss 0.008919 test accuracy 0.985000
step 4200, loss 0.014542 test accuracy 0.980000
step 4300, loss 0.019433 test accuracy 0.985000
step 4400, loss 0.006040 test accuracy 0.985000
step 4500, loss 0.007214 test accuracy 0.990000
Model saved in file: /home/kesci/input/TibetanMNIST5610/ckpt1/my_model.ckpt-4500
final test accuracy 0.988745