我在尝试使用Ruby来构建一些人工神经网络,我尝试了几种gem(ruby-fann, Ai4r),但每次我用一些测试输入运行训练好的网络时,总是得到同样的结果[1.0, 1.0],然而在训练数据中,所有的输出值都在100左右。我有10个输入神经元和2个输出神经元。我尝试了不同的网络配置、期望误差,以及不同的层数和神经元数量。在训练ruby-fann的NN时,我得到了以下信息:
1. Current error: 10034.23571597 Bit fail: 1938100. Current error: 9937.62571597 Bit fail: 1938
在那之后,所有的错误和失败都保持相同。以下是我的代码:
inputs_to_learn = []outputs_to_learn = []some cycle: inputs_to_learn.push([i1,i2,i3,i4,i5,i6,i7,i8,i9,i10,]) outputs_to_learn.push([o1, o2])train = RubyFann::TrainData.new(:inputs=>inputs_to_learn, :desired_outputs=>outputs_to_learn)fann = RubyFann::Standard.new(:num_inputs=>10, :hidden_neurons=>[30, 30, 30, 30], :num_outputs=>2) fann.train_on_data(train, 1000, 100, 0.5)result = fann.run([100, 100, 95, 105, 95, 105, 95, 105, 95, 105])
那么问题来了,为什么我得到的是1.0,而训练数据中的数值是它的100倍?
回答:
在构建神经网络时,有很多可选项。一个重要的选择是应用于每个神经元所有输入乘以权重总和的传递函数。这也可能被称为激活函数。
这主要影响到输出层。对于你的网络,输出值为100是不可能的,因此网络无法正确学习这些值。
使用逻辑函数(或称作Sigmoid函数)的网络非常常见,它的输出总是介于0.0和1.0之间。在某些神经网络库中,这可能是你唯一的选择。
你有两个基本选择来改善你的网络的收敛性:
1) 阅读你正在使用的库的文档,看看是否可以设置一个线性输出层(即不应用传递函数)。如果你是试图创建一个连续变量的回归模型,这可能是一个不错的选择。
2) 将你的输出变量缩放到可用的输出范围0.0..1.0。你需要将你的训练数据映射到这个范围,然后在解释输出时反向映射,使用网络处理新的输入数据。
如果我没记错的话,FANN以及因此的ruby-fann,在神经元类型和其他现代NN功能(例如正则化、各种“聪明”的批量学习技巧等)方面选择相当有限。我认为可能没有其他选择——在这种情况下,你唯一的选择就是将训练目标缩放到0..1范围内。然而,从你的评论中我可以看到有一些方法可以设置激活函数。
为了获得最佳性能,理想情况下你也应该根据你的训练数据缩放输入。通常,你会将它们标准化为在训练集上具有均值0.0和标准差1.0(并且从那时起对所有输入使用相同的偏移量和乘数),尽管将范围限制在0.0..1.0或-1.0..1.0也很常见。