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
É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?
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)