keras實(shí)現(xiàn)圖像預(yù)處理并生成一個(gè)generator的案例
如下所示:
接下來(lái),給出我自己目前積累的代碼,從目錄中自動(dòng)讀取圖像,并產(chǎn)生generator:
第一步:建立好目錄結(jié)構(gòu)和圖像
可以看到目錄images_keras_dict下有次級(jí)目錄,次級(jí)目錄下就直接包含照片了
**第二步:寫(xiě)代碼建立預(yù)處理程序
# 先進(jìn)行預(yù)處理圖像 train_datagen = ImageDataGenerator(rescale=1./255, rotation_range=50, height_shift_range=[-0.005, 0, 0.005], width_shift_range=[-0.005, 0, 0.005], horizontal_flip=True, fill_mode='reflect') #再對(duì)預(yù)處理圖像指定從目錄中讀取數(shù)據(jù),可以看到我的目錄最核心的地方是images_keras_dict(可以對(duì)照上一張圖片) train_generator = train_datagen.flow_from_directory('AgriculturalDisease_trainingset/images_keras_dict', target_size=(height, width), batch_size=16) val_datagen = ImageDataGenerator(rescale=1./255) val_generator = val_datagen.flow_from_directory('AgriculturalDisease_validationset/images_keras_dict', target_size=(height, width), batch_size=64) save_weights = ModelCheckpoint(filepath='models/best_weights.hdf5',monitor='val_loss', verbose=1, save_best_only=True) # 最后在fit_generator 中放入生成器的函數(shù)train_generator model.fit_generator(train_generator, steps_per_epoch=times_train, verbose=1, epochs=300, initial_epoch=0, validation_data=val_generator, validation_steps=times_val, callbacks=[save_weights, TrainValTensorBoard(write_graph=False)])
第三步:寫(xiě)入fit_generator進(jìn)行訓(xùn)練
已經(jīng)寫(xiě)在上一個(gè)代碼中。
第四步:寫(xiě)predict_generator進(jìn)行預(yù)測(cè)**
首先我們需要建立同樣的目錄結(jié)構(gòu)。把包含預(yù)測(cè)圖片的次級(jí)目錄放在一個(gè)文件夾下,這個(gè)文件夾名就是關(guān)鍵文件夾。
這里我的關(guān)鍵文件夾是test文件夾
# 建立預(yù)處理 predict_datagen = ImageDataGenerator(rescale=1./255) predict_generator = predict_datagen.flow_from_directory('AgriculturalDisease_validationset/test', target_size=(height, width), batch_size=128) # predict_generator.reset() # 利用predict_generator進(jìn)行預(yù)測(cè) pred = model.predict_generator(predict_generator, max_queue_size=10, workers=1, verbose=1) # 利用幾個(gè)屬性來(lái)讀取文件夾和對(duì)應(yīng)的分類(lèi) train_datagen = ImageDataGenerator(rescale=1./255, rotation_range=40, fill_mode='wrap') train_generator = train_datagen.flow_from_directory('new_images', target_size=(height, width), batch_size=96) labels = (train_generator.class_indices) labels = dict((v,k) for k,v in labels.items()) predictions = [labels[k] for k in predicted_class_indices] # 還可以知道圖片的名字 filenames = predict_generator.filenames
補(bǔ)充知識(shí):[TensorFlow 2] [Keras] fit()、fit_generator() 和 train_on_batch() 分析與應(yīng)用
前言
是的,除了水報(bào)錯(cuò)文,我也來(lái)寫(xiě)點(diǎn)其他的。本文主要介紹Keras中以下三個(gè)函數(shù)的用法:
1、fit()
2、fit_generator()
3、train_on_batch()
當(dāng)然,與上述三個(gè)函數(shù)相似的evaluate、predict、test_on_batch、predict_on_batch、evaluate_generator和predict_generator等就不詳細(xì)說(shuō)了,舉一反三嘛。
環(huán)境
本文的代碼是在以下環(huán)境下進(jìn)行測(cè)試的:
Windows 10
Python 3.6
TensorFlow 2.0 Alpha
異同
大家用Keras也就圖個(gè)簡(jiǎn)單快捷,但是在享受簡(jiǎn)單快捷的時(shí)候,也常常需要些定制化需求,除了model.fit(),有時(shí)候model.fit_generator()和model.train_on_batch()也很重要。
那么,這三個(gè)函數(shù)有什么異同呢?Adrian Rosebrock [1] 有如下總結(jié):
當(dāng)你使用.fit()函數(shù)時(shí),意味著如下兩個(gè)假設(shè):
訓(xùn)練數(shù)據(jù)可以 完整地 放入到內(nèi)存(RAM)里
數(shù)據(jù)已經(jīng)不需要再進(jìn)行任何處理了
這兩個(gè)原因解釋的非常好,之前我運(yùn)行程序的時(shí)候,由于數(shù)據(jù)集太大(實(shí)際中的數(shù)據(jù)集顯然不會(huì)都像 TensorFlow 官方教程里經(jīng)常使用的 MNIST 數(shù)據(jù)集那樣?。淮涡约虞d訓(xùn)練數(shù)據(jù)到fit()函數(shù)里根本行不通:
history = model.fit(train_data, train_label) // Bomb!!!
于是我想,能不能先加載一個(gè)batch訓(xùn)練,然后再加載一個(gè)batch,如此往復(fù)。于是我就注意到了fit_generator()函數(shù)。什么時(shí)候該使用fit_generator函數(shù)呢?Adrian Rosebrock 的總結(jié)道:
內(nèi)存不足以一次性加載整個(gè)訓(xùn)練數(shù)據(jù)的時(shí)候
需要一些數(shù)據(jù)預(yù)處理(例如旋轉(zhuǎn)和平移圖片、增加噪音、擴(kuò)大數(shù)據(jù)集等操作)
在生成batch的時(shí)候需要更多的處理
對(duì)于我自己來(lái)說(shuō),除了數(shù)據(jù)集太大的緣故之外,我需要在生成batch的時(shí)候,對(duì)輸入數(shù)據(jù)進(jìn)行padding,所以fit_generator()就派上了用場(chǎng)。下面介紹如何使用這三種函數(shù)。
fit()函數(shù)
fit()函數(shù)其實(shí)沒(méi)什么好說(shuō)的,大家在看TensorFlow教程的時(shí)候已經(jīng)見(jiàn)識(shí)過(guò)了。此外插一句話(huà),tf.data.Dataset對(duì)不規(guī)則的序列數(shù)據(jù)真是不友好。
import tensorflow as tf model = tf.keras.models.Sequential([ ... // 你的模型 ]) model.fit(train_x, // 訓(xùn)練輸入 train_y, // 訓(xùn)練標(biāo)簽 epochs=5 // 訓(xùn)練5輪 )
fit_generator()函數(shù)
fit_generator()函數(shù)就比較重要了,也是本文討論的重點(diǎn)。fit_generator()與fit()的主要區(qū)別就在一個(gè)generator上。之前,我們把整個(gè)訓(xùn)練數(shù)據(jù)都輸入到fit()里,我們也不需要考慮batch的細(xì)節(jié);現(xiàn)在,我們使用一個(gè)generator,每次生成一個(gè)batch送給fit_generator()訓(xùn)練。
def generator(x, y, b_size): ... // 處理函數(shù) model.fit_generator(generator(train_x, train_y, batch_size), step_per_epochs=np.ceil(len(train_x)/batch_size), epochs=5 )
從上述代碼中,我們發(fā)現(xiàn)有兩處不同:
一個(gè)我們自定義的generator()函數(shù),作為fit_generator()函數(shù)的第一個(gè)參數(shù);
fit_generator()函數(shù)的step_per_epochs參數(shù)
自定義的generator()函數(shù)
該函數(shù)即是我們數(shù)據(jù)的生成器,在訓(xùn)練的時(shí)候,fit_generator()函數(shù)會(huì)不斷地執(zhí)行g(shù)enerator()函數(shù),獲取一個(gè)個(gè)的batch。
def generator(x, y, b_size): """Generates batch and batch and batch then feed into models. Args: x: input data; y: input labels; b_size: batch_size. Yield: (batch_x, batch_label): batched x and y. """ while 1: // 死循環(huán) idx = ... batch_x = ... batch_y = ... ... // 任何你想要對(duì)這個(gè)`batch`中的數(shù)據(jù)執(zhí)行的操作 yield (batch_x, batch_y)
需要注意的是,不要使用return或者exit。
step_per_epochs參數(shù)
由于generator()函數(shù)的循環(huán)沒(méi)有終止條件,fit_generator也不知道一個(gè)epoch什么時(shí)候結(jié)束,所以我們需要手動(dòng)指定step_per_epochs參數(shù),一般的數(shù)值即為len(y)//batch_size。如果數(shù)據(jù)集大小不能整除batch_size,而且你打算使用最后一個(gè)batch的數(shù)據(jù)(該batch比batch_size要?。?,此時(shí)使用np.ceil(len(y)/batch_size)。
keras.utils.Sequence類(lèi)(2019年6月10日更新)
除了寫(xiě)generator()函數(shù),我們還可以利用keras.utils.Sequence類(lèi)來(lái)生成batch。先扔代碼:
class Generator(keras.utils.Sequence): def __init__(self, x, y, b_size): self.x, self.y = x, y self.batch_size = b_size def __len__(self): return math.ceil(len(self.y)/self.batch_size def __getitem__(self, idx): b_x = self.x[idx*self.batch_size:(idx+1)*self.batch_size] b_y = self.y[idx*self.batch_size:(idx+1)*self.batch_size] ... // 對(duì)`batch`的其余操作 return np.array(b_x), np.array(b_y) def on_epoch_end(self): """執(zhí)行完一個(gè)`epoch`之后,還可以做一些其他的事情!""" ...
我們首先定義__init__函數(shù),讀取訓(xùn)練集數(shù)據(jù),然后定義__len__函數(shù),返回一個(gè)epoch中需要執(zhí)行的step數(shù)(此時(shí)在fit_generator()函數(shù)中就不需要指定steps_per_epoch參數(shù)了),最后定義__getitem__函數(shù),返回一個(gè)batch的數(shù)據(jù)。代碼如下:
train_generator = Generator(train_x, train_y, batch_size) val_generator = Generator(val_x, val_y, batch_size) model.fit_generator(generator=train_generator, epochs=3197747, validation_data=val_generator )
根據(jù)官方 [2] 的說(shuō)法,使用Sequence類(lèi)可以保證在多進(jìn)程的情況下,每個(gè)epoch中的樣本只會(huì)被訓(xùn)練一次??傊?,使用keras.utils.Sequence也是很方便的啦!
train_on_batch()函數(shù)
train_on_batch()函數(shù)接受一個(gè)batch的輸入和標(biāo)簽,然后開(kāi)始反向傳播,更新參數(shù)等。大部分情況下你都不需要用到train_on_batch()函數(shù),除非你有著充足的理由去定制化你的模型的訓(xùn)練流程。
結(jié)語(yǔ)
本文到此結(jié)束啦!希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
PyTorch零基礎(chǔ)入門(mén)之構(gòu)建模型基礎(chǔ)
PyTorch是一個(gè)開(kāi)源的Python機(jī)器學(xué)習(xí)庫(kù),基于Torch,用于自然語(yǔ)言處理等應(yīng)用程序,它是一個(gè)可續(xù)計(jì)算包,提供兩個(gè)高級(jí)功能:1、具有強(qiáng)大的GPU加速的張量計(jì)算(如NumPy)。2、包含自動(dòng)求導(dǎo)系統(tǒng)的深度神經(jīng)網(wǎng)絡(luò)2021-10-10python計(jì)算兩個(gè)矩形框重合百分比的實(shí)例
今天小編就為大家分享一篇python計(jì)算兩個(gè)矩形框重合百分比的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-11-11python中的print()函數(shù)end=' '的使用及說(shuō)明
這篇文章主要介紹了python中的print()函數(shù)end=' '的使用及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-02-02Python鍵盤(pán)輸入轉(zhuǎn)換為列表的實(shí)例
今天小編就為大家分享一篇Python鍵盤(pán)輸入轉(zhuǎn)換為列表的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-06-06用十張圖詳解TensorFlow數(shù)據(jù)讀取機(jī)制(附代碼)
這篇文章主要介紹了用十張圖詳解TensorFlow數(shù)據(jù)讀取機(jī)制(附代碼),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-02-02通過(guò)python爬蟲(chóng)mechanize庫(kù)爬取本機(jī)ip地址的方法
python中的mechanize算是一個(gè)比較古老的庫(kù)了,在python2的時(shí)代中,使用的多一些,在python3以后就很少使用了,現(xiàn)在已經(jīng)是2202年了,可能很多人都沒(méi)聽(tīng)說(shuō)過(guò)mechanize,這不要緊,我們先來(lái)簡(jiǎn)單的講解一下,如何使用mechanize,感興趣的朋友一起看看吧2022-08-08