data augementation : mixup

mixup1は、2つの訓練サンプルのペアを混合して新たな訓練サンプルを作成するdata augmentation手法の1つ
具体的には、データとラベルのペア(X_1,y_1)(X_1,y_1), (X_2,y_2)(X_2,y_2)から、下記の式により新たな訓練サンプル(X,y)を作成します。ここでラベルy_1,y_2はone-hot表現のベクトルになっているものとします。X_1,X_2は任意のベクトルやテンソルです。
X=λX_1+(1−λ)X_2
y=λy_1+(1−λ)y_2
ここでλ∈[0,1]は、ベータ分布Be(α,α)からのサンプリングにより取得し、αはハイパーパラメータとなります。特徴的なのは、データX_1,X_2だけではなく、ラベルy_1,y_2も混合してしまう点です。
この定式化の解釈の参考記事:
http://www.inference.vc/mixup-data-dependent-data-augmentation/
実装

ジェネレータとして実装します。
https://github.com/yu4u/mixup-generator
import numpy as np

class MixupGenerator():
    def __init__(self, X_train, y_train, batch_size=32, alpha=0.2, shuffle=True, datagen=None):
        self.X_train = X_train
        self.y_train = y_train
        self.batch_size = batch_size
        self.alpha = alpha
        self.shuffle = shuffle
        self.sample_num = len(X_train)
        self.datagen = datagen

    def __call__(self):
        while True:
            indexes = self.__get_exploration_order()
            itr_num = int(len(indexes) // (self.batch_size * 2))

            for i in range(itr_num):
                batch_ids = indexes[i * self.batch_size * 2:(i + 1) * self.batch_size * 2]
                X, y = self.__data_generation(batch_ids)

                yield X, y

    def __get_exploration_order(self):
        indexes = np.arange(self.sample_num)

        if self.shuffle:
            np.random.shuffle(indexes)

        return indexes

    def __data_generation(self, batch_ids):
        _, h, w, c = self.X_train.shape
        _, class_num = self.y_train.shape
        X1 = self.X_train[batch_ids[:self.batch_size]]
        X2 = self.X_train[batch_ids[self.batch_size:]]
        y1 = self.y_train[batch_ids[:self.batch_size]]
        y2 = self.y_train[batch_ids[self.batch_size:]]
        l = np.random.beta(self.alpha, self.alpha, self.batch_size)
        X_l = l.reshape(self.batch_size, 1, 1, 1)
        y_l = l.reshape(self.batch_size, 1)

        X = X1 * X_l + X2 * (1 - X_l)
        y = y1 * y_l + y2 * (1 - y_l)

        if self.datagen:
            for i in range(self.batch_size):
                X[i] = self.datagen.random_transform(X[i])

        return X, y

training_generator = MixoutGenerator(x_train, y_train)()で、訓練データとラベルの集合を引数としてジェネレータを取得し、x, y = next(training_generator)で学習用のバッチが取得できます。
CIFAR-10データセットを利用してmixupした例です。


参考
新たなdata augmentation手法mixupを試してみた - Qiita