Почему RNN всегда выводит 1


Я использую рекуррентные нейронные сети (RNN) для прогнозирования, но по какой-то странной причине он всегда выдает 1. Здесь я объясняю это на примере игрушки следующим образом:

Пример Рассмотрим матрицу M размерностей (360, 5) и Вектор Y, содержащий сумму строк M. Теперь, используя RNN, я хочу предсказать Y из M. Использование rnn R пакет, я обучил модель как

   library(rnn) 
    M <- matrix(c(1:1800),ncol=5,byrow = TRUE) # Matrix (say features) 
    Y <- apply(M,1,sum) # Output equls to row sum of M
    mt <- array(c(M),dim=c(NROW(M),1,NCOL(M))) # matrix formatting as [samples, timesteps, features]
    yt <- array(c(Y),dim=c(NROW(M),1,NCOL(Y))) # formatting
    model <- trainr(X=mt,Y=yt,learningrate=0.5,hidden_dim=10,numepochs=1000) # training
Одна странная вещь, которую я наблюдал во время обучения, заключается в том, что ошибка эпохи всегда равна 4501. В идеале погрешность эпох должна уменьшаться с увеличением эпох.

Затем я создал тестовый набор данных с той же структурой, что и выше:

M2 <- matrix(c(1:15),nrow=3,byrow = TRUE)
mt2 <- array(c(M2),dim=c(NROW(M2),1,NCOL(M2)))
predictr(model,mt2)

При прогнозировании я всегда получаю результат в виде 1. В чем может быть причина постоянной ошибки эпохи и одного и того же вывода?

Обновление # 1

Ответ, предоставленный @Barker, не работает над моей проблемой. Чтобы сделать его открытым, здесь я делюсь минималистичными данными через ссылки dropbox как traindata , testadata , и мой R код as.

Подробности данных: столбец "мощность" - это переменная отклика, которая является функцией температуры, влажности и мощности, потребляемой в предыдущие дни с 1 по 14 день.

normalize_data <- function(x){
  normalized = (x-min(x))/(max(x)-min(x))
  return(normalized)
}

#read test and train data
traindat <- read.csv(file = "train.csv")
testdat <- read.csv(file = "test.csv")
# column "power" is response variable and remaining are predictors
# predictors in  traindata
trainX <- traindat[,1:dim(traindat)[2]-1]
# response of train data
trainY <- traindat$power
# arrange data acc. to RNN as [samples,time steps, features]
tx <- array(as.matrix(trainX), dim=c(NROW(trainX), 1, NCOL(trainX)))
tx <- normalize_data(tx) # normalize data in range of [0,1]
ty <- array(trainY, dim=c(NROW(trainY), 1, NCOL(trainY))) # arrange response acc. to predictors
# train model
model <- trainr(X = tx, Y = ty, learningrate = 0.08, hidden_dim = 6, numepochs = 400)

# predictors in test data
testX <- testdat[,1:dim(testdat)[2]-1]
testX <- normalize_data(testX) # normalize data in range of [0,1]
#testY <- testdat$power
# arrange data acc. to RNN as [samples,time steps, features]
tx2 <- array(as.matrix(testX), dim=c(NROW(testX), 1, NCOL(testX))) # predict
pred <- predictr(model,tx2)
pred

Я варьировал параметры learning rate, hidden_dim, numepochs, но все равно это приводит либо к 0.9, либо к 1.

2 4

2 ответа:

Большинство RNN не любят данные, которые не имеют постоянного среднего значения. Одной из стратегий решения этой проблемы является дифференциация данных. Чтобы увидеть, как это работает, давайте работать с базовым R временным рядом co2. Это временной ряд с хорошей плавной сезонностью и тенденцией, поэтому мы должны уметь его прогнозировать.

временных рядов СО2

Для нашей модели нашей входной матрицей будет "сезонность" и "тренд" временного ряда co2, созданного с помощью декомпозиции stl. Так что давайте сделайте наши обучающие и тестовые данные такими же, как и раньше, и обучите модель (обратите внимание, что я уменьшил numepochs для времени выполнения). Я буду использовать все данные до последних полутора лет для обучения, а затем использовать последние полтора года для тестирования:

#Create the STL decomposition
sdcomp <- stl(co2, s.window = 7)$time.series[,1:2]

Y <- window(co2, end = c(1996, 6))
M <- window(sdcomp, end = c(1996, 6))
#Taken from OP's code
mt <- array(c(M),dim=c(NROW(M),1,NCOL(M)))
yt <- array(c(Y),dim=c(NROW(M),1,NCOL(Y))) 
model <- trainr(X=mt,Y=yt,learningrate=0.5,hidden_dim=10,numepochs=100)

Теперь мы можем создавать наши прогнозы на последний год тестирования данных:

M2 <- window(sdcomp, start = c(1996,7))
mt2 <- array(c(M2),dim=c(NROW(M2),1,NCOL(M2)))
predictr(model,mt2)

output:
      [,1]
 [1,]    1
 [2,]    1
 [3,]    1
 [4,]    1
 [5,]    1
 [6,]    1
 [7,]    1
 [8,]    1
 [9,]    1
[10,]    1
[11,]    1
[12,]    1
[13,]    1
[14,]    1
[15,]    1
[16,]    1
[17,]    1
[18,]    1

Эве, это снова все единицы, как и в вашем примере. Теперь давайте попробуем еще раз, но на этот раз мы будем различать данные. Так как мы пытаемся сделать наши предсказания через полтора года мы будем использовать 18 в качестве лага дифференцирования, поскольку эти значения мы будем знать на 18 месяцев раньше времени.

dco2 <- diff(co2, 18)
sdcomp <- stl(dco2, s.window = "periodic")$time.series[,1:2]
plot(dco2)

различные значения c02

Отлично, тренд теперь исчез, так что наша нейронная сеть должна быть в состоянии найти паттерн лучше. Давайте попробуем еще раз с новыми данными.
Y <- window(dco2, end = c(1996, 6))
M <- window(sdcomp, end = c(1996, 6))

mt <- array(c(M),dim=c(NROW(M),1,NCOL(M)))
yt <- array(c(Y),dim=c(NROW(M),1,NCOL(Y)))
model <- trainr(X=mt,Y=yt,learningrate=0.5,hidden_dim=10,numepochs=100)

M2 <- window(sdcomp, start = c(1996,7))
mt2 <- array(c(M2),dim=c(NROW(M2),1,NCOL(M2)))
(preds <- predictr(model,mt2))

output:
              [,1]
 [1,] 9.999408e-01
 [2,] 9.478496e-01
 [3,] 6.101828e-08
 [4,] 2.615463e-08
 [5,] 3.144719e-08
 [6,] 1.668084e-06
 [7,] 9.972314e-01
 [8,] 9.999901e-01
 [9,] 9.999916e-01
[10,] 9.999916e-01
[11,] 9.999916e-01
[12,] 9.999915e-01
[13,] 9.999646e-01
[14,] 1.299846e-02
[15,] 3.114577e-08
[16,] 2.432247e-08
[17,] 2.586075e-08
[18,] 1.101596e-07

Хорошо, теперь там что-то есть! Давайте посмотрим, как это соотносится с тем, что мы пытались предсказать, dco2:

Наложение участков

Не идеально, но мы, но это нахождение общего паттерна "вверх вниз" данных. Теперь все, что вам нужно сделать, это поработать с вашими темпами обучения и начать оптимизацию со всеми этими прекрасными гиперпараметрами, которые делают работу с нейронными сетями такой радостью. Когда он работает так, как вы хотите, вы можете просто взять свой конечный результат и добавить обратно данные за последние 18 месяцев обучения.

Из моего обзора примеров с пакетом (см. ?trainr) входы в обучающую функцию должны быть двоичными. В пакете есть функции int2bin и bin2int.

Я не смог заставить их работать правильно, но, похоже, преобразование в двоичный код необходимо.