zoukankan      html  css  js  c++  java
  • 神经网络计算简单的加法运算

    神经网络

    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[] { ' ', '	', '
    ', '
    ' }, 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] + "
    ");
                }
                //Console.WriteLine("请输入您想要的第一个预测数据(三位有效数字):");
                //forecastInput [0] = Convert.ToDouble(Console.ReadLine());
                //Console.WriteLine("请输入您想要的第二个预测数据(三位有效数字):");
                //forecastInput[1] = Convert.ToDouble(Console.ReadLine());
                //dpNet.Forecast (forecastInput);
                //Console.WriteLine(output);
                //Console.ReadKey();
            }
        }
    }
  • 相关阅读:
    微信开放平台(公众号第三方平台) -- 全网发布
    SQL 邮件配置篇
    让BI告诉你:圣诞老人去哪了?
    锁定和行版本控制
    数据库质疑修复总结(转)
    抢救损坏数据库中的数据
    将 PAGE_VERIFY 数据库选项设置为 CHECKSUM
    replicate复制函数
    @@IDENTITY与SCOPE_IDENTITY()
    RESTORE DATABASE的standby选项
  • 原文地址:https://www.cnblogs.com/jiang2020/p/12606782.html
Copyright © 2011-2022 走看看