• 在学习模式识别理论中的模板匹配以及贝叶斯算法的基础上，利用模板匹配算法和贝叶斯分类决策算法，在VC++6．0开发环境中设计了一个手写数字识别系统。该系统采用6×6和8×8两种等间距网格模板提取手写数字的特征，以...
• 设计了一种基于matlab的手写数字识别系统，全面覆盖多种分类器，有Fisher线性判别，贝叶斯分类器，神经网络，k近邻等等线性与非线性的分类器，识别的准确率较高，具体依据各个算法的不同，可以在此基础上进行改进。
• Tensorflow VGG网络构建手写数字识别系统设计 1、建立VGG16模型 class VGG16_Mode(): """ create vgg16 network use tensorflow VGG16 network structure: (conv 3x3 64)=>(conv 3x3 64, pool/2) ...
Tensorflow VGG网络构建手写数字识别系统设计

1、建立VGG16模型

class VGG16_Mode():
""" create vgg16 network use tensorflow
VGG16 network structure:
(conv 3x3 64)=>(conv 3x3 64, pool/2)
(conv 3x3 128)=>(conv 3x3 128, pool/2)
(conv 3x3 256)=>(conv 3x3 256)=>(conv 3x3 256)=>(conv 3x3 256, pool/2)
(conv 3x3 512)=>(conv 3x3 512)=>(conv 3x3 512)=>(conv 3x3 512, pool/2)
(fc 4096)=>(fc 4096)=>(fc classes)
"""

def variable_summaries(self, var, name):
with tf.name_scope('summaries'):
tf.summary.histogram(name, var)
mean = tf.reduce_mean(var)
tf.summary.scalar('mean/' + name, mean)
stddev = tf.sqrt(tf.reduce_mean(tf.square(var - mean)))
tf.summary.scalar('stddev/' + name, stddev)

def conv_layer(self, data, ksize, stride, name, w_biases = False,padding = "SAME"):
with tf.variable_scope(name) as scope:
with tf.name_scope(name):
with tf.name_scope("weights"):
w_init = tf.contrib.layers.xavier_initializer()
w = tf.get_variable(shape= ksize, initializer= w_init,name= 'w')
self.variable_summaries(w, name + "/weights")
with tf.name_scope("biases"):
biases = tf.Variable(tf.constant(0.0, shape=[ksize[3]], dtype=tf.float32), 'biases')
self.variable_summaries(biases, name + "/biases")
with tf.name_scope("Wx_plus_b"):
if w_biases == False:
else:

# 记录神经网络节点输出在经过激活函数之后的分布。
tf.summary.histogram(name + '/activations', cov)
return cov

def pool_layer(self, data, ksize, stride, name, padding= 'VALID'):
with tf.variable_scope(name) as scope:
return max_pool

def flatten(self,data):
[a,b,c,d] = data.shape
ft = tf.reshape(data,[-1,b*c*d])
return ft

def fc_layer(self,data,name,fc_dims):
with tf.variable_scope(name) as scope:
with tf.name_scope(name):
with tf.name_scope("weights"):
w_init = tf.contrib.layers.xavier_initializer()
w = tf.get_variable(shape=[data.shape[1],fc_dims],name= 'w',initializer=w_init)
self.variable_summaries(w, name + "/weights")
with tf.name_scope("biases"):
biases = tf.Variable(tf.constant(0.0, shape=[fc_dims], dtype=tf.float32), 'biases')
self.variable_summaries(biases, name + "/biases")
with tf.name_scope("Wx_plus_b"):
fc = tf.nn.relu(tf.matmul(data,w)+ biases)
tf.summary.histogram(name + '/pre_activations', tf.matmul(data,w)+ biases)

# 记录神经网络节点输出在经过激活函数之后的分布。
tf.summary.histogram(name + '/activations', fc)
return fc

def finlaout_layer(self,data,name,fc_dims):
with tf.variable_scope(name, reuse=tf.AUTO_REUSE):
with tf.name_scope(name):
with tf.name_scope("weights"):
w_init = tf.contrib.layers.xavier_initializer()
w = tf.get_variable(shape=[data.shape[1],fc_dims],name= 'w',initializer=w_init)
self.variable_summaries(w, name + "/weights")
with tf.name_scope("biases"):
biases = tf.Variable(tf.constant(0.0, shape=[fc_dims], dtype=tf.float32), 'biases')
self.variable_summaries(biases, name + "/biases")
with tf.name_scope("Wx_plus_b"):
fc = tf.nn.softmax(tf.matmul(data,w)+ biases)
tf.summary.histogram(name + '/pre_activations', tf.matmul(data,w)+ biases)

# 记录神经网络节点输出在经过激活函数之后的分布。
tf.summary.histogram(name + '/activations', fc)
return fc

def model_bulid(self, height, width, channel,classes):

with tf.name_scope("input"):
x = tf.placeholder(dtype= tf.float32, shape = [None,height,width,channel])
y = tf.placeholder(dtype= tf.float32 ,shape=[None,classes])
tf.summary.image("input", x, 50)
# conv 1 ,if image Nx465x128x1 ,(conv 3x3 64)=>(conv 3x3 64, pool/2)
with tf.name_scope("conv1"):
conv1_2 = tf.nn.relu(self.conv_layer(conv1_1,ksize=[3,3,64,64],stride=[1,1,1,1],padding="SAME",name="conv1_2")) # Nx465x128x1 ==>   Nx465x128x64
pool1_1 = self.pool_layer(conv1_2,ksize=[1,2,2,1],stride=[1,2,2,1],name="pool1_1") # N*232x64x64

# conv 2,(conv 3x3 128)=>(conv 3x3 128, pool/2)
with tf.name_scope("conv2"):
pool2_1 = self.pool_layer(conv2_2,ksize=[1,2,2,1],stride=[1,2,2,1],name="pool2_1") # Nx116x32x128

# conv 3,(conv 3x3 256)=>(conv 3x3 256)=>(conv 3x3 256)=>(conv 3x3 256, pool/2)
with tf.name_scope("conv3"):
pool3_1 = self.pool_layer(conv3_4,ksize=[1,2,2,1],stride=[1,2,2,1],name="pool3_1") # Nx58x16x256

#conv 4,(conv 3x3 512) = > (conv 3x3 512) = > (conv 3x3 512) = > (conv 3x3 512, pool / 2)
with tf.name_scope("conv4"):
pool4_1 = self.pool_layer(conv4_4,ksize=[1,2,2,1],stride=[1,2,2,1],name="pool4_1") # Nx29x8x512

# Flatten
with tf.name_scope("Flatten"):
ft = self.flatten(pool4_1)

# Dense layer,(fc 4096)=>(fc 4096)=>(fc classes)
fc1 = self.fc_layer(ft,fc_dims=4096,name="fc1")
fc2 = self.fc_layer(fc1,fc_dims=4096,name="fc2")
# fc3 = self.fc_layer(fc2,fc_dims=10,name="fc3")

with tf.name_scope("Final_Output"):
finaloutput = self.finlaout_layer(fc2,fc_dims=10,name="final")

# cost
with tf.name_scope("cross_entropy"):
cross_entropy = tf.losses.softmax_cross_entropy(y,finaloutput)
tf.summary.scalar("cross_entropy", cross_entropy)

2、设置训练参数

# optimize
LEARNING_RATE_BASE = 0.0001
LEARNING_RATE_DECAY = 0.000001
LEARNING_RATE_STEP = 1000
#MOVING_AVERAGE_DECAY = 0.99
global_steps = tf.Variable(0, trainable=False)

# 处理滑动平均的命名空间。
#with tf.name_scope("moving_average"):
#variable_averages = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY, global_steps)
#variables_averages_op = variable_averages.apply(tf.trainable_variables())

with tf.name_scope("train"):
learning_rate = tf.train.exponential_decay(LEARNING_RATE_BASE,
global_steps,
LEARNING_RATE_STEP,
LEARNING_RATE_DECAY,
staircase=True)

with tf.variable_scope(tf.get_variable_scope(), reuse=tf.AUTO_REUSE):
optimize = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cross_entropy,global_step=global_steps)

3、使用Tensorboard对训练过程进行监视

with tf.name_scope("Accuracy"):
with tf.name_scope("prediction_label"):
prediction_label = finaloutput
with tf.name_scope("correct_prediction"):
correct_prediction = tf.equal(tf.argmax(prediction_label, 1), tf.argmax(y, 1))
with tf.name_scope("accurary"):
accurary = tf.reduce_mean(tf.cast(correct_prediction, dtype=tf.float32))
with tf.name_scope("correct_times_in_batch"):
correct_times_in_batch = tf.reduce_mean(tf.cast(correct_prediction, dtype=tf.int32))
tf.summary.scalar("Accuracy", accurary)

4、打开会话session，对模型进行训练

self.merged = tf.summary.merge_all()
self.init_sess()
self.writer = tf.summary.FileWriter("log", self.sess.graph)
return dict(
x=x,
y=y,
optimize=optimize,
prediction_label=prediction_label,
correct_times_in_batch=correct_times_in_batch,
cross_entropy=cross_entropy,
accurary=accurary,
global_steps=global_steps,
Flatten=ft
)

def init_sess(self):
init = tf.group(tf.global_variables_initializer(),tf.local_variables_initializer())
self.sess = tf.Session()
self.sess.run(init)

def train_network(self,graph,x_train,y_train):
# Tensorfolw Adding more and more nodes to the previous graph results in a larger and larger memory footprint
# reset graph
tf.reset_default_graph()
self.sess.run(graph['optimize'],feed_dict={graph['x']:x_train, graph['y']:y_train})

def train(self, n_epcho=1000, imgsize=[28,28], chnnels=1, n_classes=10,batch_size=500):
imgsize1, imgsize2 = imgsize

#self.init_sess()
g = self.model_bulid(28, 28, 1, 10)
#writer = g["writer"]
for i in range(n_epcho):
batch_xs, batch_ys = self.mnist.train.next_batch(500)
batch_xs = np.reshape(batch_xs,[-1,28,28,1])
#self.train_network(g, batch_xs, batch_ys)
if i % 1000 == 0:
# 配置运行时需要记录的信息。
#run_options = tf.RunOptions(trace_level=tf.RunOptions.FULL_TRACE)
# 运行时记录运行信息的proto。
summary, _, cross_entropy, step, accuracy = self.sess.run([self.merged,
g["optimize"],
g["cross_entropy"],
g["global_steps"],
g["accurary"]],
feed_dict={g["x"]: batch_xs, g["y"]: batch_ys}
)
#options=run_options,
print("After %d training step(s), loss on training batch is %g." % (int(step/100), cross_entropy))
else:
summary, _, cross_entropy, step, accuracy = self.sess.run([self.merged,
g["optimize"],
g["cross_entropy"],
g["global_steps"],
g["accurary"]],
feed_dict={g["x"]: batch_xs, g["y"]: batch_ys})

self.save_model(g)
self.close()

def close(self):
self.sess.close()
self.writer.close()

def save_model(self, graph):

export_path = "pb_model/1"
if os.path.exists(export_path):
os.system("rm -rf "+ export_path)
print("Export the model to {}".format(export_path))

# 构建需要在新会话中恢复的变量的 TensorInfo protobuf
X_TensorInfo = sm.utils.build_tensor_info(graph["x"])
y_true_TensorInfo = sm.utils.build_tensor_info(graph["y"])

features_TensorInfo = sm.utils.build_tensor_info(graph["Flatten"])
y_pred_cls_TensorInfo = sm.utils.build_tensor_info(graph["prediction_label"])
accu_TensorInfo = sm.utils.build_tensor_info(graph["accurary"])
# 构建 SignatureDef protobuf
model_signature = sm.signature_def_utils.build_signature_def(
inputs={'input_1': X_TensorInfo,
'input_2': y_true_TensorInfo},
outputs={'output_1': features_TensorInfo,
'output_2': y_pred_cls_TensorInfo,
'output_3': accu_TensorInfo},method_name=signature_constants.PREDICT_METHOD_NAME)

try:
legacy_init_op = tf.group(
tf.tables_initializer(), name='legacy_init_op')
builder = saved_model_builder.SavedModelBuilder(export_path)
self.sess, [tag_constants.SERVING],
clear_devices=True,
signature_def_map={
signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY:
model_signature,
},
legacy_init_op=legacy_init_op)

builder.save()
except Exception as e:
print("Fail to export saved model, exception: {}".format(e))

5、开始训练

vgg_model = VGG16_Mode()  # 创建模型
vgg_model.train(n_epcho=20000)  # 训练模型

6、加载模型

#加载pb模型
session = tf.Session(graph=tf.Graph())
model_file_path = "model"

model_graph_signature = list(meta_graph.signature_def.items())[0][1]
output_tensor_names = []
output_op_names = []
for output_item in model_graph_signature.outputs.items():
output_op_name = output_item[0]
output_op_names.append(output_op_name)
output_tensor_name = output_item[1].name
output_tensor_names.append(output_tensor_name)
sentences = {}
# 测试pb模型
sentences["input_1"] = data
sentences["input_2"] = labels
feed_dict_map = {}
for input_item in model_graph_signature.inputs.items():
input_op_name = input_item[0]
input_tensor_name = input_item[1].name
feed_dict_map[input_tensor_name] = sentences[input_op_name]

result = session.run(output_tensor_names, feed_dict=feed_dict_map)
return result

7、模型评估

show_function = ShowResult()
show_example = show_function.show(img_data=mnist.test.images,
img_labels=mnist.test.labels,
y_pred=result[1],
show_example_errors=True,
show_confusion_matrix=True,
show_exmaple_random=True)

from performace_evaluation import chswn
evaluation = chswn()
classes=[0,1,2,3,4,5,6,7,8,9]
y_predict = evaluation.label_binarize_convert(np.argmax(result[1],axis=1), classes)
evaluation.Average_precision_score(mnist.test.labels, y_predict, classes)
evaluation.Precision_Recall_curve_to_multi_class(classes=classes)

8、实验结果


展开全文
• 基于卷积神经网络的手写数字识别系统设计（调用USB摄像头） ** 本科毕业设计做的就是这个，所以想了想就在这里写一下。 至于讲述卷积神经网络以及图像处理的部分，在网上一搜能够找到打把的资料，这里就不多说，直接...
**
基于卷积神经网络的手写数字识别系统设计（调用USB摄像头）
**
本科毕业设计做的就是这个，所以想了想就在这里写一下。
至于讲述卷积神经网络以及图像处理的部分，在网上一搜能够找到打把的资料，这里就不多说，直接放毕设所使用的代码。
卷积神将网络的部分代码：
from __future__ import print_function
import keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras import backend as K
import time

# batch大小，每处理128个样本进行一次梯度更新
batch_size = 128
# 类别数
num_classes = 10
# 迭代次数
epochs = 20

# input image dimensions
# 28x28 图像
img_rows, img_cols = 28, 28

(x_train, y_train), (x_test, y_test) = mnist.load_data()
# -x_train.shape:(6000, 28, 28)
# -x_test.shape:(1000, 28, 28)

#我们知道彩色图像一般会有Width, Height, Channels，而“channels_first”或“channels_last”
# ，则代表数据的通道维的位置。该参数是Keras 1.x中的image_dim_ordering，“channels_last”
# 对应原本的“tf”，“channels_first”对应原本的“th”。以128x128x128的数据为例，
# “channels_first”应将数据组织为（3,128,128,128），
# 而“channels_last”应将数据组织为（128,128,128,3）。
# 该参数的默认值是~/.keras/keras.json中设置的值，若从未设置过，则为“channels_last”。
if K.image_data_format() == 'channels_first':
# -x_train.shape[0]=6000
x_train = x_train.reshape(x_train.shape[0], 1, img_rows, img_cols)
# -x_train.shape:(60000, 1, 28, 28)
x_test = x_test.reshape(x_test.shape[0], 1, img_rows, img_cols)
# x_test.shape:(10000, 1, 28, 28)
# 单通道灰度图像,channel=1
input_shape = (1, img_rows, img_cols)
else:
x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1)
x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1)
input_shape = (img_rows, img_cols, 1)

# 数据转为float32型
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
# 归一化
x_train /= 255
x_test /= 255
print('x_train shape:', x_train.shape)

# 标签转换为独热码
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)

# 构建模型
model = Sequential()
# 第一层为二维卷积层
# 32 为filters卷积核的数目，也为输出的维度
# kernel_size 卷积核的大小，3x3
# 激活函数选为relu
# 第一层必须包含输入数据规模input_shape这一参数，后续层不必包含
# 再加一层卷积，64个卷积核
# 加最大值池化
# 加Dropout，断开神经元比例为25%

在MNIST上23代训练结果为99.44%
调用摄像头的部分代码：
import cv2
import numpy as np
import cv2 as cv

path = './CNN.h5'

def findRoi(frame, thresValue):
rois = []
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
gray2 = cv2.dilate(gray,None,iterations=2)
gray2 = cv2.erode(gray2,None,iterations=2)
edges = cv2.absdiff(gray,gray2)
x = cv2.Sobel(edges,cv2.CV_16S,1,0)
y = cv2.Sobel(edges,cv2.CV_16S,0,1)
absX = cv2.convertScaleAbs(x)
absY = cv2.convertScaleAbs(y)
ret, ddst = cv2.threshold(dst,thresValue,255,cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(ddst,cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for c in contours:
x, y, w, h = cv2.boundingRect(c)
if w > 10 and h > 20:
rois.append((x,y,w,h))
return rois, edges

img_rows, img_cols = 28, 28
cap = cv2.VideoCapture(1)
count = 0


下图展示用摄像头识别的效果图：
（这里只是放的截图，实际上是每30ms读取一帧，是实时变化的，另外下图放的是装入GUI的识别效果）当然，这里为了方便用的白纸黑字，完全可以用其他颜色的字体。
转载注明出处，需要完整代码可以加qq:2607981163（有偿）


展开全文
• 内容摘要：本文论述并设计实现了一个自由手写数字识别系统。文中首先对待识别数字的预处理进行了介绍，包括二值化、噪声处理、图像分割、归一化、细化等图像处理方法；其次，探讨了数字字符特征向量的提取；最后...
内容摘要：本文论述并设计实现了一个自由手写体数字识别系统。文中首先对待识别数字的预处理进行了介绍，包括二值化、噪声处理、图像分割、归一化、细化等图像处理方法；其次，探讨了数字字符特征向量的提取；最后采用了bp神经网络算法,并以MATLAB作为编程工具实现了具有友好的图形用户界面的自由手写体数字识别系统。实验结果表明，本方法具有较高的识别率，并具有较好的抗噪性能。

目 录

内容摘要……...............................................................................................4
关键字……………………………………………………………………...4
Abstract……………………………………………………………………..5
Keywords…………………………………………………………………...5
第一章 绪论...6
1.1  字符识别概述………………………………………………………..6
1.2  数字识别研究的目的及意义………………………………………..6
1.3  手写数字识别的典型应用…………………………………………..7
1.4  国内外研究现状……………………………………………………..8
1.5  手写体数字识别系统概述…………………………………………10
1.6  文章结构……………………………………………………………11
第二章  手写体数字识别中预处理技术...13
2.1  图像灰度化…………………………………………………………13
2.2  图像二值化…………………………………………………………14
2.3  图像反色……………………………………………………………16
2.4  图像去噪声…………………………………………………………16
2.5  数字分割……………………………………………………………17
2.6  数字归一化…………………………………………………………18
2.7  数字细化……………………………………………………………21
第三章 手写体数字识别中特征值提取技术...25
3.1  特征提取概述………………………………………………………25
3.2  手写体字符特征提取方法概述……………………………………27
3.3  手写体数字识别中的结构特征提取………………………………29
3.4  手写体数字识别中的统计特征提取……………………………….31
第四章  人工神经网络分类器...32
4.1  人工神经网络概述…………………………………………………32
4.2  BP神经网络概述…………………………………………………..33
4.3  本文的神经网络结构设计…………………………………………34

第五章  系统实现与结果分析...39
5.1  系统实现……………………………………………………………39
5.1.1  系统实现环境...39
5.1.2  系统处理流程图及主要工作...40
5.1.3  系统界面...41
5.2  结果分析……………………………………………………………..42
第六章   结束语...43
参考文献...44
致谢...46
点击下载

展开全文
• 本文使用Tensorflow框架进行Python编程实现基于卷积神经网络的手写数字识别算法，并将其封装在一个GUI界面中，最终，设计并实现了一个手写数字识别系统
手写数字识别算法的设计与实现
本文使用python基于TensorFlow设计手写数字识别算法，并编程实现GUI界面，构建手写数字识别系统。这是本人的本科毕业论文课题，当然，这个也是机器学习的基本问题。本博文不会以论文的形式展现，而是以编程实战完成机器学习项目的角度去描述。
项目要求：本文主要解决的问题是手写数字识别，最终要完成一个识别系统。
设计识别率高的算法，实现快速识别的系统。
1 LeNet-5模型的介绍
本文实现手写数字识别，使用的是卷积神经网络，建模思想来自LeNet-5，如下图所示：
这是原始的应用于手写数字识别的网络，我认为这也是最简单的深度网络。
LeNet-5不包括输入，一共7层，较低层由卷积层和最大池化层交替构成，更高层则是全连接和高斯连接。
LeNet-5的输入与BP神经网路的不一样。这里假设图像是黑白的，那么LeNet-5的输入是一个32*32的二维矩阵。同时，输入与下一层并不是全连接的，而是进行稀疏连接。本层每个神经元的输入来自于前一层神经元的局部区域(5×5)，卷积核对原始图像卷积的结果加上相应的阈值，得出的结果再经过激活函数处理，输出即形成卷积层（C层）。卷积层中的每个特征映射都各自共享权重和阈值，这样能大大减少训练开销。降采样层（S层）为减少数据量同时保存有用信息，进行亚抽样。
第一个卷积层（C1层）由6个特征映射构成，每个特征映射是一个28×28的神经元阵列，其中每个神经元负责从5×5的区域通过卷积滤波器提取局部特征。一般情况下，滤波器数量越多，就会得出越多的特征映射，反映越多的原始图像的特征。本层训练参数共6×(5×5+1)=156个，每个像素点都是由上层5×5=25个像素点和1个阈值连接计算所得，共28×28×156=122304个连接。
S2层是对应上述6个特征映射的降采样层（pooling层）。pooling层的实现方法有两种，分别是max-pooling和mean-pooling，LeNet-5采用的是mean-pooling，即取n×n区域内像素的均值。C1通过2×2的窗口区域像素求均值再加上本层的阈值，然后经过激活函数的处理，得到S2层。pooling的实现，在保存图片信息的基础上，减少了权重参数，降低了计算成本，还能控制过拟合。本层学习参数共有1*6+6=12个，S2中的每个像素都与C1层中的2×2个像素和1个阈值相连，共6×(2×2+1)×14×14=5880个连接。
S2层和C3层的连接比较复杂。C3卷积层是由16个大小为10×10的特征映射组成的，当中的每个特征映射与S2层的若干个特征映射的局部感受野（大小为5×5）相连。其中，前6个特征映射与S2层连续3个特征映射相连，后面接着的6个映射与S2层的连续的4个特征映射相连，然后的3个特征映射与S2层不连续的4个特征映射相连，最后一个映射与S2层的所有特征映射相连。此处卷积核大小为5×5，所以学习参数共有6×(3×5×5+1)+9×(4×5×5+1)+1×(6×5×5+1)=1516个参数。而图像大小为28×28，因此共有151600个连接。
S4层是对C3层进行的降采样，与S2同理，学习参数有16×1+16=32个，同时共有16×(2×2+1)×5×5=2000个连接。
C5层是由120个大小为1×1的特征映射组成的卷积层，而且S4层与C5层是全连接的，因此学习参数总个数为120×(16×25+1)=48120个。
F6是与C5全连接的84个神经元，所以共有84×(120+1)=10164个学习参数。
卷积神经网络通过通过稀疏连接和共享权重和阈值，大大减少了计算的开销，同时，pooling的实现，一定程度上减少了过拟合问题的出现，非常适合用于图像的处理和识别。
2 手写数字识别算法模型的构建
2.1 各层设计
有了第一节的基础知识，在这基础上，进行完善和改进。

输入层设计

输入为28×28的矩阵，而不是向量。

激活函数的选取

Sigmoid函数具有光滑性、鲁棒性和其导数可用自身表示的优点，但其运算涉及指数运算，反向传播求误差梯度时，求导又涉及乘除运算，计算量相对较大。同时，针对本文构建的含有两层卷积层和降采样层，由于sgmoid函数自身的特性，在反向传播时，很容易出现梯度消失的情况，从而难以完成网络的训练。因此，本文设计的网络使用ReLU函数作为激活函数。
ReLU的表达式：

卷积层设计

本文设计卷积神经网络采取的是离散卷积，卷积步长为1，即水平和垂直方向每次运算完，移动一个像素。卷积核大小为5×5。

降采样层

本文降采样层的pooling方式是max-pooling，大小为2×2。

输出层设计

输出层设置为10个神经网络节点。数字0~9的目标向量如下表所示：
2.2 网络模型的总体结构

其实，本文网络的构建，参考自TensorFlow的手写数字识别的官方教程的，读者有兴趣也可以详细阅读。
2.3 编程实现算法
本文使用Python，调用TensorFlow的api完成手写数字识别的算法。
注：本文程序运行环境是：Win10,python3.5.2。当然，也可以在Linux下运行，由于TensorFlow对py2和py3兼容得比较好，在Linux下可以在python2.7中运行。
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
"""
Created on Fri Feb 17 19:50:49 2017

@author: Yonghao Huang
"""

#import modules
import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf
import time
from datetime import timedelta
import math
from tensorflow.examples.tutorials.mnist import input_data

def new_weights(shape):
return tf.Variable(tf.truncated_normal(shape,stddev=0.05))
def new_biases(length):
return tf.Variable(tf.constant(0.1,shape=length))
def conv2d(x,W):
def max_pool_2x2(inputx):

#import data
data = input_data.read_data_sets("./data", one_hot=True)  # one_hot means [0 0 1 0 0 0 0 0 0 0] stands for 2

print("Size of:")
print("--Training-set:\t\t{}".format(len(data.train.labels)))
print("--Testing-set:\t\t{}".format(len(data.test.labels)))
print("--Validation-set:\t\t{}".format(len(data.validation.labels)))
data.test.cls = np.argmax(data.test.labels,axis=1)   # show the real test labels:  [7 2 1 ..., 4 5 6], 10000values

x = tf.placeholder("float",shape=[None,784],name='x')
x_image = tf.reshape(x,[-1,28,28,1])

y_true = tf.placeholder("float",shape=[None,10],name='y_true')
y_true_cls = tf.argmax(y_true,dimension=1)
# Conv 1
layer_conv1 = {"weights":new_weights([5,5,1,32]),
"biases":new_biases([32])}
h_conv1 = tf.nn.relu(conv2d(x_image,layer_conv1["weights"])+layer_conv1["biases"])
h_pool1 = max_pool_2x2(h_conv1)
# Conv 2
layer_conv2 = {"weights":new_weights([5,5,32,64]),
"biases":new_biases([64])}
h_conv2 = tf.nn.relu(conv2d(h_pool1,layer_conv2["weights"])+layer_conv2["biases"])
h_pool2 = max_pool_2x2(h_conv2)
# Full-connected layer 1
fc1_layer = {"weights":new_weights([7*7*64,1024]),
"biases":new_biases([1024])}
h_pool2_flat = tf.reshape(h_pool2,[-1,7*7*64])
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat,fc1_layer["weights"])+fc1_layer["biases"])
# Droupout Layer
keep_prob = tf.placeholder("float")
h_fc1_drop = tf.nn.dropout(h_fc1,keep_prob)
# Full-connected layer 2
fc2_layer = {"weights":new_weights([1024,10]),
"biases":new_weights([10])}
# Predicted class
y_pred = tf.nn.softmax(tf.matmul(h_fc1_drop,fc2_layer["weights"])+fc2_layer["biases"])  # The output is like [0 0 1 0 0 0 0 0 0 0]
y_pred_cls = tf.argmax(y_pred,dimension=1)  # Show the real predict number like '2'
# cost function to be optimized
cross_entropy = -tf.reduce_mean(y_true*tf.log(y_pred))
# Performance Measures
correct_prediction = tf.equal(y_pred_cls,y_true_cls)
accuracy = tf.reduce_mean(tf.cast(correct_prediction,"float"))
with tf.Session() as sess:
init = tf.global_variables_initializer()
sess.run(init)
train_batch_size = 50
def optimize(num_iterations):
total_iterations=0
start_time = time.time()
for i in range(total_iterations,total_iterations+num_iterations):
x_batch,y_true_batch = data.train.next_batch(train_batch_size)
feed_dict_train_op = {x:x_batch,y_true:y_true_batch,keep_prob:0.5}
feed_dict_train = {x:x_batch,y_true:y_true_batch,keep_prob:1.0}
sess.run(optimizer,feed_dict=feed_dict_train_op)
# Print status every 100 iterations.
if i%100==0:
# Calculate the accuracy on the training-set.
acc = sess.run(accuracy,feed_dict=feed_dict_train)
# Message for printing.
msg = "Optimization Iteration:{0:>6}, Training Accuracy: {1:>6.1%}"
# Print it.
print(msg.format(i+1,acc))
# Update the total number of iterations performed
total_iterations += num_iterations
# Ending time
end_time = time.time()
# Difference between start and end_times.
time_dif = end_time-start_time
# Print the time-usage
print("Time usage:"+str(timedelta(seconds=int(round(time_dif)))))
test_batch_size = 256
def print_test_accuracy():
# Number of images in the test-set.
num_test = len(data.test.images)
cls_pred = np.zeros(shape=num_test,dtype=np.int)
i = 0
while i < num_test:
# The ending index for the next batch is denoted j.
j = min(i+test_batch_size,num_test)
# Get the images from the test-set between index i and j
images = data.test.images[i:j, :]
# Get the associated labels
labels = data.test.labels[i:j, :]
# Create a feed-dict with these images and labels.
feed_dict={x:images,y_true:labels,keep_prob:1.0}
# Calculate the predicted class using Tensorflow.
cls_pred[i:j] = sess.run(y_pred_cls,feed_dict=feed_dict)
# Set the start-index for the next batch to the
# end-index of the current batch
i = j
cls_true = data.test.cls
correct = (cls_true==cls_pred)
correct_sum = correct.sum()
acc = float(correct_sum) / num_test
# Print the accuracy
msg = "Accuracy on Test-Set: {0:.1%} ({1}/{2})"
print(msg.format(acc,correct_sum,num_test))
# Performance after 10000 optimization iterations


运行结果显示：测试集中准确率大概为99.2%。
我还写了一些辅助函数，可以查看部分识别错误的图片，
还可以查看混淆矩阵，
2.3 实现手写识别系统
最后，将训练好的参数保存，封装进一个GUI界面中，形成一个手写识别系统。
系统中还添加了一点图像预处理的操作，比如灰度化，图像信息的归一化等，更贴近实际应用。
系统可进行快速识别，如下图：
3 总结
本文实现的系统其实是基于卷积神经网络的手写数字识别系统。该系统能快速实现手写数字识别，成功识别率高。缺点：只能正确识别单个数字，图像预处理还不够，没有进行图像分割，读者也可以自行添加，进行完善。
4 收获
本人之前的本科期间，虽然努力学习高数、线性代数和概率论，但是没有认真学习过机器学习，本人是2017年才开始系统学习机器学习相关知识，而且本科毕业论文也选择了相关的课题，虽然比较基础，但是认真完成后，有一种学以致用的满足感，同时也激励着我进行更深入的理论学习和实践探讨，与所有读者共勉。
==================================
2018年5月13日更新
以上是基本网络的设计与基本的实现，可满足入门学习。
相关链接:
========================================
2018年6月6日更新更新！！
python(TensorFlow)实现手写字符识别
此处的“手写字符”，其实指的是notMNIST数据库中的手写字符，其实和MNIST数据库是一样的。这里实现手写字符识别，主要是展示TensorFlow框架的可拓展性很强，具体来说，就是可以通过改动少部分的代码，从而实现一个新的识别功能。
NotMnist数据库
这个数据库和MNIST数据库基本一样，只是把10个数字换成了10个字母，即：A,B,C,D,E,F,G,H,I,J,K
当然，这个数据库的识别难度大一些，因为数据噪声更多一些，详情读者可以搜一搜了解一下。
实战
将NotMNIST数据库下载以后，放在本博文上述的网络中，基本不需要修改代码，直接训练，即可得到一个能识别字符的网络模型。
最后在测试集中的准确率，比MNIST的会低一些，大概为96%左右。
本文也将训练好的网络模型封装在和上述系统相似的GUI系统中，
[外链图片转存失败(img-k7xPyAio-1564543116627)(https://i.imgur.com/59M3NlD.png)]
识别效果还可以！
同样，将卷积卷积层可视化。
[外链图片转存失败(img-tIWWgZB9-1564543116629)(https://i.imgur.com/4awe7NY.png)]
结语
TensorFlow框架可拓展性很强，只要设计好了网络，就能很容易的实现出来；同时，使用基本的CNN识别整体架构也是大同小异的，很多识别任务是通用的。当然，在具体的实践中需要得到接近完美的效果，还是要下很大功夫的！努力学习吧，加油！
（如果你/您有什么有趣的想法，可以在下面留言，如果我也感兴趣同时又有时间的话，我会尝试做一做，_）


展开全文
• 在OpenCV的安装路径下，搜索digits.png，可以得到一张图片，图片大小为1000* 2000,有0-9的10个数字，每5行为一个数字，总共50行，共有5000个手写数字，每个数字块大小为20* 20。 如下图所示： 下面将把这些数字中的...
• 在朋友的强烈建议下，写一篇关于利用CNN卷积神经网络实现基于MATLAB的手写数字识别系统设计的博客。 一、关于卷积神经网络 关于卷积神经网络我写过一篇文章单独介绍，可以参考：手写数字识别问题（3）——详解卷积...
• 基于TensorFlow卷积神经网络的手写数字识别系统的建立 一、知识储备 ①卷积神经网络 ②OpenCV图像处理 ③Tkinter用户界面设计 二、实验代码 （1）模型的训练和保存 import tensorflow as tf import os from ...
• 本文使用python基于TensorFlow设计手写数字识别算法，并编程实现GUI界面，构建手写数字识别系统。这是本人的本科毕业论文课题，当然，这个也是机器学习的基本问题。本博文不会以论文的形式展现，而是以编程实战完成...
• 本文使用python基于TensorFlow设计手写数字识别算法，并编程实现GUI界面，构建手写数字识别系统。文中首先对如何对手写数字图像的获取进行了介绍；其次，对待手写数字图片的预处理的进行了介绍，包括二值化、高斯...
• 机器学习KNN算法手写数字识别系统 下载本文手写数字识别系统代码和课设报告的连接： 摘要 本文手写体数字识别系统的工作主要是运用K最邻近算法实现了对手写体数字的识别，支持上传本地图片和调用摄像头进行拍摄并...
• 手写数字识别是模式识别中一个非常重要和活跃的研究领域，数字识别也不是一项孤立的技术，它所涉及的问题是模式识别的其他领域都无法回避的；应用上，作为一种信息处理手段，字符识别有广阔的应用背景和巨大的市场...
• 设计一个简单的手写数字识别系统，能够识别手写输入的数字1-9。目前像汉王公司推出了一系列的手写笔等产品，通过实现这样的一个简单功能可以有效地学习VC++基于MFC的编程，同时对于手写笔这样的产品的工作原理能够...
• 目录一、OpenCV3对MNIST数据集的解析1.1 MNIST数据集介绍1.2 小端格式和大端格式1.3 小端存储转换代码示例1.4 OpenCV3对图像数据的解析代码示例...结果三、调用训练好的模型进行手写数字识别3.1 代码示例3.2 运行结果...
• 本文论述并设计实现了一个脱机自由手写数字识别系统。文中首先对待识别数字的预处理进行了介绍，包括二值化、平滑滤波、规范化、细化等图像处理方法；其次，探讨了如何提取数字字符的结构特征和笔划特征，并详细地...
• 摘耍：介绍了基于TMS320VC5402的手写数字识别系统和该系统的基本原理，给出了它的硬件原理图和软件设计程序框图。最后描述了所 用的识别算法和改进的训练算法。
• 本文使用Python基于TensorFlow 卷积神经网络设计手写数字识别算法，并编程实现GUI 界面，构建手写数字识别系统。本系统界面设计友好，功能完善。通过测试，本识别系统对于较规范的手写体数字的识别达到了很好的识别...
• 源码:...一、课题介绍 该课题为基于MATLAB光流法OCR的手写数字识别系统。带一个GUI界面。可以识别单独字符，也可以识别连续的字符串。 二、GUI界面设计及预期图 ...
• 本文使用python基于TensorFlow设计手写数字识别算法，并编程实现GUI界面，构建手写数字识别系统。这是本人的本科毕业论文课题，当然，这个也是机器学习的基本问题。本博文不会以论文的形式展现，而是以编程实战完成...

...