[PYTHON] Essayez MNIST avec VAT (Virtual Adversarial Training) avec Keras

introduction

** Remarque: [Version améliorée] Essayez MNIST avec TVA (Virtual Adversarial Training) sur Keras est une meilleure implémentation. Veuillez vous y référer. ** **

Dernièrement, j'ai appris une méthode d'apprentissage appelée VAT (Virtual Adversarial Training), mais je n'ai pas trouvé d'implémentation dans Keras, alors je l'ai essayée.

Pour faire simple, la TVA provient de "l'entrée normale X-> sortie Y" et "entrée (X + d) -> sortie Y '" avec un bruit minuscule d ajouté à l'entrée afin que le résultat soit aussi différent que possible de "KL". -Divergence (Y, Y ') "est ajouté à la fonction de perte pour l'apprentissage.

Je ne sais pas ce que vous entendez par là, veuillez donc vous référer au document original ou Explication de cette personne -Formation /) Je pense que tu devrais y jeter un œil.

La TVA serait proche de la «régularisation» en termes de position dans l'apprentissage, et pourrait être une alternative à l'ajout de Dropout and Noise. Il est également difficile d'ajuster des paramètres tels que l'abandon, je serais donc heureux si la TVA pouvait être utilisée à la place.

Avec Keras, il est un peu difficile d'utiliser l'entrée X pour les fonctions de coût et de régularisation, mais si c'est le cas, vous pouvez le porter car il est implémenté dans Chainer et Theano.

Version

la mise en oeuvre

Il s'est avéré être quelque chose comme ça.

Le point est

Je pense que c'est l'endroit.

keras_mnist_vat.py


# coding: utf8
"""
* VAT: https://arxiv.org/abs/1507.00677

#Code référencé
Original: https://github.com/fchollet/keras/blob/master/examples/mnist_cnn.py
VAT: https://github.com/musyoku/vat/blob/master/vat.py

# Result Example
use_dropout=False, use_vat=False: score=0.211949993095, accuracy=0.9877
use_dropout=True, use_vat=False: score=0.238920686956, accuracy=0.9853
use_dropout=False, use_vat=True: score=0.180048364889, accuracy=0.9916
use_dropout=True, use_vat=True: score=0.245401585515, accuracy=0.9901
"""

import numpy as np
from keras.engine.topology import Input, Container
from keras.engine.training import Model

np.random.seed(1337)  # for reproducibility

from keras.datasets import mnist
from keras.layers import Dense, Dropout, Activation, Flatten
from keras.layers import Convolution2D, MaxPooling2D
from keras.utils import np_utils
from keras import backend as K

SAMPLE_SIZE = 0

batch_size = 128
nb_classes = 10
nb_epoch = 12

# input image dimensions
img_rows, img_cols = 28, 28
# number of convolutional filters to use
nb_filters = 32
# size of pooling area for max pooling
pool_size = (2, 2)
# convolution kernel size
kernel_size = (3, 3)


def main(data, use_dropout, use_vat):
    # the data, shuffled and split between train and test sets
    (X_train, y_train), (X_test, y_test) = data

    if K.image_dim_ordering() == 'th':
        X_train = X_train.reshape(X_train.shape[0], 1, img_rows, img_cols)
        X_test = X_test.reshape(X_test.shape[0], 1, img_rows, img_cols)
        input_shape = (1, img_rows, img_cols)
    else:
        X_train = X_train.reshape(X_train.shape[0], img_rows, img_cols, 1)
        X_test = X_test.reshape(X_test.shape[0], img_rows, img_cols, 1)
        input_shape = (img_rows, img_cols, 1)

    X_train = X_train.astype('float32')
    X_test = X_test.astype('float32')
    X_train /= 255.
    X_test /= 255.

    # convert class vectors to binary class matrices
    y_train = np_utils.to_categorical(y_train, nb_classes)
    y_test = np_utils.to_categorical(y_test, nb_classes)

    if SAMPLE_SIZE:
        X_train = X_train[:SAMPLE_SIZE]
        y_train = y_train[:SAMPLE_SIZE]
        X_test = X_test[:SAMPLE_SIZE]
        y_test = y_test[:SAMPLE_SIZE]

    my_model = MyModel(input_shape, use_dropout).build()
    my_model.training(X_train, y_train, X_test, y_test, use_vat=use_vat)

    score = my_model.model.evaluate(X_test, y_test, verbose=0)
    print("use_dropout=%s, use_vat=%s: score=%s, accuracy=%s" % (use_dropout, use_vat, score[0], score[1]))


class MyModel:
    model = None
    core_layers = None

    def __init__(self, input_shape, use_dropout=True):
        self.input_shape = input_shape
        self.use_dropout = use_dropout

    def build(self):
        input_layer = Input(self.input_shape)
        output_layer = self.core_data_flow(input_layer)
        self.model = Model(input_layer, output_layer)
        return self

    def core_data_flow(self, input_layer):
        x = Convolution2D(nb_filters, kernel_size[0], kernel_size[1], border_mode='valid')(input_layer)
        x = Activation('relu')(x)
        x = Convolution2D(nb_filters, kernel_size[0], kernel_size[1])(x)
        x = Activation('relu')(x)
        x = MaxPooling2D(pool_size=pool_size)(x)
        if self.use_dropout:
            x = Dropout(0.25)(x)

        x = Flatten()(x)
        x = Dense(128, activation="relu")(x)
        if self.use_dropout:
            x = Dropout(0.5)(x)
        x = Dense(nb_classes, activation='softmax')(x)
        self.core_layers = Container(input_layer, x)
        return x

    def training(self, X_train, y_train, X_test, y_test, use_vat=False):
        orig_loss_func = loss_func = K.categorical_crossentropy
        if use_vat:
            # y_concat à vrai(y_true, x_train)Utilisez la fonction de perte anormale pour prendre
            loss_func = self.loss_with_vat_loss(loss_func)
            self.model.compile(loss=loss_func, optimizer='adadelta', metrics=['accuracy'])
            # train,tester les deux y,Créer des données en concaténant X horizontalement
            yX_train = np.concatenate((y_train, X_train.reshape((X_train.shape[0], -1))), axis=1)
            yX_test = np.concatenate((y_test, X_test.reshape((X_test.shape[0], -1))), axis=1)

            #Apprenez normalement
            self.model.fit(X_train, yX_train, batch_size=batch_size, nb_epoch=nb_epoch,
                           verbose=1, validation_data=(X_test, yX_test))
            #J'ai donné une LossFunction anormale, donc je dois la changer en LossFunction normale et la recompiler, ou l'évaluer()Va échouer
            self.model.compile(loss=orig_loss_func, optimizer='adadelta', metrics=['accuracy'])
        else:
            self.model.compile(loss=loss_func, optimizer='adadelta', metrics=['accuracy'])
            self.model.fit(X_train, y_train, batch_size=batch_size, nb_epoch=nb_epoch,
                           verbose=1, validation_data=(X_test, y_test))

    def loss_with_vat_loss(self, original_loss_func, eps=1, xi=10, ip=1):
        def with_vat_loss(yX_train, y_pred):
            nb_output_classes = y_pred.shape[1]
            y_true = yX_train[:, :nb_output_classes]

            # VAT
            X_train = yX_train[:, nb_output_classes:].reshape((-1, ) + self.input_shape)
            d = K.random_normal(X_train.shape)

            for _ in range(ip):
                y = self.core_layers(X_train + self.normalize_vector(d) * xi)
                kld = K.sum(self.kld(y_pred, y))
                d = K.stop_gradient(K.gradients(kld, [d])[0])  # stop_gradient is important!!

            y_perturbation = self.core_layers(X_train + self.normalize_vector(d)*eps)
            kld = self.kld(y_pred, y_perturbation)
            return original_loss_func(y_pred, y_true) + kld
        return with_vat_loss

    @staticmethod
    def normalize_vector(x):
        z = K.sum(K.batch_flatten(K.square(x)), axis=1)
        while K.ndim(z) < K.ndim(x):
            z = K.expand_dims(z, dim=-1)
        return x / (K.sqrt(z) + K.epsilon())

    @staticmethod
    def kld(p, q):
        v = p * (K.log(p + K.epsilon()) - K.log(q + K.epsilon()))
        return K.sum(K.batch_flatten(v), axis=1, keepdims=True)


data = mnist.load_data()
main(data, use_dropout=False, use_vat=False)
main(data, use_dropout=True, use_vat=False)
main(data, use_dropout=False, use_vat=True)
main(data, use_dropout=True, use_vat=True)

Résultat expérimental

J'ai expérimenté 4 modèles avec et sans Dropout et avec et sans TVA. 1 époque correspond à la GeForce GTX 1080, variable d'environnement

KERAS_BACKEND=theano 
THEANO_FLAGS=device=gpu,floatX=float32,lib.cnmem=1

C'est quand il est exécuté comme.

Dropout VAT Accuracy 1 époque
ne pas utiliser ne pas utiliser 98.77% 8 secondes
utilisation ne pas utiliser 98.53% 8 secondes
ne pas utiliser utilisation 99.16% 18 secondes
utilisation utilisation 99.01% 19 secondes

Eh bien, le résultat est raisonnablement bon, donc je pense qu'il n'y a pas de problème en termes de mise en œuvre. La TVA étant calculée deux fois en 1 lot, le temps d'exécution est également doublé.

à la fin

La TVA peut également être utilisée pour l'apprentissage non supervisé, c'est donc une méthode d'apprentissage avec un large éventail d'applications. Je souhaite l'utiliser de différentes manières.

Recommended Posts

Essayez MNIST avec VAT (Virtual Adversarial Training) avec Keras
[Version améliorée] Essayez MNIST avec VAT (Virtual Adversarial Training) sur Keras
Essayez TensorFlow MNIST avec RNN
MNIST (DCNN) avec Keras (backend TensorFlow)
Débutant RNN (LSTM) | Essayer avec Keras
Essayez de vous connecter à qiita avec Python
Essayez de travailler avec des données binaires en Python
Essayez d'implémenter XOR avec l'API fonctionnelle Keras
Essayez de résoudre le problème du fizzbuzz avec Keras
J'ai essayé de déplacer GAN (mnist) avec keras
J'ai essayé d'intégrer Keras dans TFv1.1
Créer un environnement virtuel avec conda avec Python
Essayez d'utiliser l'environnement virtuel conda avec Jupyter Notebook
Essayez de travailler avec Mongo en Python sur Mac
Essayez Theano avec les données MNIST de Kaggle ~ Retour logistique ~
Travaillez dans un environnement virtuel avec Python virtualenv.
Essayez de convertir des vidéos en temps réel avec OpenCV