我不是神经网络方面的专家,但我认为以下几点可能对您有所帮助。还有一些不错的帖子,例如这个关于隐藏单元的帖子,你可以在这个网站上搜索你可能会发现有用的神经网络做什么。
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 个隐藏单元来测试你的神经网络的合理方法是什么?神经网络通常用于分类,因此决定是否是一个合理的问题选择。我用和。请注意,有几个参数需要学习。x⋅k>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 个参数。我怀疑在这种情况下,您可以通过减少单位数量来减少要估计的参数数量。你可以从构建一个神经网络来做加法中看到,一个更简单的神经网络可能不太可能在训练过程中遇到问题。
但作为任何机器学习(包括线性回归)的一般规则,您希望拥有比要估计的参数更多的训练示例。