在深度學習訓練過程中如何設定資料增強?

賈瀾鵬發表於2019-04-30

影象資料增強是人工增加訓練集的一種方式,主要是通過修改資料集中的圖片達成。

更多的訓練資料帶來的是更有效的深度學習模型,同時,資料增強技術會產生更多的圖片變體,這些變體會提高模型對新圖片的泛化能力。

在 Keras 框架中,ImageDataGenerator 類提供了資料增強的相關功能。

在本教程中,你將學會如何在訓練模型時使用影象資料增強技術。

在完成本教程後,你將明白下面幾點:

  • 影象資料增強是為了擴充套件訓練資料集從而提高模型的精度和泛化能力。
  • 在 Keras 框架中,你可以通過 ImageDataGenerator 類使用影象資料增強方法。
  • 如何使用平移、翻轉、亮度以及縮放的資料增強方法。

讓我們開始吧。

教程總覽

本教程被分為以下八個部分,他們分別是:

  1. 影象資料增強
  2. 樣本圖片
  3. 使用 ImageDataGenerator 進行資料增強
  4. 水平和垂直方向的平移增強
  5. 水平和垂直方向的翻轉增強
  6. 隨機旋轉增強
  7. 隨機亮度增強
  8. 隨機縮放增強

資料增強

深度學習網路的表現總是和資料量成正比的。

資料增強是一種人工的在原有資料基礎上增加新訓練資料的方法,是利用特定領域的技術將訓練集的資料轉變成一個新的資料達成的。

影象資料增強大概是最眾所周知的一種資料增強方法,主要是涉及建立一個和原始圖片屬於同一類別的變形後的圖片。

從影象處理領域我們可以獲得很多的變形方法,比如:平移、翻轉、縮放等等。

這麼做的主要意圖是用合理的新資料去擴充套件訓練資料。換句話說,我們可以讓模型看到更多樣性的訓練資料。舉個例子,如果我們對一隻貓進行水平的翻轉,這個是有意義的,因為攝像頭的拍攝角度可能是左邊也可能是右邊。但是做垂直翻轉就沒什麼意義並且不太適合,因為模型不太會接收到一個頭上腳下的貓。

所以,我們應該明白,我們一定要根據訓練資料和問題領域的具體場景來慎重的選擇應用於訓練集的資料增強方法。此外,有一種比較有效的方法,就是在小的原型資料集上做一些獨立的實驗來度量增強後的模型是否在效能上有所提升。

現代的深度學習方法,像卷積神經網路(CNN),都可以學習到圖片中的位置無關性特徵。資料增強可以幫助模型去學習這種性質並且可以使得模型對一些變化也不敏感,比如左到右和上到下的順序、照片的光照變化等等。

這些圖片資料的增強一般是應用於訓練集而不是驗證集和測試集。這些資料增強方法不同於那些需要在各個與模型互動的資料集上都保持一致的預處理方法,比如調整圖片大小與縮放畫素值等。

想要計算機視覺方向的結果?

現在就參加我的7天電子郵件速成課(包含示例程式碼)。

點選註冊還有可以獲得課程的免費 PDF 版本。

下載你的免費迷你課程

樣本圖片

我們需要一個樣本圖片來展示標準的資料增強技術。

本教程中,我們會用到一個已經獲得使用許可,由 AndYaDontStop 拍攝,名為 Feathered Friend 的鳥類照片。

下載這張照片,並儲存在你的工作目錄命名為 ‘bird.jpg‘。

Feathered Friend,作者 AndYaDontStop。

Feathered Friend,作者 AndYaDontStop。
保留部分權力.

使用 ImageDataGenerator 進行影象資料增強

Keras 框架可以在訓練模型時,自動使用資料增強。

可以利用 ImageDataGenerator 類 達到這一目的。

首先,可以在類例項化時傳入特定的引數到建構函式來配置對應的增強方法。

該類支援一系列的增強方法,包括畫素值的縮放,但是我們只關注以下五種主要的影象資料增強方法:

  • 通過 width_shift_rangeheight_shift_range 引數設定影象平移。
  • 通過 rotation_range 引數設定影象翻轉。
  • 通過 brightness_range 引數設定影象亮度。
  • 通過 zoom_range 引數設定影象縮放。

一個通過建構函式例項化 ImageDataGenerator 的例子。

# 建立資料生成器
datagen = ImageDataGenerator()
複製程式碼

一旦構造完成,這個資料集的迭代器就被建立了。

這個迭代器每次迭代會返回一個批次的增強資料。

利用 flow() 函式可以將讀入了記憶體的資料集建立為一個迭代器,示例程式碼如下:

# 讀取圖片資料集
X, y = ...
# 建立迭代器
it = dataset.flow(X, y)
複製程式碼

或者,可以對指定的檔案路徑的資料集建立一個迭代器,在這個資料夾中,不同子類的資料需要存放到不同的子資料夾中。

...
# 建立迭代器
it = dataset.flow_from_directory(X, y, ...)
複製程式碼

迭代器建立完成後,可以通過呼叫 fit_generator() 函式來訓練神經網路。

steps_per_epoch 引數需要設定為能包含整個資料集的批次數。舉個例子,如果你的原始資料是 10000 張圖片,同時你的 batch_size 設定為 32,那麼當你訓練一個基於增強資料的模型時,一個合理的 steps_per_epoch 應該設定為 ceil(10,000/32),或者說 313 個批次。

# 定義模型
model = ...
# 在增強資料集上擬合模型
model.fit_generator(it, steps_per_epoch=313, ...)
複製程式碼

資料集中的圖片並沒有被直接使用,而是將增強後的圖片提供給模型。由於增強的圖片表現是隨機的,容許修改後的圖片以及接近原圖(例如,幾乎沒有增強的圖片)的資料被生成並在訓練中使用。

資料的生成器也可以使用在驗證集和測試集上。通常來說,用於驗證集和測試集的 ImageDataGenerator 會和訓練集的 ImageDataGenerator 有相同的畫素值縮放配置(本教程未涉及),但是不會涉及到資料增強。這是因為資料增強的目的是為了可以人工的擴充訓練資料集的數量,進而去提高模型在未做增強的資料集上的表現。

現在我們已經熟悉了 ImageDataGenerator 的用法,那麼我去看幾個具體的針對於影象資料的增強方法。

我們會單獨的展示每一種方法增強後的圖片效果圖。這是一種很好的事件方式,建議在在配置你們自己的資料增強時也這麼做。在訓練過程中,同時採用好幾種增強方法也是很常見的。這裡為了達到展示的效果,我們分章節單獨的討論每一個增強方法。

水平和垂直平移增強

平移意味著將圖片上的所有畫素沿著某一個方向移動,可以是水平或者垂直,同時要保證大小沒有變化。

這也意味著一些原有的畫素點會被移出圖片,那麼就會有一塊區域的畫素值需要重新指定。

width_shift_rangeheight_shift_range 兩個引數分別用來控制水平和垂直方向平移的大小,它們是在 ImageDataGenerator 類被構造的時候傳入的。

這兩個引數可以被指定為一個 0 到 1 之間的小數,代表著平移距離相對於寬度或者高度的百分比。或者,也可以被指定為一個確切的畫素值。

具體來說,實際的平移值會在沒有平移和百分比(或者具體的畫素值)之間選取一個,用該值來處理圖片,距離來說,就是在 [0, value] 之間選擇。或者,你可以傳入一組指定的元組或陣列,確定具體的最大和最小值來進行取樣,舉個例子:[-100, 100] 或者 [-0.5, 0.5]。

下面展示的就是一個將平移引數 width_shift_range 設定為 [-200, 200] 畫素,並畫出對應結果的程式碼。

# 水平平移增強的例子
from numpy import expand_dims
from keras.preprocessing.image import load_img
from keras.preprocessing.image import img_to_array
from keras.preprocessing.image import ImageDataGenerator
from matplotlib import pyplot
# 讀入圖片
img = load_img('bird.jpg')
# 轉換為 numpy 陣列
data = img_to_array(img)
# 擴充套件維度
samples = expand_dims(data, 0)
# 生成資料增強迭工廠
datagen = ImageDataGenerator(width_shift_range=[-200,200])
# 準備迭代器
it = datagen.flow(samples, batch_size=1)
# 生成資料並畫圖
for i in range(9):
	# 定義子圖
	pyplot.subplot(330 + 1 + i)
	# 生成一個批次圖片
	batch = it.next()
	# 轉換為無符號整型方便顯示
	image = batch[0].astype('uint32')
	# 畫圖
	pyplot.imshow(image)
# 展示圖片
pyplot.show()
複製程式碼

執行這段程式碼,通過配置 ImageDataGenerator 會生成一個圖片增強例項,並建立一個迭代器。這個迭代器會在一個迴圈中被執行 9 次並畫出每一次經過增強後的圖片。

我通過觀察畫出的結果可以發現,圖片會進行隨機的正向或者負向的平移,同時平移帶來的空白區域會使用邊緣區域的畫素來填充。

平移資料增強的結果

隨機平移資料增強結果圖

下面是類似的例子,通過調整 height_shift_range 引數實現垂直平移,其中該引數被設定為 0.5。

# 垂直平移增強的例子
from numpy import expand_dims
from keras.preprocessing.image import load_img
from keras.preprocessing.image import img_to_array
from keras.preprocessing.image import ImageDataGenerator
from matplotlib import pyplot
# 讀圖
img = load_img('bird.jpg')
# convert to numpy array
data = img_to_array(img)
# 擴充套件維度
samples = expand_dims(data, 0)
# 建立一個生成器
datagen = ImageDataGenerator(height_shift_range=0.5)
# 準備迭代器
it = datagen.flow(samples, batch_size=1)
# 生成樣本和畫圖
for i in range(9):
	# 定義子圖
	pyplot.subplot(330 + 1 + i)
	# 生成一個批次的圖片
	batch = it.next()
	# 轉換為整形顯示
	image = batch[0].astype('uint32')
	# 畫圖
	pyplot.imshow(image)
# 顯示
pyplot.show()
複製程式碼

執行這段程式碼,就可以隨機的產生通過正向或者負向平移的增強圖片。

可以發現水平位移或者垂直位移,不論是正向平或者負向都可以有效的增強對應的圖片,但是那些被重新填充的部分對模型就沒什麼意義了。

值得一提的是,其他的填充方式是可以通過 “fill_mode” 引數來指定的。

Plot of Augmented Images With a Random Vertical Shift

垂直隨機平移的效果圖

水平和垂直翻轉增強

圖片的翻轉就是在垂直翻轉時顛倒所有行的畫素值,在水平翻轉時顛倒所有列的畫素值。

翻轉的引數是構造 ImageDataGenerator 類時,分別通過 boolean 型的引數 horizontal_flip 或者 vertical_flip 來指定的。針對於之前提到的鳥的圖片,水平翻轉是有意義的,而垂直翻轉是沒什麼意義的。

而對於航拍圖片、天文圖片和顯微圖片而言,垂直翻轉很大可能是有效的。

下面的例子就是通過控制 horizontal_flip 引數來實現圖片翻轉增強的例子。

# 水平翻轉示例
from numpy import expand_dims
from keras.preprocessing.image import load_img
from keras.preprocessing.image import img_to_array
from keras.preprocessing.image import ImageDataGenerator
from matplotlib import pyplot
# 讀圖
img = load_img('bird.jpg')
# 轉為 numpy 陣列
data = img_to_array(img)
# 擴充套件維度
samples = expand_dims(data, 0)
# 建立生成器
datagen = ImageDataGenerator(horizontal_flip=True)
# 準備迭代器
it = datagen.flow(samples, batch_size=1)
# 生成圖片並畫圖
for i in range(9):
	# 定義子圖
	pyplot.subplot(330 + 1 + i)
	# 生成一個批次圖片
	batch = it.next()
	# 轉化為整型方便顯示
	image = batch[0].astype('uint32')
	# 畫圖
	pyplot.imshow(image)
# 顯示
pyplot.show()
複製程式碼

執行這段程式會產生 9 張增強後的圖片。

我們會發現水平的翻轉只是在一部分的圖片上被使用了。

Plot of Augmented Images With a Random Horizontal Flip

隨機水平翻轉的增強結果

隨機旋轉增強

旋轉增強是隨機的對圖片進行 0 到 360 度的順時針旋轉。

旋轉也會導致部分的資料被移出圖片框,會產生一些沒有畫素值的區域,這些區域也需要被填充

下面的例子通過控制 rotation_range 引數在 0 到 90 度之間去旋轉圖片,來展示隨機旋轉增強的效果。

# 旋轉增強示例
from numpy import expand_dims
from keras.preprocessing.image import load_img
from keras.preprocessing.image import img_to_array
from keras.preprocessing.image import ImageDataGenerator
from matplotlib import pyplot
# 讀圖
img = load_img('bird.jpg')
# 轉為 numpy 陣列
data = img_to_array(img)
# 擴充套件維度
samples = expand_dims(data, 0)
# 建立生成器
datagen = ImageDataGenerator(rotation_range=90)
# 準備迭代器
it = datagen.flow(samples, batch_size=1)
# 生成圖片並畫圖
for i in range(9):
	# 定義子圖
	pyplot.subplot(330 + 1 + i)
	# 生成一個批次圖片
	batch = it.next()
	# 轉化為整型方便顯示
	image = batch[0].astype('uint32')
	# 畫圖
	pyplot.imshow(image)
# 顯示
pyplot.show()
複製程式碼

執行這個例子,會產生旋轉圖片的示例,其中空白區域是通過最鄰近法進行填充的。

Plot of Images Generated With a Random Rotation Augmentation

隨機旋轉增強的結果圖

隨機亮度增強

圖片的亮度增強可以是使圖片變亮、使圖片變暗或者兼顧兩者。

這樣是為了使模型在訓練過程中覆蓋不同的亮度水平。

我可以在 ImageDataGenerator() 的建構函式中傳入 brightness_range 引數來指定一個最大值和最小值範圍來選擇一個亮度數值。

值小於 1.0 的時候,會變暗圖片,如 [0.5 , 1.0],相反的,值大於 1.0 時,會使圖片變亮,如 [1.0,1.5],當值為 1.0 時,亮度不會變化。

下面的例子展示了亮度在 0.2(20%) 到 1 之間變化的隨機亮度增強的效果。

# 亮度增強示例
from numpy import expand_dims
from keras.preprocessing.image import load_img
from keras.preprocessing.image import img_to_array
from keras.preprocessing.image import ImageDataGenerator
from matplotlib import pyplot
# 讀圖
img = load_img('bird.jpg')
# 轉為 numpy 陣列
data = img_to_array(img)
# 擴充套件維度
samples = expand_dims(data, 0)
# 建立生成器
datagen = ImageDataGenerator(brightness_range=[0.2,1.0])
# 準備迭代器
it = datagen.flow(samples, batch_size=1)
# 生成圖片並畫圖
for i in range(9):
	# 定義子圖
	pyplot.subplot(330 + 1 + i)
	# 生成一個批次圖片
	batch = it.next()
	# 轉化為整型方便顯示
	image = batch[0].astype('uint32')
	# 畫圖
	pyplot.imshow(image)
# 顯示
pyplot.show()
複製程式碼

執行示例你會看到不同數值調暗圖片的效果。

Plot of Images Generated With a Random Brightness Augmentation

隨機亮度增強生成的圖片

隨機縮放增強

縮放增強就是隨機的縮放圖片,利用在圖片周圍新增畫素或者插值來實現。

ImageDataGenerator 類的建構函式內傳入 zoom_range 來配置縮放的尺度。該引數可以是一個浮點數也可以是陣列或者元組。

如果指定為一個浮點數,那麼縮放的範圍是 [1 - value , 1 + value] 之間。舉個例子,如果你設定的引數為 0.3,那麼你的縮放範圍就是 [0.7, 1.3] 之間,換言之就是 70% (放大)到 130%(縮小)之間。

縮放量是從縮放區域中對每個維度(寬,高)分別均勻隨機抽樣得到的。

縮放引數有點不直觀。需要明白一點,當數值小於 1.0 時圖片會放大,如 [ 0.5 , 0.5] 會使圖片中的目標變大或者拉近 50%,同樣的,如果數值大於 1.0 時,圖拼啊會被縮小 50%,如 [ 1.5 , 1.5 ] 目標會被縮小到或者拉遠。當係數為 1.0 時,圖片不會有什麼變化。

下面的例子展示了讓圖片中目標變大的例子。

# 尺度縮放增強示例
from numpy import expand_dims
from keras.preprocessing.image import load_img
from keras.preprocessing.image import img_to_array
from keras.preprocessing.image import ImageDataGenerator
from matplotlib import pyplot
# 讀圖
img = load_img('bird.jpg')
# 轉為 numpy 陣列
data = img_to_array(img)
# 擴充套件維度
samples = expand_dims(data, 0)
# 建立生成器
datagen = ImageDataGenerator(zoom_range=[0.5,1.0])
# 準備迭代器
it = datagen.flow(samples, batch_size=1)
# 生成圖片並畫圖
for i in range(9):
	# 定義子圖
	pyplot.subplot(330 + 1 + i)
	# 生成一個批次圖片
	batch = it.next()
	# 轉化為整型方便顯示
	image = batch[0].astype('uint32')
	# 畫圖
	pyplot.imshow(image)
# 顯示
pyplot.show()
複製程式碼

執行示例就可以得到縮放圖片,該圖片展示了一個在寬和高尺度變化不同的例子,由於寬高的縮放尺度不同,影象的縱橫比也會發生變化。

Plot of Images Generated With a Random Zoom Augmentation

隨機縮放增強的效果圖

擴充套件閱讀

該部分會提供更多的資源供你進一步的學習。

出版物

API

文章

總結

本教程帶你探索了影象資料增強在模型訓練時的應用。

你應該有以下收穫:

  • 影象資料增強是為了擴充套件訓練資料集,從而提高模型的效能和泛化能力。
  • 通過使用 ImageDataGenerator 類,你可以在 Keras 上獲得影象資料增強的支援。
  • 如何使用平移、翻轉、亮度和縮放增強方法。

還有別的問題? 請在下方留言,我會盡我所能回答你的問題。

如果發現譯文存在錯誤或其他需要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可獲得相應獎勵積分。文章開頭的 本文永久連結 即為本文在 GitHub 上的 MarkDown 連結。


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章