使用TensorFlow-Keras API进行数据增强

时间:2020-09-18 23:15:14

标签: python tensorflow keras

以下代码允许将训练集的图像在每个时期结束时旋转90º。

from skimage.io import imread
from skimage.transform import resize, rotate
import numpy as np

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
from keras.utils import Sequence 
from keras.models import Sequential
from keras.layers import Conv2D, Activation, Flatten, Dense

# Model architecture  (dummy)
model = Sequential()
model.add(Conv2D(32, (3, 3), input_shape=(15, 15, 4)))
model.add(Activation('relu'))
model.add(Flatten())
model.add(Dense(1))
model.add(Activation('sigmoid'))
model.compile(loss='binary_crossentropy',
              optimizer='rmsprop',
              metrics=['accuracy'])

# Data iterator 
class CIFAR10Sequence(Sequence):
    def __init__(self, filenames, labels, batch_size):
        self.filenames, self.labels = filenames, labels
        self.batch_size = batch_size
        self.angles = [0,90,180,270]
        self.current_angle_idx = 0

    # Method to loop throught the available angles
    def change_angle(self):
      self.current_angle_idx += 1
      if self.current_angle_idx >= len(self.angles):
        self.current_angle_idx = 0
  
    def __len__(self):
        return int(np.ceil(len(self.filenames) / float(self.batch_size)))

    # read, resize and rotate the image and return a batch of images
    def __getitem__(self, idx):
        angle = self.angles[self.current_angle_idx]
        print (f"Rotating Angle: {angle}")

        batch_x = self.filenames[idx * self.batch_size:(idx + 1) * self.batch_size]
        batch_y = self.labels[idx * self.batch_size:(idx + 1) * self.batch_size]
        return np.array([
            rotate(resize(imread(filename), (15, 15)), angle)
               for filename in batch_x]), np.array(batch_y)

# Custom call back to hook into on epoch end
class CustomCallback(keras.callbacks.Callback):
    def __init__(self, sequence):
      self.sequence = sequence

    # after end of each epoch change the rotation for next epoch
    def on_epoch_end(self, epoch, logs=None):
      self.sequence.change_angle()               


# Create data reader
sequence = CIFAR10Sequence(["f1.PNG"]*10, [0, 1]*5, 8)
# fit the model and hook in the custom call back
model.fit(sequence, epochs=10, callbacks=[CustomCallback(sequence)])

如何修改代码,以使图像在每个时期旋转?

所需的输出:

Epoch 1/10
Rotating Angle: 0
Rotating Angle: 90
Rotating Angle: 180
Rotating Angle: 270

Epoch 2/10
Rotating Angle: 0
Rotating Angle: 90
Rotating Angle: 180
Rotating Angle: 270

(...)

Epoch 10/10
Rotating Angle: 0
Rotating Angle: 90
Rotating Angle: 180
Rotating Angle: 270

换句话说,我该如何编写一个在某个时代的“结尾”运行的回调,该回调会更改角度值并继续在同一时代进行训练(而不更改为下一个)?

预先感谢

注意:代码来源来自“ mujjiga”。

2 个答案:

答案 0 :(得分:1)

由于具有自定义序列生成器,因此可以创建一个在纪​​元的开始或结尾运行的函数。您可以在其中放置代码来修改图像。文档在[这里。] [1]

Epoch-level methods (training only)
on_epoch_begin(self, epoch, logs=None)
Called at the beginning of an epoch during training.

on_epoch_end(self, epoch, logs=None)
Called at the end of an epoch during training.


  [1]: https://keras.io/guides/writing_your_own_callbacks/

答案 1 :(得分:0)

为此无需创建CustomCallback;最后,您想在训练期间进行扩充。

解决方案是以一定概率应用旋转操作

# read, resize and rotate the image and return a batch of images
def __getitem__(self, idx):
    angle = self.angles[self.current_angle_idx]
    print(f"Rotating Angle: {angle}")
    batch_x = self.filenames[idx * self.batch_size:(idx + 1) * self.batch_size]
    batch_y = self.labels[idx * self.batch_size:(idx + 1) * self.batch_size]
    #These new lines (say we augment with probability > 0.5)
    #Number between 0 and 1
    images = []
    for filename in batch_x:
        probability = random.random()
        apply_rotate = probability > 0.5
        if apply_rotate:
            images.append(rotate(resize(imread(filename), (15, 15)), angle))
        else:
            images.append(resize(imread(filename), (15, 15)))
    return np.array(images), np.array(batch_y)