手写数字识别
手写数字识别
1.建立卷积神经网络层并进行训练模型
- 导入MNIST数据集,定义变量x和y,并进行设置形状,控制图片大小为28*28
mnist = input_data.read_data_sets('./MNIST_data/', one_hot=True)
sess = tf.InteractiveSession()
#训练数据
x = tf.placeholder("float", shape=[None, 784])
#训练标签数据
y_ = tf.placeholder("float", shape=[None, 10])
#把x更改为4维张量,第1维代表样本数量,第2维和第3维代表图像长宽, 第4维代表图像通道数, 1表示黑白
x_image = tf.reshape(x, [-1,28,28,1])
- 第一层:开始建立卷积层,定义Weights和Biases,建立过滤器大小为5*5,当前深度为1,过滤器深度为32,并建立卷积函数,再通过relu进行一次**函数,其作用是去线性化
#第一层:卷积层
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')
max_pool的作用:
- invariance(不变性),这种不变性包括translation(平移),rotation(旋转),scale(尺度)
- 保留主要的特征同时减少参数(降维,效果类似PCA)和计算量,防止过拟合,提高模型泛化能力
- 第三层;再一次建立卷积层进行收集数据集
#第三层:卷积层
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')
- Dropout层处理
#为了减少过拟合,加入Dropout层
keep_prob = tf.placeholder(tf.float32)
fc1_dropout = tf.nn.dropout(fc1, keep_prob)
- 第五层:建立全连接层,把前一层的输出变成特征向量
#第五层:全连接层
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)
- 第六层:搭建全连接层
#第六层:全连接层
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,这一步通常是求取输出属于某一类的概率,reduce_mean函数用来降低损失值
#第七层:输出层
# softmax
y_conv = tf.nn.softmax(fc2)
#定义交叉熵损失函数
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y_conv), reduction_indices=[1]))
- 再使用选择优化器进行梯度计算并进行训练
#选择优化器,并让优化器最小化损失函数/收敛, 反向传播
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
# tf.argmax()返回的是某一维度上其数据最大所在的索引值,在这里即代表预测值和真实值
# 判断预测值y和真实值y_中最大数的索引是否一致,y的值为1-10概率
correct_prediction = tf.equal(tf.argmax(y_conv,1), tf.argmax(y_,1))
# 用平均值来统计测试准确率
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
- 将训练好的数据集存储在文件中
saver_path = saver.save(sess, "/home/cris/AI/MNIST/save/model.ckpt") # 将模型保存到save/model.ckpt文件
print("Model saved in file:", saver_path)
2.安装opencv第三方库,进行剪裁图片,在建立神经网络模型的时候我们已控制图片的大小为28*28,通过opencv的剪裁功能进行控制图片的大小,再将图片进行二值化,并进行保存
img = cv2.imread('/home/cris/AI/MNIST/image/hei9.png') # 手写数字图像所在位置
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 转换图像为单通道(灰度图)
cv2.namedWindow('image')
cv2.setMouseCallback('image', on_mouse) # 调用回调函数
cv2.imshow('image', img)
cv2.waitKey(0)
min_x = min(point1[0], point2[0])
min_y = min(point1[1], point2[1])
width = abs(point1[0] - point2[0])
height = abs(point1[1] -point2[1])
cut_img = img[min_y:min_y+height, min_x:min_x+width]
resize_img = cv2.resize(cut_img, (28,28)) # 调整图像尺寸为28*28
ret, thresh_img = cv2.threshold(resize_img,127,255,cv2.THRESH_BINARY) # 二值化
cv2.imshow('result', thresh_img)
cv2.imwrite('/home/cris/AI/MNIST/image/text.png', thresh_img) # 预处理后图像保存位置
3.调用第一步训练好的模型,再通过Image库打开剪裁后的图片,并建立卷积神经网络层,进行手写数字识别功能
file_name='/home/cris/AI/MNIST/image/hei8.png'#导入自己的图片地址
#进行灰度处理
im = Image.open(file_name).convert('L')
#将图片进行剪裁成28*28像素大小
img = im.resize((28, 28), Image.ANTIALIAS).filter(ImageFilter.SHARPEN)
#导入训练好的模型
sess = tf.InteractiveSession()
saver = tf.train.Saver()
tf.global_variables_initializer().run()
saver.restore(sess, "/home/cris/AI/MNIST/save/model.ckpt")
最终进行识别数据,将结果打印出来,最终纯白底黑字的图片识别率较高,图片较模糊底色偏暗的图片情况识别率较低