Keras訓練數據加載實現小結

對於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)

從官方文檔中可以看出,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)


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)
1
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。

我的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()方法,第一個爲數據集路徑。生成數據集及標籤
rain_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)


我的數據集目錄結構如下:


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)


對於標籤爲圖像的數據,當用這種方式加載的時候,需將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)


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)


3.train_on_batch()
類似於TensorFlow的數據填充了,一次喂一個batch_size的數據。

train_on_batch(x, y, sample_weight=None, class_weight=None)
1
採用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)

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)


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章