CIFAR-10 Impossible d'obtenir une précision supérieure à 60%, Keras avec le backend Tensorflow [fermé]

11

La formation après 15 époques sur l'ensemble de données CIFAR-10 semble faire en sorte que la perte de validation ne diminue plus, se situant autour de 1,4 (avec une précision de validation de 60%). J'ai mélangé l'ensemble d'entraînement, divisé par 255 et importé en float32. J'ai essayé de nombreuses architectures, avec et sans décrochage dans les couches Conv2D et rien ne semble fonctionner. La même architecture atteint une précision de 99,7% sur les ensembles de test pour MNIST. Veuillez consulter l'architecture ci-dessous:

(Remarque: j'ai essayé d'augmenter le décrochage et d'augmenter / diminuer le taux d'apprentissage de l'optimiseur Adam pour éviter le surapprentissage, tout cela empêche le surapprentissage, mais avec la formation et l'ensemble de test ayant maintenant une faible précision similaire autour de 60%).

with tf.device('/gpu:0'):
    tf.placeholder(tf.float32, shape=(None, 20, 64))
    #placeholder initialized (pick /cpu:0 or /gpu:0)
    seed = 6
    np.random.seed(seed)
    modelnn = Sequential()
    neurons = x_train_reduced.shape[1:]

    modelnn.add(Convolution2D(32, 3, 3, input_shape=neurons, activation='relu', border_mode='same'))
    modelnn.add(Convolution2D(32, 3, 3, activation='relu', border_mode='same'))
    modelnn.add(MaxPooling2D(pool_size=(2, 2)))
    modelnn.add(Dropout(0.2))
    modelnn.add(Convolution2D(64, 3, 3, activation='relu', border_mode='same'))
    modelnn.add(Convolution2D(64, 3, 3, activation='relu', border_mode='same'))
    modelnn.add(MaxPooling2D(pool_size=(2, 2)))
    modelnn.add(Dropout(0.2))
    modelnn.add(Convolution2D(128, 3, 3, activation='relu', border_mode='same'))
    modelnn.add(Convolution2D(128, 3, 3, activation='relu', border_mode='same'))
    modelnn.add(MaxPooling2D(pool_size=(2, 2)))
    modelnn.add(Dropout(0.2))
    #modelnn.add(Convolution2D(256, 3, 3, activation='relu', border_mode='same'))
    #modelnn.add(Convolution2D(256, 3, 3, activation='relu', border_mode='same'))
    #modelnn.add(MaxPooling2D(pool_size=(2, 2)))
    modelnn.add(Flatten())
    #modelnn.add(Dropout(0.5))
    modelnn.add(Dense(1024, activation='relu', W_constraint=maxnorm(3)))
    modelnn.add(Dropout(0.5))
    modelnn.add(Dense(512, activation='relu', W_constraint=maxnorm(3)))
    modelnn.add(Dropout(0.5))
    modelnn.add(Dense(10, activation='softmax'))
    modelnn.compile(loss='categorical_crossentropy', optimizer=optimizer_input, metrics=['accuracy'])
    y_train = to_categorical(y_train)
    modelnn.fit(x_train_reduced, y_train, nb_epoch=nb_epoch_count, shuffle=True, batch_size=bsize,
                           validation_split=0.1)

Résultats:

    44100/44100 [==============================] - 22s - loss: 2.1453 - acc: 0.2010 - val_loss: 1.9812 - val_acc: 0.2959
    Epoch 2/50
    44100/44100 [==============================] - 24s - loss: 1.9486 - acc: 0.3089 - val_loss: 1.8685 - val_acc: 0.3567
    Epoch 3/50
    44100/44100 [==============================] - 18s - loss: 1.8599 - acc: 0.3575 - val_loss: 1.7822 - val_acc: 0.3982
    Epoch 4/50
    44100/44100 [==============================] - 18s - loss: 1.7925 - acc: 0.3933 - val_loss: 1.7272 - val_acc: 0.4229
    Epoch 5/50
    44100/44100 [==============================] - 18s - loss: 1.7425 - acc: 0.4195 - val_loss: 1.6806 - val_acc: 0.4459
    Epoch 6/50
    44100/44100 [==============================] - 18s - loss: 1.6998 - acc: 0.4440 - val_loss: 1.6436 - val_acc: 0.4682
    Epoch 7/50
    44100/44100 [==============================] - 18s - loss: 1.6636 - acc: 0.4603 - val_loss: 1.6156 - val_acc: 0.4837
    Epoch 8/50
    44100/44100 [==============================] - 18s - loss: 1.6333 - acc: 0.4781 - val_loss: 1.6351 - val_acc: 0.4776
    Epoch 9/50
    44100/44100 [==============================] - 18s - loss: 1.6086 - acc: 0.4898 - val_loss: 1.5732 - val_acc: 0.5063
    Epoch 10/50
    44100/44100 [==============================] - 18s - loss: 1.5776 - acc: 0.5065 - val_loss: 1.5411 - val_acc: 0.5227
    Epoch 11/50
    44100/44100 [==============================] - 18s - loss: 1.5585 - acc: 0.5145 - val_loss: 1.5485 - val_acc: 0.5212
    Epoch 12/50
    44100/44100 [==============================] - 18s - loss: 1.5321 - acc: 0.5288 - val_loss: 1.5354 - val_acc: 0.5316
    Epoch 13/50
    44100/44100 [==============================] - 18s - loss: 1.5082 - acc: 0.5402 - val_loss: 1.5022 - val_acc: 0.5427
    Epoch 14/50
    44100/44100 [==============================] - 18s - loss: 1.4945 - acc: 0.5438 - val_loss: 1.4916 - val_acc: 0.5490
    Epoch 15/50
    44100/44100 [==============================] - 192s - loss: 1.4762 - acc: 0.5535 - val_loss: 1.5159 - val_acc: 0.5394
    Epoch 16/50
    44100/44100 [==============================] - 18s - loss: 1.4577 - acc: 0.5620 - val_loss: 1.5389 - val_acc: 0.5257
    Epoch 17/50
    44100/44100 [==============================] - 18s - loss: 1.4425 - acc: 0.5671 - val_loss: 1.4590 - val_acc: 0.5667
    Epoch 18/50
    44100/44100 [==============================] - 18s - loss: 1.4258 - acc: 0.5766 - val_loss: 1.4552 - val_acc: 0.5763
    Epoch 19/50
    44100/44100 [==============================] - 18s - loss: 1.4113 - acc: 0.5805 - val_loss: 1.4439 - val_acc: 0.5767
    Epoch 20/50
    44100/44100 [==============================] - 18s - loss: 1.3971 - acc: 0.5879 - val_loss: 1.4473 - val_acc: 0.5769
    Epoch 21/50
    44100/44100 [==============================] - 18s - loss: 1.3850 - acc: 0.5919 - val_loss: 1.4251 - val_acc: 0.5871
    Epoch 22/50
    44100/44100 [==============================] - 18s - loss: 1.3668 - acc: 0.6006 - val_loss: 1.4203 - val_acc: 0.5910
    Epoch 23/50
    44100/44100 [==============================] - 18s - loss: 1.3549 - acc: 0.6051 - val_loss: 1.4207 - val_acc: 0.5939
    Epoch 24/50
    44100/44100 [==============================] - 18s - loss: 1.3373 - acc: 0.6111 - val_loss: 1.4516 - val_acc: 0.5784
    Epoch 25/50
    44100/44100 [==============================] - 18s - loss: 1.3285 - acc: 0.6149 - val_loss: 1.4146 - val_acc: 0.5922
    Epoch 26/50
    44100/44100 [==============================] - 18s - loss: 1.3134 - acc: 0.6205 - val_loss: 1.4090 - val_acc: 0.6024
    Epoch 27/50
    44100/44100 [==============================] - 18s - loss: 1.3043 - acc: 0.6239 - val_loss: 1.4307 - val_acc: 0.5959
    Epoch 28/50
    44100/44100 [==============================] - 18s - loss: 1.2862 - acc: 0.6297 - val_loss: 1.4241 - val_acc: 0.5978
    Epoch 29/50
    44100/44100 [==============================] - 18s - loss: 1.2706 - acc: 0.6340 - val_loss: 1.4046 - val_acc: 0.6067
    Epoch 30/50
    44100/44100 [==============================] - 18s - loss: 1.2634 - acc: 0.6405 - val_loss: 1.4120 - val_acc: 0.6037
    Epoch 31/50
    44100/44100 [==============================] - 18s - loss: 1.2473 - acc: 0.6446 - val_loss: 1.4067 - val_acc: 0.6045
    Epoch 32/50
    44100/44100 [==============================] - 18s - loss: 1.2411 - acc: 0.6471 - val_loss: 1.4083 - val_acc: 0.6098
    Epoch 33/50
    44100/44100 [==============================] - 18s - loss: 1.2241 - acc: 0.6498 - val_loss: 1.4091 - val_acc: 0.6076
    Epoch 34/50
    44100/44100 [==============================] - 18s - loss: 1.2121 - acc: 0.6541 - val_loss: 1.4209 - val_acc: 0.6127
    Epoch 35/50
    44100/44100 [==============================] - 18s - loss: 1.1995 - acc: 0.6582 - val_loss: 1.4230 - val_acc: 0.6131
    Epoch 36/50
    44100/44100 [==============================] - 18s - loss: 1.1884 - acc: 0.6622 - val_loss: 1.4024 - val_acc: 0.6124
    Epoch 37/50
    44100/44100 [==============================] - 18s - loss: 1.1778 - acc: 0.6657 - val_loss: 1.4328 - val_acc: 0.6080
    Epoch 38/50
    44100/44100 [==============================] - 18s - loss: 1.1612 - acc: 0.6683 - val_loss: 1.4246 - val_acc: 0.6159
    Epoch 39/50
    44100/44100 [==============================] - 18s - loss: 1.1466 - acc: 0.6735 - val_loss: 1.4282 - val_acc: 0.6122
    Epoch 40/50
    44100/44100 [==============================] - 18s - loss: 1.1325 - acc: 0.6783 - val_loss: 1.4311 - val_acc: 0.6157
    Epoch 41/50
    44100/44100 [==============================] - 18s - loss: 1.1213 - acc: 0.6806 - val_loss: 1.4647 - val_acc: 0.6047
    Epoch 42/50
    44100/44100 [==============================] - 18s - loss: 1.1064 - acc: 0.6842 - val_loss: 1.4631 - val_acc: 0.6047
    Epoch 43/50
    44100/44100 [==============================] - 18s - loss: 1.0967 - acc: 0.6870 - val_loss: 1.4535 - val_acc: 0.6106
    Epoch 44/50
    44100/44100 [==============================] - 18s - loss: 1.0822 - acc: 0.6893 - val_loss: 1.4532 - val_acc: 0.6149
    Epoch 45/50
    44100/44100 [==============================] - 18s - loss: 1.0659 - acc: 0.6941 - val_loss: 1.4691 - val_acc: 0.6108
    Epoch 46/50
    44100/44100 [==============================] - 18s - loss: 1.0610 - acc: 0.6956 - val_loss: 1.4751 - val_acc: 0.6106
    Epoch 47/50
    44100/44100 [==============================] - 18s - loss: 1.0397 - acc: 0.6981 - val_loss: 1.4857 - val_acc: 0.6041
    Epoch 48/50
    44100/44100 [==============================] - 18s - loss: 1.0208 - acc: 0.7039 - val_loss: 1.4901 - val_acc: 0.6106
    Epoch 49/50
    44100/44100 [==============================] - 18s - loss: 1.0187 - acc: 0.7036 - val_loss: 1.4994 - val_acc: 0.6106
    Epoch 50/50
    44100/44100 [==============================] - 18s - loss: 1.0024 - acc: 0.7070 - val_loss: 1.5078 - val_acc: 0.6039
    Time: 1109.7512991428375
    Neural Network now trained from dimensions (49000, 3, 32, 32)

Mise à jour: tests supplémentaires, y compris BatchNormalization avec et sans MaxNorm -

img

Nouvelle architecture:

    modelnn.add(Convolution2D(32, 3, 3, input_shape=neurons, activation='relu', border_mode='same'))
    modelnn.add(Convolution2D(32, 3, 3, activation='relu', border_mode='same'))
    modelnn.add(MaxPooling2D(pool_size=(2, 2)))
    modelnn.add(BatchNormalization())
    modelnn.add(Dropout(0.2))
    modelnn.add(Convolution2D(64, 3, 3, activation='relu', border_mode='same'))
    modelnn.add(Convolution2D(64, 3, 3, activation='relu', border_mode='same'))
    modelnn.add(MaxPooling2D(pool_size=(2, 2)))
    modelnn.add(BatchNormalization())
    modelnn.add(Dropout(0.2))
    modelnn.add(Convolution2D(128, 3, 3, activation='relu', border_mode='same'))
    modelnn.add(Convolution2D(128, 3, 3, activation='relu', border_mode='same'))
    modelnn.add(BatchNormalization())
    modelnn.add(MaxPooling2D(pool_size=(2, 2)))
    modelnn.add(Dropout(0.2))
    # modelnn.add(Convolution2D(256, 3, 3, activation='relu', border_mode='same'))
    # modelnn.add(Convolution2D(256, 3, 3, activation='relu', border_mode='same'))
    # modelnn.add(MaxPooling2D(pool_size=(2, 2)))
    modelnn.add(Flatten())
    modelnn.add(Dense(1024, activation='relu', W_constraint=maxnorm(3)))
    modelnn.add(BatchNormalization())
    modelnn.add(Dropout(0.5))
    modelnn.add(Dense(512, activation='relu', W_constraint=maxnorm(3)))
    modelnn.add(BatchNormalization())
    modelnn.add(Dropout(0.5))
    modelnn.add(Dense(10, activation='softmax'))
user4779
la source

Réponses:

8

Notez que MNIST est un ensemble de problèmes beaucoup plus simple que CIFAR-10, et vous pouvez obtenir 98% d'un réseau NNet entièrement connecté (non convolutionnel) avec très peu de difficulté. Un CNN très simple avec seulement une ou deux couches convolutionnelles peut également atteindre le même niveau de précision.

Je ne suis pas sûr de votre architecture NNet, mais je peux vous amener à une précision de test de 78% sur CIFAR-10 avec l'architecture suivante (qui est relativement plus simple et a moins de poids). Aucune initialisation ou prise en main spéciale n'était requise, en utilisant les valeurs par défaut vanilla et l'optimiseur Adam:

model = Sequential()
model.add(Conv2D(input_shape=trainX[0,:,:,:].shape, filters=96, kernel_size=(3,3)))
model.add(Activation('relu'))
model.add(Conv2D(filters=96, kernel_size=(3,3), strides=2))
model.add(Activation('relu'))
model.add(Dropout(0.2))
model.add(Conv2D(filters=192, kernel_size=(3,3)))
model.add(Activation('relu'))
model.add(Conv2D(filters=192, kernel_size=(3,3), strides=2))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Flatten())
model.add(BatchNormalization())
model.add(Dense(256))
model.add(Activation('relu'))
model.add(Dense(n_classes, activation="softmax"))
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

Cette architecture est assez simple et est vaguement basée sur https://arxiv.org/pdf/1412.6806.pdf .

Former ainsi ce modèle:

n_epochs = 25
batch_size = 256
callbacks_list = None
H = model.fit(trainX, trainY, validation_data=(testX, testY), 
              epochs=n_epochs, batch_size=batch_size, callbacks=callbacks_list)
print('Done!!!')

Donne ce qui suit, que vous pouvez voir atteindre près de 77% à la 25e époque et s'aplatir plus ou moins à partir de là (mais a suffisamment de régularisation du décrochage pour l'empêcher de se dégrader en raison d'un sur-ajustement, au moins sur le nombre d'itérations testé) .

Former sur 50000 échantillons, valider sur 10000 échantillons
Epoque 1/50
50000/50000 [===============================] - 19s 390us / pas - perte: 1,6058 - acc: 0,4150 - val_loss: 1,5285 - val_acc: 0,4669
Époque 2/50
50000/50000 [======================== =======] - 19s 371us / step - perte: 1.2563 - acc: 0.5477 - val_loss: 1.1447 - val_acc: 0.5901
Epoch 3/50
50000/50000 [============== =================] - 19s 373us / step - perte: 1.0784 - acc: 0.6163 - val_loss: 1.1577 - val_acc: 0.6002
...
Epoch 25/50
50000/50000 [ ==============================] - 19s 374us / step - perte: 0,3188 - acc: 0,88857 - val_loss: 0,7493 - val_acc : 0,7680
...
Epoque 50/50
50000/50000 [==============================] - 19s 373us / step - perte: 0,1928 - acc: 0,9329 - val_loss : 0,8718 - val_acc: 0,7751
Terminé !!!

Voici une architecture encore plus simple et beaucoup plus petite qui peut atteindre 70% assez rapidement avec le même régime d'entraînement (pas de couches BatchNormalization ou pooling):

# CNN architecture with Keras
model = Sequential()
model.add(Conv2D(input_shape=trainX[0,:,:,:].shape, filters=32, 
                 use_bias=True, kernel_size=(3,3)))
model.add(Activation('relu'))
model.add(Dropout(0.1))
model.add(Conv2D(filters=64, use_bias=False, kernel_size=(5,5), strides=2))
model.add(Activation('relu'))
model.add(Dropout(0.2))
model.add(Flatten())
model.add(Dense(128))
model.add(Activation('relu'))
model.add(Dropout(0.3))
model.add(Dense(n_classes, activation="softmax"))
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=    ['accuracy'])

Il convient de noter que les architectures qui atteignent la précision la mieux publiée sur CIFAR-10 (actuellement dans la plage de 90 à 96%) sont généralement plus compliquées et prennent de nombreuses heures à s'entraîner sur du matériel GPU. Mais j'ai pu atteindre la fourchette 70-80% avec des architectures assez simples qui s'entraînent en quelques minutes, ce que je recommanderais avant d'aller chercher les meilleurs résultats publiés qui nécessitent généralement des architectures plus compliquées, des périodes de formation plus longues, parfois régimes de prise en main / formation spéciaux ou augmentation des données, et heures de train.

MISE À JOUR:

Sur la base des graphiques mis à jour dans la question, le problème le plus évident qui est démontré est le sur-ajustement. Ceci est mis en évidence par la divergence des données de train-test après environ la 15e époque qui démontre une régularisation insuffisante pour cette architecture, pour cet ensemble de données. Il est peu probable que vous amélioriez le réglage d'autres hyperparamètres (stratégies de normalisation, taux d'apprentissage, etc.) à moins que le sur-ajustement ne soit résolu.

En utilisant NNets, je recommande ce qui suit:

  1. Partir d'architectures qui imitent ou reproduisent celles connues pour produire de bons résultats
  2. Vérifiez les performances de votre ensemble de données, avec un œil particulier sur le sur-ajustement dans le réseau (mis en évidence par une divergence importante d'erreurs de test de train)
  3. Ajoutez une régularisation supplémentaire (augmentez les taux d'abandon) en cas de sur-ajustement (vous recherchez «juste assez» pour éviter le sur-ajustement - trop entraînera un sous-ajustement)
  4. Expérimentez avec la structure, les approches de formation et les hyper-paramètres pour trouver des pistes d'amélioration

Les prescriptions concernant ces derniers sont en fait assez difficiles à trouver, car il existe peu de bases théoriques sur la façon dont la structure, la formation ou les hyper-paramètres interagissent pour produire des performances sur un ensemble de données donné. Le fait que les approches employées par les architectures publiées atteignant des niveaux de performances similaires sur des ensembles de données de référence varient si fortement en est la preuve.

Il a été constaté que la normalisation par lots améliore considérablement certaines architectures, mais d'autres peuvent très bien s'en passer (ou sont indifférentes à sa présence). Le seul véritable conseil à fournir ici est de l'essayer et de voir si cela aide.

Les taux d'apprentissage de réglage fin doivent généralement être évités à moins que vous ne soyez un praticien avancé ayant une compréhension approfondie des ConvNets et la capacité correspondante de lire les feuilles de thé en ce qui concerne les performances incrémentielles inter-époques pendant la formation. Des taux d'apprentissage personnalisés et d'autres régimes de formation spécialisés peuvent dans certains cas aider les réseaux à naviguer autour des minima locaux et à trouver de meilleures solutions globales, mais à moins que vous ayez beaucoup de temps et le savoir-faire pour diagnostiquer le comportement de convergence du réseau, ce n'est pas le cas. un bon point de départ. La plupart d'entre nous devraient utiliser un optimiseur comme Adam qui surpassera les tentatives des novices en matière de taux d'apprentissage ajustés à la main dans la grande majorité des cas.

L'augmentation des données via le prétraitement des images peut parfois entraîner des améliorations significatives des performances (en général, plus les données d'entrée sont variées, mieux le modèle généralisera - le prétraitement des données ajoute des variations à l'espace d'entrée, ce qui peut améliorer la précision hors échantillon et peutpermettre une réduction des exigences de régularisation - hypothétiquement, avec des données d'entraînement infinies, nous n'aurions pas besoin de régularisation du tout, mais dans l'espace de traitement d'image, nous sommes peu susceptibles d'approcher cette asymptote). Cela peut cependant augmenter considérablement le temps de formation et les taux de convergence lents, et introduit un tout autre ensemble d'hyperparamètres liés aux techniques de permutation d'images d'entrée (rotation, recadrage, mise à l'échelle, bruit, etc., etc.). Étant donné que ce chemin peut augmenter les temps de formation et nécessiter des expériences supplémentaires pour ajuster les résultats, certains conseils généraux seraient de rechercher la meilleure précision dans votre réseau sans augmentation préalable, puis de voir si une augmentation modeste donne une amélioration. Si tel est le cas, cela peut justifier une expérimentation supplémentaire.

Pour toutes les expériences de réglage, vous devrez garder un œil sur les changements de comportement sur et sous-ajustés. La modification de l'architecture du réseau, des régimes d'entraînement ou des hyperparamètres peut nécessiter un réglage supplémentaire de la régularisation de l'abandon. La capacité de déterminer facilement un comportement sur et sous-ajusté à partir des performances du train / test est sans doute la compétence de base la plus importante dans le travail avec NNets, et cela devient plus intuitif avec l'expérience.

C'est la bougie qui guidera tous vos efforts. La bougie ne peut que faiblement éclairer le chemin, mais sans elle, vous trébucherez dans le noir. Si votre réseau est mal sur ou sous-ajusté, cela doit être résolu avant de tenter des permutations aléatoires de la structure du réseau ou des hyperparamètres.

Les architectures relativement simples avec des schémas de formation à la vanille inclus dans cette réponse démontrent une réalité de travailler avec des architectures NNET sur des problèmes difficiles comme la classification d'image: atteindre un résultat "assez bon" basé sur des approches qui fonctionnent bien n'est pas difficile, mais une amélioration progressive est de plus en plus coûteux. L'obtention des meilleurs résultats publiés par l'expérimentation dépassera les capacités ou la disponibilité de temps de beaucoup (bien qu'il soit possible, avec suffisamment de temps et d'efforts, de suivre les recettes de livres de recettes d'approches publiées pour reproduire leurs résultats - mais même cela n'est en aucun cas signifie trivial). L'obtention d'une amélioration incrémentielle à partir d'un «assez bon» point de départ peut être un processus très long d'essais et d'erreurs, et de nombreuses expériences ne produiront aucune amélioration significative.

Cela ne vise pas à dissuader quiconque d'essayer d'apprendre, mais seulement à préciser qu'un investissement important est nécessaire pour maîtriser le jeu d'outils (en constante expansion) dans le sac de trucs NNet, et la conduite d'améliorations par essais et erreurs peut nécessiter des dizaines (ou des centaines) d'expériences sur des jours ou des semaines de formation dédiée au GPU.

Le temps, les compétences et les ressources (GPU dédié) nécessaires pour former les réseaux à des niveaux de performance très élevés expliquent en partie la popularité des réseaux pré-formés.

T3am5hark
la source
1
Vous, les architectures de réseaux de neurones ne disposent pas de couches de mutualisation? cela ne crée-t-il pas un nombre ingérable de paramètres?
Spandyie
2
Mise en commun - pfft! Surévalué. Cela utilise une approche tout convolutionnelle qui utilise la foulée pour la décimation plutôt que la mise en commun - voir le document lié pour la description. La foulée convolutionnelle peut obtenir le même effet «d'entonnoir» que la mise en commun par des moyens légèrement différents. Le fait qu'ils fonctionnent tous les deux illustre simplement qu'il n'y a pas beaucoup de bases théoriques solides sur lesquelles s'appuyer pour expliquer pourquoi tout cela fonctionne.
T3am5hark
6

En regardant vos valeurs de perte et de précision dans l'échantillon et hors échantillon, votre modèle est actuellement sous-adapté, mais il s'améliore de façon monotone. En d'autres termes, il semble que l'exécution de cette fonction pour plus d'époques entraînerait une performance prédictive plus élevée / moins de perte d'entropie.

Vous utilisez une architecture hautement régularisée (couches de suppression), ce qui n'est pas mauvais. Cependant, il n'est pas non plus surprenant que la formation prenne beaucoup plus de temps que sans aucune régularisation. En raison des couches d'abandon, il est peu probable que vous vous équipiez (sensiblement).

Choses que vous pouvez essayer d'accélérer l'apprentissage:

je. ajustez le taux d'apprentissage: par exemple, commencez par un petit, montez-le au milieu, et vers la fin, abaissez-le à nouveau.

ii. ajouter la normalisation par lots : dans l'architecture ci-dessus, vous pouvez inclure la norme de lot à la fois dans vos blocs convolutionnels et vos couches denses. Habituellement, la couche batch-norm est ajoutée après l'activation non linéaire mais avant le décrochage. Je ne sais pas dans quelle mesure batch-standard joue avec maxnorm. Pour vos couches denses, j'essaierais la norme batch + dropuout avec / sans maxnorm. J'ai l'impression que vous n'avez pas besoin de maxnorm si vous appliquez la normalisation par lots.

iii. augmenter la taille du lot: je ne sais pas quelle est votre taille de lot et si vous possédez un GPU. Si vous avez un GPU, vous devriez probablement essayer de maximiser la taille de votre lot en multiplicatifs de 32.

Enfin, pour vous assurer que vos données sont «apprenables» / non corrompues (par exemple, vous n'avez pas appliqué à contrecœur une transformation pour la déformer), je supprimerais toute régularisation de votre architecture, exécuterais la formation et verrais que vous pouvez vous adapter à l'ensemble de formation . Si vous pouvez apprendre les données d'entraînement avec succès, le reste est un exercice de généralisation. Si vous ne pouvez pas vous adapter aux données d'entraînement même sans régularisation, votre modèle a probablement besoin de plus de capacité (architecture plus profonde et plus large).

Zhubarb
la source
Merci pour les conseils! Vous aviez raison sur le fait que MaxNorm interférait légèrement. Néanmoins, même après avoir ajouté les couches BatchNormalization (voir la mise à jour) et supprimé / inclus MaxNorm, la précision est toujours faible. Aucune augmentation n'a lieu non plus. J'ai un GPU et j'ai essayé de m'entraîner à 64 128 256 et 512 lots mais peu de différence est remarquée. En ce qui concerne le taux d'apprentissage, j'utilise l'optimiseur Adam et pensais que cela devrait plus ou moins être laissé seul? Néanmoins, j'ai essayé LR à 0,05, 0,001, 0,0005 et j'ai remarqué que la valeur par défaut de 0,001 semble toujours meilleure. Des idées?
user4779
De plus, je suis capable de sur-ajuster très bien. J'ai fait de mon mieux pour copier l'architecture dans les documents qui semblent pouvoir atteindre une précision de 80% ++ avec MNIST10. Lorsque je quitte le modèle de formation pour des époques plus longues, il semble que la perte augmente maintenant (plus de 20 époques environ).
user4779
Modification du commentaire - à la suite des changements apportés au modèle, les graphiques indiquent désormais qu'il suradapte considérablement les données (sur la base de la divergence de l'erreur de validation après ~ 15 époques)
T3am5hark
Je conteste en fait l'utilité des conseils proposés ici, en particulier pour les nouveaux praticiens. Ce sont toutes des choses que vous pouvez faire, bien sûr, mais pour les gens qui sont nouveaux dans les CNN et qui n'ont pas l'intuition ou la compréhension de la façon dont ces choses fonctionnent, c'est beaucoup trop de boutons et de leviers à modifier sans aucune directive prescriptive autre qu'un procès à l'aveugle et erreur, peu susceptible de donner des résultats positifs. Mieux serait de commencer par des architectures plus simples capables d'obtenir de bonnes performances (pas les mieux publiées) avec un minimum de twiddling, puis d'explorer des pistes d'amélioration à partir de là. Mes deux centimes.
T3am5hark
Pour élaborer davantage - ne jouez pas avec les taux d'apprentissage, utilisez Adam. Cela va battre le réglage manuel des taux d'apprentissage 99,99% du temps. En outre, l'affirmation selon laquelle il est "peu probable que vous surjamasserez jamais" est tout simplement fausse (comme l'indiquent les graphiques de suivi qui démontrent désormais un sur-ajustement significatif), et il n'y a aucune bonne raison pour que l'affiche présume que ... il n'y a rien à vous dire a priori pour une architecture donnée si un taux d'abandon donné se régularise suffisamment pour éviter un sur-ajustement.
T3am5hark
1

J'ai donné un coup de feu aujourd'hui et j'ai toujours été en mesure d'atteindre 75 à 80% de la précision du test.

Historique de formation

  • Le nombre total de paramètres utilisés était: 183,242

  • Vous pouvez faire mieux en ajoutant peut-être quelques couches supplémentaires, mais vous n'avez pas besoin d'être excessif. Des réseaux plus complexes ne donnent pas toujours de meilleurs résultats.

Suggestions

Je vous suggère de garder votre architecture simple. Suivez le rasoir d'Occam , simple c'est mieux.

  • Faites évoluer vos données

  • N'utilisez pas de graine aléatoire

  • Utilisez un optimiseur approprié; J'ai utilisé Adadelta tel quel de Keras.

  • Les CNN n'ont pas besoin d'être alambiqués; rester simple

  • Les réseaux plus maigres plus profonds fonctionnent parfois mieux que les réseaux plus larges

  • Utilisez la régularisation (par exemple Dropout)

Voici mon code (en utilisant Keras)

# Define the model
model = Sequential()
model.add(Convolution2D(64, (4, 4), padding='same', input_shape=(3, 32, 32)))
model.add(MaxPooling2D(pool_size=(2, 2), strides=2))
model.add(Activation('relu'))
model.add(Dropout(0.25))
model.add(Convolution2D(64, (2, 2), padding='same'))
model.add(Activation('relu'))
model.add(Dropout(0.25))
model.add(Convolution2D(32, (3, 3), padding='same'))
model.add(Activation('relu'))
model.add(Dropout(0.25))
model.add(Convolution2D(32, (3, 3), padding='same'))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2), strides=2))
model.add(Dropout(0.15))
model.add(Flatten())
model.add(Dense(64))
model.add(Activation('relu'))
model.add(Dropout(0.25))
model.add(Dense(64))
model.add(Activation('tanh'))
model.add(Dropout(0.25))
model.add(Dense(num_classes, activation='softmax'))
# Compile the model
Jon
la source