Tensorflow搭建卷积神经网络识别手写英语字母

更新记录:python

2018年2月5日 初始文章版本git


 

近几天须要进行英语手写体识别,查阅了不少资料,可是大多数资料都是针对MNIST数据集的,而且主要识别手写数字。为了知足实际的英文手写识别需求,须要从训练集构造到神经网络搭建各个方面对现有代码进行修改。网络

神经网络的结构:ide

1.输入28*28=784维行向量函数

2.卷积层:卷积核大小5*5,共32个,激活函数ReLu测试

3.池化层:最大值池化,2*2窗口字体

4.卷积层:卷积核大小5*5,共64个,激活函数ReLu优化

5.池化层:最大值池化,2*2窗口ui

6.全链接层(多层感知机)spa

 

训练代码:

 1 import tensorflow as tf  2 import numpy as np  3 import xlrd  4 # 开始读取训练数据
 5 data = xlrd.open_workbook('train_set.xlsx')  6 table = data.sheets()[0]  7 nrows = table.nrows  8 ncols = table.ncols  9 c1 = np.arange(0, nrows, 1)  10 datamatrix = np.zeros((nrows, ncols))  11 for x in range(ncols):  12     cols = table.col_values(x)  13     cols1 = np.matrix(cols)   # 把list转换为矩阵进行矩阵操做
 14     datamatrix[:, x] = cols1  # 把数据进行存储
 15 x_data = datamatrix  16 
 17 table = data.sheets()[1]  18 nrows = table.nrows  19 ncols = table.ncols  20 c1 = np.arange(0, nrows, 1)  21 datamatrix = np.zeros((nrows, ncols))  22 for x in range(ncols):  23     cols = table.col_values(x)  24     cols1 = np.matrix(cols)   # 把list转换为矩阵进行矩阵操做
 25     datamatrix[:, x] = cols1  # 把数据进行存储
 26 y_data = datamatrix  27 # 完成训练数据读取
 28 # 开始定义神经网络结构
 29 
 30 # 定义占位符x和y_
 31 x = tf.placeholder(tf.float32, shape=[None, 784])  32 y_ = tf.placeholder(tf.float32, shape=[None, 26])  33 
 34 
 35 # 开始定义用于初始化的两个函数
 36 def weight_variable(shape):  37     initial = tf.truncated_normal(shape, stddev=0.1)  38     return tf.Variable(initial)  39 
 40 
 41 def bias_variable(shape):  42     initial = tf.constant(0.1, shape=shape)  43     return tf.Variable(initial)  44 
 45 # 完成初始化函数定义
 46 
 47 
 48 # 开始定义卷积和池化的函数
 49 # 卷积使用1步长(stride size),0边距(padding size)的模板,保证输出和输入大小相同
 50 # 池化用简单传统的2x2大小的模板作max pooling,所以输出的长宽会变为输入的一半
 51 
 52 
 53 def conv2d(x, W):  54     return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')  55 
 56 
 57 def max_pool_2x2(x):  58     return tf.nn.max_pool(x, ksize=[1,2,2,1], strides=[1, 2, 2, 1], padding='SAME')  59 # 完成卷积池化函数定义
 60 
 61 
 62 # 开始定义神经网络结构定义
 63 # 第一层卷积,卷积在每一个5x5的patch中算出32个特征
 64 W_conv1 = weight_variable([5, 5, 1, 32])  65 b_conv1 = bias_variable([32])  66 x_image = tf.reshape(x, [-1, 28, 28, 1])  67 # 第二、第3维对应图片的宽、高,最后一维表明图片的颜色通道数(由于是灰度图因此这里的通道数为1,若是是rgb彩色图,则为3)
 68 h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)  69 h_pool1 = max_pool_2x2(h_conv1)  70 
 71 # 第二层卷积,每一个5x5的patch会获得64个特征
 72 W_conv2 = weight_variable([5, 5, 32, 64])  73 b_conv2 = bias_variable([64])  74 h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)  75 h_pool2 = max_pool_2x2(h_conv2)  76 
 77 # 有1024个神经元的全链接层,此时图片大小为7*7
 78 W_fc1 = weight_variable([7*7*64, 1024])  79 b_fc1 = bias_variable([1024])  80 h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])  81 h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)  82 
 83 # 为了减小过拟合,在输出层以前加入dropout。用一个placeholder表明一个神经元的输出在dropout中保持不变的几率。
 84 # 这样能够在训练过程当中启用dropout,在测试过程当中关闭dropout。
 85 keep_prob = tf.placeholder(tf.float32)  86 h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)  87 # softmax输出层
 88 W_fc2 = weight_variable([1024, 26])  89 b_fc2 = bias_variable([26])  90 y_conv = tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)  91 # 应为 y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)
 92 # 完成神经网络结构定义
 93 
 94 # 开始定义训练和评估操做
 95 # 用更加复杂的ADAM优化器来作梯度最速降低,在feed_dict中加入额外的参数keep_prob来控制dropout比例
 96 cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y_conv))  97 train_step = tf.train.AdamOptimizer(1e-6).minimize(cross_entropy)  98 correct_prediction = tf.equal(tf.argmax(y_conv, 1), tf.argmax(y_, 1))  99 accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) 100 # 完成训练和评估操做的定义
101 
102 # 开始定义储存器操做并装载已经训练过的神经网络
103 saver = tf.train.Saver(write_version=tf.train.SaverDef.V1) 104 sess = tf.InteractiveSession() 105 saver.restore(sess, "cnnres/model.ckpt") 106 # sess.run(tf.global_variables_initializer())
107 # 完成定义储存器操做和装载神经网络
108 
109 # 开始对训练集进行循环训练
110 for k in range(20): 111     for i in range(55):  # 为减小训练时间,下降迭代次数
112         x_datap = x_data[i*26:(i+1)*26, 0:28*28] 113         y_datap = y_data[i*26:(i+1)*26, 0:26] 114         for j in range(3000): 115             if j % 100 == 0: 116                 train_accuracy = accuracy.eval(feed_dict={x: x_data, y_: y_data, keep_prob: 1.0}) 117                 print("step %d, training accuracy %g"%(i, train_accuracy)) 118             train_step.run(feed_dict={x: x_datap, y_: y_datap, keep_prob: 0.5}) 119 # if train_accuracy >= 0.942:
120 # train_step = tf.train.AdamOptimizer(1e-6).minimize(cross_entropy)
121 # if train_accuracy <= 0.9:
122 # train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
123         if train_accuracy >= 0.95: 124             saver_path = saver.save(sess, "cnnres/model.ckpt") 125             print('Save the par in', saver_path) 126 # 完成训练和储存过程

 

备注:

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张表的同一行,再进行手工合并。而第二张预期输出表须要使用其它方法进行构造,此处不给出相关代码。

 

测试代码:

 1 import tensorflow as tf  2 import numpy as np  3 from PIL import Image  4 import matplotlib.pyplot as plt  5 # 开始读取测试图片
 6 
 7 
 8 def ImageToMatrix(filename):  9     im = Image.open(filename)  10     width, height = im.size  11     im = im.convert("L")  12     data = im.getdata()  13     data = np.matrix(data, dtype='float')/255.0
 14     new_data = np.reshape(data, (height, width))  15     return new_data  16 
 17 def ImageToMatrix2(ima):  18     width, height = ima.size  19     ima = ima.convert("L")  20     data = ima.getdata()  21     data = np.matrix(data, dtype='float')/255.0
 22     new_data = np.reshape(data, (height, width))  23     return new_data  24 
 25 def MatrixToImage(data):  26     data = data*255
 27     new_im = Image.fromarray(data.astype(np.uint8))  28     return new_im  29 
 30 
 31 test_pic = ImageToMatrix('test.png')  32 
 33 # 完成测试图片读取
 34 # -------------------------
 35 # 开始处理测试图片
 36 # 开始寻找图片四边
 37 hang, lie = np.shape(test_pic)  38 for top in range(0, hang):  39     if np.min(test_pic[top, :]) != 1:  40         break
 41 for bot in range(hang-1, 0, -1):  42     if np.min(test_pic[bot, :]) != 1:  43         break
 44 for left in range(0, lie):  45     if np.min(test_pic[:, left]) != 1:  46         break
 47 for right in range(lie - 1, 0, -1):  48     if np.min(test_pic[:, right]) != 1:  49         break
 50 new_test_pic = test_pic[top:bot, left:right]  51 # 完成图片四边寻找
 52 # 开始进行图片尺寸转换
 53 pic = MatrixToImage(new_test_pic)  54 pic2 = pic.resize((28, 28))  55 test_data = ImageToMatrix2(pic2)  56 test_data = np.reshape(test_data, (1, 784))  57 # 完成图片尺寸转换
 58 
 59 # 完成测试图片的处理
 60 # --------------------------
 61 # 开始定义神经网络结构
 62 
 63 # 定义占位符x和y_
 64 x = tf.placeholder(tf.float32, shape=[None, 784])  65 y_ = tf.placeholder(tf.float32, shape=[None, 26])  66 
 67 
 68 # 开始定义用于初始化的两个函数
 69 def weight_variable(shape):  70     initial = tf.truncated_normal(shape, stddev=0.1)  71     return tf.Variable(initial)  72 
 73 
 74 def bias_variable(shape):  75     initial = tf.constant(0.1, shape=shape)  76     return tf.Variable(initial)  77 
 78 # 完成初始化函数定义
 79 
 80 
 81 # 开始定义卷积和池化的函数
 82 # 卷积使用1步长(stride size),0边距(padding size)的模板,保证输出和输入大小相同
 83 # 池化用简单传统的2x2大小的模板作max pooling,所以输出的长宽会变为输入的一半
 84 
 85 
 86 def conv2d(x, W):  87     return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')  88 
 89 
 90 def max_pool_2x2(x):  91     return tf.nn.max_pool(x, ksize=[1,2,2,1], strides=[1, 2, 2, 1], padding='SAME')  92 # 完成卷积池化函数定义
 93 
 94 
 95 # 开始定义神经网络结构定义
 96 # 第一层卷积,卷积在每一个5x5的patch中算出32个特征
 97 W_conv1 = weight_variable([5, 5, 1, 32])  98 b_conv1 = bias_variable([32])  99 x_image = tf.reshape(x, [-1, 28, 28, 1]) 100 # 第二、第3维对应图片的宽、高,最后一维表明图片的颜色通道数(由于是灰度图因此这里的通道数为1,若是是rgb彩色图,则为3)
101 h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1) 102 h_pool1 = max_pool_2x2(h_conv1) 103 
104 # 第二层卷积,每一个5x5的patch会获得64个特征
105 W_conv2 = weight_variable([5, 5, 32, 64]) 106 b_conv2 = bias_variable([64]) 107 h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2) 108 h_pool2 = max_pool_2x2(h_conv2) 109 
110 # 有1024个神经元的全链接层,此时图片大小为7*7
111 W_fc1 = weight_variable([7*7*64, 1024]) 112 b_fc1 = bias_variable([1024]) 113 h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64]) 114 h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1) 115 
116 # 为了减小过拟合,在输出层以前加入dropout。用一个placeholder表明一个神经元的输出在dropout中保持不变的几率。
117 # 这样能够在训练过程当中启用dropout,在测试过程当中关闭dropout。
118 keep_prob = tf.placeholder(tf.float32) 119 h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob) 120 # softmax输出层
121 W_fc2 = weight_variable([1024, 26]) 122 b_fc2 = bias_variable([26]) 123 y_conv = tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2) 124 # 应为 y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)
125 # 完成神经网络结构定义
126 
127 # 开始定义训练和评估操做
128 # 用更加复杂的ADAM优化器来作梯度最速降低,在feed_dict中加入额外的参数keep_prob来控制dropout比例
129 cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y_conv)) 130 train_step = tf.train.AdamOptimizer(1e-6).minimize(cross_entropy) 131 correct_prediction = tf.equal(tf.argmax(y_conv, 1), tf.argmax(y_, 1)) 132 accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) 133 # 完成训练和评估操做的定义
134 
135 # 开始定义储存器操做并装载已经训练过的神经网络
136 saver = tf.train.Saver(write_version=tf.train.SaverDef.V1) 137 sess = tf.InteractiveSession() 138 saver.restore(sess, "cnnres/model.ckpt") 139 # sess.run(tf.global_variables_initializer())
140 # 完成定义储存器操做和装载神经网络
141 
142 # 开始对神经网络进行输入测试
143 res = sess.run(y_conv, feed_dict={x: test_data, keep_prob: 1.0}) 144 temp = np.argmax(res) 145 letter = chr(97+temp) 146 print('The test letter is '+letter) 147 # 完成测试

 

备注:

1.要求已经被训练完成的模型储存在cnnres/model.ckpt

2.预测函数为:res = sess.run(y_conv, feed_dict={x: test_data, keep_prob: 1.0})

不要试图计算y_占位符的值,那是用于训练的,不是用于结果预测的

对CNN的效果备注和研究:

1.在训练集为较粗字体的状况下测试图片必须相应采用较粗字体,不然结果不好

相关文章
相关标签/搜索