赞
踩
本文主要总结我对李宏毅老师讲的CNN和RNN的理解,通过对比总结各自的优势,同时加深自己对这方面知识的理解。
CNN是一种利用卷积计算的神经网络。它可以通过卷积计算将原像素很大的图片保留主要特征变成很小的像素图片。本文介绍方式以李宏毅老师ppt内容为主,具体下面介绍。
①为什么引入CNN??
图片示意:给定一个图片放入全连接神经网络,第一个hidden layer识别这张图片有没有绿色出现?有没有黄色出现?有没有斜的条纹?第二个hidden layer结合第一个hidden layer的输出实现更复杂的功能,例如:如图如果看到直线+横线就是框框一部分,如果看到棕色+条纹就是木纹,如果看到斜条纹+绿色就是灰色类条纹一部分。再根据第二个hidden layer输出结果,如果某个神经元看到蜂巢就会activate,某个神经元如果看到人就会activate。
但是我们如果一般地用fully network(全连接)神经网络处理的话,我们会需要很多的参数,例如如果input的vector是个30000维,第一个hidden layer假设是1000个神经元,那么第一个hidden layer就会30000*1000个,数据量非常大,导致计算效率和准确率效果低,而引入CNN,主要就是解决我们这些问题,简化我们神经网络架构。因为 某些weight我们是用不到的,CNN会使用过滤手段(filter)将一些不需要的参数过滤掉,保留一些重要的参数做图像处理。
②为什么使用比较少的参数就足够进行图像处理??
三个特性:
1.1节的前两个property需要卷积计算,后一个池化层处理,具体下节介绍。
参数名称 | 含义 |
---|---|
stride | 移动步幅 |
padding | 填充数据 |
矩阵卷积计算如下:
RGB三色图如同几个矩阵叠加在一起的立方体,其卷积计算过程图如下:
计算如下:图像传入的是553的像素值,经过padding=1的填充构成773的像素值,卷积核是333的大小,2个卷积核,步数stride=2。注意这里的卷积核深度要核传入过来的像素值深度相同,当每次扫描到的蓝色位置数对应卷积核红色位置数位置相乘后相加得到绿色位置的数据。
像素数变化为:(n+2p-f)\s = (5+2-3)\2 + 1= 3得到332的数据,经过卷积输出的像素深度等于上一层输入的卷积核数目。将得的结果作为池化层的输入值。
卷积核大小选取往往是奇数。深度要和它的上一层输出像素值深度相同,如动图卷积核的选取是333,,而输出像素值深度=本次卷积的卷积核数。这点不要混淆。
其实卷积就是将全连接层的一些weight拿掉,卷积层计算输出的结果,其实就是全连接层的hidden layer输出的结果。如下图所示:
卷积没有考虑输入的全部特征,只和filter中经过的特征有关,如下:6*6的图像展开成36pixel,然后下一层只和输入层的9个pixel有关,没有连接全部,这样就会使用很少的参数,具体图解如下:
由上图也可发现,计算结果3和-1不像全连接网络那样全部都需要不同的weight,而这个3和-1的部分计算的weight相同,这就是所谓的参数共享(权值共享)
根据前一个卷积计算后的矩阵,再进行池化处理(将一个框框内的四个值合并一个值,可取最大值或者平均值),如下图:
经过一次卷积一次池化就将原来6x6的image转化成2x2的image
本博客主要是使用pytorch框架来介绍卷积神经网络。
torch.nn.Conv2d( in_channels: int, #输入图像的通道数 out_channels: int, #卷积产生的输出通道数 kernel_size: Union[T, Tuple[T, T]], #卷积核大小 stride: Union[T, Tuple[T, T]] = 1, #卷积的步数 默认:1 padding: Union[T, Tuple[T, T]] = 0, #0填充添加到输入的两边 默认:0 dilation: Union[T, Tuple[T, T]] = 1, #核元素之间的间距 默认:1 groups: int = 1, #从输入通道到输出通道的阻塞链接数,默认:1 #groups:控制输入和输出之间的连接,输入和输出通道数必须被组整除, #当groups=1:所有输入移交给所有输出 #当groups=2:相当于两个卷积层,一个看到一半的输入通道并产生一半的输出通道,将两个合并 #当groups=in_channels:每个通道都有自己的一组过滤器,其大小为out_channel/in_channel bias: bool = True, #将可学习的偏差添加到输出中 默认:true padding_mode: str = 'zeros') #注:kenerl_size,stride,padding,dilation参数类型可以是int,可以是tuple,当是tuple时,第一个int是高度维度,第二个是宽度维度。当是单个int时,高度宽度值相同 # 方形核和等步幅 m = nn.Conv2d(16, 33, 3, stride=2) # 非方形核和不等步幅和填充 m = nn.Conv2d(16, 33, (3, 5), stride=(2, 1), padding=(4, 2)) # 非方形核和不等步幅和填充和扩展 m = nn.Conv2d(16, 33, (3, 5), stride=(2, 1), padding=(4, 2), dilation=(3, 1)) input = torch.randn(20, 16, 50, 100) output = m(input)
输入输出关系公式如下:
i
n
p
u
t
:
(
N
,
C
i
n
,
H
i
n
,
W
i
n
)
input:(N,C_{in},H_{in},W_{in})
input:(N,Cin,Hin,Win)
o
u
t
p
u
t
:
(
N
,
C
o
u
t
,
H
o
u
t
,
W
o
u
t
)
output:(N,C_{out},H_{out},W_{out})
output:(N,Cout,Hout,Wout)
H
o
u
t
=
{
H
i
n
+
2
×
p
a
d
d
i
n
g
[
0
]
−
d
i
l
a
t
i
o
n
[
0
]
×
(
k
e
r
n
e
l
s
i
z
e
[
0
]
−
1
)
−
1
}
/
s
t
r
i
d
e
[
0
]
+
1
H_{out} = \{H_{in}+2×padding[0]−dilation[0]×(kernelsize[0]−1)−1\}/stride[0] + 1
Hout={Hin+2×padding[0]−dilation[0]×(kernelsize[0]−1)−1}/stride[0]+1
W
o
u
t
=
{
W
i
n
+
2
×
p
a
d
d
i
n
g
[
1
]
−
d
i
l
a
t
i
o
n
[
1
]
×
(
k
e
r
n
e
l
s
i
z
e
[
1
]
−
1
)
−
1
}
/
s
t
r
i
d
e
[
1
]
+
1
W_{out} = \{W_{in}+2×padding[1]−dilation[1]×(kernelsize[1]−1)−1\}/stride[1] + 1
Wout={Win+2×padding[1]−dilation[1]×(kernelsize[1]−1)−1}/stride[1]+1
torch.nn.MaxPool2d( kernel_size: Union[T, Tuple[T, T]], #窗口大小以便取最大值 stride: Union[T, Tuple[T, T]] = 1, #窗口的步幅,默认:kernel_size padding: Union[T, Tuple[T, T]] = 0, #0填充添加到输入的两边 默认:0 dilation: Union[T, Tuple[T, T]] = 1, #核元素之间的间距 默认:1 return_indices: bool = false, #如果为true则返回最大索引和输出,默认:1 ceil_mode: bool=false,#如果为真用ceil代替floor计算输出形状) #注:kenerl_size,stride,padding,dilation参数类型可以是int,可以是tuple,当是tuple时,第一个int是高度维度,第二个是宽度维度。当是单个int时,高度宽度值相同 #窗口大小为3,步幅为2 m = nn.MaxPool2d(3, stride=2) #非方形窗口 m = nn.MaxPool2d((3, 2), stride=(2, 1)) input = torch.randn(20, 16, 50, 32) output = m(input)
输入输出关系公式如下:
i
n
p
u
t
:
(
N
,
C
,
H
i
n
,
W
i
n
)
input:(N,C,H_{in},W_{in})
input:(N,C,Hin,Win)
o
u
t
p
u
t
:
(
N
,
C
,
H
o
u
t
,
W
o
u
t
)
output:(N,C,H_{out},W_{out})
output:(N,C,Hout,Wout)
H
o
u
t
=
{
H
i
n
+
2
×
p
a
d
d
i
n
g
[
0
]
−
d
i
l
a
t
i
o
n
[
0
]
×
(
k
e
r
n
e
l
s
i
z
e
[
0
]
−
1
)
−
1
}
/
s
t
r
i
d
e
[
0
]
+
1
H_{out} = \{H_{in}+2×padding[0]−dilation[0]×(kernelsize[0]−1)−1\}/stride[0] + 1
Hout={Hin+2×padding[0]−dilation[0]×(kernelsize[0]−1)−1}/stride[0]+1
W
o
u
t
=
{
W
i
n
+
2
×
p
a
d
d
i
n
g
[
1
]
−
d
i
l
a
t
i
o
n
[
1
]
×
(
k
e
r
n
e
l
s
i
z
e
[
1
]
−
1
)
−
1
}
/
s
t
r
i
d
e
[
1
]
+
1
W_{out} = \{W_{in}+2×padding[1]−dilation[1]×(kernelsize[1]−1)−1\}/stride[1] + 1
Wout={Win+2×padding[1]−dilation[1]×(kernelsize[1]−1)−1}/stride[1]+1
然后就是将5055做个flatten(拉直),变成1250,再将flatten后的数据丢到fully connected里,再输出。图解如下:
总结:filter只看图的一小部分,flatten后是看图的整个部分。图解如下:
卷积层:
一个filter只识别一个条纹或一条直线等图片的部分特征,
全连接层:是看整张图
每个订票系统都会有一个空位填充(slot filling),有些slot是Destination,有些slot是time of arrival,系统要知道哪些词属于哪个slot;例如:
I would like to arrive Taipei on November 2nd;
这里的Taipei就是Destination,November 2nd就是time of arrival;
采用普通的神经网络,将Taipei这个词丢入到网络中,当然在丢入之前要将其转化成向量表示,如何表示成向量?方法很多此处采用:1-of-N Encoding,表示方式如下:
其他词向量方式如下:
但是,如果有如下情况,系统就会出错
那么这种有记忆的网络就叫做:Recurrent Neural Network(RNN)
RNN的隐藏层的输出会存储在内存中,当下次输入数据时会使用到内存中存储的上次的输出。图解如下:
图中,同样的weight用同样的颜色表示。当然hidden layer可以有很多层;
以上介绍的RNN是最简单的,接下来介绍加强版的LSTM;
现在常用的内存(memory)是Long short-term内存。
当外部信息需要输入到memory时需要一个“闸门”——input gate,而input gate什么时候打开和关闭是被神经网络学到的,同理output gate也是神经网络学习的,forget gate也是如此。
所以LSTM有四个input,1个output。简图如下:
公式如下:
图中x2 = 1将x1送入memory中,如果x2=-1就清空memory的数值,如果x3=1,就将memory中的数据输出。如上图,第一列,x2=0不送入memory,第二列x2=1,将此刻x1=3送入memory中(注意memory中的数据是x1的累加,例如第四列,x2=1,此时有x1=4,memory中=3,所以一起就是7)第五列发现x3=1,可以输出,所以输出memory中的值7.
结合LSTM简图如下:
假设进来的是第一列:x1=3,x2=1,x3=0
步骤:
g—Tanh: x1w1+x2w2+x3w3 = 3
f—sigmod: x1w1+x2w2+x3w3=90 sigmod后=1
算好f和g后传入input gate=3*1=3,forget gate = 1,代表不需要清0,x3=0,代表output gate锁上,输出的还是0。
CNN与RNN区别链接如下,我认为这个博客作者总结的很是浅显易懂。
https://blog.csdn.net/lff1208/article/details/77717149
以上就是根据李宏毅老师的课程,编写的对RNN和CNN知识的总结,同时还包括别人博客对神经网络算法区别的介绍。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。