首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

感知器-神经网络的最基本形式

近年来,人工神经网络在深度学习的推动下获得了关注。 但是什么是人工神经网络,它是由什么构成的?

一起来认识一下感知器。

在本文中,我们将简要介绍一下人工神经网络,然后我们检查单个神经元,最后(也就是编码部分),我们采用最基本的人造神经元版本感知器,并使其 在一个平面上进行分类。但首先,让我介绍一下这个话题。

人工神经网络作为人类大脑的模型

你有没有想过为什么有些任务对于任何人来说都很简单,但对于电脑来说非常困难? 人工神经网络(简称ANN)受到人类中枢神经系统的启发。 就像它们的生物副本一样,ANN的构建依赖于简单的信号处理单元,它们连接在一起形成一个大网格。

神经网络可以做什么?

人工神经网络已成功应用于一些问题领域:

通过识别模式分类数据。 这是这张照片上的一棵树吗?

当测试数据与通常的模式不匹配时,检测异常或新奇事物。 卡车司机是否有可能入睡? 这些地震事件是否显示正常的地面运动或大地震?

处理信号,例如,通过过滤,分离或压缩。

近似目标函数 - 对预测和预测有用。 这场风暴会变成龙卷风吗?

同意,这听起来有点抽象,所以让我们看看一些现实世界的应用。 神经网络可以 - 面部识别,语音识别,手写输入(我的也许不是),文本翻译,玩游戏(通常是棋盘游戏或纸牌游戏)自动驾驶和机器人当然还有更多的东西!

神经网络的拓扑结构

将神经网络的节点编织在一起有多种方式,每种方式都会导致或多或少的复杂行为。 可能最简单的拓扑结构就是前馈网络。 信号只在一个方向上流动; 信号路径中永远不会有任何回路。

通常,ANN具有分层结构。 输入层拾取输入信号并将它们传递到下一层,即所谓的“隐藏”层。 (实际上,神经网络中可能有多个隐藏层。)最后是传递结果的输出层。

神经网络必学

与传统算法不同,神经网络不能被“编程”或“配置”以预定的方式工作。 就像人脑一样,他们必须学习如何完成任务。 粗略地说,有三种学习策略:

1. 监督学习

最简单的方法。 如果存在已知结果的(足够大的)一组测试数据,则可以使用它。 然后学习如下:处理一个数据集。 将输出与已知结果进行比较。 调整网络并重复。 这是我们在这里使用的学习策略。

2. 无监督学习

如果没有可用的测试数据,以及是否可以从期望的行为中推导出某种成本函数,那么这很有用。 成本函数告诉神经网络它离目标多远。 网络随后可以在处理实际数据时随时调整其参数。

3. 强化学习

“胡萝卜和棒”的方法。 如果神经网络产生连续动作,那么可以使用本方法。 跟着你鼻子前面的胡萝卜走! 如果你走错了路 - “棒!”。 随着时间的推移,网络学习偏好正确的行为并避免错误行为。

好的,现在我们对人工神经网络的性质有了一些了解,但是他们的结构究竟是什么? 如果我们打开封面并在窥探其内,我们会看到什么?

神经元:神经网络的基石

任何人造神经网络的基本成分都是人造神经元。 它们不仅以它们的生物对应物命名,而且还以大脑中神经元的行为为模型。

生物与技术

就像一个生物神经元有树突来接收信号,一个细胞体来处理它们,一个轴突发送信号到其他神经元一样,人造神经元有许多输入通道,一个处理阶段和一个输出可以扇出 到多个其他人造神经元。

人造神经元内

让我们进一步放大。 神经元如何处理其输入? 您可能会惊讶地发现神经元内部的计算有多简单。 我们可以确定三个处理步骤:

1.每个输入被放大或缩小

当一个信号进入时,它会乘以一个分配给这个特定输入的权重值。 也就是说,如果一个神经元有三个输入,那么它有三个可以单独调整的权重。 在学习阶段,神经网络可以根据最后测试结果的错误来调整权重。

2.所有信号加和

在接下来的步骤中,修改后的输入信号总计为单个值。 在这一步中,偏移量也被添加到总和中。 这个偏移量被称为偏差。 神经网络也在学习阶段调整偏差。

这是魔术发生的地方! 一开始,所有神经元都有随机权和随机偏差。 在每次学习迭代之后,权重和偏差逐渐偏移,以便下一个结果更接近期望的输出。 这样,神经网络逐渐走向期望模式被“学习”的状态。

3.激活

最后,神经元计算的结果变成输出信号。 这通过将结果馈送到激活功能(也称为传递函数)来完成。

感知器

激活函数的最基本形式是一个简单的二元函数,它只有两个可能的结果。

注:尽管看起来很简单,但该函数有一个相当复杂的名称:单位阶跃函数。 如果输入为正或零,则此函数返回1,对于任何负输入,此函数返回0。 一个神经元的激活函数就是这样的函数,称为感知器。

单个感知器能做什么有用的工作吗?

如果你仔细想一想,看起来好像感知器为很少的输出消耗了大量的信息 - 只有0或者1。这怎么会有用呢?

确实有一类问题可以用感知器来解决。 考虑输入矢量作为点的坐标。 对于具有n个元素的矢量,这个点将存在于一个n维空间中。 为了让讲解(和下面的代码)更容易,让我们假设在一个像纸一样的二维平面,即n=2。

进一步考虑我们在这个平面上画出许多随机点,并且我们通过在纸上划一条直线将它们分成两组:在一个平面上画出许多随机点,然后通过在这个平面上划一条直线将它们分成两组:

这条线将点分为两组,一组在上面,一组在下面。 (这两组被称为线性可分。)

一个单独的感知器,就像它看起来那样简单而且简单,能够知道这条线是什么,当它完成学习时,它可以知道给定点是高于还是低于该线。

想象一下:单个感知器已经可以学习如何对点进行分类!

让我们跳入编码,看看如何。

代码:分类点的感知器

输入

除了一些标准库之外,我们只需要一个小型自定义库来将感知器的输出绘制到PNG上。

感知器

首先我们定义感知器。 一个新的感知器使用在训练过程中将被修改的随机权重和偏差。 感知器执行两项任务:

处理输入信号

按照“训练者”的指示调整输入砝码。

## 我们的感知器是一个简单的结构,可以保存输入权重和偏差。

typePerceptronstruct{

weights []float32

biasfloat32

}

## 这是单位阶跃函数

func(p*Perceptron) heaviside(ffloat32)int32{

return

}

return1

}

## 用n个输入创建一个新的感知器。权重和偏差用-1和1之间的随机值进行初始化。

funcNewPerceptron(nint32)*Perceptron{

variint32

w:=make([]float32, n, n)

fori =; i < n; i++{

w[i] = rand.Float32()*2-1

}

return&Perceptron{

weights: w,

bias: rand.Float32()*2-1,

}

}

## 过程实现感知器的核心功能。它权衡输入信号,将它们相加,增加偏差,并通过单位阶跃函数运行结果。(返回值可能是一个布尔值,但是属于int32类型,所以我们可以直接使用该值来调整感知器)

func(p*Perceptron) Process(inputs []int32)int32{

sum:=p.bias

fori, input:=rangeinputs {

sum+=float32(input)*p.weights[i]

}

returnp.heaviside(sum)

}

## 在学习阶段,感知器根据感知器的答案与正确答案的差异来调整权重和偏差。

func(p*Perceptron) Adjust(inputs []int32, deltaint32, learningRatefloat32) {

fori, input:=rangeinputs {

p.weights[i]+=float32(input)*float32(delta)*learningRate

}

p.bias+=float32(delta)*learningRate

}

训练

我们排除分类线垂直的情况。 我们可以将线条指定为线性函数方程:

参数a指定线的梯度(即线的陡峭程度),b设置偏移量。

通过这种方式描述线条,检查给定的点是在线之上还是之下变得非常容易。 对于一个点(x,y),如果y的值大于f(x)的结果,那么(x,y)在该线的上方。

示例如下:

a和b指定描述分隔线的线性函数; 详情见下文。 它们是在全局层面定义的,因为我们在几个地方需要它们,而且我不想随意地混淆参数列表。

## a和b指定描述分隔线的线性函数; 详情见下文。它们是在全局层面定义的,因为我们在几个地方需要它们,而且我不想随意地混淆参数列表。

var(

a, bint32

)

## 此功能描述分隔线。

funcf(xint32)int32{

returna*x+b

}

## 如果点(x,y)高于线y = ax + b,函数“isAboveLine”返回1,否则为0。这是老师们的解决方案手册。

funcisAboveLine(point []int32, ffunc(int32)int32)int32{

x:=point[]

y:=point[1]

ify > f(x) {

return1

}

return

}

## 函数”train”是我们的训练师。训练师生成随机测试点并将其馈送给感知器。然后,训练师将答案与“解决方案手册”中的解答进行比较,并告知感知器它离开的距离.

functrain(p*Perceptron, itersint, ratefloat32) {

fori:=; i < iters; i++{

## 在-100和100之间生成一个随机点。

point:=[]int32{

rand.Int31n(201)-101,

rand.Int31n(201)-101,

}

## 将该点送入感知器并评估结果。

actual:=p.Process(point)

expected:=isAboveLine(point, f)

delta:=expected-actual

## 让感知器相应地调整其内部值。

p.Adjust(point, delta, rate)

}

}

开演时间!

现在是时候看看感知器如何完成任务了。我们再次抛出随机点,但这次没有训练师的反馈。感知器会将每一点正确分类吗?

这是我们的测试函数。它返回正确答案的数量。

funcverify(p*Perceptron)int32{

varcorrectAnswersint32=

创建一个新的绘图画布。 x和y的范围都从-100到100。

c:=draw.NewCanvas()

fori:=; i

在-100到100产生一个随机点。

point:=[]int32{

rand.Int31n(201)-101,

rand.Int31n(201)-101,

}

将该点送入感知器并评估结果。

result:=p.Process(point)

ifresult==isAboveLine(point, f) {

correctAnswers+=1

}

颜色表明感知器回答“是高于”还是“低于”。

c.DrawPoint(point[], point[1], result==1)

}

画分离线: y = ax + b.

c.DrawLinearFunction(a, b)

将图片保存./result.png.

c.Save()

returncorrectAnswers

}

主函数Main: 建立、训练和测试感知器。

funcmain() {

设置线路参数。 a(线的斜率)可以在-5和5之间变化,并且b(偏移量)在-50和50之间变化。

rand.Seed(time.Now().UnixNano())

a = rand.Int31n(11)-6

b = rand.Int31n(101)-51

创建一个具备两个输入(一个为x一个为y)的感知器。

p:=NewPerceptron(2)

开始学习。

iterations:=1000

varlearningRatefloat32=0.1//Allowedrange:< learning rate

尝试用这些参数来训练!

train(p, iterations, learningRate)

接下来感知器开始准备测试。

successRate:=verify(p)

fmt.Printf("%d%% of the answers werecorrect.\n",successRate)

}

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180223G0Y2JL00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券