图片生成--扰动旋转噪声

1. 背景

        针对标准的CIFAR10 训练集,通过旋转、比例调整、水平/垂直翻转、缩放、信道交换等多种类型的转换来增加图形(生成更多的图片)。这也是针对训练图片数据不足的情况下提升模型性能的一个方法。

2. 数据预处理与数据提升

  为了尽量利用我们有限的训练数据,我们将通过一系列变换堆数据进行提升,这样我们的模型将看不到任何两张完全相同的图片,有利于抑制过拟合,使得模型的泛化能力更好。

2.1  图片预处理生成器 ImageDataGenerator

    Keras中提供了图片预处理生成器:

(1)在训练过程中,设置要施行的随机变换;

(2)通过 .flow 或者 .flow_from_directory(directory) 方法实例化一个针对图像 batch 的生成器;最终把数据按照每个batch进行划分,送到模型进行训练;

datagen = ImageDataGenerator()
datagen.fit(x_train)

 (3)ImageDataGenerator()接收numpy数组和标签为参数,生成经过数据提升或标准化后的batch数据,并在一个无限循环中不断的返回batch数据

        图片生成器ImageDataGenerator() 可以用以生成一个 batch的图像数据,支持实时数据提升,训练时该函数会无限生成数据,直到达到规定的 epoch次数为止。

        而flow_from_directory(directory):以文件夹路径为参数,生成经过数据提升/归一化后的数据,在一个无限循环中无限产生batch数据。

2.2 使用ImageDataGenerator 生成增强图片Demo

针对一张输入图片dog.png,进行一系列随机变换生成20张增强图片,并存储在目标文件夹gen_img_list内:

from keras.preprocessing.image import ImageDataGenerator, image_utils
import os

datagen = ImageDataGenerator(
    rotation_range=40,  # 随机旋转角度(0~180)
    width_shift_range=0.2,  # 水平方向的随机移动程度
    height_shift_range=0.2,  # 竖直方向的随机移动程度
    rescale=1. / 255,  # 将在执行其他处理前乘到整个图像上
    shear_range=0.2,  # 用来进行剪切变换的程度,参考剪切变换
    zoom_range=0.2,  # 随机缩放
    horizontal_flip=True,  # 随机水平翻转
    fill_mode='nearest'  # 图片翻转或交换后用来填充新像素时采用的策略
)

img_path = 'dog.png'
img = image_utils.load_img(img_path)  
x = image_utils.img_to_array(img)  # this is a Numpy array with shape (150, 150, 3)
x = x.reshape((1,) + x.shape)  # this is a Numpy array with shape (1, 150, 150, 3)
if not os.path.exists('gen_img_list'):
    os.mkdir('gen_img_list')
i = 0
for batch in datagen.flow(x, batch_size=1, save_to_dir='gen_img_list', save_prefix='dog', save_format='jpg'):
    i += 1
    if i > 20:
        break

3. 数据增强方式训练模型

3.1 构建模型

# _*_coding:utf-8_*_
from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D
from keras.layers import Activation, Dropout, Flatten, Dense
from keras.preprocessing.image import ImageDataGenerator, image_utils
from keras.models import load_model
import cv2
import numpy as np

def built_model():
    model = Sequential()
    model.add(Conv2D(32, (3, 3), input_shape=(150, 150, 3)))
    model.add(Activation('relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))

    # 此处可加多层
    model.add(Conv2D(32, (3, 3)))
    model.add(Activation('relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))

    model.add(Flatten())
    model.add(Dense(64))
    model.add(Activation('relu'))
    model.add(Dropout(0.5))

    # -------多分类----------
    model.add(Dense(5))
    model.add(Activation('softmax'))
    model.compile(loss='categorical_crossentropy', optimizer='rmsprop', metrics=['accuracy'])

    # -------二分类----------
    # model.add(Dense(1))
    # model.add(Activation('sigmoid'))
    # model.compile(loss='binary_crossentropy', optimizer='rmsprop', metrics=['accuracy'])
    model.summary()
    return model

3.2 生成数据

def generate_data():
    train_datagen = ImageDataGenerator(
        rescale=1. / 255,
        shear_range=0.2,
        zoom_range=0.2,
        horizontal_flip=True
    )
    test_datagen = ImageDataGenerator(rescale=1. / 255)

    # 使用 .flow_from_directory() 来从我们的jpgs图片中直接产生数据和标签
    train_generator = train_datagen.flow_from_directory(
        'data/mytrain',
        target_size=(150, 150),  # all images will be resized to 150*150
        batch_size=32,
        class_mode='categorical'  # 多分类
        # class_mode = 'binary'    # 二分类
    )
    validation_generator = test_datagen.flow_from_directory(
        'data/mytest',
        target_size=(150, 150),
        batch_size=32,
        class_mode='categorical'  # 多分类
    )
    return train_generator, validation_generator

3.3 训练模型

def train_model(train_generator, validation_generator):
    model = built_model()
    model.fit_generator(
        train_generator,
        samples_per_epoch=2000,  # 相当于每个epoch数据量峰值,每个epoch以经过模型的样本数达到samples_per_epoch时,记一个epoch结束
        nb_epoch=50,
        validation_data=validation_generator,
        nb_val_samples=800)
    model.save_weights('animal.h5')

3.4 模型预测

3.4.1 批量预测

def model_predict_batch(model, img_dir, target_size):
    img_gen = ImageDataGenerator(rescale=1. / 255)
    newsample_generator = img_gen.flow_from_directory(
        img_dir,
        target_size=target_size,
        batch_size=16,
        class_mode=None,
        shuffle=False)
    res = model.predict_generator(newsample_generator)
    return res

3.4.2 单个预测

def model_predict_one(model, img_path, target_size):
    img = cv2.imread(img_path)
    if img.shape != target_size:
        img = cv2.resize(img, target_size)
    # print(img.shape)
    x = image_utils.img_to_array(img)
    x *= 1. / 255  # 相当于ImageDataGenerator(rescale=1. / 255)
    x = np.expand_dims(x, axis=0)  # 调整图片维度
    preds = model.predict(x)
    return preds[0]

4. 测试

if __name__ == '__main__':
    train_generator, validation_generator = generate_data()
    train_model(train_generator, validation_generator)

    model_path = 'animal.h5'
    model = load_model(model_path)

    target_size = (150, 150)
    img_dir = 'img_path'
    res = model_predict_batch(model, img_dir, target_size)
    print(res)

    img_path = 'data/test/300.jpg'
    res = model.predict(model, img_path, target_size)
    print(res)

おすすめ

転載: blog.csdn.net/MusicDancing/article/details/130271726