Keras: un réseau neuronal simple avec des données simples ne fonctionne pas
J'essaie de créer un réseau de neurones très simple: une couche cachée, avec 2 neurones. Pour certaines données très simples: une seule fonctionnalité.
import numpy as np
X=np.concatenate([np.linspace(0,10,100),np.linspace(11,20,100),np.linspace(21,30,100)])
y=np.concatenate([np.repeat(0,100),np.repeat(1,100),np.repeat(0,100)])

Voici le modèle
from keras.models import Sequential
from keras.layers import Dense
model = Sequential()
model.add(Dense(2, activation='sigmoid'))
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='sgd', metrics=['accuracy'])
model.fit(X, y, epochs=200)
En théorie, ce modèle devrait fonctionner. Mais même après 1000 époques, la précision est toujours de 0,667.
Epoch 999/1000
10/10 [==============================] - 0s 1ms/step - loss: 0.5567 - accuracy: 0.6667
Epoch 1000/1000
10/10 [==============================] - 0s 2ms/step - loss: 0.5566 - accuracy: 0.6667
Je pense que j'ai fait quelque chose de mal. Pouvez-vous suggérer une modification?
Il semble qu'il y ait beaucoup de minimums locaux et l' initialisation peut changer le modèle final. C'est le cas lors des tests avec le package nnet
en R. J'ai dû tester beaucoup de graines, j'ai trouvé ce modèle (entre autres).

Et c'est la structure que je voulais créer avec des keras: une couche cachée avec 2 neurones. La fonction d'activation est sigmoïde.
Je me demande donc si Keras a le même problème d'initialisation. Avec ce package nnet
en R, j'ai pensé que ce n'était pas un package "parfait". Et je pensais que les keras seraient plus performants. Si l'initialisation est importante, Keras teste-t-il une initialisation différente? Sinon pourquoi? Peut-être parce qu'en général, avec plus de données (et plus de fonctionnalités), cela fonctionne mieux (sans tester de nombreuses initialisations)?
Par exemple, avec kmeans, il semble que différentes initialisations soient testées.
Réponses
Cette question montre l'importance de la normalisation des données d'entrée pour les réseaux de neurones. Sans normalisation, la formation des réseaux de neurones est parfois difficile car l'optimisation peut rester bloquée à certains minimums locaux.
Je veux commencer par la visualisation de l'ensemble de données. L'ensemble de données est 1D et après avoir été normalisé avec une normalisation standard, il ressemble à ce qui suit.
X_original = np.concatenate([np.linspace(0, 10, 100), np.linspace(
11, 20, 100), np.linspace(21, 30, 100)])
X = (X_original - X_original.mean())/X_original.std()
y = np.concatenate(
[np.repeat(0, 100), np.repeat(1, 100), np.repeat(0, 100)])
plt.figure()
plt.scatter(X, np.zeros(X.shape[0]), c=y)
plt.show()

Cela implique qu'un réseau à une seule couche comme la régression logistique ne peut pas classer cet ensemble de données. Mais un réseau de neurones avec deux couches suivies d'une activation non linéaire devrait être capable de classer l'ensemble de données.
Maintenant, avec la normalisation et le script de formation suivant, le modèle peut facilement apprendre à classer les points.
model = Sequential()
model.add(Dense(2, activation='sigmoid'))
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy',
optimizer=keras.optimizers.Adam(1e-1), metrics=['accuracy'])
model.fit(X, y, epochs=20)
Train on 300 samples
Epoch 1/20
300/300 [==============================] - 1s 2ms/sample - loss: 0.6455 - accuracy: 0.6467
Epoch 2/20
300/300 [==============================] - 0s 79us/sample - loss: 0.6493 - accuracy: 0.6667
Epoch 3/20
300/300 [==============================] - 0s 85us/sample - loss: 0.6397 - accuracy: 0.6667
Epoch 4/20
300/300 [==============================] - 0s 100us/sample - loss: 0.6362 - accuracy: 0.6667
Epoch 5/20
300/300 [==============================] - 0s 115us/sample - loss: 0.6342 - accuracy: 0.6667
Epoch 6/20
300/300 [==============================] - 0s 96us/sample - loss: 0.6317 - accuracy: 0.6667
Epoch 7/20
300/300 [==============================] - 0s 93us/sample - loss: 0.6110 - accuracy: 0.6667
Epoch 8/20
300/300 [==============================] - 0s 110us/sample - loss: 0.5746 - accuracy: 0.6667
Epoch 9/20
300/300 [==============================] - 0s 142us/sample - loss: 0.5103 - accuracy: 0.6900
Epoch 10/20
300/300 [==============================] - 0s 124us/sample - loss: 0.4207 - accuracy: 0.9367
Epoch 11/20
300/300 [==============================] - 0s 124us/sample - loss: 0.3283 - accuracy: 0.9833
Epoch 12/20
300/300 [==============================] - 0s 124us/sample - loss: 0.2553 - accuracy: 0.9800
Epoch 13/20
300/300 [==============================] - 0s 138us/sample - loss: 0.2030 - accuracy: 1.0000
Epoch 14/20
300/300 [==============================] - 0s 124us/sample - loss: 0.1624 - accuracy: 1.0000
Epoch 15/20
300/300 [==============================] - 0s 150us/sample - loss: 0.1375 - accuracy: 1.0000
Epoch 16/20
300/300 [==============================] - 0s 122us/sample - loss: 0.1161 - accuracy: 1.0000
Epoch 17/20
300/300 [==============================] - 0s 115us/sample - loss: 0.1025 - accuracy: 1.0000
Epoch 18/20
300/300 [==============================] - 0s 126us/sample - loss: 0.0893 - accuracy: 1.0000
Epoch 19/20
300/300 [==============================] - 0s 121us/sample - loss: 0.0804 - accuracy: 1.0000
Epoch 20/20
300/300 [==============================] - 0s 132us/sample - loss: 0.0720 - accuracy: 1.0000
Le modèle étant très simple, le choix du taux d'apprentissage et de l'optimiseur affecte la vitesse de l'apprentissage. Avec l'optimiseur SGD et le taux d'apprentissage 1e-1, le modèle peut prendre plus de temps à s'entraîner que l'optimiseur Adam avec le même taux d'apprentissage.