Pau*_*rds 14 c# neural-network
我在C#中使用NeuronDotNet用于神经网络.为了测试网络(以及训练它),我编写了自己的函数来得到平方误差.但是,当我通过在训练数据上运行它并将其与Backpropagation网络的MeanSquaredError进行比较来测试此函数时,结果是不同的.
我发现不同错误的原因是当我在学习阶段运行时,网络返回不同的输出.我使用以下命令为每个TrainingSample运行它:
double[] output = xorNetwork.Run(sample.InputVector);
Run Code Online (Sandbox Code Playgroud)
在学习阶段,它使用:
xorNetwork.Learn(trainingSet, cycles);
Run Code Online (Sandbox Code Playgroud)
...使用委托来捕获最终样本事件:
xorNetwork.EndSampleEvent +=
delegate(object network, TrainingSampleEventArgs args)
{
double[] test = xorNetwork.OutputLayer.GetOutput();
debug.addSampleOutput(test);
};
Run Code Online (Sandbox Code Playgroud)
我尝试使用XOR问题,保持简单,输出仍然不同.例如,在第一个纪元结束时,EndSampleEvent委托的输出与我的函数的输出是:
它不像在时代的不同阶段被捕获那么简单,输出与下一个/上一个时期的输出不同.
我已经尝试过调试,但我不是Visual Studio的专家,而且我正在努力解决这个问题.我的项目引用了NeuronDotNet DLL.当我将断点放入我的代码时,它不会进入DLL的代码.我已经在其他地方寻求过这方面的建议并尝试了几种解决方案而无处可去.
我不认为它是由于'观察者效应',即我的函数中的Run方法导致网络改变.我检查了代码(在制作DLL的项目中),我不认为Run会改变任何权重.我的函数中的错误往往比EndSampleEvent中的错误要低一个因子,该因子超过了典型时期的错误减少,即它就好像网络在我的代码中暂时超越自身(就训练而言).
神经网络在训练期间调整其功能的意义上是随机的.但是,输出应该是确定性的.为什么两组输出不同?
编辑:这是我正在使用的代码.
/***********************************************************************************************
COPYRIGHT 2008 Vijeth D
This file is part of NeuronDotNet XOR Sample.
(Project Website : http://neurondotnet.freehostia.com)
NeuronDotNet is a free software. You can redistribute it and/or modify it under the terms of
the GNU General Public License as published by the Free Software Foundation, either version 3
of the License, or (at your option) any later version.
NeuronDotNet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with NeuronDotNet.
If not, see <http://www.gnu.org/licenses/>.
***********************************************************************************************/
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Text;
using System.Windows.Forms;
using NeuronDotNet.Core;
using NeuronDotNet.Core.Backpropagation;
using ZedGraph;
namespace NeuronDotNet.Samples.XorSample
{
public partial class MainForm : Form
{
private BackpropagationNetwork xorNetwork;
private double[] errorList;
private int cycles = 5000;
private int neuronCount = 3;
private double learningRate = 0.25d;
public MainForm()
{
InitializeComponent();
}
private void Train(object sender, EventArgs e)
{
EnableControls(false);
if (!int.TryParse(txtCycles.Text.Trim(), out cycles)) { cycles = 5000; }
if (!double.TryParse(txtLearningRate.Text.Trim(), out learningRate)) { learningRate = 0.25d; }
if (!int.TryParse(txtNeuronCount.Text.Trim(), out neuronCount)) { neuronCount = 3; }
if (cycles < 1) { cycles = 1; }
if (learningRate < 0.01) { learningRate = 0.01; }
if (neuronCount < 1) { neuronCount = 1; }
txtNeuronCount.Text = neuronCount.ToString();
txtCycles.Text = cycles.ToString();
txtLearningRate.Text = learningRate.ToString();
errorList = new double[cycles];
InitGraph();
LinearLayer inputLayer = new LinearLayer(2);
SigmoidLayer hiddenLayer = new SigmoidLayer(neuronCount);
SigmoidLayer outputLayer = new SigmoidLayer(1);
new BackpropagationConnector(inputLayer, hiddenLayer);
new BackpropagationConnector(hiddenLayer, outputLayer);
xorNetwork = new BackpropagationNetwork(inputLayer, outputLayer);
xorNetwork.SetLearningRate(learningRate);
TrainingSet trainingSet = new TrainingSet(2, 1);
trainingSet.Add(new TrainingSample(new double[2] { 0d, 0d }, new double[1] { 0d }));
trainingSet.Add(new TrainingSample(new double[2] { 0d, 1d }, new double[1] { 1d }));
trainingSet.Add(new TrainingSample(new double[2] { 1d, 0d }, new double[1] { 1d }));
trainingSet.Add(new TrainingSample(new double[2] { 1d, 1d }, new double[1] { 0d }));
Console.WriteLine("mse_begin,mse_end,output,outputs,myerror");
double max = 0d;
Console.WriteLine(NNDebug.Header);
List < NNDebug > debugList = new List<NNDebug>();
NNDebug debug = null;
xorNetwork.BeginEpochEvent +=
delegate(object network, TrainingEpochEventArgs args)
{
debug = new NNDebug(trainingSet);
};
xorNetwork.EndSampleEvent +=
delegate(object network, TrainingSampleEventArgs args)
{
double[] test = xorNetwork.OutputLayer.GetOutput();
debug.addSampleOutput(args.TrainingSample, test);
};
xorNetwork.EndEpochEvent +=
delegate(object network, TrainingEpochEventArgs args)
{
errorList[args.TrainingIteration] = xorNetwork.MeanSquaredError;
debug.setMSE(xorNetwork.MeanSquaredError);
double[] test = xorNetwork.OutputLayer.GetOutput();
GetError(trainingSet, debug);
max = Math.Max(max, xorNetwork.MeanSquaredError);
progressBar.Value = (int)(args.TrainingIteration * 100d / cycles);
//Console.WriteLine(debug);
debugList.Add(debug);
};
xorNetwork.Learn(trainingSet, cycles);
double[] indices = new double[cycles];
for (int i = 0; i < cycles; i++) { indices[i] = i; }
lblTrainErrorVal.Text = xorNetwork.MeanSquaredError.ToString("0.000000");
LineItem errorCurve = new LineItem("Error Dynamics", indices, errorList, Color.Tomato, SymbolType.None, 1.5f);
errorGraph.GraphPane.YAxis.Scale.Max = max;
errorGraph.GraphPane.CurveList.Add(errorCurve);
errorGraph.Invalidate();
writeOut(debugList);
EnableControls(true);
}
private const String pathFileName = "C:\\Temp\\NDN_Debug_Output.txt";
private void writeOut(IEnumerable<NNDebug> data)
{
using (StreamWriter streamWriter = new StreamWriter(pathFileName))
{
streamWriter.WriteLine(NNDebug.Header);
//write results to a file for each load combination
foreach (NNDebug debug in data)
{
streamWriter.WriteLine(debug);
}
}
}
private void GetError(TrainingSet trainingSet, NNDebug debug)
{
double total = 0;
foreach (TrainingSample sample in trainingSet.TrainingSamples)
{
double[] output = xorNetwork.Run(sample.InputVector);
double[] expected = sample.OutputVector;
debug.addOutput(sample, output);
int len = output.Length;
for (int i = 0; i < len; i++)
{
double error = output[i] - expected[i];
total += (error * error);
}
}
total = total / trainingSet.TrainingSampleCount;
debug.setMyError(total);
}
private class NNDebug
{
public const String Header = "output(00->0),output(01->1),output(10->1),output(11->0),mse,my_output(00->0),my_output(01->1),my_output(10->1),my_output(11->0),my_error";
public double MyErrorAtEndOfEpoch;
public double MeanSquaredError;
public double[][] OutputAtEndOfEpoch;
public double[][] SampleOutput;
private readonly List<TrainingSample> samples;
public NNDebug(TrainingSet trainingSet)
{
samples =new List<TrainingSample>(trainingSet.TrainingSamples);
SampleOutput = new double[samples.Count][];
OutputAtEndOfEpoch = new double[samples.Count][];
}
public void addSampleOutput(TrainingSample mySample, double[] output)
{
int index = samples.IndexOf(mySample);
SampleOutput[index] = output;
}
public void addOutput(TrainingSample mySample, double[] output)
{
int index = samples.IndexOf(mySample);
OutputAtEndOfEpoch[index] = output;
}
public void setMyError(double error)
{
MyErrorAtEndOfEpoch = error;
}
public void setMSE(double mse)
{
this.MeanSquaredError = mse;
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
foreach (double[] arr in SampleOutput)
{
writeOut(arr, sb);
sb.Append(',');
}
sb.Append(Math.Round(MeanSquaredError,6));
sb.Append(',');
foreach (double[] arr in OutputAtEndOfEpoch)
{
writeOut(arr, sb);
sb.Append(',');
}
sb.Append(Math.Round(MyErrorAtEndOfEpoch,6));
return sb.ToString();
}
}
private static void writeOut(double[] arr, StringBuilder sb)
{
bool first = true;
foreach (double d in arr)
{
if (first)
{
first = false;
}
else
{
sb.Append(',');
}
sb.Append(Math.Round(d, 6));
}
}
private void EnableControls(bool enabled)
{
btnTrain.Enabled = enabled;
txtCycles.Enabled = enabled;
txtNeuronCount.Enabled = enabled;
txtLearningRate.Enabled = enabled;
progressBar.Value = 0;
btnTest.Enabled = enabled;
txtTestInput.Enabled = enabled;
}
private void LoadForm(object sender, EventArgs e)
{
InitGraph();
txtCycles.Text = cycles.ToString();
txtLearningRate.Text = learningRate.ToString();
txtNeuronCount.Text = neuronCount.ToString();
}
private void InitGraph()
{
GraphPane pane = errorGraph.GraphPane;
pane.Chart.Fill = new Fill(Color.AntiqueWhite, Color.Honeydew, -45F);
pane.Title.Text = "Back Propagation Training - Error Graph";
pane.XAxis.Title.Text = "Training Iteration";
pane.YAxis.Title.Text = "Sum Squared Error";
pane.XAxis.MajorGrid.IsVisible = true;
pane.YAxis.MajorGrid.IsVisible = true;
pane.YAxis.MajorGrid.Color = Color.LightGray;
pane.XAxis.MajorGrid.Color = Color.LightGray;
pane.XAxis.Scale.Max = cycles;
pane.XAxis.Scale.Min = 0;
pane.YAxis.Scale.Min = 0;
pane.CurveList.Clear();
pane.Legend.IsVisible = false;
pane.AxisChange();
errorGraph.Invalidate();
}
private void Test(object sender, EventArgs e)
{
if (xorNetwork != null)
{
lblTestOutput.Text = xorNetwork.Run(
new double[] {double.Parse(txtTestInput.Text.Substring(2,4)),
double.Parse(txtTestInput.Text.Substring(8,4))})[0].ToString("0.000000");
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
它与归一化无关,因为两组输出之间的映射不是单调的.例如,{0,1}中的输出在EndSampleEvent中较高,但在{1,1}中较低.归一化将是一个简单的线性函数.
它也与抖动无关,因为我已经尝试将其关闭,结果仍然不同.
我已经收到了教授的答复。问题在于 BackpropagationNetwork 类中的 LearnSample 方法,每次迭代都会为每个训练样本调用该方法。
\n\n此方法中相关事件的顺序为 \xe2\x80\xa6。\n1) 添加到仅使用输出层和所需输出计算的 MeanSquaredError\n2) 将误差反向传播到所有较早的层;这对网络没有影响。\n3) 最后重新计算每层的偏差;这会影响网络。
\n\n(3) 是 LearnSample 方法中发生的最后一件事,发生在计算每个训练实例的输出误差之后。对于 XOR 示例,这意味着网络与进行 MSE 计算时的状态相比发生了 4 次变化。
\n\n理论上,如果您想比较训练和测试错误,那么您应该进行手动计算(如我的 GetError 函数)并运行两次:每个数据集运行一次。然而,实际上可能没有必要这么麻烦,因为价值观并没有那么不同。
\n| 归档时间: |
|
| 查看次数: |
1559 次 |
| 最近记录: |