J'essaie d'implémenter un réseau de neurones qui classe les images dans l'une des deux catégories distinctes. Le problème, cependant, est qu’il prédit toujours 0 pour chaque entrée et je ne sais pas trop pourquoi.
Voici ma méthode d'extraction de fonctionnalités:
def extract(file):
# Resize and subtract mean pixel
img = cv2.resize(cv2.imread(file), (224, 224)).astype(np.float32)
img[:, :, 0] -= 103.939
img[:, :, 1] -= 116.779
img[:, :, 2] -= 123.68
# Normalize features
img = (img.flatten() - np.mean(img)) / np.std(img)
return np.array([img])
Voici ma routine de descente de gradient:
def fit(x, y, t1, t2):
"""Training routine"""
ils = x.shape[1] if len(x.shape) > 1 else 1
labels = len(set(y))
if t1 is None or t2 is None:
t1 = randweights(ils, 10)
t2 = randweights(10, labels)
params = np.concatenate([t1.reshape(-1), t2.reshape(-1)])
res = grad(params, ils, 10, labels, x, y)
params -= 0.1 * res
return unpack(params, ils, 10, labels)
Voici mes propagations avant et arrière (dégradé):
def forward(x, theta1, theta2):
"""Forward propagation"""
m = x.shape[0]
# Forward prop
a1 = np.vstack((np.ones([1, m]), x.T))
z2 = np.dot(theta1, a1)
a2 = np.vstack((np.ones([1, m]), sigmoid(z2)))
a3 = sigmoid(np.dot(theta2, a2))
return (a1, a2, a3, z2, m)
def grad(params, ils, hls, labels, x, Y, lmbda=0.01):
"""Compute gradient for hypothesis Theta"""
theta1, theta2 = unpack(params, ils, hls, labels)
a1, a2, a3, z2, m = forward(x, theta1, theta2)
d3 = a3 - Y.T
print('Current error: {}'.format(np.mean(np.abs(d3))))
d2 = np.dot(theta2.T, d3) * (np.vstack([np.ones([1, m]), sigmoid_prime(z2)]))
d3 = d3.T
d2 = d2[1:, :].T
t1_grad = np.dot(d2.T, a1.T)
t2_grad = np.dot(d3.T, a2.T)
theta1[0] = np.zeros([1, theta1.shape[1]])
theta2[0] = np.zeros([1, theta2.shape[1]])
t1_grad = t1_grad + (lmbda / m) * theta1
t2_grad = t2_grad + (lmbda / m) * theta2
return np.concatenate([t1_grad.reshape(-1), t2_grad.reshape(-1)])
Et voici ma fonction de prédiction:
def predict(theta1, theta2, x):
"""Predict output using learned weights"""
m = x.shape[0]
h1 = sigmoid(np.hstack((np.ones([m, 1]), x)).dot(theta1.T))
h2 = sigmoid(np.hstack((np.ones([m, 1]), h1)).dot(theta2.T))
return h2.argmax(axis=1)
Je peux voir que le taux d'erreur diminue progressivement à chaque itération, convergeant généralement autour de 1,26e-05.
Ce que j'ai essayé jusqu'à présent:
Edit : Une sortie moyenne de h2 se présente comme suit:
[0.5004899 0.45264441]
[0.50048522 0.47439413]
[0.50049019 0.46557124]
[0.50049261 0.45297816]
Donc, des sorties sigmoïdes très similaires pour tous les exemples de validation.
Après une semaine et demie de recherche, je pense comprendre le problème. Il n'y a rien de mal avec le code lui-même. Les deux seuls problèmes qui empêchent ma mise en œuvre de classer avec succès sont le temps passé à apprendre et le choix approprié des paramètres de cadence d'apprentissage/de régularisation.
La routine d'apprentissage est en cours depuis un certain temps déjà, et elle pousse déjà à 75% de précision, bien qu'il y ait encore beaucoup de place pour l'amélioration.
Mon réseau prédit toujours la même classe. Quel est le problème?
J'ai eu cela plusieurs fois. Bien que je sois actuellement trop paresseux pour consulter votre code, je pense pouvoir vous donner quelques conseils généraux qui pourraient également aider d'autres personnes ayant le même symptôme, mais probablement différents problèmes sous-jacents.
Pour chaque classe i que le réseau devrait pouvoir prévoir, essayez ce qui suit:
Si cela ne fonctionne pas, il existe quatre sources d'erreur possibles:
float32
mais qu’il s’agisse d’un nombre entier.Voir sklearn pour plus de détails.
L'idée est de commencer avec un petit ensemble de données d'apprentissage (probablement un seul élément). Ensuite, le modèle devrait pouvoir adapter les données à la perfection. Si cela fonctionne, vous créez un jeu de données légèrement plus grand. Votre erreur d’entraînement devrait légèrement augmenter jusqu’à Cela révèle la capacité de vos modèles à modéliser les données.
Vérifiez la fréquence à laquelle les autres classes apparaissent. Si une classe domine les autres (par exemple, une classe représente 99,9% des données), cela pose un problème. Rechercher des techniques de "détection des valeurs aberrantes".
0.001
est souvent utilisé/fonctionnel. Ceci est également pertinent si vous utilisez Adam comme optimiseur.Ceci est inspiré par reddit :
imbalanced-learn
Incase juste quelqu'un d'autre rencontre ce problème. Le mien était avec une architecture deeplearning4j
Lenet (CNN), il continuait à donner le résultat final du dernier dossier de formation pour chaque test. J'ai réussi à le résoudre par increasing my batchsize
et shuffling the training data
afin que chaque lot contienne au moins un échantillon de plusieurs dossiers. Ma classe de données avait une taille de lot de 1 qui était vraiment dangerous
.
Edit: Bien que l’une des choses que j’ai récemment constatée, c’est le nombre limité d’échantillons d’entraînement par classe, malgré un dataset
important. eg formant un neural-network
à reconnaître human faces
mais n'ayant qu'un maximum de dire 2 faces différentes pour 1person
moyenne alors que le jeu de données consiste en: 10,000persons
donc un dataset
de 20 000faces
au total. Une meilleure dataset
serait 1000 différente faces
pour 10 000persons
soit une dataset
de 10 000 000faces
au total. Ceci est relativement nécessaire si vous voulez éviter surcharger les données dans une classe} afin que votre network
puisse facilement généraliser et produire une meilleure prédiction.