深度學習基礎系列(十一)| Keras中影象增強技術詳解
在深度學習中,資料短缺是我們經常面臨的一個問題,雖然現在有不少公開資料集,但跟大公司掌握的海量資料集相比,數量上仍然偏少,而某些特定領域的資料採集更是非常困難。根據之前的學習可知,資料量少帶來的最直接影響就是過擬合。那有沒有辦法在現有少量資料基礎上,降低或解決過擬合問題呢?
答案是有的,就是資料增強技術。我們可以對現有的資料,如圖片資料進行平移、翻轉、旋轉、縮放、亮度增強等操作,以生成新的圖片來參與訓練或測試。這種操作可以將圖片數量提升數倍,由此大大降低了過擬合的可能。本文將詳解影象增強技術在Keras中的原理和應用。
一、Keras中的ImageDataGenerator類
影象增強的官網地址是:https://keras.io/preprocessing/image/ ,API使用相對簡單,功能也很強大。
先介紹的是ImageDataGenerator類,這個類定義了圖片該如何進行增強操作,其API及引數定義如下:
keras.preprocessing.image.ImageDataGenerator(
featurewise_center=False, #輸入值按照均值為0進行處理 samplewise_center=False, #每個樣本的均值按0處理 featurewise_std_normalization=False, #輸入值按照標準正態化處理
samplewise_std_normalization=False, #每個樣本按照標準正態化處理 zca_whitening=False, # 是否開啟增白 zca_epsilon=1e-06, rotation_range=0, #影象隨機旋轉一定角度,最大旋轉角度為設定值 width_shift_range=0.0, #影象隨機水平平移,最大平移值為設定值。若值為小於1的float值,則可認為是按比例平移,若大於1,則平移的是畫素;若值為整型,平移的也是畫素;假設畫素為2.0,則移動範圍為[-1,1]之間 height_shift_range=0.0, #影象隨機垂直平移,同上 brightness_range=None, # 影象隨機亮度增強,給定一個含兩個float值的list,亮度值取自上下限值間 shear_range=0.0, # 影象隨機修剪 zoom_range=0.0, # 影象隨機變焦 channel_shift_range=0.0, fill_mode='nearest', #填充模式,預設為最近原則,比如一張圖片向右平移,那麼最左側部分會被臨近的圖案覆蓋 cval=0.0, horizontal_flip=False, #影象隨機水平翻轉 vertical_flip=False, #影象隨機垂直翻轉 rescale=None, #縮放尺寸 preprocessing_function=None, data_format=None, validation_split=0.0, dtype=None)
下文將以mnist和花類的資料集進行圖片操作,其中花類(17種花,共1360張圖片)資料集可見我的百度網盤: https://pan.baidu.com/s/1YDA_VOBlJSQEijcCoGC60w 。讓我們以直觀地方式看看各引數能帶來什麼樣的圖片變化。
隨機旋轉
我們可用mnist資料集對圖片進行隨機旋轉,旋轉的最大角度由引數定義。
from keras.datasets import mnist from keras.preprocessing.image import ImageDataGenerator from matplotlib import pyplot from keras import backend as K K.set_image_dim_ordering('th') (train_data, train_label), (test_data, test_label) = mnist.load_data() train_data = train_data.reshape(train_data.shape[0], 1, 28, 28) train_data = train_data.astype('float32') # 建立影象生成器,指定對影象操作的內容 datagen = ImageDataGenerator(rotation_range=90) # 影象生成器要訓練的資料 datagen.fit(train_data) # 這是個影象生成迭代器,是可以無限生成各種新圖片,我們指定每輪迭代只生成9張圖片 for batch_data, batch_label in datagen.flow(train_data, train_label, batch_size=9): for i in range(0, 9): # 建立一個 3*3的九宮格,以顯示圖片 pyplot.subplot(330 + 1 + i) pyplot.imshow(batch_data[i].reshape(28, 28), cmap=pyplot.get_cmap('gray')) pyplot.show() break
生成結果為:
隨機平移
我們可用花類資料集對圖片進行隨機平移,可以在垂直和水平方向上平移,平移最大值由引數定義。
from keras.preprocessing.image import ImageDataGenerator from matplotlib import pyplot from keras.preprocessing.image import array_to_img IMAGE_SIZE = 224 NUM_CLASSES = 17 TRAIN_PATH = '/home/yourname/Documents/tensorflow/images/17flowerclasses/train' TEST_PATH = '/home/yourname/Documents/tensorflow/images/17flowerclasses/test' FLOWER_CLASSES = ['Bluebell', 'ButterCup', 'ColtsFoot', 'Cowslip', 'Crocus', 'Daffodil', 'Daisy', 'Dandelion', 'Fritillary', 'Iris', 'LilyValley', 'Pansy', 'Snowdrop', 'Sunflower', 'Tigerlily', 'tulip', 'WindFlower'] # 建立影象生成器,指定對影象操作的內容,平移的最大比例為50% train_datagen = ImageDataGenerator(width_shift_range=0.5, height_shift_range=0.5) # 這是個影象生成迭代器,是可以無限生成各種新圖片,我們指定每輪迭代只生成9張圖片 for X_batch, y_batch in train_datagen.flow_from_directory(directory=TRAIN_PATH, target_size=(IMAGE_SIZE, IMAGE_SIZE),batch_size=9, classes=FLOWER_CLASSES): for i in range(0, 9): pyplot.subplot(330 + 1 + i) pyplot.imshow(array_to_img(X_batch[i])) pyplot.show() break
生成結果為:
可以觀察到,圖片除了實現平移外,其原來的位置都被最近的圖案給填充,因為預設給的填充方式是nearest。
隨機亮度調整
我們可用花類資料集對圖片進行隨機亮度調整,亮度範圍由引數定義。
from keras.preprocessing.image import ImageDataGenerator from matplotlib import pyplot from keras.preprocessing.image import array_to_img IMAGE_SIZE = 224 NUM_CLASSES = 17 TRAIN_PATH = '/home/yourname/Documents/tensorflow/images/17flowerclasses/train' TEST_PATH = '/home/yourname/Documents/tensorflow/images/17flowerclasses/test' FLOWER_CLASSES = ['Bluebell', 'ButterCup', 'ColtsFoot', 'Cowslip', 'Crocus', 'Daffodil', 'Daisy', 'Dandelion', 'Fritillary', 'Iris', 'LilyValley', 'Pansy', 'Snowdrop', 'Sunflower', 'Tigerlily', 'tulip', 'WindFlower'] # 建立影象生成器,指定對影象操作的內容,亮度範圍在0.1~10之間隨機選擇 train_datagen = ImageDataGenerator(brightness_range=[0.1, 10]) # 這是個影象生成迭代器,是可以無限生成各種新圖片,我們指定每輪迭代只生成9張圖片 for X_batch, y_batch in train_datagen.flow_from_directory(directory=TRAIN_PATH, target_size=(IMAGE_SIZE, IMAGE_SIZE),batch_size=9, classes=FLOWER_CLASSES): for i in range(0, 9): pyplot.subplot(330 + 1 + i) pyplot.imshow(array_to_img(X_batch[i])) pyplot.show() break
生成結果為:
隨機焦距調整
我們可用mnist資料集對圖片進行隨機焦距調整,焦距調整值由引數定義。
from keras.datasets import mnist from keras.preprocessing.image import ImageDataGenerator from matplotlib import pyplot from keras import backend as K K.set_image_dim_ordering('th') (train_data, train_label), (test_data, test_label) = mnist.load_data() train_data = train_data.reshape(train_data.shape[0], 1, 28, 28) train_data = train_data.astype('float32') # 建立影象生成器,指定對影象操作的內容,焦距值在0.1~1之間 datagen = ImageDataGenerator(zoom_range=[0.1, 1]) # 影象生成器要訓練的資料 datagen.fit(train_data) # 這是個影象生成迭代器,是可以無限生成各種新圖片,我們指定每輪迭代只生成9張圖片 for batch_data, batch_label in datagen.flow(train_data, train_label, batch_size=9): for i in range(0, 9): # 建立一個 3*3的九宮格,以顯示圖片 pyplot.subplot(330 + 1 + i) pyplot.imshow(batch_data[i].reshape(28, 28), cmap=pyplot.get_cmap('gray')) pyplot.show() break
生成結果為:
可以看出這跟相機調焦一樣,可以放大或縮小焦距。
隨機翻轉
我們可用花類資料集對圖片進行隨機翻轉。
from keras.preprocessing.image import ImageDataGenerator from matplotlib import pyplot from keras.preprocessing.image import array_to_img IMAGE_SIZE = 224 NUM_CLASSES = 17 TRAIN_PATH = '/home/hutao/Documents/tensorflow/images/17flowerclasses/train' TEST_PATH = '/home/hutao/Documents/tensorflow/images/17flowerclasses/test' FLOWER_CLASSES = ['Bluebell', 'ButterCup', 'ColtsFoot', 'Cowslip', 'Crocus', 'Daffodil', 'Daisy', 'Dandelion', 'Fritillary', 'Iris', 'LilyValley', 'Pansy', 'Snowdrop', 'Sunflower', 'Tigerlily', 'tulip', 'WindFlower'] # 建立影象生成器,指定對影象操作的內容,圖片隨機翻轉 train_datagen = ImageDataGenerator(horizontal_flip=True, vertical_flip=True) # 這是個影象生成迭代器,是可以無限生成各種新圖片,我們指定每輪迭代只生成9張圖片 for X_batch, y_batch in train_datagen.flow_from_directory(directory=TRAIN_PATH, target_size=(IMAGE_SIZE, IMAGE_SIZE),batch_size=9, classes=FLOWER_CLASSES): for i in range(0, 9): pyplot.subplot(330 + 1 + i) pyplot.imshow(array_to_img(X_batch[i])) pyplot.show() break
生成結果為:
從上圖可看出,有些圖片水平翻轉了,有些是垂直翻轉了。
ZCA影象增白
說實在我不太清楚該技術有何用,用花類圖片實驗結果顯示zca不支援,可以用mnist資料集來看看效果。
from keras.datasets import mnist from keras.preprocessing.image import ImageDataGenerator from matplotlib import pyplot from keras import backend as K K.set_image_dim_ordering('th') (train_data, train_label), (test_data, test_label) = mnist.load_data() train_data = train_data.reshape(train_data.shape[0], 1, 28, 28) train_data = train_data.astype('float32') # 建立影象生成器,指定對影象操作的內容,增白圖片 datagen = ImageDataGenerator(zca_whitening=True) # 影象生成器要訓練的資料 datagen.fit(train_data) # 這是個影象生成迭代器,是可以無限生成各種新圖片,我們指定每輪迭代只生成9張圖片 for batch_data, batch_label in datagen.flow(train_data, train_label, batch_size=9): for i in range(0, 9): # 建立一個 3*3的九宮格,以顯示圖片 pyplot.subplot(330 + 1 + i) pyplot.imshow(batch_data[i].reshape(28, 28), cmap=pyplot.get_cmap('gray')) pyplot.show() break
生成結果為:
特徵標準化
特徵標準化的含義是使圖片的畫素均值為0,標準差為1,不過我試了多次,直觀效果不明顯。
from keras.datasets import mnist from keras.preprocessing.image import ImageDataGenerator from matplotlib import pyplot from keras import backend as K K.set_image_dim_ordering('th') (train_data, train_label), (test_data, test_label) = mnist.load_data() train_data = train_data.reshape(train_data.shape[0], 1, 28, 28) train_data = train_data.astype('float32') # 建立影象生成器,指定對影象操作的內容,允許圖片標準化處理 datagen = ImageDataGenerator(featurewise_center=True, featurewise_std_normalization=True) # 影象生成器要訓練的資料 datagen.fit(train_data) # 這是個影象生成迭代器,是可以無限生成各種新圖片,我們指定每輪迭代只生成9張圖片 for batch_data, batch_label in datagen.flow(train_data, train_label, batch_size=9): for i in range(0, 9): # 建立一個 3*3的九宮格,以顯示圖片 pyplot.subplot(330 + 1 + i) pyplot.imshow(batch_data[i].reshape(28, 28), cmap=pyplot.get_cmap('gray')) pyplot.show() break
生成結果為:
就個人而言,我傾向於在影象增強中使用旋轉、亮度調整、翻轉和平移操作。
二、Keras如何進行影象增強資料訓練
在之前的文章中我已經展現過資料增強的使用。在Keras中,增強圖片有三種來源:
- 圖片來源於已知資料集,如mnist、cifar,資料格式為numpy格式;
- 圖片來源於我們自己蒐集的圖片,如本文引入的花類資料集,其圖片為jpg、png等格式;
- 圖片來源於panda資料集;
其中資料來源已知資料集,其操作方法如下:
(x_train, y_train), (x_test, y_test) = cifar10.load_data() y_train = np_utils.to_categorical(y_train, num_classes) y_test = np_utils.to_categorical(y_test, num_classes) datagen = ImageDataGenerator( featurewise_center=True, featurewise_std_normalization=True, rotation_range=20, width_shift_range=0.2, height_shift_range=0.2, horizontal_flip=True) #生成器繫結訓練集 datagen.fit(x_train) # 模型繫結生成器,並不停地迭代產生資料,可指定迭代次數,假設圖片總數為1000張,batch預設為32,則每次迭代需要產生1000/32=32個步驟 history = model.fit_generator(datagen.flow(x_train, y_train, batch_size=32), steps_per_epoch=len(x_train) / 32, epochs=epochs)
資料來源圖片集,其操作方法如下:
batch_size = 32 # 迭代50次 epochs = 50 # 依照模型規定,圖片大小被設定為224 IMAGE_SIZE = 224 TRAIN_PATH = '/home/yourname/Documents/tensorflow/images/17flowerclasses/train' TEST_PATH = '/home/yourname/Documents/tensorflow/images/17flowerclasses/test' FLOWER_CLASSES = ['Bluebell', 'ButterCup', 'ColtsFoot', 'Cowslip', 'Crocus', 'Daffodil', 'Daisy','Dandelion', 'Fritillary', 'Iris', 'LilyValley', 'Pansy', 'Snowdrop', 'Sunflower','Tigerlily', 'tulip', 'WindFlower'] # 使用資料增強 train_datagen = ImageDataGenerator(rotation_range=90)
# 可指定輸出圖片大小,因為深度學習要求訓練圖片大小保持一致 train_generator = train_datagen.flow_from_directory(directory=TRAIN_PATH, target_size=(IMAGE_SIZE, IMAGE_SIZE), classes=FLOWER_CLASSES) test_datagen = ImageDataGenerator() test_generator = test_datagen.flow_from_directory(directory=TEST_PATH, target_size=(IMAGE_SIZE, IMAGE_SIZE), classes=FLOWER_CLASSES) # 執行模型 history = model.fit_generator(train_generator, epochs=epochs, validation_data=test_generator)
需要說明的是,這些增強圖片都是在記憶體中實時批量迭代生成的,不是一次性被讀入記憶體,這樣可以極大地節約記憶體空間,加快處理速度。若想保留中間過程生成的增強圖片,可以在上述方法中新增儲存路徑等引數,此處不再贅述。
三、結論
本文介紹瞭如何在Keras中使用影象增強技術,對圖片可以進行各種操作,以生成數倍於原圖片的增強圖片集。這些資料集可幫助我們有效地對抗過擬合問題,更好地生成理想的模型。