带你读《C#神经网络编程》之二:构建第一个神经网络

简介: 本书旨在为C#程序员使用神经网络、CNTK等C#库和TensorFlowSharp解决复杂的计算问题时,提供实践指导。本书从神经网络入门知识开始,详细介绍如何使用Encog、Aforge和Accord搭建一个神经网络,帮助你深入理解神经网络相关概念和技术,例如深度网络、感知器、优化算法、卷积网络和自动解码器。此外,还详细讲解如何向.NET应用程序中添加智能特性,例如面部和运动检测、对象检测和标注、语言理解、知识和智能搜索。

点击查看第一章
点击查看第三章

第2章

构建第一个神经网络
现在我们已经快速地对神经网络进行了复习,这是一个好的起点,为了不让大家抓狂,我们先编写一个非常简单的神经网络。我们将为几个函数搭建基本框架,以便你更好地了解将要使用的许多API的背后详情。我们将从头到尾完整地开发一个神经网络应用程序,以便你熟悉神经网络中包含的所有基本组件。这种实现并不完美或包罗万象,也不是必须这样实现。正如我提到的,这只为本书的其余章节提供一个框架。这是一个非常基本的神经网络,具有保存及加载网络和数据的功能。这将为你打下基础,让你能够编写自己的神经网络。
在本章中,我们将讨论以下主题:

  • 神经网络训练
  • 术语
  • 突触
  • 神经元
  • 前向传播
  • Sigmoid函数
  • 后向传播
  • 误差计算

技术要求
你需要在系统上安装Microsoft Visual Studio。
观看以下视频,以了解编码过程:http://bit.ly/2NYJa5G

2.1 一个简单的神经网络

我们首先展示简单神经网络的基本形式。它由带有2个输入的输入层、带有3个神经元(有时称为节点)的隐藏层和由单个神经元组成的最终输出层构成。当然,神经网络可以包含更多层(以及每层包含更多神经元),一旦深入学习,你会见到更多,但是现在这些已经足够了。请记住,如下标有N的节点都是一个单独的神经元—做一个不恰当的比喻,它们都具有自己的大脑,如图2-1所示。

image.png

我们将神经网络分解成三个基本部分:输入层、隐藏层和输出层。
输入层:这是网络的初始数据。对于每个输入,其输出到隐藏层的值是初始输入值。
隐藏层:这是网络的核心和灵魂,也是程序发挥魔力的根本。该层中的神经元为每个输入配置权重。这些权重随机设置初始值,并在网络训练时进行调整,以使神经元的输出更接近预期结果(如果幸运的话)。
输出层:这是神经网络在执行计算后得到的输出。简单案例中的输出将设置为true、false,或者on、off。神经元为每个输入配置权重,这些输入来自先前的隐藏层。虽然通常只有一个输出神经元,但如果需要或想要多个输出神经元,也可以设置更多神经元。

2.2 神经网络训练

如何训练神经网络?基本上,我们将提供一组输入数据以及我们期望看到的对应于输入的结果数据。然后,该数据将通过网络运行,直到神经网络了解了我们的目的。我们将训练、测试、训练、测试、训练、测试,直到神经网络了解了数据(或无法了解,但这是其他问题)。继续训练,直到满足一些指定的停止条件,例如误差率阈值。让我们来快速了解一下在训练神经网络时会用到的一些术语。
后向传播:数据通过网络运行后,将输出数据和预期的正确结果进行验证调整。我们通过在网络的每个隐藏层中后向传播(backprop或back propagation)来达到这一目的。最终的结果是,这会调整隐藏层中每个神经元输入的权重以及误差率。
完美情况下,每个后向传播层都应该使网络输出更接近我们期望的结果,并且使误差率越来越接近0。但误差率可能永远不会达到0,因此即使看起来差别不大,误差率0.0000001也可能超出我们的接受范围。
偏差:偏差允许我们修改函数,以便我们为网络中的每个神经元生成更好的输出。简而言之,偏差允许我们将激活函数值向左或向右偏移,而改变权重则会改变Sigmoid的陡度或垂直方向的偏移。
动量:动量仅将先前权重更新的一小部分添加到当前权重更新中。动量用于防止系统收敛于局部最小值而非全局最小值。高动量可帮助提高系统的收敛速度,然而,你必须小心,因为将此参数设置得太高会造成超出最小值的风险,导致系统不稳定。另一方面,过低的动量无法有效地避免局部最小值,并且会减慢系统的训练速度。因此,设置合适的动量值对于成功至关重要,并且你需要花费大量时间对其进行调参。
Sigmoid函数:激活函数定义每个神经元的输出。Sigmoid函数可能是最常用的激活函数,它将输入转换为介于0到1之间的值,用于生成初始权重。典型的Sigmoid函数能够接收输入值,并从该值生成输出值和相应的导数。
学习率:学习率通过控制权重大小和学习过程中网络的偏差变化来改变系统的整体学习速度。
我们已经掌握了这些术语,现在开始深入研究代码。本书使用的是Visual Studio的Community版本,但你可以使用任何喜欢的版本。
需要的话,可以随意下载该软件进行试验并修改。你可以用神经网络做任何你喜欢或想做的事情,我们为你提供了源代码。眼见为虚,动手为实。开始实践吧,学习这些优秀的开源贡献者为我们提供的代码!请记住,这个神经网络只是为了让你对自己编写的东西有所了解,并教你一些关于神经网络的基础知识。
从一些简短的代码片段开始,这些代码片段将为本章的其余部分奠定基础。首先从一个称为突触的小东西开始,它将一个神经元连接到另一个神经元。接下来编写单个神经元代码,最后讨论前向和后向传播以及这两种传播对我们的意义。为了便于理解,我们展示其中的一些代码片段。

2.2.1 突触

你可能会问,什么是突触?简而言之,它是一种将一个神经元连接到另一个神经元,以及容纳权重和权重增量的容器,如下所示:
image.png

2.2.2 神经元

我们已经讨论过神经元,现在是时候用代码来呈现它了,以便开发人员更好地理解!如你所见,我们有输入和输出突触、偏差、偏差增量、梯度,以及神经元的实际值。神经元计算其输入的加权和,加上偏差,然后决定输出是否应该“启动”—置于“激活”状态:
image.png

2.2.3 前向传播

以下是基本的前向传播过程的代码:
image.png

要实现ForwardPropagation,基本上要对每个突触的所有输入求和,并通过运行Sigmoid函数得到运行结果以获得输出。CalculateValue函数为我们执行此操作。

2.2.4 Sigmoid函数

Sigmoid函数是一个激活函数,正如我们之前所说,它也许是当今使用最广泛的函数之一。图2-2是Sigmoid函数的形状(回忆关于激活函数的部分)。它唯一的目的(非常抽象地说)是将来自外边缘的值处理成接近0和1,而不必担心大于此值。这样可以处理某些值过大的情况。

image.png

你可能会问,C#代码中的Sigmoid函数是什么样子的?如下所示:
image.png

Sigmoid类提供输出和求导两个函数。

2.2.5 后向传播

对于后向传播来说,首先我们将计算输出层的梯度,然后让这些值通过隐藏层(反转在前向传播中的方向),更新权重,最后让值通过输出层,如下:
image.png

2.2.6 计算误差

我们采取实际值减去神经网络预测值的方法来计算误差。误差越接近0,就越好。请注意,以下误差计算几乎不可能达到0,只有很小的概率得到0:
image.png

2.2.7 计算梯度

通过Sigmoid函数的导数来计算梯度:
image.png

2.2.8 更新权重

我们用学习率乘以梯度的方式来更新权重,然后加上动量并乘以先前的增量。最后通过运行每个输入突触计算最终值:
image.png

2.2.9 计算值

为了计算值,我们从Sigmoid函数中获取输出并加上偏差值:
image.png
image.png

2.3 神经网络函数

以下是我们要开发的函数,它们奠定了神经网络的基础:

  • 创建新网络
  • 导入网络
  • 手动输入用户数据
  • 导入数据集
  • 训练网络
  • 测试网络

有了这些函数,让我们开始编码吧!

2.3.1 创建新网络

创建新网络的代码如下:
image.png

注意该函数中的返回值。这是一个流畅的界面,意味着我们可以将各种函数链接在一起形成一条语句。与传统的界面相比,许多人更喜欢这种类型的界面,但你可以随意地修改代码。以下是一个流畅界面的示例。信不信由你,这是一个完整的神经网络:
image.png

2.3.2 导入现有网络

此函数允许我们导入以前保存的网络。再次强调,请注意返回值,它是形成流畅界面的关键:
image.png

获取以前保存的网络的文件名。打开后,将其反序列化为我们将要处理的网络结构(如果由于某种原因无效,请中止该操作!):
image.png

创建一个新网络和要填充的神经元列表:
image.png

复制之前保存的学习率和动量:
image.png

从导入的网络数据创建输入层:
image.png

从导入的网络数据创建隐藏层:
image.png
image.png

从导入的数据创建输出层神经元:
image.png

最后,创建将所有内容联系在一起的突触:
image.png

以下是我们手动输入的数据,以供神经网络使用:
image.png
image.png

2.3.3 导入数据集

以下是导入数据集的方式:
image.png

反序列化数据并返回:
image.png

2.3.4 网络运算

为了测试网络,我们做了一个简单的前向和后向传播运算,描述如下:
image.png

进行前向传播运算,如下所示:
image.png

得到并返回运算结果,如下所示:
image.png

2.3.5 导出网络

导出当前的网络信息,如下所示:
image.png

2.3.6 训练网络

有两种训练网络的方法。一种是最小误差值法,另一种是最大误差值法。这两个函数都有默认值,但你可以为训练设置不同的阈值,如下所示:
image.png

在前面的两个函数定义中,调用神经网络Train函数来执行实际训练。该函数在训练循环的每次迭代中依次为每个数据集调用前向和后向传播函数,如下所示:
image.png

2.3.7 测试网络

此函数允许我们测试神经网络。再次注意返回值,它是构成流畅界面的关键。对于更高、更抽象层中最常用的函数,我将把函数写得更加流畅通用,如下所示:
image.png

从用户获取输入数据,如下所示:
image.png

进行计算,如下所示:
image.png

打印出结果,如下所示:
image.png

2.3.8 计算前向传播

此函数用于根据提供的值,计算前向传播值,如下所示:
image.png

2.3.9 将网络导出为JSON格式

此函数用于导出网络。对我们来说,导出意味着将数据序列化为可以读懂的JSON格式,如下所示:
image.png
image.png

2.3.10 导出数据集

此函数用于导出数据集信息。与导出网络一样,将以可以读懂的JSON格式完成:
image.png

2.4 神经网络

在编写了许多辅助但重要的函数之后,现在我们将注意力转向神经网络的核心部分,即网络本身。在神经网络中,网络部分是一个包罗万象的宇宙,一切都蕴含其中。在此结构中,我们需要存储神经元的输入层、输出层和隐藏层,以及学习率和动量,如下所示:
image.png

神经元连接
每个神经元必须连接到其他神经元,神经元构造函数将处理所有输入神经元与突触的连接,如下所示:
image.png

2.5 例子

我们已经创建了代码,现在通过示例来了解它是如何使用的。

2.5.1 训练到最小值

在这个例子中,将使用我们编写的代码来训练网络,让其达到最小值或阈值,如图2-3所示。在每一步中,网络都会提示输入正确的数据,从而为我们节省应对数据交互操作的时间。在生产过程中,你可能希望在没有任何用户干预的情况下传递参数,以把其作为服务或微服务运行。

image.png

2.5.2 训练到最大值

在这个例子中,我们将网络训练到最大值,而非最小值,如图2-4所示。我们手动输入希望使用的数据,以及预期的结果。然后完成训练。完成后,我们输入测试数据并测试神经网络效果。

image.png

2.6 小结

在本章中,我们学习了如何从头开始编写完整的神经网络。没有进一步深入讲解具体细节,但已经涵盖了重要的基础知识,而且我们用纯C#代码实现了相关内容。现在我们应该比刚开始时更好地理解了神经网络的概念以及含义。
下一章我们将开始探索更复杂的网络结构,例如循环和卷积神经网络。还有很多内容要讲述,保持良好的编码状态!

相关文章
|
10天前
|
安全 网络安全 数据安全/隐私保护
网络堡垒的构建者:洞悉网络安全与信息安全的深层策略
【4月更文挑战第9天】在数字化时代,数据成为了新的价值核心。然而,随之而来的是日益复杂的网络安全威胁。从漏洞利用到信息泄露,从服务中断到身份盗用,攻击手段不断演变。本文深入剖析了网络安全的关键组成部分:识别和防范安全漏洞、加密技术的应用以及提升个体和企业的安全意识。通过探讨这些领域的最佳实践和最新动态,旨在为读者提供一套全面的策略工具箱,以强化他们在数字世界的防御能力。
|
27天前
|
存储 安全 网络安全
云计算与网络安全:构建数字化时代的坚固防线
在当今数字化时代,云计算和网络安全已经成为企业和个人信息安全的重要保障。本文探讨了云服务、网络安全以及信息安全等技术领域的相关议题,旨在帮助读者深入了解这些关键领域的发展和挑战,以构建更加坚固的数字化防线。
12 2
|
25天前
|
SQL 安全 网络安全
网络堡垒的构建者:深入网络安全与信息安全的核心
在数字化时代,每一次点击、每一条信息的传递都可能成为安全威胁的载体。本文将探讨网络安全漏洞的本质,加密技术的进展以及提升个人和企业的安全意识的重要性。我们将深入分析如何通过技术手段和教育措施,构筑起防御网络攻击的坚固防线,确保信息传输的安全性和隐私保护。
|
4天前
|
数据采集 API 数据安全/隐私保护
畅游网络:构建C++网络爬虫的指南
本文介绍如何使用C++和cpprestsdk库构建高效网络爬虫,以抓取知乎热点信息。通过亿牛云爬虫代理服务解决IP限制问题,利用多线程提升数据采集速度。示例代码展示如何配置代理、发送HTTP请求及处理响应,实现多线程抓取。注意替换有效代理服务器参数,并处理异常。
畅游网络:构建C++网络爬虫的指南
|
8天前
|
机器学习/深度学习 自然语言处理 算法
|
12天前
|
机器学习/深度学习 人工智能 运维
构建未来:AI驱动的自适应网络安全防御系统
【4月更文挑战第7天】 在数字时代的浪潮中,网络安全已成为维系信息完整性、保障用户隐私和确保商业连续性的关键。传统的安全防御策略,受限于其静态性质和对新型威胁的响应迟缓,已难以满足日益增长的安全需求。本文将探讨如何利用人工智能(AI)技术打造一个自适应的网络安全防御系统,该系统能够实时分析网络流量,自动识别并响应未知威胁,从而提供更为强大和灵活的保护机制。通过深入剖析AI算法的核心原理及其在网络安全中的应用,我们将展望一个由AI赋能的、更加智能和安全的网络环境。
25 0
|
24天前
|
机器学习/深度学习 自然语言处理 PyTorch
【PyTorch实战演练】基于全连接网络构建RNN并生成人名
【PyTorch实战演练】基于全连接网络构建RNN并生成人名
23 0
|
28天前
|
安全 算法 网络安全
数字堡垒的构建者:网络安全与信息安全的深度剖析
【2月更文挑战第31天】 在数字化时代,数据成为了新的石油,但随之而来的是网络安全威胁的日益增加。本文将深入探讨网络安全漏洞的本质,加密技术的进展以及提升个人和企业的安全意识的重要性。通过对当前网络攻击手段的分析,我们将了解如何通过多层次防御策略来保护信息资产。同时,文章还将介绍最新的加密技术,如量子加密和区块链技术,它们如何为数据传输提供更坚固的保障。最后,强调培养良好的安全习惯对于打造稳固的网络安全防线至关重要。
12 0
|
1月前
|
网络协议 算法 Java
|
3月前
|
Java 数据格式
最新Java基础系列课程--Day15-网络编程(三)
最新Java基础系列课程--Day15-网络编程