[英]keras `ImageDataGenerator`: apply different augmentation in different directories
我有多個具有相同子目錄結構的數據目錄。 如下-
.
└── data/
├── directory1/
│ ├── train/
│ │ ├── class1
│ │ └── class2
│ ├── validation/
│ │ ├── class1
│ │ └── class2
│ └── test
└── directory2/
├── train/
│ ├── class1
│ └── class2
├── validation/
│ ├── class1
│ └── class2
└── test
但是第二個目錄中的圖像屬性與第一個不同。 比如第二個目錄的圖片大小,或者顏色模式不同。 另外,我將在一個目錄中進行圖像增強,而不是在另一個目錄中。 我的意思是,我想分別處理兩個目錄的圖像,但以一致的形式將它們提供給 model。
這意味着目錄的結構是相同的,但圖像屬性和擴充會有所不同。 在這種情況下如何使用 Keras ImageDataGenerator
? 具體來說,我想使用flow_from_directory
方法。
我看了這個問題,但它並沒有解決我的問題,因為這個問題是關於將相同的屬性和擴充應用到不同的目錄,這不是我的情況。
幾天前我陷入了這個問題。 在網上做了很多研究之后,即使我無法直接找到合適的解決方案,我也可以提出一個想法。 follow symlink 在這里不起作用,因為兩個目錄中的圖片屬性完全不同; 再次,將應用不同的圖像增強。
在這里,我們必須創建兩個單獨的圖像生成器並分別配置它們。 然后我們必須合並它們。 我發現這個想法解決了我的問題, here 。
但是我們需要稍微調整一下。 由於這兩個目錄有不同數量的圖像,簡單地組合兩個相同大小的數據生成器將創建一個不平衡的圖像共享准備饋送。 相對更多的圖像將從圖像較少的目錄饋送到 model。 所以這兩個數據生成器的批量大小必須根據各自目錄中的圖像數量來計算。 這就是我的解決方案的獨創性。
from keras.preprocessing.image import ImageDataGenerator
from keras.utils import Sequence
import matplotlib.pyplot as plt
import numpy as np
import os
class MergedGenerators(Sequence):
def __init__(self, batch_size, generators=[], sub_batch_size=[]):
self.generators = generators
self.sub_batch_size = sub_batch_size
self.batch_size = batch_size
def __len__(self):
return int(
sum([(len(self.generators[idx]) * self.sub_batch_size[idx])
for idx in range(len(self.sub_batch_size))]) /
self.batch_size)
def __getitem__(self, index):
"""Getting items from the generators and packing them"""
X_batch = []
Y_batch = []
for generator in self.generators:
if generator.class_mode is None:
x1 = generator[index % len(generator)]
X_batch = [*X_batch, *x1]
else:
x1, y1 = generator[index % len(generator)]
X_batch = [*X_batch, *x1]
Y_batch = [*Y_batch, *y1]
if self.generators[0].class_mode is None:
return np.array(X_batch)
return np.array(X_batch), np.array(Y_batch)
def build_datagenerator(dir1=None, dir2=None, batch_size=32):
n_images_in_dir1 = sum([len(files) for r, d, files in os.walk(dir1)])
n_images_in_dir2 = sum([len(files) for r, d, files in os.walk(dir2)])
# Have to set different batch size for two generators as number of images
# in those two directories are not same. As we have to equalize the image
# share in the generators
generator1_batch_size = int((n_images_in_dir1 * batch_size) /
(n_images_in_dir1 + n_images_in_dir2))
generator2_batch_size = batch_size - generator1_batch_size
generator1 = ImageDataGenerator(
rescale=1. / 255,
shear_range=0.2,
zoom_range=0.2,
rotation_range=5.,
horizontal_flip=True,
)
generator2 = ImageDataGenerator(
rescale=1. / 255,
zoom_range=0.2,
horizontal_flip=False,
)
# generator2 has different image augmentation attributes than generaor1
generator1 = generator1.flow_from_directory(
dir1,
target_size=(128, 128),
color_mode='rgb',
class_mode=None,
batch_size=generator1_batch_size,
shuffle=True,
seed=42,
interpolation="bicubic",
)
generator2 = generator2.flow_from_directory(
dir2,
target_size=(128, 128),
color_mode='rgb',
class_mode=None,
batch_size=generator2_batch_size,
shuffle=True,
seed=42,
interpolation="bicubic",
)
return MergedGenerators(
batch_size,
generators=[generator1, generator2],
sub_batch_size=[generator1_batch_size, generator2_batch_size])
def test_datagen(batch_size=32):
datagen = build_datagenerator(dir1="./asdf",
dir2="./asdf2",
batch_size=batch_size)
print("Datagenerator length (Batch count):", len(datagen))
for batch_count, image_batch in enumerate(datagen):
if batch_count == 1:
break
print("Images: ", image_batch.shape)
plt.figure(figsize=(10, 10))
for i in range(image_batch.shape[0]):
plt.subplot(1, batch_size, i + 1)
plt.imshow(image_batch[i], interpolation='nearest')
plt.axis('off')
plt.tight_layout()
test_datagen(4)
要獲取子生成器的批量大小:
Where,
b = Batch Size Of Any Sub-generator
B = Desired Batch Size Of The Merged Generator
n = Number Of Images In That Directory Of Sub-generator
the sum of n = Total Number Of Images In All Directories
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.