我应该对图像数据生成器进行哪些更改以解决该错误?

时间:2019-06-16 12:36:49

标签: python keras deep-learning computer-vision classification

我正在尝试执行混合增强(详细信息here),但出现如下所示的值错误:

ValueError: operands could not be broadcast together with shapes (47,128,128,3) (64,1,1,1)

以下是我正在使用的MixupImageDataGenerator类定义:

class MixupImageDataGenerator():
    def __init__(self, generator, directory, batch_size, img_height, img_width, alpha=0.2, subset=None):
        """Constructor for mixup image data generator.

        Keyword Arguments:
            alpha {float} -- Mixup beta distribution alpha parameter. (default: {0.2})
            subset {str} -- 'training' or 'validation' if validation_split is specified in
            `generator` (ImageDataGenerator).(default: {None})
        """
        self.batch_index = 0
        self.batch_size = 64
        self.alpha = alpha

        # First iterator yielding tuples of (x, y)
        self.generator1 = generator.flow_from_directory(directory,
                                                        target_size=(
                                                            128, 128),
                                                        class_mode="categorical",
                                                        batch_size=64,
                                                        shuffle=True,
                                                        subset=subset)

        # Second iterator yielding tuples of (x, y)
        self.generator2 = generator.flow_from_directory(directory,
                                                        target_size=(
                                                            128, 128),
                                                        class_mode="categorical",
                                                        batch_size=64,
                                                        shuffle=True,
                                                        subset=subset)

        # Number of images across all classes in image directory.
        self.n = self.generator1.samples

    def reset_index(self):
        """Reset the generator indexes array.
        """

        self.generator1._set_index_array()
        self.generator2._set_index_array()

    def on_epoch_end(self):
        self.reset_index()

    def reset(self):
        self.batch_index = 0

    def __len__(self):
        # round up
        return (self.n + self.batch_size - 1) // self.batch_size

    def get_steps_per_epoch(self):
        """Get number of steps per epoch based on batch size and
        number of images.

        Returns:
            int -- steps per epoch.
        """

        return self.n // self.batch_size

    def __next__(self):
        """Get next batch input/output pair.

        Returns:
            tuple -- batch of input/output pair, (inputs, outputs).
        """

        if self.batch_index == 0:
            self.reset_index()

        #my_list = []
        current_index = (self.batch_index * self.batch_size) % self.n
        #my_list.insert(0,current_index)
        #print("current index" + str(current_index))


        if self.n > current_index + self.batch_size:
            self.batch_index += 1
        else:
            self.batch_index = 0
        #print("batch_index" + str(self.batch_index))

        # random sample the lambda value from beta distribution.
        l = np.random.beta(self.alpha, self.alpha, self.batch_size)
        print("l")
        print(l.shape)
        X_l = l.reshape(self.batch_size, 1, 1, 1)
        print("X_l")
        print(X_l.shape)
        y_l = l.reshape(self.batch_size, 1)
        print("y_l")
        print(y_l.shape)

        # Get a pair of inputs and outputs from two iterators.
        X1, y1 = self.generator1.next()
        print("X1, y1")
        print(X1.shape, y1.shape)
        X2, y2 = self.generator2.next()
        print("X2, y2")        
        print(X2.shape, y2.shape)

        # Perform the mixup.
        X = X1 * X_l + X2 * (1 - X_l)
        y = y1 * y_l + y2 * (1 - y_l)
        print("X")
        print(X.shape)
        print("y")
        print(y.shape)
        print("my_list " + str(my_list))
        return X, y

    def __iter__(self):
        while True:
            yield next(self)

以下是我的代码,在这里我调用Mixup类并执行实际的增强操作:

# Create training and validation generator.
train_generator = MixupImageDataGenerator(generator=input_datagen,
                                          directory='data/train/',
                                          batch_size=64,
                                          img_height=128,
                                          img_width=128,
                                          subset='training')
validation_generator = input_datagen.flow_from_directory(directory = 'data/train/', target_size=(128, 128), color_mode='rgb', class_mode='categorical',batch_size=64,subset='validation', shuffle=True, seed=42)

print('training steps: ', train_generator.get_steps_per_epoch())
print('validation steps: ', validation_generator.samples // batch_size)

输出:

Found 3503 images belonging to 5 classes.
Found 3503 images belonging to 5 classes.
Found 1496 images belonging to 5 classes.
training steps:  54
validation steps:  23

我开始了培训,并展示了第42步的输出。先前的所有步骤都具有相似的输出。

42/54 [======================>.......] - ETA: 11s - loss: 1.3245 - acc: 0.4565
current index 3392
batch_index 54
\n l
(64,)
X_l
(64, 1, 1, 1)
y_l
(64, 1)
\n X1, y1
(64, 128, 128, 3) (64, 5)
\n X2, y2
(64, 128, 128, 3) (64, 5)
\n X
(64, 128, 128, 3)
y
(64, 5)
43/54 [======================>.......] - ETA: 10s - loss: 1.3227 - acc: 0.4557
current index 3456
batch_index 0
\n l
(64,)
X_l
(64, 1, 1, 1)
y_l
(64, 1)
\n X1, y1
(47, 128, 128, 3) (47, 5)
\n X2, y2
(47, 128, 128, 3) (47, 5)
44/54 [=======================>......] - ETA: 9s - loss: 1.3233 - acc: 0.4538 current index 0
batch_index 1
\n l
(64,)
X_l
(64, 1, 1, 1)
y_l
(64, 1)
\n X1, y1
(64, 128, 128, 3) (64, 5)
\n X2, y2
(64, 128, 128, 3) (64, 5)
\n X
(64, 128, 128, 3)
y
(64, 5)
45/54 [========================>.....] - ETA: 8s - loss: 1.3214 - acc: 0.4549
current index 64
batch_index 2
\n l
(64,)
X_l
(64, 1, 1, 1)
y_l
(64, 1)
\n X1, y1
(64, 128, 128, 3) (64, 5)
\n X2, y2
(64, 128, 128, 3) (64, 5)
\n X
(64, 128, 128, 3)
y
(64, 5)
46/54 [========================>.....] - ETA: 7s - loss: 1.3211 - acc: 0.4541
current index 128
batch_index 3
\n l
(64,)
X_l
(64, 1, 1, 1)
y_l
(64, 1)
\n X1, y1
(64, 128, 128, 3) (64, 5)
\n X2, y2
(64, 128, 128, 3) (64, 5)
\n X
(64, 128, 128, 3)
y
(64, 5)
47/54 [=========================>....] - ETA: 6s - loss: 1.3193 - acc: 0.4561
current index 192
batch_index 4
\n l
(64,)
X_l
(64, 1, 1, 1)
y_l
(64, 1)
\n X1, y1
(64, 128, 128, 3) (64, 5)
\n X2, y2
(64, 128, 128, 3) (64, 5)
\n X
(64, 128, 128, 3)
y
(64, 5)
.
.
.
.
.

53/54 [============================>.] - ETA: 0s - loss: 1.3072 - acc: 0.4608
current index 576
batch_index 10
\n l
(64,)
X_l
(64, 1, 1, 1)
y_l
(64, 1)
\n X1, y1
(64, 128, 128, 3) (64, 5)
\n X2, y2
(64, 128, 128, 3) (64, 5)
\n X
(64, 128, 128, 3)
y
(64, 5)
54/54 [==============================] - 53s 986ms/step - loss: 1.3058 - acc: 0.4606 - val_loss: 1.2556 - val_acc: 0.4749

Epoch 00001: val_acc improved from -inf to 0.47486, saving model to GoDL-NP_CE_NLS_ABC-MIXUP.h5
Epoch 2/3

此后,出现以下错误:

ValueError: operands could not be broadcast together with shapes (47,128,128,3) (64,1,1,1)

我的观察是

1)除步骤43之外,所有其他步骤均具有以下形状:

X1,y1 (64,128,128,3)(64,5)

X2,y2 (64,128,128,3)(64,5)

但是步骤43具有以下形状:

X1,y1 (47,128,128,3)(47,5)

X2,y2 (47,128,128,3)(47,5)

2)在训练的第一步开始之前,数据生成器似乎已经向前移动了,这可以从以下事实看出:第一步运行时cuurent_index = 124。

3)我觉得可用于步骤43的图像仅为47个,而不是预期的64个(等于批处理大小)。我之所以这样说,是因为对于步骤47,current_index = 3456,batch_index = 0。训练图像的总大小为3503。因此,相差为3503-3456 =47。下一步,当前索引= 0,batch_index = 1。

所以,我想我需要的是以下东西:

  1. 如何确保每个步骤都可以使用相等数量的图像?
  2. 如何确保数据生成器和培训保持同步?

1 个答案:

答案 0 :(得分:0)

基于此问题:https://github.com/Tony607/keras_mixup_generator/issues/1

您需要更改混合生成器,以便使用X1.shape[0]为最后一批正确计算lambda的大小:

    # Get a pair of inputs and outputs from two iterators.
    X1, y1 = self.generator1.next()
    X2, y2 = self.generator2.next()


    # random sample the lambda value from beta distribution.
    l = np.random.beta(self.alpha, self.alpha, X1.shape[0])

    X_l = l.reshape(X1.shape[0], 1, 1, 1)
    y_l = l.reshape(X1.shape[0], 1)


    # Perform the mixup.
    X = X1 * X_l + X2 * (1 - X_l)
    y = y1 * y_l + y2 * (1 - y_l)
    return X, y