为啥RNN总是输出1

Posted

技术标签:

【中文标题】为啥RNN总是输出1【英文标题】:Why does RNN always output 1为什么RNN总是输出1 【发布时间】:2017-06-12 06:05:58 【问题描述】:

我正在使用循环神经网络 (RNN) 进行预测,但由于某些奇怪的原因,它总是输出 1。这里我用一个玩具示例对此进行解释:

示例 考虑一个维度为 (360, 5) 的矩阵 M 和一个包含 M 的行和的向量 Y。现在,使用 RNN,我想从 M 预测 Y。使用 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

我在训练时观察到的一件奇怪的事情是 epoch error 总是 4501。理想情况下,epoch error 应该随着 epochs 的增加而减少。

接下来,我创建了一个与上述结构相同的测试数据集:

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 代码共享简约数据。

数据详情:“功率”列是响应变量,它是前几天从第 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。

【问题讨论】:

最简单的原因是你的学习率太高,或者模型不适合数据。 我发现您的数据有问题。首先数据太小无法调试。给定一个 16 列和 37 行的训练数据集,即使是线性模型也可能会遇到困难,但是神经网络呢?忘掉它。您的数据似乎不按顺序排列,否则每行的滞后将与前几行相同,只是移过一列。 RNN 需要按顺序排列数据。最后,你为什么要使用滞后作为特征呢? RNN 的重点在于“记忆”方面,它可以记住先前的数据。如果您以任何方式提供先验值,那么您的网络就会变得更加复杂。 @Barker,我明白你的意思了!但是我仍然面临时间序列数据建模 acc 的问题。对于 RNN 输入,我在 ***.com/q/42431720/3317829 提出了同样的问题 【参考方案1】:

根据我对包中示例的回顾(请参阅?trainr),训练函数的输入必须是二进制的。包中有函数int2binbin2int

我无法让它们正常工作,但似乎需要转换为二进制。

【讨论】:

任何人都可以验证是否是这种情况,即 rnn 包需要转换为二进制文件。我已经尝试过了,在没有这种转换的情况下我得到了一些结果,虽然效果不是很好。 @Erik——这个小插曲可能会有所帮助;有一个步骤是颠倒数组:cran.r-project.org/web/packages/rnn/vignettes/rnn.html 谢谢!在此示例中,它们转换为二进制。我的问题是这是否是绝对必要的。无论如何,我尝试并仔细调整了超参数,即使没有转换为二进制,我也可以使用 RNN 获得合理的结果。所以我想答案是这不是严格需要的。但是,我仍然想更好地了解这种转换如何影响结果,以及何时需要。我猜它只适用于整数,对于涉及实数的问题,你可以继续在原始数据上训练 RNN(标准化为 0 到 1 之间)。【参考方案2】:

大多数 RNN 不喜欢没有恒定均值的数据。处理此问题的一种策略是区分数据。要了解它是如何工作的,让我们使用一个基本的R 时间序列co2。这是一个具有良好平滑季节性和趋势的时间序列,因此我们应该能够对其进行预测。

对于我们的模型,我们的输入矩阵将是使用stl 分解创建的co2 时间序列的“季节性”和“趋势”。因此,让我们像以前一样制作我们的训练和测试数据并训练模型(注意我减少了运行时的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)

太好了,现在趋势已经消失,所以我们的神经网络应该能够更好地找到模式。让我们用新数据再试一次。

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 个月的训练数据。

【讨论】:

谢谢,它适用于这个问题,但它不适用于我的问题。如果您能浏览更新后的问题并找出我哪里出错了,我们将不胜感激。

以上是关于为啥RNN总是输出1的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的输出总是以 NaN 的形式出现,我期待输出作为我的系列数据?

为啥输出总是零? [关闭]

为啥 PEAR mimedecode.php 正文输出几乎总是 NULL?

为啥在“if”或“when”中输出位总是输出 0? mysql 5.7

为啥“echo l > /proc/sysrq-trigger”调用跟踪输出总是相似?

为啥从 Presto 中的 dtap:// hive 表读取时总是得到 0 条记录作为输出?