FancyKeras-數據的輸入(傳統)

數據輸入如流水,流暢就如瀑布傾瀉,阻塞就如大學宿舍自來水。

如果你有上過Jeremy Howard和Rachel Tomas的fast.ai課程,課程一開始讓你直接把圖片扔進一個文件夾里,直接調用裡面自定義的「get_batch」、「get_data」函數就能實現數據的輸入,是不是特別方便?

今天就來介紹一下用keras實現數據輸入的幾種方式,因為這個是最最基礎的部分,但是很多新手往往會迷失在這一部分,而且如果設置得當,還能加速你的訓練過程哦!

首先明確一點,模型是不能直接對圖片進行卷積操作的,必須先轉化為numpy數組才能輸入模型裡面去,而且如果數據集的圖片尺寸不統一,也有不同的操作細節。

一、單張圖片輸入

先從最簡單的開始,把圖片轉成numpy array即可,單張圖片輸入只能用於模型預測的時候。

適用情況:

圖片數量:單張

適用場景:模型預測

圖片尺寸:統一

import numpy as npnfrom keras.utils import to_categoricalnfrom keras.preprocessing import imagenfrom keras.applications.resnet50 import ResNet50nnfile_path = /image/dogs_001.jpgnimg = image.load_img(file_path, target_size=(224, 224))nx = image.img_to_array(img)nx = np.expand_dims(x, axis=0)nnmodel = Resnet50(weights=imagenet)nmodel.predict(x)n

解釋下步驟,load_img是keras調用了pillow的Image函數,對指定file_path的圖片進行提取,然後使用img_to_array把圖片轉換成為numpy數組,shape為(224, 224, 3),而expand_dims的作用是把shape(224, 224, 3)轉換成(0, 224, 224, 3),為什麼要這個expand_dims?因為模型本身要求輸入尺寸是(None, 224, 224, 3),這個None表示batch,意思是你要輸入多少張圖片模型是不知道的,所以就用None來表示,而當你輸入圖片的時候,shape必須跟模型輸入的shape保持一致才能輸入。

二、多張圖片輸入

以下代碼適用模型預測。多張圖片輸入思想也很簡單,就是把同一個類別的圖片文件夾底下所有的圖片用for循環load進來,然後加到一個list裡面,最後concatenate起來。

適用情況:

圖片數量:多張

適用場景:模型預測

圖片尺寸:統一

import numpy as npnfrom keras.preprocessing import imagenfrom keras.applications.resnet50 import ResNet50nimport globnnfile_path = D:/Data/dogs/nf_names = glob.glob(file_path + *.jpg)nnimgs = []nfor i in range(len(f_names)): # f_names為所有圖片地址,listn img = image.load_img(f_names[i], target_size=(224, 224)) # 讀取圖片n arr_img = image.img_to_array(img) # 圖片轉換為數組n arr_img = np.expand_dims(arr_img, axis=0) # 增加第一個batch維度n imgs.append(arr_img) # 把圖片數組加到一個列表裡面n print("loading no.%s image."%i)nx = np.concatenate([x for x in imgs]) # 把所有圖片數組concatenate在一起nnprint("predicting...")nmodel = ResNet50(weights=imagenet)ny = model.predict(x)nprint("Completed!")n

concatenate的作用是把shape為(0, 224, 224, 3)的每張圖片tensor,打包成shape為(batch, 224, 224, 3)的tensor,這樣就能實現批量預測或批量訓練了。

三、生成器輸入

很多情況下,你並不能使用以上這些方法來直接輸入數據去訓練或者預測,原因是你的數據集太大了,沒辦法把所有的圖片都載入到內存當中。那keras的data generator就派上用場了,當你的模型需要訓練數據的時候,generator會自動從cpu生成一批圖片,喂到GPU裡面讓模型進行訓練,依次循環,直到訓練結束。

適用情況:

圖片數量:大批量

適用場景:模型預測、訓練

圖片尺寸:可不統一

from keras.preprocessing import ImageDataGeneratornfrom keras.applications.resnet50 import ResNet50nntrn_path = /image/trn/nval_path = /image/val/nn# 這裡先定義一個生成器ngenerator = ImageDataGenerator() # 這裡假設不對原圖做任何操作nn# 生成器從指定路徑中生成圖片ntrn_data = generator.flow_from_directory(trn_path, batch_size=32,n target_size=(224, 224))nval_data = generator.flow_from_directory(val_path, batch_size=32,n target_size=(224, 224))nn# 定義模型nmodel = ResNet50(weights=imagenet)nmodel.compile(optimizers=adam, loss=catagorical_crosscentropy, n metrics=[accuracy])nn# 訓練模型nmodel.fit_generator(n train_generator, # 訓練集生成器n steps_per_epoch=2000, # 每一輪訓練生成兩千個batchn epochs=50, # 一共訓練50輪n validation_data=validation_generator, # 驗證集生成器n validation_steps=800 # 驗證集訓練次數)n

使用生成器的步驟是,先設計一下這個生成器的「功能」(ImageDataGenerator()),你希望這個生成器能夠對你的原圖做何種操作,比如旋轉、放縮、平移、變色等等,我在這裡默認就不作任何操作,有興趣的可以看我另一篇詳解生成器功能的文章:圖片數據集太少?看我七十二變,Keras Image Data Augmentation 各參數詳解

而「flow_from_directory」的功能是根據你希望的功能,製作一個生成器,這個生成器將會把你的數據從某個路徑(trn_path、val_path)生成出來,每次生成32張圖片(batch_size),而且生成的都是大小為(224, 224)的圖片。

接下來當然是定義模型啦,最後就是把這些生成器都放進"fit_generator"這個機器裡面,隆隆隆隆機器就開始訓練啦!

慢著!

keras有個很特別的要求,就是上面那個文件夾路徑,比如我在"/image/trn/"這個文件夾下面有"cats"、"dogs"兩個文件夾,那麼keras的generator就會知道我有兩個分類,它會自動幫我生成標籤,無需自己定義。假如我把路徑定位到"/image/trn/cats/"這個文件夾,裡面有1000張貓咪圖片,那麼keras就會認為我有1000個分類!所以請把路徑定位到包含所有類別文件夾的那個路徑,keras會根據這個路徑下有多少個文件夾就會自動生成多少個標籤!

上面的適用範圍裡面寫到「圖片尺寸可以不統一」,但是如果圖片尺寸不統一的話就不能一批一批生成了,請看第四節。

四、圖片尺寸不統一的輸入

如果你的模型是不定尺寸輸入的,也就是說模型的input_shape是(None, None, None, 3)的話,就不能把不同尺寸的圖片打包成一個batch進行輸入了,因為這種模型在預測或者訓練的時候只能接受一種尺寸,如果batch裡面有多個尺寸,模型就會不知道使用哪個尺寸來計算輸出的shape。目前tensorflow和keras(tf後端)確實不能變尺寸,其它框架不大清楚。所以只能逐張圖片進行輸入啦。

1. 最土的方式,for loop大法逐個預測:

import blablabla......偷懶不寫了nndef read_image(path):n f_names = glob.glob(path + *.jpg)n arr_list = []n for i in range(len(f_names)): # f_names為所有圖片地址,listn img = image.load_img(f_names[i]) # 讀取圖片n arr_img = image.img_to_array(img) # 圖片轉換為數組n arr_img = np.expand_dims(arr_img, axis=0) # 增加第一個batch維度n arr_list.append(arr_img)n return arr_listnndef predict_image(model, img_arr_list):n preds = []n for i in range(len(img_arr_list)):n pred = model.predict(img_arr_list[i], batch_size=1, verbose=0)n preds.append(pred)n return predsnn## model define blablabla......nmodel = Resnet50()npath = /image/test/narr_list = read_image(path)npreds = predict_image(model, arr_list)n

2.generator的方式,一張張生成過去:

from keras.preprocessing import ImageDataGeneratornfrom keras.applications.resnet50 import ResNet50nntrn_path = /image/trn/nval_path = /image/val/nn# 這裡先定義一個生成器ngenerator = ImageDataGenerator() # 這裡假設不對原圖做任何操作nn# 生成器從指定路徑中生成圖片ntrn_data = generator.flow_from_directory(trn_path, batch_size=1) #batch_size注意是1nval_data = generator.flow_from_directory(val_path, batch_size=1)nn# 定義模型nmodel = ResNet50(weights=imagenet)nmodel.compile(optimizers=adam, loss=catagorical_crosscentropy, n metrics=[accuracy])nn# 訓練模型nmodel.fit_generator(n train_generator, # 訓練集生成器n steps_per_epoch=2000, # 每一輪訓練生成兩千個batchn epochs=50, # 一共訓練50輪n validation_data=validation_generator, # 驗證集生成器n validation_steps=800 # 驗證集訓練次數)n

generator幾乎不用修改太多的地方,就把batch_size改成1就好,推薦使用generator。generator還可以設置成多進程多線程的方式來輸入數據,能加快訓練速度,減少GPU等待時間,具體操作就期待《FancyKeras-數據的輸入(花式)》一文吧!

如果您喜歡這個專欄,請關注、分享給您的好友,作者會有更大的動力去寫作!


推薦閱讀:

深度學習畢設有什麼好的題目?
如何看待 Nervana 被 Intel 收購?
AlphaGo 演算法的通用性到底有多廣?
卷積神經網路為什麼要加一層降採樣層呢?
faster rcnn中rpn的anchor,sliding windows,proposals?

TAG:深度学习DeepLearning | Keras | 计算机视觉 |