R neuralnet - compute daje stałą odpowiedź

11

Próbuję użyć neuralnetpakietu R ( tutaj dokumentacji ) do przewidywania.

Oto, co próbuję zrobić:

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

Czy ktoś może mi wyjaśnić, dlaczego błędy są tak duże i dlaczego wszystkie przewidywane wartości są prawie stałe?

luckyi
źródło

Odpowiedzi:

6

Nie jestem ekspertem od sieci neuronowych, ale myślę, że poniższe punkty mogą być dla ciebie pomocne. Jest też kilka fajnych postów, np. Tego na ukrytych jednostkach , które możesz wyszukać na tej stronie o tym, co robią sieci neuronowe, które mogą ci się przydać.

1 Duże błędy: dlaczego twój przykład w ogóle nie działał

dlaczego błędy są tak duże i dlaczego wszystkie przewidywane wartości są prawie stałe?

Wynika to z faktu, że sieć neuronowa nie była w stanie obliczyć podanej funkcji mnożenia, a wyprowadzenie stałej liczby w środku zakresu y, niezależnie od tego x, było najlepszym sposobem na zminimalizowanie błędów podczas treningu. (Zauważ, że 58749 jest dość bliski średniej pomnożenia dwóch liczb od 1 do 500 razem).

Bardzo trudno jest zrozumieć, jak sieć neuronowa może rozsądnie obliczyć funkcję zwielokrotnienia. Pomyśl o tym, jak każdy węzeł w sieci łączy wcześniej obliczone wyniki: bierzesz ważoną sumę wyników z poprzednich węzłów (a następnie stosuje się do niej funkcję sigmoidalną, patrz np. Wprowadzenie do sieci neuronowych , aby skrócić dane wyjściowe między i ). Jak uzyskasz sumę ważoną, która da ci mnożenie dwóch danych wejściowych? (Przypuszczam jednak, że możliwe jest wzięcie dużej liczby ukrytych warstw, aby multiplikacja działała w bardzo przemyślany sposób).11

2 Minima lokalne: dlaczego teoretycznie uzasadniony przykład może nie działać

Jednak nawet przy próbie dodania napotykasz problemy w przykładzie: sieć nie trenuje pomyślnie. Uważam, że dzieje się tak z powodu drugiego problemu: uzyskania lokalnych minimów podczas szkolenia. W rzeczywistości, dla dodania, użycie dwóch warstw 5 ukrytych jednostek jest zbyt skomplikowane, aby obliczyć dodawanie. Sieć bez ukrytych jednostek doskonale trenuje:

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

Oczywiście możesz przekształcić swój pierwotny problem w problem dodatkowy, biorąc dzienniki, ale nie sądzę, że tego właśnie chcesz, więc dalej ...

3 Liczba przykładów szkolenia w porównaniu do liczby parametrów do oszacowania

Więc jaki byłby rozsądny sposób przetestowania twojej sieci neuronowej za pomocą dwóch warstw 5 ukrytych jednostek, tak jak wcześniej? Sieci neuronowe są często używane do klasyfikacji, więc decyzja, czy wydaje się rozsądnym wyborem problemu. Kiedyś i . Zauważ, że należy nauczyć się kilku parametrów.xk>ck=(1,2,3,4,5)c=3750

W poniższym kodzie mam bardzo podobne podejście do twojego, z tym wyjątkiem, że trenuję dwie sieci neuronowe, jedną z 50 przykładami z zestawu treningowego, a drugą z 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

Widać, że netALLrobi się znacznie lepiej! Dlaczego to? Zobacz, co otrzymujesz za pomocą plot(netALL)polecenia:

wprowadź opis zdjęcia tutaj

Robię 66 parametrów, które są szacowane podczas treningu (5 danych wejściowych i 1 dane wejściowe odchylenia dla każdego z 11 węzłów). Nie można wiarygodnie oszacować 66 parametrów na 50 przykładach szkolenia. Podejrzewam, że w tym przypadku możesz być w stanie zmniejszyć liczbę parametrów do oszacowania, zmniejszając liczbę jednostek. Po zbudowaniu sieci neuronowej można zauważyć, że prostsza sieć neuronowa może mniej napotykać problemy podczas treningu.

Ale jako ogólna zasada w każdym uczeniu maszynowym (w tym regresji liniowej) chcesz mieć o wiele więcej przykładów szkoleniowych niż parametrów do oszacowania.

TooTone
źródło
1
Wiele informacji do przemyślenia, dzięki! Masz absolutną rację! Jeśli zmienne zostaną znormalizowane, liczba przykładów treningowych będzie większa, a liczba neuronów na jednej ukrytej warstwie równa jednej, będzie wyglądać znacznie lepiej. Oczywiście nie funkcja mnożenia, ale coś podobnego. Ach, gdybym otrzymał tak świetną odpowiedź 2 tygodnie temu, byłoby łatwiej. Jednak bardzo wdzięczny za odpowiedź, dziękuję!
luckyi