当前位置: 首页 > 编程日记 > 正文

如何利用 C# 实现神经网络的感知器模型?

前几天我们介绍了 如何利用 C# 对神经网络模型进行抽象,在这篇图文中,我们抽象了单个神经元 Neuro,网络层 Layer,网络结构 Network,激活函数 IActivationFunction,以及监督学习 ISupervisedLearning 和非监督学习 IUnsupervisedLearning 算法。通过这些抽象,我们可以得到关于神经网络的整体框架。

今天,我们就在此基础上来继承或实现这些抽象类和接口,构造最简单的一种神经网络模型 —— 单层感知器,即用感知器学习算法训练的单层神经网络。


感知器学习算法

该学习算法用于训练具有阈值激活功能的激活神经元单层神经网络。感知器是一种线性分类器,它根据将一组权重与特征向量相结合的线性预测函数进行预测。详细的算法可以参考维基百科中的相关部分:

https://en.wikipedia.org/wiki/Perceptron

感知器


上面,我们简要的介绍了感知器学习算法,接下来我们写相应的代码。

1. 实现激活函数 IActivationFunction

通常情况下感知器神经网络的激活函数有两种,第一种是阈值函数,第二种是符号函数。

阈值函数:

public class ThresholdFunction : IActivationFunction
{public double Function(double x){return (x >= 0) ? 1 : 0;}public double Derivative(double x){return 0;}public double Derivative2(double y){return 0;}
}

符号函数:

public class SignFunction : IActivationFunction
{public double Function(double x){return x >= 0 ? 1 : -1;}public double Derivative(double x){return 0;}public double Derivative2(double y){return 0;}
}

2. 继承抽象神经元类 Neuron

public class ActivationNeuron : Neuron
{// 阈值public double Threshold { get; set; } = 0.0;// 激活函数public IActivationFunction ActivationFunction { get; set; }// 构造函数public ActivationNeuron(int inputs, IActivationFunction function): base(inputs){ActivationFunction = function;}// 初始化权值阈值public override void Randomize(){base.Randomize();Threshold = Rand.NextDouble()*(RandRange.Length) + RandRange.Min;}// 计算神经元的输出public override double Compute(double[] input){if (input.Length != InputsCount)throw new ArgumentException("输入向量的长度错误。");double sum = 0.0;for (int i = 0; i < Weights.Length; i++){sum += Weights[i]*input[i];}sum += Threshold;double output = ActivationFunction.Function(sum);Output = output;return output;}
}

3. 继承抽象神经网络层类 Layer

该类的主要作用是:实例化该层中的每个神经元,并为每个神经元设置激活函数。

public class ActivationLayer : Layer
{public ActivationLayer(int neuronsCount, int inputsCount, IActivationFunction function): base(neuronsCount, inputsCount){for (int i = 0; i < Neurons.Length; i++)Neurons[i] = new ActivationNeuron(inputsCount, function);}public void SetActivationFunction(IActivationFunction function){for (int i = 0; i < Neurons.Length; i++){((ActivationNeuron)Neurons[i]).ActivationFunction = function;}}
}

4. 继承抽象的神经网络类 Network

public class ActivationNetwork : Network
{public ActivationNetwork(IActivationFunction function, int inputsCount, params int[] neuronsCount): base(inputsCount, neuronsCount.Length){// neuronsCount 指定神经网络每层中的神经元数量。for (int i = 0; i < Layers.Length; i++){Layers[i] = new ActivationLayer(neuronsCount[i],(i == 0) ? inputsCount : neuronsCount[i - 1],function);}}public void SetActivationFunction(IActivationFunction function){for (int i = 0; i < Layers.Length; i++){((ActivationLayer)Layers[i]).SetActivationFunction(function);}}
}

写完这个激活网络的实体类 ActivationNetwork 之后,我们就可以构造神经网络的结构了。

ActivationNetwork network = new ActivationNetwork(new SigmoidFunction(), // sigmoid 激活函数3, // 3个输入new int[] {4, 1} //两层 中间层4个神经元,输出层1个神经元);

5. 实现感知器学习规则。

由于感知器学习是有监督学习,所以要实现 ISuperviseLearning 接口。

public class PerceptronLearning : ISupervisedLearning
{// 神经网络private readonly ActivationNetwork _network;// 学习率private double _learningRate = 0.1;// 学习率, [0, 1].public double LearningRate{get { return _learningRate; }set{_learningRate = Math.Max(0.0, Math.Min(1.0, value));}}public PerceptronLearning(ActivationNetwork network){if (network.Layers.Length != 1){throw new ArgumentException("无效的神经网络,它应该只有一层。");}_network = network;}// 单个训练样本public double Run(double[] input, double[] output){double[] networkOutput = _network.Compute(input);Layer layer = _network.Layers[0];double error = 0.0;for (int j = 0; j < layer.Neurons.Length; j++){double e = output[j] - networkOutput[j];if (e != 0){ActivationNeuron perceptron = layer.Neurons[j] as ActivationNeuron;if (perceptron == null)throw new Exception("神经元为null。");for (int i = 0; i < perceptron.Weights.Length; i++){perceptron.Weights[i] += _learningRate * e * input[i];}perceptron.Threshold += _learningRate * e;error += Math.Abs(e);}}return error;}// 所有训练样本public double RunEpoch(double[][] input, double[][] output){double error = 0.0;for (int i = 0, n = input.Length; i < n; i++){error += Run(input[i], output[i]);}return error;}
}

6. 感知器模型的应用

首先,我们利用感知器模型处理and问题。

double[][] inputs = new double[4][];
double[][] outputs = new double[4][];//(0,0);(0,1);(1,0)
inputs[0] = new double[] {0, 0};
inputs[1] = new double[] {0, 1};
inputs[2] = new double[] {1, 0};outputs[0] = new double[] {0};
outputs[1] = new double[] {0};
outputs[2] = new double[] {0};//(1,1)
inputs[3] = new double[] {1, 1};
outputs[3] = new double[] {1};ActivationNetwork network = new ActivationNetwork(new ThresholdFunction(), 2, 1);PerceptronLearning teacher = new PerceptronLearning(network);
teacher.LearningRate = 0.1;int iteration = 1;
while (true)
{double error = teacher.RunEpoch(inputs, outputs);Console.WriteLine(@"迭代次数:{0},总体误差:{1}", iteration, error);if (error == 0)break;iteration++;
}Console.WriteLine();ActivationNeuron neuron = network.Layers[0].Neurons[0] as ActivationNeuron;Console.WriteLine(@"Weight 1:{0}", neuron.Weights[0].ToString("F3"));
Console.WriteLine(@"Weight 2:{0}", neuron.Weights[1].ToString("F3"));
Console.WriteLine(@"Threshold:{0}", neuron.Threshold.ToString("F3"));

得到结果如下图所示:

and

其次,我们利用感知器模型处理or问题。

double[][] inputs = new double[4][];
double[][] outputs = new double[4][];//(0,0)
inputs[0] = new double[] {0, 0};
outputs[0] = new double[] {0};//(1,1);(0,1);(1,0)
inputs[1] = new double[] {0, 1};
inputs[2] = new double[] {1, 0};
inputs[3] = new double[] {1, 1};outputs[1] = new double[] {1};
outputs[2] = new double[] {1};
outputs[3] = new double[] {1};ActivationNetwork network = new ActivationNetwork(new ThresholdFunction(), 2, 1);PerceptronLearning teacher = new PerceptronLearning(network);
teacher.LearningRate = 0.1;int iteration = 1;
while (true)
{double error = teacher.RunEpoch(inputs, outputs);Console.WriteLine(@"迭代次数:{0},总体误差:{1}", iteration, error);if (error == 0)break;iteration++;
}Console.WriteLine();
ActivationNeuron neuron = network.Layers[0].Neurons[0] as ActivationNeuron;Console.WriteLine(@"Weight 1:{0}", neuron.Weights[0].ToString("F3"));
Console.WriteLine(@"Weight 2:{0}", neuron.Weights[1].ToString("F3"));
Console.WriteLine(@"Threshold:{0}", neuron.Threshold.ToString("F3"));

得到结果如下图所示:
or

最后,我们处理一个稍微复杂一些的问题,比如有以下三类数据:

第一类:(0.1,0.1);(0.2,0.3);(0.3,0.4);(0.1,0.3);(0.2,0.5)第二类:(0.1,1.0);(0.2,1.1);(0.3,0.9);(0.4,0.8);(0.2,0.9)第三类:(1.0,0.4);(0.9,0.5);(0.8,0.6);(0.9,0.4);(1.0,0.5)

我们用 ECharts 把这三类数据用不同的颜色表示:

原始数据

通常情况下,这些数据会存储在文件中,这里为了演示方便,我们手动赋值了。

double[][] inputs = new double[15][];
double[][] outputs = new double[15][];//(0.1,0.1);(0.2,0.3);(0.3,0.4);(0.1,0.3);(0.2,0.5)
inputs[0] = new double[] {0.1, 0.1};
inputs[1] = new double[] {0.2, 0.3};
inputs[2] = new double[] {0.3, 0.4};
inputs[3] = new double[] {0.1, 0.3};
inputs[4] = new double[] {0.2, 0.5};outputs[0] = new double[] {1, 0, 0};
outputs[1] = new double[] {1, 0, 0};
outputs[2] = new double[] {1, 0, 0};
outputs[3] = new double[] {1, 0, 0};
outputs[4] = new double[] {1, 0, 0};//(0.1,1.0);(0.2,1.1);(0.3,0.9);(0.4,0.8);(0.2,0.9)
inputs[5] = new double[] {0.1, 1.0};
inputs[6] = new double[] {0.2, 1.1};
inputs[7] = new double[] {0.3, 0.9};
inputs[8] = new double[] {0.4, 0.8};
inputs[9] = new double[] {0.2, 0.9};outputs[5] = new double[] {0, 1, 0};
outputs[6] = new double[] {0, 1, 0};
outputs[7] = new double[] {0, 1, 0};
outputs[8] = new double[] {0, 1, 0};
outputs[9] = new double[] {0, 1, 0};//(1.0,0.4);(0.9,0.5);(0.8,0.6);(0.9,0.4);(1.0,0.5)
inputs[10] = new double[] {1.0, 0.4};
inputs[11] = new double[] {0.9, 0.5};
inputs[12] = new double[] {0.8, 0.6};
inputs[13] = new double[] {0.9, 0.4};
inputs[14] = new double[] {1.0, 0.5};outputs[10] = new double[] {0, 0, 1};
outputs[11] = new double[] {0, 0, 1};
outputs[12] = new double[] {0, 0, 1};
outputs[13] = new double[] {0, 0, 1};
outputs[14] = new double[] {0, 0, 1};

搭建感知器网络,输入数为2,输出层神经元个数为分类数3,并进行训练。

ActivationNetwork network = new ActivationNetwork(new ThresholdFunction(), 2, 3);PerceptronLearning teacher = new PerceptronLearning(network);
teacher.LearningRate = 0.1;int iteration = 1;while (true)
{double error = teacher.RunEpoch(inputs, outputs);Console.WriteLine(@"迭代次数:{0},总体误差:{1}", iteration, error);if (error == 0)break;iteration++;
}

迭代误差

输出感知器的权值和阈值,通过这两个值我们就能得到三条分割直线。

ActivationLayer layer = network.Layers[0] as ActivationLayer;
for (int i = 0; i < 3; i++)
{Console.WriteLine(@"神经元:{0}", i + 1);Console.WriteLine(@"Weight 1:{0}", layer.Neurons[i].Weights[0]);Console.WriteLine(@"Weight 2:{0}", layer.Neurons[i].Weights[1]);Console.WriteLine(@"Threshold:{0}",((ActivationNeuron) layer.Neurons[i]).Threshold);
}

分割线


通过以上讲解,我们就把感知器神经网络搞定了。该网络可以处理andor等线性可分问题,也可以处理一些简单的多分类问题。但对线性不可分问题就无能为力了。后面我们会介绍误差反传网络的实现,通过这种网络可以进行非线性可分的分类问题。好了今天就到这里吧!See You!

相关文章:

JPA增删改查,

2019独角兽企业重金招聘Python工程师标准>>> 1. //And --- 等价于 SQL 中的 and 关键字 public List<User> findByHeightAndSex(int height,char sex); 2. // Or --- 等价于 SQL 中的 or 关键字 public List<User> findByHeightOrSex(int height,cha…

Java新手会遇到的三大误区,一定要避免!

很多学习java技术的学员都是零基础学员&#xff0c;之前对java技术一点都不了解&#xff0c;所以java新手在学习java技术的时候很容易进入误区&#xff0c;下面小编分享的Java新手会遇到的三大误区&#xff0c;一定要避免! 作为目前最为广泛的网络编程语&#xff0c;Java凭借其…

[ACM] hdu 1253 胜利大逃亡 (三维BFS)

胜利大逃亡 Problem DescriptionIgnatius被魔王抓走了,有一天魔王出差去了,这但是Ignatius逃亡的好机会.魔王住在一个城堡里,城堡是一个A*B*C的立方体,能够被表示成A个B*C的矩阵,刚開始Ignatius被关在(0,0,0)的位置,离开城堡的门在(A-1,B-1,C-1)的位置,如今知道魔王将在T分钟后…

如何利用 C# 爬取带 Token 验证的网站数据?

在对文本数据的情感分析中&#xff0c;基于情感词典的方法是最简单也是最常用的一种了。 它的大体思路如下&#xff1a; 对文档分词&#xff0c;找出文档中的情感词、否定词以及程度副词&#xff0c;然后判断每个情感词之前是否有否定词及程度副词&#xff0c;将它之前的否定…

多线程显示运行状态

最近碰见一个例子&#xff0c;Copy大文件或者网络访问的时候处理假死。 那就用多线程加个进度条(只显示运行&#xff0c;没有进度)来表示状态运行吧。好了&#xff0c;废话少说&#xff0c;上个例子。先看结果图&#xff1a; 程序说明&#xff1a; 点击Button&#xff0c;运行…

【Python培训基础知识】单例模式

单例模式是保证一个类仅有一个实例的设计模式。Windows中的任务管理器就是一个典型的单例模式软件。Windows任务管理器如图所示。 Windows任务管理器只能打开一个&#xff0c;即使用户重复打开&#xff0c;也只能获得一个实例&#xff0c;这不同于Word等软件可以打开多个实例。…

Android读写XML(上)

XML 经常用作 Internet 上的一种数据格式&#xff0c;其文件格式想必大家都比较清楚&#xff0c;在这里我结合Android平台&#xff0c;来说明Android SDK提供的读写XML的package。 首先介绍下Android SDK与Java SDK在读写XML文件方面&#xff0c;数据包之间的关系。Android 平台…

Lighttpd1.4.20源代码分析 笔记 状态机之错误处理和连接关闭

这里所说的错误有两种&#xff1a; 1.http协议规定的错误&#xff0c;如404错误。 2.server执行过程中的错误。如write错误。 对于http协议规定的错误&#xff0c;这里的“错误”是针对client的。lighttpd返回相应的错误提示文件之后&#xff0c;相当于顺利的完毕了一次请求&…

资料分享:送你一本《数据结构(C语言版)》电子书!

要想写出可复用、可扩展、易维护、灵活性好的代码&#xff0c;「数据结构」这一关必须要过啊&#xff01; 在数据结构与算法的众多教材中&#xff0c;奉为经典的当属清华大学严蔚敏老师的著作。很多学校也选择这本书作为考研指定教材。 正在学习数据结构与算法这门课程的同学…

零基础学python培训需要学习多久?

Python是一种入门比较简单的编程语言&#xff0c;但是如果是零基础学员&#xff0c;学习起来还是需要时间的&#xff0c;那么零基础学python培训需要学习多久呢?我们来看看小编的详细介绍吧。 零基础学python培训需要学习多久? 现在的培训机构&#xff0c;一般Python的培训时…

拖动无标题窗体

方法一&#xff1a; 当用户点击窗体的时候欺骗系统&#xff0c;用户是点在标题栏上&#xff0c;这样就完成了无标题栏窗体的拖动&#xff0c;实现如下&#xff1a; 在 MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest) 这个函数的方法里 &#xff1a; LRESULT CNyWnd::OnNcHitTest(…

如何利用 C# 爬取Gate.io交易所的公告!

对于大部分程序员来说&#xff0c;都希望自己或多或少拥有一些比特币&#xff08;BTC&#xff09;。获取 BTC 的途径除了挖矿计算 Hash 值之外&#xff0c;就是去交易所购买了。 由于 BTC 的价格波动非常剧烈&#xff0c;入手 BTC 的时机就显得尤为关键。在交易所搞活动时入手…

人的原罪、本我和超我

摘自&#xff1a;https://www.zhihu.com/question/31362451/answer/51606300人的原罪的存在&#xff0c;因为人人皆有&#xff0c;所以在潜意识中&#xff0c;形成了对本我的接纳&#xff0c;而神爱世人与宽恕的存在&#xff0c;形成了本我与超我的良性互动。 在这样的关系中&a…

软件测试的准入准出是什么?标准是什么?

测试的准入准出是指什么情况下可以开始当前版本的测试工作&#xff0c;什么情况下可以结束当前版本的测试工作。不同项目、不同公司的测试准入准出标准都会有所不同。下面介绍一些通用的测试准入准出标准。 测试准入标准如下&#xff1a; (1)开发编码结束&#xff0c;开发人员在…

如何利用 C# 爬取 One 持有者返利数据!

去年&#xff0c;10月份写过一篇图文 「One」的投资价值分析&#xff0c;多半年过去了&#xff0c;回头看看当时的判断还是合理的。 投资这种事情需要有自己的策略&#xff0c;更需要理性。任何决策都需要以数据作为判断的基础&#xff0c;哪么是否还继续持有 ONE呢&#xff1f…

04.微博消息的语言检测

04.微博消息的语言检测 郑昀 201010 隶属于《02.数据解析》小节 大意是&#xff0c;封装Google语言检测ajax web service的接口&#xff0c;输入一段话&#xff0c;输出语言种类。这个方法是从RssMeme.com看来的&#xff0c;经测试效果还不错&#xff0c;可用于检测微博客消息的…

CIO时代学院院长姚乐:传统行业遇上大数据 拥抱智能化未来

近几年&#xff0c;互联网行业发展突飞猛进&#xff0c;“大数据”技术瞬间变得炙手可热&#xff0c;当然&#xff0c;对于发展中的大数据技术而言&#xff0c;很多行业都不会错失良机。近日&#xff0c;CIO时代学院院长、中国新一代IT产业推进联盟秘书长姚乐在“2016CIO时代中…

自动化测试的优势和局限性有哪些

自动化测试只是众多测试中的一种&#xff0c;并不比人工测试更高级更先进。和人工测试相比自动化测试有一定的优势和劣势&#xff0c;具体如下。 1.优势 (1)自动化测试具有一致性和重复性的特点&#xff0c;而且测试更客观&#xff0c;提高了软件测试的准确度、精确度和可信任度…

也分享一个存储过程代码生成器 开源

可以通过 FILE>OPTION 修改前缀&#xff0c;作者等信息。。。。。 完全傻瓜式应用&#xff0c;开源&#xff0c;方便进行个性化开发。。。 工具地址&#xff1a;http://spgen.codeplex.com/ Stored Procedure Generator (for SQL Server 2000/2005) 虽然这样写&#xff0c;但…

如何利用 C# 爬取BigOne交易所的公告!

在当今这个时代&#xff0c;投资可以说是每个人都应该学会的一项技能。拥有一些数字货币是程序员的信仰&#xff01;交易所是进入数字货币世界最方便的一扇门&#xff0c;今天我就带着大家爬取 Bigone 交易所的公告数据。 首先&#xff0c;我们来看一下要爬取的页面以及对应的…

如何提升自己的Web前端技术

如何提升自己的Web前端技术?问这个问题的一般都是有一些web基础的同学&#xff0c;还有一部分是自学的web前端技术&#xff0c;对自己目前的能力还比较模糊&#xff0c;下面小编就这个问题为大家做下详细的介绍。 如何提升自己的Web前端技术?在IT行业&#xff0c;任何一种专业…

tomcat 性能设置

Tomcat性能调优&#xff1a; 找到Tomcat根目录下的conf目录&#xff0c;修改server.xml文件的内容。对于这部分的调优&#xff0c;我所了解到的就是无非设置一下Tomcat服务器的最大并发数和Tomcat初始化时创建的线程数的设置&#xff0c;当然还有其他一些性能调优的设置&#x…

SAP的安装后基本设定

SAPLogon登录时候是乱码,设定登陆配置的代码页属性&#xff0c;勾选Unicode off SAP英文系统下中文显示乱码 设定字符集为GB2312 RZ10常用的配置参数rz10 编辑系统参数文件 rdisp/gui_auto_logout & rdisp/keepalive 用于控制闲置时间(秒) login/system_client 用于控制默认…

如何通过 Scratch 教小朋友编程思维?

寒假的时候&#xff0c;我带着自己的小孩学 Scratch&#xff0c;希望通过这种图形化的语言来训练他的编程思维。开学之后&#xff0c;很多事情需要处理&#xff0c;所以拖到现在才写总结。希望对大家有所启发。 在介绍如何做这件事情之前&#xff0c;先介绍一个学习方面的基本…

零基础怎么学习UI设计?有哪些简单的学习方法?

UI设计近几年的就业前景是非常好的&#xff0c;所以很多人都想要学习UI设计&#xff0c;那么零基础怎么学习UI设计?有哪些简单的学习方法?下面小编就给大家做下详细的介绍。 零基础怎么学习UI设计?有哪些简单的学习方法? UI设计行业是很注重技术的&#xff0c;零基础如果直…

让资源管理器不显示最近常用文件夹

右键点任务栏&#xff0c;点“属性”->Startmenu->在Privacy框中&#xff0c;把第二个√ 去掉&#xff0c;如下图所示&#xff1a;

C# 写Windows服务

服务是一个运行在后台的程序&#xff0c;他没有界面&#xff0c;不能交互&#xff0c;只能孤独的独自运行。 在开始->运行->输入services.msc可以打开服务管理器&#xff0c;这里可以查看和管理服务   很多时候都会用到服务&#xff0c;因为服务简化了我们的操作&#…

技术图文:如何利用 C# 爬取 ONE 的交易数据?

投资一个金融产品&#xff0c;最基本的就是拿到这个金融产品的交易数据&#xff0c;对这些数据进行可视化来判断趋势。去年&#xff0c;我在听 李笑来 讲区块链的课程上知道了 BigOne 这个由 INB 投资的交易所&#xff0c;而 ONE 是 BigOne 的平台币&#xff0c;持有 ONE 可享受…

java程序猿必读的学习书籍,良心推荐!

每年都有很多人想要学习java技术&#xff0c;有的是自学&#xff0c;有的是报班学习&#xff0c;但是都免不了要看书籍学习&#xff0c;书籍学习带来的知识更加牢记&#xff0c;也可以随时做笔记&#xff0c;下面小编就为大家推荐java程序猿必读的学习书籍&#xff0c;希望能帮…

Autools学习总结(一)

一、Makefile 简介 在编写C/C程序的时候&#xff0c;我们经常需要编译并运行代码。在程序规模较小的情况下&#xff0c;可以简单地直接调用编译器来完成这项工作。然而&#xff0c;在很多情况下程序往往包括大量的代码文件&#xff0c;手动调用编译器变得麻烦无比。尤其要命的是…