2.3 神经网络简介

目前最广泛使用的定义是Kohonen于1988年的描述,神经网络是由具有适应性的简单单元组成的广泛并行互连的网络,它的组织能够模拟生物神经系统对真实世界物体所做出的交互反应。

概述

在生物神经网络中,每个神经元与其他神经元相连,当它兴奋时,就会向相连的神经元发送化学物质,从而改变这些神经元内的电位;如果某神经元的电位超过了一个阈值,那么它就会激活,即兴奋起来并向其他神经元发送化学物质。

在深度学习中也借鉴了这样的结构,每一个神经元(上面说到的简单单元)接受输入x,通过带权重w的连接进行传递,将总输入信号与神经元的阈值进行比较,最后通过激活函数处理确定是否激活,并将激活后的计算结果y输出,而我们所说的训练,所训练的就是这里面的权重w。

参考

每一个神经元的结构如下:

来源

神经网络的表示

我们可以将神经元拼接起来,两层神经元,即输入层+输出层(M-P神经元),构成感知机。
而多层功能神经元相连构成神经网络,输入层与输出层之间的所有层神经元,称为隐藏层:

如上图所示,输入层和输出层只有一个,中间的隐藏层可以有很多层(输出层也可以多个,例如经典的GoogleNet,后面会详细介绍)

激活函数

介绍神经网络的时候已经说到,神经元会对化学物质的刺激进行,当达到一定程度的时候,神经元才会兴奋,并向其他神经元发送信息。神经网络中的激活函数就是用来判断我们所计算的信息是否达到了往后面传输的条件。

为什么激活函数都是非线性的

在神经网络的计算过程中,每层都相当于矩阵相乘,无论神经网络有多少层输出都是输入的线性组合,就算我们有几千层的计算,无非还是个矩阵相乘,和一层矩阵相乘所获得的信息差距不大,所以需要激活函数来引入非线性因素,使得神经网络可以任意逼近任何非线性函数,这样神经网络就可以应用到众多的非线性模型中,增加了神经网络模型泛化的特性。

早期研究神经网络主要采用sigmoid函数或者tanh函数,输出有界,很容易充当下一层的输入。
近些年Relu函数及其改进型(如Leaky-ReLU、P-ReLU、R-ReLU等),由于计算简单、效果好所以在多层神经网络中应用比较多。

下面来总结下较常见的激活函数:

# 初始化一些信息
import torch
import torch.nn.functional as F
import matplotlib.pyplot as plt
import numpy as np
x= torch.linspace(-10,10,60)

sigmod 函数

a

=

1

1

+

e

z

a=\frac{1}{1+e^{-z}}

a=1+e−z1​ 导数 :

a

=

a

(

1

a

)

a^\prime =a(1 - a)

a′=a(1−a)

在sigmod函数中我们可以看到,其输出是在(0,1)这个开区间,它能够把输入的连续实值变换为0和1之间的输出,如果是非常大的负数,那么输出就是0;如果是非常大的正数输出就是1,起到了抑制的作用。

ax = plt.gca()
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data', 0))
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data', 0))
plt.ylim((0, 1))
sigmod=torch.sigmoid(x)
plt.plot(x.numpy(),sigmod.numpy())
[<matplotlib.lines.Line2D at 0x2ad8aa2b9b0>]

但是sigmod由于需要进行指数运算(这个对于计算机来说是比较慢,相比relu),再加上函数输出不是以0为中心的(这样会使权重更新效率降低),当输入稍微远离了坐标原点,函数的梯度就变得很小了(几乎为零)。在神经网络反向传播的过程中不利于权重的优化,这个问题叫做梯度饱和,也可以叫梯度弥散。这些不足,所以现在使用到sigmod基本很少了,基本上只有在做二元分类(0,1)时的输出层才会使用。

tanh 函数

a

=

e

z

e

z

e

z

+

e

z

a=\frac{e^z-e^{-z}}{e^z+e^{-z}}

a=ez+e−zez−e−z​ 导数:

a

=

1

a

2

a^\prime =1 - a^2

a′=1−a2

tanh是双曲正切函数,输出区间是在(-1,1)之间,而且整个函数是以0为中心的

ax = plt.gca()
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data', 0))
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data', 0))
plt.ylim((-1, 1))
tanh=torch.tanh(x)
plt.plot(x.numpy(),tanh.numpy())
[<matplotlib.lines.Line2D at 0x2ad8ab67cc0>]

与sigmoid函数类似,当输入稍微远离了坐标原点,梯度还是会很小,但是好在tanh是以0为中心点,如果使用tanh作为激活函数,还能起到归一化(均值为0)的效果。

一般二分类问题中,隐藏层用tanh函数,输出层用sigmod函数,但是随着Relu的出现所有的隐藏层基本上都使用relu来作为激活函数了

ReLU 函数

Relu(Rectified Linear Units)修正线性单元

a

=

m

a

x

(

0

,

z

)

a=max(0,z)

a=max(0,z) 导数大于0时1,小于0时0。

也就是说:
z>0时,梯度始终为1,从而提高神经网络基于梯度算法的运算速度。然而当
z<0时,梯度一直为0。
ReLU函数只有线性关系(只需要判断输入是否大于0)不管是前向传播还是反向传播,都比sigmod和tanh要快很多,

ax = plt.gca()
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data', 0))
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data', 0))
plt.ylim((-3, 10))
relu=F.relu(x)
plt.plot(x.numpy(),relu.numpy())
[<matplotlib.lines.Line2D at 0x2ad8b097470>]

当输入是负数的时候,ReLU是完全不被激活的,这就表明一旦输入到了负数,ReLU就会死掉。但是到了反向传播过程中,输入负数,梯度就会完全到0,这个和sigmod函数、tanh函数有一样的问题。 但是实际的运用中,该缺陷的影响不是很大。

Leaky Relu 函数

为了解决relu函数z<0时的问题出现了 Leaky ReLU函数,该函数保证在z<0的时候,梯度仍然不为0。
ReLU的前半段设为αz而非0,通常α=0.01 $ a=max(\alpha z,z)$

ax = plt.gca()
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data', 0))
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data', 0))
plt.ylim((-3, 10))
l_relu=F.leaky_relu(x,0.1) # 这里的0.1是为了方便展示,理论上应为0.01甚至更小的值
plt.plot(x.numpy(),l_relu.numpy())
[<matplotlib.lines.Line2D at 0x2ad8b0bd3c8>]

理论上来讲,Leaky ReLU有ReLU的所有优点,但是在实际操作当中,并没有完全证明Leaky ReLU总是好于ReLU。

ReLU目前仍是最常用的activation function,在隐藏层中推荐优先尝试!

深入理解前向传播和反向传播

在最后我们再详细说下神经网络中的前向传播和反向传播,这里继续使用吴恩达老师的板书

正向传播

对于一个神经网络来说,把输入特征

a

[

0

]

a^{[0]}

a[0]这个输入值就是我们的输入

x

x

x,放入第一层并计算第一层的激活函数,用

a

[

1

]

a^{[1]}

a[1]表示,本层中训练的结果用

W

[

1

]

W^{[1]}

W[1]和

b

[

l

]

b^{[l]}

b[l]来表示,这两个值与,计算的结果

z

[

1

]

z^{[1]}

z[1]值都需要进行缓存,而计算的结果还需要通过激活函数生成激活后的

a

[

1

]

a^{[1]}

a[1],即第一层的输出值,这个值会作为第二层的输入传到第二层,第二层里,需要用到

W

[

2

]

W^{[2]}

W[2]和

b

[

2

]

b^{[2]}

b[2],计算结果为

z

[

2

]

z^{[2]}

z[2],第二层的激活函数

a

[

2

]

a^{[2]}

a[2]。
后面几层以此类推,直到最后算出了

a

[

L

]

a^{[L]}

a[L],第

L

L

L层的最终输出值

y

^

\hat{y}

y^​,即我们网络的预测值。正向传播其实就是我们的输入

x

x

x通过一系列的网络计算,得到

y

^

\hat{y}

y^​的过程。

在这个过程里我们缓存的值,会在后面的反向传播中用到。

反向传播

对反向传播的步骤而言,就是对正向传播的一系列的反向迭代,通过反向计算梯度,来优化我们需要训练的

W

W

W和

b

b

b。

δ

a

[

l

]

{\delta}a^{[l]}

δa[l]值进行求导得到

δ

a

[

l

1

]

{\delta}a^{[l-1]}

δa[l−1],以此类推,直到我们得到

δ

a

[

2

]

{\delta}a^{[2]}

δa[2]和

δ

a

[

1

]

{\delta}a^{[1]}

δa[1]。反向传播步骤中也会输出

δ

W

[

l

]

{\delta}W^{[l]}

δW[l]和

δ

b

[

l

]

{\delta}b^{[l]}

δb[l]。这一步我们已经得到了权重的变化量,下面我们要通过学习率来对训练的

W

W

W和

b

b

b进行更新,

W

=

W

α

δ

W

W=W-\alpha{\delta}W

W=W−αδW

b

=

b

α

δ

b

b=b-\alpha{\delta}b

b=b−αδb

这样反向传播就就算是完成了

[Pytorch框架] 2.3 神经网络简介的更多相关文章

  1. 人工神经网络简介和单层网络实现AND运算--AForge.NET框架的使用(五)

    原文:人工神经网络简介和单层网络实现AND运算--AForge.NET框架的使用(五) 前面4篇文章说的是模糊系统,它不同于传统的值逻辑,理论基础是模糊数学,所以有些朋友看着有点迷糊,如果有兴趣建议参 ...

  2. 手写数字识别 卷积神经网络 Pytorch框架实现

    MNIST 手写数字识别 卷积神经网络 Pytorch框架 谨此纪念刚入门的我在卷积神经网络上面的摸爬滚打 说明 下面代码是使用pytorch来实现的LeNet,可以正常运行测试,自己添加了一些注释, ...

  3. 框架基础之Hibernate简介

    框架基础之Hibernate简介 1.什么是Hibernate? Hibernate是一个开发源代码的对象关系映射框架,它对JDBC进行非常轻量级的对象封装,使得程序员可以随心所欲地使用对象编程思维来 ...

  4. PyTorch框架+Python 3面向对象编程学习笔记

    一.CNN情感分类中的面向对象部分 sparse.py super(Embedding, self).__init__() 表示需要父类初始化,即要运行父类的_init_(),如果没有这个,则要自定义 ...

  5. SpringBoot系列之日志框架介绍及其原理简介

    SpringBoot系列之日志框架介绍及其原理简介 1.常用日志框架简介 市面上常用日志框架:JUL.JCL.jboss-logging.logback.log4j.log4j2.slf4j.etc. ...

  6. 小白学习之pytorch框架(1)-torch.nn.Module+squeeze(unsqueeze)

    我学习pytorch框架不是从框架开始,从代码中看不懂的pytorch代码开始的 可能由于是小白的原因,个人不喜欢一些一下子粘贴老多行代码的博主或者一些弄了一堆概念,导致我更迷惑还增加了畏惧的情绪(个 ...

  7. 全面解析Pytorch框架下模型存储,加载以及冻结

    最近在做试验中遇到了一些深度网络模型加载以及存储的问题,因此整理了一份比较全面的在 PyTorch 框架下有关模型的问题.首先咱们先定义一个网络来进行后续的分析: 1.本文通用的网络模型 import ...

  8. PyTorch基础——机器翻译的神经网络实现

    一.介绍 内容 "基于神经网络的机器翻译"出现了"编码器+解码器+注意力"的构架,让机器翻译的准确度达到了一个新的高度.所以本次主题就是"基于深度神经 ...

  9. Disruptor并发框架(一)简介&上手demo

    框架简介 Martin Fowler在自己网站上写了一篇LMAX架构的文章,在文章中他介绍了LMAX是一种新型零售金融交易平台,它能够以很低的延迟产生大量交易.这个系统是建立在JVM平台上,其核心是一 ...

  10. Spring框架入门之Spring简介

    一.Spring简介(由Rod Johnson创建的一个开源框架)        Spring是一个开放源代码的设计层面框架,他解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿 ...

随机推荐

  1. 2.3Dmax界面_视图调整

    一.试图模型显示效果的切换 '默认是真实显示效果' 线框模式 快捷键F3 ----> 真实显示效果和线框显示效果的切换(切换到线框显示效果再按F3就切换到了真实显示效果). 线面模式 快捷键F4 ...

  2. git push 报错error: remote unpack failed: error Short read of block

    1.解决办法:找管理代码的人给你开权限. 2如果你的push的命令写错的话,也是会出现远端拒绝的提示,所以记得检查自己的push 命令是否正确 另一种明显的权限拒绝的例子: 英语学习:to push ...

  3. F - Substring of Sorted String

    题目链接 题解(树状数组) 我们维护两个树状数组,一个记录 \(1\sim i\) 中 \(s_i>s_{i+1}\)的数量,即逆序对数量,另一个记录 \(1\sim i\) 中 \(26\) ...

  4. vue横向滑动

    代码 <template> <div> <!-- 左侧的滑动模块 --> <div class="scroll-box" :style=& ...

  5. 如何在 Net6.0 中对 WebAPI 进行 JWT 认证和授权

    一.简介 我们做微服务开发,或者说做分布式开发,有一项技术我们是避不开的,那就是WebAPI,在 Net6.0中,有两类 WebAPI,一类是极简 WebAPI,它砍掉了很多冗余的东西,更纯粹的是做 ...

  6. Web For Pentester File include

    File include(文件包含) Example 1 没有任何过滤 审计源码 没有对我们传参的page进行任何过滤,payload如下 http://172.16.1.104/fileincl/e ...

  7. Hugging Face 每周速递: Chatbot Hackathon;FLAN-T5 XL 微调;构建更安全的 LLM

    每一周,我们的同事都会向社区的成员们发布一些关于 Hugging Face 相关的更新,包括我们的产品和平台更新.社区活动.学习资源和内容更新.开源库和模型更新等,我们将其称之为「Hugging Ne ...

  8. 关于wx.panel中添加wx.button按钮无显示问题记录

    本次出现按钮不显示的原因为pos坐标理解出错: 1.按钮之所没有出现,是因为将全局坐标作为按钮pos的定位,导致在有限的panel布局内无法显示出按钮: 2.经过调试发现当pos=(-1,-1)时,按 ...

  9. 基于机器学习的语音编解码器声网Agora Silver:支持超低码率下的高音质语音互动

    从 1860 年电话发明,到现如今通过网络进行语音互动,语音始终是最自然.最基础的实时互动方式.过去几年,语音实时互动成为越来越多人日常生活的一部分.但是每个人都会遇到弱网环境,这会直接影响语音通话体 ...

  10. 使用EFCore的Code First和MySql数据库迁移

    1. 感慨一下 随着.net core的持续更新和升级,至少对于从事.net开发的人员和即将踏入这个领域的人来说,我相信大家的热情还是持续高涨的.国内的.net开发生态相比于之前来说,还是大有所好转的 ...