文档开发者中心
我的

一般在使用 Keras 进行图像方面的神经网络的训练的时候都...

一般在使用 Keras 进行图像方面的神经网络的训练的时候都会使用图片生成器 ImageDataGeneraor,它不仅仅使用方便,更支持实时数据增强。在使用 CPU 进行数据增强的同时,使用 GPU 训练模型,大大加快了模型训练的速度。

  Keras 的《官方文档》 和早期网友翻译的《文档》都对它的使用进行了较为详细的解释,可能由于篇幅的限制,这些文档对于一些较为细节的问题没有过多的介绍,在这里我在前人的基础上进行一些补充。注意本文主要参照上面两个文档的内容而成,我自己单独补充的部分进行了黑体加粗。

1. ImageDataGenerator 类
  下面是关于ImageDataGenerator 类的参数说明
keras.preprocessing.image.ImageDataGenerator(featurewise_center=False,  
                                             samplewise_center=False,
                                             featurewise_std_normalization=False,
                                             samplewise_std_normalization=False,
                                             zca_whitening=False,
                                             zca_epsilon=1e-06,
                                             rotation_range=0,
                                             width_shift_range=0.0,
                                             height_shift_range=0.0,
                                             brightness_range=None,
                                             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)
这个类用以生成一个batch的图像数据,支持实时数据提升。训练时该函数会无限生成数据,直到达到规定的 epoch 次数为止。

1.1 参数
featurewise_center: 布尔值。将输入数据的均值设置为 0,逐特征进行。这里所谓的逐特征进行,实际上就是逐通道进行,单通道图像减去的均值的是 [[[average]]],三通道图像减去的均值是 [[[R_average, G_average, B_average]]]
samplewise_center: 布尔值。将每个样本的均值设置为 0。
featurewise_std_normalization: 布尔值。将输入除以数据标准差,逐特征进行。
samplewise_std_normalization: 布尔值。将每个输入除以其标准差。
zca_epsilon: ZCA 白化的 epsilon 值,默认为 1e-6。
zca_whitening: 布尔值。是否应用 ZCA 白化。
rotation_range: 整数。随机旋转的度数范围。
width_shift_range: 浮点数、一维数组或整数。随机水平移动的幅度范围。
float: 如果 <1,则是除以总宽度的值,或者如果 >=1,则为像素值。
1-D 数组: 数组中的随机元素。
int: 来自间隔 (-width_shift_range, +width_shift_range) 之间的整数个像素。
width_shift_range=2 时,可能值是整数 [-1, 0, +1],与 width_shift_range=[-1, 0, +1] 相同;而 width_shift_range=1.0 时,可能值是 [-1.0, +1.0) 之间的浮点数。
height_shift_range: 浮点数、一维数组或整数。随机水平移动的幅度范围。
float: 如果 <1,则是除以总宽度的值,或者如果 >=1,则为像素值。
1-D array-like: 数组中的随机元素。
int: 来自间隔 (-height_shift_range, +height_shift_range) 之间的整数个像素。
height_shift_range=2 时,可能值是整数 [-1, 0, +1],与 height_shift_range=[-1, 0, +1] 相同;而 height_shift_range=1.0 时,可能值是 [-1.0, +1.0) 之间的浮点数。
shear_range: 浮点数。剪切强度(以弧度逆时针方向剪切角度)。
补充:什么是剪切变换?
剪切变换是仿射变换的一种原始变换,指的是类似四边形不稳定性的那种性质,方形变四边形,任意一边均可被拉长的过程。
zoom_range: 浮点数 或 [lower, upper]。随机缩放范围。如果是浮点数,[lower, upper] = [1-zoom_range, 1+zoom_range]。
channel_shift_range: 浮点数。随机通道转换的范围,或者可以理解为随机通道偏移的幅度。
fill_mode: {“constant”, “nearest”, “reflect” or “wrap”} 之一。常用于填充由于旋转平移造成的图像空白,默认为 ‘nearest’。输入边界以外的点根据给定的模式填充:
‘constant’: kkkkkkkk|abcd|kkkkkkkk (cval=k)
‘nearest’: aaaaaaaa|abcd|dddddddd
‘reflect’: abcddcba|abcd|dcbaabcd
‘wrap’: abcdabcd|abcd|abcdabcd
cval: 浮点数或整数。用于边界之外的点的值,当 fill_mode = “constant” 时。
horizontal_flip: 布尔值。随机水平翻转。
vertical_flip: 布尔值。随机垂直翻转。
rescale: 重缩放因子。默认为 None。如果是 None 或 0,不进行缩放,否则将数据乘以所提供的值(在应用任何其他转换之前)。常常用于将 [0, 255] 的输入图像缩放到 [0, 1]。
preprocessing_function: 应用于每个输入的函数。这个函数会在任何其他改变之前运行。这个函数需要一个参数:一张图像(秩为 3 的 Numpy 张量),并且应该输出一个同尺寸的 Numpy 张量。
也就是说这是在 Keras 进行实时数据增强之前的预处理。我们需要写这样的一个函数,它的输入是本来进行实时数据增强的图像,输出的是与原来大小相同的图像,相当于先执行一种 Keras 中没有的图像预处理方法。在下面会给出一个使用例子。
data_format: 图像数据格式,{“channels_first”, “channels_last”} 之一。“channels_last” 模式表示图像输入尺寸应该为 (samples, height, width, channels),“channels_first” 模式表示输入尺寸应该为 (samples, channels, height, width)。默认为 在 Keras 配置文件 ~/.keras/keras.json 中的 image_data_format 值。如果你从未设置它,那它就是 “channels_last”。
validation_split: 浮点数。Float. 保留用于验证的图像的比例(严格在0和1之间)。
dtype: 生成数组使用的数据类型。
1.2 关于仿射变换进度的补充
  在上面的的各种增强方式中,旋转,平移,剪切变换等各种仿射变换,均采用的是 1 阶的插值方法,具体可以参考如下的代码
cd /usr/local/lib/python2.7/dist-packages/keras_preprocessing
之后找到定义 apply_affine_transform 函数的位置,可以看到
   if transform_matrix is not None:
        h, w = x.shape[row_axis], x.shape[col_axis]
        transform_matrix = transform_matrix_offset_center(
            transform_matrix, h, w)
        x = np.rollaxis(x, channel_axis, 0)
        final_affine_matrix = transform_matrix[:2, :2]
        final_offset = transform_matrix[:2, 2]


        channel_images = [scipy.ndimage.interpolation.affine_transform(
            x_channel,
            final_affine_matrix,
            final_offset,
            order=1,
            mode=fill_mode,

        x = np.stack(channel_images, axis=0)
        x = np.rollaxis(x, 0, channel_axis + 1)
其中 scipy.ndimage.interpolation.affine_transform 的参数 order=1,其代表的含义是样条插值的阶,正常是使用 order=3。而且从 scipy.ndimage.interpolation.affine_transform 的代码可以看到,他实际上没有进行任何插值操作,如下
-def spline_filter(input, order=3, output=numpy.float64):
    """
    Multi-dimensional spline filter.


    For more details, see `spline_filter1d`.


    See Also
    --------
    spline_filter1d


    Notes
    -----
    The multi-dimensional filter is implemented as a sequence of
    one-dimensional spline filters. The intermediate arrays are stored
    in the same data type as the output. Therefore, for output types
    with a limited precision, the results may be imprecise because
    intermediate results may be stored with insufficient precision.


    """
    if order < 2 or order > 5:
        raise RuntimeError('spline order not supported')
    input = numpy.asarray(input)
    if numpy.iscomplexobj(input):
        raise TypeError('Complex type not supported')
    output = _ni_support._get_output(output, input)
    if order not in [0, 1] and input.ndim > 0:
        for axis in range(input.ndim):
            spline_filter1d(input, order, axis, output=output)
            input = output
    else:
        output[...] = input[...]
    return output

可以看到,输入是什么样,输出就是什么样。所以直接使用,会降低仿射变换后图像的精度。

2. ImageDataGenerator 类方法2.1 apply_transformapply_transform(x, transform_parameters)

根据给定的参数将变换应用于图像。


参数
x: 3D 张量,单张图像。
transform_parameters: 字符串 - 参数 对表示的字典,用于描述转换。目前,使用字典中的以下参数:
‘theta’: 浮点数。旋转角度(度)。
‘tx’: 浮点数。在 x 方向上移动。
‘ty’: 浮点数。在 y 方向上移动。
shear’: 浮点数。剪切角度(度)。
‘zx’: 浮点数。放大 x 方向。
‘zy’: 浮点数。放大 y 方向。
‘flip_horizontal’: 布尔 值。水平翻转。
‘flip_vertical’: 布尔值。垂直翻转。
‘channel_shift_intencity’: 浮点数。频道转换强度。
‘brightness’: 浮点数。亮度转换强度。
返回
  输入的转换后版本(相同尺寸)。


2.2 fit
fit(x, augment=False, rounds=1, seed=None)
将数据生成器用于某些示例数据。它基于一组样本数据,计算与数据转换相关的内部数据统计。当且仅当 featurewise_center 或 featurewise_std_normalization 或 zca_whitening 设置为 True 时才需要。

参数
x: 样本数据。秩应该为 4。对于灰度数据,通道轴的值应该为 1;对于 RGB 数据,值应该为 3。
augment: 布尔值(默认为 False)。是否使用随机样本扩张。
rounds: 整数(默认为 1)。如果数据数据增强(augment=True),表明在数据上进行多少次增强。
seed: 整数(默认 None)。随机种子。
关于“去均值”的补充
  首先需要科普一个问题,为什么使用图像训练神经网络的时候需要进行去均值,以及应该从那个维度去除均值。去均值把输入数据各个维度都中心化为0,避免数据过多偏差,影响训练效果,同时可以加快模型的收敛速度。一般是从通道的维度去除均值,即分别求出 B, G, R 三个通道的均值,比如说[[[0.21568, 0.22314, 0.25657]]],然后每个图像都减去它。

  有一点需要尤为注意,这里减去的均值是 [0, 1] 区间的。这主要是因为在执行诸如 flow_from_directory 的命令时,其首先进行归一化(recale = 1/255.0),然后在进行去均值化。进入定义 image.py 的文件夹
cd /usr/local/lib/python2.7/dist-packages/keras_preprocessing


进入 image.py 文件,找到定义 def standardize(self, x) 的函数,看到其具体实现如下
def standardize(self, x):
    """Applies the normalization configuration to a batch of inputs.


    # Arguments
        x: Batch of inputs to be normalized.


    # Returns
        The inputs, normalized.
    """
    if self.preprocessing_function:
        x = self.preprocessing_function(x)
    if self.rescale:
        x *= self.rescale
    if self.samplewise_center:
        x -= np.mean(x, keepdims=True)
    if self.samplewise_std_normalization:
        x /= (np.std(x, keepdims=True) + 1e-6)


    if self.featurewise_center:
        if self.mean is not None:
            x -= self.mean
        else:
            warnings.warn('This ImageDataGenerator specifies '
                          '`featurewise_center`, but it hasn\'t '
                          'been fit on any training data. Fit it '
                          'first by calling `.fit(numpy_data)`.')
    if self.featurewise_std_normalization:
        if self.std is not None:
            x /= (self.std + 1e-6)
        else:
            warnings.warn('This ImageDataGenerator specifies '
                          '`featurewise_std_normalization`, '
                          'but it hasn\'t '
                          'been fit on any training data. Fit it '
                          'first by calling `.fit(numpy_data)`.')
    if self.zca_whitening:
        if self.principal_components is not None:
            flatx = np.reshape(x, (-1, np.prod(x.shape[-3:])))
            whitex = np.dot(flatx, self.principal_components)
            x = np.reshape(whitex, x.shape)
        else:
            warnings.warn('This ImageDataGenerator specifies '
                          '`zca_whitening`, but it hasn\'t '
                          'been fit on any training data. Fit it '
                          'first by calling `.fit(numpy_data)`.')
    return x
可以看到它是先进行 rescale,然后再进行减均值,如果你做了 reascale = 1/255.0 ,那么减的均值一定是位与 [0,1] 区间的。


  通过手工指定均值,标准差的方法,可以使得 train, validation, test 减去相同的均值,除以相同的标准差。但是样本数据 x 需要将图片读入到内存中,在计算均值等数据,当数据量过大的时候,没有办法一次性将数据读入,这个时候可以考虑使用这样的方法。首先通过手工计算的方式求出当前数据的均值,然后修改 Keras 底层源码,将减去由 x 计算出的均值改为减去人为指定的均值。


  具体的修改方式是,进入定义 image.py 的文件夹
cd /usr/local/lib/python2.7/dist-packages/keras_preprocessing
进入 image.py 文件,找到定义类 ImageDataGenerator(object) 中进行初始化 def __init__ 的位置,进行如下的修改,其中在注释的下面
        # self.mean = None
        self.mean = [[[55, 56, 57]]]
        self.std = None
        self.principal_components = None
其中被注释掉的是原始的初始化的值,这里改为给定一个数作为初始化的值。其中原理的在于,原始只有经过 fit(x) 之后才可以给 self.mean 赋值为计算出的均值;而我们这里不进行 fir(x) 的计算,直接改变 self.mean 的初始值,这样当调用 def standardize(self, x) 的时候,就可以使用我们手工指定的初值了。


  但是在计算均值的过程中有一点需要注意,使用 Opencv 默认读入图片的颜色顺序为BGR,而使用PIL默认读入图片的颜色顺序为 RGB。Keras 在使用图片生成器读入数据的时候调用的是 PIL,所以如果是通过 Opencv 计算的均值需要将顺序从 BGR 调整为 RGB 才可以使用。


2.3 flow
flow(x, y=None, batch_size=32, shuffle=True, sample_weight=None, seed=None,
     save_to_dir=None, save_prefix='', save_format='png', subset=None)
接收numpy数组和标签为参数,生成经过数据提升或标准化后的batch数据,并在一个无限循环中不断的返回batch数据

参数
x: 输入数据。秩为 4 的 Numpy 矩阵或元组。如果是元组,第一个元素应该包含图像,第二个元素是另一个 Numpy 数组或一列 Numpy 数组,它们不经过任何修改就传递给输出。可用于将模型杂项数据与图像一起输入。对于灰度数据,图像数组的通道轴的值应该为 1,而对于 RGB 数据,其值应该为 3。
y: 标签。
batch_size: 整数 (默认为 32)。
shuffle: 布尔值 (默认为 True)。
sample_weight: 样本权重。
seed: 整数(默认为 None)。
save_to_dir: None 或 字符串(默认为 None)。这使您可以选择指定要保存的正在生成的增强图片的目录(用于可视化您正在执行的操作)。
save_prefix: 字符串(默认 ‘’)。保存图片的文件名前缀(仅当 save_to_dir 设置时可用)。
save_format: “png”, “jpeg” 之一(仅当 save_to_dir 设置时可用)。默认:“png”。
subset: 数据子集 (“training” 或 “validation”),如果 在 ImageDataGenerator 中设置了 validation_split。
返回
  一个生成元组 (x, y) 的 Iterator,其中 x 是图像数据的 Numpy 数组(在单张图像输入时),或 Numpy 数组列表(在额外多个输入时),y 是对应的标签的 Numpy 数组。如果 ‘sample_weight’ 不是 None,生成的元组形式为 (x, y, sample_weight)。如果 y 是 None, 只有 Numpy 数组 x 被返回。

2.4 flow_from_directory
flow_from_directory(directory, target_size=(256, 256), color_mode='rgb',
                    classes=None, class_mode='categorical', batch_size=32,
                    shuffle=True, seed=None, save_to_dir=None, save_prefix='',
                    save_format='png', follow_links=False, subset=None,
                    interpolation='nearest')


参数
directory: 目标目录的路径。每个类应该包含一个子目录。任何在子目录树下的 PNG, JPG, BMP, PPM 或 TIF 图像,都将被包含在生成器中。
target_size: 整数元组 (height, width),默认:(256, 256)。所有的图像将被调整到的尺寸。
color_mode: “grayscale”, “rbg” 之一。默认:“rgb”。图像是否被转换成 1 或 3 个颜色通道。
classes: 可选的类的子目录列表(例如 [‘dogs’, ‘cats’])。默认:None。如果未提供,类的列表将自动从 directory 下的 子目录名称/结构 中推断出来,其中每个子目录都将被作为不同的类(类名将按字典序映射到标签的索引)。包含从类名到类索引的映射的字典可以通过 class_indices 属性获得。
class_mode: “categorical”, “binary”, “sparse”, “input” 或 None 之一。默认:“categorical”。决定返回的标签数组的类型:
“categorical” 将是 2D one-hot 编码标签,
“binary” 将是 1D 二进制标签,“sparse” 将是 1D 整数标签,
“input” 将是与输入图像相同的图像(主要用于自动编码器)。
如果为 None,不返回标签(生成器将只产生批量的图像数据,对于 model.predict_generator(), model.evaluate_generator() 等很有用)。请注意,如果 class_mode 为 None,那么数据仍然需要驻留在 directory 的子目录中才能正常工作。
batch_size: 一批数据的大小(默认 32)。
shuffle: 是否混洗数据(默认 True)。
seed: 可选随机种子,用于混洗和转换。
save_to_dir: None 或 字符串(默认 None)。这使你可以最佳地指定正在生成的增强图片要保存的目录(用于可视化你在做什么)。
save_prefix: 字符串。 保存图片的文件名前缀(仅当 save_to_dir 设置时可用)。
save_format: “png”, “jpeg” 之一(仅当 save_to_dir 设置时可用)。默认:“png”。
follow_links: 是否跟踪类子目录中的符号链接(默认为 False)。
subset: 数据子集 (“training” 或 “validation”),如果 在 ImageDataGenerator 中设置了 validation_split。
interpolation: 在目标大小与加载图像的大小不同时,用于重新采样图像的插值方法。 支持的方法有 “nearest”, “bilinear”, and “bicubic”。 如果安装了 1.1.3 以上版本的 PIL 的话,同样支持 “lanczos”。 如果安装了 3.4.0 以上版本的 PIL 的话,同样支持 “box” 和 “hamming”。 默认情况下,使用 “nearest”。这个参数应该是在新版 keras (2.2.4) 中新添加的,在原来的 2.1.5 中是没有的。
  从这里可以看出 flow 和 flow_from_directory 的区别在于,flow 的输入是已经读入的图像,而 flow_from_directory 的输入是存放图像的文件夹。


---------------------
作者:独孤呆博
来源:CSDN
原文:
版权声明:本文为博主原创文章,转载请附上博文链接!













点赞
收藏
回复
分享
举报
浏览963 发布于2019-03-18 08:23未知归属地
全部评论
最多点赞
最新发布
最早发布
暂无评论
暂无评论
写回答
新增插入模板功能
一键使用模板,快速填写内容,轻松发帖~
知道了
  • 为了保障您的信息安全,请勿上传您的敏感个人信息(如您的密码等信息)和您的敏感资产信息(如关键源代码、签名私钥、调试安装包、业务日志等信息),且您需自行承担由此产生的信息泄露等安全风险。
  • 如您发布的内容为转载内容,请注明内容来源。

我要发帖子

了解社区公约,与您携手共创和谐专业的开发者社区。