[PYTHON] Défiez la classification des images par TensorFlow2 + Keras 5 ~ Observez les images dont la classification échoue ~

introduction

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

Dernière fois a fait des prédictions (classifications) à l'aide de modèles entraînés. Cette fois, dans le modèle créé par TF Official HP Tutorial, ** Quel type d'image la prédiction (classification) échoue-t-elle? ** Aussi ** Quel genre de classification erronée se produira? J'observerai **.

Plus précisément, avec matplotlib, affichez comme suit.

■ Cas où la valeur de réponse correcte «6» n'a pas pu être prédite (classée) correctement x6.png

Nous allons également créer un diagramme montrant les relations de classification erronées suivantes.

Heat map.png

Extraction de données numériques manuscrites n'ayant pas été classifiées

À partir des 10000 données d'entrée de test (images de nombres manuscrits), ** extrayez celles qui n'ont pas pu être classées correctement ** en utilisant le modèle du tutoriel TF.

En passant, lorsque le modèle entraîné a été évalué par model.evaluate (x_test, y_test, verbose = 2), le taux de réponse correct (précision) était de 0,9759. Par conséquent, $ (1-0,9759) \ times 10,000 = 241 $ les nombres manuscrits n'ont pas pu être classés (le modèle entraîné généré pour chaque entraînement sera légèrement différent, ce qui entraînera une classification. Veuillez noter que les images qui échouent seront également légèrement différentes).

Pour ce processus d'extraction, nous utilisons la bibliothèque "pandas", qui est pratique pour l'analyse des données. De plus, comme l'explication sur les bases des pandas n'est pas incluse, veuillez vous référer à d'autres articles pour cela.

Le code suivant stocke les valeurs correctes et prédites dans une colonne du bloc de données. Ici, l'index de ligne correspond à l'index x_test.

python


import numpy as np
import pandas as pd
p_test = model.predict_classes(x_test) #Prévoir
df = pd.DataFrame({'Valeur de réponse correcte':y_test, 'Valeur prédite':p_test})
display(df.head(5))  #Afficher 5 lignes depuis le début
display(df.tail(5))  #Afficher 5 lignes à partir de la fin

Le résultat de l'exécution est le suivant. Pour les 5 premiers cas et les 5 derniers cas, la valeur de réponse correcte et la valeur prédite correspondent toutes.

pd1.png

Ensuite, ** extrayez les lignes où les valeurs correctes et prédites ne correspondent pas ** et stockez-les dans un nouveau bloc de données df2. Il trie également.

python


#Extraire les lignes où «bonne réponse» et «prédiction» ne correspondent pas
df2 = df[df['Valeur de réponse correcte']!=df['Valeur prédite']]
display(df2.head(5))

#Trier par ordre croissant 1ère clé'Valeur de réponse correcte', 2ème clé'Valeur prédite'
df2 = df2.sort_values(['Valeur de réponse correcte', 'Valeur prédite'])
display(df2.head(5))

Le résultat de l'exécution est le suivant. pd2.png

De là, nous pouvons voir que x_test [9634] est "** la bonne réponse est" 0 ", mais la prédiction est" 1 "**".

Affichage de la liste des images numérotées manuscrites qui n'ont pas pu être classées

Le x_test [9634] qui n'a pas réussi à classer ** quel type de nombre manuscrit **, et ** a prédit par erreur "1". Dans quelle mesure était-ce convaincu? ** Je suis curieux.

** Quel genre de numéro manuscrit est ** est une image si vous utilisez ʻimshow (...) ʻ de matplotlib comme expliqué dans Partie 2. Vous pouvez sortir et vérifier.

De plus, ** À quel point j'avais confiance que j'avais prédit par erreur "1" ** a été expliqué dans 4th. Comme vous pouvez le voir, il peut être récupéré à partir des informations obtenues par model.predict (...). Plus précisément, il peut être obtenu en procédant comme suit.

python


idn = 9634
s = model.predict( np.array([x_test[idn]]) ) #Valeur de la couche de sortie
s = s[0]
print( f'La classification prédictive est "{s.argmax()}, La valeur de sortie du neurone correspondant dans la couche de sortie{s[s.argmax()]:.2f}' ) 
print( f'La classification correcte de la réponse est "{y_test[idn]}, La valeur de sortie du neurone correspondant dans la couche de sortie{s[y_test[idn]]:.2f}' )

La classification prédictive est "1" et la valeur de sortie du neurone correspondant dans la couche de sortie est de 0,62. La classification de réponse correcte est "0" et la valeur de sortie du neurone correspondant dans la couche de sortie est 0,00.

Vous pouvez également utiliser le code (sortie de rapport de classification prédictive) affiché à la fin de 4th pour vérifier comme suit.

9634.png

La bonne réponse, "0", n'est même pas faible. Cela peut être inévitable car il s'agit d'une image avec de la poussière en haut à gauche, mais si vous pouvez observer ces choses, vous pourrez peut-être obtenir des indices sur le prétraitement **.

Cependant, il est difficile de les sortir individuellement, donc je voudrais ** les afficher tous ensemble **.

python


import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patheffects as pe

for t in range(0,10):

  print(f'■ Valeur de réponse correcte "{t}N'a pas été correctement prédit (classé)')

  #Extraire les lignes avec la valeur correcte t
  index_list = list(df2[df2['Valeur de réponse correcte']==t].index.values)

  #sortie matplotlib
  n_cols = 7
  n_rows = ((len(index_list)-1)//n_cols)+1
  fig, ax = plt.subplots(nrows=n_rows, ncols=n_cols, figsize=(6.5, 0.9*n_rows), dpi=120)
  for i,ax in enumerate( np.ravel(ax) ):
    if i < len(index_list):
      
      p = index_list[i]
      ax.imshow(x_test[p],interpolation='nearest',vmin=0.,vmax=1.,cmap='Greys')

      #La prédiction (classification) s'affiche en haut à gauche
      t = ax.text(1, 1, f'{p_test[p]}', verticalalignment='top', fontsize=8, color='tab:red')
      t.set_path_effects([pe.Stroke(linewidth=2, foreground='white'), pe.Normal()]) 

      #Les valeurs des neurones de la couche de sortie correspondant à la prédiction (séparation) sont affichées entre parenthèses.
      t = ax.text(5, 2, f'({s_test[p].max():.1f})', verticalalignment='top', fontsize=6, color='tab:red')
      t.set_path_effects([pe.Stroke(linewidth=2, foreground='white'), pe.Normal()]) 
      
      #Masquer l'échelle, etc.
      ax.tick_params(axis='both', which='both', left=False, labelleft=False, 
                     bottom=False, labelbottom=False)
      
      #Index affiché en bleu
      ax.set_title(index_list[i],fontsize=7,pad=1.5,color='tab:blue')

    else :
      ax.axis('off') #Traitement des marges

  plt.show()

C'est le résultat de l'exécution (seule la partie sortie sous forme de texte est légèrement formatée).

■ Cas où la valeur de réponse correcte «0» n'a pas pu être prédite (classée) correctement x0.png

■ Cas où la valeur de réponse correcte «1» n'a pas pu être prédite (classée) correctement x1.png

■ Cas où la valeur de réponse correcte «2» n'a pas pu être prédite (classée) correctement x2.png

■ Cas où la valeur de réponse correcte «3» n'a pas pu être prédite (classée) correctement x3.png

■ Cas où la valeur de réponse correcte «4» n'a pas pu être prédite (classée) correctement x4.png

■ Cas où la valeur de réponse correcte «5» n'a pas pu être prédite (classée) correctement x5.png

■ Cas où la valeur de réponse correcte «6» n'a pas pu être prédite (classée) correctement x6.png

■ Cas où la valeur de réponse correcte «7» n'a pas pu être prédite (classée) correctement x7.png

■ Cas où la valeur de réponse correcte «8» n'a pas pu être prédite (classée) correctement x8.png

■ Cas où la valeur de réponse correcte «9» n'a pas pu être prédite (classée) correctement x9.png

Impressions

Si vous le regardez comme ça, vous pouvez voir qu'il contient des données qui ne peuvent être reconnues par aucun moyen (même si les humains le jugent ...). D'un autre côté, d'un point de vue humain, pourquoi vous méprenez-vous sur une telle chose? Il y a aussi le résultat. C'est intéressant.

Tableau croisé

Créons un ** tableau croisé ** pour les valeurs correctes et prédites. Cela permet de classer facilement quel nombre ** dans quel nombre? Vous pouvez obtenir des informations telles que **. Les tableaux croisés peuvent être facilement créés avec crosstab (...).

python


import pandas as pd

p_test = model.predict_classes(x_test) #Prévoir
df = pd.DataFrame({'Valeur de réponse correcte':y_test, 'Valeur prédite':p_test})

#Tableau croisé
dfc = pd.crosstab(index=df['Valeur de réponse correcte'], columns=df['Valeur prédite']) 
display(dfc)

Le résultat de l'exécution est le suivant.

ct.png

Il semble qu'il y ait 19 cas où "4" est mal classé comme "9" (vous pouvez le comprendre d'une manière ou d'une autre). Ensuite, 13 cas ont mal classé «3» à «5» et 12 cas ont mal classé «9» à «3» (ceci est différent du sentiment humain et est intéressant. Au fait).

Visualisation

Sortons le tableau croisé sous forme de carte thermique en utilisant matplotlib. Le code sera long, je montrerai donc le résultat en premier.

ヒートマップ.png

matplotlib_Processus de préparation de la sortie japonaise


!pip install japanize-matplotlib
import japanize_matplotlib

python


import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patheffects as pe
import matplotlib.ticker as ticker
import matplotlib.colors

p_test = model.predict_classes(x_test) #Prévoir
df = pd.DataFrame({'Valeur de réponse correcte':y_test, 'Valeur prédite':p_test})

#Tableau croisé
dfc = pd.crosstab(index=df['Valeur de réponse correcte'], columns=df['Valeur prédite']) 
#display(dfc)

for i in dfc.index.values :
  dfc.at[i,i] = 0.0

#Sortie sous forme de carte thermique
plt.figure(dpi=160)

plt.imshow(dfc,interpolation='nearest',cmap='Oranges')
plt.plot([0,0],[9,9])

n = len(dfc.columns) #Nombre d'objets
plt.gca().set_xticks(range(n))
plt.gca().set_xticklabels(dfc.columns)
plt.gca().set_yticks(range(n))
plt.gca().set_yticklabels(dfc.columns)

plt.tick_params(axis='x', which='both', direction=None, 
                top=True, bottom=False, labeltop=True, labelbottom=False)
plt.tick_params(axis='both', which='both', top=False, left=False )

#Paramètres de la grille
plt.gca().set_xticks(np.arange(-0.5, n-1), minor=True);
plt.gca().set_yticks(np.arange(-0.5, n-1), minor=True);
plt.grid( which='minor', color='white', linewidth=1)

plt.gca().xaxis.set_label_position('top') 
plt.xlabel('Valeur prédite')
plt.ylabel('Valeur de réponse correcte')

plt.plot([-0.5,n-0.5],[-0.5,n-0.5],color='black',linewidth=0.75)

#Afficher le coefficient de corrélation (texte avec bordure)
tp = dict(horizontalalignment='center',verticalalignment='center')
ep = [pe.Stroke(linewidth=3, foreground='white'),pe.Normal()]
for y,i in enumerate(dfc.index.values) :
  for x,c in enumerate(dfc.columns.values) :
    if x != y :
      if dfc.at[i,c] !=  0:
        t = plt.text(x, y, f'{dfc.at[i,c]}',**tp)
        t.set_path_effects(ep) 

la prochaine fois

――La prochaine fois, je ferai une prédiction en utilisant les données manuscrites que j'ai créées. Comprend des étapes pour télécharger des images sur Google Colab., Chargement d'images, redimensionnement et autres prétraitements.

予測.png

Recommended Posts