C# 从基础神经元到实现在0~9数字识别

训练图片:mnist160

测试结果:1000次训练学习率为0.1时,准确率在60%以上

学习的图片越多,训练的时候越长(比如把 epochs*10 = 10000或更高时)效果越好

using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Windows.Forms;

namespace LLM
{
   

// 定义权重类


    class Weight
    {
        private static Random random = new Random();
        public double Value { get; set; }

        public Weight()
        {
            Value = random.NextDouble() - 0.5;
        }
    }

   

// 定义神经元连接类


    class NeuronLink
    {
        public Weight Weight { get; set; }
        public Neuron FromNeuron { get; set; }
        public Neuron ToNeuron { get; set; }

        public NeuronLink(Neuron fromNeuron, Neuron toNeuron)
        {
            FromNeuron = fromNeuron;
            ToNeuron = toNeuron;
            Weight = new Weight();
        }
    }

    // 定义神经元类


    class Neuron
    {
        private static Random random = new Random();
        public double Bias { get; set; }
        public double Output { get; set; }
        public double Error { get; set; }
        public NeuronLink[] InputLinks { get; set; }

        public Neuron(int inputCount, Neuron[] previousLayerNeurons)
        {
            Bias = random.NextDouble() - 0.5;
            InputLinks = new NeuronLink[inputCount];
            for (int i = 0; i < inputCount; i++)
            {
                InputLinks[i] = new NeuronLink(previousLayerNeurons[i], this);
            }
        }

       

// 激活函数(Sigmoid)


        private double Sigmoid(double x)
        {
            return 1.0 / (1.0 + Math.Exp(-x));
        }

        // 计算神经元的输出


        public double CalculateOutput()
        {
            double sum = Bias;
            foreach (var link in InputLinks)
            {
                sum += link.FromNeuron.Output * link.Weight.Value;
            }
            Output = Sigmoid(sum);
            return Output;
        }

        // 激活函数的导数


        public double SigmoidDerivative()
        {
            return Output * (1 - Output);
        }
    }

    // 定义层类


    class Layer
    {
        public Neuron[] Neurons { get; set; }

        public Layer(int neuronCount, Layer previousLayer)
        {
            Neurons = new Neuron[neuronCount];
            if (previousLayer == null)
            {
                for (int i = 0; i < neuronCount; i++)
                {


                    // 输入层神经元没有输入连接


                    Neurons[i] = new Neuron(0, new Neuron[0]);
                }
            }
            else
            {
                for (int i = 0; i < neuronCount; i++)
                {
                    Neurons[i] = new Neuron(previousLayer.Neurons.Length, previousLayer.Neurons);
                }
            }
        }
    }

    // 定义神经网络类


    class NeuralNetwork
    {
        private Layer inputLayer;
        private Layer hiddenLayer;
        private Layer outputLayer;

        public NeuralNetwork(int inputSize, int hiddenSize, int outputSize)
        {
            inputLayer = new Layer(inputSize, null);
            hiddenLayer = new Layer(hiddenSize, inputLayer);
            outputLayer = new Layer(outputSize, hiddenLayer);
        }

        // 前向传播


        public double[] FeedForward(double[] input)
        {


            // 设置输入层神经元的输出


            for (int i = 0; i < inputLayer.Neurons.Length; i++)
            {
                inputLayer.Neurons[i].Output = input[i];
            }

            // 计算隐藏层神经元的输出


            foreach (var neuron in hiddenLayer.Neurons)
            {
                neuron.CalculateOutput();
            }

            // 计算输出层神经元的输出


            double[] outputs = new double[outputLayer.Neurons.Length];
            for (int i = 0; i < outputLayer.Neurons.Length; i++)
            {
                outputs[i] = outputLayer.Neurons[i].CalculateOutput();
            }

            return outputs;
        }

        // 训练网络


        public void Train(double[] input, double[] target, double learningRate)
        {


            // 前向传播


            double[] output = FeedForward(input);

            // 计算输出层的误差


            for (int i = 0; i < outputLayer.Neurons.Length; i++)
            {
                outputLayer.Neurons[i].Error = (target[i] - output[i]) * outputLayer.Neurons[i].SigmoidDerivative();
            }

            // 反向传播到隐藏层


            for (int j = 0; j < hiddenLayer.Neurons.Length; j++)
            {
                double errorSum = 0;
                foreach (var link in hiddenLayer.Neurons[j].InputLinks)
                {
                    errorSum += link.ToNeuron.Error * link.Weight.Value;
                }
                hiddenLayer.Neurons[j].Error = errorSum * hiddenLayer.Neurons[j].SigmoidDerivative();
            }

            // 更新输出层的权重和偏置


            foreach (var neuron in outputLayer.Neurons)
            {
                neuron.Bias += learningRate * neuron.Error;
                foreach (var link in neuron.InputLinks)
                {
                    link.Weight.Value += learningRate * neuron.Error * link.FromNeuron.Output;
                }
            }

            // 更新隐藏层的权重和偏置


            foreach (var neuron in hiddenLayer.Neurons)
            {
                neuron.Bias += learningRate * neuron.Error;
                foreach (var link in neuron.InputLinks)
                {
                    link.Weight.Value += learningRate * neuron.Error * link.FromNeuron.Output;
                }
            }
        }
    }

    // 定义训练数据对象类


    class TrainingData
    {
        public double[] Input { get; set; }
        public double[] Target { get; set; }

        public TrainingData(double[] input, double[] target)
        {
            Input = input;
            Target = target;
        }
    }

    public class Program
    {

//测试


        public static void Main()
        {
            // 假设图片是 28x28 的黑白图片,输入层大小为 28x28
            int inputSize = 28 * 28;
            int hiddenSize = 30;
            int outputSize = 10; // 识别 0 - 9 数字

            NeuralNetwork neuralNetwork = new NeuralNetwork(inputSize, hiddenSize, outputSize);

            // 创建训练数据对象数组
            string dire = Application.StartupPath + "\\mnist160\\train\\";
            string[] directories = System.IO.Directory.GetDirectories(dire);
            List<TrainingData> allTrainingData = new List<TrainingData>();
            string[] files = null;
            foreach (string directory in directories)
            {
                files = System.IO.Directory.GetFiles(directory);
                for (int i = 0; i < files.Length; i++)
                {
                    // 读取图片
                    string imagePath = files[i];
                    double[] input = ReadImageAsInput(imagePath);
                    double[] target = new double[outputSize];
                    string dirname = new DirectoryInfo(directory).Name;
                    target[int.Parse(dirname)] = 1;
                    allTrainingData.Add(new TrainingData(input, target));
                }
            }
            TrainingData[] trainingData = allTrainingData.ToArray();

            // 训练网络


            double learningRate = 0.1;
            int epochs = 1000;
            for (int epoch = 0; epoch < epochs; epoch++)
            {
                foreach (TrainingData data in trainingData)
                {
                    neuralNetwork.Train(data.Input, data.Target, learningRate);
                }
            }

            dire = Application.StartupPath + "\\mnist160\\test\\";
            directories = System.IO.Directory.GetDirectories(dire);
            foreach (string directory in directories)
            {
                files = System.IO.Directory.GetFiles(directory);


                // 测试网络


                foreach (var item in files)
                {
                    string testImagePath = item;
                    try
                    {
                        double[] testInput = ReadImageAsInput(testImagePath);
                        double[] output = neuralNetwork.FeedForward(testInput);

                        double maxVal = output[0];
                        for (int i = 1; i < output.Length; i++)
                        {
                            if (output[i] > maxVal)
                            {
                                maxVal = output[i];
                            }
                        }
                        int predictedDigit = Array.IndexOf(output, maxVal);

//输出结果


                        Console.WriteLine($"Predicted digit: {testImagePath}==={predictedDigit}");
                    }
                    catch (FileNotFoundException ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                }
            }
        }

        static double[] ReadImageAsInput(string imagePath)
        {
            if (!File.Exists(imagePath))
            {
                throw new FileNotFoundException($"Image file {imagePath} not found.");
            }

            using (Bitmap image = new Bitmap(imagePath))
            {
                double[] input = new double[28 * 28];
                int index = 0;
                for (int y = 0; y < 28; y++)
                {
                    for (int x = 0; x < 28; x++)
                    {
                        Color pixelColor = image.GetPixel(x, y);
                        // 将像素值转换为 0 到 1 之间的双精度值
                        input[index] = (pixelColor.R + pixelColor.G + pixelColor.B) / (3.0 * 255);
                        index++;
                    }
                }
                return input;
            }
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/978291.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

蓝桥杯 5.字符串

蓝桥杯 5.字符串 文章目录 蓝桥杯 5.字符串KMP&字符串哈希Manacher编程138-148字典树基础01Trie编程149-155 KMP&字符串哈希 KMP算法 字符串匹配算法, 用于匹配**模式串P(短)和文本串S(长)**中出现的所有位置, 例如, S “ababac”, P “aba”, 那么出现的所有位置就…

AI智能体与大语言模型:重塑SaaS系统的未来航向

在数字化转型的浪潮中&#xff0c;软件即服务&#xff08;SaaS&#xff09;系统一直是企业提升效率、优化业务流程的重要工具。随着AI智能体和大语言模型&#xff08;LLMs&#xff09;的迅速发展&#xff0c;SaaS系统正迎来前所未有的变革契机。本文将从AI智能体和大语言模型对…

Jmeter聚合报告导出log文档,Jmeter聚合报告导出到CSV

Jmeter聚合报告导出log文档 在Filename中输入 EKS_perf_log\\${type}_log\\${__P(UNIQUEID,${__time(YMDHMS)})}\all-graph-results-log.csv 可以得到执行的log&#xff0c;文件夹包含时间戳 Jmeter聚合报告导出到CSV 点击Save Table Data&#xff0c;保存到CSV文件中

基于SpringBoot的“古城景区管理系统”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“古城景区管理系统”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统整体功能图 系统首页界面 系统注册界面 景…

第五项修炼:打造学习型组织

“没有哪个教室比得上一个充满问题的团队。” — 彼得圣吉 最近有伙伴问我们&#xff0c;如何在组织中践行《第五项修炼&#xff1a;打造学习型组织》&#xff1f;我想和大家分享的是&#xff0c;这不仅仅是“学习”&#xff0c;更是通过结构和行为的深度结合&#xff0c;推动绩…

ubuntu22.04的docker容器中安装ssh服务

ubuntu22.04的docker容器中安装ssh服务&#xff0c;以便外部可以连接到容器中操作。 rootnode15:~# cat /etc/issue Ubuntu 22.04.5 LTS \n \l rootnode15:~# docker ps|grep qwen 7d3c36c37d36 vllm/vllm-openai:v0.7.3 "python3 -m …

LabVIEW 中 codeGenEngine.llb 工具库

codeGenEngine.llb 是 LabVIEW 2019 安装目录下C:\Program Files (x86)\National Instruments\LabVIEW 2019\vi.lib\Platform\路径下的工具库&#xff0c;主要用于代码生成相关的操作&#xff0c;帮助开发者在 LabVIEW 项目中便捷地实现自动化代码生成任务&#xff0c;提高开发…

基于LangChain4j调用火山引擎DeepSeek R1搭建RAG知识库实战指南

基于LangChain4j调用火山引擎DeepSeek R1搭建RAG知识库实战指南 基于LangChain4j调用火山引擎DeepSeek R1搭建RAG知识库实战指南 基于LangChain4j调用火山引擎DeepSeek R1搭建RAG知识库实战指南一、注册火山引擎账号二、RAG技术核心原理三、环境与工具准备1. 核心组件2. 依赖配…

基于YOLO11深度学习的医学X光骨折检测与语音提示系统【python源码+Pyqt5界面+数据集+训练代码】

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…

Unity百游修炼(2)——Brick_Breaker详细制作全流程

一、项目简介 Brick Breaker 是一款经典的打砖块游戏&#xff0c;本次案例将使用 Unity 引擎来实现该游戏的核心功能。 游戏画面如下&#xff1a; Brick_ breaker 二、项目结构概览和前期准备 &#xff08;1&#xff09;在 Unity 项目视图中&#xff0c;我们可以看到几个重要…

DeepSeek开源周Day2:DeepEP - 专为 MoE 模型设计的超高效 GPU 通信库

项目地址&#xff1a;https://github.com/deepseek-ai/DeepEP 开源日历&#xff1a;2025-02-24起 每日9AM(北京时间)更新&#xff0c;持续五天 (2/5)&#xff01; ​ ​ 引言 在大模型训练中&#xff0c;混合专家模型&#xff08;Mixture-of-Experts, MoE&#xff09;因其动…

前端面试基础知识整理(一)

1.vue生命周期 beforeCreate 创建 注入依赖 初始化非响应式数据 beforeCreate created 数据请求&#xff0c;初始化数据 设置全局时间监听 beforeMount挂载 模版编译完成后的调试 操作 dom初始化 操作dom初始化第三方插件 更新 在更新前查看 DOM 状态&#xff0c;不建议修改数据…

【单片机】MSP430MSP432入门

文章目录 0 前言1 开发方式选择2 CCS和开发相关软件3 Keil开发MSP4324 IAR for 430开发MSP4305 总结 0 前言 最近因为想学DSP&#xff0c;所以把之前卸载的CCS给装回来了&#xff0c;手头也还有之前电赛剩下的MSP430和MSP432的板子&#xff0c;由于年代久远&#xff0c;想着花点…

【Linux探索学习】第二十七弹——信号(上):Linux 信号基础详解

Linux学习笔记&#xff1a; https://blog.csdn.net/2301_80220607/category_12805278.html?spm1001.2014.3001.5482 前言&#xff1a; 前面我们已经将进程通信部分讲完了&#xff0c;现在我们来讲一个进程部分也非常重要的知识点——信号&#xff0c;信号也是进程间通信的一…

74道高级Java面试合集,java开发模式面试题

前言 今天我们来说说Redis为什么高性能&#xff1f;如何做高可用&#xff1f; Redis为什么这么快&#xff1f; Redis是单线程的&#xff0c;避免了多线程的上下文切换和并发控制开销&#xff1b;Redis大部分操作时基于内存&#xff0c;读写数据不需要磁盘I/O&#xff0c;所以速…

【江科协-STM32】5. 输出比较

1. 输出比较简介 OC(Output Compare)输出比较。 输出比较可以通过CNT&#xff08;CNT计数器&#xff09;与CCR寄存器值的关系&#xff0c;来对输出电平进行置1、置0或翻转的操作&#xff0c;用于输出一定频率和占空比的PWM波形。 :::tip CNT计数器是正向计数器。它只能正向累…

轻量级日志管理平台Grafana Loki

文章目录 轻量级日志管理平台Grafana Loki背景什么是Loki为什么使用 Grafana Loki&#xff1f;架构Log Storage Grafana部署使用基于 Docker Compose 安装 LokiMinIO K8s集群部署Loki采集Helm 部署方式和案例 参考 轻量级日志管理平台Grafana Loki 背景 在微服务以及云原生时…

使用 Postman 访问 Keycloak 端点

1. 引言 在本教程中&#xff0c;我们将首先快速回顾 OAuth 2.0、OpenID 和 Keycloak。然后&#xff0c;我们将了解 Keycloak REST API 以及如何在 Postman 中调用它们。 2. OAuth 2.0 OAuth 2.0 是一个授权框架&#xff0c;它允许经过身份验证的用户通过令牌向第三方授予访问…

WEB1~6通杀

##解题思路 这六道题&#xff0c;通杀了&#xff0c;只因为是PHP的特性 来&#xff0c;看web6&#xff0c;过滤最复杂的正则&#xff0c;而且不能解析成大于999的值&#xff0c;但是&#xff0c;php是弱类型的语言&#xff0c;我只要输入任意字符数字&#xff0c;最终值就为0&…

I2C协议简介:串行通信的关键技术

目录 一、总线通信基本概念 二、I2C总线协议介绍 1. 时序图解析 &#xff08;1&#xff09;起始信号 &#xff08;2&#xff09;应答信号 &#xff08;3&#xff09;终止信号 &#xff08;4&#xff09;设备地址 &#xff08;5&#xff09;I2C传输方法 ​编辑 &#…