情人节选花神器—深度学习指南

大鹏说 :本文约1200字,阅读需要4分钟。本文讲述了利用深度学习原理实现自动识别花卉品种的过程。成果优秀,令人惊奇,绝对是情人节选花神助手~

关键词:阿里云 Python 邮件 星座

p.s.文末有源代码分享

转眼,一年一度的情人节又到了。每个情人节我总要面临一个问题:如何给我的女盆友们买花?花店里琳琅满目的花,我又不认识,万一买错品种了,我将会永远失去她们。我决定搞一个模型来帮我完成花的识别工作。

1. 学习素材准备

为了掌握花卉的鉴别能力,我特地找了海量的花卉图片以供赏析。

一共14个品种的花:


image

每个品种共1000张艳照,共计14000张:


image

如何让机器能够准确识别这些花的品种,很简单,一遍一遍反复的学习,直到能认准为止——“一遍一遍反复学习”这一行为,我们称之为深度学习。

学习要讲究方法,比如如何区分玫瑰和菊花,很简单,玫瑰一般为红色,花朵是卷起来的,而菊花是黄灿灿的,花朵的形状…大家都懂的。这种提取特征的学习方法,我们通常称之为卷积。

2. 模型建立

先导入用于深度学习的python包,我们使用Keras框架

from keras.models import Sequential
from keras.layers import Conv2D,MaxPool2D,Activation,Dropout,Flatten,Dense
from keras.optimizers import Adam
from keras.preprocessing.image import ImageDataGenerator,img_to_array,load_img
from keras.models import load_model

因为Keras框架本身是基于tensorflow构建的,性能卓著,又不需要tensorflow超高难度的代码编写,封装十分彻底,用法与skitlearn类似。

在开始组织神经网络前,我们先定义一些参数,方便调试与修改。

IMG_W = 224 #定义裁剪的图片宽度
IMG_H = 224 #定义裁剪的图片高度
CLASS = 14 #图片的分类数
EPOCHS = 5 #迭代周期
BATCH_SIZE = 64 #批次大小
TRAIN_PATH = 'data/train' #训练集存放路径
TEST_PATH = 'data/test' #测试集存放路径
SAVE_PATH = 'flower_selector' #模型保存路径
LEARNING_RATE = 1e-4 #学习率
DROPOUT_RATE = 0 #抗拟合,不工作的神经网络百分比

下面是每个参数的解释:

IMG_W,IMG_H:用于模型学习的图片尺寸。
因为我们的样本图片尺寸各不相同,而模型学习需要大小统一的图片,所有这里设定其宽高。研究表明正方形的图片在模型拟合方面,效果优于长方形的图片,所以这里长宽设置相同。特别注意,图片尺寸越大,训练花费时间越久,所以千万不要设置如1920*1920分辨率大小,否则就算等到天荒地老模型也训练不完。

CLASS:图片的分类数量,
我们一共有14种花,所以,设置为14。

EPOCHS:训练周期。
模型把所有样本图片都训练一次为一周期,而需要训练成一个准确率较高的模型,一个周期显然不行。这里我们可以自由设置周期大小,我一般设置5-40个周期,循环结束保存模型,接着继续。

BATCH_SIZE:批次大小。
按理说一个周期里,我们可以把所有图片一股脑丢给机器训练,但是我们显卡的显存或者CPU的内存只有那么大,放多了容易溢出,也就是常说的爆显存,所以我们要设置个批次,把图片一批一批喂给模型训练,我这里设置为一批64张图片,如果你的显卡性能略差可以设置成32或者更小。

TRAIN_PATH:存放训练集的路径。

TEST_PATH:存放测试集的路径。

LEARNING_RATE:学习率,模型学习的速度。
并不是越快越好(数字越大),越快容易造成模型震荡,无法收敛,也就是没有训练效果。1e-4是科学计数法,为0.0001。这里学习率一般设置有几个选择1e-1,1e-2,1e-3,1e-4。通常探索阶段,设置的小一点。

DROPOUT_RATE:每次训练不工作的神经元百分比。
在模型训练中,我们通常会遇到一个问题,过拟合。也就是说在训练集上准确率很高,而测试集上准确率很低。这里设置一个DROPOUT参数,定义每一次训练,随机一定百分比的部分不参与训练,这样会起到抵抗过拟合的效果。

主要是定义训练集和测试集的图片标准。两者都有的一个参数为rescale,因为图片是RGB色彩,颜色范围从0-255,rescale,使数据归一化为0-1的范围。但是在训练集中我们还定义了旋转,平移,缩放等功能,这些操作的目的是随机变换输入的图片样式,增加样本量。注意!这一步操作仅仅只是确定了功能,并没有对任何图片进行操作,相当于先构建了一个模具。

然后,我们开始搭建神经网络:

model = Sequential() #创建一个神经网络对象

#添加一个卷积层,传入固定宽高三通道的图片,以32种不同的卷积核构建32张特征图,
# 卷积核大小为3*3,构建特征图比例和原图相同,激活函数为relu函数。
model.add(Conv2D(input_shape=(IMG_W,IMG_H,3),filters=32,kernel_size=3,padding='same',activation='relu'))
#再次构建一个卷积层
model.add(Conv2D(filters=32,kernel_size=3,padding='same',activation='relu'))
#构建一个池化层,提取特征,池化层的池化窗口为2*2,步长为2。
model.add(MaxPool2D(pool_size=2,strides=2))
#继续构建卷积层和池化层,区别是卷积核数量为64。
model.add(Conv2D(filters=64,kernel_size=3,padding='same',activation='relu'))
model.add(Conv2D(filters=64,kernel_size=3,padding='same',activation='relu'))
model.add(MaxPool2D(pool_size=2,strides=2))
#继续构建卷积层和池化层,区别是卷积核数量为128。
model.add(Conv2D(filters=128,kernel_size=3,padding='same',activation='relu'))
model.add(Conv2D(filters=128,kernel_size=3,padding='same',activation='relu'))
model.add(MaxPool2D(pool_size=2, strides=2))

model.add(Flatten()) #数据扁平化
model.add(Dense(128,activation='relu')) #构建一个具有128个神经元的全连接层
model.add(Dense(64,activation='relu')) #构建一个具有64个神经元的全连接层
model.add(Dropout(DROPOUT_RATE)) #加入dropout,防止过拟合。
model.add(Dense(CLASS,activation='softmax')) #输出层,一共14个神经元,对应14个分类

先用Sequential()定义一个模型对象,再往里面添加神经网络层。模型结构大致为两个卷积层,一个池化层,共三组,再增加两个全连接层,最终输出为10大类。

我再把网络结构进行可视化,以便更直观地观察模型。

from keras.utils.vis_utils import plot_model
from keras.models import load_model
import matplotlib.pyplot as plt

model = load_model('flower_selector.h5')

plot_model(model,to_file="model.png",show_shapes=True,show_layer_names=True,rankdir='TB')
plt.figure(figsize=(10,10))
img = plt.imread("model.png")
plt.imshow(img)
plt.axis('off')
plt.show()

绘制的结构图如下:


image

再来讲一讲如何构建合理的网络结构。一般为1-2个卷积层,加1个池化层,共2-3组,最后增加1-2个全连接层输出,结构没有定式,但如果样本太少,建议层数不宜过多,容易过拟合。

设置好网络结构,我们设置优化器,这里使用adam优化器,使用梯度下降法优化模型,并返回准确率。

adam = Adam(lr=LEARNING_RATE) #创建Adam优化器

model.compile(optimizer=adam,loss='categorical_crossentropy',metrics=['accuracy']) #使用交叉熵代价函数,adam优化器优化模型,并提取准确率

lr:学习率,数值为脚本开头设置的数值大小。

loss:损失函数,用于衡量模型误差,模型训练的目的就是让损失函数的值尽可能小,这里我们使用交叉熵代价函数。

metrics:返回准确率。

最后,生成训练集和测试集的迭代器,用于把图片按一定批次大小传入模型训练。

train_generator = train_datagen.flow_from_directory( #设置训练集迭代器
    TRAIN_PATH, #训练集存放路径
    target_size=(IMG_W,IMG_H), #训练集图片尺寸
    batch_size=BATCH_SIZE #训练集批次
    )

test_generator = test_datagen.flow_from_directory( #设置测试集迭代器
    TEST_PATH, #测试集存放路径
    target_size=(IMG_W,IMG_H), #测试集图片尺寸
    batch_size=BATCH_SIZE, #测试集批次
    )

增加判定机制,如果文件夹下没有已训练的模型,那么从头开始训练,如果已有训练过的模型,那么在此基础上,继续训练:

try:
    model = load_model('{}.h5'.format(SAVE_PATH))  #尝试读取训练好的模型,再次训练
    print('model upload,start training!')
except:
    print('not find model,start training') #如果没有训练过的模型,则从头开始训练

构建好所有内容,使用fit_generator()拟合模型:

model.fit_generator( #模型拟合
                    train_generator,  #训练集迭代器
                    steps_per_epoch=len(train_generator), #每个周期需要迭代多少步(图片总量/批次大小=11200/64=175)
                    epochs=EPOCHS, #迭代周期
                    validation_data=test_generator, #测试集迭代器
                    validation_steps=len(test_generator) #测试集迭代多少步
                    )

传入训练集和测试集迭代器,传入周期,传入迭代的步数。

模型拟合完毕,保存模型结构,用于预测和再次训练:

model.save('{}.h5'.format(SAVE_PATH)) #保存模型
print('finish {} epochs!'.format(EPOCHS))

3.模型训练

运行脚本~


image

这里会先显示训练集和测试集的样本大小,分类数量,分类名称。如果是使用GPU训练模型,这里还会显示显卡参数。强烈建议使用GPU模式。因为根据运行后的结果,模型在训练200个周期以上后,准确率才能达到80%,一个周期平均1分钟,而使用CPU模式,则要30分钟左右,效率差距巨大。

接下来,正式开始训练,会显示批次,步数,准确率等信息,一开始准确率是很低的。只有7%,约等于1/14,完全随机:


image

训练一段时间后,准确率会上升:


image

这里我训练超过200个周期以后,准确率达到约80%。这里注意,前200个周期我设置了0.5的dropout,发现模型提升速度比较慢,建议数值可以设置小一点,甚至为0。

经过漫长的训练,我训练了约400个周期。模型最终效果如图所示:


image

训练集准确率大于90%,而测试集准确率约84%。我发现再继续训练,训练集准确率还能再提高,但测试集准确率几乎提高不了了,过拟合情况越来越严重,这时,果断停止训练。

4.结果展示

模型训练好了,那么我们采用实际的案例来测试下效果。我从花店拍了一些不同花卉的照片如下:


image

写一个简单的脚本,功能为导入训练好的模型,再把用于预测的图片转换成模型的对应格式。比如尺寸为224*224~

from keras.models import load_model
from keras.preprocessing.image import img_to_array,load_img
import numpy as np
import os
# 载入模型
model = load_model('flower_selector.h5')
label = np.array(['康乃馨','杜鹃花','桂花','桃花','梅花','洛神花','牡丹','牵牛花','玫瑰','茉莉花','荷花','菊花','蒲公英','风信子'])
def image_change(image):
    image = image.resize((224,224))
    image = img_to_array(image)
    image = image/255
    image = np.expand_dims(image,0)
    return image

然后,遍历文件夹下的图片进行预测:

for pic in os.listdir('./predict'):
    print('图片真实分类为',pic)
    image = load_img('./predict/' + pic)
    image = image_change(image)
    print('预测结果为',label[model.predict_classes(image)])
    print('----------------------------------')

结果如下:


image

预测准确率达到百分之百,鼓掌~!!!!!

经过了层层挑战,我终于完成了机器识花的工作,准备去给我的女盆友们买花了!大家也快关注“大鹏教你玩数据”后在后台回复【30】,获取源代码和学习素材学起来吧~

免费获取【1.6G AI学习资料】和其他福利,请加QQ群:837627861
转载请在公众号后台联系小编,请勿擅自转载。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,738评论 5 472
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,377评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,774评论 0 333
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,032评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,015评论 5 361
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,239评论 1 278
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,724评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,374评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,508评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,410评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,457评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,132评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,733评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,804评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,022评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,515评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,116评论 2 341

推荐阅读更多精彩内容