神经网络计算简单的加法运算
神经网络
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.IO; using ElemType = System.Double; //ElemType 元素的类型//默认是int型//别名 using Status = System.Int32; //Status 现状;状态;地位 namespace BP { class DPNet { #region 定义变量 /// <summary> /// 网络层数 /// </summary> protected int layerNum; /// <summary> /// 每层节点数 /// </summary> protected int[] nodeNumEachLayer; /// <summary> /// 权重 w /// </summary> protected double[,,] weight; /// <summary> /// 权重增量 /// </summary> protected double[,,] deltaWeight; /// <summary> /// 节点 /// </summary> protected ElemType[,] node; /// <summary> /// 增量 /// </summary> //protected ElemType[,] delta; /// <summary> /// 训练数量 /// </summary> protected ElemType[] testNumber; /// <summary> /// 输入 /// </summary> protected ElemType[,] input; /// <summary> /// 输出 /// </summary> protected ElemType[,] output; /// <summary> /// 样本数量 /// </summary> protected int sampleNum; /// <summary> /// 学习效率 /// </summary> private double learningRate; /// <summary> /// 学习动量 /// </summary> private double learningMomentum; //学习动量,相当于每次更新的时候,都会考虑上次的更新值,如果方向一样就变得越来越快,如果方向不同,就会相互抵消,以便收敛 /// <summary> /// 各个节点误差 /// </summary> protected ElemType[,] layerErr;// //protected ElemType [,] /// <summary> /// 学习效率 /// </summary> public double LearningRate { get { return learningRate; } set { if (learningRate <= 1.0 || learningRate > 0)//学习效率要在0-1之间 { learningRate = value; } else { Console.WriteLine("学习速率为非法值,本次改动无效"); } } } public double LearningMomentum { get { return learningMomentum; } set { if (learningRate <= 1.0 || learningRate > 0) { learningMomentum = value; } else { Console.WriteLine("学习动量为非法值,本次改动无效"); } } } #endregion #region 网络初始化 DPNet() /// <summary> /// 网络初始化 /// </summary> public DPNet() { layerNum = 0; //网络层数 learningRate = 0.7; //学习效率 learningMomentum = 0.9; //学习动量 sampleNum = 0; //样本数量 nodeNumEachLayer = null;// weight = null; deltaWeight = null; // delta = null; testNumber = null; node = null; input = null; output = null; layerErr = null; } #endregion #region 创建网络 CreateNet() /// <summary> /// 创建网络 /// </summary> /// <param name="nums"></param> /// <returns></returns> public Status CreateNet(params int[] nums) //params 参数//(3,2,8,1) { //FreeNet//检查网络层数//这里应该默认至少有一层隐藏层 if (nums[0] <= 2) { Console.WriteLine("非法的神经网络层数"); return -1; } layerNum = nums[0]; nodeNumEachLayer = new int[layerNum];//通过一个数组保存每一层的节点数 int maxNode = 0; //最大节点数 for (int i = 0; i < layerNum; i++) { if (nums[i + 1] >= 1) // nums[i + 1]括号中的第i+1个元素//最少有一个节点,没有节点也就意味着没有有效的网络层 //(网络层数,输入层,隐藏层1节点,.....,隐藏层n节点,输出层节点) { if (maxNode < nums[i + 1]) //获取最大节点数 { maxNode = nums[i + 1]; } nodeNumEachLayer[i] = nums[i + 1] + 1; //加了1个偏置项 } else { Console.WriteLine("非法的节点数"); return -1; } } maxNode++; //添加一个偏置项 weight = new double[layerNum, maxNode, maxNode];//权重[网络层数,节点数,节点权重] deltaWeight = new double[layerNum, maxNode, maxNode];//权重增量[网络层数,节点数,节点权重增量] layerErr = new double[layerNum, maxNode]; //误差= [网络层数,最大节点数] node = new ElemType[layerNum, maxNode]; //节点= [网络层数,最大节点数] //delta = new ElemType[layerNum, maxNode]; Random random = new Random(); //随机初始化w for (int i = 0; i < layerNum - 1; i++) //-1 是因为w[]和d[]只有总网络层数-1维 { for (int j = 0; j < nodeNumEachLayer[i + 1]; j++) //下一层的每个节点 { for (int k = 0; k < nodeNumEachLayer[i]; k++) //上一层的每个节点 { weight[i, j, k] = random.NextDouble(); //do //{ // weight[i, j, k] = random.NextDouble() * 2 - 1.0;//每个权重赋值,范围0-1之间 //} //while (Math.Abs(weight[i, j, k]) < 1e-6); //如果w[]绝对值小于1x10的-6次方//Math.abs(n):对int、long、float、double类型的数取绝对值 // deltaWeight[i, j, k] = 0.0; //权重增量不变 } } } return 0; //return 0 代表正常退出,main函数还给操作系统 } #endregion #region 加载样本数据文件 LoadSimplesFromFile() /// <summary> /// 加载样本数据文件 /// </summary> /// <param name="fileName"></param> /// <returns></returns> public Status LoadSimplesFromFile(String fileName) { //Free string fileContent = File.ReadAllText(fileName); if (fileContent == null) { Console.WriteLine("未能成功打开样例文件"); return -1; } string[] integerStrings = fileContent.Split //通过分割获取样本数据 (new char[] { ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); sampleNum = int.Parse(integerStrings[0]); //数组一个元素为样本数量 int inputNodeNum = int.Parse(integerStrings[1]); //第二个元素为输入节点数 int outputNodeNum = int.Parse(integerStrings[2]); //第三个元素为输出节点数 input = new ElemType[sampleNum, inputNodeNum]; output = new ElemType[sampleNum, outputNodeNum]; if (input == null || output == null) { Console.WriteLine("创建input output数组失败"); return -1; } int numIndex = 3;//为后面索引从第4个元素开始 for (int i = 0; i < sampleNum; i++) { for (int j = 0; j < inputNodeNum; j++)//第i个样本的输入数据为 { input[i, j] = ElemType.Parse(integerStrings[numIndex]); numIndex++; } for (int k = 0; k < outputNodeNum; k++)//第i个样本的输出数据为 { output[i, k] = ElemType.Parse(integerStrings[numIndex]); numIndex++; } } return 0; } #endregion #region 训练单个样本 TrainSingleSample() /// <summary> /// 训练单个样本 /// </summary> /// <param name="sampleIndex">样本在数组中的位置</param> /// <returns></returns> public double TrainSingleSample(int sampleIndex) { //赋值 int i; for (i = 0; i < nodeNumEachLayer[0] - 1; i++)//第一层网络,输入训练数据赋值 { node[0, i] = input[sampleIndex, i]; } node[0, nodeNumEachLayer[0] - 1] = 1;//偏置项为1 //前(正)向计算 for (i = 1; i < layerNum; i++) { int j; for (j = 0; j < nodeNumEachLayer[i] - 1; j++) { node[i, j] = 0; for (int k = 0; k < nodeNumEachLayer[i - 1]; k++) { node[i, j] += node[i - 1, k] * weight[i - 1, j, k];//net1=x1*w1+x2*w2 } node[i, j] /= (nodeNumEachLayer[i - 1]);//平均分配???? node[i, j] = 1.0 / (1.0 + Math.Exp(-node[i, j])); //sigmoid激活函数,正向传播 } node[i, j] = 1;//每层最后都有一个偏置项 } //反向计算,根据误差修改权重w i = layerNum - 1; for (int j = 0; j < nodeNumEachLayer[i] - 1; j++) { layerErr [i, j] = node[i, j] * (1 - node[i, j]) * (node[i, j] - output[sampleIndex, j]);//o1*(1-01)*(01 - y) } int avoidThreshold = 1; for (i = layerNum - 2; i > 0; i--) { for (int j = 0; j < nodeNumEachLayer[i]; j++) { layerErr [i, j] = 0; int k = 0; for (k = 0; k < nodeNumEachLayer[i + 1] - avoidThreshold; k++) { layerErr[i, j] += (weight[i, k, j] * layerErr [i + 1, k]);//上一层的误差= } layerErr [i, j] *= (node[i, k] * (1.0 - node[i, k]));//记录误差 } avoidThreshold = 0;//避免阈值 } for (i = 0; i < layerNum - 1; i++) { if (i == layerNum - 2) avoidThreshold = 1; for (int j = 0; j < nodeNumEachLayer[i + 1] - avoidThreshold; j++) { for (int k = 0; k < nodeNumEachLayer[i]; k++) //更新权重 i 网络层数;j该层网络的节点数,k 各个节点的权重w { weight[i, j, k] += learningMomentum * deltaWeight[i, j, k]; weight[i, j, k] -= learningRate * layerErr [i + 1, j] * node[i, k];//调整隐藏层权重 deltaWeight[i, j, k] = learningMomentum * deltaWeight[i, j, k] - learningRate * layerErr [i + 1, j] * node[i, k];//更新后的权重//隐含层动量调整//学习动量x变换权重-学习效率 } } } ElemType error = 0; for (i = 0; i < nodeNumEachLayer[layerNum - 1] - 1; i++) { error += Math.Pow((node[layerNum - 1, i] - output[sampleIndex, i]), 2.0);//Loss损失函数 } error /= 2.0; return error; } #endregion #region 训练 Train() /// <summary> /// 训练 /// </summary> /// <param name="maxTurn">最大训练次数</param> /// <param name="allowedError"></param> /// <returns></returns> public Status Train(int maxTurn, ElemType allowedError) { for (int i = 0; i < maxTurn; i++) { Console.WriteLine("正在进行第" + (i + 1) + "次训练"); ElemType error = 0; for (int j = 0; j < sampleNum; j++) { error += TrainSingleSample(j); //误差累积 } error /= sampleNum; Console.WriteLine("本轮误差" + error); if (error < allowedError) { Console.WriteLine("已达到允许误差值"); return 0; } } Console.WriteLine("已达到最大训练数量"); return 0; } #endregion #region 测试 Test() /// <summary> /// 测试 /// </summary> /// <param name="testInput"></param> /// <param name="testOutput"></param> /// <returns></returns> public Status Test(ElemType[] testInput, ElemType[] testOutput) { int i; for (i = 0; i < nodeNumEachLayer[0] - 1; i++)//-1,偏置项 { node[0, i] = testInput[i]; } node[0, nodeNumEachLayer[0] - 1] = 1;//偏置项 for (i = 1; i < layerNum; i++)//计算每层的输出值 { int j; for (j = 0; j < nodeNumEachLayer[i] - 1; j++) { node[i, j] = 0; for (int k = 0; k < nodeNumEachLayer[i - 1]; k++)// { node[i, j] += node[i - 1, k] * weight[i - 1, j, k]; } node[i, j] /= (nodeNumEachLayer[i - 1]); node[i, j] = 1.0 / (1.0 + Math.Exp(-node[i, j])); } node[i, j] = 1; } for (i = 0; i < nodeNumEachLayer[layerNum - 1] - 1; i++)//给testOutput赋值 { testOutput[i] = node[layerNum - 1, i]; } return 0; } #endregion } }
程序主入口
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using ElemType = System.Double; namespace BP { class BPTest { static void Main(string[] args) { DPNet dpNet = new DPNet(); String filename = "E:\\test\\BPNet-simple-plus--master\\sample.txt";//样本数据文件路径 dpNet.LoadSimplesFromFile(filename); //加载样本数据文件 dpNet.CreateNet(3, 2, 8, 1); //(网络层数,输入层,隐藏层1节点,.....,隐藏层n节点,输出层节点) dpNet.Train(19999, 1e-6); //训练次数9999,精度为1x10的负5次方 dpNet.LearningMomentum=0.5; ElemType[] input = new ElemType[2];//两个输入数据 ElemType[] output = new ElemType[1];//一个输出数据 //ElemType[] forecastInput = new ElemType[2]; //double forecastOutput = 0; while (true) { //读取数据 string str = Console.ReadLine(); string[] sGroup = str.Split(' '); input[0] = double.Parse(sGroup[0]); input[1] = double.Parse(sGroup[1]); dpNet.Test(input, output); Console.WriteLine(output[0] + "\n"); } //Console.WriteLine("请输入您想要的第一个预测数据(三位有效数字):"); //forecastInput [0] = Convert.ToDouble(Console.ReadLine()); //Console.WriteLine("请输入您想要的第二个预测数据(三位有效数字):"); //forecastInput[1] = Convert.ToDouble(Console.ReadLine()); //dpNet.Forecast (forecastInput); //Console.WriteLine(output); //Console.ReadKey(); } } }
本文来自博客园,作者:季夏啸华,转载请注明原文链接:https://www.cnblogs.com/jiang2020/p/12606782.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理