[Pytorch框架] 2.3 神经网络简介
文章目录
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 神经网络简介的更多相关文章
- 人工神经网络简介和单层网络实现AND运算--AForge.NET框架的使用(五)
原文:人工神经网络简介和单层网络实现AND运算--AForge.NET框架的使用(五) 前面4篇文章说的是模糊系统,它不同于传统的值逻辑,理论基础是模糊数学,所以有些朋友看着有点迷糊,如果有兴趣建议参 ...
- 手写数字识别 卷积神经网络 Pytorch框架实现
MNIST 手写数字识别 卷积神经网络 Pytorch框架 谨此纪念刚入门的我在卷积神经网络上面的摸爬滚打 说明 下面代码是使用pytorch来实现的LeNet,可以正常运行测试,自己添加了一些注释, ...
- 框架基础之Hibernate简介
框架基础之Hibernate简介 1.什么是Hibernate? Hibernate是一个开发源代码的对象关系映射框架,它对JDBC进行非常轻量级的对象封装,使得程序员可以随心所欲地使用对象编程思维来 ...
- PyTorch框架+Python 3面向对象编程学习笔记
一.CNN情感分类中的面向对象部分 sparse.py super(Embedding, self).__init__() 表示需要父类初始化,即要运行父类的_init_(),如果没有这个,则要自定义 ...
- SpringBoot系列之日志框架介绍及其原理简介
SpringBoot系列之日志框架介绍及其原理简介 1.常用日志框架简介 市面上常用日志框架:JUL.JCL.jboss-logging.logback.log4j.log4j2.slf4j.etc. ...
- 小白学习之pytorch框架(1)-torch.nn.Module+squeeze(unsqueeze)
我学习pytorch框架不是从框架开始,从代码中看不懂的pytorch代码开始的 可能由于是小白的原因,个人不喜欢一些一下子粘贴老多行代码的博主或者一些弄了一堆概念,导致我更迷惑还增加了畏惧的情绪(个 ...
- 全面解析Pytorch框架下模型存储,加载以及冻结
最近在做试验中遇到了一些深度网络模型加载以及存储的问题,因此整理了一份比较全面的在 PyTorch 框架下有关模型的问题.首先咱们先定义一个网络来进行后续的分析: 1.本文通用的网络模型 import ...
- PyTorch基础——机器翻译的神经网络实现
一.介绍 内容 "基于神经网络的机器翻译"出现了"编码器+解码器+注意力"的构架,让机器翻译的准确度达到了一个新的高度.所以本次主题就是"基于深度神经 ...
- Disruptor并发框架(一)简介&上手demo
框架简介 Martin Fowler在自己网站上写了一篇LMAX架构的文章,在文章中他介绍了LMAX是一种新型零售金融交易平台,它能够以很低的延迟产生大量交易.这个系统是建立在JVM平台上,其核心是一 ...
- Spring框架入门之Spring简介
一.Spring简介(由Rod Johnson创建的一个开源框架) Spring是一个开放源代码的设计层面框架,他解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿 ...
随机推荐
- 10.Java中Map的entrySet() 详解以及用法
一.Map.entry是什么? Map是java中的接口,Map.Entry是Map的一个内部接口. 此接口为泛型,定义为Entry<K,V>.它表示Map中的一个实体(一个key-val ...
- LVS负载均衡 2022年4月
1. 负载均衡技术简介 2 1.1 负载均衡类型3 1.2 LVS简介4 1.3 Keepalived简介5 2. 负载均衡搭建主要步骤 6 2.1 LVS+Keepalived的负载均衡系统搭建6 ...
- [复现]2021DASCTF实战精英夏令营暨DASCTF July X CBCTF-PWN
EasyHeap 想可执行的地方写入orw的shellcode,利用tcachebin的df进行劫持malloc_hook 然后调用add来触发. from pwn import * context. ...
- ansible批量采集、批量互信、批量复制、分发文件
一.先说一下用ansible批量采集机器信息的实现办法: 1.先把要采集的机器信息的IP添加到主节点机器的/etc/ansible/hosts里面: 2.在/etc/ansible/hosts里面添加 ...
- Fiddler一些用法学习记录
最近项目中用Fiddler较多,只会之前掌握的一些最简单的用法显得有点不太够.记录一下学习到的新用法. 一.需要mock.打开AutoResponder,Add Rule,填上需要mock的网址,需要 ...
- OVS内核流表查询过程
概括 现在的OVS使用microflow+megaflow缓存查询流表,ovs整体流程是从ovs_vport_receive(datapath/vport.c)开始,然后进入ovs_dp_proces ...
- SpringCloud Ribbon 负载均衡
Spring Cloud Ribbon 是一个基于 HTTP 和 TCP 的客户端负载均衡工具.可以将面向服务的 REST 模板请求自动转化成客户端负载均衡的服务调用.Spring Cloud Rib ...
- 最新版本 Stable Diffusion 开源AI绘画工具之部署篇
目录 AI绘画 本地环境要求 下载 Stable Diffusion 运行启动 AI绘画 关于 AI 绘画最近有多火,既然你有缘能看到这篇文章,那么相信也不需要我过多赘述了吧? 随着 AI 绘画技术的 ...
- 使用nw.js打包以后的web项目 发布客户端
一.下载nw.js 直接前往官网下载即可 https://nwjs.io/downloads/ 二.封装最简单的客户端 nw.js下载完成后,在任意位置新建文件夹,例如nwtest,然后在文件夹中新建 ...
- Host key verification failed的问题解决 (亲测有效)
一.描述 scp拷贝远程内容时失败,出现以下问题: 翻译: @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ...