在my previous attempt之后,我设法训练神经网络来表达正弦函数。我使用了ai4r Ruby gem:
require 'ai4r'
srand 1
net = Ai4r::NeuralNetwork::Backpropagation.new([1, 60, 1])
net.learning_rate = 0.01
#net.propagation_function = lambda { |x| 1.0 / ( 1.0 + Math::exp( -x ) ) }
def normalise(x, xmin, xmax, ymin, ymax)
xrange = xmax - xmin
yrange = ymax - ymin
return ymin + (x - xmin) * (yrange.to_f / xrange)
end
training_data = Array.new
test = Array.new
i2 = 0.0
320.times do |i|
i2 += 0.1
hash = Hash.new
output = Math.sin(i2.to_f)
input = i2.to_f
hash.store(:input,[normalise(input,0.0,32.0,0.0,1.0)])
hash.store(:expected_result,[normalise(output,-1.0,1.0,0.0,1.0)])
training_data.push(hash)
test.push([normalise(output,-1.0,1.0,0.0,1.0)])
end
puts "#{test}"
puts "#{training_data}"
time = Time.now
999999.times do |i|
error = 0.0
training_data.each do |d|
error+=net.train(d[:input], d[:expected_result])
end
if error < 0.26
break
end
print "Times: #{i}, error: #{error} \r"
end
time2 = Time.now
puts "#{time2}-#{time} = #{time2-time} Sekunden gebraucht."
serialized = Marshal.dump(net)
File.open("net.saved", "w+") { |file| file.write(serialized) }
一切都很顺利。该网络的培训时间为4703.664857秒。
当我将输入/输出标准化为0到1之间的数字时,网络将被更快地训练。ai4r
使用sigmoid函数,因此很清楚它不输出负值。但为什么我必须规范化输入值?这种神经网络是否仅接受输入值&lt; 1?
在正弦示例中,是否可以输入任何数字,如:
Input: -10.0 -> Output: 0.5440211108893699
Input: 87654.322 -> Output: -0.6782453567239783
Input: -9878.923 -> Output: -0.9829544956991526
还是我必须定义范围?
答案 0 :(得分:1)
在您的结构中,单次输入后您有60个隐藏节点。这意味着每个隐藏节点只有1个学习权重,总共学习了60个值。从隐藏层到单个输出节点的连接同样具有60个权重或学习值。这总共提供了120个可学习的尺寸。
图像隐藏层中每个节点能够学习的内容:存在单个缩放因子,然后是非线性。让我们假设您的权重最终看起来像:
[1e-10, 1e-9, 1e-8, ..., .1]
每个条目都是隐藏层中节点的权重。现在,如果您将数字1传递到您的网络,您的隐藏图层将输出此效果:
[0, 0, 0, 0, ..., .1, .25, .5, .75, 1]
(粗略地说,实际上没有计算)
同样,如果你给它一些大的东西,比如:1e10那么第一层就会给出:
[0, .25, .5, .75, 1, 1, 1, ..., 1]
。
隐藏层的权重将学会以这种方式分离,以便能够通过将它们缩放到更小的范围来处理大范围的输入。您拥有的隐藏节点越多(在第一层中),每个节点必须分开的距离越小。在我的例子中,它们间隔十倍。如果你有1000,那么它们的间隔可能是2。
通过将输入范围标准化为介于[0,1]之间,您可以限制这些隐藏节点在开始向最终层提供有意义的信息之前需要分开多远。这允许更快的训练(假设您的停止条件基于损失的变化)。
所以直接回答你的问题:不,你没有需要来规范化,但它肯定有助于通过减少输入空间的可变性和大小来加速训练。