Il existe de nombreuses publications sur le réseau sur l'interprétation d'un réseau neuronal particulier et la signification et la contribution de certains points à l'apprentissage. Il y a beaucoup de travail sur la recherche des moustaches, des queues et d'autres parties, leur importance et leur signification. Maintenant, je ne remplacerai pas les bibliothécaires et je ferai une liste. Je vais juste vous parler de mon expérience.
Tout a commencé avec un excellent rapport vidéo «Comment pensent les robots. Interprétation des modèles ML » , examinée sur les conseils d'une personne intelligente et comme toute entreprise sensée, a soulevé de nombreuses questions. Par exemple: - dans quelle mesure les points clés du jeu de données sont-ils uniques?
Ou une autre question: - il existe de nombreux articles sur le réseau sur la façon dont le changement d'un point de l'image peut fausser considérablement la prédiction du réseau. Permettez-moi de vous rappeler que dans cet article, nous ne considérerons que les problèmes de classification. À quel point ce point insidieux est-il unique? Y a-t-il de tels points dans la séquence naturelle de MNIST et s'ils sont trouvés et rejetés, la précision d'entraînement du réseau neuronal sera-t-elle plus élevée?
L'auteur, suivant sa méthode traditionnelle de se débarrasser de tous les inutiles, a décidé de ne pas interférer avec le groupe et a choisi un moyen simple, fiable et efficace d'étudier les questions posées:
comme problème expérimental, exemple de préparation, choisissez le MNIST familier ( yann.lecun.com/exdb/mnist ) et sa classification.
En tant que réseau expérimental, j'ai choisi le classique, recommandé pour les débutants, un réseau exemplaire de l'équipe
KERAS github.com/keras-team/keras/blob/master/examples/mnist_cnn.py
Et j'ai décidé de mener la recherche elle-même très simplement.
Entraînons le réseau à partir de KERAS avec un critère d'arrêt tel que l'absence d'augmentation de la précision sur la séquence de test, c'est-à-dire enseigner au réseau jusqu'à ce que test_accuracy devienne significativement plus grand que validation_accuracy et validation_accuracy ne s'améliore pas pendant 15 époques. En d'autres termes, le réseau a cessé d'apprendre et le recyclage a commencé.
À partir du jeu de données MNIST, nous créerons 324 nouveaux jeux de données en supprimant des groupes de points et nous serons enseignés par le même réseau dans exactement les mêmes conditions avec les mêmes poids initiaux.
Commençons, je pense qu'il est juste et juste de disposer tout le code, de la première à la dernière ligne. Même si les lecteurs l'ont vu, évidemment, plusieurs fois.
Nous chargeons les bibliothèques et chargeons l'ensemble de données mnist, s'il n'a pas encore été chargé.
Ensuite, nous le convertissons au format 'float32' et le normalisons dans la plage 0. - 1.
La préparation est terminée.
'''Trains a simple convnet on the MNIST dataset.
Gets to 99.25% test accuracy after 12 epochs
(there is still a lot of margin for parameter tuning).
16 seconds per epoch on a GRID K520 GPU.
'''
from __future__ import print_function
import keras
from keras.datasets import mnist
from keras.models import Sequential, load_model
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras import backend as K
from keras.optimizers import *
from keras.callbacks import EarlyStopping
import numpy as np
import os
num_classes = 10
# input image dimensions
img_rows, img_cols = 28, 28
# the data, shuffled and split between train and test sets
(x_train, y_train), (x_test, y_test) = mnist.load_data()
if K.image_data_format() == 'channels_first':
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 /= np.max(x_train)
x_test /= np.max(x_test)
XX_test = np.copy(x_test)
XX_train = np.copy(x_train)
YY_test = np.copy(y_test)
YY_train = np.copy(y_train)
print('x_train shape:', XX_train.shape)
print('x_test shape:', XX_test.shape)
Rappelons-nous dans les variables le nom des fichiers modèles et des poids, ainsi que la précision et la perte de notre réseau. Ce n'est pas dans le code source, mais c'est nécessaire pour l'expérience.
f_model = "./data/mnist_cnn_model.h5"
f_weights = "./data/mnist_cnn_weights.h5"
accu_f = 'accuracy'
loss_f = 'binary_crossentropy'
Le réseau lui-même est exactement le même que sur
github.com/keras-team/keras/blob/master/examples/mnist_cnn.py .
Enregistrez le réseau et évoluez sur le disque. Nous exécuterons toutes nos tentatives d'entraînement avec les mêmes poids initiaux:
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)
model = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3),
activation='relu',
input_shape=input_shape))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation='softmax'))
model.compile(loss=[loss_f], optimizer=Adam(lr=1e-4), metrics=[accu_f])
model.summary()
model.save_weights(f_weights)
model.save(f_model)
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d (Conv2D) (None, 26, 26, 32) 320
_________________________________________________________________
conv2d_1 (Conv2D) (None, 24, 24, 64) 18496
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 12, 12, 64) 0
_________________________________________________________________
dropout (Dropout) (None, 12, 12, 64) 0
_________________________________________________________________
flatten (Flatten) (None, 9216) 0
_________________________________________________________________
dense (Dense) (None, 128) 1179776
_________________________________________________________________
dropout_1 (Dropout) (None, 128) 0
_________________________________________________________________
dense_1 (Dense) (None, 10) 1290
=================================================================
Total params: 1,199,882
Trainable params: 1,199,882
Non-trainable params: 0
_________________________________________________________________
Commençons par nous entraîner sur la mnist originale pour obtenir une efficacité de base de référence.
x_test = np.copy(XX_test)
x_train = np.copy(XX_train)
s0 = 0
if os.path.isfile(f_model):
model = load_model(f_model)
model.load_weights(f_weights, by_name=False)
step = 0
while True:
fit = model.fit(x_train, y_train,
batch_size=batch_size,
epochs=1,
verbose=0,
validation_data=(x_test, y_test)
)
current_accu = fit.history[accu_f][0]
current_loss = fit.history['loss'][0]
val_accu = fit.history['val_'+accu_f][0]
val_loss = fit.history['val_loss'][0]
print("\x1b[2K","accuracy {0:12.10f} loss {1:12.10f} step {2:5d} val_accu {3:12.10f} val_loss {4:12.10f} ".\
format(current_accu, current_loss, step, val_accu, val_loss), end="\r")
step += 1
if val_accu > max_accu:
s0 = 0
max_accu = val_accu
else:
s0 += 1
if current_accu * 0.995 > val_accu and s0 > 15:
break
else:
print("model not found ")
accuracy 0.9967333078 loss 0.0019656278 step 405 val_accu 0.9916999936 val_loss 0.0054226643
Commençons maintenant l'expérience principale. Nous prenons pour entraînement à partir de la séquence originale les 60 000 images balisées, et nous y remettons tout à zéro sauf le carré 9x9. Obtenons 324 séquences expérimentales et comparons le résultat de la formation du réseau sur celles-ci avec la formation sur la séquence d'origine. Nous formons le même réseau avec les mêmes poids initiaux.
batch_size = 5000
s0 = 0
max_accu = 0.
for i in range(28 - 9):
for j in range(28 - 9):
print("\ni= ", i, " j= ",j)
x_test = np.copy(XX_test)
x_train = np.copy(XX_train)
x_train[:,:i,:j,:] = 0.
x_test [:,:i,:j,:] = 0.
x_train[:,i+9:,j+9:,:] = 0.
x_test [:,i+9:,j+9:,:] = 0.
if os.path.isfile(f_model):
model = load_model(f_model)
model.load_weights(f_weights, by_name=False)
else:
print("model not found ")
break
step = 0
while True:
fit = model.fit(x_train, y_train,
batch_size=batch_size,
epochs=1,
verbose=0,
validation_data=(x_test, y_test)
)
current_accu = fit.history[accu_f][0]
current_loss = fit.history['loss'][0]
val_accu = fit.history['val_'+accu_f][0]
val_loss = fit.history['val_loss'][0]
print("\x1b[2K","accuracy {0:12.10f} loss {1:12.10f} step {2:5d} val_accu {3:12.10f} val_loss {4:12.10f} ".\
format(current_accu, current_loss, step, val_accu, val_loss), end="\r")
step += 1
if val_accu > max_accu:
s0 = 0
max_accu = val_accu
else:
s0 += 1
if current_accu * 0.995 > val_accu and s0 > 15:
break
Cela n'a aucun sens de publier les 324 résultats ici, si quelqu'un est intéressé, je peux l'envoyer personnellement. Le calcul prend plusieurs jours, si quelqu'un veut le répéter.
Il s'est avéré que le réseau sur un découpage 9x9 peut apprendre comme pire, ce qui est évident, mais aussi mieux, ce qui n'est pas du tout évident.
Par exemple:
i = 0 j = 14
précision 0,9972333312 perte 0,0017946947 étape 450 val_accu 0,9922000170 val_loss 0,0054322388
i = 18, j = 1
précision 0,9973166585 perte 0,0019487827 étape 415 val_accu 0,9922000170 val_loss 0,0053000450
Nous deux pas de photos avec des chiffres écrits à la main tous , mais le 9x9 carré et la qualité de l' apprentissage et la reconnaissance s'améliore avec nous!
Il est également clair qu'il existe plus d'un domaine spécial pour améliorer la qualité du réseau. Et pas deux, ces deux sont donnés à titre d'exemple.
Le résultat de cette expérience et les conclusions préliminaires.
- Tout jeu de données naturel, je ne pense pas que LeCune a délibérément déformé quelque chose, contient non seulement des points essentiels à l'apprentissage, mais aussi des points qui interfèrent avec l'apprentissage. La tâche de trouver des points «nuisibles» devient urgente, ils sont là, même s'ils ne sont pas visibles.
- Vous pouvez empiler et fusionner non seulement le long du jeu de données, en sélectionnant des images en groupes, mais également à travers, en sélectionnant des zones d'images à diviser, puis comme d'habitude. Dans ce cas, cette approche améliore la qualité de la formation et on espère que dans une tâche similaire, l'utilisation d'un tel empilement ajoutera de la qualité. Et sur le même kaggle.com, quelques dix millièmes permettent parfois (presque toujours) de rehausser considérablement votre autorité et votre cote.
Merci de votre attention.