Je ne suis pas un expert en réseaux neuronaux mais je pense que les points suivants pourraient vous être utiles. Il y a aussi quelques bons articles, par exemple celui-ci sur les unités cachées , que vous pouvez rechercher sur ce site à propos des réseaux neuronaux que vous pourriez trouver utiles.
1 Grandes erreurs: pourquoi votre exemple n'a-t-il pas fonctionné du tout
pourquoi les erreurs sont si importantes et pourquoi toutes les valeurs prédites sont presque constantes?
Cela est dû au fait que le réseau de neurones n'a pas pu calculer la fonction de multiplication que vous lui avez donnée et que la sortie d'un nombre constant au milieu de la plage était y
, malgré tout x
, le meilleur moyen de minimiser les erreurs pendant l'entraînement. (Remarquez comment 58749 est assez proche de la moyenne de la multiplication de deux nombres entre 1 et 500 ensemble.)
Il est très difficile de voir comment un réseau de neurones pourrait calculer une fonction de multiplication de manière sensée. Réfléchissez à la façon dont chaque nœud du réseau combine les résultats précédemment calculés: vous prenez une somme pondérée des sorties des nœuds précédents (puis vous lui appliquez une fonction sigmoïde, voir, par exemple, une introduction aux réseaux neuronaux , pour analyser la sortie entre et ). Comment allez-vous obtenir une somme pondérée pour vous donner la multiplication de deux entrées? (Je suppose, cependant, qu'il pourrait être possible de prendre un grand nombre de couches cachées pour que la multiplication fonctionne de manière très artificielle.)1- 11
2 Minima locaux: pourquoi un exemple théoriquement raisonnable pourrait ne pas fonctionner
Cependant, même en essayant de faire des ajouts, vous rencontrez des problèmes dans votre exemple: le réseau ne s'entraîne pas correctement. Je pense que c'est à cause d'un deuxième problème: obtenir des minima locaux pendant la formation. En fait, pour l'addition, l'utilisation de deux couches de 5 unités cachées est beaucoup trop compliquée pour calculer l'addition. Un réseau sans unités cachées s'entraîne parfaitement:
x <- cbind(runif(50, min=1, max=500), runif(50, min=1, max=500))
y <- x[, 1] + x[, 2]
train <- data.frame(x, y)
n <- names(train)
f <- as.formula(paste('y ~', paste(n[!n %in% 'y'], collapse = ' + ')))
net <- neuralnet(f, train, hidden = 0, threshold=0.01)
print(net) # Error 0.00000001893602844
Bien sûr, vous pouvez transformer votre problème d'origine en un problème supplémentaire en prenant des journaux, mais je ne pense pas que c'est ce que vous voulez, ainsi de suite ...
3 Nombre d'exemples de formation par rapport au nombre de paramètres à estimer
Alors, quelle serait une façon raisonnable de tester votre réseau neuronal avec deux couches de 5 unités cachées comme vous l'aviez à l'origine? Les réseaux de neurones sont souvent utilisés pour la classification, afin de décider si semblait un choix de problème raisonnable. J'ai utilisé et . Notez qu'il y a plusieurs paramètres à apprendre.k = ( 1 , 2 , 3 , 4 , 5 ) c = 3750x ⋅ k >ck =(1,2,3,4,5)c = 3750
Dans le code ci-dessous, j'adopte une approche très similaire à la vôtre, sauf que je forme deux réseaux neuronaux, l'un avec 50 exemples de l'ensemble d'entraînement et l'autre avec 500.
library(neuralnet)
set.seed(1) # make results reproducible
N=500
x <- cbind(runif(N, min=1, max=500), runif(N, min=1, max=500), runif(N, min=1, max=500), runif(N, min=1, max=500), runif(N, min=1, max=500))
y <- ifelse(x[,1] + 2*x[,1] + 3*x[,1] + 4*x[,1] + 5*x[,1] > 3750, 1, 0)
trainSMALL <- data.frame(x[1:(N/10),], y=y[1:(N/10)])
trainALL <- data.frame(x, y)
n <- names(trainSMALL)
f <- as.formula(paste('y ~', paste(n[!n %in% 'y'], collapse = ' + ')))
netSMALL <- neuralnet(f, trainSMALL, hidden = c(5,5), threshold = 0.01)
netALL <- neuralnet(f, trainALL, hidden = c(5,5), threshold = 0.01)
print(netSMALL) # error 4.117671763
print(netALL) # error 0.009598461875
# get a sense of accuracy w.r.t small training set (in-sample)
cbind(y, compute(netSMALL,x)$net.result)[1:10,]
y
[1,] 1 0.587903899825
[2,] 0 0.001158500142
[3,] 1 0.587903899825
[4,] 0 0.001158500281
[5,] 0 -0.003770868805
[6,] 0 0.587903899825
[7,] 1 0.587903899825
[8,] 0 0.001158500142
[9,] 0 0.587903899825
[10,] 1 0.587903899825
# get a sense of accuracy w.r.t full training set (in-sample)
cbind(y, compute(netALL,x)$net.result)[1:10,]
y
[1,] 1 1.0003618092051
[2,] 0 -0.0025677656844
[3,] 1 0.9999590121059
[4,] 0 -0.0003835722682
[5,] 0 -0.0003835722682
[6,] 0 -0.0003835722199
[7,] 1 1.0003618092051
[8,] 0 -0.0025677656844
[9,] 0 -0.0003835722682
[10,] 1 1.0003618092051
Il est évident que le netALL
fait beaucoup mieux! Pourquoi est-ce? Jetez un œil à ce que vous obtenez avec une plot(netALL)
commande:
Je lui fais 66 paramètres qui sont estimés pendant l'entraînement (5 entrées et 1 entrée de polarisation pour chacun des 11 nœuds). Vous ne pouvez pas estimer de manière fiable 66 paramètres avec 50 exemples de formation. Je suppose que dans ce cas, vous pourriez être en mesure de réduire le nombre de paramètres à estimer en réduisant le nombre d'unités. Et vous pouvez voir en construisant un réseau de neurones pour faire plus qu'un réseau de neurones plus simple peut être moins susceptible de rencontrer des problèmes pendant l'entraînement.
Mais en règle générale dans tout apprentissage automatique (y compris la régression linéaire), vous voulez avoir beaucoup plus d'exemples de formation que de paramètres à estimer.