对于keras加载训练数据,官方上没有详说。然而网上查各种资料,写法太多,通过自己跑代码测试总结以下几条,方便自己以后使用。
总的来说keras模型加载数据主要有三种方式:.fit(), .fit_generator()和.train_on_batch()。
1.fit():
上函数,各个参数的意义就不解释了
fit(x=None, y=None, batch_size=None, epochs=1, verbose=1, callbacks=None, validation_split=0.0, validation_data=None, shuffle=True, class_weight=None, sample_weight=None, initial_epoch=0, steps_per_epoch=None, validation_steps=None)
Copy
从官方文档中可以看出,fit()是需要先把整个数据集加载进来,然后喂入网络,因为minist数据集比较小,这么做是可行的,但对于实际开发而言,这么做是不可行的,需要大量的内存资源,同时不能对数据进行在线提升。
一次性加载整个数据集的示例代码:
任务为猫和狗的二分类,train_data下包含cat和dog两个文件夹,代码将两个文件夹下图片和标签存入numpy数组,返回为训练数据和训练标签。
def load_data():
tran_imags = []
labels = []
seq_names = ['cat','dog']
for seq_name in seq_names:
frames = sorted(os.listdir(os.path.join(root_path,'data','train_data', seq_name)))
for frame in frames:
imgs = [os.path.join(root_path, 'data', 'train_data', seq_name, frame)]
imgs = np.array(Image.open(imgs[0]))
tran_imags.append(imgs)
if seq_name=='cat':
labels.append(0)
else:
labels.append(1)
return np.array(tran_imags), np.array(labels)
##
train_data,train_labs = load_data()
model.fit(train_data,keras.utils.to_categorical(train_labs),batch_size=32,epochs=50,verbose=1)
Copy
2.fit_generator()
fit_generator()需要将数据集和标签写成生成器格式
fit_generator(generator, steps_per_epoch=None, epochs=1, verbose=1, callbacks=None, validation_data=None, validation_steps=None, class_weight=None, max_queue_size=10, workers=1, use_multiprocessing=False, shuffle=True, initial_epoch=0)
Copy
1).从txt文件读取图片路径的生成器,不进行数据增强
以下代码从给定路径的txt文本中循环读取图片路径,每次读取一个batch_size的图片,并存入numpy数组返回。其中,当读到文本末尾时,将指针指向文件第一行。
def generate_array_from_txt(path, batch_size,num_class):
with open(path) as f:
while True:
imgs = []
labs = np.zeros(shape=(batch_size,num_class))
i = 0
while len(imgs) < batch_size:
line = f.readline()
if not line:
f.seek(0)
line = f.readline()
img_path = line.split(' ')[0]
lab = line.split(' ')[1]
img = np.array(Image.open(os.path.join('./',img_path)))
lab = keras.utils.to_categorical(int(lab)-1,num_classes=num_class)
imgs.append(img)
labs[i] = lab
i = i +1
yield (np.array(imgs),labs)
##使用如下
gen = generate_arrays_from_txt(txt_path,batch_size,num_class)
model.fit_generator(gen,steps_per_epoch=N, epochs=EPOCN)
## 因为生成器是无限生成数据,所以它不知道一轮要训练多少图片,所以steps_per_epoch为数据集的总数除以batch_size。
Copy
我的txt文本格式如下:前面是图片路径,后面是类别标签,因为从1开始的,所以to_categorical 里面减了1.
2).使用.flow_from_directory(directory)
使用ImageDataGenerator类,ImageDataGenerator类有.flow()与.flow_from_directory(directory)两个加载数据的方法,个人认为第一个偏向于先将数据全部加载(看过的示例代码都是这样的),第二个从图片目录利用生成器返回数据。
2.1 用于分类网络,返回图像以及标签
## 声明一个ImageDataGenerator类对象,并给出你需要进行的数据增强选项
train_datagen = ImageDataGenerator(
rescale=1./255,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True)
##调用.flow_from_director()方法,第一个为数据集路径。生成数据集及标签
train_generator = train_datagen.flow_from_directory(
'./data/train_data',
target_size=(224, 224),
batch_size=32,
class_mode='categorical')
##
model.fit_generator(train_generator,steps_per_epoch=N, epochs=EPOCH)
Copy
我的数据集目录结构如下:
2.2 用于pix2pix
当用于图像分割、超分辨率重建等需要像素对应像素的任务时,标签也为图片(单通道或多通道)。 示例:加载用于图像分割的图像与mask,mask为单通道灰度图像,目标为白色,其余背景为黑色。
# 分别定义两个ImageDataGenerator对象
image_datagen = ImageDataGenerator(featurewise_center=True,
featurewise_std_normalization=True,
rescale= 1./255)
mask_datagen = ImageDataGenerator(rescale= 1./255)
seed = 1
#训练图片路径
image_generator = image_datagen.flow_from_directory(
'data/data_seg/davis_train',
class_mode=None,
seed=seed)
# 指定mask
mask_generator = mask_datagen.flow_from_directory(
'data/data_seg/davis_label',
class_mode=None,
color_mode = 'grayscale'
seed=seed)
# 将以上两个生成器合为一个
train_generator = zip(image_generator, mask_generator)
#
model.fit_generator(
train_generator,
steps_per_epoch=STEPS_NUM,
epochs=EPOCHS)
Copy
对于标签为图像的数据,当用这种方式加载的时候,需将class_mode指定为None,表示不返回标签。对于训练图片和标签要保证顺序不变,一一对应,名字可不同
需要将两个生成器的seed指定为相同的数字,此时两个生成器返回的图片对就一一对应
3) 使用flow(x, y=None)
使用.flow()时,需要将训练数据加载到内存中,每次填充一个Batch_size的数据进网络
train_data, train_labs = load_data()
dataGenerator = ImageDataGenerator(
preprocessing_function=normalize)
gen = dataGenerator.flow(train_data, train_labs, batch_size=8)
model.fit_generator(gen)
Copy
4) 使用.flow_from_dataframe()
dataframe中保存的是图片名字和label
import pandas as pd
df=pd.read_csv(r".\train.csv")
datagen=ImageDataGenerator(rescale=1./255)
train_generator=datagen.flow_from_dataframe(dataframe=df, directory=".\train_imgs", x_col="id", y_col="label", class_mode="categorical", target_size=(32,32), batch_size=32)
Copy
3.train_on_batch()
类似于TensorFlow的数据填充了,一次喂一个batch_size的数据。
train_on_batch(x, y, sample_weight=None, class_weight=None)
Copy
采用2.2中的生成器例子
train_generator = zip(image_generator, mask_generator)
steps = len(train_generator)/ batch_size * EPOCH
step = 0
for train_batch, label_batch in train_generator:
if step == steps:
break
step += 1
train_on_batch(train_batch, label_batch, sample_weight=None, class_weight=None)
Copy
4.对生成器返回数据进行处理
使用生成器时,如果需要对图片进行一定的处理,可以在ImageDataGenerator中定义预处理函数,但是要求返回的shape不能改变。 如果要对图片的shape进行改变,可将生成器返回结果再次包装为生成器,如下例:
# 实例化ImageDataGenerator,同时指定预处理函数
datagen = ImageDataGenerator(
preprocessing_function=normalize)
# 定义生成器,每次从datagen中取出一个Batch,然后对数据进行自己的操作
def image_a_b_gen(data_path):
for batch in datagen.flow_from_directory(data_path,
target_size=(768, 1024),
color_mode='rgb',
class_mode=None,
batch_size=batch_size,
shuffle=True):
lab_batch = rgb2lab(batch)
X_batch = lab_batch[:, :, :, 0]
Y_batch = lab_batch[:, :, :, 1:] / 128
yield (np.expand_dims(X_batch, axis=3), Y_batch)