300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > Python 3 利用机器学习模型 进行手写体数字检测

Python 3 利用机器学习模型 进行手写体数字检测

时间:2019-01-01 16:09:49

相关推荐

Python 3 利用机器学习模型 进行手写体数字检测

0.引言

介绍了如何生成手写体数字的数据,提取特征,借助 sklearn 机器学习模型建模,进行识别手写体数字 1-9 模型的建立和测试。

用到的几种模型:

1. LR,Logistic Regression, (线性模型)中的逻辑斯特回归

2. Linear SVC,Support Vector Classification,(支持向量机)中的线性支持向量分类

3. MLPC,Multi-Layer PerceptronClassification, (神经网络)多层感知机分类

4. SGDC,Stochastic Gradient Descent Classification, (线性模型)随机梯度法求解

手写体的识别是一个分类问题,提取图像特征作为模型输入,输出到标记数字 1-9;

主要内容:

1. 生成手写体数字数据集;

2. 提取图像特征存入 CSV;

3. 利用机器学习建立和测试手写体数字识别模型;

(如果你想尝试生成自己的数据集可以参考我的另一篇博客:/AdaminXie/p/8379749.html)

源码上传到了我的GitHub:/coneypo/ML_handwritten_number, 有问题可以留言或者联系我邮箱;

得到不同样本量训练下,几种机器学习模型精度随样本的变化关系曲线:

图 0 不同样本数目下的四种模型的测试精度( 数据集大小从 100 到 5800,间隔 100 )

1.开发环境

python:3.6.3

import PIL, cv2, pandas, numpy, os, csv, random

需要调用的 sklearn 库:

1 from sklearn.linear_model import LogisticRegression# 线性模型中的 Logistic 回归模型2 from sklearn.linear_model import SGDClassifier# 线性模型中的随机梯度下降模型3 from sklearn.svm import LinearSVC # SVM 模型中的线性 SVC 模型4 from sklearn.neural_network import MLPClassifier # 神经网络模型中的多层网络模型

2.整体设计思路

图 1 整体的框架设计

工程的目的,是想利用机器学习模型去训练识别生成的随机验证码图像(单个数字 1-9 ),通过以下三个步骤实现:

1. 生成手写体数据集

2. 提取特征向量写入 CSV

3. sklearn 模型训练和测试

图 2 整体的设计流程

3. 编程过程

3.1 生成多张单个验证码图像 ( generate_folders.py, generate_handwritten_numbers.py )

图 3 生成的多张单个验证码图像

手写体数据集的生成在我的另一篇博客详细介绍:( Link:/AdaminXie/p/8379749.html

思路就是 random 随机生成数字 1-9,然后利用PIL的画笔工具进行画图,对图像进行扭曲,然后根据随机数的真实标记 1-9,保存到对应文件夹内,用标记+序号命名。

1 draw = ImageDraw.Draw(im) # 画笔工具

3.2提取特征向量写入 CSV ( get_features.py )

这一步是提取图像中的特征。生成的单个图像是 30*30 即 900 个像素点的;

为了降低维度,没有选择 900 个像素点每点的灰度作为输入,而是选取了 30 行每行的黑点数,和 30 列每列的黑点数作为输入,这样降到了 60 维。

(a) 提取 900 维特征

(b) 提取 60 维特征

图 4 提取图像特征

特征的提取也比较简单,逐行逐列计算然后计数求和:

1def get_feature(img): 2 # 提取特征 3 # 30*30的图像, 4 5 width, height = img.size 6 7 global pixel_cnt_list 8 pixel_cnt_list=[] 9 10 height = 3011 for y in range(height):12 pixel_cnt_x = 013 for x in range(width):14 # print(img.getpixel((x,y)))15 if img.getpixel((x, y)) == 0: # 黑点16 pixel_cnt_x += 117 18 pixel_cnt_list.append(pixel_cnt_x)19 20 for x in range(width):21 pixel_cnt_y = 022 for y in range(height):23 if img.getpixel((x, y)) == 0: # 黑点24 pixel_cnt_y += 125 26 pixel_cnt_list.append(pixel_cnt_y)27 28 return pixel_cnt_list

所以我们接下来需要做的工作是,遍历访问文件夹 num_1-9 中的所有图像文件,进行特征提取,然后写入 CSV 文件中:

1 with open(path_csv+"tmp.csv", "w", newline="") as csvfile: 2 writer = csv.writer(csvfile) 3 # 访问文件夹 1-9 4 for i in range(1, 10): 5 num_list = os.listdir(path_images + "num_" + str(i)) 6 print(path_images + "num_" + str(i)) 7 print("num_list:", num_list) 8 # 读到图像文件 9 if os.path.isdir(path_images + "num_" + str(i)):10 print("样本个数:", len(num_list))11 sum_images = sum_images + len(num_list)12 13 # Travsel every single image to generate the features14 for j in range(0, (len(num_list))):15 16 # 处理读取单个图像文件提取特征17 img = Image.open(path_images + "num_" + str(i)+"/" + num_list[j])18 get_features_single(img)19 pixel_cnt_list.append(num_list[j][0])20 21 # 写入CSV22 writer.writerow(pixel_cnt_list)

图 5 提取出来的 CSV 文件(前 60 列为输入特征,第 61 列为输出标记)

3.3sklearn 模型训练和测试 ( ml_ana.py, test_single_images.py )

之前的准备工作都做完之后,我们生成了存放着 60 维输入特征和 1 维输出标记的 61 列的 CSV 文件;

然后就可以利用这些数据,交给 sklearn 的机器学习模型进行建模处理。

3.3.1 特征数据加工

第一步需要对 CSV 文件中的数据进行提取,利用 pd.read_csv 进行读取。写入 CSV 时,前 60 列为 60 维的特征向量,第 61 列为输出标记 1-9;

利用前面已经提取好的特征 CSV;

1 # 从 CSV 中读取数据 2 def pre_data(): 3# CSV61维表头名 4column_names = [] 5 6for i in range(0, 60): 7 column_names.append("feature_" + str(i)) 8column_names.append("true_number") 9 10# 读取csv11path_csv = "../data/data_csvs/"12data = pd.read_csv(path_csv + "data_10000.csv", names=column_names)13 14# 提取数据集15global X_train, X_test, y_train, y_test16X_train, X_test, y_train, y_test = train_test_split(17 data[column_names[0:60]],18 data[column_names[60]],19 test_size=0.25, # 75% for 训练,25% for 测试20 random_state=3321 )

利用sklearn库的train_test_split 函数将数据进行分割,

得到训练集数据:X_train, y_train

得到测试集数据:X_test, y_test

3.3.2 模型训练和测试

经过前面一系列的准备工作做完,这里正式开始使用 sklearn 的机器学习模型建模;

调用 sklearn 利用训练数据对模型进行训练,然后利用测试数据进行性能测试,并且保存模型到本地 ( "/data/data_models/model_xxx.m");

ml_ana.py:

1 # created at -01-29 2 # updated at -09-28 3 4 # Author: coneypo 5 # Blog:/AdaminXie 6 # GitHub: /coneypo/ML_handwritten_number 7 8 9 from sklearn.model_selection import train_test_split 10 import pandas as pd 11 12 from sklearn.preprocessing import StandardScaler# 标准化 13 14 # 调用模型 15 from sklearn.linear_model import LogisticRegression # 线性模型中的 Logistic 回归模型 16 from sklearn.svm import LinearSVC# SVM 模型中的线性 SVC 模型 17 from sklearn.neural_network import MLPClassifier# 神经网络模型中的多层网络模型 18 from sklearn.linear_model import SGDClassifier # 线性模型中的随机梯度下降模型 19 20 # 保存模型 21 from sklearn.externals import joblib 22 23 24 # 从 CSV 中读取数据 25 def pre_data(): 26# CSV61维表头名 27column_names = [] 28 29for i in range(0, 60): 30 column_names.append("feature_" + str(i)) 31column_names.append("true_number") 32 33# 读取csv 34path_csv = "../data/data_csvs/" 35data = pd.read_csv(path_csv + "data_10000.csv", names=column_names) 36 37# 提取数据集 38global X_train, X_test, y_train, y_test 39X_train, X_test, y_train, y_test = train_test_split( 40 data[column_names[0:60]], 41 data[column_names[60]], 42 test_size=0.25, # 75% for 训练,25% for 测试 43 random_state=33 44 ) 45 46 47 path_saved_models = "../data/data_models/" 48 49 50 # LR, logistic regression, 逻辑斯特回归分类(线性模型) 51 def way_LR(): 52X_train_LR = X_train 53y_train_LR = y_train 54 55X_test_LR = X_test 56y_test_LR = y_test 57 58# 数据预加工 59# ss_LR = StandardScaler() 60# X_train_LR = ss_LR.fit_transform(X_train_LR) 61# X_test_LR = ss_LR.transform(X_test_LR) 62 63# 初始化LogisticRegression 64LR = LogisticRegression() 65 66# 调用LogisticRegression中的fit()来训练模型参数 67LR.fit(X_train_LR, y_train_LR) 68 69# 使用训练好的模型lr对X_test进行预测 70# 结果储存在y_predict_LR中 71global y_predict_LR 72y_predict_LR = LR.predict(X_test_LR) 73 74# 评分函数 75global score_LR 76score_LR = LR.score(X_test_LR, y_test_LR) 77print("The accurary of LR:", '\t', score_LR) 78 79# 保存模型 80joblib.dump(LR, path_saved_models + "model_LR.m") 81 82return LR 83 84 85 # 多层感知机分类(神经网络) 86 def way_MLPC(): 87X_train_MLPC = X_train 88y_train_MLPC = y_train 89 90X_test_MLPC = X_test 91y_test_MLPC = y_test 92 93# ss_MLPC = StandardScaler() 94# X_train_MLPC = ss_MLPC.fit_transform(X_train_MLPC) 95# X_test_MLPC = ss_MLPC.transform(X_test_MLPC) 96 97MLPC = MLPClassifier(hidden_layer_sizes=(13, 13, 13), max_iter=500) 98MLPC.fit(X_train_MLPC, y_train_MLPC) 99 100global y_predict_MLPC101y_predict_MLPC = MLPC.predict(X_test_MLPC)102 103global score_MLPC104score_MLPC = MLPC.score(X_test_MLPC, y_test_MLPC)105print("The accurary of MLPC:", '\t', score_MLPC)106 107# 保存模型108joblib.dump(MLPC, path_saved_models + "model_MLPC.m")109 110return MLPC111 112 113 # Linear SVC, Linear Supported Vector Classifier, 线性支持向量分类(SVM支持向量机)114 def way_LSVC():115X_train_LSVC = X_train116y_train_LSVC = y_train117 118X_test_LSVC = X_test119y_test_LSVC = y_test120 121# Standard Scaler122# ss_LSVC = StandardScaler()123# X_train_LSVC = ss_LSVC.fit_transform(X_train_LSVC)124# X_test_LSVC = ss_LSVC.transform(X_test_LSVC)125 126LSVC = LinearSVC()127LSVC.fit(X_train_LSVC, y_train_LSVC)128 129global y_predict_LSVC130y_predict_LSVC = LSVC.predict(X_test_LSVC)131 132global score_LSVC133score_LSVC = LSVC.score(X_test_LSVC, y_test_LSVC)134print("The accurary of LSVC:", '\t', score_LSVC)135 136# 保存模型137joblib.dump(LSVC, path_saved_models + "model_LSVC.m")138 139return LSVC140 141 142 # SGDC, stochastic gradient decent 随机梯度下降法求解(线性模型)143 def way_SGDC():144X_train_SGDC = X_train145y_train_SGDC = y_train146 147X_test_SGDC = X_test148y_test_SGDC = y_test149 150# ss_SGDC = StandardScaler()151# X_train_SGDC = ss_SGDC.fit_transform(X_train_SGDC)152# X_test_SGDC = ss_SGDC.transform(X_test_SGDC)153 154SGDC = SGDClassifier(max_iter=5)155 156SGDC.fit(X_train_SGDC, y_train_SGDC)157 158global y_predict_SGDC159y_predict_SGDC = SGDC.predict(X_test_SGDC)160 161global score_SGDC162score_SGDC = SGDC.score(X_test_SGDC, y_test_SGDC)163print("The accurary of SGDC:", '\t', score_SGDC)164 165# 保存模型166joblib.dump(SGDC, path_saved_models + "model_SGDC.m")167 168return SGDC169 170 171 pre_data()172 way_LR()173 way_LSVC()174 way_MLPC()175 way_SGDC()

3.3.3 测试 (test_single_images.py )

对于一张手写体数字,提取特征然后利用保存的模型进行预测;

1 # created at -01-29 2 # updated at -09-28 3 4 # Author: coneypo 5 # Blog:/AdaminXie 6 # GitHub: /coneypo/ML_handwritten_number 7 8 # 利用保存到本地的训练好的模型,来检测单张 image 的标记 9 10 from sklearn.externals import joblib11 from PIL import Image12 13 img = Image.open("../test/test_1.png")14 15 # Get features16 from generate_datebase import get_features17 features_test_png = get_features.get_features_single(img)18 19 path_saved_models = "../data/data_models/"20 21 # LR22 LR = joblib.load(path_saved_models + "model_LR.m")23 predict_LR = LR.predict([features_test_png])24 print("LR:", predict_LR[0])25 26 # LSVC27 LSVC = joblib.load(path_saved_models + "model_LSVC.m")28 predict_LSVC = LSVC.predict([features_test_png])29 print("LSVC:", predict_LSVC[0])30 31 # MLPC32 MLPC = joblib.load(path_saved_models + "model_MLPC.m")33 predict_MLPC = MLPC.predict([features_test_png])34 print("MLPC:", predict_MLPC[0])35 36 # SGDC37 SGDC = joblib.load(path_saved_models + "model_SGDC.m")38 predict_SGDC = SGDC.predict([features_test_png])39 print("SGDC:", predict_SGDC[0])

3.3.4 绘制样本数-精度图像

可以绘图来更加直观的精度:

1 # -01-29 2 # By TimeStamp 3 # cnblogs: /AdaminXie/ 4 # plot_from_csv.py 5 # 从存放样本数-精度的CSV中读取数据,绘制图形 6 7 8 import numpy as np 9 import matplotlib.pyplot as plt10 import pandas as pd11 12 # CSV路径13 path_csv = "F:/***/P_ML_handwritten_number/data/score_csv/"14 15 # 存储x轴坐标16 x_array = []17 18 # 存储精度19 LR_score_arr = []20 LSVC_score_arr = []21 MLPC_score_arr = []22 SGDC_score_arr = []23 24 # 读取CSV数据25 column_names = ["samples", "acc_LR", "acc_LSVC", "acc_MLPC", "acc_SGDC"]26 rd_csv = pd.read_csv(path_csv + "score_100to5800.csv", names=column_names)27 28 print(rd_csv.shape)29 30 for i in range(len(rd_csv)):31x_array.append(float(rd_csv["samples"][i]))32LR_score_arr.append(float(rd_csv["acc_LR"][i]))33LSVC_score_arr.append(float(rd_csv["acc_LSVC"][i]))34MLPC_score_arr.append(float(rd_csv["acc_MLPC"][i]))35SGDC_score_arr.append(float(rd_csv["acc_SGDC"][i]))36 37 ################ 3次线性拟合 ################38 xray = np.array(x_array)39 y_LR = np.array(LR_score_arr)40 y_LSVC = np.array(LSVC_score_arr)41 y_MLPC = np.array(MLPC_score_arr)42 y_SGDC = np.array(SGDC_score_arr)43 44 z1 = np.polyfit(xray, y_LR, 5)45 z2 = np.polyfit(xray, y_LSVC, 5)46 z3 = np.polyfit(xray, y_MLPC, 5)47 z4 = np.polyfit(xray, y_SGDC, 5)48 49 p1 = np.poly1d(z1)50 p2 = np.poly1d(z2)51 p3 = np.poly1d(z3)52 p4 = np.poly1d(z4)53 54 y_LR_vals = p1(xray)55 y_LSVC_vals = p2(xray)56 y_MLPC_vals = p3(xray)57 y_SGDC_vals = p4(xray)58 #################################59 60 # 标明线条说明61 plt.annotate("— LR", xy=(5030, 0.34), color='b', size=12)62 plt.annotate("— LSVC", xy=(5030, 0.26), color='r', size=12)63 plt.annotate("— MLPC", xy=(5030, 0.18), color='g', size=12)64 plt.annotate("— SGDC", xy=(5030, 0.10), color='black', size=12)65 66 # 画拟合曲线67 plt.plot(xray, y_LR_vals, color='b')68 plt.plot(xray, y_LSVC_vals, color='r')69 plt.plot(xray, y_MLPC_vals, color='g')70 plt.plot(xray, y_SGDC_vals, color='black')71 72 # 画离散点73 plt.plot(xray, y_LR, color='b', linestyle='None', marker='.', label='y_test', linewidth=100)74 plt.plot(xray, y_LSVC, color='r', linestyle='None', marker='.', label='y_test', linewidth=0.01)75 plt.plot(xray, y_MLPC, color='g', linestyle='None', marker='.', label='y_test', linewidth=0.01)76 plt.plot(xray, y_SGDC, color='black', linestyle='None', marker='.', label='y_test', linewidth=0.01)77 78 # 绘制y=1参考线79 plt.plot([0, 6000], [1, 1], 'k--')80 81 # 设置y轴坐标范围82 plt.ylim(0, 1.1)83 84 # 标明xy轴85 plt.xlabel('samples')86 plt.ylabel('accuracy')87 88 plt.show()

3.3.4 测试结果

在样本数 sample_num = 50 的情况下,训练 75% 数据,用 25% 的数据即 13 个样本进行测试;

几种模型的测试结果如 图 6 所示,可见除了 SVM 达到 84.7% 的精度之外,其他都在 60-70% 左右;

但是因为只有 50 个样本点,小样本的情况下测试精度的偶然性误差比较大。

图 6 手写体识别的性能分析( 在样本数为 50 的情况下 )

增加样本数到 100,即生成了 100 张单个手写体图像,75 张用来训练,25 张用来测试;

25 张的测试结果 图 6 所示,几种模型的测试精度都达到了 90% 左右。

图 7 手写体识别的性能分析(在样本数为 100 的情况下)

图 8 不同样本数目下的四种模型的测试精度( 5次拟合 )

# 如果对您有帮助,欢迎在 GitHub 上 Star 支持我:/coneypo/ML_handwritten_number

# 请尊重他人劳动成果,转载或者使用源码请注明出处:/AdaminXie

# 如有问题联系邮箱 :coneypo@

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。