R 神经网络 - 计算给出一个恒定的答案

机器算法验证 r 神经网络 预言 错误
2022-03-10 09:17:15

我正在尝试使用 R 的neuralnet包(此处的文档)进行预测。

这是我想要做的:

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

有人可以解释一下为什么错误如此之大以及为什么所有预测值几乎都是恒定的吗?

1个回答

我不是神经网络方面的专家,但我认为以下几点可能对您有所帮助。还有一些不错的帖子,例如这个关于隐藏单元的帖子,你可以在这个网站上搜索你可能会发现有用的神经网络做什么。

1 大错误:为什么你的例子根本不起作用

为什么误差如此之大,为什么所有预测值几乎都是常数?

这是因为神经网络无法计算你给它的乘法函数,并且输出一个在 范围中间的常数y,不管x,是在训练期间最小化错误的最佳方法。(请注意 58749 非常接近将 1 到 500 之间的两个数字相乘的平均值。)

很难看出神经网络如何以合理的方式计算乘法函数。考虑一下网络中的每个节点如何结合先前计算的结果:您对来自先前节点的输出进行加权求和(然后对其应用 sigmoidal 函数,例如,参见神经网络简介,以压缩介于之间的输出和 )。您将如何获得加权和以将两个输入相乘?(不过,我想,可能需要大量的隐藏层才能让乘法以一种非常人为的方式工作。)11

2 局部最小值:为什么理论上合理的例子可能行不通

但是,即使尝试进行加法,您也会在示例中遇到问题:网络没有成功训练。我相信这是因为第二个问题:在训练期间获得局部最小值。事实上,对于加法,使用两层 5 个隐藏单元来计算加法过于复杂。没有隐藏单元的网络训练得非常好:

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

当然,您可以通过记录日志将原始问题转换为加法问题,但我认为这不是您想要的,所以……

3 训练示例的数量与要估计的参数数量的比较

那么,用原来的两层 5 个隐藏单元来测试你的神经网络的合理方法是什么?神经网络通常用于分类,因此决定是否是一个合理的问题选择。我用请注意,有几个参数需要学习。xk>ck=(1,2,3,4,5)c=3750

在下面的代码中,我采用了与您的方法非常相似的方法,只是我训练了两个神经网络,一个具有来自训练集的 50 个示例,另一个具有 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

很明显,netALL它的效果要好得多!为什么是这样?看看你用plot(netALL)命令得到了什么:

在此处输入图像描述

我将其设置为在训练期间估计的 66 个参数(5 个输入和 11 个节点中的每个节点的 1 个偏置输入)。您无法使用 50 个训练示例可靠地估计 66 个参数。我怀疑在这种情况下,您可以通过减少单位数量来减少要估计的参数数量。你可以从构建一个神经网络来做加法中看到,一个更简单的神经网络可能不太可能在训练过程中遇到问题。

但作为任何机器学习(包括线性回归)的一般规则,您希望拥有比要估计的参数更多的训练示例。