every blog every motto: You can do more than you think.
0. 前言
记录使用keras进行数据增强中遇到的有关问题
1. 正文
1.1 基本介绍
我们可以使用keras.preprocessing.image.ImageDataGenerator对数据进行“线上”或“线下”增强
1.1.1 生成对象
如下代码所示:
我们可以生成一个可迭代对象,并对其指定数据增强的具体方式(如:旋转、翻转等)
from keras.preprocessing.image import ImageDataGenerator
datagen = ImageDataGenerator(
rotation_range=40,
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')
参数:
- rotation_range是一个0~180的度数,用来指定随机选择图片的角度。
- width_shift和height_shift用来指定水平和竖直方向随机移动的程度,这是两个0~1之间的比例。
- rescale值将在执行其他处理前乘到整个图像上,我们的图像在RGB通道都是0255的整数,这样的操作可能使图像的值过高或过低,所以我们将这个值定为01之间的数。
- shear_range是用来进行剪切变换的程度,参考剪切变换。 zoom_range用来进行随机的放大。
- horizontal_flip随机的对图片进行水平翻转,这个参数适用于水平翻转不影响图片语义的时候。
- fill_mode用来指定当需要进行像素填充,如旋转,水平和竖直位移时,如何填充新出现的像素。
下面是生成器的两种方法,可以用next访问,也可以for循环遍历,下面以next为例。
1.1.2 flow
对读取图片后的数组进行变换,即参数为数组
因为是生成器,我们可以用next获取生成器的下一个值。
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
import tensorflow as tf
from keras.preprocessing.image import ImageDataGenerator
import cv2 as cv
import numpy as np
# 读取图片
img = cv.imread('./input/u=1819216937,2118754409&fm=26&gp=0.jpg')
img = np.expand_dims(img, axis=0)
# 实例化对象
agu = ImageDataGenerator(rotation_range=40) # 随机旋转0-40度之间
# print(type(agu))
# 变换并保存
next(agu.flow(img, save_to_dir='./output', save_format='jpg'))
说明: flow中接受的是4维数组,即含有btach维度,如:(batch,Height , Width , channel),上面代码中添加了一维。下同。
1.1.3 flow_from_directory
“对图片所在的文件夹进行变换”,即参数为文件夹
注意: 参数为文件夹,其中要含子文件夹!!!
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
import tensorflow as tf
from keras.preprocessing.image import ImageDataGenerator
import cv2 as cv
import numpy as np
# 输入文件夹
path = r'./input'
# 实例化对象
agu = ImageDataGenerator(rotation_range=40) # 随机旋转0-40度之间
# print(type(agu))
# 变换并保存
next(agu.flow_from_directory(path,batch_size=1, save_to_dir='./output', save_format='jpg'))
1.2 问题
基本代码同1.1.2,只是实例化对象不同,故,只贴出实例化对象部分
1.2.1 问题1
报错如下:
UserWarning: This ImageDataGenerator specifies `zca_whitening`, which overrides setting of `featurewise_center`.
warnings.warn('This ImageDataGenerator specifies '
部分代码:
# 实例化对象
agu = ImageDataGenerator(rotation_range=40,zca_whitening=True)
只是在其中增加了zca_whitening参数,出现如上警告。
解释: zca_whitening=True时,会将feature_center设为True,尽管我们没有设置,所有会出现警告。
源码:
解决方法,增加feature_center=True即可。
# 实例化对象
agu = ImageDataGenerator(rotation_range=40,zca_whitening=True,featurewise_center=True)
1.2.2 问题2
对图片白化遇到的相关问题:
UserWarning: This ImageDataGenerator specifies `featurewise_center`, but it hasn't been fit on any training data. Fit it first by calling `.fit(numpy_data)`.
warnings.warn('This ImageDataGenerator specifies '
实例化对象代码
# 实例化对象
agu = ImageDataGenerator(rotation_range=40,zca_whitening=True,featurewise_center=True)
原因: 参数中我们使用了feature_center=True,但是没有使用fit方法
官方解释:
解决办法: 使用flow 或flow_from_directory 方法前调用fit方法
代码:
另: 当使用fit方法时,会计算统计信息(均值方差),这个过程是非常慢的,若图片较大时,会出现下面一个错误
1.2.3 问题3
报错如下:
MemoryError: Unable to allocate 857. GiB for an array with shape (479700, 479700) and data type float32
原因: 要计算相关统计信息,会计算SVD,其中的数值较大,所以出现了如上错误。
一种尝试:
将fit方法替换为如下,手动计算:
完整代码:
但是结果不一定对:
这仅仅是一种尝试,结果不一定对
1.2.4 问题4
仅增加旋转参数,保存图片的颜色发生变化
代码:
原因: 我们使用cv读取图片,读取的是BRG,写入时与原先的RGB正好相反,所以出现错误。
方法一:调整BGR顺序
结果:
方法二: 转换
方法三:PIL读取
1.2.5 问题5
说明: 这个准确来说,不能算问题,而是好奇,如下:
设置多个参数时,每次仅使用一个,还是同时使用。
测试,同时使用旋转和垂直翻转这两个参数。
代码:
测试两次,结果如下:
结论: 我们发现,两个参数是随机起作用的,有时候只旋转,不翻转;有时候两个都起作用,等。
又进行一次测试,结果如下:
我们发现,其分别朝左和右进行了旋转,这也就推翻了我们之前所说,或是注释里面所注的:“旋转朝0-40度(设定的值)进行旋转”,而应该是,-40-40度之间,源码中我们发现确实是这样。
上面代码中的注释是错的,不是0-40度之间旋转,我就不回去修改了,大家注意!!!
1.3 两种使用方式
1.3.1 普通使用
这是官方的一个例子,通过循环,不断的获取数据
(x_train, y_train), (x_test, y_test) = cifar10.load_data()
y_train = np_utils.to_categorical(y_train, num_classes)
y_test = np_utils.to_categorical(y_test, num_classes)
datagen = ImageDataGenerator(
featurewise_center=True,
featurewise_std_normalization=True,
rotation_range=20,
width_shift_range=0.2,
height_shift_range=0.2,
horizontal_flip=True)
# compute quantities required for featurewise normalization
# (std, mean, and principal components if ZCA whitening is applied)
datagen.fit(x_train)
# fits the model on batches with real-time data augmentation:
model.fit_generator(datagen.flow(x_train, y_train, batch_size=32),
steps_per_epoch=len(x_train), epochs=epochs)
# here's a more "manual" example
for e in range(epochs):
print 'Epoch', e
batches = 0
for x_batch, y_batch in datagen.flow(x_train, y_train, batch_size=32):
loss = model.train(x_batch, y_batch)
batches += 1
if batches >= len(x_train) / 32:
# we need to break the loop by hand because
# the generator loops indefinitely
break
1.3.2 和keras.utils.Sequence结合使用
keras.utils.Sequence的使用参考之前的文章,文后附。
说明:
使用起来也很简单,
- 初始化时,生成数据增强对象
- __getitem __ 返回next,不断调用生成即可。
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
import tensorflow as tf
from keras.preprocessing.image import ImageDataGenerator, load_img
import cv2 as cv
import numpy as np
class Date(tf.keras.utils.Sequence):
def __init__(self):
self.input = r'./data'
self.file = os.listdir(self.input)
print(self.file)
self.batch = 2
self.agu = ImageDataGenerator(
# 增强的项目。翻转,缩放,平移,旋转,颜色等。
rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2, # 比例平移
zoom_range=0.2,
fill_mode='nearest',
horizontal_flip=True,
vertical_flip=True,
zca_whitening=True,
featurewise_center=True,
rescale=1. / 255
)
def __len__(self):
"""
此方法要实现,否则会报错
正常程序中返回1个epoch迭代的次数
:return:
"""
return len(self.file)
def generate_batch(self):
x_batch = np.zeros((3, 256, 256, 3))
for i, file in enumerate(self.file):
path = os.path.join(self.input, file)
# print(path)
img = cv.imread(path)
x_batch[i,] = img
x_batch = np.array(x_batch)
return x_batch
def __getitem__(self, index):
"""生成一个batch的数据"""
x_batch = self.generate_batch()
# self.agu.fit(x_batch)
return next(self.agu.flow(x_batch,batch_size=1,save_to_dir='./output',save_format='jpg'))
# return next((self.agu.flow_from_directory(self.input,save_to_dir='./output',save_format='jpg')))
# return x_batch
# 实例化数据
date = Date()
for batch_number, x in enumerate(date):
print('正在进行第{} batch'.format(batch_number))
参考文献
[1] https://blog.csdn.net/weixin_39190382/article/details/109195031
[2] https://blog.csdn.net/xijuezhu8128/article/details/79895856
[3] https://blog.csdn.net/wang263334857/article/details/88749379
[4] https://blog.csdn.net/qq_36537768/article/details/103066394
[5] https://www.cnblogs.com/hutao722/p/10075150.html
[6] https://blog.csdn.net/jacke121/article/details/79245732
[7] https://blog.csdn.net/qq_27825451/article/details/90172030
[8] https://blog.csdn.net/dugudaibo/article/details/87719078
[9] https://tensorflow.google.cn/versions/r2.0/api_docs/python/tf/keras/preprocessing/image/ImageDataGenerator
[10] https://keras-cn.readthedocs.io/en/latest/preprocessing/image/#imagedatagenerator