C#构建一个简单的前馈神经网络
1. 神经网络的基本概念
神经网络是一种模拟人脑神经元结构的计算模型,由多个神经元(节点)组成,这些神经元通过连接(边)相互作用。每个连接都有一个权重,用于表示连接的重要性。神经网络通常分为输入层、隐藏层和输出层。
2. 神经元
神经元是神经网络的基本单元,它接收输入信号,通过激活函数处理这些信号,然后产生输出。常见的激活函数包括Sigmoid、ReLU、Tanh等。
3. 前向传播
前向传播是从输入层到输出层的信号传递过程。每个神经元的输出作为下一层神经元的输入,直到最终产生输出。
4. 反向传播
反向传播是训练神经网络的关键步骤,通过计算损失函数的梯度并调整权重,使得网络的预测误差最小化。
using System;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Project.NeuralNetwork
{
/// <summary>
/// 构建神经网络
/// 简单的前馈神经网络
/// </summary>
public class NeuralNetwork
{
/// <summary>
/// 定义神经网络的层数和每层的神经元数量
/// </summary>
private readonly int[] layers;
/// <summary>
/// 存储每层的神经元值
/// </summary>
private double[][] neurons;
/// <summary>
/// 存储每层之间的权重
/// </summary>
private double[][][] weights;
/// <summary>
/// 存储每层的偏置
/// </summary>
private double[][] biases;
/// <summary>
/// 初始化
/// </summary>
/// <param name="layers"></param>
public NeuralNetwork(int[] layers)
{
this.layers = layers;
InitializeNeurons();
InitializeWeightsAndBiases();
}
/// <summary>
/// 初始化神经元数组
/// </summary>
private void InitializeNeurons()
{
neurons = new double[layers.Length][];
for (int i = 0; i < layers.Length; i++)
{
neurons[i] = new double[layers[i]];
}
}
/// <summary>
/// 随机初始化权重和偏置
/// </summary>
private void InitializeWeightsAndBiases()
{
Random random = new Random();
weights = new double[layers.Length - 1][][];
biases = new double[layers.Length - 1][];
for (int i = 0; i < layers.Length - 1; i++)
{
weights[i] = new double[layers[i]][];
for (int j = 0; j < layers[i]; j++)
{
weights[i][j] = new double[layers[i + 1]];
for (int k = 0; k < layers[i + 1]; k++)
{
weights[i][j][k] = random.NextDouble() * 2 - 1;
}
}
biases[i] = new double[layers[i + 1]];
for (int j = 0; j < layers[i + 1]; j++)
{
biases[i][j] = random.NextDouble() * 2 - 1;
}
}
}
/// <summary>
/// sigmoid激活函数
/// </summary>
/// <param name="x"></param>
/// <returns></returns>
private double Sigmoid(double x)
{
return 1.0 / (1.0 + Math.Exp(-x));
}
/// <summary>
/// sigmoid激活函数的导数
/// </summary>
/// <param name="x"></param>
/// <returns></returns>
private double SigmoidDerivative(double x)
{
return x * (1 - x);
}
/// <summary>
/// 前向传播
/// </summary>
/// <param name="inputs"></param>
public void Forward(double[] inputs)
{
Array.Copy(inputs, neurons[0], inputs.Length);
for (int i = 1; i < layers.Length; i++)
{
for (int j = 0; j < layers[i]; j++)
{
double sum = biases[i - 1][j];
for (int k = 0; k < layers[i - 1]; k++)
{
sum += neurons[i - 1][k] * weights[i - 1][k][j];
}
neurons[i][j] = Sigmoid(sum);
}
}
}
/// <summary>
/// 反向传播
/// </summary>
/// <param name="target"></param>
/// <param name="learningRate"></param>
public void Backward(double[] target, double learningRate)
{
double[][] deltas = new double[layers.Length - 1][];
// 计算输出层
deltas[layers.Length - 2] = new double[layers[layers.Length - 1]];
for (int i = 0; i < layers[layers.Length - 1]; i++)
{
double error = target[i] - neurons[layers.Length - 1][i];
deltas[layers.Length - 2][i] = error * SigmoidDerivative(neurons[layers.Length - 1][i]);
}
// 计算隐藏层
for (int i = layers.Length - 3; i >= 0; i--)
{
deltas[i] = new double[layers[i + 1]];
for (int j = 0; j < layers[i + 1]; j++)
{
double error = 0.0;
for (int k = 0; k < layers[i + 2]; k++)
{
error += deltas[i + 1][k] * weights[i + 1][j][k];
}
deltas[i][j] = error * SigmoidDerivative(neurons[i + 1][j]);
}
}
// 更新权重和偏差
for (int i = 0; i < layers.Length - 1; i++)
{
for (int j = 0; j < layers[i]; j++)
{
for (int k = 0; k < layers[i + 1]; k++)
{
weights[i][j][k] += learningRate * neurons[i][j] * deltas[i][k];
}
}
for (int j = 0; j < layers[i + 1]; j++)
{
biases[i][j] += learningRate * deltas[i][j];
}
}
}
/// <summary>
/// 训练神经网络,使用反向传播算法更新权重和偏置
/// </summary>
/// <param name="inputs">输入</param>
/// <param name="targets">目标</param>
/// <param name="epochs">数据运算次数</param>
/// <param name="learningRate">学习速率</param>
public void Train(double[][] inputs, double[][] targets, int epochs, double learningRate)
{
for (int epoch = 0; epoch < epochs; epoch++)
{
for (int i = 0; i < inputs.Length; i++)
{
Forward(inputs[i]);
Backward(targets[i], learningRate);
}
}
}
/// <summary>
/// 使用训练好的模型进行预测
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public double[] Predict(double[] input)
{
Forward(input);
return neurons[layers.Length - 1];
}
}
}
- 准备训练数据
- 训练网络
- 测试网络并输出结果
//1. 数据准备
double[][] inputs = new double[][]
{
new double[] { 0, 0 },
new double[] { 0, 1 },
new double[] { 1, 0 },
new double[] { 1, 1 }
};
double[][] targets = new double[][]
{
new double[] { 0 },
new double[] { 1 },
new double[] { 1 },
new double[] { 0 }
};
//2. 构建神经网络
// 定义神经网络结构:输入层2个神经元,隐藏层3个神经元,输出层1个神经元
int[] layers = { 2, 3, 1 };
NeuralNetwork model = new NeuralNetwork(layers);
//3. 训练和评估
//使用训练数据训练神经网络,并评估其性能。
model.Train(inputs, targets, 10000, 0.01);
//4. 训练神经网络
model.Train(inputs, targets, epochs: 10000, learningRate: 0.5);
// 预测数据
foreach (var input in inputs)
{
double[] prediction = model.Predict(input);
Console.WriteLine($"输入: [{string.Join(", ", input)}] => 输出: [{string.Join(", ", prediction)}]");
}