1
votes

Le modèle Keras (même pendant l'entraînement) ne prédit que 0

J'essaie de former un classificateur d'images keras pour prédire entre les mauvaises herbes (1) et les herbes (0) dans les images. Cependant, quelle que soit la méthode / le modèle que j'essaie de créer, la précision reste bloquée, et par là, je veux dire que la précision d'entraînement est comme si elle ne prédit que des 0. Je peux le confirmer, car lorsque j'ai changé mon tableau d'étiquettes pour ne contenir que des zéros, le modèle réclamait en quelque sorte une précision de 1,00, mais lorsque j'ai changé les étiquettes en un, la précision du modèle était de 0,00. Toutes mes images sont redimensionnées et converties en RVB. voici le code:

model = Sequential()
model.add(Conv2D(32, kernel_size=3, input_shape=(530, 400, 1)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.2))
model.add(Conv2D(32, kernel_size=3))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.5))
model.add(Conv2D(64, kernel_size=3))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten())
model.add(Dense(64))
model.add(Activation('relu'))
#model.add(Dropout(0.5))
model.add(Dense(2)) #or n_clasess
model.add(Activation('softmax'))

model.compile(optimizer=Adam(0.0001), loss='categorical_crossentropy', metrics=['accuracy'])

J'applique ensuite to_categorical (étiquettes) pour les encoder à chaud model:

def prep_image(filename):
  im = cv2.imread(filename, 0)
  new_im = cv2.resize(im, (400,530))
  arr = np.array(new_im)
  arr = np.reshape(arr, (530, 400))
  return arr

image_files = [] #contains the file paths of the images
images = [] # contains arrays/images
labels = []
n_classes = 2
def add_image_data(root):
  global images
  global labels
  print("starting")
  delim = os.sep

  for dirpath, dirs, files in tqdm(os.walk(root)): 
    for file in [f for f in files if (f.endswith(".jpg"))]:
      image_files.append(os.path.join(dirpath, file))

  for file in tqdm(image_files):
    image_arr = prep_image(file)
    images.append(image_arr)
    #print("supposed added ", file)
    label = file.split(delim)[-2]
    if label == "Grass":
      label = 0;
    else:
      label = 1;
    labels.append(label)

  images = np.array(images)
  labels = np.array(labels)

il ne semble pas non plus y avoir d'apprentissage en cours, la perte et la précision semblent rester bloquées après la première époque. les étiquettes contiennent les deux classes. Merci d'avance


5 commentaires

Puisque vous n'avez que 2 classes, vous devez utiliser loss = 'binary_crossentropy' ; Je suggérerais également de laisser votre dernière couche dense avec seulement 1 unité et l'activation sigmoïde (est-ce que vous encodez actuellement vos étiquettes à chaud?)


@desertnaut J'ai essayé cela aussi, mais même résultat, j'ai basculé entre les deux modèles et les deux donnent les mêmes sorties. J'ai également essayé la crossentropie binaire avec 1 unité et sigmoïde, mais cela n'a pas non plus fonctionné


De tels détails sont toujours utiles à inclure dans la question ...


Incluez également ce que vous appelez pour entraîner le modèle. Je suppose que model.fit mais je l'inclus pour être complet. De plus, par "toutes mes images sont mises à l'échelle", voulez-vous dire redimensionnées? Faites-vous une normalisation que nous ne voyons pas? Une certaine visualisation des données serait utile. Et, pour référence future, vous n'avez pas besoin de convertir une image en tableau puisque cv2 utilisera NumPy comme représentation des images.


@LukeDeLuccia J'ai supposé que l'échelle de gris était une normalisation automatique, mais j'ai résolu le problème maintenant, en normalisant manuellement. Merci


3 Réponses :


0
votes

Votre ensemble de données est-il déséquilibré? C'est un problème courant lorsque vous avez un jeu de données fortement déséquilibré. Cela signifie qu'une ou plusieurs des classes et bien plus fréquentes que les autres. Votre modèle a découvert que le moyen le plus simple d'obtenir une précision considérable est de deviner la classe la plus fréquente. Cela peut rendre l'optimisation de l'apprentissage beaucoup plus difficile.

Il existe plusieurs façons de gérer les ensembles de données non équilibrés que vous pouvez essayer: https://machinelearningmastery.com/tactics-to-combat-imbalanced-classes-in-your-machine-learning-dataset/


1 commentaires

70-30% seraient-ils considérés comme très déséquilibrés?, et comme je l'ai mentionné, même lorsque j'ai fait de mes étiquettes tous les zéros ou tous les uns, cela rendait l'acc 0 ou 1, donc je pense que le problème pourrait être autre chose



1
votes

avez-vous regardé vos scores de pronostics? Si la métrique de précision est basée sur un score de prédiction> 0,5, il se peut qu'aucune de vos classes n'obtienne un score supérieur à 0,5. Cela est probablement dû au déséquilibre des classes. Vous pouvez ensuite modifier le seuil d'une prédiction "positive".

Essayez plutôt d'utiliser une métrique telle que l'AUC, ou imprimez simplement vos prédictions et examinez les scores.

Modifier à partir des commentaires: Avez-vous prétraité correctement vos entrées? Normalisation, etc. Si vos valeurs d'entrée sont trop grandes, les dégradés ne couleront pas correctement.

Le manque de normalisation arrêtera le flux de gradient. Cela est dû au fait que vous n'utiliserez pas la non-linéarité dans les fonctions d'activation si vos valeurs sont trop grandes / petites pour toutes les entrées.


2 commentaires

Avez-vous prétraité correctement vos entrées? Normalisation, etc. Si vos valeurs d'entrée sont trop grandes, les dégradés ne couleront pas correctement.


Cela fonctionne, j'ai simplement supposé parce que c'était en niveaux de gris qu'il était normalisé, mais ce n'était pas le cas, maintenant c'est une formation, merci!



0
votes

Je pense que le problème peut être que vous comparez une étiquette (0 ou 1) avec le résultat de softmax qui est deux valeurs représentant la probabilité que le sujet soit pour cette classe.

Vous devriez effectuer une conversion d'encodage à chaud comme ceci: 0 -> [1, 0] 1 -> [0, 1]

De cette façon, la sortie du réseau neuronal et les étiquettes sont dans le même format et peuvent être comparées.


1 commentaires

mon mauvais, j'ai oublié d'ajouter le code pour cela, mais j'utilise to_categorical pour encoder à chaud mes étiquettes