Tensorflow搭建卷积神经网络识别手写英语字母
更新记录:
2018年2月5日 初始文章版本
近几天需要进行英语手写体识别,查阅了很多资料,但是大多数资料都是针对MNIST数据集的,并且主要识别手写数字。为了满足实际的英文手写识别需求,需要从训练集构造到神经网络搭建各个方面对现有代码进行修改。
神经网络的结构:
1.输入28*28=784维行向量
2.卷积层:卷积核大小5*5,共32个,激活函数ReLu
3.池化层:最大值池化,2*2窗口
4.卷积层:卷积核大小5*5,共64个,激活函数ReLu
5.池化层:最大值池化,2*2窗口
6.全连接层(多层感知机)
训练代码:
import tensorflow as tf
import numpy as np
import xlrd
# 开始读取训练数据
data = xlrd.open_workbook('train_set.xlsx')
table = data.sheets()[0]
nrows = table.nrows
ncols = table.ncols
c1 = np.arange(0, nrows, 1)
datamatrix = np.zeros((nrows, ncols))
for x in range(ncols):
cols = table.col_values(x)
cols1 = np.matrix(cols) # 把list转换为矩阵进行矩阵操作
datamatrix[:, x] = cols1 # 把数据进行存储
x_data = datamatrix table = data.sheets()[1]
nrows = table.nrows
ncols = table.ncols
c1 = np.arange(0, nrows, 1)
datamatrix = np.zeros((nrows, ncols))
for x in range(ncols):
cols = table.col_values(x)
cols1 = np.matrix(cols) # 把list转换为矩阵进行矩阵操作
datamatrix[:, x] = cols1 # 把数据进行存储
y_data = datamatrix
# 完成训练数据读取
# 开始定义神经网络结构 # 定义占位符x和y_
x = tf.placeholder(tf.float32, shape=[None, 784])
y_ = tf.placeholder(tf.float32, shape=[None, 26]) # 开始定义用于初始化的两个函数
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) # 完成初始化函数定义 # 开始定义卷积和池化的函数
# 卷积使用1步长(stride size),0边距(padding size)的模板,保证输出和输入大小相同
# 池化用简单传统的2x2大小的模板做max pooling,因此输出的长宽会变为输入的一半 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')
# 完成卷积池化函数定义 # 开始定义神经网络结构定义
# 第一层卷积,卷积在每个5x5的patch中算出32个特征
W_conv1 = weight_variable([5, 5, 1, 32])
b_conv1 = bias_variable([32])
x_image = tf.reshape(x, [-1, 28, 28, 1])
# 第2、第3维对应图片的宽、高,最后一维代表图片的颜色通道数(因为是灰度图所以这里的通道数为1,如果是rgb彩色图,则为3)
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1) # 第二层卷积,每个5x5的patch会得到64个特征
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) # 有1024个神经元的全连接层,此时图片大小为7*7
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。用一个placeholder代表一个神经元的输出在dropout中保持不变的概率。
# 这样可以在训练过程中启用dropout,在测试过程中关闭dropout。
keep_prob = tf.placeholder(tf.float32)
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
# softmax输出层
W_fc2 = weight_variable([1024, 26])
b_fc2 = bias_variable([26])
y_conv = tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)
# 应为 y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)
# 完成神经网络结构定义 # 开始定义训练和评估操作
# 用更加复杂的ADAM优化器来做梯度最速下降,在feed_dict中加入额外的参数keep_prob来控制dropout比例
cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y_conv))
train_step = tf.train.AdamOptimizer(1e-6).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(write_version=tf.train.SaverDef.V1)
sess = tf.InteractiveSession()
saver.restore(sess, "cnnres/model.ckpt")
# sess.run(tf.global_variables_initializer())
# 完成定义储存器操作和装载神经网络 # 开始对训练集进行循环训练
for k in range(20):
for i in range(55): # 为减少训练时间,降低迭代次数
x_datap = x_data[i*26:(i+1)*26, 0:28*28]
y_datap = y_data[i*26:(i+1)*26, 0:26]
for j in range(3000):
if j % 100 == 0:
train_accuracy = accuracy.eval(feed_dict={x: x_data, y_: y_data, keep_prob: 1.0})
print("step %d, training accuracy %g"%(i, train_accuracy))
train_step.run(feed_dict={x: x_datap, y_: y_datap, keep_prob: 0.5})
# if train_accuracy >= 0.942:
# train_step = tf.train.AdamOptimizer(1e-6).minimize(cross_entropy)
# if train_accuracy <= 0.9:
# train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
if train_accuracy >= 0.95:
saver_path = saver.save(sess, "cnnres/model.ckpt")
print('Save the par in', saver_path)
# 完成训练和储存过程
备注:
1.由于GUP运算能力的限制,需要将训练集每次取出一部分进行训练,但是对模型的准确度进行评估时应当feed全部数据。
相关代码:
x_datap = x_data[i*26:(i+1)*26, 0:28*28]
y_datap = y_data[i*26:(i+1)*26, 0:26]
train_accuracy = accuracy.eval(feed_dict={x: x_data, y_: y_data, keep_prob: 1.0})
train_step.run(feed_dict={x: x_datap, y_: y_datap, keep_prob: 0.5})
2.考虑到对训练集的读取是顺序的,因此训练集必须随机乱序,绝对不能按照字母表排序,否则将会出现严重的过拟合。
3.神经网络的训练结果被储存在cnnres/model.ckpt中
4.在精确度达到0.8之前将步长定为1E-4,在精确度达到0.9之后将步长定为1E-6,不要将步长设定为小于这个值,否则训练进展极为缓慢。
训练集构成:
储存在train_set.xlsx中。共有两张表,第一张表每一行有28*28=784列,对应一个784维输入向量;第二张表每一行有26列,该行与第一张表同一行的预期输出结果对应,在第x列值为1,其余列值为0,表示第一张表同一行的预期输出结果是字母表中第x个字母。
训练集的生成代码:
import numpy as np
from PIL import Image
import xlsxwriter # 开始读取测试图片 def ImageToMatrix(filename):
im = Image.open(filename)
width, height = im.size
im = im.convert("L")
data = im.getdata()
data = np.matrix(data, dtype='float')/255.0
new_data = np.reshape(data, (height, width))
return new_data def ImageToMatrix2(ima):
width, height = ima.size
ima = ima.convert("L")
data = ima.getdata()
data = np.matrix(data, dtype='float')/255.0
new_data = np.reshape(data, (height, width))
return new_data def MatrixToImage(data):
data = data*255
new_im = Image.fromarray(data.astype(np.uint8))
return new_im # 循环读取测试图片并写入
# 开始进行写excel的准备
book = xlsxwriter.Workbook(r'train_set.xlsx')
sheet1 = book.add_worksheet('train_input1')
sheet2 = book.add_worksheet('train_input2')
sheet3 = book.add_worksheet('train_input3')
sheet4 = book.add_worksheet('train_input4')
# 完成写excel的准备
for i in range(1, 1430+1):
test_pic = ImageToMatrix(str(i)+'.png')
# 完成测试图片读取
# -------------------------
# 开始处理测试图片
# 开始寻找图片四边
hang, lie = np.shape(test_pic)
for top in range(0, hang):
if np.min(test_pic[top, :]) != 1:
break
for bot in range(hang-1, 0, -1):
if np.min(test_pic[bot, :]) != 1:
break
for left in range(0, lie):
if np.min(test_pic[:, left]) != 1:
break
for right in range(lie - 1, 0, -1):
if np.min(test_pic[:, right]) != 1:
break
new_test_pic = test_pic[top:bot, left:right]
# 完成图片四边寻找
# 开始进行图片尺寸转换
pic = MatrixToImage(new_test_pic)
pic2 = pic.resize((28, 28))
test_datap = ImageToMatrix2(pic2)
test_data = np.reshape(test_datap, (1, 784))
# 完成图片尺寸转换
# 对行向量进行储存
for j in range(0, 200):
sheet1.write(i-1, j, test_data[0, j])
sheet2.write(i - 1, j, test_data[0, j+200])
sheet3.write(i - 1, j, test_data[0, j+400])
if j+600 <= 783:
sheet4.write(i - 1, j, test_data[0, j+600])
print(i)
book.close()
备注:此处由于python提供的xlsxwriter库存如下限制:每一行最多可以写256列,因此必须将这个786维的向量分别写到4张表的同一行,再进行手工合并。而第二张预期输出表需要使用其它方法进行构造,此处不给出相关代码。
测试代码:
import tensorflow as tf
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
# 开始读取测试图片 def ImageToMatrix(filename):
im = Image.open(filename)
width, height = im.size
im = im.convert("L")
data = im.getdata()
data = np.matrix(data, dtype='float')/255.0
new_data = np.reshape(data, (height, width))
return new_data def ImageToMatrix2(ima):
width, height = ima.size
ima = ima.convert("L")
data = ima.getdata()
data = np.matrix(data, dtype='float')/255.0
new_data = np.reshape(data, (height, width))
return new_data def MatrixToImage(data):
data = data*255
new_im = Image.fromarray(data.astype(np.uint8))
return new_im test_pic = ImageToMatrix('test.png') # 完成测试图片读取
# -------------------------
# 开始处理测试图片
# 开始寻找图片四边
hang, lie = np.shape(test_pic)
for top in range(0, hang):
if np.min(test_pic[top, :]) != 1:
break
for bot in range(hang-1, 0, -1):
if np.min(test_pic[bot, :]) != 1:
break
for left in range(0, lie):
if np.min(test_pic[:, left]) != 1:
break
for right in range(lie - 1, 0, -1):
if np.min(test_pic[:, right]) != 1:
break
new_test_pic = test_pic[top:bot, left:right]
# 完成图片四边寻找
# 开始进行图片尺寸转换
pic = MatrixToImage(new_test_pic)
pic2 = pic.resize((28, 28))
test_data = ImageToMatrix2(pic2)
test_data = np.reshape(test_data, (1, 784))
# 完成图片尺寸转换 # 完成测试图片的处理
# --------------------------
# 开始定义神经网络结构 # 定义占位符x和y_
x = tf.placeholder(tf.float32, shape=[None, 784])
y_ = tf.placeholder(tf.float32, shape=[None, 26]) # 开始定义用于初始化的两个函数
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) # 完成初始化函数定义 # 开始定义卷积和池化的函数
# 卷积使用1步长(stride size),0边距(padding size)的模板,保证输出和输入大小相同
# 池化用简单传统的2x2大小的模板做max pooling,因此输出的长宽会变为输入的一半 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')
# 完成卷积池化函数定义 # 开始定义神经网络结构定义
# 第一层卷积,卷积在每个5x5的patch中算出32个特征
W_conv1 = weight_variable([5, 5, 1, 32])
b_conv1 = bias_variable([32])
x_image = tf.reshape(x, [-1, 28, 28, 1])
# 第2、第3维对应图片的宽、高,最后一维代表图片的颜色通道数(因为是灰度图所以这里的通道数为1,如果是rgb彩色图,则为3)
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1) # 第二层卷积,每个5x5的patch会得到64个特征
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) # 有1024个神经元的全连接层,此时图片大小为7*7
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。用一个placeholder代表一个神经元的输出在dropout中保持不变的概率。
# 这样可以在训练过程中启用dropout,在测试过程中关闭dropout。
keep_prob = tf.placeholder(tf.float32)
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
# softmax输出层
W_fc2 = weight_variable([1024, 26])
b_fc2 = bias_variable([26])
y_conv = tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)
# 应为 y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)
# 完成神经网络结构定义 # 开始定义训练和评估操作
# 用更加复杂的ADAM优化器来做梯度最速下降,在feed_dict中加入额外的参数keep_prob来控制dropout比例
cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y_conv))
train_step = tf.train.AdamOptimizer(1e-6).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(write_version=tf.train.SaverDef.V1)
sess = tf.InteractiveSession()
saver.restore(sess, "cnnres/model.ckpt")
# sess.run(tf.global_variables_initializer())
# 完成定义储存器操作和装载神经网络 # 开始对神经网络进行输入测试
res = sess.run(y_conv, feed_dict={x: test_data, keep_prob: 1.0})
temp = np.argmax(res)
letter = chr(97+temp)
print('The test letter is '+letter)
# 完成测试
备注:
1.要求已经被训练完成的模型储存在cnnres/model.ckpt
2.预测函数为:res = sess.run(y_conv, feed_dict={x: test_data, keep_prob: 1.0})
不要试图计算y_占位符的值,那是用于训练的,不是用于结果预测的
对CNN的效果备注和研究:
1.在训练集为较粗字体的情况下测试图片必须相应采用较粗字体,否则结果很差
Tensorflow搭建卷积神经网络识别手写英语字母的更多相关文章
- 使用TensorFlow的卷积神经网络识别手写数字(3)-识别篇
from PIL import Image import numpy as np import tensorflow as tf import time bShowAccuracy = True # ...
- 使用TensorFlow的卷积神经网络识别手写数字(2)-训练篇
import numpy as np import tensorflow as tf import matplotlib import matplotlib.pyplot as plt import ...
- 使用TensorFlow的卷积神经网络识别手写数字(1)-预处理篇
功能: 将文件夹下的20*20像素黑白图片,根据重心位置绘制到28*28图片上,然后保存.经过预处理的图片有利于数字的准确识别.参见MNIST对图片的要求. 此处可下载已处理好的图片: https:/ ...
- PyTorch基础——使用卷积神经网络识别手写数字
一.介绍 实验内容 内容包括用 PyTorch 来实现一个卷积神经网络,从而实现手写数字识别任务. 除此之外,还对卷积神经网络的卷积核.特征图等进行了分析,引出了过滤器的概念,并简单示了卷积神经网络的 ...
- Pytorch卷积神经网络识别手写数字集
卷积神经网络目前被广泛地用在图片识别上, 已经有层出不穷的应用, 如果你对卷积神经网络充满好奇心,这里为你带来pytorch实现cnn一些入门的教程代码 #首先导入包 import torchfrom ...
- 使用TensorFlow的卷积神经网络识别自己的单个手写数字,填坑总结
折腾了几天,爬了大大小小若干的坑,特记录如下.代码在最后面. 环境: Python3.6.4 + TensorFlow 1.5.1 + Win7 64位 + I5 3570 CPU 方法: 先用MNI ...
- TensorFlow卷积神经网络实现手写数字识别以及可视化
边学习边笔记 https://www.cnblogs.com/felixwang2/p/9190602.html # https://www.cnblogs.com/felixwang2/p/9190 ...
- 用BP人工神经网络识别手写数字
http://wenku.baidu.com/link?url=HQ-5tZCXBQ3uwPZQECHkMCtursKIpglboBHq416N-q2WZupkNNH3Gv4vtEHyPULezDb5 ...
- 卷积神经网络CNN 手写数字识别
1. 知识点准备 在了解 CNN 网络神经之前有两个概念要理解,第一是二维图像上卷积的概念,第二是 pooling 的概念. a. 卷积 关于卷积的概念和细节可以参考这里,卷积运算有两个非常重要特性, ...
随机推荐
- VB代码收集
1.随机获取5位验证码? 需求: 创建一个Label1:名称为随机验证码生成 创建一个Label2:名称为为空,属性BorderStyle=1 创建一个CommandButton:名称为获取随机码 代 ...
- Python中自定义filter用法
django中新建项目,在项目中新建app,自定义filter一般放到app中.结构目录如下: 1.先在APP中新建一个templatetags的django文件夹,文件夹中新建一个filter的py ...
- Centos7通过SSH使用密钥实现免密登录
日常开发中,难免会有登录服务器的操作,而通过ssh方式登录无疑是比较方便的一种方式. 如果登录较频繁,使用密钥实现免密登录无疑更是方便中的方便.因此本文就简单说一说如何实现免密登录. 一.安装配置ss ...
- Linux启动过程简述
Linux启动过程: 图片来自:https://www.cnblogs.com/codecc/p/boot.html 简单来讲: 加载BIOS–>读取MBR–>Boot Loader–&g ...
- xpath解析数据
xpath解析数据 """ xpath 也是一种用于解析xml文档数据的方式 xml path w3c xpath搜索用法 在 XPath 中,有七种类型的节点:元素.属 ...
- LINUX之根目录介绍、普通目录创建、删除、复制、移动、权限管理命令记录
(一)Linux 系统目录结构 登录系统后,在当前命令窗口下输入命令:ls / /bin:bin是Binary的缩写, 这个目录存放着最经常使用的命令. /boot:这里存放的是启动Linux时使用的 ...
- [转载] 修改linux终端用户名的颜色
此文章为转载,来源:https://blog.csdn.net/vactivx/article/details/62219349,目的是怕以后他博客打不开,文章就没了.存个档. 这个基本都需要手动修改 ...
- oralce问题
死锁,如果较多使用存储过程杀死 create or replace procedure killer is v_obj varchar2(200); v_sql varchar2(500) ...
- Asp.net core Identity + identity server + angular 学习笔记 (第三篇)
register -> login 讲了 我们来讲讲 forgot password -> reset password 和 change password 吧 先来 forgot pa ...
- android -------- RecyclerView的可(多个Item水平,垂直)滚动列表的实现
RecyclerView的可滚动的列表实现,视图相邻的视图在屏幕上部分或完全可见(水平3个item,第一个和第三个显示一部分,第二个完全显示) 效果如图: 基于RecyclerView完成的(自定义控 ...