大鵬說 :本文約1200字,閱讀需要4分鐘秤标。本文講述了利用深度學(xué)習(xí)原理實(shí)現(xiàn)自動識別花卉品種的過程银伟。成果優(yōu)秀,令人驚奇并徘,絕對是情人節(jié)選花神助手~
關(guān)鍵詞:阿里云 Python 郵件 星座
p.s.文末有源代碼分享
轉(zhuǎn)眼,一年一度的情人節(jié)又到了扰魂。每個(gè)情人節(jié)我總要面臨一個(gè)問題:如何給我的女盆友們買花麦乞?花店里琳瑯滿目的花蕴茴,我又不認(rèn)識,萬一買錯(cuò)品種了姐直,我將會永遠(yuǎn)失去她們倦淀。我決定搞一個(gè)模型來幫我完成花的識別工作。
1. 學(xué)習(xí)素材準(zhǔn)備
為了掌握花卉的鑒別能力声畏,我特地找了海量的花卉圖片以供賞析撞叽。
一共14個(gè)品種的花:
每個(gè)品種共1000張艷照,共計(jì)14000張:
如何讓機(jī)器能夠準(zhǔn)確識別這些花的品種插龄,很簡單愿棋,一遍一遍反復(fù)的學(xué)習(xí),直到能認(rèn)準(zhǔn)為止——“一遍一遍反復(fù)學(xué)習(xí)”這一行為均牢,我們稱之為深度學(xué)習(xí)糠雨。
學(xué)習(xí)要講究方法,比如如何區(qū)分玫瑰和菊花徘跪,很簡單甘邀,玫瑰一般為紅色,花朵是卷起來的,而菊花是黃燦燦的垮庐,花朵的形狀…大家都懂的松邪。這種提取特征的學(xué)習(xí)方法,我們通常稱之為卷積哨查。
2. 模型建立
先導(dǎo)入用于深度學(xué)習(xí)的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
因?yàn)镵eras框架本身是基于tensorflow構(gòu)建的,性能卓著解恰,又不需要tensorflow超高難度的代碼編寫锋八,封裝十分徹底,用法與skitlearn類似护盈。
在開始組織神經(jīng)網(wǎng)絡(luò)前挟纱,我們先定義一些參數(shù),方便調(diào)試與修改腐宋。
IMG_W = 224 #定義裁剪的圖片寬度
IMG_H = 224 #定義裁剪的圖片高度
CLASS = 14 #圖片的分類數(shù)
EPOCHS = 5 #迭代周期
BATCH_SIZE = 64 #批次大小
TRAIN_PATH = 'data/train' #訓(xùn)練集存放路徑
TEST_PATH = 'data/test' #測試集存放路徑
SAVE_PATH = 'flower_selector' #模型保存路徑
LEARNING_RATE = 1e-4 #學(xué)習(xí)率
DROPOUT_RATE = 0 #抗擬合紊服,不工作的神經(jīng)網(wǎng)絡(luò)百分比
下面是每個(gè)參數(shù)的解釋:
IMG_W,IMG_H:用于模型學(xué)習(xí)的圖片尺寸。
因?yàn)槲覀兊臉颖緢D片尺寸各不相同胸竞,而模型學(xué)習(xí)需要大小統(tǒng)一的圖片欺嗤,所有這里設(shè)定其寬高。研究表明正方形的圖片在模型擬合方面卫枝,效果優(yōu)于長方形的圖片煎饼,所以這里長寬設(shè)置相同。特別注意校赤,圖片尺寸越大吆玖,訓(xùn)練花費(fèi)時(shí)間越久筒溃,所以千萬不要設(shè)置如1920*1920分辨率大小,否則就算等到天荒地老模型也訓(xùn)練不完沾乘。
CLASS:圖片的分類數(shù)量怜奖,
我們一共有14種花,所以翅阵,設(shè)置為14歪玲。
EPOCHS:訓(xùn)練周期。
模型把所有樣本圖片都訓(xùn)練一次為一周期掷匠,而需要訓(xùn)練成一個(gè)準(zhǔn)確率較高的模型滥崩,一個(gè)周期顯然不行。這里我們可以自由設(shè)置周期大小槐雾,我一般設(shè)置5-40個(gè)周期夭委,循環(huán)結(jié)束保存模型,接著繼續(xù)募强。
BATCH_SIZE:批次大小株灸。
按理說一個(gè)周期里,我們可以把所有圖片一股腦丟給機(jī)器訓(xùn)練擎值,但是我們顯卡的顯存或者CPU的內(nèi)存只有那么大慌烧,放多了容易溢出,也就是常說的爆顯存鸠儿,所以我們要設(shè)置個(gè)批次屹蚊,把圖片一批一批喂給模型訓(xùn)練,我這里設(shè)置為一批64張圖片进每,如果你的顯卡性能略差可以設(shè)置成32或者更小汹粤。
TRAIN_PATH:存放訓(xùn)練集的路徑。
TEST_PATH:存放測試集的路徑田晚。
LEARNING_RATE:學(xué)習(xí)率嘱兼,模型學(xué)習(xí)的速度。
并不是越快越好(數(shù)字越大)贤徒,越快容易造成模型震蕩芹壕,無法收斂,也就是沒有訓(xùn)練效果接奈。1e-4是科學(xué)計(jì)數(shù)法踢涌,為0.0001。這里學(xué)習(xí)率一般設(shè)置有幾個(gè)選擇1e-1,1e-2,1e-3,1e-4序宦。通常探索階段睁壁,設(shè)置的小一點(diǎn)。
DROPOUT_RATE:每次訓(xùn)練不工作的神經(jīng)元百分比。
在模型訓(xùn)練中堡僻,我們通常會遇到一個(gè)問題糠惫,過擬合。也就是說在訓(xùn)練集上準(zhǔn)確率很高钉疫,而測試集上準(zhǔn)確率很低。這里設(shè)置一個(gè)DROPOUT參數(shù)巢价,定義每一次訓(xùn)練牲阁,隨機(jī)一定百分比的部分不參與訓(xùn)練,這樣會起到抵抗過擬合的效果壤躲。
主要是定義訓(xùn)練集和測試集的圖片標(biāo)準(zhǔn)城菊。兩者都有的一個(gè)參數(shù)為rescale,因?yàn)閳D片是RGB色彩碉克,顏色范圍從0-255凌唬,rescale,使數(shù)據(jù)歸一化為0-1的范圍漏麦。但是在訓(xùn)練集中我們還定義了旋轉(zhuǎn)客税,平移,縮放等功能撕贞,這些操作的目的是隨機(jī)變換輸入的圖片樣式更耻,增加樣本量。注意捏膨!這一步操作僅僅只是確定了功能秧均,并沒有對任何圖片進(jìn)行操作,相當(dāng)于先構(gòu)建了一個(gè)模具号涯。
然后目胡,我們開始搭建神經(jīng)網(wǎng)絡(luò):
model = Sequential() #創(chuàng)建一個(gè)神經(jīng)網(wǎng)絡(luò)對象
#添加一個(gè)卷積層,傳入固定寬高三通道的圖片链快,以32種不同的卷積核構(gòu)建32張?zhí)卣鲌D誉己,
# 卷積核大小為3*3,構(gòu)建特征圖比例和原圖相同久又,激活函數(shù)為relu函數(shù)巫延。
model.add(Conv2D(input_shape=(IMG_W,IMG_H,3),filters=32,kernel_size=3,padding='same',activation='relu'))
#再次構(gòu)建一個(gè)卷積層
model.add(Conv2D(filters=32,kernel_size=3,padding='same',activation='relu'))
#構(gòu)建一個(gè)池化層,提取特征地消,池化層的池化窗口為2*2炉峰,步長為2。
model.add(MaxPool2D(pool_size=2,strides=2))
#繼續(xù)構(gòu)建卷積層和池化層脉执,區(qū)別是卷積核數(shù)量為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))
#繼續(xù)構(gòu)建卷積層和池化層,區(qū)別是卷積核數(shù)量為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()) #數(shù)據(jù)扁平化
model.add(Dense(128,activation='relu')) #構(gòu)建一個(gè)具有128個(gè)神經(jīng)元的全連接層
model.add(Dense(64,activation='relu')) #構(gòu)建一個(gè)具有64個(gè)神經(jīng)元的全連接層
model.add(Dropout(DROPOUT_RATE)) #加入dropout婆廊,防止過擬合迅细。
model.add(Dense(CLASS,activation='softmax')) #輸出層,一共14個(gè)神經(jīng)元淘邻,對應(yīng)14個(gè)分類
先用Sequential()定義一個(gè)模型對象茵典,再往里面添加神經(jīng)網(wǎng)絡(luò)層。模型結(jié)構(gòu)大致為兩個(gè)卷積層宾舅,一個(gè)池化層统阿,共三組,再增加兩個(gè)全連接層筹我,最終輸出為10大類扶平。
我再把網(wǎng)絡(luò)結(jié)構(gòu)進(jìn)行可視化,以便更直觀地觀察模型蔬蕊。
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()
繪制的結(jié)構(gòu)圖如下:
再來講一講如何構(gòu)建合理的網(wǎng)絡(luò)結(jié)構(gòu)结澄。一般為1-2個(gè)卷積層,加1個(gè)池化層岸夯,共2-3組麻献,最后增加1-2個(gè)全連接層輸出,結(jié)構(gòu)沒有定式囱修,但如果樣本太少赎瑰,建議層數(shù)不宜過多,容易過擬合破镰。
設(shè)置好網(wǎng)絡(luò)結(jié)構(gòu)餐曼,我們設(shè)置優(yōu)化器,這里使用adam優(yōu)化器鲜漩,使用梯度下降法優(yōu)化模型源譬,并返回準(zhǔn)確率。
adam = Adam(lr=LEARNING_RATE) #創(chuàng)建Adam優(yōu)化器
model.compile(optimizer=adam,loss='categorical_crossentropy',metrics=['accuracy']) #使用交叉熵代價(jià)函數(shù)孕似,adam優(yōu)化器優(yōu)化模型踩娘,并提取準(zhǔn)確率
lr:學(xué)習(xí)率,數(shù)值為腳本開頭設(shè)置的數(shù)值大小喉祭。
loss:損失函數(shù)养渴,用于衡量模型誤差,模型訓(xùn)練的目的就是讓損失函數(shù)的值盡可能小泛烙,這里我們使用交叉熵代價(jià)函數(shù)理卑。
metrics:返回準(zhǔn)確率。
最后蔽氨,生成訓(xùn)練集和測試集的迭代器藐唠,用于把圖片按一定批次大小傳入模型訓(xùn)練帆疟。
train_generator = train_datagen.flow_from_directory( #設(shè)置訓(xùn)練集迭代器
TRAIN_PATH, #訓(xùn)練集存放路徑
target_size=(IMG_W,IMG_H), #訓(xùn)練集圖片尺寸
batch_size=BATCH_SIZE #訓(xùn)練集批次
)
test_generator = test_datagen.flow_from_directory( #設(shè)置測試集迭代器
TEST_PATH, #測試集存放路徑
target_size=(IMG_W,IMG_H), #測試集圖片尺寸
batch_size=BATCH_SIZE, #測試集批次
)
增加判定機(jī)制,如果文件夾下沒有已訓(xùn)練的模型宇立,那么從頭開始訓(xùn)練踪宠,如果已有訓(xùn)練過的模型,那么在此基礎(chǔ)上妈嘹,繼續(xù)訓(xùn)練:
try:
model = load_model('{}.h5'.format(SAVE_PATH)) #嘗試讀取訓(xùn)練好的模型柳琢,再次訓(xùn)練
print('model upload,start training!')
except:
print('not find model,start training') #如果沒有訓(xùn)練過的模型,則從頭開始訓(xùn)練
構(gòu)建好所有內(nèi)容润脸,使用fit_generator()擬合模型:
model.fit_generator( #模型擬合
train_generator, #訓(xùn)練集迭代器
steps_per_epoch=len(train_generator), #每個(gè)周期需要迭代多少步(圖片總量/批次大小=11200/64=175)
epochs=EPOCHS, #迭代周期
validation_data=test_generator, #測試集迭代器
validation_steps=len(test_generator) #測試集迭代多少步
)
傳入訓(xùn)練集和測試集迭代器染厅,傳入周期,傳入迭代的步數(shù)津函。
模型擬合完畢,保存模型結(jié)構(gòu)孤页,用于預(yù)測和再次訓(xùn)練:
model.save('{}.h5'.format(SAVE_PATH)) #保存模型
print('finish {} epochs!'.format(EPOCHS))
3.模型訓(xùn)練
運(yùn)行腳本~
這里會先顯示訓(xùn)練集和測試集的樣本大小尔苦,分類數(shù)量,分類名稱行施。如果是使用GPU訓(xùn)練模型允坚,這里還會顯示顯卡參數(shù)。強(qiáng)烈建議使用GPU模式蛾号。因?yàn)楦鶕?jù)運(yùn)行后的結(jié)果稠项,模型在訓(xùn)練200個(gè)周期以上后,準(zhǔn)確率才能達(dá)到80%鲜结,一個(gè)周期平均1分鐘展运,而使用CPU模式,則要30分鐘左右精刷,效率差距巨大拗胜。
接下來,正式開始訓(xùn)練怒允,會顯示批次埂软,步數(shù),準(zhǔn)確率等信息纫事,一開始準(zhǔn)確率是很低的勘畔。只有7%,約等于1/14丽惶,完全隨機(jī):
訓(xùn)練一段時(shí)間后炫七,準(zhǔn)確率會上升:
這里我訓(xùn)練超過200個(gè)周期以后,準(zhǔn)確率達(dá)到約80%蚊夫。這里注意诉字,前200個(gè)周期我設(shè)置了0.5的dropout,發(fā)現(xiàn)模型提升速度比較慢,建議數(shù)值可以設(shè)置小一點(diǎn)壤圃,甚至為0陵霉。
經(jīng)過漫長的訓(xùn)練,我訓(xùn)練了約400個(gè)周期伍绳。模型最終效果如圖所示:
訓(xùn)練集準(zhǔn)確率大于90%踊挠,而測試集準(zhǔn)確率約84%。我發(fā)現(xiàn)再繼續(xù)訓(xùn)練冲杀,訓(xùn)練集準(zhǔn)確率還能再提高效床,但測試集準(zhǔn)確率幾乎提高不了了,過擬合情況越來越嚴(yán)重权谁,這時(shí)剩檀,果斷停止訓(xùn)練。
4.結(jié)果展示
模型訓(xùn)練好了旺芽,那么我們采用實(shí)際的案例來測試下效果沪猴。我從花店拍了一些不同花卉的照片如下:
寫一個(gè)簡單的腳本,功能為導(dǎo)入訓(xùn)練好的模型采章,再把用于預(yù)測的圖片轉(zhuǎn)換成模型的對應(yīng)格式运嗜。比如尺寸為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(['康乃馨','杜鵑花','桂花','桃花','梅花','洛神花','牡丹','牽牛花','玫瑰','茉莉花','荷花','菊花','蒲公英','風(fēng)信子'])
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
然后悯舟,遍歷文件夾下的圖片進(jìn)行預(yù)測:
for pic in os.listdir('./predict'):
print('圖片真實(shí)分類為',pic)
image = load_img('./predict/' + pic)
image = image_change(image)
print('預(yù)測結(jié)果為',label[model.predict_classes(image)])
print('----------------------------------')
結(jié)果如下:
預(yù)測準(zhǔn)確率達(dá)到百分之百担租,鼓掌~!5衷酢7芫取!便贵!
經(jīng)過了層層挑戰(zhàn)菠镇,我終于完成了機(jī)器識花的工作,準(zhǔn)備去給我的女盆友們買花了承璃!大家也快關(guān)注“大鵬教你玩數(shù)據(jù)”后在后臺回復(fù)【30】利耍,獲取源代碼和學(xué)習(xí)素材學(xué)起來吧~
免費(fèi)獲取【1.6G AI學(xué)習(xí)資料】和其他福利,請加QQ群:837627861
轉(zhuǎn)載請?jiān)诠娞柡笈_聯(lián)系小編盔粹,請勿擅自轉(zhuǎn)載隘梨。