当前位置: 首页 > article >正文

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)}]");
            }


http://www.kler.cn/a/409018.html

相关文章:

  • 【计算机网络】网段划分
  • 一文学习开源框架OkHttp
  • 文小言1:
  • React的基本知识:事件监听器、Props和State的区分、改变state的方法、使用回调函数改变state、使用三元运算符改变state
  • repmgr安装及常用运维指令
  • 部署一套开源客服系统,用户需要准备什么设备?
  • linux命令之openssl用法
  • 重绘重排、CSS树DOM树渲染树、动画加速 ✅
  • 原生Android调用uniapp项目中的方法
  • 引用类型的局部变量线程安全问题分析——以多线程对方法局部变量List类型对象实例的add、remove操作为例
  • node.js中使用express.static()托管静态资源
  • Java项目实战II基于微信小程序的南宁周边乡村游平台(开发文档+数据库+源码)
  • 工业边缘计算网关在生产设备数据采集中的应用
  • C51数字时钟/日历---LCD1602液晶显示屏
  • 线性代数的发展简史
  • 7-10 解一元二次方程
  • Android 数据处理 ------ BigDecimal
  • 【什么是RabbitMQ】
  • Flink学习连载第二篇-使用flink编写WordCount(多种情况演示)
  • TCL大数据面试题及参考答案
  • HTML 元素类型介绍
  • Python3.9.13与深度学习框架TensorFlow的完整详细安装教程
  • Charles抓包工具-笔记
  • MyBatis 的多对一,一对多以及多对多的增删改查的xml映射语句
  • (Keil)MDK-ARM各种优化选项详细说明、实际应用及拓展内容
  • 【Github】如何使用Git将本地项目上传到Github