Essayez l'augmentation de l'effacement aléatoire des données

Qu'est-ce que l'augmentation aléatoire des données d'effacement?

Dans l'apprentissage automatique, l'augmentation des données qui empêche le sur-apprentissage en traitant les données d'entrée est souvent utilisée, mais récemment une nouvelle méthode d'augmentation des données a été proposée dans le domaine de la reconnaissance d'images.

Les deux sont des méthodes de masquage d'une zone rectangulaire partielle aléatoire de l'image qui est les données de l'enseignant. La différence est que l'effacement aléatoire rend aléatoire la taille et le rapport hauteur / largeur du rectangle, tandis que la découpe a une taille fixe. (Cependant, Cutout expérimente également une méthode de masquage sélectif d'une partie de l'objet cible, et un masque de taille fixe est tout aussi efficace que cela, donc si vous utilisez un masque de taille fixe pour plus de simplicité Prétendre) En plus de la classification des images, la fonction Random Erasing a confirmé son efficacité dans la détection d'objets et l'appariement de personnes.

Image de l'effacement aléatoire

(L'image utilisée ici est différente des données utilisées cette fois)

Avant le traitement d'image Après le traitement de l'image
remove_aug1.jpg remove_aug2.jpg

Essayez l'augmentation de l'effacement aléatoire des données

J'ai décidé d'essayer l'effacement aléatoire. J'ai choisi ceci au lieu de Cutout car il semble plus efficace de rendre la taille du rectangle aléatoire.

La tâche effectuée est la classification de l'ensemble de données CIFAR-10. Mis en œuvre avec Chainer. Le code source est ci-dessous.

Après avoir cloné le code source, vous pouvez vous entraîner avec la commande suivante (garder la dernière option -p de la même manière écrasera les données enregistrées, il est donc recommandé de la changer à chaque fois que vous vous entraînez).

$ python src/download.py
$ python src/dataset.py
$ python src/train.py -g 0 -m vgg_no_fc -p remove_aug --iter 300 -b 128 --lr 0.1 --lr_decay_iter 150,225

Mise en œuvre de l'effacement aléatoire

Hyper paramètres

Les hyper paramètres liés à l'effacement aléatoire sont les suivants.

Cette fois, j'ai choisi une valeur proche du papier et je l'ai définie comme suit.

Hyper paramètres valeur
p 0.5
s_l 0.02
s_h 0.4
r_1 1/3
r_2 3

la mise en oeuvre

Le code réellement utilisé est le suivant. Il est implémenté comme une méthode de la classe héritée de chainer.datasets.TupleDataset. Les parties de «# Supprimer le début de l'effacement» à «# Supprimer la fin de l'effacement» sont les processus liés à Supprimer l'effacement, et la zone rectangulaire aléatoire est remplie de valeurs aléatoires. (Je pense qu'il vaut mieux aligner la plage de valeurs à remplir avec la plage de données à utiliser) x of _transform est un tableau de données d'entrée et a la taille de [Taille du lot, nombre de canaux, hauteur, largeur].

    def _transform(self, x):
        image = np.zeros_like(x)
        size = x.shape[2]
        offset = np.random.randint(-4, 5, size=(2,))
        mirror = np.random.randint(2)
        remove = np.random.randint(2)
        top, left = offset
        left = max(0, left)
        top = max(0, top)
        right = min(size, left + size)
        bottom = min(size, top + size)
        if mirror > 0:
            x = x[:,:,::-1]
        image[:,size-bottom:size-top,size-right:size-left] = x[:,top:bottom,left:right]
        # Remove erasing start
        if remove > 0:
            while True:
                s = np.random.uniform(0.02, 0.4) * size * size
                r = np.random.uniform(-np.log(3.0), np.log(3.0))
                r = np.exp(r)
                w = int(np.sqrt(s / r))
                h = int(np.sqrt(s * r))
                left = np.random.randint(0, size)
                top = np.random.randint(0, size)
                if left + w < size and top + h < size:
                    break
            c = np.random.randint(-128, 128)
            image[:, top:top + h, left:left + w] = c
        # Remove erasing end
        return image

Structure du réseau neuronal

Le code réseau est indiqué ci-dessous. Il combine convolutionnel et Max Pooling comme VGG. Cependant, la couche entièrement connectée n'est pas fournie et le nombre de paramètres est réduit en effectuant un regroupement global à la place.


class BatchConv2D(chainer.Chain):
    def __init__(self, ch_in, ch_out, ksize, stride=1, pad=0, activation=F.relu):
        super(BatchConv2D, self).__init__(
            conv=L.Convolution2D(ch_in, ch_out, ksize, stride, pad),
            bn=L.BatchNormalization(ch_out),
        )
        self.activation=activation

    def __call__(self, x):
        h = self.bn(self.conv(x))
        if self.activation is None:
            return h
        return self.activation(h)

class VGGNoFC(chainer.Chain):
    def __init__(self):
        super(VGGNoFC, self).__init__(
            bconv1_1=BatchConv2D(3, 64, 3, stride=1, pad=1),
            bconv1_2=BatchConv2D(64, 64, 3, stride=1, pad=1),
            bconv2_1=BatchConv2D(64, 128, 3, stride=1, pad=1),
            bconv2_2=BatchConv2D(128, 128, 3, stride=1, pad=1),
            bconv3_1=BatchConv2D(128, 256, 3, stride=1, pad=1),
            bconv3_2=BatchConv2D(256, 256, 3, stride=1, pad=1),
            bconv3_3=BatchConv2D(256, 256, 3, stride=1, pad=1),
            bconv3_4=BatchConv2D(256, 256, 3, stride=1, pad=1),
            fc=L.Linear(256, 10),
        )

    def __call__(self, x):
        h = self.bconv1_1(x)
        h = self.bconv1_2(h)
        h = F.dropout(F.max_pooling_2d(h, 2), 0.25)
        h = self.bconv2_1(h)
        h = self.bconv2_2(h)
        h = F.dropout(F.max_pooling_2d(h, 2), 0.25)
        h = self.bconv3_1(h)
        h = self.bconv3_2(h)
        h = self.bconv3_3(h)
        h = self.bconv3_4(h)
        h = F.dropout(F.max_pooling_2d(h, 2), 0.25)
        h = F.average_pooling_2d(h, 4, 1, 0)
        h = self.fc(F.dropout(h))
        return h

Conditions d'apprentissage

Les conditions d'apprentissage sont les suivantes.

résultat

La précision a été améliorée en utilisant l'effacement aléatoire comme suit.

Méthode Test Error
Effacement aléatoire non utilisé 6.68
Utiliser l'effacement aléatoire 5.67

La transition entre Erreur d'entraînement et Erreur de test est la suivante. Lors de l'utilisation de l'effacement aléatoire, la différence entre l'erreur d'entraînement et l'erreur de test est plus petite, et il semble que le surapprentissage est supprimé.

Effacement aléatoire non utilisé: vgg_no_fc_error.png

Effacement aléatoire utilisé: vgg_no_fc_remove_aug_error.png

en conclusion

C'était une méthode simple pour masquer l'image d'entrée, j'ai donc pu l'essayer immédiatement. C'était efficace cette fois, mais je pense qu'il est nécessaire de vérifier si c'est une méthode efficace dans diverses conditions. S'il est efficace, il pourrait devenir la norme à l'avenir.

C'est une méthode tellement simple que je me demande personnellement si elle a été proposée dans le passé.

Les références

Recommended Posts

Essayez l'augmentation de l'effacement aléatoire des données
Augmentation des données avec openCV
Essayez de désactiver IPv6 au hasard
Essayez «100 coups sur la science des données» ①
[PyTorch] Augmentation des données pour la segmentation
Nouvelle augmentation des données? [Grid Mix]
Essayez de mettre des données dans MongoDB
Comment augmenter les données avec PyTorch
[Apprentissage automatique] Essayez d'étudier une forêt aléatoire
Essayez les données en parallèle avec TensorFlow distribué