web-dev-qa-db-fra.com

ResNet: précision de 100% pendant l'entraînement, mais précision de prédiction de 33% avec les mêmes données

Je suis nouveau dans l'apprentissage automatique et l'apprentissage en profondeur, et à des fins d'apprentissage, j'ai essayé de jouer avec Resnet. J'ai essayé de surcharger les petites données (3 différentes images) et de voir si je pouvais obtenir près de 0 perte et une précision de 1,0 - et je l'ai fait.

Le problème est que les prédictions sur les images d'entraînement (c'est-à-dire les mêmes 3 images utilisées pour l'entraînement) ne sont pas correctes.

Images d'entraînement

image 1image 2image 3

Étiquettes d'image

[1,0,0], [0,1,0], [0,0,1]

Mon python

#loading 3 images and resizing them
imgs = np.array([np.array(Image.open("./Images/train/" + fname)
                          .resize((197, 197), Image.ANTIALIAS)) for fname in
                 os.listdir("./Images/train/")]).reshape(-1,197,197,1)
# creating labels
y = np.array([[1,0,0],[0,1,0],[0,0,1]])
# create resnet model
model = ResNet50(input_shape=(197, 197,1),classes=3,weights=None)

# compile & fit model
model.compile(loss='categorical_crossentropy', optimizer='adam',metrics=['acc'])

model.fit(imgs,y,epochs=5,shuffle=True)

# predict on training data
print(model.predict(imgs))

Le modèle surpasse les données:

3/3 [==============================] - 22s - loss: 1.3229 - acc: 0.0000e+00
Epoch 2/5
3/3 [==============================] - 0s - loss: 0.1474 - acc: 1.0000
Epoch 3/5
3/3 [==============================] - 0s - loss: 0.0057 - acc: 1.0000
Epoch 4/5
3/3 [==============================] - 0s - loss: 0.0107 - acc: 1.0000
Epoch 5/5
3/3 [==============================] - 0s - loss: 1.3815e-04 - acc: 1.0000

mais les prédictions sont:

 [[  1.05677405e-08   9.99999642e-01   3.95520459e-07]
 [  1.11955103e-08   9.99999642e-01   4.14905685e-07]
 [  1.02637095e-07   9.99997497e-01   2.43751242e-06]]

ce qui signifie que toutes les images ont obtenu label=[0,1,0]

pourquoi? et comment cela peut-il arriver?

25
Dvir Samuel

C'est à cause des couches de normalisation par lots.

En phase de formation, le lot est normalisé w.r.t. sa moyenne et sa variance. Cependant, en phase de test, le lot est normalisé w.r.t. moyenne mobile de la moyenne et de la variance observées précédemment.

C'est maintenant un problème lorsque le nombre de lots observés est petit (par exemple, 5 dans votre exemple) car dans la couche BatchNormalization, par défaut moving_mean Est initialisé à 0 et moving_variance est initialisé à 1.

Étant donné également que la valeur par défaut momentum est 0,99, vous devrez mettre à jour les moyennes mobiles plusieurs fois avant qu'elles ne convergent vers la moyenne et la variance "réelles".

C'est pourquoi la prédiction est erronée au début, mais elle est correcte après 1000 époques.


Vous pouvez le vérifier en forçant les couches BatchNormalization à fonctionner en "mode de formation".

Pendant l'entraînement, la précision est de 1 et la perte est proche de zéro:

model.fit(imgs,y,epochs=5,shuffle=True)
Epoch 1/5
3/3 [==============================] - 19s 6s/step - loss: 1.4624 - acc: 0.3333
Epoch 2/5
3/3 [==============================] - 0s 63ms/step - loss: 0.6051 - acc: 0.6667
Epoch 3/5
3/3 [==============================] - 0s 57ms/step - loss: 0.2168 - acc: 1.0000
Epoch 4/5
3/3 [==============================] - 0s 56ms/step - loss: 1.1921e-07 - acc: 1.0000
Epoch 5/5
3/3 [==============================] - 0s 53ms/step - loss: 1.1921e-07 - acc: 1.0000

Maintenant, si nous évaluons le modèle, nous observerons une perte élevée et une faible précision car après 5 mises à jour, les moyennes mobiles sont encore assez proches des valeurs initiales:

model.evaluate(imgs,y)
3/3 [==============================] - 3s 890ms/step
[10.745396614074707, 0.3333333432674408]

Cependant, si nous spécifions manuellement la variable "phase d'apprentissage" et laissons les couches BatchNormalization utiliser la moyenne et la variance "réelles" du lot, le résultat devient le même que celui observé dans fit().

sample_weights = np.ones(3)
learning_phase = 1  # 1 means "training"
ins = [imgs, y, sample_weights, learning_phase]
model.test_function(ins)
[1.192093e-07, 1.0]

Il est également possible de le vérifier en changeant l'élan sur une valeur plus petite.

Par exemple, en ajoutant momentum=0.01 À toutes les couches de normes de lot dans ResNet50, La prédiction après 20 époques est la suivante:

model.predict(imgs)
array([[  1.00000000e+00,   1.34882026e-08,   3.92139575e-22],
       [  0.00000000e+00,   1.00000000e+00,   0.00000000e+00],
       [  8.70998792e-06,   5.31159838e-10,   9.99991298e-01]], dtype=float32)
16
Yu-Yang