【问题标题】:Order of rotated images by using a custom generator使用自定义生成器的旋转图像顺序
【发布时间】:2018-12-24 12:42:10
【问题描述】:

我为我的项目使用自定义图像数据生成器。它接收成批的图像并返回图像的 [0, 90, 180 和 270] 度旋转版本以及相应的类索引 {0:0, 1:90, 2:180, 3:270}。假设我们有一批图像 A、B 和 C,整个数据集中有图像 A 到 Z。所有图像自然是 0 度方向。最初我同时返回了所有旋转的图像。这是返回批次的示例:[A0,B0,C0,A1,B1,C1,...,A3,B3,C3]。但这给了我无用的结果。为了比较我的方法,我使用我的生成器训练了相同的模型,并内置了 Keras ImageDataGeneratorflow_from_directory。对于内置功能,我手动旋转原始图像并将它们存储在单独的文件夹中。以下是用于比较的准确度图:

我只使用了几张图片来看看是否有任何区别。从图中可以明显看出自定义生成器不正确。因此我认为它必须将图像返回为[[A0,B0,C0],[D0,E0,F0]...[...,Z0]],然后是[[A1,B1,C1],[D1,E1,F1]...[...,Z1]],依此类推。为此,我必须多次使用以下功能(在我的情况下为 4)。

    def next(self):
    with self.lock:
        # get input data index and size of the current batch
        index_array = next(self.index_generator)
    # create array to hold the images
    return self._get_batches_of_transformed_samples(index_array)

此函数遍历目录并返回批量图像。当它到达最后一个图像时,它完成并开始下一个纪元。就我而言,在一个时代,我想通过发送旋转角度作为这样的参数来运行 4 次:self._get_batches_of_transformed_samples(index_array) , rotation_angle)。我想知道这是否可能?如果不是,那可能是什么解决方案?这是当前的数据生成器代码:

    def _get_batches_of_transformed_samples(self, index_array):
    # create list to hold the images and labels
    batch_x = []    
    batch_y = []

    # create angle categories corresponding to number of rotation angles
    angle_categories = list(range(0, len(self.target_angles)))

    # generate rotated images and corresponding labels
    for rotation_angle, angle_indice in zip(self.target_angles, angle_categories):
        for i, j in enumerate(index_array):
            if self.filenames is None:
                image = self.images[j]
                if len(image.shape) == 2: image = cv2.cvtColor(image,cv2.COLOR_GRAY2RGB)
            else:
                is_color = int(self.color_mode == 'rgb')
                image = cv2.imread(self.filenames[j], is_color)
                if is_color:
                    if not image is None:
                        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

            # do nothing if the image is none
            if not image is None:
                rotated_im = rotate(image, rotation_angle, self.target_size[:2])
                if self.preprocess_func: rotated_im = self.preprocess_func(rotated_im)

                # add dimension to account for the channels if the image is greyscale
                if rotated_im.ndim == 2: rotated_im = np.expand_dims(rotated_im, axis=2)                                
                batch_x.append(rotated_im)
                batch_y.append(angle_indice)

    # convert lists to numpy arrays
    batch_x = np.asarray(batch_x)
    batch_y = np.asarray(batch_y)        

    batch_y = to_categorical(batch_y, len(self.target_angles))            
    return batch_x, batch_y

def next(self):
    with self.lock:
        # get input data index and size of the current batch
        index_array = next(self.index_generator)
    # create array to hold the images
    return self._get_batches_of_transformed_samples(index_array)

【问题讨论】:

    标签: python-3.x keras conv-neural-network


    【解决方案1】:

    嗯,我可能会通过 keras.utils.Sequence 做到这一点

    from keras.utils import Sequence
    import numpy as np
    
    class RotationSequence(Sequence):
        def __init__(self, x_set, y_set, batch_size, rotations=(0,90,180,270)):
            self.rotations = rotations
            self.x, self.y = x_set, y_set
            self.batch_size = batch_size
    
        def __len__(self):
            return int(np.ceil(len(self.x) / float(self.batch_size)))
    
        def __getitem__(self, idx):
            batch_x = self.x[idx * self.batch_size:(idx + 1) * self.batch_size]
            batch_y = self.y[idx * self.batch_size:(idx + 1) * self.batch_size]
    
            x, y = [], []
            for rot in self.rotations:
                x += [rotate(cv2.imread(file_name), rotation_angle) for file_name in batch_x]
                y += batch_y
    
            return np.array(x), np.array(y)
    
        def on_epoch_end(self):
            shuffle_idx = np.random.permutation(len(self.x))
            self.x, self.y = self.x[shuffle_idx], self.y[shuffle_idx]
    

    然后只需将批处理器传递给model.fit()

    rotation_batcher = RotationSequence(...)
    model.fit_generator(rotation_batcher,
        steps_per_epoch=len(rotation_batcher),
        validation_data=validation_batcher,
        epochs=epochs)
    

    这使您可以更好地控制输入模型的批次。这个实现几乎可以运行。您只需要在__getitem__ 中实现rotate() 函数即可。此外,batch_size 将是设定大小的 4 倍,因为我只是复制并旋转了每个批次。希望对你有帮助

    【讨论】:

    • 感谢您的回答。我从代码中了解到,在 for 循环中,您批量生成每个图像的所有旋转版本,并在同一批次中返回 4 个不同方向的图像。如果是,我当前的代码实际上做同样的事情。我的问题是我仍然不确定这是否正确。我认为在每批中我必须只返回属于同一类的图像。我相信这可以运行 'def next(self):' 四次。有没有办法做到这一点?
    • 每批次的种类越多越有利于泛化。为什么你想要一个批次中的所有相同的类?您可以将其更改为self.rotations[epoch%4],这样它只会在一个纪元内旋转一次
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-08-12
    • 2012-03-15
    • 2018-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多