📄 net.cs
字号:
using System;
using System.Collections.Generic;
using System.Text;
namespace NeuralNetCS
{
class Net
{
private double[] _examples;
private Node[] _input;
private Node[] _hidden;
private Node _output;
private double _learningRate;
/// <summary>
/// Initializes a new instance of the Net class.
/// </summary>
/// <param name="hiddenNodeCount">The number of nodes, not including the bias node, in the hidden layer.</param>
/// <param name="learningRate"></param>
/// <param name="examples"></param>
public Net(int hiddenNodeCount, double learningRate, double[] examples)
{
if( hiddenNodeCount <= 0 )
throw new ArgumentException("The net needs at least one hidden node.", "hiddenNodeCount");
if( learningRate <= 0 )
throw new ArgumentException("The learning rate must be larger than zero.", "learningRate");
if( examples == null )
throw new ArgumentNullException("examples");
if( examples.Length == 0 )
throw new ArgumentException("No examples specified.", "examples");
_examples = examples;
_learningRate = learningRate;
// Create the input layer: one bias node and one input node.
_input = new Node[2];
_input[0] = new Node(-1.0f); // Bias node
_input[1] = new Node(0);
// Create the hidden layer, using one bias node.
_hidden = new Node[hiddenNodeCount + 1];
_hidden[0] = new Node(-1.0f); // Bias node
for( int x = 1; x < _hidden.Length; ++x )
_hidden[x] = new Node(_input);
// Create the output layer
_output = new Node(_hidden);
}
/// <summary>
/// Execute the learning algorithm, and write the final net output to a file.
/// </summary>
/// <param name="epochs">The number of epochs to use when learning.</param>
/// <param name="outputFile">The output file name.</param>
public void Learn(uint epochs, string outputFile)
{
if( outputFile == null )
throw new ArgumentNullException("outputFile");
if( epochs <= 0 )
throw new ArgumentException("The number of epochs must be larger than zero.", "epochs");
BackPropLearning(epochs);
OutputNet(outputFile);
}
/// <summary>
/// Evaluates the entire network.
/// </summary>
private void EvalNet()
{
// Evaluate hidden layer, all but the bias node.
int length = _hidden.Length;
for( int x = 1; x < length; ++x )
_hidden[x].Eval();
// Evaluate the output layer
_output.Eval();
}
/// <summary>
/// Trains the net using the example data, using the back-propagation learning algorithm.
/// </summary>
/// <param name="epochs">The number of epochs to use when learning.</param>
private void BackPropLearning(uint epochs)
{
double[] hiddenDelta = new double[_hidden.Length];
int examplesLength = _examples.Length;
int hiddenLength = _hidden.Length;
int inputLength = _input.Length;
for( uint epoch = 1; epoch <= epochs; ++epoch )
{
double totalError = 0;
bool computeError = epoch % 1000 == 0 || epoch == epochs || epoch == 1;
for( int input = 0; input < examplesLength; ++input )
{
// Set the input
_input[1].Value = input / 100.0f;
// Forward pass: evaluate the network
EvalNet();
if( computeError )
totalError += Math.Pow(_examples[input] - _output.Value, 2);
// Backward pass: update the weights
double outputDelta = SigmoidDerived(_output.LastInput) * (_examples[input] - _output.Value);
for( int x = 0; x < hiddenLength; ++x )
{
hiddenDelta[x] = SigmoidDerived(_hidden[x].LastInput) * _output.GetWeigth(x) * outputDelta;
_output.SetWeight(x, _output.GetWeigth(x) + _learningRate * _hidden[x].Value * outputDelta);
}
for( int x = 0; x < inputLength; ++x )
{
// No point computing the delta, it won't be used
for( int y = 1; y < hiddenLength; ++y )
_hidden[y].SetWeight(x, _hidden[y].GetWeigth(x) + _learningRate * _input[x].Value * hiddenDelta[y]);
}
}
if( computeError )
Console.Write("\rEpoch: {0}; Sum of squared errors: {1} ", epoch, totalError / 2);
}
}
/// <summary>
/// Outputs the net to a file in a format that can be used by gnuplot.
/// </summary>
/// <param name="outputFile">The output file name</param>
private void OutputNet(string outputFile)
{
using( System.IO.StreamWriter writer = new System.IO.StreamWriter(outputFile) )
{
for( int x = 0; x < _examples.Length; ++x )
{
_input[1].Value = x / 100.0f;
EvalNet();
// Couldn't find a way to set the formatprovider for the StreamWriter, so using String.Format
// instead.
writer.WriteLine(String.Format(System.Globalization.CultureInfo.InvariantCulture, "{0:0.######}\t{1:0.######}", _input[1].Value, _output.Value));
}
}
}
/// <summary>
/// The node activation function.
/// </summary>
/// <param name="input">The input.</param>
/// <returns>The result of the function.</returns>
public static double Sigmoid(double input)
{
return 1.0f / (1.0f + Math.Exp(-1.0f * input));
}
/// <summary>
/// The first derivative of the node activiation function.
/// </summary>
/// <param name="input">The input.</param>
/// <returns>The result of the function.</returns>
public static double SigmoidDerived(double input)
{
return Sigmoid(input) * (1 - Sigmoid(input));
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -