Cet article présente la classification des ensembles de données MNIST à l'aide de l'environnement de développement de Kaggle (bloc-notes Kernel) et Keras comme introduction à l'analyse des moines de peinture. Le noyau est ouvert au public sur Kaggle, alors jetez un œil si vous voulez l'exécuter vous-même.
Si vous avez des erreurs, des questions ou des commentaires, veuillez nous en informer. Ce sera encourageant si vous pouvez obtenir LGTM!
Kaggle est le plus grand concours analytique en ligne au monde. En outre, il existe un environnement de développement en ligne appelé Kernel notebook qui vous permet de travailler immédiatement sur l'analyse, ce qui est idéal pour démarrer l'analyse des données. Cet article est destiné à ceux qui se sont déjà inscrits auprès de Kaggle et savent comment utiliser Kernel. (Il existe de nombreux articles que même ceux qui ne connaissent pas peuvent être utiles, donc je pense que vous pouvez les rattraper immédiatement.)
Voir ci-dessous pour plus de détails.
Keras est une bibliothèque d'apprentissage en profondeur basée sur Tensorflow, connue pour sa capacité à créer des modèles d'apprentissage en profondeur très rapidement.
Voir ci-dessous pour plus de détails.
Il s'agit d'un ensemble de données d'image très connu, composé de nombres manuscrits (0-9) et des nombres qu'ils représentent vraiment (étiquette correcte).
Voir ci-dessous pour plus de détails.
Encore une fois, cet article est également posté sur le noyau de Kaggle, donc si vous voulez un fork, veuillez le voir également.
Vous pouvez voir que les données d'entraînement se composent de 42 000 éléments de données. De plus, bien qu'il y ait 785 colonnes, l'étiquette correcte est la première, vous pouvez donc voir que la quantité de caractéristiques utilisée pour l'apprentissage se compose de 784. Vous pouvez voir que l'étiquette est un entier et que la quantité d'entités est 0 pour la plupart des éléments.
#Chargement des données d'entraînement
train = pd.read_csv("../input/train.csv")
print(train.shape)
train.head()
Il y a 28000 données de test. Il n'y a pas d'étiquette correcte, il se compose donc de 784 colonnes.
#Chargement des données de test
test= pd.read_csv("../input/test.csv")
print(test.shape)
test.head()
Conversion de type et conversion en données numpy faciles à utiliser.
#Découpez la partie quantité de fonction des données d'entraînement à l'exclusion de l'étiquette de réponse correcte.
X_train = train.iloc[:,1:].values.astype('float32')
#Découpez uniquement l'étiquette de réponse correcte dans les données d'entraînement.
y_train = train.iloc[:,0].values.astype('int32')
#Ce sont des données de test.
X_test = test.values.astype('float32')
Regardons le pourcentage de 0 dans les données. Le rapport de 0 est d'environ 80%, et vous pouvez voir que la plupart des éléments sont 0. Dans cet ensemble de données, 0 signifie vide = zone non caractérisée.
print(f"Le pourcentage d'éléments non nuls{round((X_train > 0).sum()/(X_train >= 0 ).sum()*100)}%est")
print(f"Le pourcentage de 0 éléments{round((X_train == 0).sum()/(X_train >= 0 ).sum()*100)}%est")
En regardant la distribution des étiquettes correctes, nous pouvons voir que chaque étiquette de 0 à 9 constitue environ 10%. Par conséquent, il semble que l'ajustement dû au déséquilibre de classe ne soit pas nécessaire.
#Afficher le pourcentage d'étiquettes correctes dans un graphique circulaire
f, ax = plt.subplots(1,figsize=(6,6))
y_count = pd.Series(y_train).value_counts().sort_index()
ax.pie(y_count.values ,
labels=y_count.index,
autopct='%1.1f%%',
counterclock = False,
startangle = 90)
plt.show()
Ensuite, transformez les données dans un formulaire facile à gérer comme une image. Comme nous l'avons vu précédemment, chaque image se compose de 784 éléments, ce qui est en fait un effondrement unidimensionnel de données carrées comprenant 28 éléments verticaux et 28 éléments horizontaux. Se transforme en 28x28 pour toutes les données d'entraînement (42000 = X_train.shape [0]).
#Transformation des données
X_train = X_train.reshape(X_train.shape[0], 28, 28)
Visualisons les données brutes transformées. Ici, afin de considérer la signification des données brutes, exprimons les données sous forme de chaîne de caractères sans utiliser de bibliothèque d'images. Affiche la partie où l'élément non nul existe sous la forme #. Ensuite, vous pouvez obtenir la sortie comme des nombres manuscrits.
Les données originales sont une liste de nombres difficiles à comprendre pour les humains, mais il s'agissait en fait de données constituées de l'intention de l'encre (qu'elle ne soit pas 0 ou non) et de sa densité (valeur du nombre).
#Convertir les données en chaîne de caractères et afficher
def visualize_str(d):
d = d.astype("int32").astype("str")
d[d != "0"] = "# "
d[d == "0"] = ". "
d = pd.DataFrame(d)
for i in range(d.shape[0]):
print("".join(d.iloc[i,:]))
print("")
for i in range(1):
visualize_str(X_train[i])
Si vous essayez de l'afficher sous forme d'image, vous obtiendrez toujours le même résultat que l'affichage de chaîne de caractères précédent.
#Visualisez avec l'image
f, ax = plt.subplots(1,3)
for i in range(3):
ax[i].imshow(X_train[i], cmap=plt.get_cmap('gray'))
Étant donné que les images colorées sont parfois utilisées dans l'analyse d'images, on suppose que l'entrée du modèle a une dimension appelée canal de couleur qui comprend des nuances de couleur (principalement Mihara). Puisque cette fois c'est une échelle de gris, il n'y a pas de nouvelles données, mais nous allons convertir le tenseur selon l'idée ci-dessus. De plus, définissez un encodage à chaud et des nombres aléatoires comme préparation avant l'apprentissage.
#Ajouter un canal de couleur
X_train = X_train.reshape(X_train.shape[0], 28, 28,1)
X_test = X_test.reshape(X_test.shape[0], 28, 28,1)
#Un encodage à chaud
from keras.utils.np_utils import to_categorical
y_train= to_categorical(y_train)
#Nombres aléatoires fixes pour la reproductibilité
seed = 0
np.random.seed(seed)
C'est enfin la modélisation, mais essayons d'abord un modèle linéaire très simple.
Et avant cela, définissez les fonctions d'importation et de standardisation de modules requises.
from keras.models import Sequential
from keras.layers.core import Lambda , Dense, Flatten, Dropout
#from keras.callbacks import EarlyStopping
from keras.layers import BatchNormalization, Convolution2D , MaxPooling2D
#Définition de la fonction de normalisation
mean_X = X_train.mean().astype(np.float32)
std_X = X_train.std().astype(np.float32)
def standardize(x):
return (x-mean_X)/std_X
Créons maintenant le modèle.
#Définition du modèle linéaire
model_linear= Sequential()
#Standardisation
model_linear.add(Lambda(standardize,input_shape=(28,28,1)))
#Passez à une dimension pour insérer la couche entièrement connectée
model_linear.add(Flatten())
#Couche entièrement connectée
model_linear.add(Dense(10, activation='softmax'))
#Visualisation du modèle
print("model_linear")
model_linear.summary()
Keras se compile après avoir défini le modèle. Lors de la compilation, l'index à optimiser par learning = loss et l'indice à vraiment optimiser sont spécifiés.
#Compiler le modèle
#Spécifiez l'index à optimiser et l'index à observer
from keras.optimizers import Adam ,RMSprop
model_linear.compile(optimizer=RMSprop(lr=0.001),
loss='categorical_crossentropy',
metrics=['accuracy'])
Maintenant que le modèle est prêt, je souhaite remplir le modèle avec des données, mais je dois préparer les données. Préparez un générateur et divisez les données pour la validation croisée. (Cela devrait être appelé la méthode holdout, mais dans Kaggle, elle est généralement exprimée comme une validation croisée, donc je suis conscient du malentendu et je l'exprime de cette façon.)
#Préparation des données à saisir
#Définition du générateur
from keras.preprocessing import image
generator = image.ImageDataGenerator()
#Toutes les données d'apprentissage utilisées au moment de la soumission
X = X_train
y = y_train
#Validation croisée
from sklearn.model_selection import train_test_split
X_train, X_val, y_train, y_val = train_test_split(X_train, y_train, test_size=0.15, random_state=seed)
train_generator = generator.flow(X_train, y_train, batch_size=64)
val_generator = generator.flow(X_val, y_val, batch_size=64)
Préparez également une planche tensorielle pour faciliter la visualisation de la situation d'apprentissage et des résultats. La sortie standard affichera l'URL, alors ouvrez-la dans votre navigateur.
#Lancement de tensorboard
import tensorflow as tf
!rm -rf ./logs/
!mkdir ./logs/
!wget https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip
!unzip ngrok-stable-linux-amd64.zip
import os
import multiprocessing
import datetime
pool = multiprocessing.Pool(processes = 10)
results_of_processes = [pool.apply_async(os.system, args=(cmd, ), callback = None )
for cmd in [
f"tensorboard --logdir ./logs/ --host 0.0.0.0 --port 6006 &",
"./ngrok http 6006 &","y"
]]
! curl -s http://localhost:4040/api/tunnels | python3 -c \
"import sys, json; print(json.load(sys.stdin)['tunnels'][0]['public_url'])"
log_dir = "logs/fit/" + datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir=log_dir, histogram_freq=0)
Maintenant que nous sommes prêts, il est temps de commencer à apprendre. Il montre la progression de l'apprentissage avec la barre de progression et l'index spécifié par compile.
#Apprentissage des données avec epoch3
# ~Je pense que cela prendra environ 15 minutes
import tensorflow as tf
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
history_linear=model_linear.fit_generator(generator=train_generator,
steps_per_epoch=train_generator.n,
epochs=3,
validation_data=val_generator,
validation_steps=val_generator.n,
callbacks=[tensorboard_callback]
)
Les résultats ci-dessus montrent comment l'apprentissage se fait, mais nous visualiserons les résultats pour une compréhension plus intuitive.
En regardant les pertes, nous pouvons voir qu'un surapprentissage se produit parce que les résultats de validation augmentent à mesure que l'apprentissage progresse. En revanche, notez que la validation de l'ACC (taux de réponse correcte) n'a pas diminué de manière monotone. Les indicateurs discontinus comme ACC sont difficiles à gérer, vous optimisez donc à la place avec une fonction de perte facile à utiliser.
#Visualisation des résultats
#Définition de la fonction pour tracer le résultat
def plt_history(history,keys):
history_dict = history.history
n = len(keys)
f, ax = plt.subplots(n,figsize=(8,4*n))
for i in range(n):
train_value = history_dict[keys[i][0]]
val_value = history_dict[keys[i][1]]
epochs = range(1, len(train_value) + 1)
if n==1:
ax.plot(epochs, train_value, 'bo',label = keys[i][0])
ax.plot(epochs, val_value, 'b+',label = keys[i][1])
ax.legend()
ax.set_xlabel('Epochs')
ax.set_ylabel(keys[i][0])
else:
ax[i].plot(epochs, train_value, 'bo',label = keys[i][0])
ax[i].plot(epochs, val_value, 'b+',label = keys[i][1])
ax[i].legend()
ax[i].set_xlabel('Epochs')
ax[i].set_ylabel(keys[i][0])
plt.show()
#Visualisation
plt_history(history_linear, [["loss","val_loss"],["acc","val_acc"]])
Dans ce modèle, une couche entièrement connectée est ajoutée pour approfondir la couche. Nous avons également changé l'algorithme d'optimisation en Adam. (Cela devrait être comparé expérimentalement pour déterminer l'optimum.)
De plus, bien que nous ayons défini et traité des modèles séquentiellement plus tôt, en général, nous définissons des types de modèles avec des classes et des fonctions, et créons différents modèles d'entraînement avec plusieurs paramètres et données d'apprentissage différents. Par conséquent, à partir de là, nous définirons le modèle avec une fonction.
#Définition du modèle
def get_fc_model():
model = Sequential()
model.add(Lambda(standardize,input_shape=(28,28,1)))
model.add(Flatten())
model.add(Dense(512, activation='relu'))
model.add(Dense(10, activation='softmax'))
model.compile(optimizer = Adam(),
loss='categorical_crossentropy',
metrics=['accuracy'])
return model
model_fc = get_fc_model()
model_fc.optimizer.lr=0.01
model_fc.summary()
Apprenez le modèle de la même manière qu'avant. Si vous souhaitez essayer plusieurs modèles en peu de temps, vous devez faire un compromis tel que la réduction du nombre d'époques. En regardant les résultats, nous pouvons voir que la validation ACC est plus élevée qu'avant.
#Apprentissage de modèle
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
history_fc=model_fc.fit_generator(generator=train_generator,
steps_per_epoch=train_generator.n,
epochs=1,
validation_data=val_generator,
validation_steps=val_generator.n,
callbacks=[tensorboard_callback]
)
#Résultat d'apprentissage
history_dict_fc = history_fc.history
history_dict_fc
Ensuite, essayez le modèle CNN qui inclut la couche de pliage et la couche de regroupement. Comme CNN peut apprendre efficacement une large zone, une grande précision peut être attendue pour les problèmes d'analyse d'image. Cette fois, nous allons préparer deux types de profondeur de couche et voir la différence.
#Définition du modèle
from keras.layers import Convolution2D, MaxPooling2D
#Un modèle avec deux plis et deux regroupements
def get_cnn_model1():
model = Sequential([
Lambda(standardize, input_shape=(28,28,1)),
Convolution2D(32,(3,3), activation='relu'),
MaxPooling2D(),
Convolution2D(64,(3,3), activation='relu'),
MaxPooling2D(),
Flatten(),
Dense(512, activation='relu'),
Dense(10, activation='softmax')
])
model.compile(optimizer = Adam(), loss='categorical_crossentropy',
metrics=['accuracy'])
return model
#Un modèle avec pliage et mise en commun 3 fois chacun
def get_cnn_model2():
model = Sequential([
Lambda(standardize, input_shape=(28,28,1)),
Convolution2D(32,(3,3), activation='relu'),
MaxPooling2D(),
Convolution2D(64,(3,3), activation='relu'),
MaxPooling2D(),
Convolution2D(128,(3,3), activation='relu'),
MaxPooling2D(),
Flatten(),
Dense(512, activation='relu'),
Dense(10, activation='softmax')
])
model.compile(optimizer = Adam(), loss='categorical_crossentropy',
metrics=['accuracy'])
return model
model_cnn1 = get_cnn_model1()
model_cnn2 = get_cnn_model2()
model_cnn1.optimizer.lr=0.01
model_cnn2.optimizer.lr=0.01
Le modèle peu profond apprend 843658 paramètres
model_cnn1.summary()
Le modèle plus profond apprend 163 850 paramètres, ce qui est inférieur à model_cnn1. En effet, l'effet périphérique de la couche de pliage et de la couche de mise en commun réduit considérablement l'entrée de données dans la couche entièrement connectée. En fait, en regardant les dimensions d'aplatir, il était de 1600 pour cnn1, mais seulement de 128 pour cnn2. Si la taille de l'image est grande, il est souhaitable de réduire la taille des données de cette manière, mais quel genre de résultat sera obtenu avec des données compactes comme cette fois?
model_cnn2.summary()
Nous étudierons chacun.
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
history_cnn1=model_cnn1.fit_generator(generator=train_generator,
steps_per_epoch=train_generator.n,
epochs=1,
validation_data=val_generator,
validation_steps=val_generator.n,
callbacks=[tensorboard_callback]
)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
history_cnn2=model_cnn2.fit_generator(generator=train_generator,
steps_per_epoch=train_generator.n,
epochs=1,
validation_data=val_generator,
validation_steps=val_generator.n,
#callbacks=[tensorboard_callback]
)
Vérifions le résultat.
Comparé au modèle CNN avec une couche peu profonde, le modèle CNN avec une couche profonde a de mauvais résultats en termes de taux de perte et de précision pour les données d'apprentissage et les données de validation. Il y a plusieurs raisons possibles à cela.
① Le modèle est mauvais La raison pour laquelle le modèle est mauvais est que les paramètres d'apprentissage ont diminué. Le fait qu'il existe de nombreux paramètres qui peuvent être ajustés signifie que vous pouvez créer une expression plus variée. Ce modèle a un petit nombre de paramètres, il n'a donc peut-être pas été suffisamment expressif.
② Les données d'apprentissage sont mauvaises Le surentraînement est susceptible de se produire lorsque le nombre de données d'entraînement est insuffisant. Cette fois, le taux de précision des données d'apprentissage n'est pas si mauvais, mais le résultat de la validation présente une grande divergence, ce qui est un état de surapprentissage typique. Il est peut-être possible de s'améliorer en élargissant les données à essayer à partir de maintenant.
③ Manque d'apprentissage Il est possible que le modèle n'ait pas encore été entièrement formé. Dans ce cas, la perte de données d'apprentissage est plus grande que celle de cnn1, donc si vous augmentez l'époque, la formation peut avoir lieu. Cependant, la divergence par rapport à la validation est un autre problème, donc augmenter l'époque dans cet état ne sera pas une solution essentielle.
history_cnn1.history
history_cnn2.history
On pense que plus il y a de données d'entraînement, plus la performance de généralisation est élevée = un surapprentissage est moins susceptible de se produire. L'augumentation des données est une méthode permettant d'augmenter artificiellement les données d'entraînement à partir d'un nombre limité de données. L'expansion des données est une technique pour gonfler les données en apportant des modifications mineures aux données données.
#Expansion des données
from keras.preprocessing import image
DA_generator =image.ImageDataGenerator(rotation_range=10,
width_shift_range=0.1,
shear_range=0.1,
height_shift_range=0.1,
zoom_range=0.1)
train_DA_generator = DA_generator.flow(X_train, y_train, batch_size=64)
val_DA_generator = DA_generator.flow(X_val, y_val, batch_size=64)
#Exemple de données étendues
tmp_gen = DA_generator.flow(X_train[0].reshape((1,28,28,1)), batch_size = 1)
for i, tmp in enumerate(tmp_gen):
plt.subplot(330 + (i+1))
plt.imshow(tmp.reshape((28,28)), cmap=plt.get_cmap('gray'))
if i == 8:
break
Je pense que cela prendra environ 15 minutes pour apprendre. Suite à l'expansion des données, les résultats de la validation ont été améliorés. Les résultats des données d'entraînement et les résultats de la validation s'amélioreront pour chaque époque, donc si vous avez le temps, essayez d'augmenter l'époque et expérimentez.
#CNN 1 couche CNN peu profonde
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
model_cnn1.optimizer.lr=0.005
history_cnn1_DA=model_cnn1.fit_generator(generator=train_DA_generator,
steps_per_epoch=train_DA_generator.n,
epochs=1,
validation_data=val_DA_generator,
validation_steps=val_DA_generator.n,
callbacks=[tensorboard_callback]
)
history_cnn1_DA.history
Dans les modèles précédents, l'entrée était normalisée. Cependant, cela ne garantit pas que la sortie de chaque couche est normalisée. Ensuite, après une certaine couche, la sortie devient très grande et les paramètres peuvent devenir très petits. Ou vice versa, les paramètres peuvent être très importants.
Dans un tel cas, l'apprentissage ne peut pas être bien fait, mais ce problème peut être résolu en ajoutant une couche de normalisation par lots qui standardise pour chaque couche. On dit que cela améliore à la fois les performances de généralisation et la vitesse d'apprentissage.
Le nombre d'époques est également fixé à 1 cette fois, mais si vous avez du temps à perdre, augmentez le nombre d'époques et observez les conditions de surapprentissage.
from keras.layers.normalization import BatchNormalization
def get_bn_model():
model = Sequential([
Lambda(standardize, input_shape=(28,28,1)),
Convolution2D(32,(3,3), activation='relu'),
BatchNormalization(axis=1),
MaxPooling2D(),
BatchNormalization(axis=1),
Convolution2D(64,(3,3), activation='relu'),
BatchNormalization(axis=1),
MaxPooling2D(),
BatchNormalization(axis=1),
Flatten(),
BatchNormalization(),
Dense(512, activation='relu'),
BatchNormalization(),
Dense(10, activation='softmax')
])
model.compile(optimizer = Adam(), loss='categorical_crossentropy', metrics=['accuracy'])
return model
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
model_bn= get_bn_model()
model_bn.optimizer.lr=0.01
history_bn=model_bn.fit_generator(generator=train_DA_generator,
steps_per_epoch=train_DA_generator.n,
epochs=1,
validation_data=val_DA_generator,
validation_steps=val_DA_generator.n,
callbacks=[tensorboard_callback]
)
history_bn.history
Enfin, je présenterai le modèle avec le score le plus élevé parmi les modèles présentés dans cet article. La conception de ce modèle nécessite des essais et des erreurs, comme l'ajout de couches et la modification des fonctions d'optimisation, comme nous l'avons vu jusqu'à présent. Ce modèle optimal est un modèle qui a subi une série d'essais et d'erreurs (dans mes capacités et mon environnement de développement actuels).
Nous avons ajouté une couche d'exclusion, le réglage initial de He et un rappel qui modifie le taux d'apprentissage étape par étape.
En conséquence, la variation marque un taux de réponse correcte de 99,4%.
from keras.layers import Dense, Dropout, Flatten, Convolution2D, MaxPooling2D
from keras.layers.normalization import BatchNormalization
from keras.callbacks import ReduceLROnPlateau
def get_opt_model():
model = Sequential([
Lambda(standardize, input_shape=(28,28,1)),
Convolution2D(32,(3,3), activation='relu',kernel_initializer='he_normal'),
Convolution2D(32,(3,3), activation='relu',kernel_initializer='he_normal'),
MaxPooling2D(),
Dropout(0.20),
Convolution2D(32,(3,3), activation='relu',kernel_initializer='he_normal'),
Convolution2D(32,(3,3), activation='relu',kernel_initializer='he_normal'),
MaxPooling2D(),
Dropout(0.25),
Convolution2D(32,(3,3), activation='relu',kernel_initializer='he_normal'),
Dropout(0.25),
Flatten(),
Dense(128, activation='relu'),
BatchNormalization(),
Dropout(0.25),
Dense(10, activation='softmax')
])
model.compile(optimizer=Adam(),
loss='categorical_crossentropy',
metrics=['accuracy'])
return model
learning_rate_reduction = ReduceLROnPlateau(monitor='val_loss',
patience=3,
verbose=1,
factor=0.5,
min_lr=0.0001)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
model_opt = get_opt_model()
history_opt = model_opt.fit_generator(generator=train_DA_generator,
steps_per_epoch=train_DA_generator.n,
epochs=3,
validation_data=val_DA_generator,
validation_steps=val_DA_generator.n,
callbacks=[tensorboard_callback, learning_rate_reduction]
)
Y_pred = model_opt.predict_classes(X_val,verbose = 0)
Y_pred_prob = model_opt.predict(X_val,verbose = 0)
#Visualisation des résultats
plt_history(history_opt, [["loss","val_loss"],["acc","val_acc"]])
history_opt.history
Il y avait des réponses incorrectes même dans le modèle optimal, mais quel type de données sont-elles incorrectes? En regardant la matrice mixte, il semble qu'il n'y ait presque pas de réponses incorrectes, mais il y a des cas où 1 est confondu avec 7 et 7 est confondu avec 2.
#Définition d'une fonction qui affiche une matrice de confusion
import itertools
def plt_confusion_mtx(confusion_mtx):
cmap=plt.cm.Reds
title='Confusion matrix'
f, ax = plt.subplots(1,figsize=(6,6))
im = ax.imshow(confusion_mtx, interpolation='nearest', cmap=cmap)
ax.set_title(title)
ax.set_xticks(np.arange(10))
ax.set_yticks(np.arange(10))
ax.set_xlabel('Predicted label')
ax.set_ylabel('True label')
f.colorbar(im)
thresh = confusion_mtx.max() / 2
for i, j in itertools.product(range(confusion_mtx.shape[0]), range(confusion_mtx.shape[1])):
ax.text(j, i, confusion_mtx[i, j],
horizontalalignment="center",
color="white" if confusion_mtx[i, j] > thresh else "black")
#Affichage de la matrice de confusion
from sklearn.metrics import confusion_matrix
Y_true = np.argmax(y_val,axis=1)
confusion_mtx = confusion_matrix(Y_true, Y_pred)
plt_confusion_mtx(confusion_mtx)
#Précision pour chaque classe mondiale,Confirmation de rappel, etc.
from sklearn.metrics import classification_report
target_names = ["Class {}".format(i) for i in range(10)]
print(classification_report(Y_true, Y_pred, target_names=target_names))
Lorsque vous regardez les données de réponse incorrectes, il y a des cas où il est difficile pour les humains de les distinguer, mais on soupçonne plutôt que l'étiquetage est erroné.
#Confirmation de données de réponse incorrectes
errors = (Y_pred - Y_true != 0)
Y_pred_errors = Y_pred[errors]
Y_pred_prob_errors = Y_pred_prob[errors]
Y_true_errors = Y_true[errors]
X_val_errors = X_val[errors]
def display_errors(errors_index,img_errors,pred_errors, obs_errors):
""" This function shows 6 images with their predicted and real labels"""
n = 0
nrows = 2
ncols = 3
fig, ax = plt.subplots(nrows,ncols, figsize = (8,8))
for row in range(nrows):
for col in range(ncols):
error = errors_index[n]
ax[row,col].imshow((img_errors[error]).reshape((28,28)))
ax[row,col].set_title("Predicted label :{}\nTrue label :{}".format(pred_errors[error],obs_errors[error]))
n += 1
errors = (Y_pred - Y_true != 0)
tmp = Y_pred_prob[errors] - to_categorical(Y_pred[errors])
display_index = np.argsort(tmp.max(axis=1))[:6]
display_errors(display_index, X_val_errors, Y_pred_errors, Y_true_errors)
On peut dire que le modèle optimal a des performances suffisantes pour résister à une utilisation pratique.
Ceci conclut l'introduction à l'analyse d'images Deep Learning par Keras. À partir de là, vous pouvez essayer de vous entraîner avec des ensembles de données plus complexes, essayer le transfert d'apprentissage avec des modèles entraînés, essayer des modèles d'apprentissage en profondeur célèbres, et bien plus encore. Je vais. Si cet article est utile à quelqu'un, j'aimerais mettre à jour ces articles de tutoriel à l'avenir, alors veuillez me soutenir chez LGTM.
Aussi, je suis toujours à la recherche d'un emploi, alors faites-le moi savoir si vous en avez l'opportunité.