R neuralnet - le calcul donne une réponse constante

11

J'essaie d'utiliser le neuralnetpackage de R (documentation ici ) pour la prédiction.

Voici ce que j'essaie de faire:

library(neuralnet)
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 = c(5, 5), threshold=0.01)
print(net)

all: neuralnet(formula = f, data = train, hidden = c(5, 5), threshold = 0.01)

1 repetition was calculated.

    Error Reached Threshold Steps
1 66136930789    0.004658283648 97938

test <- cbind(runif(10, min=1, max=500), runif(10, min=1, max=500))
res <- compute(net, test)
res$net.result
         [,1]
[1,] 58749.01798
[2,] 58749.01798
[3,] 58749.01798
[4,] 58749.01798
[5,] 58749.01798
[6,] 58749.01798
[7,] 58749.01798
[8,] 58749.01798
[9,] 58749.01798
[10,] 58749.01798

Quelqu'un peut-il m'expliquer pourquoi les erreurs sont si importantes et pourquoi toutes les valeurs prédites sont presque constantes?

luckyi
la source

Réponses:

6

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.)111

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 = 3750xk>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 netALLfait beaucoup mieux! Pourquoi est-ce? Jetez un œil à ce que vous obtenez avec une plot(netALL)commande:

entrez la description de l'image ici

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.

TooTone
la source
1
Beaucoup d'informations à penser, merci! Tu as tout à fait raison! Si les variables étaient normalisées, le nombre d'exemples d'apprentissage était plus grand et le nombre de neurones sur une couche cachée égal à un, cela aurait l'air beaucoup mieux. Bien sûr, pas une fonction de multiplication mais quelque chose de similaire. Ah, si j'avais une si bonne réponse il y a 2 semaines, les choses seraient plus faciles. Cependant, très reconnaissant pour votre réponse, merci!
luckyi