[PYTHON] Apprentissage profond appris par mise en œuvre (segmentation) ~ Mise en œuvre de SegNet ~

environnement

tensorflow == 2.2.0 keras == 2.3.1 (Version par défaut de Google Colab à partir du 202.6.10)

code

Vous pouvez trouver tout le code sur github. https://github.com/milky1210/Segnet Le code de l'article est un extrait, donc si vous voulez vraiment le travailler, veuillez télécharger le code.

Résumer le contenu de l'article de SegNet

スクリーンショット 2020-06-09 13.18.49.png

Abstrait

Dans le problème de la déduction de l'étiquette de ce qui est reflété pour chaque pixel de l'image appelée segmentation SEMANTIQUE par apprentissage en profondeur, il est précis de restaurer la carte de caractéristiques qui a été abaissée en résolution par Pooling, etc. à la dimension d'origine. Nous proposons un modèle qui correspond à la ligne de démarcation. スクリーンショット 2020-06-09 13.29.43.png

Différence par rapport aux autres études

SegNet effectue un UpSampling après avoir réduit la résolution dans la couche de convolution et la couche de pooling comme un FCN normal, mais lors de l'augmentation de la résolution, il utilise une technique appelée indice de pooling pour éviter que la limite ne devienne floue. Il y a. スクリーンショット 2020-06-09 13.34.45.png Ici, Encode et Decode héritent de la forme du modèle VGG16 (un modèle célèbre pour la classification d'images). Pooling indices スクリーンショット 2020-06-09 13.39.25.png Comme le montre cette figure, rappelez-vous où se trouvait Max lorsque Max Pooling a été effectué et transférez chaque carte d'entités à cette position pendant l'échantillonnage ascendant.

Comparaison des performances avec VOC12

Qu'est-ce que VOC12

Il s'agit d'un ensemble de données qui prend en charge des problèmes tels que la reconnaissance d'image, la détection d'image et la segmentation, qui sont également utilisés dans les articles de SegNet pour la vérification des performances. Vous pouvez le télécharger depuis ici.

Une fois téléchargés, JPEGImages / et SegmentationObject / sont inclus dans VOCdevkit / VOC2012 /, et la formation et la vérification sont effectuées avec JPEGImage comme image d'entrée et SegmentationObject comme image de sortie.

JPEGImages / ~ .jpg et Segmentation Object / ~ .png sont pris en charge dans chaque répertoire. 22 classes sont classées, y compris le contexte et les limites.

la mise en oeuvre

Seules la définition du modèle, la définition de la fonction de perte et la formation seront couvertes dans l'article. De plus, la formation et la vérification seront menées à une résolution de 64x64.

Définition du modèle

Premièrement, comme cible de comparaison, SegNet (encodeur-décodeur) sans indice de regroupement est modélisé comme VGG16 comme suit.

def build_FCN():
  ffc = 32
  inputs = layers.Input(shape=(64,64,3))
  for i in range(2):
    x = layers.Conv2D(ffc,kernel_size=3,padding="same")(inputs)
    x = layers.BatchNormalization()(x)
    x = layers.ReLU()(x)
  x = layers.MaxPooling2D((2,2))(x)
  for i in range(2):
    x = layers.Conv2D(ffc*2,kernel_size=3,padding="same")(x)
    x = layers.BatchNormalization()(x)
    x = layers.ReLU()(x)
  x = layers.MaxPooling2D((2,2))(x)
  for i in range(3):
    x = layers.Conv2D(ffc*4,kernel_size=3,padding="same")(x)
    x = layers.BatchNormalization()(x)
    x = layers.ReLU()(x)
  x = layers.MaxPooling2D((2,2))(x)
  for i in range(3):
    x = layers.Conv2D(ffc*8,kernel_size=3,padding="same")(x)
    x = layers.BatchNormalization()(x)
    x = layers.ReLU()(x)
  x = layers.MaxPooling2D((2,2))(x)
  for i in range(3):
    x = layers.Conv2D(ffc*8,kernel_size=3,padding="same")(x)
    x = layers.BatchNormalization()(x)
    x = layers.ReLU()(x)
  x = layers.UpSampling2D((2,2))(x)
  for i in range(3):
    x = layers.Conv2D(ffc*4,kernel_size=3,padding="same")(x)
    x = layers.BatchNormalization()(x)
    x = layers.ReLU()(x)
  x = layers.UpSampling2D((2,2))(x)
  for i in range(3):
    x = layers.Conv2D(ffc*2,kernel_size=3,padding="same")(x)
    x = layers.BatchNormalization()(x)
    x = layers.ReLU()(x)
  x = layers.UpSampling2D((2,2))(x)
  for i in range(2):
    x = layers.Conv2D(ffc*2,kernel_size=3,padding="same")(x)
    x = layers.BatchNormalization()(x)
    x = layers.ReLU()(x)
  x = layers.UpSampling2D((2,2))(x)
  for i in range(2):
    x = layers.Conv2D(ffc,kernel_size=3,padding="same")(x)
    x = layers.BatchNormalization()(x)
    x = layers.ReLU()(x)
  x = layers.Conv2D(22,kernel_size=3,padding="same",activation="softmax")(x)
  return models.Model(inputs,x)

S'il est modélisé d'après vgg16, il aura une telle structure, et ce sera un réseau avec 24 couches de convolution. Notez que MaxPooling2D est utilisé pour rendre l'image plus petite et UpSampling2D est utilisé pour agrandir l'image. Ensuite, regardons la différence entre Segnet et ce modèle. Premièrement, Segnet contient les informations correspondant à ArgMaxPooling2D dans cette couche comme suit avant d'exécuter MaxPooling2D. Cette fonction n'est pas dans Keras et utilise celle de tensorflow. Par conséquent, il est nécessaire de créer la couche Keras d'origine. Si vous définissez la fonction comme suit, ce sera une couche qui s'exécute sur Keras.

class MaxPoolingWithArgmax2D(Layer):
    def __init__(self):
        super(MaxPoolingWithArgmax2D,self).__init__()
    def call(self,inputs):
        output,argmax = tf.nn.max_pool_with_argmax(inputs,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')
        argmax = K.cast(argmax,K.floatx())
        return [output,argmax]
    def compute_output_shape(self,input_shape):
        ratio = (1,2,2,1)
        output_shape = [dim//ratio[idx] if dim is not None else None for idx, dim in enumerate(input_shape)]
        output_shape = tuple(output_shape)
        return [output_shape,output_shape]

Définissez un calque pour revenir à l'emplacement qui était argmax la prochaine fois que vous effectuez un échantillonnage ascendant (c'est assez long)

class MaxUnpooling2D(Layer):
    def __init__(self):
        super(MaxUnpooling2D,self).__init__()
    def call(self,inputs,output_shape = None):
        updates, mask = inputs[0],inputs[1]
        with tf.variable_scope(self.name):
            mask = K.cast(mask, 'int32')
            input_shape = tf.shape(updates, out_type='int32')
            #  calculation new shape
            if output_shape is None:
                output_shape = (input_shape[0],input_shape[1]*2,input_shape[2]*2,input_shape[3])
            self.output_shape1 = output_shape
            # calculation indices for batch, height, width and feature maps
            one_like_mask = K.ones_like(mask, dtype='int32')
            batch_shape = K.concatenate([[input_shape[0]], [1 ], [1], [1]],axis=0)
            batch_range = K.reshape(tf.range(output_shape[0], dtype='int32'),shape=batch_shape)
            b = one_like_mask * batch_range
            y = mask // (output_shape[2] * output_shape[3])
            x = (mask // output_shape[3]) % output_shape[2]
            feature_range = tf.range(output_shape[3], dtype='int32')
            f = one_like_mask * feature_range

            # transpose indices & reshape update values to one dimension
            updates_size = tf.size(updates)
            indices = K.transpose(K.reshape(
                K.stack([b, y, x, f]),
                [4, updates_size]))
            values = K.reshape(updates, [updates_size])
            ret = tf.scatter_nd(indices, values, output_shape)
            return ret
    def compute_output_shape(self,input_shape):
        shape = input_shape[1]
        return (shape[0],shape[1]*2,shape[2]*2,shape[3])

Si Segnet est défini en utilisant la couche définie par ceux-ci, ce sera comme suit.

def build_Segnet():
    ffc = 32
    inputs = layers.Input(shape=(64,64,3))
    for i in range(2):
      x = layers.Conv2D(ffc,kernel_size=3,padding="same")(inputs)
      x = layers.BatchNormalization()(x)
      x = layers.ReLU()(x)
    x,x1 = MaxPoolingWithArgmax2D()(x)
    for i in range(2):
      x = layers.Conv2D(ffc*2,kernel_size=3,padding="same")(x)
      x = layers.BatchNormalization()(x)
      x = layers.ReLU()(x)
    x,x2 = MaxPoolingWithArgmax2D()(x)
    for i in range(3):
      x = layers.Conv2D(ffc*4,kernel_size=3,padding="same")(x)
      x = layers.BatchNormalization()(x)
      x = layers.ReLU()(x)
    x,x3 = MaxPoolingWithArgmax2D()(x)
    for i in range(3):
      x = layers.Conv2D(ffc*8,kernel_size=3,padding="same")(x)
      x = layers.BatchNormalization()(x)
      x = layers.ReLU()(x)
    x,x4 = MaxPoolingWithArgmax2D()(x)
    for i in range(3):
      x = layers.Conv2D(ffc*8,kernel_size=3,padding="same")(x)
      x = layers.BatchNormalization()(x)
      x = layers.ReLU()(x)
    x = layers.Dropout(rate = 0.5)(x)
    x = MaxUnpooling2D()([x,x4])
    for i in range(3):
      x = layers.Conv2D(ffc*4,kernel_size=3,padding="same")(x)
      x = layers.BatchNormalization()(x)
      x = layers.ReLU()(x)
    x = MaxUnpooling2D()([x,x3])
    for i in range(3):
      x = layers.Conv2D(ffc*2,kernel_size=3,padding="same")(x)
      x = layers.BatchNormalization()(x)
      x = layers.ReLU()(x)
    x = MaxUnpooling2D()([x,x2])
    for i in range(2):
      x = layers.Conv2D(ffc,kernel_size=3,padding="same")(x)
      x = layers.BatchNormalization()(x)
      x = layers.ReLU()(x)
    x = MaxUnpooling2D()([x,x1])
    for i in range(2):
      x = layers.Conv2D(ffc,kernel_size=3,padding="same")(x)
      x = layers.BatchNormalization()(x)
      x = layers.ReLU()(x)
    x = layers.Conv2D(22,kernel_size=3,padding="same",activation="softmax")(x)
    return models.Model(inputs,x)

Fonction de perte et optimisation

Cette fois, la fonction de perte a utilisé l'entropie croisée de chaque pixel. Adam (lr = 0,001, beta_1 = 0,9, beta_2 = 0,999) a été utilisé pour l'optimisation.

résultat

Nous avons confirmé combien le résultat change en fonction de la présence ou de l'absence de mise en commun dans les dés. La perte de la formation et la moyenne du taux de réponse correct à chaque pixel ont été représentées graphiquement. Premièrement, le résultat du modèle sans indice de pooling acc (1).png

loss (1).png

Les données de vérification avaient un taux de réponse correcte d'environ 78%. Ensuite, je publierai les résultats de SegNet.

acc.png loss.png Il était stable avec un taux de réponse correcte d'environ 82%, et nous avons pu voir le comportement selon l'article.

Exemple d'image de sortie

Entrée de gauche, pas d'indice de regroupement, toutes les données de test avec SegNet, GT

Il a été constaté que la détention de l'indice de mise en commun devrait améliorer considérablement la précision.

Recommended Posts

Apprentissage profond appris par mise en œuvre (segmentation) ~ Mise en œuvre de SegNet ~
Apprentissage profond appris par l'implémentation 1 (édition de retour)
Apprentissage profond appris par la mise en œuvre ~ Détection d'anomalies (apprentissage sans enseignant) ~
Apprentissage par renforcement profond 2 Mise en œuvre de l'apprentissage par renforcement
Othello-De la troisième ligne de "Implementation Deep Learning" (3)
Othello-De la troisième ligne de "Implementation Deep Learning" (2)
Chainer et deep learning appris par approximation de fonction
Deep learning 1 Pratique du deep learning
Apprentissage parallèle du deep learning par Keras et Kubernetes
Deep Learning from scratch La théorie et la mise en œuvre de l'apprentissage profond appris avec Python Chapitre 3
Othello ~ De la troisième ligne de "Implementation Deep Learning" (4) [Fin]
Deep running 2 Réglage de l'apprentissage profond
[Pour les débutants en apprentissage profond] Implémentation d'une classification binaire simple par couplage complet à l'aide de Keras
[Deep Learning from scratch] Implémentation de la méthode Momentum et de la méthode AdaGrad
Apprentissage des classements à l'aide d'un réseau neuronal (implémentation RankNet par Chainer)
Compréhension de base de l'estimation de la profondeur par caméra mono (Deep Learning)
Résumé de l'implémentation de base par PyTorch
Implémentation du modèle de reconnaissance d'images d'apprentissage en profondeur 2
Essayez de faire une stratégie de blackjack en renforçant l'apprentissage ((1) Implémentation du blackjack)
[Mémo d'apprentissage] Bases de la classe par python
Signification des modèles et paramètres d'apprentissage en profondeur
Branchement conditionnel de Python appris avec la chimioinfomatique
Qiskit: mise en œuvre de l'apprentissage des circuits quantiques (QCL)
Produisez de belles vaches de mer par apprentissage profond
Implémentation de SVM par méthode de descente de gradient probabiliste
Essayez l'apprentissage profond de la génomique avec Kipoi
Algorithme d'apprentissage automatique (implémentation de la classification multi-classes)
Visualisez les effets de l'apprentissage profond / de la régularisation
Détection d'objets par apprentissage profond pour comprendre en profondeur par Keras
Analyse émotionnelle des tweets avec apprentissage en profondeur
L'apprentissage en profondeur
Enregistrement d'apprentissage de la lecture "Deep Learning from scratch"
Apprentissage profond à partir de zéro - Conseils du chapitre 4 pour la théorie de l'apprentissage profond et la mise en œuvre apprise en Python
Python vs Ruby "Deep Learning from scratch" Chapitre 4 Implémentation de la fonction de perte
Python vs Ruby "Deep Learning from scratch" Chapitre 3 Implémentation d'un réseau neuronal à 3 couches
Créez un environnement python pour apprendre la théorie et la mise en œuvre de l'apprentissage profond
Python: Apprentissage en profondeur dans le traitement du langage naturel: Implémentation d'un système de sélection de phrases de réponses
Mise en place d'un modèle de prédiction des taux de change (taux dollar-yen) par machine learning
L'histoire de l'apprentissage profond avec TPU
Classification des images de guitare par apprentissage automatique Partie 1
Apprentissage profond / rétropropagation d'erreur de la fonction sigmoïde
Un mémorandum d'étude et de mise en œuvre du Deep Learning
Compréhension de base de l'estimation de la profondeur stéréo (Deep Learning)
99,78% de précision avec apprentissage en profondeur en reconnaissant les hiragana manuscrits
Interpolation d'images vidéo par apprentissage en profondeur, partie 1 [Python]
Vue d'ensemble des techniques d'apprentissage automatique apprises grâce à scikit-learn
Amélioration de la metrix de performance par modèle d'apprentissage en 2 étapes
[Français] scikit-learn 0.18 Introduction de l'apprentissage automatique par le didacticiel scikit-learn
Classification des images de guitare par apprentissage automatique, partie 2
Premier apprentissage profond en C # -Imitation de l'implémentation en Python-
Mémorandum d'apprentissage profond
Commencer l'apprentissage en profondeur
Apprentissage en profondeur Python
Apprentissage profond × Python
Investissement en actions par apprentissage approfondi (méthode du gradient de politique) (1)
Détection de valeur anormale par apprentissage non supervisé: distance Maharanobis (implémentation)
Comptez le nombre de paramètres dans le modèle d'apprentissage en profondeur
Présentation de DNC (Differentiable Neural Computers) + Implémentation par Chainer