我正在尝试为多层前馈神经网络实现反向传播算法,但我遇到了将其收敛到良好结果的问题。原因是,梯度下降卡在均方根误差的平板上。
正如您在图表中看到的那样,前70个时期的rms值几乎没有变化。因此,梯度下降的东西发现最小并停止。为了解决这个问题,我设定了一个要求,即除了低于给定值的变化率之外,均方根误差必须低于0.3。但是,我不认为这很好,因为我认为我的实施有问题。
以下是红宝石代码:
def train eta, criteria
rms = 1
old_rms = 0
rms_window = Array.new 20, 0
new_avg = 10
old_avg = 0
diff = 100
epoch = 0
@data[:training].shuffle!
while (diff > criteria || rms > 0.3) do
#while (diff > criteria) do
rms = 0
old_avg = new_avg
new_avg = 0
classification_error = 0
sample_num = 0
@data[:training].each_with_index do |s, s_i|
# Forward Propagation
inputs = [1, s[1], s[2]]
@hidden_layers.each_with_index do |hl, hl_i|
outputs = Array.new
# Bias Term
outputs << 1
# Compute the output for each neuron
hl.each do |p|
outputs << p.compute_output(inputs)
end
inputs = outputs
end
# Compute System Outputs
outputs = Array.new
@outputs.each do |p|
outputs << p.compute_output(inputs)
end
# Comput Errors
errors = Array.new
desired = @desired_values[s[0]-1]
@outputs.length.times do |x|
errors[x] = desired[x] - outputs[x]
rms += errors[x]**2
end
decision = outputs.each_with_index.max[1]
if decision+1 != s[0]
classification_error += 1
end
# Back Propagation
gradients = Array.new
local_gradient = Array.new
next_layer = Array.new
@outputs.each_with_index do |o, i|
local_gradient << errors[i] * o.activation_prime(o.output)
o.weights.length.times do |x|
o.weights[x] += eta * local_gradient[i] * o.inputs[x]
end
end
gradients << local_gradient
next_layer = @outputs
@hidden_layers.reverse_each do |hl|
local_gradient = Array.new
hl.each do |p|
gradient = 0
gradients.last.each_with_index do |g, i|
gradient += g * next_layer[i].weights[p.index+1]
end
gradient *= p.activation_prime(p.output)
local_gradient << gradient
p.weights.each_index do |x|
p.weights[x] += eta * gradient * p.inputs[x]
end
end
gradients << local_gradient
next_layer = hl
end
if s_i == 0
#puts "Epoch: #{epoch}\nOutputs: #{outputs}\nGradients:\n#{gradients[0]}\n#{gradients[1]}\n#{gradients[2]}\n\n"
#puts "Epoch #{epoch}\nError: #{errors}\nSE: #{rms}"
end
end
rms = Math::sqrt(rms / (@data[:training].length * 4))
rms_window[0] = rms
rms_window.rotate!
rms_window.each do |x|
new_avg += x
end
new_avg /= 20
diff = (new_avg - old_avg).abs
@rms << rms
epoch += 1
if classification_error == 0
break
end
#puts "RMS: #{rms}\tDiff: \t#{diff}\tClassification: #{classification_error}\n\n"
end
self.rms_plot "Plot"
self.grid_eval "Test", 250
end
显示的图表是2个隐藏层网络,每个隐藏层有5个神经元。有2个输入和4个输出。也许这是正常的行为,但对我来说似乎有些不对劲。任何帮助将不胜感激。
答案 0 :(得分:0)
需要调整许多参数才能使多层神经网络正常工作。根据我的实验,我的第一个建议是:
1-给它一小组合成数据并运行一个婴儿项目,看看框架是否有效。
2-使用更凸的成本函数。没有保证凸性的函数,但有许多函数比RMS更凸。
3-尝试在(-1,1)中缩放输入数据,在(0,1)中输出数据。
4-尝试不同的学习率值。
答案 1 :(得分:0)
除了已经说过的内容之外:
稍微改变一下初始权重的范围(例如0-1)
确保您的输入数据已正确标准化 - 我认为这不能说得足够
改变学习率,从0.05开始并逐步增加/减少(如果你发现改变你的学习率对网络的性能有太大的影响,那么你可能没有规范化适当的输入数据)
在每个纪元之前随机播放输入数据
尝试使用动量(这实际上意味着,在渐变陡峭时提高学习率,如果变得更平坦则减少),这通常有助于跳过局部最优
尝试使用正规化
试验结构(添加另一个隐藏层,增加隐藏层中的单位数量)