我尝试创建一个神经网络来估计y = x ^ 2。因此,我创建了一个拟合神经网络,并为其提供了输入和输出的样本。我尝试在C++中构建这个网络,但结果与我预期的不同。
使用以下输入:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -69 -70 -71
以及以下输出:
0 1 4 9 16 25 36 49 64 81 100 121 144 169 196 225 256 289 324 361 400 441 484 529 576 625 676 729 784 841 900 961 1024 1089 1156 1225 1296 1369 1444 1521 1600 1681 1764 1849 1936 2025 2116 2209 2304 2401 2500 2601 2704 2809 2916 3025 3136 3249 3364 3481 3600 3721 3844 3969 4096 4225 4356 4489 4624 4761 4900 5041 1 4 9 16 25 36 49 64 81 100 121 144 169 196 225 256 289 324 361 400 441 484 529 576 625 676 729 784 841 900 961 1024 1089 1156 1225 1296 1369 1444 1521 1600 1681 1764 1849 1936 2025 2116 2209 2304 2401 2500 2601 2704 2809 2916 3025 3136 3249 3364 3481 3600 3721 3844 3969 4096 4225 4356 4489 4624 4761 4900 5041
我使用了拟合工具网络,采用矩阵行。训练数据占70%,验证数据和测试数据各占15%。隐藏层神经元数量为两个。然后我在命令行中输入了以下代码:
purelin(net.LW{2}*tansig(net.IW{1}*inputTest+net.b{1})+net.b{2})
其他信息:
我的net.b[1]是:-1.16610230053776 1.16667147712026
我的net.b[2]是:51.3266249426358
我的net.IW(1)是:0.344272596370387 0.344111217766824
我的net.LW(2)是:31.7635369693519 -31.8082184881063
当我的inputTest为3时,该命令的结果是16,而它应该大约是9。我在哪里犯了错误吗?
我在Stack Overflow上找到了一篇帖子在MATLAB中使用神经网络,其中描述的问题与我的问题类似,但有一点不同,那就是在那个问题中,输入和输出的范围是相同的,而在我的问题中则不是。那个解决方案说我需要对结果进行缩放,但我该如何缩放我的结果呢?
回答:
你关于缩放的说法是正确的。正如链接的回答中提到的,神经网络默认将输入和输出缩放到[-1,1]范围内。这可以在网络处理函数配置中看到:
>> net = fitnet(2);>> net.inputs{1}.processFcnsans = 'removeconstantrows' 'mapminmax'>> net.outputs{2}.processFcnsans = 'removeconstantrows' 'mapminmax'
应用于输入/输出的第二个预处理函数是mapminmax
,其参数如下:
>> net.inputs{1}.processParams{2}ans = ymin: -1 ymax: 1>> net.outputs{2}.processParams{2}ans = ymin: -1 ymax: 1
将两者映射到[-1,1]范围内(在训练之前)。
这意味着训练后的网络期望输入值在这个范围内,输出值也在相同的范围内。如果你想手动向网络输入数据,并自己计算输出,你必须在输入时缩放数据,并在输出时反转映射。
最后要记住的一点是,每次你训练人工神经网络时,你会得到不同的权重。如果你想要可重复的结果,你需要固定随机数生成器的状态(每次用相同的种子初始化)。阅读关于rng
和RandStream
等函数的文档。
你还必须注意,如果你将数据分为训练/测试/验证集,你必须每次使用相同的分割(可能也受到我提到的随机性方面的影响)。
这里有一个例子来说明这个想法(改编自我的另一篇帖子):
%%# datax = linspace(-71,71,200); %# 1D inputy_model = x.^2; %# modely = y_model + 10*randn(size(x)).*x; %# add some noise%%# create ANN, train, simulatenet = fitnet(2); %# one hidden layer with 2 nodesnet.divideFcn = 'dividerand';net.trainParam.epochs = 50;net = train(net,x,y);y_hat = net(x);%%# plotplot(x, y, 'b.'), hold onplot(x, x.^2, 'Color','g', 'LineWidth',2)plot(x, y_hat, 'Color','r', 'LineWidth',2)legend({'data (noisy)','model (x^2)','fitted'})hold off, grid on%%# manually simulate network%# map input to [-1,1] range[~,inMap] = mapminmax(x, -1, 1);in = mapminmax('apply', x, inMap);%# propagate values to get output (scaled to [-1,1])hid = tansig( bsxfun(@plus, net.IW{1}*in, net.b{1}) ); %# hidden layeroutLayerOut = purelin( net.LW{2}*hid + net.b{2} ); %# output layer%# reverse mapping from [-1,1] to original data scale[~,outMap] = mapminmax(y, -1, 1);out = mapminmax('reverse', outLayerOut, outMap);%# compare against MATLAB outputmax( abs(out - y_hat) ) %# this should be zero (or in the order of `eps`)
我选择使用mapminmax
函数,但你也可以手动完成。公式是一个非常简单的线性映射:
y = (ymax-ymin)*(x-xmin)/(xmax-xmin) + ymin;