Python实现基于神经网络的“你画我猜”你画我猜

资源下载地址:https://download.csdn.net/download/sheziqiong/85929037
资源下载地址:https://download.csdn.net/download/sheziqiong/85929037
项目简介:

通过在鼠标在页面上进行绘图,利用神经网络识别所画内容

源数据

来源:https://www.kaggle.com/c/quickdraw-doodle-recognition/data

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LMK0mxcs-1657087880216)(https://www.writebug.com/myres/static/uploads/2022/1/12/de479707abbf38e5ad726d2274ed1e09.writebug)]

我使用了其中的 train_simplified.zip 大小约为 22GB,格式为 countrycode,drawing,key_id,recognized,timestamp,word。
我只使用了其中的 drawing,recognized,word 分别为轨迹坐标,判断成功的标签,lable

train_simplified.zip 和源数据的区别是使用了 Ramer-Douglas-Peucker algorithm 对源数据的点进行了处理,若需要自己处理可以调用 python 中的 rdp 包,
在我的 draw_test 中我就是用它对自己的数据进行处理

shuffle 处理:

由于机器条件和时间限制我只挑选了 71 个种类进行训练,340 种类训练只迭代两次

由于源数据过大无法全部加载进入内存,而神经网络需要对数据进行 shuffle 处理,因此我通过 draw/preprecess_shuffle/csv_merage.py 对所需要的文件进行合并,
而 draw/preprecess_shuffle/shuffle_occ.py 是某大手写的文件 shuffle 方法,可以 shuffle 我 71 分类的源文件,

但是 在shuffle过大文件时会发生错误
可以通过
部分合并 +shuffle+ 分割 + 部分合并 +shuffle+ 合并
实现总体的 shuffle

处理过的 71 分类源数据 csv_71_shuffled.csv 已上传至:https://pan.baidu.com/s/19eWRtCTtAaiMH7JRT34VZA

源数据处理:

draw/read.py 用于读入源数据,将其处理为如下格式存入 迭代器
x 中的单一项形如:

[[[167, 109, 80, 69, 58, 31, 57, 117, 99, 52, 30, 6, 1, 2, 66, 98, 253, 254, 246, 182, 165], [140, 194, 227, 232, 229, 229, 206, 124, 123, 149, 157, 159, 153, 110, 82, 77, 74, 109, 121, 127, 120]], [[207, 207, 210, 221, 238], [74, 103, 114, 128, 135]], [[119, 107, 76, 70, 49, 39, 60, 93], [72, 41, 3, 0, 1, 5, 38, 70]]

y 中的单一项形如:

'airplane'

draw/rnnmodel.py 中使用 get_train_batch 和 get_test_batch 读取并且修改 x 的格式,x 的单一项形如:

[[167,140,1],[109,194,0],[80,227,0],[69,229,0]....[165,120,0],[207,74,1],[207,103,0]....]

将标签值 y 进行 one-hot 处理为单一项形如:

[1,0,0,0,0,.......]

x 为 shape 为(p,q,3)的二维列表,p 代表每次迭代读取的个数,q 代表该条源数据轨迹点的长度,而每个三元组中前两项为点的 x,y 坐标,第三项为 1 代表是笔画的开头,0 则代表为笔画的过程点
同样将其存入 迭代器

模型:

模型搭建时,第一次尝试中使用了单层的 lstm 模型,2epoch 后测试集精确率大约为 0.768,模型保存于 model/model1,

# lstm
model.add(Masking(mask_value=-1, input_shape=(self.maxlen, 3)))
model.add(LSTM(units=self.lstm_units, input_shape=(self.maxlen, 3)))
model.add(Dense(self.classification_num, activation='softmax'))
adam = Adam(lr=0.005, beta_1=0.9, beta_2=0.999, epsilon=1e-08, amsgrad=True)
model.compile(loss="categorical_crossentropy", optimizer=adam, metrics=["accuracy"])
model.fit_generator(generator=self.get_train_batch(),steps_per_epoch=self.lines,epochs=self.n_epochs,verbose=1) 
model.save(self.model_path)

后改用一层卷积加上一层 lstm,2epoch 后测试集精确率大约为 0.817,4epoch 后测试集精确率大约为 0.844,模型保存于 model/model2

# conv+lstm
model.add(Conv1D(filters=128, kernel_size=3, activation='relu',padding="same",input_shape=(None,3)))
model.add(MaxPooling1D(pool_size=2,strides=2))
model.add(Masking(mask_value=-1, input_shape=(self.maxlen//2, 3)))
model.add(LSTM(units=self.lstm_units, input_shape=(self.maxlen//2, 3)))
model.add(Dense(self.classification_num, activation='softmax'))
adam = Adam(lr=0.005, beta_1=0.9, beta_2=0.999, epsilon=1e-08, amsgrad=True)
model.compile(loss="categorical_crossentropy", optimizer=adam, metrics=["accuracy"])
model.fit_generator(generator=self.get_train_batch(), steps_per_epoch=self.lines, epochs=self.n_epochs,
 verbose=1)
model.save(self.model_path)

340 分类的 2epoch 精确率大约为 63%,模型保存于 model/model3

在我的 cnn+lstm 模型中,卷积层 filters=128,窗口为 3,进行 padding,使用 relu 作为激活函数,

使用 maxpooling,步长为 2,窗口为 2,因此在进入 lstm 层时长度减半,

masking 层用于处理边长序列,使其都为指定长度输入 lstm 层,我在这里使用了 150 作为 maxlen,

因此 lstm 层 inputshape 变为了(?,3),lstm 神经元个数我使用了 200,

全连接层的激活函数使用 softmax 作为我的分类模型的激活函数,此时 shape 变为了 71 项的向量

我使用 adamw 作为神经网络优化算法,并且略微调大了学习率

使用 fit_generator 作为训练函数,可以通过 generator 调用 get_train_batch 函数迭代的读入数据,规避内存不够的问题

模型调用参数说明:

raw_train_path # 训练集路径

raw_test_path # 测试集路径

model_path # 神经网络模型(存储/加载)路径

delfalse # 是否过滤源数据中识别失败部分

continue_train # 是否是继续训练

lines #源数据行数

n_epochs #训练次数

maxlen #输入图画最大点数

lstm_units #lstm 神经元个数

若是源数据没有手动分为训练及测试集,即训练集路径=测试集路径,会自动随机分割 10% 作为测试集,
因为源数据中存在一些图是 Google 的模型难以识别的

即源数据中 recognized 为 false 的条目,该部分源数据作为干扰项也许会降低训练效果,delfase=1 时会过滤该部分源数据,
continue_train=1 时代表我已经存在该神经网络模型,并且需要在该模型基础上进行继续训练,
maxlen 代表每个图 rdp 处理后的轨迹点数

ui:

draw/drawing.py 调用 cv2 实现了鼠标绘图并记录轨迹点的功能,并在 draw/drawing_test.py 中被调用,
再 draw/drawing_test.py 中通过 rdp 对轨迹点进行预处理,再转换为三元组形式,
作为源数据输入神经网络模型,输出所有类别的可能性列表,选取列表中十个最大的,也就是神经网络识别认为最有可能性的十项,
然后通过 tkinter 库制作简单 ui 展示输出结果,绘图完成后按 C 让神经网络识别图形,识别后通过点击按钮继续绘图

复现步骤:

1 解压 kaggle 下载的 simple 数据,
2Csv_merge.py 中的第一个路径改为你所挑选的所有分类的源数据文件所在文件夹,第二个路径修改位存储路径(rawdate.csv)
3 在命令提示符中使用 python shuffle_ooc.py rawdate.csv > rawdate_shuffled.csv 命令进行 shuffle,注意 py 文件和两个 CSV 文件需要完整路径,或是存储在同一个目录下,在该目录下运行命令提示符,会输出文件行数(文件过大时需要分割 shuffle 再合并)
4 调用 rnnmodel.py 进行模型训练,注意所有参数都需要填写,会输出测试集的训练准确率,也可以调用 acc.py 进行精确率测试
5 调用 draw_test.py 可以进行简单绘图并识别

我挑选的 71 种类型:

'mushroom': 0, 'moon': 1, 'bread': 2, 'rain': 3, 'hand': 4, 'ice cream': 5, 'tree': 6, 'hamburger': 7,
'cloud': 8, 'basketball': 9, 'mountain': 10, 'finger': 11, 'tiger': 12, 'fork': 13, 'star': 14,
'baseball': 15, 'house': 16, 'cake': 17, 'castle': 18, 'line': 19, 'bear': 20, 'arm': 21, 'bus': 22,
'bridge': 23, 'wheel': 24, 'fish': 25, 'sun': 26, 'calculator': 27, 'pencil': 28, 'bed': 29, 'key': 30,
'river': 31, 'chair': 32, 'circle': 33, 'face': 34, 'airplane': 35, 'pig': 36, 'banana': 37, 'car': 38,
'bicycle': 39, 'cat': 40, 'bee': 41, 'clock': 42, 'door': 43, 'fence': 44, 'guitar': 45, 'dog': 46,
'tooth': 47, 'baseball bat': 48, 'camel': 49, 'train': 50, 'camera': 51, 'table': 52, 'eye': 53,
'shoe': 54, 'axe': 55, 'grass': 56, 'foot': 57, 'hospital': 58, 'apple': 59, 'cell phone': 60,
'beard': 61, 'cup': 62, 'elephant': 63, 'umbrella': 64, 'rabbit': 65, 'flower': 66, 't-shirt': 67,
'bird': 68, 'watermelon': 69, 'hammer': 70

部分灵魂画作的识别:












资源下载地址:https://download.csdn.net/download/sheziqiong/85929037
资源下载地址:https://download.csdn.net/download/sheziqiong/85929037

作者:biyezuopin原文地址:https://blog.csdn.net/sheziqiong/article/details/125638643

%s 个评论

要回复文章请先登录注册