[PYTHON] Challenge classification des images par TensorFlow2 + Keras 7-Compréhension des types de couches et des fonctions d'activation-

introduction

Il s'agit d'un mémo d'étude (7ème) sur la classification des images (environnement Google Colaboratory) à l'aide de TensorFlow2 + Keras. Le sujet est la classification des images numériques manuscrites (MNIST), qui est un élément standard.

Dernière fois, à propos de l'image préparée par lui-même, "[Introduction à TensorFlow 2.0 pour les débutants](https: //www.tensorflow. La prédiction (classification) a été réalisée en utilisant le modèle introduit dans "org / tutorials / quickstart / beginner? Hl = ja)".

Cette fois, j'ai étudié le modèle de réseau neuronal présenté dans ce didacticiel, les types de couches qui le composent («Dense», «Dropout», «Flatten») et la fonction d'activation.

SoftMax.png

Comment écrire un modèle

Le code suivant est une copie de "Introduction à TensorFlow 2.0 pour les débutants".

Construction du modèle NN (Description 1)


model = tf.keras.models.Sequential([
  tf.keras.layers.Flatten(input_shape=(28, 28)),
  tf.keras.layers.Dense(128, activation='relu'),
  tf.keras.layers.Dropout(0.2),
  tf.keras.layers.Dense(10, activation='softmax')
])

Dans le code ci-dessus, l'argument mot-clé ʻactivation` qui spécifie la ** fonction d'activation ** est spécifié sous forme de chaîne de caractères, mais il peut également être spécifié en donnant directement la fonction comme suit.

Construction du modèle NN (Description 2)


model = tf.keras.models.Sequential([
  tf.keras.layers.Flatten(input_shape=(28, 28)),
  tf.keras.layers.Dense(128, activation=tf.nn.relu),   #Changement
  tf.keras.layers.Dropout(0.2),
  tf.keras.layers.Dense(10, activation=tf.nn.softmax)  #Changement
])

De plus, ici, les informations de composition de couche du réseau neuronal sont données sous forme de type liste en argument de Sequential (...), mais ** layer est donnée en utilisant ʻadd (...) ʻ comme suit. Vous pouvez également ajouter ** un par un.

Construction du modèle NN (Description 3)


model = tf.keras.models.Sequential()                             # (0)
model.add( tf.keras.layers.Flatten(input_shape=(28, 28)) )       # (1)
model.add( tf.keras.layers.Dense(128, activation=tf.nn.relu) )   # (2)
model.add( tf.keras.layers.Dropout(0.2) )                        # (3)
model.add( tf.keras.layers.Dense(10, activation=tf.nn.softmax) ) # (4)

Afficher l'aperçu du modèle

Vous pouvez obtenir un aperçu du modèle NN avec les couches définies comme ci-dessus avec summary ().

Vérifiez le contour du modèle


model.summary()

Résultat d'exécution


Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
flatten (Flatten)            (None, 784)               0         
_________________________________________________________________
dense (Dense)                (None, 128)               100480    
_________________________________________________________________
dropout (Dropout)            (None, 128)               0         
_________________________________________________________________
dense_1 (Dense)              (None, 10)                1290      
=================================================================
Total params: 101,770
Trainable params: 101,770
Non-trainable params: 0
_________________________________________________________________

De haut en bas, le tableau est ** couche d'entrée **, ** couche intermédiaire (couche cachée) **, ..., ** couche de sortie **.

La valeur la plus à gauche du tableau est "Nom de la couche". Il est automatiquement attribué si name = est omis dans ʻadd () , et est numéroté comme flatten_1, flatten_2` chaque fois que le modèle est construit.

La deuxième valeur () à partir de la gauche est le "type de calque". Il existe trois types ici: «Aplatir», «Dense» et «Dropout». Ce commentaire est dans la section suivante.

La deuxième valeur numérique du taple de l'item "Output Shape" est ** le nombre de neurones dans la couche concernée (= le nombre de sorties de la couche concernée) **. Si c'est «(Aucun, 128)», cela signifie qu'il y a 128 neurones (nœuds) dans cette couche.

Ensuite, l'item "Param" est le nombre total de ** paramètres ** (** poids ** et ** biais ** liés à l'entrée de la couche).

Par exemple, 100480 $ de la deuxième couche «dense (Dense)» est un paramètre de ** weight ** qui est le nombre de sorties de la première couche 784 $ multiplié par le nombre de nœuds de la deuxième couche 128 $, la deuxième couche. Le nombre total de paramètres incluant le ** biais ** des nœuds 128 $. Autrement dit, 784 $ \ fois 128 + 128 = 100480 $. La formation (formation / apprentissage) est l'opération qui permet de trouver les valeurs optimales de ces paramètres.

À la fin du tableau se trouve le nombre de paramètres totaux (nombre total de paramètres), de paramètres entraînables (paramètres requis par la formation) et de paramètres non entraînables (paramètres non requis par la formation).

Rôles, actions et significations de chaque couche

Aplatir la couche

Une image de caractères numériques manuscrits fait 28 $ \ fois 28 $ pixel et est de type (28,28) numpy.ndarray, un tableau à deux dimensions. Dans la couche Flatten, ceci est ** aplati ** et fixé dans un tableau unidimensionnel. Par conséquent, le nombre de sorties est de 28 $ \ fois 28 = 784 $ comme confirmé par model.summary ().

Le programme ajoute une couche d'aplatissement au modèle comme suit:

model.add( tf.keras.layers.Flatten(input_shape=(28, 28)) )   # (1)

L'argument input_shape est spécifié comme (28, 28) to match x_train [*] .shape. Si vous voulez entrer une image de 32 $ \ fois 32 $ pixel, utilisez ʻinput_shape = (32, 32) `. La référence est ici.

Couche dense

Cela signifie une ** couche entièrement connectée ** qui est entièrement liée (étroitement liée) entre la couche précédente et la couche concernée. C'est la couche standard qui constitue un réseau neuronal.

Le programme ajoute une couche dense au modèle comme suit:

Couche entièrement connectée en tant que couche intermédiaire


model.add( tf.keras.layers.Dense(128, activation=tf.nn.relu) )   # (2)

Couche entièrement connectée comme couche de sortie


model.add( tf.keras.layers.Dense(10, activation=tf.nn.softmax) ) # (4)

Le premier argument est le nombre de nœuds (nombre de neurones) qui composent la couche. Comme dans (2) ci-dessus, ** Combien de nœuds doivent être définis dans la couche entièrement connectée comme couche intermédiaire? ** est un élément qui affecte les performances du modèle (c'est un hyper paramètre que l'utilisateur devine et définit par essais et erreurs). Notez qu'un grand nombre de nœuds ne signifie pas que le modèle sera un modèle haute performance (au moins, à mesure que le nombre de nœuds augmente, le nombre de paramètres augmente, donc la quantité de calcul augmente et l'apprentissage prend du temps).

D'un autre côté, si vous avez affaire à un problème de classification multi-classes, ** le nombre de nœuds dans l'ensemble de couches entièrement connecté en tant que couche de sortie doit correspondre au nombre de classes que vous souhaitez classer **. Dans le cas de MNIST, il s'agit d'une classification des nombres de 0 à 9, c'est-à-dire ** 10 problème de classification **, vous devez donc définir «10» ici.

Donnez également ** fonction d'activation ** à l'argument «activation». La ** fonction ReLU ** (tf.nn.relu) et la ** fonction SoftMax ** (tf.nn.softmax) sont utilisées ici, dont les détails sont expliqués dans la section suivante. Si ʻactivation = ʻest omis, la fonction d'activation n'est pas appliquée et la valeur calculée est sortie telle quelle). La référence est ici.

Couche d'abandon

Lors de la formation du modèle **, il fonctionne pour bloquer la sortie de la couche précédente vers la couche suivante en fonction de la probabilité spécifiée (nœud par nœud) (désactiver le nœud correspondant dans la couche précédente selon la probabilité). / Il est également exprimé en baisse). En fournissant cette couche, il semble qu'il soit difficile de rentrer dans la situation du ** surapprentissage **.

À ce sujet, l'explication de "[Neural network] Dropout is summary" était très facile à comprendre.

Le programme ajoute une couche Dropout au modèle comme suit:

model.add( tf.keras.layers.Dropout(0.2) )  # (3) 

Dans l'argument, spécifiez le pourcentage de nœuds que vous souhaitez désactiver dans la plage 0,0 à 1,0. Définir ce paramètre sur 0,0 équivaut essentiellement à ne pas avoir de couche Dropout. De plus, s'il est défini sur 1.0, le réseau sera complètement bloqué au niveau de la couche Dropout, donc aucun apprentissage ne fonctionnera (en fait, ValueError: rate doit être un tenseur scalaire ou un flottant dans l'intervalle [0, 1), J'obtiens l'erreur 1).

Notez que le nœud inactivé est sélectionné ** aléatoirement ** selon la probabilité spécifiée. Par conséquent, si vous avez cette couche Dropout, ** le modèle entraîné changera (légèrement) à chaque entraînement **. Par conséquent, lorsque vous étudiez l'influence d'autres paramètres hyper tels que la relation entre le nombre de nœuds dans la couche dense et le taux de précision, donnez un argument tel que `` seed = 1 '' et corrigez la graine aléatoire (cependant, l'entraînement est meilleur). S'il y a un élément aléatoire dans, même s'il est fixé ici, le modèle entraîné généré changera à chaque exécution).

La référence est ici.

Évaluez l'efficacité de la couche Dropout contre le surapprentissage

Préparez un modèle dans lequel les paramètres de la couche Dropout (taux de nœuds inactivés) sont modifiés de 0,0 à 0,8 par incréments de 0,2. Est-ce efficace contre le surapprentissage en s'entraînant et en évaluant avec Epochs number = 100 et en ajoutant une couche Dropout? J'ai observé **.

Pour chaque époque d'entraînement, le taux de réponse correct (précision) et la valeur de la fonction de perte (perte) pour les données d'entraînement x_train, et le taux de réponse correct (val_accuracy) et la valeur de la fonction de perte (val_loss) pour les données de test x_test ont été acquis et tracés. ..

python


mport numpy as np
import tensorflow as tf

# (1)Téléchargez un ensemble de données d'images numériques manuscrites
mnist = tf.keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()

# (2)Normalisation des données
x_train, x_test = x_train / 255.0, x_test / 255.0

# (3)Construire un modèle NN
#■■ Taux d'abandon à 0.0 à 0.Changer jusqu'à 8 ■■
epochs = 100
results = list()
for p in np.arange(0.0, 1.0, 0.2) :
  print(f'■ Dropout p={p:.1f}')
  tf.keras.backend.clear_session()  
  model = tf.keras.models.Sequential()
  model.add( tf.keras.layers.Flatten(input_shape=(28, 28)) )
  model.add( tf.keras.layers.Dense(128, activation=tf.nn.relu) )
  model.add( tf.keras.layers.Dropout(p) ) #Voir l'effet du paramètre p ici
  model.add( tf.keras.layers.Dense(10, activation=tf.nn.softmax) )

  # (4)Compiler le modèle
  model.compile(optimizer='adam',loss='sparse_categorical_crossentropy',metrics=['accuracy'])

  # (5)Modèle de formation (apprentissage / formation)
  r = model.fit(x_train, y_train, validation_data=(x_test,y_test), epochs=epochs)
  print(r.history)
  results.append( dict( rate=p, hist=r.history ) )

#■■ Sortie graphique ■■
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as tk

ylim = dict( )
ylim['accuracy']     = (0.90, 1.00)
ylim['val_accuracy'] = (0.95, 1.00)
ylim['loss']         = (0.00, 0.20)
ylim['val_loss']     = (0.05, 0.30)

xt_style = lambda x, pos=None : f'{x:.0f}'

for v in ['accuracy','loss','val_accuracy','val_loss'] :
  plt.figure(dpi=96)
  for r in results :
    plt.plot( range(1,epochs+1),r['hist'][v],label=f"rate={r['rate']:.1f}")
  plt.xlim(1,epochs)
  plt.ylim( *(ylim[v]) )
  plt.gca().xaxis.set_major_formatter(tk.FuncFormatter(xt_style))
  plt.tick_params(direction='in')
  plt.legend(bbox_to_anchor=(1.02, 1), loc='upper left', borderaxespad=0)
  plt.xlabel('epoch')
  plt.ylabel(v)
  plt.show()

Résultat expérimental

Corriger la précision du taux de réponse pour les données d'entraînement

g1.png

Dans les deux modèles, plus vous en apprenez, meilleure sera la valeur. En particulier, à un taux = 0,0, ce qui équivaut à la couche d'abandon réelle, le score le plus élevé de 1,0 est atteint. Fondamentalement, plus le taux d'inactivation est petit, plus l'apprentissage est rapide et meilleur est le taux de réponse correcte finale.

Valeur de la fonction de perte pour la perte de données d'entraînement

g2.png

Fondamentalement, il a la même tendance que le taux de réponse correct (précision).

Taux de réponse correct pour les données de test val_accuracy

g3.png

De là, il devient un véritable indice d'évaluation incluant les performances de généralisation.

les taux = 0,2 et 0,4 convergent rapidement et les valeurs finales sont bonnes. En revanche, 0,6 est nettement inférieur à 0,2 et 0,4. 0.0 est un peu moins stable que les autres.

Tant que vous ne regardez que le pourcentage de bonnes réponses, vous ne pouvez pas lire la tendance du surapprentissage.

Valeur de la fonction de perte pour les données de test val_loss

g4.png

Au taux = 0,0 (équivalent à aucune couche d'abandon), la valeur se détériore progressivement après Epoch = 8. Vous pouvez clairement voir la tendance du surapprentissage.

En observant la pente de chaque donnée après Epoch = 20, on peut voir que plus le taux d'inactivité (taux) est élevé, plus il est difficile de surentraîner. Nous avons pu confirmer l'efficacité de la couche Dropout.

Une évaluation complète a confirmé que les valeurs de rate = 0,2 et Epochs = 5 définies dans le didacticiel étaient de bons paramètres bien réglés.

Fonction d'activation

Si la fonction d'activation n'est ** pas appliquée **, la sortie $ y_1 $ du premier nœud de la deuxième couche est calculée comme suit ($ x_i $ est la sortie du $ i $ e nœud de la couche précédente, $ w_ {i1} $ est le poids, $ b_ {1} $ est le biais).

y_1 = b_1 + \sum_{i=1}^{784} x_{i}w_{i1}

En revanche, si vous appliquez la fonction d'activation $ f $, son $ y_1 $ sera:

y_1 = f ( b_1 + \sum_{i=1}^{784} x_{i}w_{i1} )

Il existe diverses fonctions d'activation utilisées dans le réseau neuronal, mais elles peuvent être globalement divisées en ** couramment utilisées dans la couche intermédiaire ** et ** utilisées dans la couche de sortie ** en fonction du type de problème. Je vais.

Dans la couche intermédiaire, la ** fonction ReLU ** et la ** fonction sigmoïde ** sont utilisées. De plus, en raison de sa nature, la couche de sortie des problèmes de classification multi-classes utilise la ** fonction SoftnMax **, et le problème de classification à deux classes utilise la ** fonction sigmoïde **.

Fonction ReLU

** Cela semble être la fonction d'activation la plus couramment utilisée dans la couche intermédiaire **. Si l'entrée est inférieure à 0, la sortie est égale à 0 et si l'entrée est égale ou supérieure à 0, l'entrée est sortie telle quelle. tf.nn.relu (). La référence est ici.

ReLU.png

Fonction ReLU


import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf

xmin, xmax = -10,10
x = np.linspace(xmin, xmax,1000)
y = tf.nn.relu(x)  #Fonction ReLU

#Vérifiez la forme sur le graphique
plt.figure(dpi=96)
plt.plot(x,y,lw=3)
plt.xlim(xmin, xmax)
plt.ylim(-1, 12)
plt.hlines([0],*(plt.xlim()),ls='--',lw=0.5)
plt.vlines([0],*(plt.ylim()),ls='--',lw=0.5)

Il semble qu'il existe une "fonction Leaky Relu" et une "fonction Parametric ReLU" comme variantes de la fonction ReLU.

--Référence: À propos de la fonction d'activation ReLU et du clan ReLU

Fonction Sigmaid

L'une des fonctions d'activation souvent utilisées dans la couche intermédiaire. Cependant, si la fonction sigmoïde est utilisée comme fonction d'activation dans le modèle ** NN avec un grand nombre de couches **, la fonction ReLU semble être privée de sa popularité en raison du problème de disparition du gradient. tf.math.sigmoid (). La référence est ici.

sig.png

python


import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf

xmin, xmax = -10,10
x = np.linspace(xmin, xmax,1000)
y = tf.math.sigmoid(x)  #Fonction Sigmaid

#Vérifiez la forme sur le graphique
plt.figure(dpi=96)
plt.plot(x,y,lw=3)
plt.xlim(xmin, xmax)
plt.ylim(-0.2, 1.2)
plt.hlines([0,0.5,1],*(plt.xlim()),ls='--',lw=0.5)
plt.vlines([0],*(plt.ylim()),ls='--',lw=0.5)

Fonction SoftMax

Couramment utilisé dans la ** couche de sortie ** des problèmes de classification multiclasse. Quelle que soit l'entrée, la sortie varie de 0,0 à 1,0 et la sortie totale est de 1,0. tf.nn.softmax (). La référence est ici.

Par exemple, si vous appliquez la fonction SoftMax à l'entrée «[2, -1, 1, 1]» comme suit, vous obtiendrez une sortie telle que «[0,56, 0,03, 0,21, 0,21]» (la somme des éléments est 1,0). Tu peux l'avoir.

SoftMax.png

Fonction ReLU


import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patheffects as pe
import tensorflow as tf

x = np.array( [2, -1, 1, 1], dtype=np.float64 )
fx = tf.nn.softmax(x)
fx = fx.numpy() # 'numpy.ndarray'Obtenez du contenu avec

np.set_printoptions(precision=2)
print(f'fx = {fx}')
print(f'fx.sum() = {fx.sum():.2f}')

fig, ax = plt.subplots(nrows=2, ncols=1, dpi=96)
plt.subplots_adjust(hspace=0.12)
ep = (pe.Stroke(linewidth=3, foreground='white'),pe.Normal())
tp = dict(horizontalalignment='center',verticalalignment='center')

ax[0].bar( np.arange(0,len(x)), x, fc='tab:red' )
ax[1].bar( np.arange(0,len(fx)), fx )
ax[1].set_ylim(0,1)

for i, p in enumerate([x,fx]) :
  ax[i].tick_params(axis='x', which='both', bottom=False, labelbottom=False)
  ax[i].set_xlim(-0.5,len(p)-0.5)
  for j, v in enumerate(p):
    t = ax[i].text(j, v/2, f'{v:.2f}',**tp)
    t.set_path_effects(ep) 

ax[0].hlines([0],*(plt.xlim()),lw=1)

ax[0].set_ylabel('x')
ax[1].set_ylabel('SoftMax(x)')

la prochaine fois

Indécis

Recommended Posts

Challenge classification des images par TensorFlow2 + Keras 7-Compréhension des types de couches et des fonctions d'activation-
Défiez la classification des images par TensorFlow2 + Keras 6-Essayez le prétraitement et la classification des images préparées par vous-même-
Challenge classification des images par TensorFlow2 + Keras 1-Move pour le moment-
Défiez la classification des images avec TensorFlow2 + Keras 9-Apprentissage, sauvegarde et chargement de modèles-
Défiez la classification des images par TensorFlow2 + Keras 5 ~ Observez les images dont la classification échoue ~
Challenge classification des images par TensorFlow2 + Keras 3 ~ Visualiser les données MNIST ~
Classification d'images avec un réseau de neurones auto-fabriqué par Keras et PyTorch
Challenge classification des images par TensorFlow2 + Keras 2 ~ Regardons de plus près les données d'entrée ~
Défiez la classification des images avec TensorFlow2 + Keras CNN 1 ~ Bougez pour le moment ~
Juge Yosakoi Naruko par classification d'image de Tensorflow.
Visualisez les fonctions d'activation côte à côte
J'ai touché Tensorflow et keras